MailPoet Newsletters (New) - Version 3.0.0-beta.14

Version Description

  • 2017-01-19 =
  • Fixed: images can't be added to newsletters. Thanks Leon!;
  • Fixed: forms require first & last name input fields on some systems;
  • Fixed: unable to remove subscribers from lists in admin panel. Thanks Kay!
Download this release

Release Info

Developer wysija
Plugin Icon 128x128 MailPoet Newsletters (New)
Version 3.0.0-beta.14
Comparing to
See all releases

Code changes from version 3.0.0-beta.13 to 3.0.0-beta.14

Files changed (65) hide show
  1. assets/css/admin.css +2 -2
  2. assets/js/admin.js +257 -89
  3. assets/js/form_editor.js +679 -676
  4. assets/js/mailpoet.js +6 -6
  5. assets/js/newsletter_editor.js +9 -8
  6. assets/js/public.js +6 -6
  7. lang/index.php +0 -3
  8. lang/mailpoet.pot +3 -3
  9. lib/API/Endpoints/Subscribers.php +3 -0
  10. lib/Models/Subscriber.php +11 -0
  11. lib/Models/SubscriberSegment.php +9 -6
  12. lib/Util/ConflictResolver.php +19 -18
  13. mailpoet.php +3 -3
  14. readme.txt +7 -2
  15. vendor/autoload.php +1 -1
  16. vendor/composer/ClassLoader.php +31 -5
  17. vendor/composer/autoload_real.php +8 -8
  18. vendor/composer/autoload_static.php +5 -5
  19. vendor/composer/installed.json +12 -12
  20. vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/CSSList/AtRuleBlockListTest.php +0 -27
  21. vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/CSSList/DocumentTest.php +0 -26
  22. vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/CSSList/index.php +0 -0
  23. vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/OutputFormatTest.php +0 -170
  24. vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/ParserTest.php +0 -585
  25. vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/RuleSet/DeclarationBlockTest.php +0 -267
  26. vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/RuleSet/LenientParsingTest.php +0 -76
  27. vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/RuleSet/index.php +0 -0
  28. vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/index.php +0 -0
  29. vendor/sabberworm/php-css-parser/tests/Sabberworm/index.php +0 -0
  30. vendor/sabberworm/php-css-parser/tests/bootstrap.php +0 -10
  31. vendor/sabberworm/php-css-parser/tests/files/-charset-after-rule.css +0 -5
  32. vendor/sabberworm/php-css-parser/tests/files/-charset-in-block.css +0 -3
  33. vendor/sabberworm/php-css-parser/tests/files/-empty.css +0 -0
  34. vendor/sabberworm/php-css-parser/tests/files/-end-token-2.css +0 -1
  35. vendor/sabberworm/php-css-parser/tests/files/-end-token.css +0 -1
  36. vendor/sabberworm/php-css-parser/tests/files/-fault-tolerance.css +0 -15
  37. vendor/sabberworm/php-css-parser/tests/files/-tobedone.css +0 -9
  38. vendor/sabberworm/php-css-parser/tests/files/1readme.css +0 -10
  39. vendor/sabberworm/php-css-parser/tests/files/2readme.css +0 -5
  40. vendor/sabberworm/php-css-parser/tests/files/atrules.css +0 -57
  41. vendor/sabberworm/php-css-parser/tests/files/case-insensitivity.css +0 -15
  42. vendor/sabberworm/php-css-parser/tests/files/colortest.css +0 -12
  43. vendor/sabberworm/php-css-parser/tests/files/comments.css +0 -17
  44. vendor/sabberworm/php-css-parser/tests/files/create-shorthands.css +0 -6
  45. vendor/sabberworm/php-css-parser/tests/files/docuwiki.css +0 -1
  46. vendor/sabberworm/php-css-parser/tests/files/expand-shorthands.css +0 -7
  47. vendor/sabberworm/php-css-parser/tests/files/functions.css +0 -21
  48. vendor/sabberworm/php-css-parser/tests/files/ie-hacks.css +0 -9
  49. vendor/sabberworm/php-css-parser/tests/files/ie.css +0 -6
  50. vendor/sabberworm/php-css-parser/tests/files/important.css +0 -8
  51. vendor/sabberworm/php-css-parser/tests/files/index.php +0 -0
  52. vendor/sabberworm/php-css-parser/tests/files/inner-color.css +0 -3
  53. vendor/sabberworm/php-css-parser/tests/files/line-numbers.css +0 -32
  54. vendor/sabberworm/php-css-parser/tests/files/namespaces.css +0 -18
  55. vendor/sabberworm/php-css-parser/tests/files/nested.css +0 -17
  56. vendor/sabberworm/php-css-parser/tests/files/slashed.css +0 -4
  57. vendor/sabberworm/php-css-parser/tests/files/specificity.css +0 -7
  58. vendor/sabberworm/php-css-parser/tests/files/unicode.css +0 -12
  59. vendor/sabberworm/php-css-parser/tests/files/url.css +0 -4
  60. vendor/sabberworm/php-css-parser/tests/files/values.css +0 -14
  61. vendor/sabberworm/php-css-parser/tests/files/webkit.css +0 -1
  62. vendor/sabberworm/php-css-parser/tests/files/whitespace.css +0 -3
  63. vendor/sabberworm/php-css-parser/tests/index.php +0 -0
  64. vendor/sabberworm/php-css-parser/tests/phpunit.xml +0 -1
  65. vendor/sabberworm/php-css-parser/tests/quickdump.php +0 -20
assets/css/admin.css CHANGED
@@ -1799,8 +1799,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
1799
  position: relative;
1800
  overflow: visible;
1801
  -webkit-tap-highlight-color: transparent;
1802
- -webkit-font-variant-ligatures: none;
1803
- font-variant-ligatures: none;
1804
  }
1805
  .CodeMirror-wrap pre {
1806
  word-wrap: break-word;
1799
  position: relative;
1800
  overflow: visible;
1801
  -webkit-tap-highlight-color: transparent;
1802
+ -webkit-font-variant-ligatures: contextual;
1803
+ font-variant-ligatures: contextual;
1804
  }
1805
  .CodeMirror-wrap pre {
1806
  word-wrap: break-word;
assets/js/admin.js CHANGED
@@ -360,8 +360,15 @@ webpackJsonp([0],[
360
  /* 5 */
361
  /***/ function(module, exports) {
362
 
 
 
 
 
 
 
363
  'use strict';
364
  /* eslint-disable no-unused-vars */
 
365
  var hasOwnProperty = Object.prototype.hasOwnProperty;
366
  var propIsEnumerable = Object.prototype.propertyIsEnumerable;
367
 
@@ -382,7 +389,7 @@ webpackJsonp([0],[
382
  // Detect buggy property enumeration order in older V8 versions.
383
 
384
  // https://bugs.chromium.org/p/v8/issues/detail?id=4118
385
- var test1 = new String('abc'); // eslint-disable-line
386
  test1[5] = 'de';
387
  if (Object.getOwnPropertyNames(test1)[0] === '5') {
388
  return false;
@@ -411,7 +418,7 @@ webpackJsonp([0],[
411
  }
412
 
413
  return true;
414
- } catch (e) {
415
  // We don't expect any of the above to throw, but better to be safe.
416
  return false;
417
  }
@@ -431,8 +438,8 @@ webpackJsonp([0],[
431
  }
432
  }
433
 
434
- if (Object.getOwnPropertySymbols) {
435
- symbols = Object.getOwnPropertySymbols(from);
436
  for (var i = 0; i < symbols.length; i++) {
437
  if (propIsEnumerable.call(from, symbols[i])) {
438
  to[symbols[i]] = from[symbols[i]];
@@ -712,17 +719,6 @@ webpackJsonp([0],[
712
  }
713
  };
714
 
715
- var fiveArgumentPooler = function (a1, a2, a3, a4, a5) {
716
- var Klass = this;
717
- if (Klass.instancePool.length) {
718
- var instance = Klass.instancePool.pop();
719
- Klass.call(instance, a1, a2, a3, a4, a5);
720
- return instance;
721
- } else {
722
- return new Klass(a1, a2, a3, a4, a5);
723
- }
724
- };
725
-
726
  var standardReleaser = function (instance) {
727
  var Klass = this;
728
  !(instance instanceof Klass) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Trying to release an instance into a pool of a different type.') : _prodInvariant('25') : void 0;
@@ -762,8 +758,7 @@ webpackJsonp([0],[
762
  oneArgumentPooler: oneArgumentPooler,
763
  twoArgumentPooler: twoArgumentPooler,
764
  threeArgumentPooler: threeArgumentPooler,
765
- fourArgumentPooler: fourArgumentPooler,
766
- fiveArgumentPooler: fiveArgumentPooler
767
  };
768
 
769
  module.exports = PooledClass;
@@ -839,12 +834,18 @@ webpackJsonp([0],[
839
  * will remain to ensure logic does not differ in production.
840
  */
841
 
842
- function invariant(condition, format, a, b, c, d, e, f) {
843
- if (process.env.NODE_ENV !== 'production') {
 
 
844
  if (format === undefined) {
845
  throw new Error('invariant requires an error message argument');
846
  }
847
- }
 
 
 
 
848
 
849
  if (!condition) {
850
  var error;
@@ -3097,7 +3098,14 @@ webpackJsonp([0],[
3097
  // We warn in this case but don't throw. We expect the element creation to
3098
  // succeed and there will likely be errors in render.
3099
  if (!validType) {
3100
- process.env.NODE_ENV !== 'production' ? warning(false, 'React.createElement: type should not be null, undefined, boolean, or ' + 'number. It should be a string (for DOM elements) or a ReactClass ' + '(for composite components).%s', getDeclarationErrorAddendum()) : void 0;
 
 
 
 
 
 
 
3101
  }
3102
 
3103
  var element = ReactElement.createElement.apply(this, arguments);
@@ -4068,7 +4076,7 @@ webpackJsonp([0],[
4068
 
4069
  'use strict';
4070
 
4071
- module.exports = '15.4.1';
4072
 
4073
  /***/ },
4074
  /* 32 */
@@ -4266,6 +4274,13 @@ webpackJsonp([0],[
4266
 
4267
  var internalInstanceKey = '__reactInternalInstance$' + Math.random().toString(36).slice(2);
4268
 
 
 
 
 
 
 
 
4269
  /**
4270
  * Drill down (through composites and empty components) until we get a host or
4271
  * host text component.
@@ -4331,7 +4346,7 @@ webpackJsonp([0],[
4331
  }
4332
  // We assume the child nodes are in the same order as the child instances.
4333
  for (; childNode !== null; childNode = childNode.nextSibling) {
4334
- if (childNode.nodeType === 1 && childNode.getAttribute(ATTR_NAME) === String(childID) || childNode.nodeType === 8 && childNode.nodeValue === ' react-text: ' + childID + ' ' || childNode.nodeType === 8 && childNode.nodeValue === ' react-empty: ' + childID + ' ') {
4335
  precacheNode(childInst, childNode);
4336
  continue outer;
4337
  }
@@ -6504,8 +6519,15 @@ webpackJsonp([0],[
6504
  /* 51 */
6505
  /***/ function(module, exports) {
6506
 
 
 
 
 
 
 
6507
  'use strict';
6508
  /* eslint-disable no-unused-vars */
 
6509
  var hasOwnProperty = Object.prototype.hasOwnProperty;
6510
  var propIsEnumerable = Object.prototype.propertyIsEnumerable;
6511
 
@@ -6526,7 +6548,7 @@ webpackJsonp([0],[
6526
  // Detect buggy property enumeration order in older V8 versions.
6527
 
6528
  // https://bugs.chromium.org/p/v8/issues/detail?id=4118
6529
- var test1 = new String('abc'); // eslint-disable-line
6530
  test1[5] = 'de';
6531
  if (Object.getOwnPropertyNames(test1)[0] === '5') {
6532
  return false;
@@ -6555,7 +6577,7 @@ webpackJsonp([0],[
6555
  }
6556
 
6557
  return true;
6558
- } catch (e) {
6559
  // We don't expect any of the above to throw, but better to be safe.
6560
  return false;
6561
  }
@@ -6575,8 +6597,8 @@ webpackJsonp([0],[
6575
  }
6576
  }
6577
 
6578
- if (Object.getOwnPropertySymbols) {
6579
- symbols = Object.getOwnPropertySymbols(from);
6580
  for (var i = 0; i < symbols.length; i++) {
6581
  if (propIsEnumerable.call(from, symbols[i])) {
6582
  to[symbols[i]] = from[symbols[i]];
@@ -6661,17 +6683,6 @@ webpackJsonp([0],[
6661
  }
6662
  };
6663
 
6664
- var fiveArgumentPooler = function (a1, a2, a3, a4, a5) {
6665
- var Klass = this;
6666
- if (Klass.instancePool.length) {
6667
- var instance = Klass.instancePool.pop();
6668
- Klass.call(instance, a1, a2, a3, a4, a5);
6669
- return instance;
6670
- } else {
6671
- return new Klass(a1, a2, a3, a4, a5);
6672
- }
6673
- };
6674
-
6675
  var standardReleaser = function (instance) {
6676
  var Klass = this;
6677
  !(instance instanceof Klass) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Trying to release an instance into a pool of a different type.') : _prodInvariant('25') : void 0;
@@ -6711,8 +6722,7 @@ webpackJsonp([0],[
6711
  oneArgumentPooler: oneArgumentPooler,
6712
  twoArgumentPooler: twoArgumentPooler,
6713
  threeArgumentPooler: threeArgumentPooler,
6714
- fourArgumentPooler: fourArgumentPooler,
6715
- fiveArgumentPooler: fiveArgumentPooler
6716
  };
6717
 
6718
  module.exports = PooledClass;
@@ -11530,12 +11540,18 @@ webpackJsonp([0],[
11530
  } else {
11531
  var contentToUse = CONTENT_TYPES[typeof props.children] ? props.children : null;
11532
  var childrenToUse = contentToUse != null ? null : props.children;
 
11533
  if (contentToUse != null) {
11534
- // TODO: Validate that text is allowed as a child of this node
11535
- if (process.env.NODE_ENV !== 'production') {
11536
- setAndValidateContentChildDev.call(this, contentToUse);
 
 
 
 
 
 
11537
  }
11538
- DOMLazyTree.queueText(lazyTree, contentToUse);
11539
  } else if (childrenToUse != null) {
11540
  var mountImages = this.mountChildren(childrenToUse, transaction, context);
11541
  for (var i = 0; i < mountImages.length; i++) {
@@ -13455,7 +13471,17 @@ webpackJsonp([0],[
13455
  }
13456
  } else {
13457
  if (props.value == null && props.defaultValue != null) {
13458
- node.defaultValue = '' + props.defaultValue;
 
 
 
 
 
 
 
 
 
 
13459
  }
13460
  if (props.checked == null && props.defaultChecked != null) {
13461
  node.defaultChecked = !!props.defaultChecked;
@@ -14202,9 +14228,15 @@ webpackJsonp([0],[
14202
  // This is in postMount because we need access to the DOM node, which is not
14203
  // available until after the component has mounted.
14204
  var node = ReactDOMComponentTree.getNodeFromInstance(inst);
 
14205
 
14206
- // Warning: node.value may be the empty string at this point (IE11) if placeholder is set.
14207
- node.value = node.textContent; // Detach value from defaultValue
 
 
 
 
 
14208
  }
14209
  };
14210
 
@@ -15006,7 +15038,17 @@ webpackJsonp([0],[
15006
  instance = ReactEmptyComponent.create(instantiateReactComponent);
15007
  } else if (typeof node === 'object') {
15008
  var element = node;
15009
- !(element && (typeof element.type === 'function' || typeof element.type === 'string')) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s', element.type == null ? element.type : typeof element.type, getDeclarationErrorAddendum(element._owner)) : _prodInvariant('130', element.type == null ? element.type : typeof element.type, getDeclarationErrorAddendum(element._owner)) : void 0;
 
 
 
 
 
 
 
 
 
 
15010
 
15011
  // Special case string values
15012
  if (typeof element.type === 'string') {
@@ -15296,7 +15338,7 @@ webpackJsonp([0],[
15296
  // Since plain JS classes are defined without any special initialization
15297
  // logic, we can not catch common errors early. Therefore, we have to
15298
  // catch them here, at initialization time, instead.
15299
- process.env.NODE_ENV !== 'production' ? warning(!inst.getInitialState || inst.getInitialState.isReactClassApproved, 'getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', this.getName() || 'a component') : void 0;
15300
  process.env.NODE_ENV !== 'production' ? warning(!inst.getDefaultProps || inst.getDefaultProps.isReactClassApproved, 'getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', this.getName() || 'a component') : void 0;
15301
  process.env.NODE_ENV !== 'production' ? warning(!inst.propTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', this.getName() || 'a component') : void 0;
15302
  process.env.NODE_ENV !== 'production' ? warning(!inst.contextTypes, 'contextTypes was defined as an instance property on %s. Use a ' + 'static property to define contextTypes instead.', this.getName() || 'a component') : void 0;
@@ -16300,14 +16342,11 @@ webpackJsonp([0],[
16300
 
16301
  'use strict';
16302
 
16303
- var _prodInvariant = __webpack_require__(36),
16304
- _assign = __webpack_require__(51);
16305
 
16306
  var invariant = __webpack_require__(9);
16307
 
16308
  var genericComponentClass = null;
16309
- // This registry keeps track of wrapper classes around host tags.
16310
- var tagToComponentClass = {};
16311
  var textComponentClass = null;
16312
 
16313
  var ReactHostComponentInjection = {
@@ -16320,11 +16359,6 @@ webpackJsonp([0],[
16320
  // rendered as props.
16321
  injectTextComponentClass: function (componentClass) {
16322
  textComponentClass = componentClass;
16323
- },
16324
- // This accepts a keyed object with classes as values. Each key represents a
16325
- // tag. That particular tag will use this class instead of the generic one.
16326
- injectComponentClasses: function (componentClasses) {
16327
- _assign(tagToComponentClass, componentClasses);
16328
  }
16329
  };
16330
 
@@ -21179,7 +21213,7 @@ webpackJsonp([0],[
21179
 
21180
  'use strict';
21181
 
21182
- module.exports = '15.4.1';
21183
 
21184
  /***/ },
21185
  /* 174 */
@@ -21854,7 +21888,7 @@ webpackJsonp([0],[
21854
 
21855
  var match = void 0,
21856
  lastIndex = 0,
21857
- matcher = /:([a-zA-Z_$][a-zA-Z0-9_$]*)|\*\*|\*|\(|\)/g;
21858
  while (match = matcher.exec(pattern)) {
21859
  if (match.index !== lastIndex) {
21860
  tokens.push(pattern.slice(lastIndex, match.index));
@@ -21874,6 +21908,10 @@ webpackJsonp([0],[
21874
  regexpSource += '(?:';
21875
  } else if (match[0] === ')') {
21876
  regexpSource += ')?';
 
 
 
 
21877
  }
21878
 
21879
  tokens.push(match[0]);
@@ -22028,6 +22066,10 @@ webpackJsonp([0],[
22028
  parenCount -= 1;
22029
 
22030
  if (parenCount) parenHistory[parenCount - 1] += parenText;else pathname += parenText;
 
 
 
 
22031
  } else if (token.charAt(0) === ':') {
22032
  paramName = token.substring(1);
22033
  paramValue = params[paramName];
@@ -22895,7 +22937,7 @@ webpackJsonp([0],[
22895
  return runTransitionHooks(hooks.length, function (index, replace, next) {
22896
  var wrappedNext = function wrappedNext() {
22897
  if (enterHooks.has(hooks[index])) {
22898
- next();
22899
  enterHooks.remove(hooks[index]);
22900
  }
22901
  };
@@ -22919,7 +22961,7 @@ webpackJsonp([0],[
22919
  return runTransitionHooks(hooks.length, function (index, replace, next) {
22920
  var wrappedNext = function wrappedNext() {
22921
  if (changeHooks.has(hooks[index])) {
22922
- next();
22923
  changeHooks.remove(hooks[index]);
22924
  }
22925
  };
@@ -23321,9 +23363,14 @@ webpackJsonp([0],[
23321
  if ((0, _PromiseUtils.isPromise)(indexRoutesReturn)) indexRoutesReturn.then(function (indexRoute) {
23322
  return callback(null, (0, _RouteUtils.createRoutes)(indexRoute)[0]);
23323
  }, callback);
23324
- } else if (route.childRoutes) {
23325
- (function () {
23326
- var pathless = route.childRoutes.filter(function (childRoute) {
 
 
 
 
 
23327
  return !childRoute.path;
23328
  });
23329
 
@@ -23339,7 +23386,12 @@ webpackJsonp([0],[
23339
  }, function (err, routes) {
23340
  callback(null, routes);
23341
  });
23342
- })();
 
 
 
 
 
23343
  } else {
23344
  callback();
23345
  }
@@ -23393,7 +23445,7 @@ webpackJsonp([0],[
23393
  // By assumption, pattern is non-empty here, which is the prerequisite for
23394
  // actually terminating a match.
23395
  if (remainingPathname === '') {
23396
- var _ret2 = function () {
23397
  var match = {
23398
  routes: [route],
23399
  params: createParams(paramNames, paramValues)
@@ -23424,7 +23476,7 @@ webpackJsonp([0],[
23424
  };
23425
  }();
23426
 
23427
- if ((typeof _ret2 === 'undefined' ? 'undefined' : _typeof(_ret2)) === "object") return _ret2.v;
23428
  }
23429
  }
23430
 
@@ -24002,7 +24054,7 @@ webpackJsonp([0],[
24002
 
24003
  if (router) {
24004
  // If user does not specify a `to` prop, return an empty anchor tag.
24005
- if (to == null) {
24006
  return _react2.default.createElement('a', props);
24007
  }
24008
 
@@ -24119,6 +24171,10 @@ webpackJsonp([0],[
24119
  var _this = this;
24120
 
24121
  var router = this.props.router || this.context.router;
 
 
 
 
24122
  var params = router.params,
24123
  location = router.location,
24124
  routes = router.routes;
@@ -24784,6 +24840,92 @@ webpackJsonp([0],[
24784
  var strictUriEncode = __webpack_require__(214);
24785
  var objectAssign = __webpack_require__(215);
24786
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24787
  function encode(value, opts) {
24788
  if (opts.encode) {
24789
  return opts.strict ? strictUriEncode(value) : encodeURIComponent(value);
@@ -24792,11 +24934,29 @@ webpackJsonp([0],[
24792
  return value;
24793
  }
24794
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24795
  exports.extract = function (str) {
24796
  return str.split('?')[1] || '';
24797
  };
24798
 
24799
- exports.parse = function (str) {
 
 
 
 
24800
  // Create an object with no prototype
24801
  // https://github.com/sindresorhus/query-string/issues/47
24802
  var ret = Object.create(null);
@@ -24818,32 +24978,37 @@ webpackJsonp([0],[
24818
  var key = parts.shift();
24819
  var val = parts.length > 0 ? parts.join('=') : undefined;
24820
 
24821
- key = decodeURIComponent(key);
24822
-
24823
  // missing `=` should be `null`:
24824
  // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
24825
  val = val === undefined ? null : decodeURIComponent(val);
24826
 
24827
- if (ret[key] === undefined) {
24828
- ret[key] = val;
24829
- } else if (Array.isArray(ret[key])) {
24830
- ret[key].push(val);
 
 
 
 
24831
  } else {
24832
- ret[key] = [ret[key], val];
24833
  }
24834
- });
24835
 
24836
- return ret;
 
24837
  };
24838
 
24839
  exports.stringify = function (obj, opts) {
24840
  var defaults = {
24841
  encode: true,
24842
- strict: true
 
24843
  };
24844
 
24845
  opts = objectAssign(defaults, opts);
24846
 
 
 
24847
  return obj ? Object.keys(obj).sort().map(function (key) {
24848
  var val = obj[key];
24849
 
@@ -24863,11 +25028,7 @@ webpackJsonp([0],[
24863
  return;
24864
  }
24865
 
24866
- if (val2 === null) {
24867
- result.push(encode(key, opts));
24868
- } else {
24869
- result.push(encode(key, opts) + '=' + encode(val2, opts));
24870
- }
24871
  });
24872
 
24873
  return result.join('&');
@@ -24896,8 +25057,15 @@ webpackJsonp([0],[
24896
  /* 215 */
24897
  /***/ function(module, exports) {
24898
 
 
 
 
 
 
 
24899
  'use strict';
24900
  /* eslint-disable no-unused-vars */
 
24901
  var hasOwnProperty = Object.prototype.hasOwnProperty;
24902
  var propIsEnumerable = Object.prototype.propertyIsEnumerable;
24903
 
@@ -24918,7 +25086,7 @@ webpackJsonp([0],[
24918
  // Detect buggy property enumeration order in older V8 versions.
24919
 
24920
  // https://bugs.chromium.org/p/v8/issues/detail?id=4118
24921
- var test1 = new String('abc'); // eslint-disable-line
24922
  test1[5] = 'de';
24923
  if (Object.getOwnPropertyNames(test1)[0] === '5') {
24924
  return false;
@@ -24947,7 +25115,7 @@ webpackJsonp([0],[
24947
  }
24948
 
24949
  return true;
24950
- } catch (e) {
24951
  // We don't expect any of the above to throw, but better to be safe.
24952
  return false;
24953
  }
@@ -24967,8 +25135,8 @@ webpackJsonp([0],[
24967
  }
24968
  }
24969
 
24970
- if (Object.getOwnPropertySymbols) {
24971
- symbols = Object.getOwnPropertySymbols(from);
24972
  for (var i = 0; i < symbols.length; i++) {
24973
  if (propIsEnumerable.call(from, symbols[i])) {
24974
  to[symbols[i]] = from[symbols[i]];
360
  /* 5 */
361
  /***/ function(module, exports) {
362
 
363
+ /*
364
+ object-assign
365
+ (c) Sindre Sorhus
366
+ @license MIT
367
+ */
368
+
369
  'use strict';
370
  /* eslint-disable no-unused-vars */
371
+ var getOwnPropertySymbols = Object.getOwnPropertySymbols;
372
  var hasOwnProperty = Object.prototype.hasOwnProperty;
373
  var propIsEnumerable = Object.prototype.propertyIsEnumerable;
374
 
389
  // Detect buggy property enumeration order in older V8 versions.
390
 
391
  // https://bugs.chromium.org/p/v8/issues/detail?id=4118
392
+ var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
393
  test1[5] = 'de';
394
  if (Object.getOwnPropertyNames(test1)[0] === '5') {
395
  return false;
418
  }
419
 
420
  return true;
421
+ } catch (err) {
422
  // We don't expect any of the above to throw, but better to be safe.
423
  return false;
424
  }
438
  }
439
  }
440
 
441
+ if (getOwnPropertySymbols) {
442
+ symbols = getOwnPropertySymbols(from);
443
  for (var i = 0; i < symbols.length; i++) {
444
  if (propIsEnumerable.call(from, symbols[i])) {
445
  to[symbols[i]] = from[symbols[i]];
719
  }
720
  };
721
 
 
 
 
 
 
 
 
 
 
 
 
722
  var standardReleaser = function (instance) {
723
  var Klass = this;
724
  !(instance instanceof Klass) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Trying to release an instance into a pool of a different type.') : _prodInvariant('25') : void 0;
758
  oneArgumentPooler: oneArgumentPooler,
759
  twoArgumentPooler: twoArgumentPooler,
760
  threeArgumentPooler: threeArgumentPooler,
761
+ fourArgumentPooler: fourArgumentPooler
 
762
  };
763
 
764
  module.exports = PooledClass;
834
  * will remain to ensure logic does not differ in production.
835
  */
836
 
837
+ var validateFormat = function validateFormat(format) {};
838
+
839
+ if (process.env.NODE_ENV !== 'production') {
840
+ validateFormat = function validateFormat(format) {
841
  if (format === undefined) {
842
  throw new Error('invariant requires an error message argument');
843
  }
844
+ };
845
+ }
846
+
847
+ function invariant(condition, format, a, b, c, d, e, f) {
848
+ validateFormat(format);
849
 
850
  if (!condition) {
851
  var error;
3098
  // We warn in this case but don't throw. We expect the element creation to
3099
  // succeed and there will likely be errors in render.
3100
  if (!validType) {
3101
+ if (typeof type !== 'function' && typeof type !== 'string') {
3102
+ var info = '';
3103
+ if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {
3104
+ info += ' You likely forgot to export your component from the file ' + 'it\'s defined in.';
3105
+ }
3106
+ info += getDeclarationErrorAddendum();
3107
+ process.env.NODE_ENV !== 'production' ? warning(false, 'React.createElement: type is invalid -- expected a string (for ' + 'built-in components) or a class/function (for composite ' + 'components) but got: %s.%s', type == null ? type : typeof type, info) : void 0;
3108
+ }
3109
  }
3110
 
3111
  var element = ReactElement.createElement.apply(this, arguments);
4076
 
4077
  'use strict';
4078
 
4079
+ module.exports = '15.4.2';
4080
 
4081
  /***/ },
4082
  /* 32 */
4274
 
4275
  var internalInstanceKey = '__reactInternalInstance$' + Math.random().toString(36).slice(2);
4276
 
4277
+ /**
4278
+ * Check if a given node should be cached.
4279
+ */
4280
+ function shouldPrecacheNode(node, nodeID) {
4281
+ return node.nodeType === 1 && node.getAttribute(ATTR_NAME) === String(nodeID) || node.nodeType === 8 && node.nodeValue === ' react-text: ' + nodeID + ' ' || node.nodeType === 8 && node.nodeValue === ' react-empty: ' + nodeID + ' ';
4282
+ }
4283
+
4284
  /**
4285
  * Drill down (through composites and empty components) until we get a host or
4286
  * host text component.
4346
  }
4347
  // We assume the child nodes are in the same order as the child instances.
4348
  for (; childNode !== null; childNode = childNode.nextSibling) {
4349
+ if (shouldPrecacheNode(childNode, childID)) {
4350
  precacheNode(childInst, childNode);
4351
  continue outer;
4352
  }
6519
  /* 51 */
6520
  /***/ function(module, exports) {
6521
 
6522
+ /*
6523
+ object-assign
6524
+ (c) Sindre Sorhus
6525
+ @license MIT
6526
+ */
6527
+
6528
  'use strict';
6529
  /* eslint-disable no-unused-vars */
6530
+ var getOwnPropertySymbols = Object.getOwnPropertySymbols;
6531
  var hasOwnProperty = Object.prototype.hasOwnProperty;
6532
  var propIsEnumerable = Object.prototype.propertyIsEnumerable;
6533
 
6548
  // Detect buggy property enumeration order in older V8 versions.
6549
 
6550
  // https://bugs.chromium.org/p/v8/issues/detail?id=4118
6551
+ var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
6552
  test1[5] = 'de';
6553
  if (Object.getOwnPropertyNames(test1)[0] === '5') {
6554
  return false;
6577
  }
6578
 
6579
  return true;
6580
+ } catch (err) {
6581
  // We don't expect any of the above to throw, but better to be safe.
6582
  return false;
6583
  }
6597
  }
6598
  }
6599
 
6600
+ if (getOwnPropertySymbols) {
6601
+ symbols = getOwnPropertySymbols(from);
6602
  for (var i = 0; i < symbols.length; i++) {
6603
  if (propIsEnumerable.call(from, symbols[i])) {
6604
  to[symbols[i]] = from[symbols[i]];
6683
  }
6684
  };
6685
 
 
 
 
 
 
 
 
 
 
 
 
6686
  var standardReleaser = function (instance) {
6687
  var Klass = this;
6688
  !(instance instanceof Klass) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Trying to release an instance into a pool of a different type.') : _prodInvariant('25') : void 0;
6722
  oneArgumentPooler: oneArgumentPooler,
6723
  twoArgumentPooler: twoArgumentPooler,
6724
  threeArgumentPooler: threeArgumentPooler,
6725
+ fourArgumentPooler: fourArgumentPooler
 
6726
  };
6727
 
6728
  module.exports = PooledClass;
11540
  } else {
11541
  var contentToUse = CONTENT_TYPES[typeof props.children] ? props.children : null;
11542
  var childrenToUse = contentToUse != null ? null : props.children;
11543
+ // TODO: Validate that text is allowed as a child of this node
11544
  if (contentToUse != null) {
11545
+ // Avoid setting textContent when the text is empty. In IE11 setting
11546
+ // textContent on a text area will cause the placeholder to not
11547
+ // show within the textarea until it has been focused and blurred again.
11548
+ // https://github.com/facebook/react/issues/6731#issuecomment-254874553
11549
+ if (contentToUse !== '') {
11550
+ if (process.env.NODE_ENV !== 'production') {
11551
+ setAndValidateContentChildDev.call(this, contentToUse);
11552
+ }
11553
+ DOMLazyTree.queueText(lazyTree, contentToUse);
11554
  }
 
11555
  } else if (childrenToUse != null) {
11556
  var mountImages = this.mountChildren(childrenToUse, transaction, context);
11557
  for (var i = 0; i < mountImages.length; i++) {
13471
  }
13472
  } else {
13473
  if (props.value == null && props.defaultValue != null) {
13474
+ // In Chrome, assigning defaultValue to certain input types triggers input validation.
13475
+ // For number inputs, the display value loses trailing decimal points. For email inputs,
13476
+ // Chrome raises "The specified value <x> is not a valid email address".
13477
+ //
13478
+ // Here we check to see if the defaultValue has actually changed, avoiding these problems
13479
+ // when the user is inputting text
13480
+ //
13481
+ // https://github.com/facebook/react/issues/7253
13482
+ if (node.defaultValue !== '' + props.defaultValue) {
13483
+ node.defaultValue = '' + props.defaultValue;
13484
+ }
13485
  }
13486
  if (props.checked == null && props.defaultChecked != null) {
13487
  node.defaultChecked = !!props.defaultChecked;
14228
  // This is in postMount because we need access to the DOM node, which is not
14229
  // available until after the component has mounted.
14230
  var node = ReactDOMComponentTree.getNodeFromInstance(inst);
14231
+ var textContent = node.textContent;
14232
 
14233
+ // Only set node.value if textContent is equal to the expected
14234
+ // initial value. In IE10/IE11 there is a bug where the placeholder attribute
14235
+ // will populate textContent as well.
14236
+ // https://developer.microsoft.com/microsoft-edge/platform/issues/101525/
14237
+ if (textContent === inst._wrapperState.initialValue) {
14238
+ node.value = textContent;
14239
+ }
14240
  }
14241
  };
14242
 
15038
  instance = ReactEmptyComponent.create(instantiateReactComponent);
15039
  } else if (typeof node === 'object') {
15040
  var element = node;
15041
+ var type = element.type;
15042
+ if (typeof type !== 'function' && typeof type !== 'string') {
15043
+ var info = '';
15044
+ if (process.env.NODE_ENV !== 'production') {
15045
+ if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {
15046
+ info += ' You likely forgot to export your component from the file ' + 'it\'s defined in.';
15047
+ }
15048
+ }
15049
+ info += getDeclarationErrorAddendum(element._owner);
15050
+ true ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s', type == null ? type : typeof type, info) : _prodInvariant('130', type == null ? type : typeof type, info) : void 0;
15051
+ }
15052
 
15053
  // Special case string values
15054
  if (typeof element.type === 'string') {
15338
  // Since plain JS classes are defined without any special initialization
15339
  // logic, we can not catch common errors early. Therefore, we have to
15340
  // catch them here, at initialization time, instead.
15341
+ process.env.NODE_ENV !== 'production' ? warning(!inst.getInitialState || inst.getInitialState.isReactClassApproved || inst.state, 'getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', this.getName() || 'a component') : void 0;
15342
  process.env.NODE_ENV !== 'production' ? warning(!inst.getDefaultProps || inst.getDefaultProps.isReactClassApproved, 'getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', this.getName() || 'a component') : void 0;
15343
  process.env.NODE_ENV !== 'production' ? warning(!inst.propTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', this.getName() || 'a component') : void 0;
15344
  process.env.NODE_ENV !== 'production' ? warning(!inst.contextTypes, 'contextTypes was defined as an instance property on %s. Use a ' + 'static property to define contextTypes instead.', this.getName() || 'a component') : void 0;
16342
 
16343
  'use strict';
16344
 
16345
+ var _prodInvariant = __webpack_require__(36);
 
16346
 
16347
  var invariant = __webpack_require__(9);
16348
 
16349
  var genericComponentClass = null;
 
 
16350
  var textComponentClass = null;
16351
 
16352
  var ReactHostComponentInjection = {
16359
  // rendered as props.
16360
  injectTextComponentClass: function (componentClass) {
16361
  textComponentClass = componentClass;
 
 
 
 
 
16362
  }
16363
  };
16364
 
21213
 
21214
  'use strict';
21215
 
21216
+ module.exports = '15.4.2';
21217
 
21218
  /***/ },
21219
  /* 174 */
21888
 
21889
  var match = void 0,
21890
  lastIndex = 0,
21891
+ matcher = /:([a-zA-Z_$][a-zA-Z0-9_$]*)|\*\*|\*|\(|\)|\\\(|\\\)/g;
21892
  while (match = matcher.exec(pattern)) {
21893
  if (match.index !== lastIndex) {
21894
  tokens.push(pattern.slice(lastIndex, match.index));
21908
  regexpSource += '(?:';
21909
  } else if (match[0] === ')') {
21910
  regexpSource += ')?';
21911
+ } else if (match[0] === '\\(') {
21912
+ regexpSource += '\\(';
21913
+ } else if (match[0] === '\\)') {
21914
+ regexpSource += '\\)';
21915
  }
21916
 
21917
  tokens.push(match[0]);
22066
  parenCount -= 1;
22067
 
22068
  if (parenCount) parenHistory[parenCount - 1] += parenText;else pathname += parenText;
22069
+ } else if (token === '\\(') {
22070
+ pathname += '(';
22071
+ } else if (token === '\\)') {
22072
+ pathname += ')';
22073
  } else if (token.charAt(0) === ':') {
22074
  paramName = token.substring(1);
22075
  paramValue = params[paramName];
22937
  return runTransitionHooks(hooks.length, function (index, replace, next) {
22938
  var wrappedNext = function wrappedNext() {
22939
  if (enterHooks.has(hooks[index])) {
22940
+ next.apply(undefined, arguments);
22941
  enterHooks.remove(hooks[index]);
22942
  }
22943
  };
22961
  return runTransitionHooks(hooks.length, function (index, replace, next) {
22962
  var wrappedNext = function wrappedNext() {
22963
  if (changeHooks.has(hooks[index])) {
22964
+ next.apply(undefined, arguments);
22965
  changeHooks.remove(hooks[index]);
22966
  }
22967
  };
23363
  if ((0, _PromiseUtils.isPromise)(indexRoutesReturn)) indexRoutesReturn.then(function (indexRoute) {
23364
  return callback(null, (0, _RouteUtils.createRoutes)(indexRoute)[0]);
23365
  }, callback);
23366
+ } else if (route.childRoutes || route.getChildRoutes) {
23367
+ var onChildRoutes = function onChildRoutes(error, childRoutes) {
23368
+ if (error) {
23369
+ callback(error);
23370
+ return;
23371
+ }
23372
+
23373
+ var pathless = childRoutes.filter(function (childRoute) {
23374
  return !childRoute.path;
23375
  });
23376
 
23386
  }, function (err, routes) {
23387
  callback(null, routes);
23388
  });
23389
+ };
23390
+
23391
+ var result = getChildRoutes(route, location, paramNames, paramValues, onChildRoutes);
23392
+ if (result) {
23393
+ onChildRoutes.apply(undefined, result);
23394
+ }
23395
  } else {
23396
  callback();
23397
  }
23445
  // By assumption, pattern is non-empty here, which is the prerequisite for
23446
  // actually terminating a match.
23447
  if (remainingPathname === '') {
23448
+ var _ret = function () {
23449
  var match = {
23450
  routes: [route],
23451
  params: createParams(paramNames, paramValues)
23476
  };
23477
  }();
23478
 
23479
+ if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
23480
  }
23481
  }
23482
 
24054
 
24055
  if (router) {
24056
  // If user does not specify a `to` prop, return an empty anchor tag.
24057
+ if (!to) {
24058
  return _react2.default.createElement('a', props);
24059
  }
24060
 
24171
  var _this = this;
24172
 
24173
  var router = this.props.router || this.context.router;
24174
+ if (!router) {
24175
+ return _react2.default.createElement(WrappedComponent, this.props);
24176
+ }
24177
+
24178
  var params = router.params,
24179
  location = router.location,
24180
  routes = router.routes;
24840
  var strictUriEncode = __webpack_require__(214);
24841
  var objectAssign = __webpack_require__(215);
24842
 
24843
+ function encoderForArrayFormat(opts) {
24844
+ switch (opts.arrayFormat) {
24845
+ case 'index':
24846
+ return function (key, value, index) {
24847
+ return value === null ? [
24848
+ encode(key, opts),
24849
+ '[',
24850
+ index,
24851
+ ']'
24852
+ ].join('') : [
24853
+ encode(key, opts),
24854
+ '[',
24855
+ encode(index, opts),
24856
+ ']=',
24857
+ encode(value, opts)
24858
+ ].join('');
24859
+ };
24860
+
24861
+ case 'bracket':
24862
+ return function (key, value) {
24863
+ return value === null ? encode(key, opts) : [
24864
+ encode(key, opts),
24865
+ '[]=',
24866
+ encode(value, opts)
24867
+ ].join('');
24868
+ };
24869
+
24870
+ default:
24871
+ return function (key, value) {
24872
+ return value === null ? encode(key, opts) : [
24873
+ encode(key, opts),
24874
+ '=',
24875
+ encode(value, opts)
24876
+ ].join('');
24877
+ };
24878
+ }
24879
+ }
24880
+
24881
+ function parserForArrayFormat(opts) {
24882
+ var result;
24883
+
24884
+ switch (opts.arrayFormat) {
24885
+ case 'index':
24886
+ return function (key, value, accumulator) {
24887
+ result = /\[(\d*)]$/.exec(key);
24888
+
24889
+ key = key.replace(/\[\d*]$/, '');
24890
+
24891
+ if (!result) {
24892
+ accumulator[key] = value;
24893
+ return;
24894
+ }
24895
+
24896
+ if (accumulator[key] === undefined) {
24897
+ accumulator[key] = {};
24898
+ }
24899
+
24900
+ accumulator[key][result[1]] = value;
24901
+ };
24902
+
24903
+ case 'bracket':
24904
+ return function (key, value, accumulator) {
24905
+ result = /(\[])$/.exec(key);
24906
+
24907
+ key = key.replace(/\[]$/, '');
24908
+
24909
+ if (!result || accumulator[key] === undefined) {
24910
+ accumulator[key] = value;
24911
+ return;
24912
+ }
24913
+
24914
+ accumulator[key] = [].concat(accumulator[key], value);
24915
+ };
24916
+
24917
+ default:
24918
+ return function (key, value, accumulator) {
24919
+ if (accumulator[key] === undefined) {
24920
+ accumulator[key] = value;
24921
+ return;
24922
+ }
24923
+
24924
+ accumulator[key] = [].concat(accumulator[key], value);
24925
+ };
24926
+ }
24927
+ }
24928
+
24929
  function encode(value, opts) {
24930
  if (opts.encode) {
24931
  return opts.strict ? strictUriEncode(value) : encodeURIComponent(value);
24934
  return value;
24935
  }
24936
 
24937
+ function keysSorter(input) {
24938
+ if (Array.isArray(input)) {
24939
+ return input.sort();
24940
+ } else if (typeof input === 'object') {
24941
+ return keysSorter(Object.keys(input)).sort(function (a, b) {
24942
+ return Number(a) - Number(b);
24943
+ }).map(function (key) {
24944
+ return input[key];
24945
+ });
24946
+ }
24947
+
24948
+ return input;
24949
+ }
24950
+
24951
  exports.extract = function (str) {
24952
  return str.split('?')[1] || '';
24953
  };
24954
 
24955
+ exports.parse = function (str, opts) {
24956
+ opts = objectAssign({arrayFormat: 'none'}, opts);
24957
+
24958
+ var formatter = parserForArrayFormat(opts);
24959
+
24960
  // Create an object with no prototype
24961
  // https://github.com/sindresorhus/query-string/issues/47
24962
  var ret = Object.create(null);
24978
  var key = parts.shift();
24979
  var val = parts.length > 0 ? parts.join('=') : undefined;
24980
 
 
 
24981
  // missing `=` should be `null`:
24982
  // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
24983
  val = val === undefined ? null : decodeURIComponent(val);
24984
 
24985
+ formatter(decodeURIComponent(key), val, ret);
24986
+ });
24987
+
24988
+ return Object.keys(ret).sort().reduce(function (result, key) {
24989
+ var val = ret[key];
24990
+ if (Boolean(val) && typeof val === 'object' && !Array.isArray(val)) {
24991
+ // Sort object keys, not values
24992
+ result[key] = keysSorter(val);
24993
  } else {
24994
+ result[key] = val;
24995
  }
 
24996
 
24997
+ return result;
24998
+ }, Object.create(null));
24999
  };
25000
 
25001
  exports.stringify = function (obj, opts) {
25002
  var defaults = {
25003
  encode: true,
25004
+ strict: true,
25005
+ arrayFormat: 'none'
25006
  };
25007
 
25008
  opts = objectAssign(defaults, opts);
25009
 
25010
+ var formatter = encoderForArrayFormat(opts);
25011
+
25012
  return obj ? Object.keys(obj).sort().map(function (key) {
25013
  var val = obj[key];
25014
 
25028
  return;
25029
  }
25030
 
25031
+ result.push(formatter(key, val2, result.length));
 
 
 
 
25032
  });
25033
 
25034
  return result.join('&');
25057
  /* 215 */
25058
  /***/ function(module, exports) {
25059
 
25060
+ /*
25061
+ object-assign
25062
+ (c) Sindre Sorhus
25063
+ @license MIT
25064
+ */
25065
+
25066
  'use strict';
25067
  /* eslint-disable no-unused-vars */
25068
+ var getOwnPropertySymbols = Object.getOwnPropertySymbols;
25069
  var hasOwnProperty = Object.prototype.hasOwnProperty;
25070
  var propIsEnumerable = Object.prototype.propertyIsEnumerable;
25071
 
25086
  // Detect buggy property enumeration order in older V8 versions.
25087
 
25088
  // https://bugs.chromium.org/p/v8/issues/detail?id=4118
25089
+ var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
25090
  test1[5] = 'de';
25091
  if (Object.getOwnPropertyNames(test1)[0] === '5') {
25092
  return false;
25115
  }
25116
 
25117
  return true;
25118
+ } catch (err) {
25119
  // We don't expect any of the above to throw, but better to be safe.
25120
  return false;
25121
  }
25135
  }
25136
  }
25137
 
25138
+ if (getOwnPropertySymbols) {
25139
+ symbols = getOwnPropertySymbols(from);
25140
  for (var i = 0; i < symbols.length; i++) {
25141
  if (propIsEnumerable.call(from, symbols[i])) {
25142
  to[symbols[i]] = from[symbols[i]];
assets/js/form_editor.js CHANGED
@@ -2077,12 +2077,12 @@ webpackJsonp([1],{
2077
  var bidiOrdering = (function() {
2078
  // Character types for codepoints 0 to 0xff
2079
  var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"
2080
- // Character types for codepoints 0x600 to 0x6ff
2081
- var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"
2082
  function charType(code) {
2083
  if (code <= 0xf7) { return lowTypes.charAt(code) }
2084
  else if (0x590 <= code && code <= 0x5f4) { return "R" }
2085
- else if (0x600 <= code && code <= 0x6ed) { return arabicTypes.charAt(code - 0x600) }
2086
  else if (0x6ee <= code && code <= 0x8ac) { return "r" }
2087
  else if (0x2000 <= code && code <= 0x200b) { return "w" }
2088
  else if (code == 0x200c) { return "b" }
@@ -4388,7 +4388,7 @@ webpackJsonp([1],{
4388
  }
4389
  }
4390
 
4391
- function NativeScrollbars(place, scroll, cm) {
4392
  this.cm = cm
4393
  var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar")
4394
  var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar")
@@ -4404,91 +4404,92 @@ webpackJsonp([1],{
4404
  this.checkedZeroWidth = false
4405
  // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
4406
  if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px" }
4407
- }
4408
-
4409
- NativeScrollbars.prototype = copyObj({
4410
- update: function(measure) {
4411
- var needsH = measure.scrollWidth > measure.clientWidth + 1
4412
- var needsV = measure.scrollHeight > measure.clientHeight + 1
4413
- var sWidth = measure.nativeBarWidth
4414
-
4415
- if (needsV) {
4416
- this.vert.style.display = "block"
4417
- this.vert.style.bottom = needsH ? sWidth + "px" : "0"
4418
- var totalHeight = measure.viewHeight - (needsH ? sWidth : 0)
4419
- // A bug in IE8 can cause this value to be negative, so guard it.
4420
- this.vert.firstChild.style.height =
4421
- Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"
4422
- } else {
4423
- this.vert.style.display = ""
4424
- this.vert.firstChild.style.height = "0"
4425
- }
4426
-
4427
- if (needsH) {
4428
- this.horiz.style.display = "block"
4429
- this.horiz.style.right = needsV ? sWidth + "px" : "0"
4430
- this.horiz.style.left = measure.barLeft + "px"
4431
- var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0)
4432
- this.horiz.firstChild.style.width =
4433
- (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"
4434
- } else {
4435
- this.horiz.style.display = ""
4436
- this.horiz.firstChild.style.width = "0"
4437
- }
4438
-
4439
- if (!this.checkedZeroWidth && measure.clientHeight > 0) {
4440
- if (sWidth == 0) { this.zeroWidthHack() }
4441
- this.checkedZeroWidth = true
4442
- }
4443
-
4444
- return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
4445
- },
4446
- setScrollLeft: function(pos) {
4447
- if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos }
4448
- if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz) }
4449
- },
4450
- setScrollTop: function(pos) {
4451
- if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos }
4452
- if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert) }
4453
- },
4454
- zeroWidthHack: function() {
4455
- var w = mac && !mac_geMountainLion ? "12px" : "18px"
4456
- this.horiz.style.height = this.vert.style.width = w
4457
- this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"
4458
- this.disableHoriz = new Delayed
4459
- this.disableVert = new Delayed
4460
- },
4461
- enableZeroWidthBar: function(bar, delay) {
4462
- bar.style.pointerEvents = "auto"
4463
- function maybeDisable() {
4464
- // To find out whether the scrollbar is still visible, we
4465
- // check whether the element under the pixel in the bottom
4466
- // left corner of the scrollbar box is the scrollbar box
4467
- // itself (when the bar is still visible) or its filler child
4468
- // (when the bar is hidden). If it is still visible, we keep
4469
- // it enabled, if it's hidden, we disable pointer events.
4470
- var box = bar.getBoundingClientRect()
4471
- var elt = document.elementFromPoint(box.left + 1, box.bottom - 1)
4472
- if (elt != bar) { bar.style.pointerEvents = "none" }
4473
- else { delay.set(1000, maybeDisable) }
4474
- }
4475
- delay.set(1000, maybeDisable)
4476
- },
4477
- clear: function() {
4478
- var parent = this.horiz.parentNode
4479
- parent.removeChild(this.horiz)
4480
- parent.removeChild(this.vert)
4481
  }
4482
- }, NativeScrollbars.prototype)
4483
-
4484
- function NullScrollbars() {}
4485
 
4486
- NullScrollbars.prototype = copyObj({
4487
- update: function() { return {bottom: 0, right: 0} },
4488
- setScrollLeft: function() {},
4489
- setScrollTop: function() {},
4490
- clear: function() {}
4491
- }, NullScrollbars.prototype)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4492
 
4493
  function updateScrollbars(cm, measure) {
4494
  if (!measure) { measure = measureForScrollbars(cm) }
@@ -5067,7 +5068,7 @@ webpackJsonp([1],{
5067
 
5068
  // DISPLAY DRAWING
5069
 
5070
- function DisplayUpdate(cm, viewport, force) {
5071
  var display = cm.display
5072
 
5073
  this.viewport = viewport
@@ -5080,18 +5081,18 @@ webpackJsonp([1],{
5080
  this.force = force
5081
  this.dims = getDimensions(cm)
5082
  this.events = []
5083
- }
5084
 
5085
- DisplayUpdate.prototype.signal = function(emitter, type) {
5086
  if (hasHandler(emitter, type))
5087
  { this.events.push(arguments) }
5088
- }
5089
- DisplayUpdate.prototype.finish = function() {
5090
- var this$1 = this;
5091
 
5092
  for (var i = 0; i < this.events.length; i++)
5093
  { signal.apply(null, this$1.events[i]) }
5094
- }
5095
 
5096
  function maybeClipScrollbars(cm) {
5097
  var display = cm.display
@@ -8219,7 +8220,7 @@ webpackJsonp([1],{
8219
  for (var i = newBreaks.length - 1; i >= 0; i--)
8220
  { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) }
8221
  })
8222
- option("specialChars", /[\u0000-\u001f\u007f\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
8223
  cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g")
8224
  if (old != Init) { cm.refresh() }
8225
  })
@@ -8309,7 +8310,7 @@ webpackJsonp([1],{
8309
  function guttersChanged(cm) {
8310
  updateGutters(cm)
8311
  regChange(cm)
8312
- setTimeout(function () { return alignHorizontally(cm); }, 20)
8313
  }
8314
 
8315
  function dragDropChanged(cm, value, old) {
@@ -8364,7 +8365,6 @@ webpackJsonp([1],{
8364
  themeChanged(this)
8365
  if (options.lineWrapping)
8366
  { this.display.wrapper.className += " CodeMirror-wrap" }
8367
- if (options.autofocus && !mobile) { display.input.focus() }
8368
  initScrollbars(this)
8369
 
8370
  this.state = {
@@ -8383,6 +8383,8 @@ webpackJsonp([1],{
8383
  specialChars: null
8384
  }
8385
 
 
 
8386
  // Override magic textarea content restore that IE sometimes does
8387
  // on our hidden textarea on reload
8388
  if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20) }
@@ -8738,6 +8740,7 @@ webpackJsonp([1],{
8738
  options[option] = value
8739
  if (optionHandlers.hasOwnProperty(option))
8740
  { operation(this, optionHandlers[option])(this, value, old) }
 
8741
  },
8742
 
8743
  getOption: function(option) {return this.options[option]},
@@ -9245,331 +9248,333 @@ webpackJsonp([1],{
9245
 
9246
  // CONTENTEDITABLE INPUT STYLE
9247
 
9248
- function ContentEditableInput(cm) {
9249
  this.cm = cm
9250
  this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null
9251
  this.polling = new Delayed()
9252
  this.composing = null
9253
  this.gracePeriod = false
9254
  this.readDOMTimeout = null
9255
- }
9256
 
9257
- ContentEditableInput.prototype = copyObj({
9258
- init: function(display) {
9259
  var this$1 = this;
9260
 
9261
- var input = this, cm = input.cm
9262
- var div = input.div = display.lineDiv
9263
- disableBrowserMagic(div, cm.options.spellcheck)
9264
 
9265
- on(div, "paste", function (e) {
9266
- if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
9267
- // IE doesn't fire input events, so we schedule a read for the pasted content in this way
9268
- if (ie_version <= 11) { setTimeout(operation(cm, function () {
9269
- if (!input.pollContent()) { regChange(cm) }
9270
- }), 20) }
9271
- })
9272
 
9273
- on(div, "compositionstart", function (e) {
9274
- this$1.composing = {data: e.data}
9275
- })
9276
- on(div, "compositionupdate", function (e) {
9277
- if (!this$1.composing) { this$1.composing = {data: e.data} }
9278
- })
9279
- on(div, "compositionend", function (e) {
9280
- if (this$1.composing) {
9281
- if (e.data != this$1.composing.data) { this$1.readFromDOMSoon() }
9282
- this$1.composing = null
9283
- }
9284
- })
9285
 
9286
- on(div, "touchstart", function () { return input.forceCompositionEnd(); })
9287
 
9288
- on(div, "input", function () {
9289
- if (!this$1.composing) { this$1.readFromDOMSoon() }
9290
- })
9291
 
9292
- function onCopyCut(e) {
9293
- if (signalDOMEvent(cm, e)) { return }
9294
- if (cm.somethingSelected()) {
9295
- setLastCopied({lineWise: false, text: cm.getSelections()})
9296
- if (e.type == "cut") { cm.replaceSelection("", null, "cut") }
9297
- } else if (!cm.options.lineWiseCopyCut) {
9298
- return
9299
- } else {
9300
- var ranges = copyableRanges(cm)
9301
- setLastCopied({lineWise: true, text: ranges.text})
9302
- if (e.type == "cut") {
9303
- cm.operation(function () {
9304
- cm.setSelections(ranges.ranges, 0, sel_dontScroll)
9305
- cm.replaceSelection("", null, "cut")
9306
- })
9307
- }
9308
  }
9309
- if (e.clipboardData) {
9310
- e.clipboardData.clearData()
9311
- var content = lastCopied.text.join("\n")
9312
- // iOS exposes the clipboard API, but seems to discard content inserted into it
9313
- e.clipboardData.setData("Text", content)
9314
- if (e.clipboardData.getData("Text") == content) {
9315
- e.preventDefault()
9316
- return
9317
- }
9318
  }
9319
- // Old-fashioned briefly-focus-a-textarea hack
9320
- var kludge = hiddenTextarea(), te = kludge.firstChild
9321
- cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild)
9322
- te.value = lastCopied.text.join("\n")
9323
- var hadFocus = document.activeElement
9324
- selectInput(te)
9325
- setTimeout(function () {
9326
- cm.display.lineSpace.removeChild(kludge)
9327
- hadFocus.focus()
9328
- if (hadFocus == div) { input.showPrimarySelection() }
9329
- }, 50)
9330
  }
9331
- on(div, "copy", onCopyCut)
9332
- on(div, "cut", onCopyCut)
9333
- },
9334
-
9335
- prepareSelection: function() {
9336
- var result = prepareSelection(this.cm, false)
9337
- result.focus = this.cm.state.focused
9338
- return result
9339
- },
9340
-
9341
- showSelection: function(info, takeFocus) {
9342
- if (!info || !this.cm.display.view.length) { return }
9343
- if (info.focus || takeFocus) { this.showPrimarySelection() }
9344
- this.showMultipleSelections(info)
9345
- },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9346
 
9347
- showPrimarySelection: function() {
9348
- var sel = window.getSelection(), prim = this.cm.doc.sel.primary()
9349
- var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset)
9350
- var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset)
9351
- if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
9352
- cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&
9353
- cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
9354
- { return }
9355
-
9356
- var start = posToDOM(this.cm, prim.from())
9357
- var end = posToDOM(this.cm, prim.to())
9358
- if (!start && !end) { return }
9359
-
9360
- var view = this.cm.display.view
9361
- var old = sel.rangeCount && sel.getRangeAt(0)
9362
- if (!start) {
9363
- start = {node: view[0].measure.map[2], offset: 0}
9364
- } else if (!end) { // FIXME dangerously hacky
9365
- var measure = view[view.length - 1].measure
9366
- var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map
9367
- end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}
9368
- }
9369
-
9370
- var rng
9371
- try { rng = range(start.node, start.offset, end.offset, end.node) }
9372
- catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
9373
- if (rng) {
9374
- if (!gecko && this.cm.state.focused) {
9375
- sel.collapse(start.node, start.offset)
9376
- if (!rng.collapsed) {
9377
- sel.removeAllRanges()
9378
- sel.addRange(rng)
9379
- }
9380
- } else {
9381
  sel.removeAllRanges()
9382
  sel.addRange(rng)
9383
  }
9384
- if (old && sel.anchorNode == null) { sel.addRange(old) }
9385
- else if (gecko) { this.startGracePeriod() }
 
9386
  }
9387
- this.rememberSelection()
9388
- },
 
 
 
9389
 
9390
- startGracePeriod: function() {
9391
  var this$1 = this;
9392
 
9393
- clearTimeout(this.gracePeriod)
9394
- this.gracePeriod = setTimeout(function () {
9395
- this$1.gracePeriod = false
9396
- if (this$1.selectionChanged())
9397
- { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }) }
9398
- }, 20)
9399
- },
9400
-
9401
- showMultipleSelections: function(info) {
9402
- removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors)
9403
- removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection)
9404
- },
9405
-
9406
- rememberSelection: function() {
9407
- var sel = window.getSelection()
9408
- this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset
9409
- this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset
9410
- },
9411
-
9412
- selectionInEditor: function() {
9413
- var sel = window.getSelection()
9414
- if (!sel.rangeCount) { return false }
9415
- var node = sel.getRangeAt(0).commonAncestorContainer
9416
- return contains(this.div, node)
9417
- },
9418
-
9419
- focus: function() {
9420
- if (this.cm.options.readOnly != "nocursor") {
9421
- if (!this.selectionInEditor())
9422
- { this.showSelection(this.prepareSelection(), true) }
9423
- this.div.focus()
9424
- }
9425
- },
9426
- blur: function() { this.div.blur() },
9427
- getField: function() { return this.div },
9428
-
9429
- supportsTouch: function() { return true },
9430
-
9431
- receivedFocus: function() {
9432
- var input = this
9433
- if (this.selectionInEditor())
9434
- { this.pollSelection() }
9435
- else
9436
- { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }) }
9437
 
9438
- function poll() {
9439
- if (input.cm.state.focused) {
9440
- input.pollSelection()
9441
- input.polling.set(input.cm.options.pollInterval, poll)
9442
- }
9443
- }
9444
- this.polling.set(this.cm.options.pollInterval, poll)
9445
- },
9446
 
9447
- selectionChanged: function() {
9448
- var sel = window.getSelection()
9449
- return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
9450
- sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
9451
- },
 
9452
 
9453
- pollSelection: function() {
9454
- if (!this.composing && this.readDOMTimeout == null && !this.gracePeriod && this.selectionChanged()) {
9455
- var sel = window.getSelection(), cm = this.cm
9456
- this.rememberSelection()
9457
- var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset)
9458
- var head = domToPos(cm, sel.focusNode, sel.focusOffset)
9459
- if (anchor && head) { runInOp(cm, function () {
9460
- setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll)
9461
- if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true }
9462
- }) }
9463
  }
9464
- },
 
 
9465
 
9466
- pollContent: function() {
9467
- if (this.readDOMTimeout != null) {
9468
- clearTimeout(this.readDOMTimeout)
9469
- this.readDOMTimeout = null
9470
- }
9471
 
9472
- var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary()
9473
- var from = sel.from(), to = sel.to()
9474
- if (from.ch == 0 && from.line > cm.firstLine())
9475
- { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length) }
9476
- if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
9477
- { to = Pos(to.line + 1, 0) }
9478
- if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9479
 
9480
- var fromIndex, fromLine, fromNode
9481
- if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
9482
- fromLine = lineNo(display.view[0].line)
9483
- fromNode = display.view[0].node
9484
- } else {
9485
- fromLine = lineNo(display.view[fromIndex].line)
9486
- fromNode = display.view[fromIndex - 1].node.nextSibling
9487
- }
9488
- var toIndex = findViewIndex(cm, to.line)
9489
- var toLine, toNode
9490
- if (toIndex == display.view.length - 1) {
9491
- toLine = display.viewTo - 1
9492
- toNode = display.lineDiv.lastChild
9493
- } else {
9494
- toLine = lineNo(display.view[toIndex + 1].line) - 1
9495
- toNode = display.view[toIndex + 1].node.previousSibling
9496
- }
9497
-
9498
- if (!fromNode) { return false }
9499
- var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine))
9500
- var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length))
9501
- while (newText.length > 1 && oldText.length > 1) {
9502
- if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine-- }
9503
- else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++ }
9504
- else { break }
9505
- }
9506
-
9507
- var cutFront = 0, cutEnd = 0
9508
- var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length)
9509
- while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
9510
- { ++cutFront }
9511
- var newBot = lst(newText), oldBot = lst(oldText)
9512
- var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
9513
- oldBot.length - (oldText.length == 1 ? cutFront : 0))
9514
- while (cutEnd < maxCutEnd &&
9515
- newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
9516
- { ++cutEnd }
9517
-
9518
- newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "")
9519
- newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "")
9520
-
9521
- var chFrom = Pos(fromLine, cutFront)
9522
- var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0)
9523
- if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
9524
- replaceRange(cm.doc, newText, chFrom, chTo, "+input")
9525
- return true
9526
- }
9527
- },
9528
 
9529
- ensurePolled: function() {
9530
- this.forceCompositionEnd()
9531
- },
9532
- reset: function() {
9533
- this.forceCompositionEnd()
9534
- },
9535
- forceCompositionEnd: function() {
9536
- if (!this.composing) { return }
9537
- this.composing = null
9538
- if (!this.pollContent()) { regChange(this.cm) }
9539
- this.div.blur()
9540
- this.div.focus()
9541
- },
9542
- readFromDOMSoon: function() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9543
  var this$1 = this;
9544
 
9545
- if (this.readDOMTimeout != null) { return }
9546
- this.readDOMTimeout = setTimeout(function () {
9547
- this$1.readDOMTimeout = null
9548
- if (this$1.composing) { return }
9549
- if (this$1.cm.isReadOnly() || !this$1.pollContent())
9550
- { runInOp(this$1.cm, function () { return regChange(this$1.cm); }) }
9551
- }, 80)
9552
- },
 
 
 
9553
 
9554
- setUneditable: function(node) {
9555
- node.contentEditable = "false"
9556
- },
9557
 
9558
- onKeyPress: function(e) {
9559
- e.preventDefault()
9560
- if (!this.cm.isReadOnly())
9561
- { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) }
9562
- },
9563
 
9564
- readOnlyChanged: function(val) {
9565
- this.div.contentEditable = String(val != "nocursor")
9566
- },
9567
 
9568
- onContextMenu: nothing,
9569
- resetPosition: nothing,
9570
 
9571
- needsContentAttribute: true
9572
- }, ContentEditableInput.prototype)
9573
 
9574
  function posToDOM(cm, pos) {
9575
  var view = findViewForLine(cm, pos.line)
@@ -9706,7 +9711,7 @@ webpackJsonp([1],{
9706
 
9707
  // TEXTAREA INPUT STYLE
9708
 
9709
- function TextareaInput(cm) {
9710
  this.cm = cm
9711
  // See input.poll and input.reset
9712
  this.prevInput = ""
@@ -9723,335 +9728,333 @@ webpackJsonp([1],{
9723
  // Used to work around IE issue with selection being forgotten when focus moves away from textarea
9724
  this.hasSelection = false
9725
  this.composing = null
9726
- }
9727
 
9728
- TextareaInput.prototype = copyObj({
9729
- init: function(display) {
9730
  var this$1 = this;
9731
 
9732
- var input = this, cm = this.cm
9733
 
9734
- // Wraps and hides input textarea
9735
- var div = this.wrapper = hiddenTextarea()
9736
- // The semihidden textarea that is focused when the editor is
9737
- // focused, and receives input.
9738
- var te = this.textarea = div.firstChild
9739
- display.wrapper.insertBefore(div, display.wrapper.firstChild)
9740
 
9741
- // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
9742
- if (ios) { te.style.width = "0px" }
9743
 
9744
- on(te, "input", function () {
9745
- if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null }
9746
- input.poll()
9747
- })
9748
 
9749
- on(te, "paste", function (e) {
9750
- if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
9751
 
9752
- cm.state.pasteIncoming = true
9753
- input.fastPoll()
9754
- })
9755
 
9756
- function prepareCopyCut(e) {
9757
- if (signalDOMEvent(cm, e)) { return }
9758
- if (cm.somethingSelected()) {
9759
- setLastCopied({lineWise: false, text: cm.getSelections()})
9760
- if (input.inaccurateSelection) {
9761
- input.prevInput = ""
9762
- input.inaccurateSelection = false
9763
- te.value = lastCopied.text.join("\n")
9764
- selectInput(te)
9765
- }
9766
- } else if (!cm.options.lineWiseCopyCut) {
9767
- return
 
 
 
 
 
9768
  } else {
9769
- var ranges = copyableRanges(cm)
9770
- setLastCopied({lineWise: true, text: ranges.text})
9771
- if (e.type == "cut") {
9772
- cm.setSelections(ranges.ranges, null, sel_dontScroll)
9773
- } else {
9774
- input.prevInput = ""
9775
- te.value = ranges.text.join("\n")
9776
- selectInput(te)
9777
- }
9778
  }
9779
- if (e.type == "cut") { cm.state.cutIncoming = true }
9780
  }
9781
- on(te, "cut", prepareCopyCut)
9782
- on(te, "copy", prepareCopyCut)
9783
-
9784
- on(display.scroller, "paste", function (e) {
9785
- if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
9786
- cm.state.pasteIncoming = true
9787
- input.focus()
9788
- })
9789
-
9790
- // Prevent normal selection in the editor (we handle our own)
9791
- on(display.lineSpace, "selectstart", function (e) {
9792
- if (!eventInWidget(display, e)) { e_preventDefault(e) }
9793
- })
9794
 
9795
- on(te, "compositionstart", function () {
9796
- var start = cm.getCursor("from")
9797
- if (input.composing) { input.composing.range.clear() }
9798
- input.composing = {
9799
- start: start,
9800
- range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
9801
- }
9802
- })
9803
- on(te, "compositionend", function () {
9804
- if (input.composing) {
9805
- input.poll()
9806
- input.composing.range.clear()
9807
- input.composing = null
9808
- }
9809
- })
9810
- },
9811
 
9812
- prepareSelection: function() {
9813
- // Redraw the selection and/or cursor
9814
- var cm = this.cm, display = cm.display, doc = cm.doc
9815
- var result = prepareSelection(cm)
9816
 
9817
- // Move the hidden textarea near the cursor to prevent scrolling artifacts
9818
- if (cm.options.moveInputWithCursor) {
9819
- var headPos = cursorCoords(cm, doc.sel.primary().head, "div")
9820
- var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect()
9821
- result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
9822
- headPos.top + lineOff.top - wrapOff.top))
9823
- result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
9824
- headPos.left + lineOff.left - wrapOff.left))
9825
  }
9826
-
9827
- return result
9828
- },
9829
-
9830
- showSelection: function(drawn) {
9831
- var cm = this.cm, display = cm.display
9832
- removeChildrenAndAdd(display.cursorDiv, drawn.cursors)
9833
- removeChildrenAndAdd(display.selectionDiv, drawn.selection)
9834
- if (drawn.teTop != null) {
9835
- this.wrapper.style.top = drawn.teTop + "px"
9836
- this.wrapper.style.left = drawn.teLeft + "px"
9837
  }
9838
- },
9839
-
9840
- // Reset the input to correspond to the selection (or to be empty,
9841
- // when not typing and nothing is selected)
9842
- reset: function(typing) {
9843
- if (this.contextMenuPending) { return }
9844
- var minimal, selected, cm = this.cm, doc = cm.doc
9845
- if (cm.somethingSelected()) {
9846
- this.prevInput = ""
9847
- var range = doc.sel.primary()
9848
- minimal = hasCopyEvent &&
9849
- (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000)
9850
- var content = minimal ? "-" : selected || cm.getSelection()
9851
- this.textarea.value = content
9852
- if (cm.state.focused) { selectInput(this.textarea) }
9853
- if (ie && ie_version >= 9) { this.hasSelection = content }
9854
- } else if (!typing) {
9855
- this.prevInput = this.textarea.value = ""
9856
- if (ie && ie_version >= 9) { this.hasSelection = null }
9857
- }
9858
- this.inaccurateSelection = minimal
9859
- },
9860
 
9861
- getField: function() { return this.textarea },
 
 
 
9862
 
9863
- supportsTouch: function() { return false },
 
 
 
 
 
 
 
 
9864
 
9865
- focus: function() {
9866
- if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
9867
- try { this.textarea.focus() }
9868
- catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
9869
- }
9870
- },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9871
 
9872
- blur: function() { this.textarea.blur() },
9873
 
9874
- resetPosition: function() {
9875
- this.wrapper.style.top = this.wrapper.style.left = 0
9876
- },
9877
 
9878
- receivedFocus: function() { this.slowPoll() },
 
 
 
 
 
9879
 
9880
- // Poll for input changes, using the normal rate of polling. This
9881
- // runs as long as the editor is focused.
9882
- slowPoll: function() {
9883
- var this$1 = this;
9884
 
9885
- if (this.pollingFast) { return }
9886
- this.polling.set(this.cm.options.pollInterval, function () {
9887
- this$1.poll()
9888
- if (this$1.cm.state.focused) { this$1.slowPoll() }
9889
- })
9890
- },
9891
 
9892
- // When an event has just come in that is likely to add or change
9893
- // something in the input textarea, we poll faster, to ensure that
9894
- // the change appears on the screen quickly.
9895
- fastPoll: function() {
9896
- var missed = false, input = this
9897
- input.pollingFast = true
9898
- function p() {
9899
- var changed = input.poll()
9900
- if (!changed && !missed) {missed = true; input.polling.set(60, p)}
9901
- else {input.pollingFast = false; input.slowPoll()}
9902
- }
9903
- input.polling.set(20, p)
9904
- },
9905
 
9906
- // Read input from the textarea, and update the document to match.
9907
- // When something is selected, it is present in the textarea, and
9908
- // selected (unless it is huge, in which case a placeholder is
9909
- // used). When nothing is selected, the cursor sits after previously
9910
- // seen text (can be empty), which is stored in prevInput (we must
9911
- // not reset the textarea when typing, because that breaks IME).
9912
- poll: function() {
9913
  var this$1 = this;
9914
 
9915
- var cm = this.cm, input = this.textarea, prevInput = this.prevInput
9916
- // Since this is called a *lot*, try to bail out as cheaply as
9917
- // possible when it is clear that nothing happened. hasSelection
9918
- // will be the case when there is a lot of text in the textarea,
9919
- // in which case reading its value would be expensive.
9920
- if (this.contextMenuPending || !cm.state.focused ||
9921
- (hasSelection(input) && !prevInput && !this.composing) ||
9922
- cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
9923
- { return false }
9924
-
9925
- var text = input.value
9926
- // If nothing changed, bail.
9927
- if (text == prevInput && !cm.somethingSelected()) { return false }
9928
- // Work around nonsensical selection resetting in IE9/10, and
9929
- // inexplicable appearance of private area unicode characters on
9930
- // some key combos in Mac (#2689).
9931
- if (ie && ie_version >= 9 && this.hasSelection === text ||
9932
- mac && /[\uf700-\uf7ff]/.test(text)) {
9933
- cm.display.input.reset()
9934
- return false
9935
- }
9936
-
9937
- if (cm.doc.sel == cm.display.selForContextMenu) {
9938
- var first = text.charCodeAt(0)
9939
- if (first == 0x200b && !prevInput) { prevInput = "\u200b" }
9940
- if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
9941
- }
9942
- // Find the part of the input that is actually new
9943
- var same = 0, l = Math.min(prevInput.length, text.length)
9944
- while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same }
9945
 
9946
- runInOp(cm, function () {
9947
- applyTextInput(cm, text.slice(same), prevInput.length - same,
9948
- null, this$1.composing ? "*compose" : null)
 
 
 
 
 
 
9949
 
9950
- // Don't leave long text in the textarea, since it makes further polling slow
9951
- if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = "" }
9952
- else { this$1.prevInput = text }
 
 
 
 
 
 
 
 
9953
 
9954
- if (this$1.composing) {
9955
- this$1.composing.range.clear()
9956
- this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
9957
- {className: "CodeMirror-composing"})
9958
- }
9959
- })
9960
- return true
9961
- },
9962
 
9963
- ensurePolled: function() {
9964
- if (this.pollingFast && this.poll()) { this.pollingFast = false }
9965
- },
9966
 
9967
- onKeyPress: function() {
9968
- if (ie && ie_version >= 9) { this.hasSelection = null }
9969
- this.fastPoll()
9970
- },
9971
 
9972
- onContextMenu: function(e) {
9973
- var input = this, cm = input.cm, display = cm.display, te = input.textarea
9974
- var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop
9975
- if (!pos || presto) { return } // Opera is difficult.
9976
-
9977
- // Reset the current text selection only if the click is done outside of the selection
9978
- // and 'resetSelectionOnContextMenu' option is true.
9979
- var reset = cm.options.resetSelectionOnContextMenu
9980
- if (reset && cm.doc.sel.contains(pos) == -1)
9981
- { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll) }
9982
-
9983
- var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText
9984
- input.wrapper.style.cssText = "position: absolute"
9985
- var wrapperBox = input.wrapper.getBoundingClientRect()
9986
- te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"
9987
- var oldScrollY
9988
- if (webkit) { oldScrollY = window.scrollY } // Work around Chrome issue (#2712)
9989
- display.input.focus()
9990
- if (webkit) { window.scrollTo(null, oldScrollY) }
9991
- display.input.reset()
9992
- // Adds "Select all" to context menu in FF
9993
- if (!cm.somethingSelected()) { te.value = input.prevInput = " " }
9994
- input.contextMenuPending = true
9995
- display.selForContextMenu = cm.doc.sel
9996
- clearTimeout(display.detectingSelectAll)
9997
-
9998
- // Select-all will be greyed out if there's nothing to select, so
9999
- // this adds a zero-width space so that we can later check whether
10000
- // it got selected.
10001
- function prepareSelectAllHack() {
10002
- if (te.selectionStart != null) {
10003
- var selected = cm.somethingSelected()
10004
- var extval = "\u200b" + (selected ? te.value : "")
10005
- te.value = "\u21da" // Used to catch context-menu undo
10006
- te.value = extval
10007
- input.prevInput = selected ? "" : "\u200b"
10008
- te.selectionStart = 1; te.selectionEnd = extval.length
10009
- // Re-set this, in case some other handler touched the
10010
- // selection in the meantime.
10011
- display.selForContextMenu = cm.doc.sel
10012
- }
10013
  }
10014
- function rehide() {
10015
- input.contextMenuPending = false
10016
- input.wrapper.style.cssText = oldWrapperCSS
10017
- te.style.cssText = oldCSS
10018
- if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos) }
10019
-
10020
- // Try to detect the user choosing select-all
10021
- if (te.selectionStart != null) {
10022
- if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack() }
10023
- var i = 0, poll = function () {
10024
- if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
10025
- te.selectionEnd > 0 && input.prevInput == "\u200b")
10026
- { operation(cm, selectAll)(cm) }
10027
- else if (i++ < 10) { display.detectingSelectAll = setTimeout(poll, 500) }
10028
- else { display.input.reset() }
10029
- }
10030
- display.detectingSelectAll = setTimeout(poll, 200)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10031
  }
 
10032
  }
 
10033
 
10034
- if (ie && ie_version >= 9) { prepareSelectAllHack() }
10035
- if (captureRightClick) {
10036
- e_stop(e)
10037
- var mouseup = function () {
10038
- off(window, "mouseup", mouseup)
10039
- setTimeout(rehide, 20)
10040
- }
10041
- on(window, "mouseup", mouseup)
10042
- } else {
10043
- setTimeout(rehide, 50)
10044
  }
10045
- },
 
 
 
 
10046
 
10047
- readOnlyChanged: function(val) {
10048
- if (!val) { this.reset() }
10049
- },
10050
 
10051
- setUneditable: nothing,
10052
 
10053
- needsContentAttribute: false
10054
- }, TextareaInput.prototype)
10055
 
10056
  function fromTextArea(textarea, options) {
10057
  options = options ? copyObj(options) : {}
@@ -10202,7 +10205,7 @@ webpackJsonp([1],{
10202
 
10203
  addLegacyProps(CodeMirror)
10204
 
10205
- CodeMirror.version = "5.21.0"
10206
 
10207
  return CodeMirror;
10208
 
@@ -10739,7 +10742,7 @@ webpackJsonp([1],{
10739
  "transition-property", "transition-timing-function", "unicode-bidi",
10740
  "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
10741
  "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
10742
- "voice-volume", "volume", "white-space", "widows", "width", "word-break",
10743
  "word-spacing", "word-wrap", "z-index",
10744
  // SVG-specific
10745
  "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
@@ -10813,7 +10816,7 @@ webpackJsonp([1],{
10813
  "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
10814
  "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
10815
  "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
10816
- "compact", "condensed", "contain", "content",
10817
  "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
10818
  "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
10819
  "decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
@@ -10856,7 +10859,7 @@ webpackJsonp([1],{
10856
  "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
10857
  "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
10858
  "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
10859
- "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
10860
  "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
10861
  "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
10862
  "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
@@ -10868,7 +10871,7 @@ webpackJsonp([1],{
10868
  "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
10869
  "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
10870
  "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
10871
- "scroll", "scrollbar", "se-resize", "searchfield",
10872
  "searchfield-cancel-button", "searchfield-decoration",
10873
  "searchfield-results-button", "searchfield-results-decoration",
10874
  "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
@@ -10886,9 +10889,9 @@ webpackJsonp([1],{
10886
  "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
10887
  "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
10888
  "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
10889
- "trad-chinese-formal", "trad-chinese-informal",
10890
  "translate", "translate3d", "translateX", "translateY", "translateZ",
10891
- "transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
10892
  "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
10893
  "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
10894
  "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
2077
  var bidiOrdering = (function() {
2078
  // Character types for codepoints 0 to 0xff
2079
  var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"
2080
+ // Character types for codepoints 0x600 to 0x6f9
2081
+ var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111"
2082
  function charType(code) {
2083
  if (code <= 0xf7) { return lowTypes.charAt(code) }
2084
  else if (0x590 <= code && code <= 0x5f4) { return "R" }
2085
+ else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
2086
  else if (0x6ee <= code && code <= 0x8ac) { return "r" }
2087
  else if (0x2000 <= code && code <= 0x200b) { return "w" }
2088
  else if (code == 0x200c) { return "b" }
4388
  }
4389
  }
4390
 
4391
+ var NativeScrollbars = function(place, scroll, cm) {
4392
  this.cm = cm
4393
  var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar")
4394
  var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar")
4404
  this.checkedZeroWidth = false
4405
  // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
4406
  if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px" }
4407
+ };
4408
+
4409
+ NativeScrollbars.prototype.update = function (measure) {
4410
+ var needsH = measure.scrollWidth > measure.clientWidth + 1
4411
+ var needsV = measure.scrollHeight > measure.clientHeight + 1
4412
+ var sWidth = measure.nativeBarWidth
4413
+
4414
+ if (needsV) {
4415
+ this.vert.style.display = "block"
4416
+ this.vert.style.bottom = needsH ? sWidth + "px" : "0"
4417
+ var totalHeight = measure.viewHeight - (needsH ? sWidth : 0)
4418
+ // A bug in IE8 can cause this value to be negative, so guard it.
4419
+ this.vert.firstChild.style.height =
4420
+ Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"
4421
+ } else {
4422
+ this.vert.style.display = ""
4423
+ this.vert.firstChild.style.height = "0"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4424
  }
 
 
 
4425
 
4426
+ if (needsH) {
4427
+ this.horiz.style.display = "block"
4428
+ this.horiz.style.right = needsV ? sWidth + "px" : "0"
4429
+ this.horiz.style.left = measure.barLeft + "px"
4430
+ var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0)
4431
+ this.horiz.firstChild.style.width =
4432
+ (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"
4433
+ } else {
4434
+ this.horiz.style.display = ""
4435
+ this.horiz.firstChild.style.width = "0"
4436
+ }
4437
+
4438
+ if (!this.checkedZeroWidth && measure.clientHeight > 0) {
4439
+ if (sWidth == 0) { this.zeroWidthHack() }
4440
+ this.checkedZeroWidth = true
4441
+ }
4442
+
4443
+ return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
4444
+ };
4445
+
4446
+ NativeScrollbars.prototype.setScrollLeft = function (pos) {
4447
+ if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos }
4448
+ if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz) }
4449
+ };
4450
+
4451
+ NativeScrollbars.prototype.setScrollTop = function (pos) {
4452
+ if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos }
4453
+ if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert) }
4454
+ };
4455
+
4456
+ NativeScrollbars.prototype.zeroWidthHack = function () {
4457
+ var w = mac && !mac_geMountainLion ? "12px" : "18px"
4458
+ this.horiz.style.height = this.vert.style.width = w
4459
+ this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"
4460
+ this.disableHoriz = new Delayed
4461
+ this.disableVert = new Delayed
4462
+ };
4463
+
4464
+ NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay) {
4465
+ bar.style.pointerEvents = "auto"
4466
+ function maybeDisable() {
4467
+ // To find out whether the scrollbar is still visible, we
4468
+ // check whether the element under the pixel in the bottom
4469
+ // left corner of the scrollbar box is the scrollbar box
4470
+ // itself (when the bar is still visible) or its filler child
4471
+ // (when the bar is hidden). If it is still visible, we keep
4472
+ // it enabled, if it's hidden, we disable pointer events.
4473
+ var box = bar.getBoundingClientRect()
4474
+ var elt = document.elementFromPoint(box.left + 1, box.bottom - 1)
4475
+ if (elt != bar) { bar.style.pointerEvents = "none" }
4476
+ else { delay.set(1000, maybeDisable) }
4477
+ }
4478
+ delay.set(1000, maybeDisable)
4479
+ };
4480
+
4481
+ NativeScrollbars.prototype.clear = function () {
4482
+ var parent = this.horiz.parentNode
4483
+ parent.removeChild(this.horiz)
4484
+ parent.removeChild(this.vert)
4485
+ };
4486
+
4487
+ var NullScrollbars = function () {};
4488
+
4489
+ NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };
4490
+ NullScrollbars.prototype.setScrollLeft = function () {};
4491
+ NullScrollbars.prototype.setScrollTop = function () {};
4492
+ NullScrollbars.prototype.clear = function () {};
4493
 
4494
  function updateScrollbars(cm, measure) {
4495
  if (!measure) { measure = measureForScrollbars(cm) }
5068
 
5069
  // DISPLAY DRAWING
5070
 
5071
+ var DisplayUpdate = function(cm, viewport, force) {
5072
  var display = cm.display
5073
 
5074
  this.viewport = viewport
5081
  this.force = force
5082
  this.dims = getDimensions(cm)
5083
  this.events = []
5084
+ };
5085
 
5086
+ DisplayUpdate.prototype.signal = function (emitter, type) {
5087
  if (hasHandler(emitter, type))
5088
  { this.events.push(arguments) }
5089
+ };
5090
+ DisplayUpdate.prototype.finish = function () {
5091
+ var this$1 = this;
5092
 
5093
  for (var i = 0; i < this.events.length; i++)
5094
  { signal.apply(null, this$1.events[i]) }
5095
+ };
5096
 
5097
  function maybeClipScrollbars(cm) {
5098
  var display = cm.display
8220
  for (var i = newBreaks.length - 1; i >= 0; i--)
8221
  { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) }
8222
  })
8223
+ option("specialChars", /[\u0000-\u001f\u007f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
8224
  cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g")
8225
  if (old != Init) { cm.refresh() }
8226
  })
8310
  function guttersChanged(cm) {
8311
  updateGutters(cm)
8312
  regChange(cm)
8313
+ alignHorizontally(cm)
8314
  }
8315
 
8316
  function dragDropChanged(cm, value, old) {
8365
  themeChanged(this)
8366
  if (options.lineWrapping)
8367
  { this.display.wrapper.className += " CodeMirror-wrap" }
 
8368
  initScrollbars(this)
8369
 
8370
  this.state = {
8383
  specialChars: null
8384
  }
8385
 
8386
+ if (options.autofocus && !mobile) { display.input.focus() }
8387
+
8388
  // Override magic textarea content restore that IE sometimes does
8389
  // on our hidden textarea on reload
8390
  if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20) }
8740
  options[option] = value
8741
  if (optionHandlers.hasOwnProperty(option))
8742
  { operation(this, optionHandlers[option])(this, value, old) }
8743
+ signal(this, "optionChange", this, option)
8744
  },
8745
 
8746
  getOption: function(option) {return this.options[option]},
9248
 
9249
  // CONTENTEDITABLE INPUT STYLE
9250
 
9251
+ var ContentEditableInput = function(cm) {
9252
  this.cm = cm
9253
  this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null
9254
  this.polling = new Delayed()
9255
  this.composing = null
9256
  this.gracePeriod = false
9257
  this.readDOMTimeout = null
9258
+ };
9259
 
9260
+ ContentEditableInput.prototype.init = function (display) {
 
9261
  var this$1 = this;
9262
 
9263
+ var input = this, cm = input.cm
9264
+ var div = input.div = display.lineDiv
9265
+ disableBrowserMagic(div, cm.options.spellcheck)
9266
 
9267
+ on(div, "paste", function (e) {
9268
+ if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
9269
+ // IE doesn't fire input events, so we schedule a read for the pasted content in this way
9270
+ if (ie_version <= 11) { setTimeout(operation(cm, function () {
9271
+ if (!input.pollContent()) { regChange(cm) }
9272
+ }), 20) }
9273
+ })
9274
 
9275
+ on(div, "compositionstart", function (e) {
9276
+ this$1.composing = {data: e.data, done: false}
9277
+ })
9278
+ on(div, "compositionupdate", function (e) {
9279
+ if (!this$1.composing) { this$1.composing = {data: e.data, done: false} }
9280
+ })
9281
+ on(div, "compositionend", function (e) {
9282
+ if (this$1.composing) {
9283
+ if (e.data != this$1.composing.data) { this$1.readFromDOMSoon() }
9284
+ this$1.composing.done = true
9285
+ }
9286
+ })
9287
 
9288
+ on(div, "touchstart", function () { return input.forceCompositionEnd(); })
9289
 
9290
+ on(div, "input", function () {
9291
+ if (!this$1.composing) { this$1.readFromDOMSoon() }
9292
+ })
9293
 
9294
+ function onCopyCut(e) {
9295
+ if (signalDOMEvent(cm, e)) { return }
9296
+ if (cm.somethingSelected()) {
9297
+ setLastCopied({lineWise: false, text: cm.getSelections()})
9298
+ if (e.type == "cut") { cm.replaceSelection("", null, "cut") }
9299
+ } else if (!cm.options.lineWiseCopyCut) {
9300
+ return
9301
+ } else {
9302
+ var ranges = copyableRanges(cm)
9303
+ setLastCopied({lineWise: true, text: ranges.text})
9304
+ if (e.type == "cut") {
9305
+ cm.operation(function () {
9306
+ cm.setSelections(ranges.ranges, 0, sel_dontScroll)
9307
+ cm.replaceSelection("", null, "cut")
9308
+ })
 
9309
  }
9310
+ }
9311
+ if (e.clipboardData) {
9312
+ e.clipboardData.clearData()
9313
+ var content = lastCopied.text.join("\n")
9314
+ // iOS exposes the clipboard API, but seems to discard content inserted into it
9315
+ e.clipboardData.setData("Text", content)
9316
+ if (e.clipboardData.getData("Text") == content) {
9317
+ e.preventDefault()
9318
+ return
9319
  }
 
 
 
 
 
 
 
 
 
 
 
9320
  }
9321
+ // Old-fashioned briefly-focus-a-textarea hack
9322
+ var kludge = hiddenTextarea(), te = kludge.firstChild
9323
+ cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild)
9324
+ te.value = lastCopied.text.join("\n")
9325
+ var hadFocus = document.activeElement
9326
+ selectInput(te)
9327
+ setTimeout(function () {
9328
+ cm.display.lineSpace.removeChild(kludge)
9329
+ hadFocus.focus()
9330
+ if (hadFocus == div) { input.showPrimarySelection() }
9331
+ }, 50)
9332
+ }
9333
+ on(div, "copy", onCopyCut)
9334
+ on(div, "cut", onCopyCut)
9335
+ };
9336
+
9337
+ ContentEditableInput.prototype.prepareSelection = function () {
9338
+ var result = prepareSelection(this.cm, false)
9339
+ result.focus = this.cm.state.focused
9340
+ return result
9341
+ };
9342
+
9343
+ ContentEditableInput.prototype.showSelection = function (info, takeFocus) {
9344
+ if (!info || !this.cm.display.view.length) { return }
9345
+ if (info.focus || takeFocus) { this.showPrimarySelection() }
9346
+ this.showMultipleSelections(info)
9347
+ };
9348
+
9349
+ ContentEditableInput.prototype.showPrimarySelection = function () {
9350
+ var sel = window.getSelection(), prim = this.cm.doc.sel.primary()
9351
+ var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset)
9352
+ var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset)
9353
+ if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
9354
+ cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&
9355
+ cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
9356
+ { return }
9357
 
9358
+ var start = posToDOM(this.cm, prim.from())
9359
+ var end = posToDOM(this.cm, prim.to())
9360
+ if (!start && !end) { return }
9361
+
9362
+ var view = this.cm.display.view
9363
+ var old = sel.rangeCount && sel.getRangeAt(0)
9364
+ if (!start) {
9365
+ start = {node: view[0].measure.map[2], offset: 0}
9366
+ } else if (!end) { // FIXME dangerously hacky
9367
+ var measure = view[view.length - 1].measure
9368
+ var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map
9369
+ end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}
9370
+ }
9371
+
9372
+ var rng
9373
+ try { rng = range(start.node, start.offset, end.offset, end.node) }
9374
+ catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
9375
+ if (rng) {
9376
+ if (!gecko && this.cm.state.focused) {
9377
+ sel.collapse(start.node, start.offset)
9378
+ if (!rng.collapsed) {
 
 
 
 
 
 
 
 
 
 
 
 
 
9379
  sel.removeAllRanges()
9380
  sel.addRange(rng)
9381
  }
9382
+ } else {
9383
+ sel.removeAllRanges()
9384
+ sel.addRange(rng)
9385
  }
9386
+ if (old && sel.anchorNode == null) { sel.addRange(old) }
9387
+ else if (gecko) { this.startGracePeriod() }
9388
+ }
9389
+ this.rememberSelection()
9390
+ };
9391
 
9392
+ ContentEditableInput.prototype.startGracePeriod = function () {
9393
  var this$1 = this;
9394
 
9395
+ clearTimeout(this.gracePeriod)
9396
+ this.gracePeriod = setTimeout(function () {
9397
+ this$1.gracePeriod = false
9398
+ if (this$1.selectionChanged())
9399
+ { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }) }
9400
+ }, 20)
9401
+ };
9402
+
9403
+ ContentEditableInput.prototype.showMultipleSelections = function (info) {
9404
+ removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors)
9405
+ removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection)
9406
+ };
9407
+
9408
+ ContentEditableInput.prototype.rememberSelection = function () {
9409
+ var sel = window.getSelection()
9410
+ this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset
9411
+ this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset
9412
+ };
9413
+
9414
+ ContentEditableInput.prototype.selectionInEditor = function () {
9415
+ var sel = window.getSelection()
9416
+ if (!sel.rangeCount) { return false }
9417
+ var node = sel.getRangeAt(0).commonAncestorContainer
9418
+ return contains(this.div, node)
9419
+ };
9420
+
9421
+ ContentEditableInput.prototype.focus = function () {
9422
+ if (this.cm.options.readOnly != "nocursor") {
9423
+ if (!this.selectionInEditor())
9424
+ { this.showSelection(this.prepareSelection(), true) }
9425
+ this.div.focus()
9426
+ }
9427
+ };
9428
+ ContentEditableInput.prototype.blur = function () { this.div.blur() };
9429
+ ContentEditableInput.prototype.getField = function () { return this.div };
 
 
 
 
 
 
 
 
 
9430
 
9431
+ ContentEditableInput.prototype.supportsTouch = function () { return true };
 
 
 
 
 
 
 
9432
 
9433
+ ContentEditableInput.prototype.receivedFocus = function () {
9434
+ var input = this
9435
+ if (this.selectionInEditor())
9436
+ { this.pollSelection() }
9437
+ else
9438
+ { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }) }
9439
 
9440
+ function poll() {
9441
+ if (input.cm.state.focused) {
9442
+ input.pollSelection()
9443
+ input.polling.set(input.cm.options.pollInterval, poll)
 
 
 
 
 
 
9444
  }
9445
+ }
9446
+ this.polling.set(this.cm.options.pollInterval, poll)
9447
+ };
9448
 
9449
+ ContentEditableInput.prototype.selectionChanged = function () {
9450
+ var sel = window.getSelection()
9451
+ return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
9452
+ sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
9453
+ };
9454
 
9455
+ ContentEditableInput.prototype.pollSelection = function () {
9456
+ if (!this.composing && this.readDOMTimeout == null && !this.gracePeriod && this.selectionChanged()) {
9457
+ var sel = window.getSelection(), cm = this.cm
9458
+ this.rememberSelection()
9459
+ var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset)
9460
+ var head = domToPos(cm, sel.focusNode, sel.focusOffset)
9461
+ if (anchor && head) { runInOp(cm, function () {
9462
+ setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll)
9463
+ if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true }
9464
+ }) }
9465
+ }
9466
+ };
9467
+
9468
+ ContentEditableInput.prototype.pollContent = function () {
9469
+ if (this.readDOMTimeout != null) {
9470
+ clearTimeout(this.readDOMTimeout)
9471
+ this.readDOMTimeout = null
9472
+ }
9473
+
9474
+ var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary()
9475
+ var from = sel.from(), to = sel.to()
9476
+ if (from.ch == 0 && from.line > cm.firstLine())
9477
+ { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length) }
9478
+ if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
9479
+ { to = Pos(to.line + 1, 0) }
9480
+ if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
9481
+
9482
+ var fromIndex, fromLine, fromNode
9483
+ if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
9484
+ fromLine = lineNo(display.view[0].line)
9485
+ fromNode = display.view[0].node
9486
+ } else {
9487
+ fromLine = lineNo(display.view[fromIndex].line)
9488
+ fromNode = display.view[fromIndex - 1].node.nextSibling
9489
+ }
9490
+ var toIndex = findViewIndex(cm, to.line)
9491
+ var toLine, toNode
9492
+ if (toIndex == display.view.length - 1) {
9493
+ toLine = display.viewTo - 1
9494
+ toNode = display.lineDiv.lastChild
9495
+ } else {
9496
+ toLine = lineNo(display.view[toIndex + 1].line) - 1
9497
+ toNode = display.view[toIndex + 1].node.previousSibling
9498
+ }
9499
 
9500
+ if (!fromNode) { return false }
9501
+ var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine))
9502
+ var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length))
9503
+ while (newText.length > 1 && oldText.length > 1) {
9504
+ if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine-- }
9505
+ else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++ }
9506
+ else { break }
9507
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9508
 
9509
+ var cutFront = 0, cutEnd = 0
9510
+ var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length)
9511
+ while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
9512
+ { ++cutFront }
9513
+ var newBot = lst(newText), oldBot = lst(oldText)
9514
+ var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
9515
+ oldBot.length - (oldText.length == 1 ? cutFront : 0))
9516
+ while (cutEnd < maxCutEnd &&
9517
+ newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
9518
+ { ++cutEnd }
9519
+
9520
+ newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "")
9521
+ newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "")
9522
+
9523
+ var chFrom = Pos(fromLine, cutFront)
9524
+ var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0)
9525
+ if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
9526
+ replaceRange(cm.doc, newText, chFrom, chTo, "+input")
9527
+ return true
9528
+ }
9529
+ };
9530
+
9531
+ ContentEditableInput.prototype.ensurePolled = function () {
9532
+ this.forceCompositionEnd()
9533
+ };
9534
+ ContentEditableInput.prototype.reset = function () {
9535
+ this.forceCompositionEnd()
9536
+ };
9537
+ ContentEditableInput.prototype.forceCompositionEnd = function () {
9538
+ if (!this.composing) { return }
9539
+ clearTimeout(this.readDOMTimeout)
9540
+ this.composing = null
9541
+ if (!this.pollContent()) { regChange(this.cm) }
9542
+ this.div.blur()
9543
+ this.div.focus()
9544
+ };
9545
+ ContentEditableInput.prototype.readFromDOMSoon = function () {
9546
  var this$1 = this;
9547
 
9548
+ if (this.readDOMTimeout != null) { return }
9549
+ this.readDOMTimeout = setTimeout(function () {
9550
+ this$1.readDOMTimeout = null
9551
+ if (this$1.composing) {
9552
+ if (this$1.composing.done) { this$1.composing = null }
9553
+ else { return }
9554
+ }
9555
+ if (this$1.cm.isReadOnly() || !this$1.pollContent())
9556
+ { runInOp(this$1.cm, function () { return regChange(this$1.cm); }) }
9557
+ }, 80)
9558
+ };
9559
 
9560
+ ContentEditableInput.prototype.setUneditable = function (node) {
9561
+ node.contentEditable = "false"
9562
+ };
9563
 
9564
+ ContentEditableInput.prototype.onKeyPress = function (e) {
9565
+ e.preventDefault()
9566
+ if (!this.cm.isReadOnly())
9567
+ { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) }
9568
+ };
9569
 
9570
+ ContentEditableInput.prototype.readOnlyChanged = function (val) {
9571
+ this.div.contentEditable = String(val != "nocursor")
9572
+ };
9573
 
9574
+ ContentEditableInput.prototype.onContextMenu = function () {};
9575
+ ContentEditableInput.prototype.resetPosition = function () {};
9576
 
9577
+ ContentEditableInput.prototype.needsContentAttribute = true
 
9578
 
9579
  function posToDOM(cm, pos) {
9580
  var view = findViewForLine(cm, pos.line)
9711
 
9712
  // TEXTAREA INPUT STYLE
9713
 
9714
+ var TextareaInput = function(cm) {
9715
  this.cm = cm
9716
  // See input.poll and input.reset
9717
  this.prevInput = ""
9728
  // Used to work around IE issue with selection being forgotten when focus moves away from textarea
9729
  this.hasSelection = false
9730
  this.composing = null
9731
+ };
9732
 
9733
+ TextareaInput.prototype.init = function (display) {
 
9734
  var this$1 = this;
9735
 
9736
+ var input = this, cm = this.cm
9737
 
9738
+ // Wraps and hides input textarea
9739
+ var div = this.wrapper = hiddenTextarea()
9740
+ // The semihidden textarea that is focused when the editor is
9741
+ // focused, and receives input.
9742
+ var te = this.textarea = div.firstChild
9743
+ display.wrapper.insertBefore(div, display.wrapper.firstChild)
9744
 
9745
+ // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
9746
+ if (ios) { te.style.width = "0px" }
9747
 
9748
+ on(te, "input", function () {
9749
+ if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null }
9750
+ input.poll()
9751
+ })
9752
 
9753
+ on(te, "paste", function (e) {
9754
+ if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
9755
 
9756
+ cm.state.pasteIncoming = true
9757
+ input.fastPoll()
9758
+ })
9759
 
9760
+ function prepareCopyCut(e) {
9761
+ if (signalDOMEvent(cm, e)) { return }
9762
+ if (cm.somethingSelected()) {
9763
+ setLastCopied({lineWise: false, text: cm.getSelections()})
9764
+ if (input.inaccurateSelection) {
9765
+ input.prevInput = ""
9766
+ input.inaccurateSelection = false
9767
+ te.value = lastCopied.text.join("\n")
9768
+ selectInput(te)
9769
+ }
9770
+ } else if (!cm.options.lineWiseCopyCut) {
9771
+ return
9772
+ } else {
9773
+ var ranges = copyableRanges(cm)
9774
+ setLastCopied({lineWise: true, text: ranges.text})
9775
+ if (e.type == "cut") {
9776
+ cm.setSelections(ranges.ranges, null, sel_dontScroll)
9777
  } else {
9778
+ input.prevInput = ""
9779
+ te.value = ranges.text.join("\n")
9780
+ selectInput(te)
 
 
 
 
 
 
9781
  }
 
9782
  }
9783
+ if (e.type == "cut") { cm.state.cutIncoming = true }
9784
+ }
9785
+ on(te, "cut", prepareCopyCut)
9786
+ on(te, "copy", prepareCopyCut)
 
 
 
 
 
 
 
 
 
9787
 
9788
+ on(display.scroller, "paste", function (e) {
9789
+ if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
9790
+ cm.state.pasteIncoming = true
9791
+ input.focus()
9792
+ })
 
 
 
 
 
 
 
 
 
 
 
9793
 
9794
+ // Prevent normal selection in the editor (we handle our own)
9795
+ on(display.lineSpace, "selectstart", function (e) {
9796
+ if (!eventInWidget(display, e)) { e_preventDefault(e) }
9797
+ })
9798
 
9799
+ on(te, "compositionstart", function () {
9800
+ var start = cm.getCursor("from")
9801
+ if (input.composing) { input.composing.range.clear() }
9802
+ input.composing = {
9803
+ start: start,
9804
+ range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
 
 
9805
  }
9806
+ })
9807
+ on(te, "compositionend", function () {
9808
+ if (input.composing) {
9809
+ input.poll()
9810
+ input.composing.range.clear()
9811
+ input.composing = null
 
 
 
 
 
9812
  }
9813
+ })
9814
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9815
 
9816
+ TextareaInput.prototype.prepareSelection = function () {
9817
+ // Redraw the selection and/or cursor
9818
+ var cm = this.cm, display = cm.display, doc = cm.doc
9819
+ var result = prepareSelection(cm)
9820
 
9821
+ // Move the hidden textarea near the cursor to prevent scrolling artifacts
9822
+ if (cm.options.moveInputWithCursor) {
9823
+ var headPos = cursorCoords(cm, doc.sel.primary().head, "div")
9824
+ var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect()
9825
+ result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
9826
+ headPos.top + lineOff.top - wrapOff.top))
9827
+ result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
9828
+ headPos.left + lineOff.left - wrapOff.left))
9829
+ }
9830
 
9831
+ return result
9832
+ };
9833
+
9834
+ TextareaInput.prototype.showSelection = function (drawn) {
9835
+ var cm = this.cm, display = cm.display
9836
+ removeChildrenAndAdd(display.cursorDiv, drawn.cursors)
9837
+ removeChildrenAndAdd(display.selectionDiv, drawn.selection)
9838
+ if (drawn.teTop != null) {
9839
+ this.wrapper.style.top = drawn.teTop + "px"
9840
+ this.wrapper.style.left = drawn.teLeft + "px"
9841
+ }
9842
+ };
9843
+
9844
+ // Reset the input to correspond to the selection (or to be empty,
9845
+ // when not typing and nothing is selected)
9846
+ TextareaInput.prototype.reset = function (typing) {
9847
+ if (this.contextMenuPending) { return }
9848
+ var minimal, selected, cm = this.cm, doc = cm.doc
9849
+ if (cm.somethingSelected()) {
9850
+ this.prevInput = ""
9851
+ var range = doc.sel.primary()
9852
+ minimal = hasCopyEvent &&
9853
+ (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000)
9854
+ var content = minimal ? "-" : selected || cm.getSelection()
9855
+ this.textarea.value = content
9856
+ if (cm.state.focused) { selectInput(this.textarea) }
9857
+ if (ie && ie_version >= 9) { this.hasSelection = content }
9858
+ } else if (!typing) {
9859
+ this.prevInput = this.textarea.value = ""
9860
+ if (ie && ie_version >= 9) { this.hasSelection = null }
9861
+ }
9862
+ this.inaccurateSelection = minimal
9863
+ };
9864
 
9865
+ TextareaInput.prototype.getField = function () { return this.textarea };
9866
 
9867
+ TextareaInput.prototype.supportsTouch = function () { return false };
 
 
9868
 
9869
+ TextareaInput.prototype.focus = function () {
9870
+ if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
9871
+ try { this.textarea.focus() }
9872
+ catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
9873
+ }
9874
+ };
9875
 
9876
+ TextareaInput.prototype.blur = function () { this.textarea.blur() };
 
 
 
9877
 
9878
+ TextareaInput.prototype.resetPosition = function () {
9879
+ this.wrapper.style.top = this.wrapper.style.left = 0
9880
+ };
 
 
 
9881
 
9882
+ TextareaInput.prototype.receivedFocus = function () { this.slowPoll() };
 
 
 
 
 
 
 
 
 
 
 
 
9883
 
9884
+ // Poll for input changes, using the normal rate of polling. This
9885
+ // runs as long as the editor is focused.
9886
+ TextareaInput.prototype.slowPoll = function () {
 
 
 
 
9887
  var this$1 = this;
9888
 
9889
+ if (this.pollingFast) { return }
9890
+ this.polling.set(this.cm.options.pollInterval, function () {
9891
+ this$1.poll()
9892
+ if (this$1.cm.state.focused) { this$1.slowPoll() }
9893
+ })
9894
+ };
9895
+
9896
+ // When an event has just come in that is likely to add or change
9897
+ // something in the input textarea, we poll faster, to ensure that
9898
+ // the change appears on the screen quickly.
9899
+ TextareaInput.prototype.fastPoll = function () {
9900
+ var missed = false, input = this
9901
+ input.pollingFast = true
9902
+ function p() {
9903
+ var changed = input.poll()
9904
+ if (!changed && !missed) {missed = true; input.polling.set(60, p)}
9905
+ else {input.pollingFast = false; input.slowPoll()}
9906
+ }
9907
+ input.polling.set(20, p)
9908
+ };
9909
+
9910
+ // Read input from the textarea, and update the document to match.
9911
+ // When something is selected, it is present in the textarea, and
9912
+ // selected (unless it is huge, in which case a placeholder is
9913
+ // used). When nothing is selected, the cursor sits after previously
9914
+ // seen text (can be empty), which is stored in prevInput (we must
9915
+ // not reset the textarea when typing, because that breaks IME).
9916
+ TextareaInput.prototype.poll = function () {
9917
+ var this$1 = this;
 
9918
 
9919
+ var cm = this.cm, input = this.textarea, prevInput = this.prevInput
9920
+ // Since this is called a *lot*, try to bail out as cheaply as
9921
+ // possible when it is clear that nothing happened. hasSelection
9922
+ // will be the case when there is a lot of text in the textarea,
9923
+ // in which case reading its value would be expensive.
9924
+ if (this.contextMenuPending || !cm.state.focused ||
9925
+ (hasSelection(input) && !prevInput && !this.composing) ||
9926
+ cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
9927
+ { return false }
9928
 
9929
+ var text = input.value
9930
+ // If nothing changed, bail.
9931
+ if (text == prevInput && !cm.somethingSelected()) { return false }
9932
+ // Work around nonsensical selection resetting in IE9/10, and
9933
+ // inexplicable appearance of private area unicode characters on
9934
+ // some key combos in Mac (#2689).
9935
+ if (ie && ie_version >= 9 && this.hasSelection === text ||
9936
+ mac && /[\uf700-\uf7ff]/.test(text)) {
9937
+ cm.display.input.reset()
9938
+ return false
9939
+ }
9940
 
9941
+ if (cm.doc.sel == cm.display.selForContextMenu) {
9942
+ var first = text.charCodeAt(0)
9943
+ if (first == 0x200b && !prevInput) { prevInput = "\u200b" }
9944
+ if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
9945
+ }
9946
+ // Find the part of the input that is actually new
9947
+ var same = 0, l = Math.min(prevInput.length, text.length)
9948
+ while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same }
9949
 
9950
+ runInOp(cm, function () {
9951
+ applyTextInput(cm, text.slice(same), prevInput.length - same,
9952
+ null, this$1.composing ? "*compose" : null)
9953
 
9954
+ // Don't leave long text in the textarea, since it makes further polling slow
9955
+ if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = "" }
9956
+ else { this$1.prevInput = text }
 
9957
 
9958
+ if (this$1.composing) {
9959
+ this$1.composing.range.clear()
9960
+ this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
9961
+ {className: "CodeMirror-composing"})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9962
  }
9963
+ })
9964
+ return true
9965
+ };
9966
+
9967
+ TextareaInput.prototype.ensurePolled = function () {
9968
+ if (this.pollingFast && this.poll()) { this.pollingFast = false }
9969
+ };
9970
+
9971
+ TextareaInput.prototype.onKeyPress = function () {
9972
+ if (ie && ie_version >= 9) { this.hasSelection = null }
9973
+ this.fastPoll()
9974
+ };
9975
+
9976
+ TextareaInput.prototype.onContextMenu = function (e) {
9977
+ var input = this, cm = input.cm, display = cm.display, te = input.textarea
9978
+ var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop
9979
+ if (!pos || presto) { return } // Opera is difficult.
9980
+
9981
+ // Reset the current text selection only if the click is done outside of the selection
9982
+ // and 'resetSelectionOnContextMenu' option is true.
9983
+ var reset = cm.options.resetSelectionOnContextMenu
9984
+ if (reset && cm.doc.sel.contains(pos) == -1)
9985
+ { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll) }
9986
+
9987
+ var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText
9988
+ input.wrapper.style.cssText = "position: absolute"
9989
+ var wrapperBox = input.wrapper.getBoundingClientRect()
9990
+ te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"
9991
+ var oldScrollY
9992
+ if (webkit) { oldScrollY = window.scrollY } // Work around Chrome issue (#2712)
9993
+ display.input.focus()
9994
+ if (webkit) { window.scrollTo(null, oldScrollY) }
9995
+ display.input.reset()
9996
+ // Adds "Select all" to context menu in FF
9997
+ if (!cm.somethingSelected()) { te.value = input.prevInput = " " }
9998
+ input.contextMenuPending = true
9999
+ display.selForContextMenu = cm.doc.sel
10000
+ clearTimeout(display.detectingSelectAll)
10001
+
10002
+ // Select-all will be greyed out if there's nothing to select, so
10003
+ // this adds a zero-width space so that we can later check whether
10004
+ // it got selected.
10005
+ function prepareSelectAllHack() {
10006
+ if (te.selectionStart != null) {
10007
+ var selected = cm.somethingSelected()
10008
+ var extval = "\u200b" + (selected ? te.value : "")
10009
+ te.value = "\u21da" // Used to catch context-menu undo
10010
+ te.value = extval
10011
+ input.prevInput = selected ? "" : "\u200b"
10012
+ te.selectionStart = 1; te.selectionEnd = extval.length
10013
+ // Re-set this, in case some other handler touched the
10014
+ // selection in the meantime.
10015
+ display.selForContextMenu = cm.doc.sel
10016
+ }
10017
+ }
10018
+ function rehide() {
10019
+ input.contextMenuPending = false
10020
+ input.wrapper.style.cssText = oldWrapperCSS
10021
+ te.style.cssText = oldCSS
10022
+ if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos) }
10023
+
10024
+ // Try to detect the user choosing select-all
10025
+ if (te.selectionStart != null) {
10026
+ if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack() }
10027
+ var i = 0, poll = function () {
10028
+ if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
10029
+ te.selectionEnd > 0 && input.prevInput == "\u200b")
10030
+ { operation(cm, selectAll)(cm) }
10031
+ else if (i++ < 10) { display.detectingSelectAll = setTimeout(poll, 500) }
10032
+ else { display.input.reset() }
10033
  }
10034
+ display.detectingSelectAll = setTimeout(poll, 200)
10035
  }
10036
+ }
10037
 
10038
+ if (ie && ie_version >= 9) { prepareSelectAllHack() }
10039
+ if (captureRightClick) {
10040
+ e_stop(e)
10041
+ var mouseup = function () {
10042
+ off(window, "mouseup", mouseup)
10043
+ setTimeout(rehide, 20)
 
 
 
 
10044
  }
10045
+ on(window, "mouseup", mouseup)
10046
+ } else {
10047
+ setTimeout(rehide, 50)
10048
+ }
10049
+ };
10050
 
10051
+ TextareaInput.prototype.readOnlyChanged = function (val) {
10052
+ if (!val) { this.reset() }
10053
+ };
10054
 
10055
+ TextareaInput.prototype.setUneditable = function () {};
10056
 
10057
+ TextareaInput.prototype.needsContentAttribute = false
 
10058
 
10059
  function fromTextArea(textarea, options) {
10060
  options = options ? copyObj(options) : {}
10205
 
10206
  addLegacyProps(CodeMirror)
10207
 
10208
+ CodeMirror.version = "5.22.2"
10209
 
10210
  return CodeMirror;
10211
 
10742
  "transition-property", "transition-timing-function", "unicode-bidi",
10743
  "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
10744
  "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
10745
+ "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
10746
  "word-spacing", "word-wrap", "z-index",
10747
  // SVG-specific
10748
  "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
10816
  "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
10817
  "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
10818
  "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
10819
+ "compact", "condensed", "contain", "content", "contents",
10820
  "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
10821
  "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
10822
  "decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
10859
  "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
10860
  "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
10861
  "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
10862
+ "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
10863
  "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
10864
  "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
10865
  "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
10871
  "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
10872
  "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
10873
  "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
10874
+ "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
10875
  "searchfield-cancel-button", "searchfield-decoration",
10876
  "searchfield-results-button", "searchfield-results-decoration",
10877
  "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
10889
  "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
10890
  "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
10891
  "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
10892
+ "trad-chinese-formal", "trad-chinese-informal", "transform",
10893
  "translate", "translate3d", "translateX", "translateY", "translateZ",
10894
+ "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
10895
  "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
10896
  "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
10897
  "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
assets/js/mailpoet.js CHANGED
@@ -18055,7 +18055,7 @@ webpackJsonp([2],[
18055
 
18056
  /* WEBPACK VAR INJECTION */(function(global) {/*!
18057
  * Parsley.js
18058
- * Version 2.6.0 - built Wed, Nov 2nd 2016, 10:27 am
18059
  * http://parsleyjs.org
18060
  * Guillaume Potier - <guillaume@wisembly.com>
18061
  * Marc-Andre Lafortune - <petroselinum@marc-andre.ca>
@@ -19741,13 +19741,13 @@ webpackJsonp([2],[
19741
  if ('string' === typeof this.$element.attr('pattern')) this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);
19742
 
19743
  // range
19744
- if ('undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max')) this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);
19745
 
19746
  // HTML5 min
19747
- else if ('undefined' !== typeof this.$element.attr('min')) this.addConstraint('min', this.$element.attr('min'), undefined, true);
19748
 
19749
  // HTML5 max
19750
- else if ('undefined' !== typeof this.$element.attr('max')) this.addConstraint('max', this.$element.attr('max'), undefined, true);
19751
 
19752
  // length
19753
  if ('undefined' !== typeof this.$element.attr('minlength') && 'undefined' !== typeof this.$element.attr('maxlength')) this.addConstraint('length', [this.$element.attr('minlength'), this.$element.attr('maxlength')], undefined, true);
@@ -19938,7 +19938,7 @@ webpackJsonp([2],[
19938
  ParsleyFactory.prototype = {
19939
  init: function init(options) {
19940
  this.__class__ = 'Parsley';
19941
- this.__version__ = '2.6.0';
19942
  this.__id__ = ParsleyUtils__default.generateID();
19943
 
19944
  // Pre-compute options
@@ -20060,7 +20060,7 @@ webpackJsonp([2],[
20060
  actualizeOptions: null,
20061
  _resetOptions: null,
20062
  Factory: ParsleyFactory,
20063
- version: '2.6.0'
20064
  });
20065
 
20066
  // Supplement ParsleyField and Form with ParsleyAbstract
18055
 
18056
  /* WEBPACK VAR INJECTION */(function(global) {/*!
18057
  * Parsley.js
18058
+ * Version 2.6.2 - built Wed, Jan 4th 2017, 8:58 am
18059
  * http://parsleyjs.org
18060
  * Guillaume Potier - <guillaume@wisembly.com>
18061
  * Marc-Andre Lafortune - <petroselinum@marc-andre.ca>
19741
  if ('string' === typeof this.$element.attr('pattern')) this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);
19742
 
19743
  // range
19744
+ if (this.$element.attr('type') !== 'date' && 'undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max')) this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);
19745
 
19746
  // HTML5 min
19747
+ else if (this.$element.attr('type') !== 'date' && 'undefined' !== typeof this.$element.attr('min')) this.addConstraint('min', this.$element.attr('min'), undefined, true);
19748
 
19749
  // HTML5 max
19750
+ else if (this.$element.attr('type') !== 'date' && 'undefined' !== typeof this.$element.attr('max')) this.addConstraint('max', this.$element.attr('max'), undefined, true);
19751
 
19752
  // length
19753
  if ('undefined' !== typeof this.$element.attr('minlength') && 'undefined' !== typeof this.$element.attr('maxlength')) this.addConstraint('length', [this.$element.attr('minlength'), this.$element.attr('maxlength')], undefined, true);
19938
  ParsleyFactory.prototype = {
19939
  init: function init(options) {
19940
  this.__class__ = 'Parsley';
19941
+ this.__version__ = '2.6.2';
19942
  this.__id__ = ParsleyUtils__default.generateID();
19943
 
19944
  // Pre-compute options
20060
  actualizeOptions: null,
20061
  _resetOptions: null,
20062
  Factory: ParsleyFactory,
20063
+ version: '2.6.2'
20064
  });
20065
 
20066
  // Supplement ParsleyField and Form with ParsleyAbstract
assets/js/newsletter_editor.js CHANGED
@@ -14624,7 +14624,7 @@ webpackJsonp([3],{
14624
  /***/ function(module, exports, __webpack_require__) {
14625
 
14626
  /**
14627
- * interact.js v1.2.6
14628
  *
14629
  * Copyright (c) 2012-2015 Taye Adeyemi <dev@taye.me>
14630
  * Open source under the MIT License.
@@ -14869,7 +14869,8 @@ webpackJsonp([3],{
14869
  supportsTouch = (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch),
14870
 
14871
  // Does the browser support PointerEvents
14872
- supportsPointerEvent = !!PointerEvent,
 
14873
 
14874
  // Less Precision with touch input
14875
  margin = supportsTouch || supportsPointerEvent? 20: 10,
@@ -16002,14 +16003,14 @@ webpackJsonp([3],{
16002
 
16003
  this.pointerHover(pointer, event, this.matches, this.matchElements);
16004
  events.add(eventTarget,
16005
- PointerEvent? pEventTypes.move : 'mousemove',
16006
  listeners.pointerHover);
16007
  }
16008
  else if (this.target) {
16009
  if (nodeContains(prevTargetElement, eventTarget)) {
16010
  this.pointerHover(pointer, event, this.matches, this.matchElements);
16011
  events.add(this.element,
16012
- PointerEvent? pEventTypes.move : 'mousemove',
16013
  listeners.pointerHover);
16014
  }
16015
  else {
@@ -16061,7 +16062,7 @@ webpackJsonp([3],{
16061
  // Remove temporary event listeners for selector Interactables
16062
  if (!interactables.get(eventTarget)) {
16063
  events.remove(eventTarget,
16064
- PointerEvent? pEventTypes.move : 'mousemove',
16065
  listeners.pointerHover);
16066
  }
16067
 
@@ -16373,7 +16374,7 @@ webpackJsonp([3],{
16373
 
16374
  // set the startCoords if there was no prepared action
16375
  if (!this.prepared.name) {
16376
- this.setEventXY(this.startCoords);
16377
  }
16378
 
16379
  this.prepared.name = action.name;
@@ -18555,7 +18556,7 @@ webpackJsonp([3],{
18555
 
18556
  if (isElement(element, _window)) {
18557
 
18558
- if (PointerEvent) {
18559
  events.add(this._element, pEventTypes.down, listeners.pointerDown );
18560
  events.add(this._element, pEventTypes.move, listeners.pointerHover);
18561
  }
@@ -20400,7 +20401,7 @@ webpackJsonp([3],{
20400
  events.add(doc, eventType, delegateUseCapture, true);
20401
  }
20402
 
20403
- if (PointerEvent) {
20404
  if (PointerEvent === win.MSPointerEvent) {
20405
  pEventTypes = {
20406
  up: 'MSPointerUp', down: 'MSPointerDown', over: 'mouseover',
14624
  /***/ function(module, exports, __webpack_require__) {
14625
 
14626
  /**
14627
+ * interact.js v1.2.8
14628
  *
14629
  * Copyright (c) 2012-2015 Taye Adeyemi <dev@taye.me>
14630
  * Open source under the MIT License.
14869
  supportsTouch = (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch),
14870
 
14871
  // Does the browser support PointerEvents
14872
+ // Avoid PointerEvent bugs introduced in Chrome 55
14873
+ supportsPointerEvent = PointerEvent && !/Chrome/.test(navigator.userAgent),
14874
 
14875
  // Less Precision with touch input
14876
  margin = supportsTouch || supportsPointerEvent? 20: 10,
16003
 
16004
  this.pointerHover(pointer, event, this.matches, this.matchElements);
16005
  events.add(eventTarget,
16006
+ supportsPointerEvent? pEventTypes.move : 'mousemove',
16007
  listeners.pointerHover);
16008
  }
16009
  else if (this.target) {
16010
  if (nodeContains(prevTargetElement, eventTarget)) {
16011
  this.pointerHover(pointer, event, this.matches, this.matchElements);
16012
  events.add(this.element,
16013
+ supportsPointerEvent? pEventTypes.move : 'mousemove',
16014
  listeners.pointerHover);
16015
  }
16016
  else {
16062
  // Remove temporary event listeners for selector Interactables
16063
  if (!interactables.get(eventTarget)) {
16064
  events.remove(eventTarget,
16065
+ supportsPointerEvent? pEventTypes.move : 'mousemove',
16066
  listeners.pointerHover);
16067
  }
16068
 
16374
 
16375
  // set the startCoords if there was no prepared action
16376
  if (!this.prepared.name) {
16377
+ this.setEventXY(this.startCoords, this.pointers);
16378
  }
16379
 
16380
  this.prepared.name = action.name;
18556
 
18557
  if (isElement(element, _window)) {
18558
 
18559
+ if (supportsPointerEvent) {
18560
  events.add(this._element, pEventTypes.down, listeners.pointerDown );
18561
  events.add(this._element, pEventTypes.move, listeners.pointerHover);
18562
  }
20401
  events.add(doc, eventType, delegateUseCapture, true);
20402
  }
20403
 
20404
+ if (supportsPointerEvent) {
20405
  if (PointerEvent === win.MSPointerEvent) {
20406
  pEventTypes = {
20407
  up: 'MSPointerUp', down: 'MSPointerDown', over: 'mouseover',
assets/js/public.js CHANGED
@@ -1945,7 +1945,7 @@
1945
 
1946
  /* WEBPACK VAR INJECTION */(function(global) {/*!
1947
  * Parsley.js
1948
- * Version 2.6.0 - built Wed, Nov 2nd 2016, 10:27 am
1949
  * http://parsleyjs.org
1950
  * Guillaume Potier - <guillaume@wisembly.com>
1951
  * Marc-Andre Lafortune - <petroselinum@marc-andre.ca>
@@ -3631,13 +3631,13 @@
3631
  if ('string' === typeof this.$element.attr('pattern')) this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);
3632
 
3633
  // range
3634
- if ('undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max')) this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);
3635
 
3636
  // HTML5 min
3637
- else if ('undefined' !== typeof this.$element.attr('min')) this.addConstraint('min', this.$element.attr('min'), undefined, true);
3638
 
3639
  // HTML5 max
3640
- else if ('undefined' !== typeof this.$element.attr('max')) this.addConstraint('max', this.$element.attr('max'), undefined, true);
3641
 
3642
  // length
3643
  if ('undefined' !== typeof this.$element.attr('minlength') && 'undefined' !== typeof this.$element.attr('maxlength')) this.addConstraint('length', [this.$element.attr('minlength'), this.$element.attr('maxlength')], undefined, true);
@@ -3828,7 +3828,7 @@
3828
  ParsleyFactory.prototype = {
3829
  init: function init(options) {
3830
  this.__class__ = 'Parsley';
3831
- this.__version__ = '2.6.0';
3832
  this.__id__ = ParsleyUtils__default.generateID();
3833
 
3834
  // Pre-compute options
@@ -3950,7 +3950,7 @@
3950
  actualizeOptions: null,
3951
  _resetOptions: null,
3952
  Factory: ParsleyFactory,
3953
- version: '2.6.0'
3954
  });
3955
 
3956
  // Supplement ParsleyField and Form with ParsleyAbstract
1945
 
1946
  /* WEBPACK VAR INJECTION */(function(global) {/*!
1947
  * Parsley.js
1948
+ * Version 2.6.2 - built Wed, Jan 4th 2017, 8:58 am
1949
  * http://parsleyjs.org
1950
  * Guillaume Potier - <guillaume@wisembly.com>
1951
  * Marc-Andre Lafortune - <petroselinum@marc-andre.ca>
3631
  if ('string' === typeof this.$element.attr('pattern')) this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);
3632
 
3633
  // range
3634
+ if (this.$element.attr('type') !== 'date' && 'undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max')) this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);
3635
 
3636
  // HTML5 min
3637
+ else if (this.$element.attr('type') !== 'date' && 'undefined' !== typeof this.$element.attr('min')) this.addConstraint('min', this.$element.attr('min'), undefined, true);
3638
 
3639
  // HTML5 max
3640
+ else if (this.$element.attr('type') !== 'date' && 'undefined' !== typeof this.$element.attr('max')) this.addConstraint('max', this.$element.attr('max'), undefined, true);
3641
 
3642
  // length
3643
  if ('undefined' !== typeof this.$element.attr('minlength') && 'undefined' !== typeof this.$element.attr('maxlength')) this.addConstraint('length', [this.$element.attr('minlength'), this.$element.attr('maxlength')], undefined, true);
3828
  ParsleyFactory.prototype = {
3829
  init: function init(options) {
3830
  this.__class__ = 'Parsley';
3831
+ this.__version__ = '2.6.2';
3832
  this.__id__ = ParsleyUtils__default.generateID();
3833
 
3834
  // Pre-compute options
3950
  actualizeOptions: null,
3951
  _resetOptions: null,
3952
  Factory: ParsleyFactory,
3953
+ version: '2.6.2'
3954
  });
3955
 
3956
  // Supplement ParsleyField and Form with ParsleyAbstract
lang/index.php CHANGED
@@ -1,3 +0,0 @@
1
- <?php
2
-
3
- // Silence is golden
 
 
 
lang/mailpoet.pot CHANGED
@@ -4,7 +4,7 @@ msgid ""
4
  msgstr ""
5
  "Project-Id-Version: \n"
6
  "Report-Msgid-Bugs-To: http://support.mailpoet.com/\n"
7
- "POT-Creation-Date: 2017-01-17 17:30:15+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
@@ -132,8 +132,8 @@ msgstr ""
132
  msgid "You have not specified any settings to be saved."
133
  msgstr ""
134
 
135
- #: lib/API/Endpoints/Subscribers.php:29 lib/API/Endpoints/Subscribers.php:127
136
- #: lib/API/Endpoints/Subscribers.php:143 lib/API/Endpoints/Subscribers.php:159
137
  msgid "This subscriber does not exist."
138
  msgstr ""
139
 
4
  msgstr ""
5
  "Project-Id-Version: \n"
6
  "Report-Msgid-Bugs-To: http://support.mailpoet.com/\n"
7
+ "POT-Creation-Date: 2017-01-19 16:53:12+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
132
  msgid "You have not specified any settings to be saved."
133
  msgstr ""
134
 
135
+ #: lib/API/Endpoints/Subscribers.php:29 lib/API/Endpoints/Subscribers.php:130
136
+ #: lib/API/Endpoints/Subscribers.php:146 lib/API/Endpoints/Subscribers.php:162
137
  msgid "This subscriber does not exist."
138
  msgstr ""
139
 
lib/API/Endpoints/Subscribers.php CHANGED
@@ -107,6 +107,9 @@ class Subscribers extends APIEndpoint {
107
  }
108
 
109
  function save($data = array()) {
 
 
 
110
  $subscriber = Subscriber::createOrUpdate($data);
111
  $errors = $subscriber->getErrors();
112
 
107
  }
108
 
109
  function save($data = array()) {
110
+ if(empty($data['segments'])) {
111
+ $data['segments'] = array();
112
+ }
113
  $subscriber = Subscriber::createOrUpdate($data);
114
  $errors = $subscriber->getErrors();
115
 
lib/Models/Subscriber.php CHANGED
@@ -485,6 +485,17 @@ class Subscriber extends Model {
485
  unset($data['segments']);
486
  }
487
 
 
 
 
 
 
 
 
 
 
 
 
488
  // custom fields
489
  $custom_fields = array();
490
  foreach($data as $key => $value) {
485
  unset($data['segments']);
486
  }
487
 
488
+ // fields that must exist
489
+ $not_null_fields = array(
490
+ 'first_name' => '',
491
+ 'last_name' => ''
492
+ );
493
+ foreach($not_null_fields as $field => $value) {
494
+ if(!isset($data[$field])) {
495
+ $data[$field] = $value;
496
+ }
497
+ }
498
+
499
  // custom fields
500
  $custom_fields = array();
501
  foreach($data as $key => $value) {
lib/Models/SubscriberSegment.php CHANGED
@@ -54,6 +54,15 @@ class SubscriberSegment extends Model {
54
  return true;
55
  }
56
 
 
 
 
 
 
 
 
 
 
57
  static function subscribeToSegments($subscriber, $segment_ids = array()) {
58
  if($subscriber === false) return false;
59
  if(!empty($segment_ids)) {
@@ -68,12 +77,6 @@ class SubscriberSegment extends Model {
68
  }
69
  }
70
  return true;
71
- } else {
72
- // (re)subscribe to all segments linked to the subscriber
73
- return self::where('subscriber_id', $subscriber->id)
74
- ->findResultSet()
75
- ->set('status', Subscriber::STATUS_SUBSCRIBED)
76
- ->save();
77
  }
78
  }
79
 
54
  return true;
55
  }
56
 
57
+ static function resubscribeToAllSegments($subscriber) {
58
+ if($subscriber === false) return false;
59
+ // (re)subscribe to all segments linked to the subscriber
60
+ return self::where('subscriber_id', $subscriber->id)
61
+ ->findResultSet()
62
+ ->set('status', Subscriber::STATUS_SUBSCRIBED)
63
+ ->save();
64
+ }
65
+
66
  static function subscribeToSegments($subscriber, $segment_ids = array()) {
67
  if($subscriber === false) return false;
68
  if(!empty($segment_ids)) {
77
  }
78
  }
79
  return true;
 
 
 
 
 
 
80
  }
81
  }
82
 
lib/Util/ConflictResolver.php CHANGED
@@ -2,23 +2,19 @@
2
  namespace MailPoet\Util;
3
 
4
  class ConflictResolver {
5
- public $allowed_assets = array(
6
  'styles' => array(
7
  // WP default
8
- 'admin-bar',
9
- 'colors',
10
- 'ie',
11
- 'wp-auth-check',
12
  // third-party
13
  'query-monitor'
14
  ),
15
  'scripts' => array(
16
  // WP default
17
- 'common',
18
- 'admin-bar',
19
- 'utils',
20
- 'svg-painter',
21
- 'wp-auth-check',
22
  // third-party
23
  'query-monitor'
24
  )
@@ -57,16 +53,19 @@ class ConflictResolver {
57
  // unload all styles except from the list of allowed
58
  $dequeue_styles = function() {
59
  global $wp_styles;
 
60
  foreach($wp_styles->queue as $wp_style) {
61
- if(!in_array($wp_style, $this->allowed_assets['styles'])) {
 
 
62
  wp_dequeue_style($wp_style);
63
  }
64
  }
65
  };
66
- add_action('wp_print_styles', $dequeue_styles);
67
- add_action('admin_print_styles', $dequeue_styles);
68
- add_action('admin_print_footer_scripts', $dequeue_styles);
69
- add_action('admin_footer', $dequeue_styles);
70
  }
71
 
72
  function resolveScriptsConflict() {
@@ -74,12 +73,14 @@ class ConflictResolver {
74
  $dequeue_scripts = function() {
75
  global $wp_scripts;
76
  foreach($wp_scripts->queue as $wp_script) {
77
- if(!in_array($wp_script, $this->allowed_assets['scripts'])) {
 
 
78
  wp_dequeue_script($wp_script);
79
  }
80
  }
81
  };
82
- add_action('wp_print_scripts', $dequeue_scripts);
83
- add_action('admin_print_footer_scripts', $dequeue_scripts);
84
  }
85
  }
2
  namespace MailPoet\Util;
3
 
4
  class ConflictResolver {
5
+ public $permitted_assets_locations = array(
6
  'styles' => array(
7
  // WP default
8
+ '^/wp-admin',
9
+ '^/wp-includes',
 
 
10
  // third-party
11
  'query-monitor'
12
  ),
13
  'scripts' => array(
14
  // WP default
15
+ '^/wp-admin',
16
+ '^/wp-includes',
17
+ 'googleapis.com/ajax/libs',
 
 
18
  // third-party
19
  'query-monitor'
20
  )
53
  // unload all styles except from the list of allowed
54
  $dequeue_styles = function() {
55
  global $wp_styles;
56
+ if(empty($wp_styles->queue)) return;
57
  foreach($wp_styles->queue as $wp_style) {
58
+ if(empty($wp_styles->registered[$wp_style])) continue;
59
+ $registered_style = $wp_styles->registered[$wp_style];
60
+ if(!preg_match('!' . implode('|', $this->permitted_assets_locations['styles']) . '!i', $registered_style->src)) {
61
  wp_dequeue_style($wp_style);
62
  }
63
  }
64
  };
65
+ add_action('wp_print_styles', $dequeue_styles, PHP_INT_MAX);
66
+ add_action('admin_print_styles', $dequeue_styles, PHP_INT_MAX);
67
+ add_action('admin_print_footer_scripts', $dequeue_styles, PHP_INT_MAX);
68
+ add_action('admin_footer', $dequeue_styles, PHP_INT_MAX);
69
  }
70
 
71
  function resolveScriptsConflict() {
73
  $dequeue_scripts = function() {
74
  global $wp_scripts;
75
  foreach($wp_scripts->queue as $wp_script) {
76
+ if(empty($wp_scripts->registered[$wp_script])) continue;
77
+ $registered_script = $wp_scripts->registered[$wp_script];
78
+ if(!preg_match('!' . implode('|', $this->permitted_assets_locations['scripts']) . '!i', $registered_script->src)) {
79
  wp_dequeue_script($wp_script);
80
  }
81
  }
82
  };
83
+ add_action('wp_print_scripts', $dequeue_scripts, PHP_INT_MAX);
84
+ add_action('admin_print_footer_scripts', $dequeue_scripts, PHP_INT_MAX);
85
  }
86
  }
mailpoet.php CHANGED
@@ -5,7 +5,7 @@ use MailPoet\Config\Initializer;
5
 
6
  /*
7
  * Plugin Name: MailPoet
8
- * Version: 3.0.0-beta.13
9
  * Plugin URI: http://www.mailpoet.com
10
  * Description: Create and send beautiful email newsletters, autoresponders, and post notifications without leaving WordPress. This is a beta version of our brand new plugin!
11
  * Author: MailPoet
@@ -24,7 +24,7 @@ use MailPoet\Config\Initializer;
24
  $mailpoet_loader = dirname(__FILE__) . '/vendor/autoload.php';
25
  if(file_exists($mailpoet_loader)) {
26
  require $mailpoet_loader;
27
- define('MAILPOET_VERSION', '3.0.0-beta.13');
28
  $initializer = new Initializer(
29
  array(
30
  'file' => __FILE__,
@@ -37,4 +37,4 @@ if(file_exists($mailpoet_loader)) {
37
  $notice = __('MailPoet cannot start because it is missing core files. Please reinstall the plugin.', 'mailpoet');
38
  printf('<div class="error"><p>%1$s</p></div>', $notice);
39
  });
40
- }
5
 
6
  /*
7
  * Plugin Name: MailPoet
8
+ * Version: 3.0.0-beta.14
9
  * Plugin URI: http://www.mailpoet.com
10
  * Description: Create and send beautiful email newsletters, autoresponders, and post notifications without leaving WordPress. This is a beta version of our brand new plugin!
11
  * Author: MailPoet
24
  $mailpoet_loader = dirname(__FILE__) . '/vendor/autoload.php';
25
  if(file_exists($mailpoet_loader)) {
26
  require $mailpoet_loader;
27
+ define('MAILPOET_VERSION', '3.0.0-beta.14');
28
  $initializer = new Initializer(
29
  array(
30
  'file' => __FILE__,
37
  $notice = __('MailPoet cannot start because it is missing core files. Please reinstall the plugin.', 'mailpoet');
38
  printf('<div class="error"><p>%1$s</p></div>', $notice);
39
  });
40
+ }
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: mailpoet, wysija
3
  Tags: newsletter, email, welcome email, post notification, autoresponder, mailchimp, signup, smtp
4
  Requires at least: 4.6
5
- Tested up to: 4.7
6
- Stable tag: 3.0.0-beta.13
7
  Create and send beautiful emails and newsletters from WordPress.
8
 
9
  == Description ==
@@ -83,6 +83,11 @@ Our [support site](https://docs.mailpoet.com/) has plenty of articles. You can w
83
 
84
  == Changelog ==
85
 
 
 
 
 
 
86
  = 3.0.0-beta.13 - 2017-01-17 =
87
  * Improved: style/script conflicts on MailPoet pages are now resolved by unloading non-default assets. Thx Michel for reporting one such case!;
88
  * Fixed: MySQL wait_timeout of less than 20 seconds results in errors when sending. Thx Tim!;
2
  Contributors: mailpoet, wysija
3
  Tags: newsletter, email, welcome email, post notification, autoresponder, mailchimp, signup, smtp
4
  Requires at least: 4.6
5
+ Tested up to: 4.7.1
6
+ Stable tag: 3.0.0-beta.14
7
  Create and send beautiful emails and newsletters from WordPress.
8
 
9
  == Description ==
83
 
84
  == Changelog ==
85
 
86
+ = 3.0.0-beta.14 - 2017-01-19 =
87
+ * Fixed: images can't be added to newsletters. Thanks Leon!;
88
+ * Fixed: forms require first & last name input fields on some systems;
89
+ * Fixed: unable to remove subscribers from lists in admin panel. Thanks Kay!
90
+
91
  = 3.0.0-beta.13 - 2017-01-17 =
92
  * Improved: style/script conflicts on MailPoet pages are now resolved by unloading non-default assets. Thx Michel for reporting one such case!;
93
  * Fixed: MySQL wait_timeout of less than 20 seconds results in errors when sending. Thx Tim!;
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit2344798a24c3433a0a523c6adee5b65d::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit83c1ef3bbd07823e0af45a8bca5c9bf3::getLoader();
vendor/composer/ClassLoader.php CHANGED
@@ -55,6 +55,7 @@ class ClassLoader
55
  private $classMap = array();
56
  private $classMapAuthoritative = false;
57
  private $missingClasses = array();
 
58
 
59
  public function getPrefixes()
60
  {
@@ -271,6 +272,26 @@ class ClassLoader
271
  return $this->classMapAuthoritative;
272
  }
273
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  /**
275
  * Registers this instance as an autoloader.
276
  *
@@ -313,11 +334,6 @@ class ClassLoader
313
  */
314
  public function findFile($class)
315
  {
316
- // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
317
- if ('\\' == $class[0]) {
318
- $class = substr($class, 1);
319
- }
320
-
321
  // class map lookup
322
  if (isset($this->classMap[$class])) {
323
  return $this->classMap[$class];
@@ -325,6 +341,12 @@ class ClassLoader
325
  if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
326
  return false;
327
  }
 
 
 
 
 
 
328
 
329
  $file = $this->findFileWithExtension($class, '.php');
330
 
@@ -333,6 +355,10 @@ class ClassLoader
333
  $file = $this->findFileWithExtension($class, '.hh');
334
  }
335
 
 
 
 
 
336
  if (false === $file) {
337
  // Remember that this class does not exist.
338
  $this->missingClasses[$class] = true;
55
  private $classMap = array();
56
  private $classMapAuthoritative = false;
57
  private $missingClasses = array();
58
+ private $apcuPrefix;
59
 
60
  public function getPrefixes()
61
  {
272
  return $this->classMapAuthoritative;
273
  }
274
 
275
+ /**
276
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
277
+ *
278
+ * @param string|null $apcuPrefix
279
+ */
280
+ public function setApcuPrefix($apcuPrefix)
281
+ {
282
+ $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
283
+ }
284
+
285
+ /**
286
+ * The APCu prefix in use, or null if APCu caching is not enabled.
287
+ *
288
+ * @return string|null
289
+ */
290
+ public function getApcuPrefix()
291
+ {
292
+ return $this->apcuPrefix;
293
+ }
294
+
295
  /**
296
  * Registers this instance as an autoloader.
297
  *
334
  */
335
  public function findFile($class)
336
  {
 
 
 
 
 
337
  // class map lookup
338
  if (isset($this->classMap[$class])) {
339
  return $this->classMap[$class];
341
  if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
342
  return false;
343
  }
344
+ if (null !== $this->apcuPrefix) {
345
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
346
+ if ($hit) {
347
+ return $file;
348
+ }
349
+ }
350
 
351
  $file = $this->findFileWithExtension($class, '.php');
352
 
355
  $file = $this->findFileWithExtension($class, '.hh');
356
  }
357
 
358
+ if (null !== $this->apcuPrefix) {
359
+ apcu_add($this->apcuPrefix.$class, $file);
360
+ }
361
+
362
  if (false === $file) {
363
  // Remember that this class does not exist.
364
  $this->missingClasses[$class] = true;
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit2344798a24c3433a0a523c6adee5b65d
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit2344798a24c3433a0a523c6adee5b65d
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit2344798a24c3433a0a523c6adee5b65d', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit2344798a24c3433a0a523c6adee5b65d', 'loadClassLoader'));
25
 
26
- $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInit2344798a24c3433a0a523c6adee5b65d::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
@@ -48,19 +48,19 @@ class ComposerAutoloaderInit2344798a24c3433a0a523c6adee5b65d
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
- $includeFiles = Composer\Autoload\ComposerStaticInit2344798a24c3433a0a523c6adee5b65d::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
- composerRequire2344798a24c3433a0a523c6adee5b65d($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
- function composerRequire2344798a24c3433a0a523c6adee5b65d($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit83c1ef3bbd07823e0af45a8bca5c9bf3
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit83c1ef3bbd07823e0af45a8bca5c9bf3', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit83c1ef3bbd07823e0af45a8bca5c9bf3', 'loadClassLoader'));
25
 
26
+ $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit83c1ef3bbd07823e0af45a8bca5c9bf3::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
48
  $loader->register(true);
49
 
50
  if ($useStaticLoader) {
51
+ $includeFiles = Composer\Autoload\ComposerStaticInit83c1ef3bbd07823e0af45a8bca5c9bf3::$files;
52
  } else {
53
  $includeFiles = require __DIR__ . '/autoload_files.php';
54
  }
55
  foreach ($includeFiles as $fileIdentifier => $file) {
56
+ composerRequire83c1ef3bbd07823e0af45a8bca5c9bf3($fileIdentifier, $file);
57
  }
58
 
59
  return $loader;
60
  }
61
  }
62
 
63
+ function composerRequire83c1ef3bbd07823e0af45a8bca5c9bf3($fileIdentifier, $file)
64
  {
65
  if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
66
  require $file;
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInit2344798a24c3433a0a523c6adee5b65d
8
  {
9
  public static $files = array (
10
  '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
@@ -602,10 +602,10 @@ class ComposerStaticInit2344798a24c3433a0a523c6adee5b65d
602
  public static function getInitializer(ClassLoader $loader)
603
  {
604
  return \Closure::bind(function () use ($loader) {
605
- $loader->prefixLengthsPsr4 = ComposerStaticInit2344798a24c3433a0a523c6adee5b65d::$prefixLengthsPsr4;
606
- $loader->prefixDirsPsr4 = ComposerStaticInit2344798a24c3433a0a523c6adee5b65d::$prefixDirsPsr4;
607
- $loader->prefixesPsr0 = ComposerStaticInit2344798a24c3433a0a523c6adee5b65d::$prefixesPsr0;
608
- $loader->classMap = ComposerStaticInit2344798a24c3433a0a523c6adee5b65d::$classMap;
609
 
610
  }, null, ClassLoader::class);
611
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit83c1ef3bbd07823e0af45a8bca5c9bf3
8
  {
9
  public static $files = array (
10
  '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
602
  public static function getInitializer(ClassLoader $loader)
603
  {
604
  return \Closure::bind(function () use ($loader) {
605
+ $loader->prefixLengthsPsr4 = ComposerStaticInit83c1ef3bbd07823e0af45a8bca5c9bf3::$prefixLengthsPsr4;
606
+ $loader->prefixDirsPsr4 = ComposerStaticInit83c1ef3bbd07823e0af45a8bca5c9bf3::$prefixDirsPsr4;
607
+ $loader->prefixesPsr0 = ComposerStaticInit83c1ef3bbd07823e0af45a8bca5c9bf3::$prefixesPsr0;
608
+ $loader->classMap = ComposerStaticInit83c1ef3bbd07823e0af45a8bca5c9bf3::$classMap;
609
 
610
  }, null, ClassLoader::class);
611
  }
vendor/composer/installed.json CHANGED
@@ -14,7 +14,7 @@
14
  "reference": "b0c1bda3be5a35da44ba1ac28cc61c67d2ada465",
15
  "shasum": ""
16
  },
17
- "time": "2015-11-28 21:47:43",
18
  "type": "library",
19
  "installation-source": "dist",
20
  "autoload": {
@@ -55,7 +55,7 @@
55
  "require-dev": {
56
  "phpunit/phpunit": "^5.6"
57
  },
58
- "time": "2016-12-14 06:28:26",
59
  "type": "library",
60
  "installation-source": "dist",
61
  "autoload": {
@@ -116,7 +116,7 @@
116
  "j4mie/idiorm": "1.5.*",
117
  "php": ">=5.2.0"
118
  },
119
- "time": "2014-09-23 10:49:36",
120
  "type": "library",
121
  "installation-source": "dist",
122
  "autoload": {
@@ -180,7 +180,7 @@
180
  "require-dev": {
181
  "phpunit/phpunit": "~4.0|~5.0"
182
  },
183
- "time": "2016-01-26 21:23:30",
184
  "type": "library",
185
  "installation-source": "dist",
186
  "autoload": {
@@ -226,7 +226,7 @@
226
  "suggest": {
227
  "ext-mbstring": "For best performance"
228
  },
229
- "time": "2016-11-14 01:06:16",
230
  "type": "library",
231
  "extra": {
232
  "branch-alias": {
@@ -299,7 +299,7 @@
299
  "symfony/config": "",
300
  "symfony/yaml": ""
301
  },
302
- "time": "2017-01-02 20:30:24",
303
  "type": "library",
304
  "extra": {
305
  "branch-alias": {
@@ -354,7 +354,7 @@
354
  "require-dev": {
355
  "phpunit/phpunit": "~4.0|~5.0"
356
  },
357
- "time": "2015-11-04 20:07:17",
358
  "type": "library",
359
  "installation-source": "dist",
360
  "autoload": {
@@ -402,7 +402,7 @@
402
  "require-dev": {
403
  "phpunit/phpunit": "*"
404
  },
405
- "time": "2016-07-19 19:14:21",
406
  "type": "library",
407
  "installation-source": "dist",
408
  "autoload": {
@@ -451,7 +451,7 @@
451
  "phpunit/phpunit": ">=4.0",
452
  "soundasleep/component-tests": "dev-master"
453
  },
454
- "time": "2016-07-28 01:09:53",
455
  "type": "library",
456
  "installation-source": "dist",
457
  "autoload": {
@@ -504,7 +504,7 @@
504
  "mockery/mockery": "~0.9.1",
505
  "symfony/phpunit-bridge": "~3.2"
506
  },
507
- "time": "2016-12-29 10:02:40",
508
  "type": "library",
509
  "extra": {
510
  "branch-alias": {
@@ -559,7 +559,7 @@
559
  "require-dev": {
560
  "htmlawed/htmlawed": "dev-master"
561
  },
562
- "time": "2016-01-14 20:55:00",
563
  "type": "library",
564
  "installation-source": "dist",
565
  "autoload": {
@@ -614,7 +614,7 @@
614
  "symfony/debug": "~2.7",
615
  "symfony/phpunit-bridge": "~3.2"
616
  },
617
- "time": "2017-01-11 19:36:15",
618
  "type": "library",
619
  "extra": {
620
  "branch-alias": {
14
  "reference": "b0c1bda3be5a35da44ba1ac28cc61c67d2ada465",
15
  "shasum": ""
16
  },
17
+ "time": "2015-11-28T21:47:43+00:00",
18
  "type": "library",
19
  "installation-source": "dist",
20
  "autoload": {
55
  "require-dev": {
56
  "phpunit/phpunit": "^5.6"
57
  },
58
+ "time": "2016-12-14T06:28:26+00:00",
59
  "type": "library",
60
  "installation-source": "dist",
61
  "autoload": {
116
  "j4mie/idiorm": "1.5.*",
117
  "php": ">=5.2.0"
118
  },
119
+ "time": "2014-09-23T10:49:36+00:00",
120
  "type": "library",
121
  "installation-source": "dist",
122
  "autoload": {
180
  "require-dev": {
181
  "phpunit/phpunit": "~4.0|~5.0"
182
  },
183
+ "time": "2016-01-26T21:23:30+00:00",
184
  "type": "library",
185
  "installation-source": "dist",
186
  "autoload": {
226
  "suggest": {
227
  "ext-mbstring": "For best performance"
228
  },
229
+ "time": "2016-11-14T01:06:16+00:00",
230
  "type": "library",
231
  "extra": {
232
  "branch-alias": {
299
  "symfony/config": "",
300
  "symfony/yaml": ""
301
  },
302
+ "time": "2017-01-02T20:30:24+00:00",
303
  "type": "library",
304
  "extra": {
305
  "branch-alias": {
354
  "require-dev": {
355
  "phpunit/phpunit": "~4.0|~5.0"
356
  },
357
+ "time": "2015-11-04T20:07:17+00:00",
358
  "type": "library",
359
  "installation-source": "dist",
360
  "autoload": {
402
  "require-dev": {
403
  "phpunit/phpunit": "*"
404
  },
405
+ "time": "2016-07-19T19:14:21+00:00",
406
  "type": "library",
407
  "installation-source": "dist",
408
  "autoload": {
451
  "phpunit/phpunit": ">=4.0",
452
  "soundasleep/component-tests": "dev-master"
453
  },
454
+ "time": "2016-07-28T01:09:53+00:00",
455
  "type": "library",
456
  "installation-source": "dist",
457
  "autoload": {
504
  "mockery/mockery": "~0.9.1",
505
  "symfony/phpunit-bridge": "~3.2"
506
  },
507
+ "time": "2016-12-29T10:02:40+00:00",
508
  "type": "library",
509
  "extra": {
510
  "branch-alias": {
559
  "require-dev": {
560
  "htmlawed/htmlawed": "dev-master"
561
  },
562
+ "time": "2016-01-14T20:55:00+00:00",
563
  "type": "library",
564
  "installation-source": "dist",
565
  "autoload": {
614
  "symfony/debug": "~2.7",
615
  "symfony/phpunit-bridge": "~3.2"
616
  },
617
+ "time": "2017-01-11T19:36:15+00:00",
618
  "type": "library",
619
  "extra": {
620
  "branch-alias": {
vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/CSSList/AtRuleBlockListTest.php DELETED
@@ -1,27 +0,0 @@
1
- <?php
2
-
3
- namespace Sabberworm\CSS\CSSList;
4
-
5
- use Sabberworm\CSS\Parser;
6
-
7
- class AtRuleBlockListTest extends \PHPUnit_Framework_TestCase {
8
-
9
- public function testMediaQueries() {
10
- $sCss = '@media(min-width: 768px){.class{color:red}}';
11
- $oParser = new Parser($sCss);
12
- $oDoc = $oParser->parse();
13
- $aContents = $oDoc->getContents();
14
- $oMediaQuery = $aContents[0];
15
- $this->assertSame('media', $oMediaQuery->atRuleName(), 'Does not interpret the type as a function');
16
- $this->assertSame('(min-width: 768px)', $oMediaQuery->atRuleArgs(), 'The media query is the value');
17
-
18
- $sCss = '@media (min-width: 768px) {.class{color:red}}';
19
- $oParser = new Parser($sCss);
20
- $oDoc = $oParser->parse();
21
- $aContents = $oDoc->getContents();
22
- $oMediaQuery = $aContents[0];
23
- $this->assertSame('media', $oMediaQuery->atRuleName(), 'Does not interpret the type as a function');
24
- $this->assertSame('(min-width: 768px)', $oMediaQuery->atRuleArgs(), 'The media query is the value');
25
- }
26
-
27
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/CSSList/DocumentTest.php DELETED
@@ -1,26 +0,0 @@
1
- <?php
2
-
3
- namespace Sabberworm\CSS\CSSList;
4
-
5
- use Sabberworm\CSS\Parser;
6
-
7
- class DocumentTest extends \PHPUnit_Framework_TestCase {
8
-
9
- public function testOverrideContents() {
10
- $sCss = '.thing { left: 10px; }';
11
- $oParser = new Parser($sCss);
12
- $oDoc = $oParser->parse();
13
- $aContents = $oDoc->getContents();
14
- $this->assertCount(1, $aContents);
15
-
16
- $sCss2 = '.otherthing { right: 10px; }';
17
- $oParser2 = new Parser($sCss);
18
- $oDoc2 = $oParser2->parse();
19
- $aContents2 = $oDoc2->getContents();
20
-
21
- $oDoc->setContents(array($aContents[0], $aContents2[0]));
22
- $aFinalContents = $oDoc->getContents();
23
- $this->assertCount(2, $aFinalContents);
24
- }
25
-
26
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/CSSList/index.php DELETED
File without changes
vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/OutputFormatTest.php DELETED
@@ -1,170 +0,0 @@
1
- <?php
2
-
3
- namespace Sabberworm\CSS;
4
-
5
- use Sabberworm\CSS\Parser;
6
- use Sabberworm\CSS\OutputFormat;
7
-
8
- global $TEST_CSS;
9
-
10
- $TEST_CSS = <<<EOT
11
-
12
- .main, .test {
13
- font: italic normal bold 16px/1.2 "Helvetica", Verdana, sans-serif;
14
- background: white;
15
- }
16
-
17
- @media screen {
18
- .main {
19
- background-size: 100% 100%;
20
- font-size: 1.3em;
21
- background-color: #fff;
22
- }
23
- }
24
-
25
- EOT;
26
-
27
- class OutputFormatTest extends \PHPUnit_Framework_TestCase {
28
- private $oParser;
29
- private $oDocument;
30
-
31
- function setUp() {
32
- global $TEST_CSS;
33
- $this->oParser = new Parser($TEST_CSS);
34
- $this->oDocument = $this->oParser->parse();
35
- }
36
-
37
- public function testPlain() {
38
- $this->assertSame('.main, .test {font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;background: white;}
39
- @media screen {.main {background-size: 100% 100%;font-size: 1.3em;background-color: #fff;}}', $this->oDocument->render());
40
- }
41
-
42
- public function testCompact() {
43
- $this->assertSame('.main,.test{font:italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;background:white;}@media screen{.main{background-size:100% 100%;font-size:1.3em;background-color:#fff;}}', $this->oDocument->render(OutputFormat::createCompact()));
44
- }
45
-
46
- public function testPretty() {
47
- global $TEST_CSS;
48
- $this->assertSame($TEST_CSS, $this->oDocument->render(OutputFormat::createPretty()));
49
- }
50
-
51
- public function testSpaceAfterListArgumentSeparator() {
52
- $this->assertSame('.main, .test {font: italic normal bold 16px/ 1.2 "Helvetica", Verdana, sans-serif;background: white;}
53
- @media screen {.main {background-size: 100% 100%;font-size: 1.3em;background-color: #fff;}}', $this->oDocument->render(OutputFormat::create()->setSpaceAfterListArgumentSeparator(" ")));
54
- }
55
-
56
- public function testSpaceAfterListArgumentSeparatorComplex() {
57
- $this->assertSame('.main, .test {font: italic normal bold 16px/1.2 "Helvetica", Verdana, sans-serif;background: white;}
58
- @media screen {.main {background-size: 100% 100%;font-size: 1.3em;background-color: #fff;}}', $this->oDocument->render(OutputFormat::create()->setSpaceAfterListArgumentSeparator(array('default' => ' ', ',' => "\t", '/' => '', ' ' => ''))));
59
- }
60
-
61
- public function testSpaceAfterSelectorSeparator() {
62
- $this->assertSame('.main,
63
- .test {font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;background: white;}
64
- @media screen {.main {background-size: 100% 100%;font-size: 1.3em;background-color: #fff;}}', $this->oDocument->render(OutputFormat::create()->setSpaceAfterSelectorSeparator("\n")));
65
- }
66
-
67
- public function testStringQuotingType() {
68
- $this->assertSame('.main, .test {font: italic normal bold 16px/1.2 \'Helvetica\',Verdana,sans-serif;background: white;}
69
- @media screen {.main {background-size: 100% 100%;font-size: 1.3em;background-color: #fff;}}', $this->oDocument->render(OutputFormat::create()->setStringQuotingType("'")));
70
- }
71
-
72
- public function testRGBHashNotation() {
73
- $this->assertSame('.main, .test {font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;background: white;}
74
- @media screen {.main {background-size: 100% 100%;font-size: 1.3em;background-color: rgb(255,255,255);}}', $this->oDocument->render(OutputFormat::create()->setRGBHashNotation(false)));
75
- }
76
-
77
- public function testSemicolonAfterLastRule() {
78
- $this->assertSame('.main, .test {font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;background: white}
79
- @media screen {.main {background-size: 100% 100%;font-size: 1.3em;background-color: #fff}}', $this->oDocument->render(OutputFormat::create()->setSemicolonAfterLastRule(false)));
80
- }
81
-
82
- public function testSpaceAfterRuleName() {
83
- $this->assertSame('.main, .test {font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;background: white;}
84
- @media screen {.main {background-size: 100% 100%;font-size: 1.3em;background-color: #fff;}}', $this->oDocument->render(OutputFormat::create()->setSpaceAfterRuleName("\t")));
85
- }
86
-
87
- public function testSpaceRules() {
88
- $this->assertSame('.main, .test {
89
- font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;
90
- background: white;
91
- }
92
- @media screen {.main {
93
- background-size: 100% 100%;
94
- font-size: 1.3em;
95
- background-color: #fff;
96
- }}', $this->oDocument->render(OutputFormat::create()->set('Space*Rules', "\n")));
97
- }
98
-
99
- public function testSpaceBlocks() {
100
- $this->assertSame('
101
- .main, .test {font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;background: white;}
102
- @media screen {
103
- .main {background-size: 100% 100%;font-size: 1.3em;background-color: #fff;}
104
- }
105
- ', $this->oDocument->render(OutputFormat::create()->set('Space*Blocks', "\n")));
106
- }
107
-
108
- public function testSpaceBoth() {
109
- $this->assertSame('
110
- .main, .test {
111
- font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;
112
- background: white;
113
- }
114
- @media screen {
115
- .main {
116
- background-size: 100% 100%;
117
- font-size: 1.3em;
118
- background-color: #fff;
119
- }
120
- }
121
- ', $this->oDocument->render(OutputFormat::create()->set('Space*Rules', "\n")->set('Space*Blocks', "\n")));
122
- }
123
-
124
- public function testSpaceBetweenBlocks() {
125
- $this->assertSame('.main, .test {font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;background: white;}@media screen {.main {background-size: 100% 100%;font-size: 1.3em;background-color: #fff;}}', $this->oDocument->render(OutputFormat::create()->setSpaceBetweenBlocks('')));
126
- }
127
-
128
- public function testIndentation() {
129
- $this->assertSame('
130
- .main, .test {
131
- font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;
132
- background: white;
133
- }
134
- @media screen {
135
- .main {
136
- background-size: 100% 100%;
137
- font-size: 1.3em;
138
- background-color: #fff;
139
- }
140
- }
141
- ', $this->oDocument->render(OutputFormat::create()->set('Space*Rules', "\n")->set('Space*Blocks', "\n")->setIndentation('')));
142
- }
143
-
144
- public function testSpaceBeforeBraces() {
145
- $this->assertSame('.main, .test{font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;background: white;}
146
- @media screen{.main{background-size: 100% 100%;font-size: 1.3em;background-color: #fff;}}', $this->oDocument->render(OutputFormat::create()->setSpaceBeforeOpeningBrace('')));
147
- }
148
-
149
- /**
150
- * @expectedException Sabberworm\CSS\Parsing\OutputException
151
- */
152
- public function testIgnoreExceptionsOff() {
153
- $aBlocks = $this->oDocument->getAllDeclarationBlocks();
154
- $oFirstBlock = $aBlocks[0];
155
- $oFirstBlock->removeSelector('.main');
156
- $this->assertSame('.test {font: italic normal bold 16px/1.2 "Helvetica",Verdana,sans-serif;background: white;}
157
- @media screen {.main {background-size: 100% 100%;font-size: 1.3em;background-color: #fff;}}', $this->oDocument->render(OutputFormat::create()->setIgnoreExceptions(false)));
158
- $oFirstBlock->removeSelector('.test');
159
- $this->oDocument->render(OutputFormat::create()->setIgnoreExceptions(false));
160
- }
161
-
162
- public function testIgnoreExceptionsOn() {
163
- $aBlocks = $this->oDocument->getAllDeclarationBlocks();
164
- $oFirstBlock = $aBlocks[0];
165
- $oFirstBlock->removeSelector('.main');
166
- $oFirstBlock->removeSelector('.test');
167
- $this->assertSame('@media screen {.main {background-size: 100% 100%;font-size: 1.3em;background-color: #fff;}}', $this->oDocument->render(OutputFormat::create()->setIgnoreExceptions(true)));
168
- }
169
-
170
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/ParserTest.php DELETED
@@ -1,585 +0,0 @@
1
- <?php
2
-
3
- namespace Sabberworm\CSS;
4
-
5
- use Sabberworm\CSS\CSSList\KeyFrame;
6
- use Sabberworm\CSS\Value\Size;
7
- use Sabberworm\CSS\Property\Selector;
8
- use Sabberworm\CSS\RuleSet\DeclarationBlock;
9
- use Sabberworm\CSS\Property\AtRule;
10
- use Sabberworm\CSS\Value\URL;
11
- use Sabberworm\CSS\Parsing\UnexpectedTokenException;
12
-
13
- class ParserTest extends \PHPUnit_Framework_TestCase {
14
-
15
- function testFiles() {
16
- $sDirectory = dirname(__FILE__) . '/../../files';
17
- if ($rHandle = opendir($sDirectory)) {
18
- /* This is the correct way to loop over the directory. */
19
- while (false !== ($sFileName = readdir($rHandle))) {
20
- if (strpos($sFileName, '.') === 0) {
21
- continue;
22
- }
23
- if (strrpos($sFileName, '.css') !== strlen($sFileName) - strlen('.css')) {
24
- continue;
25
- }
26
- if (strpos($sFileName, '-') === 0) {
27
- //Either a file which SHOULD fail (at least in strict mode) or a future test of a as-of-now missing feature
28
- continue;
29
- }
30
- $oParser = new Parser(file_get_contents($sDirectory . DIRECTORY_SEPARATOR . $sFileName));
31
- try {
32
- $this->assertNotEquals('', $oParser->parse()->render());
33
- } catch (\Exception $e) {
34
- $this->fail($e);
35
- }
36
- }
37
- closedir($rHandle);
38
- }
39
- }
40
-
41
- /**
42
- * @depends testFiles
43
- */
44
- function testColorParsing() {
45
- $oDoc = $this->parsedStructureForFile('colortest');
46
- foreach ($oDoc->getAllRuleSets() as $oRuleSet) {
47
- if (!$oRuleSet instanceof DeclarationBlock) {
48
- continue;
49
- }
50
- $sSelector = $oRuleSet->getSelectors();
51
- $sSelector = $sSelector[0]->getSelector();
52
- if ($sSelector === '#mine') {
53
- $aColorRule = $oRuleSet->getRules('color');
54
- $oColor = $aColorRule[0]->getValue();
55
- $this->assertSame('red', $oColor);
56
- $aColorRule = $oRuleSet->getRules('background-');
57
- $oColor = $aColorRule[0]->getValue();
58
- $this->assertEquals(array('r' => new Size(35.0, null, true, $oColor->getLineNo()), 'g' => new Size(35.0, null, true, $oColor->getLineNo()), 'b' => new Size(35.0, null, true, $oColor->getLineNo())), $oColor->getColor());
59
- $aColorRule = $oRuleSet->getRules('border-color');
60
- $oColor = $aColorRule[0]->getValue();
61
- $this->assertEquals(array('r' => new Size(10.0, null, true, $oColor->getLineNo()), 'g' => new Size(100.0, null, true, $oColor->getLineNo()), 'b' => new Size(230.0, null, true, $oColor->getLineNo())), $oColor->getColor());
62
- $oColor = $aColorRule[1]->getValue();
63
- $this->assertEquals(array('r' => new Size(10.0, null, true, $oColor->getLineNo()), 'g' => new Size(100.0, null, true, $oColor->getLineNo()), 'b' => new Size(231.0, null, true, $oColor->getLineNo()), 'a' => new Size("0000.3", null, true, $oColor->getLineNo())), $oColor->getColor());
64
- $aColorRule = $oRuleSet->getRules('outline-color');
65
- $oColor = $aColorRule[0]->getValue();
66
- $this->assertEquals(array('r' => new Size(34.0, null, true, $oColor->getLineNo()), 'g' => new Size(34.0, null, true, $oColor->getLineNo()), 'b' => new Size(34.0, null, true, $oColor->getLineNo())), $oColor->getColor());
67
- } else if($sSelector === '#yours') {
68
- $aColorRule = $oRuleSet->getRules('background-color');
69
- $oColor = $aColorRule[0]->getValue();
70
- $this->assertEquals(array('h' => new Size(220.0, null, true, $oColor->getLineNo()), 's' => new Size(10.0, '%', true, $oColor->getLineNo()), 'l' => new Size(220.0, '%', true, $oColor->getLineNo())), $oColor->getColor());
71
- $oColor = $aColorRule[1]->getValue();
72
- $this->assertEquals(array('h' => new Size(220.0, null, true, $oColor->getLineNo()), 's' => new Size(10.0, '%', true, $oColor->getLineNo()), 'l' => new Size(220.0, '%', true, $oColor->getLineNo()), 'a' => new Size(0000.3, null, true, $oColor->getLineNo())), $oColor->getColor());
73
- }
74
- }
75
- foreach ($oDoc->getAllValues('color') as $sColor) {
76
- $this->assertSame('red', $sColor);
77
- }
78
- $this->assertSame('#mine {color: red;border-color: #0a64e6;border-color: rgba(10,100,231,.3);outline-color: #222;background-color: #232323;}
79
- #yours {background-color: hsl(220,10%,220%);background-color: hsla(220,10%,220%,.3);}', $oDoc->render());
80
- }
81
-
82
- function testUnicodeParsing() {
83
- $oDoc = $this->parsedStructureForFile('unicode');
84
- foreach ($oDoc->getAllDeclarationBlocks() as $oRuleSet) {
85
- $sSelector = $oRuleSet->getSelectors();
86
- $sSelector = $sSelector[0]->getSelector();
87
- if (substr($sSelector, 0, strlen('.test-')) !== '.test-') {
88
- continue;
89
- }
90
- $aContentRules = $oRuleSet->getRules('content');
91
- $aContents = $aContentRules[0]->getValues();
92
- $sString = $aContents[0][0]->__toString();
93
- if ($sSelector == '.test-1') {
94
- $this->assertSame('" "', $sString);
95
- }
96
- if ($sSelector == '.test-2') {
97
- $this->assertSame('"é"', $sString);
98
- }
99
- if ($sSelector == '.test-3') {
100
- $this->assertSame('" "', $sString);
101
- }
102
- if ($sSelector == '.test-4') {
103
- $this->assertSame('"𝄞"', $sString);
104
- }
105
- if ($sSelector == '.test-5') {
106
- $this->assertSame('"水"', $sString);
107
- }
108
- if ($sSelector == '.test-6') {
109
- $this->assertSame('"¥"', $sString);
110
- }
111
- if ($sSelector == '.test-7') {
112
- $this->assertSame('"\A"', $sString);
113
- }
114
- if ($sSelector == '.test-8') {
115
- $this->assertSame('"\"\""', $sString);
116
- }
117
- if ($sSelector == '.test-9') {
118
- $this->assertSame('"\"\\\'"', $sString);
119
- }
120
- if ($sSelector == '.test-10') {
121
- $this->assertSame('"\\\'\\\\"', $sString);
122
- }
123
- if ($sSelector == '.test-11') {
124
- $this->assertSame('"test"', $sString);
125
- }
126
- }
127
- }
128
-
129
- function testSpecificity() {
130
- $oDoc = $this->parsedStructureForFile('specificity');
131
- $oDeclarationBlock = $oDoc->getAllDeclarationBlocks();
132
- $oDeclarationBlock = $oDeclarationBlock[0];
133
- $aSelectors = $oDeclarationBlock->getSelectors();
134
- foreach ($aSelectors as $oSelector) {
135
- switch ($oSelector->getSelector()) {
136
- case "#test .help":
137
- $this->assertSame(110, $oSelector->getSpecificity());
138
- break;
139
- case "#file":
140
- $this->assertSame(100, $oSelector->getSpecificity());
141
- break;
142
- case ".help:hover":
143
- $this->assertSame(20, $oSelector->getSpecificity());
144
- break;
145
- case "ol li::before":
146
- $this->assertSame(3, $oSelector->getSpecificity());
147
- break;
148
- case "li.green":
149
- $this->assertSame(11, $oSelector->getSpecificity());
150
- break;
151
- default:
152
- $this->fail("specificity: untested selector " . $oSelector->getSelector());
153
- }
154
- }
155
- $this->assertEquals(array(new Selector('#test .help', true)), $oDoc->getSelectorsBySpecificity('> 100'));
156
- }
157
-
158
- function testManipulation() {
159
- $oDoc = $this->parsedStructureForFile('atrules');
160
- $this->assertSame('@charset "utf-8";
161
- @font-face {font-family: "CrassRoots";src: url("../media/cr.ttf");}
162
- html, body {font-size: -.6em;}
163
- @keyframes mymove {from {top: 0px;}
164
- to {top: 200px;}}
165
- @-moz-keyframes some-move {from {top: 0px;}
166
- to {top: 200px;}}
167
- @supports ( (perspective: 10px) or (-moz-perspective: 10px) or (-webkit-perspective: 10px) or (-ms-perspective: 10px) or (-o-perspective: 10px) ) {body {font-family: "Helvetica";}}
168
- @page :pseudo-class {margin: 2in;}
169
- @-moz-document url(http://www.w3.org/),
170
- url-prefix(http://www.w3.org/Style/),
171
- domain(mozilla.org),
172
- regexp("https:.*") {body {color: purple;background: yellow;}}
173
- @media screen and (orientation: landscape) {@-ms-viewport {width: 1024px;height: 768px;}}
174
- @region-style #intro {p {color: blue;}}', $oDoc->render());
175
- foreach ($oDoc->getAllDeclarationBlocks() as $oBlock) {
176
- foreach ($oBlock->getSelectors() as $oSelector) {
177
- //Loop over all selector parts (the comma-separated strings in a selector) and prepend the id
178
- $oSelector->setSelector('#my_id ' . $oSelector->getSelector());
179
- }
180
- }
181
- $this->assertSame('@charset "utf-8";
182
- @font-face {font-family: "CrassRoots";src: url("../media/cr.ttf");}
183
- #my_id html, #my_id body {font-size: -.6em;}
184
- @keyframes mymove {from {top: 0px;}
185
- to {top: 200px;}}
186
- @-moz-keyframes some-move {from {top: 0px;}
187
- to {top: 200px;}}
188
- @supports ( (perspective: 10px) or (-moz-perspective: 10px) or (-webkit-perspective: 10px) or (-ms-perspective: 10px) or (-o-perspective: 10px) ) {#my_id body {font-family: "Helvetica";}}
189
- @page :pseudo-class {margin: 2in;}
190
- @-moz-document url(http://www.w3.org/),
191
- url-prefix(http://www.w3.org/Style/),
192
- domain(mozilla.org),
193
- regexp("https:.*") {#my_id body {color: purple;background: yellow;}}
194
- @media screen and (orientation: landscape) {@-ms-viewport {width: 1024px;height: 768px;}}
195
- @region-style #intro {#my_id p {color: blue;}}', $oDoc->render());
196
-
197
- $oDoc = $this->parsedStructureForFile('values');
198
- $this->assertSame('#header {margin: 10px 2em 1cm 2%;font-family: Verdana,Helvetica,"Gill Sans",sans-serif;font-size: 10px;color: red !important;background-color: green;background-color: rgba(0,128,0,.7);frequency: 30Hz;}
199
- body {color: green;font: 75% "Lucida Grande","Trebuchet MS",Verdana,sans-serif;}', $oDoc->render());
200
- foreach ($oDoc->getAllRuleSets() as $oRuleSet) {
201
- $oRuleSet->removeRule('font-');
202
- }
203
- $this->assertSame('#header {margin: 10px 2em 1cm 2%;color: red !important;background-color: green;background-color: rgba(0,128,0,.7);frequency: 30Hz;}
204
- body {color: green;}', $oDoc->render());
205
- foreach ($oDoc->getAllRuleSets() as $oRuleSet) {
206
- $oRuleSet->removeRule('background-');
207
- }
208
- $this->assertSame('#header {margin: 10px 2em 1cm 2%;color: red !important;frequency: 30Hz;}
209
- body {color: green;}', $oDoc->render());
210
- }
211
-
212
- function testRuleGetters() {
213
- $oDoc = $this->parsedStructureForFile('values');
214
- $aBlocks = $oDoc->getAllDeclarationBlocks();
215
- $oHeaderBlock = $aBlocks[0];
216
- $oBodyBlock = $aBlocks[1];
217
- $aHeaderRules = $oHeaderBlock->getRules('background-');
218
- $this->assertSame(2, count($aHeaderRules));
219
- $this->assertSame('background-color', $aHeaderRules[0]->getRule());
220
- $this->assertSame('background-color', $aHeaderRules[1]->getRule());
221
- $aHeaderRules = $oHeaderBlock->getRulesAssoc('background-');
222
- $this->assertSame(1, count($aHeaderRules));
223
- $this->assertSame(true, $aHeaderRules['background-color']->getValue() instanceof \Sabberworm\CSS\Value\Color);
224
- $this->assertSame('rgba', $aHeaderRules['background-color']->getValue()->getColorDescription());
225
- $oHeaderBlock->removeRule($aHeaderRules['background-color']);
226
- $aHeaderRules = $oHeaderBlock->getRules('background-');
227
- $this->assertSame(1, count($aHeaderRules));
228
- $this->assertSame('green', $aHeaderRules[0]->getValue());
229
- }
230
-
231
- function testSlashedValues() {
232
- $oDoc = $this->parsedStructureForFile('slashed');
233
- $this->assertSame('.test {font: 12px/1.5 Verdana,Arial,sans-serif;border-radius: 5px 10px 5px 10px/10px 5px 10px 5px;}', $oDoc->render());
234
- foreach ($oDoc->getAllValues(null) as $mValue) {
235
- if ($mValue instanceof Size && $mValue->isSize() && !$mValue->isRelative()) {
236
- $mValue->setSize($mValue->getSize() * 3);
237
- }
238
- }
239
- foreach ($oDoc->getAllDeclarationBlocks() as $oBlock) {
240
- $oRule = $oBlock->getRules('font');
241
- $oRule = $oRule[0];
242
- $oSpaceList = $oRule->getValue();
243
- $this->assertEquals(' ', $oSpaceList->getListSeparator());
244
- $oSlashList = $oSpaceList->getListComponents();
245
- $oCommaList = $oSlashList[1];
246
- $oSlashList = $oSlashList[0];
247
- $this->assertEquals(',', $oCommaList->getListSeparator());
248
- $this->assertEquals('/', $oSlashList->getListSeparator());
249
- $oRule = $oBlock->getRules('border-radius');
250
- $oRule = $oRule[0];
251
- $oSlashList = $oRule->getValue();
252
- $this->assertEquals('/', $oSlashList->getListSeparator());
253
- $oSpaceList1 = $oSlashList->getListComponents();
254
- $oSpaceList2 = $oSpaceList1[1];
255
- $oSpaceList1 = $oSpaceList1[0];
256
- $this->assertEquals(' ', $oSpaceList1->getListSeparator());
257
- $this->assertEquals(' ', $oSpaceList2->getListSeparator());
258
- }
259
- $this->assertSame('.test {font: 36px/1.5 Verdana,Arial,sans-serif;border-radius: 15px 30px 15px 30px/30px 15px 30px 15px;}', $oDoc->render());
260
- }
261
-
262
- function testFunctionSyntax() {
263
- $oDoc = $this->parsedStructureForFile('functions');
264
- $sExpected = 'div.main {background-image: linear-gradient(#000,#fff);}
265
- .collapser::before, .collapser::-moz-before, .collapser::-webkit-before {content: "»";font-size: 1.2em;margin-right: .2em;-moz-transition-property: -moz-transform;-moz-transition-duration: .2s;-moz-transform-origin: center 60%;}
266
- .collapser.expanded::before, .collapser.expanded::-moz-before, .collapser.expanded::-webkit-before {-moz-transform: rotate(90deg);}
267
- .collapser + * {height: 0;overflow: hidden;-moz-transition-property: height;-moz-transition-duration: .3s;}
268
- .collapser.expanded + * {height: auto;}';
269
- $this->assertSame($sExpected, $oDoc->render());
270
-
271
- foreach ($oDoc->getAllValues(null, true) as $mValue) {
272
- if ($mValue instanceof Size && $mValue->isSize()) {
273
- $mValue->setSize($mValue->getSize() * 3);
274
- }
275
- }
276
- $sExpected = str_replace(array('1.2em', '.2em', '60%'), array('3.6em', '.6em', '180%'), $sExpected);
277
- $this->assertSame($sExpected, $oDoc->render());
278
-
279
- foreach ($oDoc->getAllValues(null, true) as $mValue) {
280
- if ($mValue instanceof Size && !$mValue->isRelative() && !$mValue->isColorComponent()) {
281
- $mValue->setSize($mValue->getSize() * 2);
282
- }
283
- }
284
- $sExpected = str_replace(array('.2s', '.3s', '90deg'), array('.4s', '.6s', '180deg'), $sExpected);
285
- $this->assertSame($sExpected, $oDoc->render());
286
- }
287
-
288
- function testExpandShorthands() {
289
- $oDoc = $this->parsedStructureForFile('expand-shorthands');
290
- $sExpected = 'body {font: italic 500 14px/1.618 "Trebuchet MS",Georgia,serif;border: 2px solid #f0f;background: #ccc url("/images/foo.png") no-repeat left top;margin: 1em !important;padding: 2px 6px 3px;}';
291
- $this->assertSame($sExpected, $oDoc->render());
292
- $oDoc->expandShorthands();
293
- $sExpected = 'body {margin-top: 1em !important;margin-right: 1em !important;margin-bottom: 1em !important;margin-left: 1em !important;padding-top: 2px;padding-right: 6px;padding-bottom: 3px;padding-left: 6px;border-top-color: #f0f;border-right-color: #f0f;border-bottom-color: #f0f;border-left-color: #f0f;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-left-style: solid;border-top-width: 2px;border-right-width: 2px;border-bottom-width: 2px;border-left-width: 2px;font-style: italic;font-variant: normal;font-weight: 500;font-size: 14px;line-height: 1.618;font-family: "Trebuchet MS",Georgia,serif;background-color: #ccc;background-image: url("/images/foo.png");background-repeat: no-repeat;background-attachment: scroll;background-position: left top;}';
294
- $this->assertSame($sExpected, $oDoc->render());
295
- }
296
-
297
- function testCreateShorthands() {
298
- $oDoc = $this->parsedStructureForFile('create-shorthands');
299
- $sExpected = 'body {font-size: 2em;font-family: Helvetica,Arial,sans-serif;font-weight: bold;border-width: 2px;border-color: #999;border-style: dotted;background-color: #fff;background-image: url("foobar.png");background-repeat: repeat-y;margin-top: 2px;margin-right: 3px;margin-bottom: 4px;margin-left: 5px;}';
300
- $this->assertSame($sExpected, $oDoc->render());
301
- $oDoc->createShorthands();
302
- $sExpected = 'body {background: #fff url("foobar.png") repeat-y;margin: 2px 5px 4px 3px;border: 2px dotted #999;font: bold 2em Helvetica,Arial,sans-serif;}';
303
- $this->assertSame($sExpected, $oDoc->render());
304
- }
305
-
306
- function testNamespaces() {
307
- $oDoc = $this->parsedStructureForFile('namespaces');
308
- $sExpected = '@namespace toto "http://toto.example.org";
309
- @namespace "http://example.com/foo";
310
- @namespace foo url("http://www.example.com/");
311
- @namespace foo url("http://www.example.com/");
312
- foo|test {gaga: 1;}
313
- |test {gaga: 2;}';
314
- $this->assertSame($sExpected, $oDoc->render());
315
- }
316
-
317
- function testInnerColors() {
318
- $oDoc = $this->parsedStructureForFile('inner-color');
319
- $sExpected = 'test {background: -webkit-gradient(linear,0 0,0 bottom,from(#006cad),to(hsl(202,100%,49%)));}';
320
- $this->assertSame($sExpected, $oDoc->render());
321
- }
322
-
323
- function testPrefixedGradient() {
324
- $oDoc = $this->parsedStructureForFile('webkit');
325
- $sExpected = '.test {background: -webkit-linear-gradient(top right,white,black);}';
326
- $this->assertSame($sExpected, $oDoc->render());
327
- }
328
-
329
- function testListValueRemoval() {
330
- $oDoc = $this->parsedStructureForFile('atrules');
331
- foreach ($oDoc->getContents() as $oItem) {
332
- if ($oItem instanceof AtRule) {
333
- $oDoc->remove($oItem);
334
- continue;
335
- }
336
- }
337
- $this->assertSame('html, body {font-size: -.6em;}', $oDoc->render());
338
-
339
- $oDoc = $this->parsedStructureForFile('nested');
340
- foreach ($oDoc->getAllDeclarationBlocks() as $oBlock) {
341
- $oDoc->removeDeclarationBlockBySelector($oBlock, false);
342
- break;
343
- }
344
- $this->assertSame('html {some-other: -test(val1);}
345
- @media screen {html {some: -test(val2);}}
346
- #unrelated {other: yes;}', $oDoc->render());
347
-
348
- $oDoc = $this->parsedStructureForFile('nested');
349
- foreach ($oDoc->getAllDeclarationBlocks() as $oBlock) {
350
- $oDoc->removeDeclarationBlockBySelector($oBlock, true);
351
- break;
352
- }
353
- $this->assertSame('@media screen {html {some: -test(val2);}}
354
- #unrelated {other: yes;}', $oDoc->render());
355
- }
356
-
357
- /**
358
- * @expectedException Sabberworm\CSS\Parsing\OutputException
359
- */
360
- function testSelectorRemoval() {
361
- $oDoc = $this->parsedStructureForFile('1readme');
362
- $aBlocks = $oDoc->getAllDeclarationBlocks();
363
- $oBlock1 = $aBlocks[0];
364
- $this->assertSame(true, $oBlock1->removeSelector('html'));
365
- $sExpected = '@charset "utf-8";
366
- @font-face {font-family: "CrassRoots";src: url("../media/cr.ttf");}
367
- body {font-size: 1.6em;}';
368
- $this->assertSame($sExpected, $oDoc->render());
369
- $this->assertSame(false, $oBlock1->removeSelector('html'));
370
- $this->assertSame(true, $oBlock1->removeSelector('body'));
371
- // This tries to output a declaration block without a selector and throws.
372
- $oDoc->render();
373
- }
374
-
375
- function testComments() {
376
- $oDoc = $this->parsedStructureForFile('comments');
377
- $sExpected = '@import url("some/url.css") screen;
378
- .foo, #bar {background-color: #000;}
379
- @media screen {#foo.bar {position: absolute;}}';
380
- $this->assertSame($sExpected, $oDoc->render());
381
- }
382
-
383
- function testUrlInFile() {
384
- $oDoc = $this->parsedStructureForFile('url', Settings::create()->withMultibyteSupport(true));
385
- $sExpected = 'body {background: #fff url("http://somesite.com/images/someimage.gif") repeat top center;}
386
- body {background-url: url("http://somesite.com/images/someimage.gif");}';
387
- $this->assertSame($sExpected, $oDoc->render());
388
- }
389
-
390
- function testUrlInFileMbOff() {
391
- $oDoc = $this->parsedStructureForFile('url', Settings::create()->withMultibyteSupport(false));
392
- $sExpected = 'body {background: #fff url("http://somesite.com/images/someimage.gif") repeat top center;}
393
- body {background-url: url("http://somesite.com/images/someimage.gif");}';
394
- $this->assertSame($sExpected, $oDoc->render());
395
- }
396
-
397
- function testEmptyFile() {
398
- $oDoc = $this->parsedStructureForFile('-empty', Settings::create()->withMultibyteSupport(true));
399
- $sExpected = '';
400
- $this->assertSame($sExpected, $oDoc->render());
401
- }
402
-
403
- function testEmptyFileMbOff() {
404
- $oDoc = $this->parsedStructureForFile('-empty', Settings::create()->withMultibyteSupport(false));
405
- $sExpected = '';
406
- $this->assertSame($sExpected, $oDoc->render());
407
- }
408
-
409
- function testCharsetLenient1() {
410
- $oDoc = $this->parsedStructureForFile('-charset-after-rule', Settings::create()->withLenientParsing(true));
411
- $sExpected = '#id {prop: var(--val);}';
412
- $this->assertSame($sExpected, $oDoc->render());
413
- }
414
-
415
- function testCharsetLenient2() {
416
- $oDoc = $this->parsedStructureForFile('-charset-in-block', Settings::create()->withLenientParsing(true));
417
- $sExpected = '@media print {}';
418
- $this->assertSame($sExpected, $oDoc->render());
419
- }
420
-
421
- /**
422
- * @expectedException Sabberworm\CSS\Parsing\UnexpectedTokenException
423
- */
424
- function testCharsetFailure1() {
425
- $this->parsedStructureForFile('-charset-after-rule', Settings::create()->withLenientParsing(false));
426
- }
427
-
428
- /**
429
- * @expectedException Sabberworm\CSS\Parsing\UnexpectedTokenException
430
- */
431
- function testCharsetFailure2() {
432
- $this->parsedStructureForFile('-charset-in-block', Settings::create()->withLenientParsing(false));
433
- }
434
-
435
- function parsedStructureForFile($sFileName, $oSettings = null) {
436
- $sFile = dirname(__FILE__) . '/../../files' . DIRECTORY_SEPARATOR . "$sFileName.css";
437
- $oParser = new Parser(file_get_contents($sFile), $oSettings);
438
- return $oParser->parse();
439
- }
440
-
441
- /**
442
- * @depends testFiles
443
- */
444
- function testLineNumbersParsing() {
445
- $oDoc = $this->parsedStructureForFile('line-numbers');
446
- // array key is the expected line number
447
- $aExpected = array(
448
- 1 => array('Sabberworm\CSS\Property\Charset'),
449
- 3 => array('Sabberworm\CSS\Property\CSSNamespace'),
450
- 5 => array('Sabberworm\CSS\RuleSet\AtRuleSet'),
451
- 11 => array('Sabberworm\CSS\RuleSet\DeclarationBlock'),
452
- // Line Numbers of the inner declaration blocks
453
- 17 => array('Sabberworm\CSS\CSSList\KeyFrame', 18, 20),
454
- 23 => array('Sabberworm\CSS\Property\Import'),
455
- 25 => array('Sabberworm\CSS\RuleSet\DeclarationBlock')
456
- );
457
-
458
- $aActual = array();
459
- foreach ($oDoc->getContents() as $oContent) {
460
- $aActual[$oContent->getLineNo()] = array(get_class($oContent));
461
- if ($oContent instanceof KeyFrame) {
462
- foreach ($oContent->getContents() as $block) {
463
- $aActual[$oContent->getLineNo()][] = $block->getLineNo();
464
- }
465
- }
466
- }
467
-
468
- $aUrlExpected = array(7, 26); // expected line numbers
469
- $aUrlActual = array();
470
- foreach ($oDoc->getAllValues() as $oValue) {
471
- if ($oValue instanceof URL) {
472
- $aUrlActual[] = $oValue->getLineNo();
473
- }
474
- }
475
-
476
- // Checking for the multiline color rule lines 27-31
477
- $aExpectedColorLines = array(28, 29, 30);
478
- $aDeclBlocks = $oDoc->getAllDeclarationBlocks();
479
- // Choose the 2nd one
480
- $oDeclBlock = $aDeclBlocks[1];
481
- $aRules = $oDeclBlock->getRules();
482
- // Choose the 2nd one
483
- $oColor = $aRules[1]->getValue();
484
- $this->assertEquals(27, $aRules[1]->getLineNo());
485
-
486
- foreach ($oColor->getColor() as $oSize) {
487
- $aActualColorLines[] = $oSize->getLineNo();
488
- }
489
-
490
- $this->assertEquals($aExpectedColorLines, $aActualColorLines);
491
- $this->assertEquals($aUrlExpected, $aUrlActual);
492
- $this->assertEquals($aExpected, $aActual);
493
- }
494
-
495
- /**
496
- * @expectedException \Sabberworm\CSS\Parsing\UnexpectedTokenException
497
- * Credit: This test by @sabberworm (from https://github.com/sabberworm/PHP-CSS-Parser/pull/105#issuecomment-229643910 )
498
- */
499
- function testUnexpectedTokenExceptionLineNo() {
500
- $oParser = new Parser("\ntest: 1;", Settings::create()->beStrict());
501
- try {
502
- $oParser->parse();
503
- } catch (UnexpectedTokenException $e) {
504
- $this->assertSame(2, $e->getLineNo());
505
- throw $e;
506
- }
507
- }
508
-
509
- /**
510
- * @expectedException Sabberworm\CSS\Parsing\UnexpectedTokenException
511
- */
512
- function testIeHacksStrictParsing() {
513
- // We can't strictly parse IE hacks.
514
- $this->parsedStructureForFile('ie-hacks', Settings::create()->beStrict());
515
- }
516
-
517
- function testIeHacksParsing() {
518
- $oDoc = $this->parsedStructureForFile('ie-hacks', Settings::create()->withLenientParsing(true));
519
- $sExpected = 'p {padding-right: .75rem \9;background-image: none \9;color: red \9\0;background-color: red \9\0;background-color: red \9\0 !important;content: "red \0";content: "red઼";}';
520
- $this->assertEquals($sExpected, $oDoc->render());
521
- }
522
-
523
- /**
524
- * @depends testFiles
525
- */
526
- function testCommentExtracting() {
527
- $oDoc = $this->parsedStructureForFile('comments');
528
- $aNodes = $oDoc->getContents();
529
-
530
- // Import property.
531
- $importComments = $aNodes[0]->getComments();
532
- $this->assertCount(1, $importComments);
533
- $this->assertEquals("*\n * Comments Hell.\n ", $importComments[0]->getComment());
534
-
535
- // Declaration block.
536
- $fooBarBlock = $aNodes[1];
537
- $fooBarBlockComments = $fooBarBlock->getComments();
538
- // TODO Support comments in selectors.
539
- // $this->assertCount(2, $fooBarBlockComments);
540
- // $this->assertEquals("* Number 4 *", $fooBarBlockComments[0]->getComment());
541
- // $this->assertEquals("* Number 5 *", $fooBarBlockComments[1]->getComment());
542
-
543
- // Declaration rules.
544
- $fooBarRules = $fooBarBlock->getRules();
545
- $fooBarRule = $fooBarRules[0];
546
- $fooBarRuleComments = $fooBarRule->getComments();
547
- $this->assertCount(1, $fooBarRuleComments);
548
- $this->assertEquals(" Number 6 ", $fooBarRuleComments[0]->getComment());
549
-
550
- // Media property.
551
- $mediaComments = $aNodes[2]->getComments();
552
- $this->assertCount(0, $mediaComments);
553
-
554
- // Media children.
555
- $mediaRules = $aNodes[2]->getContents();
556
- $fooBarComments = $mediaRules[0]->getComments();
557
- $this->assertCount(1, $fooBarComments);
558
- $this->assertEquals("* Number 10 *", $fooBarComments[0]->getComment());
559
-
560
- // Media -> declaration -> rule.
561
- $fooBarRules = $mediaRules[0]->getRules();
562
- $fooBarChildComments = $fooBarRules[0]->getComments();
563
- $this->assertCount(1, $fooBarChildComments);
564
- $this->assertEquals("* Number 10b *", $fooBarChildComments[0]->getComment());
565
- }
566
-
567
- function testFlatCommentExtracting() {
568
- $parser = new Parser('div {/*Find Me!*/left:10px; text-align:left;}');
569
- $doc = $parser->parse();
570
- $contents = $doc->getContents();
571
- $divRules = $contents[0]->getRules();
572
- $comments = $divRules[0]->getComments();
573
- $this->assertCount(1, $comments);
574
- $this->assertEquals("Find Me!", $comments[0]->getComment());
575
- }
576
-
577
- function testTopLevelCommentExtracting() {
578
- $parser = new Parser('/*Find Me!*/div {left:10px; text-align:left;}');
579
- $doc = $parser->parse();
580
- $contents = $doc->getContents();
581
- $comments = $contents[0]->getComments();
582
- $this->assertCount(1, $comments);
583
- $this->assertEquals("Find Me!", $comments[0]->getComment());
584
- }
585
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/RuleSet/DeclarationBlockTest.php DELETED
@@ -1,267 +0,0 @@
1
- <?php
2
-
3
- namespace Sabberworm\CSS\RuleSet;
4
-
5
- use Sabberworm\CSS\Parser;
6
- use Sabberworm\CSS\Rule\Rule;
7
- use Sabberworm\CSS\Value\Size;
8
-
9
- class DeclarationBlockTest extends \PHPUnit_Framework_TestCase {
10
-
11
- /**
12
- * @dataProvider expandBorderShorthandProvider
13
- * */
14
- public function testExpandBorderShorthand($sCss, $sExpected) {
15
- $oParser = new Parser($sCss);
16
- $oDoc = $oParser->parse();
17
- foreach ($oDoc->getAllDeclarationBlocks() as $oDeclaration) {
18
- $oDeclaration->expandBorderShorthand();
19
- }
20
- $this->assertSame(trim((string) $oDoc), $sExpected);
21
- }
22
-
23
- public function expandBorderShorthandProvider() {
24
- return array(
25
- array('body{ border: 2px solid #000 }', 'body {border-width: 2px;border-style: solid;border-color: #000;}'),
26
- array('body{ border: none }', 'body {border-style: none;}'),
27
- array('body{ border: 2px }', 'body {border-width: 2px;}'),
28
- array('body{ border: #f00 }', 'body {border-color: #f00;}'),
29
- array('body{ border: 1em solid }', 'body {border-width: 1em;border-style: solid;}'),
30
- array('body{ margin: 1em; }', 'body {margin: 1em;}')
31
- );
32
- }
33
-
34
- /**
35
- * @dataProvider expandFontShorthandProvider
36
- * */
37
- public function testExpandFontShorthand($sCss, $sExpected) {
38
- $oParser = new Parser($sCss);
39
- $oDoc = $oParser->parse();
40
- foreach ($oDoc->getAllDeclarationBlocks() as $oDeclaration) {
41
- $oDeclaration->expandFontShorthand();
42
- }
43
- $this->assertSame(trim((string) $oDoc), $sExpected);
44
- }
45
-
46
- public function expandFontShorthandProvider() {
47
- return array(
48
- array(
49
- 'body{ margin: 1em; }',
50
- 'body {margin: 1em;}'
51
- ),
52
- array(
53
- 'body {font: 12px serif;}',
54
- 'body {font-style: normal;font-variant: normal;font-weight: normal;font-size: 12px;line-height: normal;font-family: serif;}'
55
- ),
56
- array(
57
- 'body {font: italic 12px serif;}',
58
- 'body {font-style: italic;font-variant: normal;font-weight: normal;font-size: 12px;line-height: normal;font-family: serif;}'
59
- ),
60
- array(
61
- 'body {font: italic bold 12px serif;}',
62
- 'body {font-style: italic;font-variant: normal;font-weight: bold;font-size: 12px;line-height: normal;font-family: serif;}'
63
- ),
64
- array(
65
- 'body {font: italic bold 12px/1.6 serif;}',
66
- 'body {font-style: italic;font-variant: normal;font-weight: bold;font-size: 12px;line-height: 1.6;font-family: serif;}'
67
- ),
68
- array(
69
- 'body {font: italic small-caps bold 12px/1.6 serif;}',
70
- 'body {font-style: italic;font-variant: small-caps;font-weight: bold;font-size: 12px;line-height: 1.6;font-family: serif;}'
71
- ),
72
- );
73
- }
74
-
75
- /**
76
- * @dataProvider expandBackgroundShorthandProvider
77
- * */
78
- public function testExpandBackgroundShorthand($sCss, $sExpected) {
79
- $oParser = new Parser($sCss);
80
- $oDoc = $oParser->parse();
81
- foreach ($oDoc->getAllDeclarationBlocks() as $oDeclaration) {
82
- $oDeclaration->expandBackgroundShorthand();
83
- }
84
- $this->assertSame(trim((string) $oDoc), $sExpected);
85
- }
86
-
87
- public function expandBackgroundShorthandProvider() {
88
- return array(
89
- array('body {border: 1px;}', 'body {border: 1px;}'),
90
- array('body {background: #f00;}', 'body {background-color: #f00;background-image: none;background-repeat: repeat;background-attachment: scroll;background-position: 0% 0%;}'),
91
- array('body {background: #f00 url("foobar.png");}', 'body {background-color: #f00;background-image: url("foobar.png");background-repeat: repeat;background-attachment: scroll;background-position: 0% 0%;}'),
92
- array('body {background: #f00 url("foobar.png") no-repeat;}', 'body {background-color: #f00;background-image: url("foobar.png");background-repeat: no-repeat;background-attachment: scroll;background-position: 0% 0%;}'),
93
- array('body {background: #f00 url("foobar.png") no-repeat center;}', 'body {background-color: #f00;background-image: url("foobar.png");background-repeat: no-repeat;background-attachment: scroll;background-position: center center;}'),
94
- array('body {background: #f00 url("foobar.png") no-repeat top left;}', 'body {background-color: #f00;background-image: url("foobar.png");background-repeat: no-repeat;background-attachment: scroll;background-position: top left;}'),
95
- );
96
- }
97
-
98
- /**
99
- * @dataProvider expandDimensionsShorthandProvider
100
- * */
101
- public function testExpandDimensionsShorthand($sCss, $sExpected) {
102
- $oParser = new Parser($sCss);
103
- $oDoc = $oParser->parse();
104
- foreach ($oDoc->getAllDeclarationBlocks() as $oDeclaration) {
105
- $oDeclaration->expandDimensionsShorthand();
106
- }
107
- $this->assertSame(trim((string) $oDoc), $sExpected);
108
- }
109
-
110
- public function expandDimensionsShorthandProvider() {
111
- return array(
112
- array('body {border: 1px;}', 'body {border: 1px;}'),
113
- array('body {margin-top: 1px;}', 'body {margin-top: 1px;}'),
114
- array('body {margin: 1em;}', 'body {margin-top: 1em;margin-right: 1em;margin-bottom: 1em;margin-left: 1em;}'),
115
- array('body {margin: 1em 2em;}', 'body {margin-top: 1em;margin-right: 2em;margin-bottom: 1em;margin-left: 2em;}'),
116
- array('body {margin: 1em 2em 3em;}', 'body {margin-top: 1em;margin-right: 2em;margin-bottom: 3em;margin-left: 2em;}'),
117
- );
118
- }
119
-
120
- /**
121
- * @dataProvider createBorderShorthandProvider
122
- * */
123
- public function testCreateBorderShorthand($sCss, $sExpected) {
124
- $oParser = new Parser($sCss);
125
- $oDoc = $oParser->parse();
126
- foreach ($oDoc->getAllDeclarationBlocks() as $oDeclaration) {
127
- $oDeclaration->createBorderShorthand();
128
- }
129
- $this->assertSame(trim((string) $oDoc), $sExpected);
130
- }
131
-
132
- public function createBorderShorthandProvider() {
133
- return array(
134
- array('body {border-width: 2px;border-style: solid;border-color: #000;}', 'body {border: 2px solid #000;}'),
135
- array('body {border-style: none;}', 'body {border: none;}'),
136
- array('body {border-width: 1em;border-style: solid;}', 'body {border: 1em solid;}'),
137
- array('body {margin: 1em;}', 'body {margin: 1em;}')
138
- );
139
- }
140
-
141
- /**
142
- * @dataProvider createFontShorthandProvider
143
- * */
144
- public function testCreateFontShorthand($sCss, $sExpected) {
145
- $oParser = new Parser($sCss);
146
- $oDoc = $oParser->parse();
147
- foreach ($oDoc->getAllDeclarationBlocks() as $oDeclaration) {
148
- $oDeclaration->createFontShorthand();
149
- }
150
- $this->assertSame(trim((string) $oDoc), $sExpected);
151
- }
152
-
153
- public function createFontShorthandProvider() {
154
- return array(
155
- array('body {font-size: 12px; font-family: serif}', 'body {font: 12px serif;}'),
156
- array('body {font-size: 12px; font-family: serif; font-style: italic;}', 'body {font: italic 12px serif;}'),
157
- array('body {font-size: 12px; font-family: serif; font-style: italic; font-weight: bold;}', 'body {font: italic bold 12px serif;}'),
158
- array('body {font-size: 12px; font-family: serif; font-style: italic; font-weight: bold; line-height: 1.6;}', 'body {font: italic bold 12px/1.6 serif;}'),
159
- array('body {font-size: 12px; font-family: serif; font-style: italic; font-weight: bold; line-height: 1.6; font-variant: small-caps;}', 'body {font: italic small-caps bold 12px/1.6 serif;}'),
160
- array('body {margin: 1em;}', 'body {margin: 1em;}')
161
- );
162
- }
163
-
164
- /**
165
- * @dataProvider createDimensionsShorthandProvider
166
- * */
167
- public function testCreateDimensionsShorthand($sCss, $sExpected) {
168
- $oParser = new Parser($sCss);
169
- $oDoc = $oParser->parse();
170
- foreach ($oDoc->getAllDeclarationBlocks() as $oDeclaration) {
171
- $oDeclaration->createDimensionsShorthand();
172
- }
173
- $this->assertSame(trim((string) $oDoc), $sExpected);
174
- }
175
-
176
- public function createDimensionsShorthandProvider() {
177
- return array(
178
- array('body {border: 1px;}', 'body {border: 1px;}'),
179
- array('body {margin-top: 1px;}', 'body {margin-top: 1px;}'),
180
- array('body {margin-top: 1em; margin-right: 1em; margin-bottom: 1em; margin-left: 1em;}', 'body {margin: 1em;}'),
181
- array('body {margin-top: 1em; margin-right: 2em; margin-bottom: 1em; margin-left: 2em;}', 'body {margin: 1em 2em;}'),
182
- array('body {margin-top: 1em; margin-right: 2em; margin-bottom: 3em; margin-left: 2em;}', 'body {margin: 1em 2em 3em;}'),
183
- );
184
- }
185
-
186
- /**
187
- * @dataProvider createBackgroundShorthandProvider
188
- * */
189
- public function testCreateBackgroundShorthand($sCss, $sExpected) {
190
- $oParser = new Parser($sCss);
191
- $oDoc = $oParser->parse();
192
- foreach ($oDoc->getAllDeclarationBlocks() as $oDeclaration) {
193
- $oDeclaration->createBackgroundShorthand();
194
- }
195
- $this->assertSame(trim((string) $oDoc), $sExpected);
196
- }
197
-
198
- public function createBackgroundShorthandProvider() {
199
- return array(
200
- array('body {border: 1px;}', 'body {border: 1px;}'),
201
- array('body {background-color: #f00;}', 'body {background: #f00;}'),
202
- array('body {background-color: #f00;background-image: url(foobar.png);}', 'body {background: #f00 url("foobar.png");}'),
203
- array('body {background-color: #f00;background-image: url(foobar.png);background-repeat: no-repeat;}', 'body {background: #f00 url("foobar.png") no-repeat;}'),
204
- array('body {background-color: #f00;background-image: url(foobar.png);background-repeat: no-repeat;}', 'body {background: #f00 url("foobar.png") no-repeat;}'),
205
- array('body {background-color: #f00;background-image: url(foobar.png);background-repeat: no-repeat;background-position: center;}', 'body {background: #f00 url("foobar.png") no-repeat center;}'),
206
- array('body {background-color: #f00;background-image: url(foobar.png);background-repeat: no-repeat;background-position: top left;}', 'body {background: #f00 url("foobar.png") no-repeat top left;}'),
207
- );
208
- }
209
-
210
- public function testOverrideRules() {
211
- $sCss = '.wrapper { left: 10px; text-align: left; }';
212
- $oParser = new Parser($sCss);
213
- $oDoc = $oParser->parse();
214
- $oRule = new Rule('right');
215
- $oRule->setValue('-10px');
216
- $aContents = $oDoc->getContents();
217
- $oWrapper = $aContents[0];
218
-
219
- $this->assertCount(2, $oWrapper->getRules());
220
- $aContents[0]->setRules(array($oRule));
221
-
222
- $aRules = $oWrapper->getRules();
223
- $this->assertCount(1, $aRules);
224
- $this->assertEquals('right', $aRules[0]->getRule());
225
- $this->assertEquals('-10px', $aRules[0]->getValue());
226
- }
227
-
228
- public function testRuleInsertion() {
229
- $sCss = '.wrapper { left: 10px; text-align: left; }';
230
- $oParser = new Parser($sCss);
231
- $oDoc = $oParser->parse();
232
- $aContents = $oDoc->getContents();
233
- $oWrapper = $aContents[0];
234
-
235
- $oFirst = $oWrapper->getRules('left');
236
- $this->assertCount(1, $oFirst);
237
- $oFirst = $oFirst[0];
238
-
239
- $oSecond = $oWrapper->getRules('text-');
240
- $this->assertCount(1, $oSecond);
241
- $oSecond = $oSecond[0];
242
-
243
- $oBefore = new Rule('left');
244
- $oBefore->setValue(new Size(16, 'em'));
245
-
246
- $oMiddle = new Rule('text-align');
247
- $oMiddle->setValue(new Size(1));
248
-
249
- $oAfter = new Rule('border-bottom-width');
250
- $oAfter->setValue(new Size(1, 'px'));
251
-
252
- $oWrapper->addRule($oAfter);
253
- $oWrapper->addRule($oBefore, $oFirst);
254
- $oWrapper->addRule($oMiddle, $oSecond);
255
-
256
- $aRules = $oWrapper->getRules();
257
-
258
- $this->assertSame($oBefore, $aRules[0]);
259
- $this->assertSame($oFirst, $aRules[1]);
260
- $this->assertSame($oMiddle, $aRules[2]);
261
- $this->assertSame($oSecond, $aRules[3]);
262
- $this->assertSame($oAfter, $aRules[4]);
263
-
264
- $this->assertSame('.wrapper {left: 16em;left: 10px;text-align: 1;text-align: left;border-bottom-width: 1px;}', $oDoc->render());
265
- }
266
-
267
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/RuleSet/LenientParsingTest.php DELETED
@@ -1,76 +0,0 @@
1
- <?php
2
-
3
- namespace Sabberworm\CSS\RuleSet;
4
-
5
- use Sabberworm\CSS\Parser;
6
- use Sabberworm\CSS\Settings;
7
-
8
- class LenientParsingTest extends \PHPUnit_Framework_TestCase {
9
-
10
- /**
11
- * @expectedException Sabberworm\CSS\Parsing\UnexpectedTokenException
12
- */
13
- public function testFaultToleranceOff() {
14
- $sFile = dirname(__FILE__) . '/../../../files' . DIRECTORY_SEPARATOR . "-fault-tolerance.css";
15
- $oParser = new Parser(file_get_contents($sFile), Settings::create()->beStrict());
16
- $oParser->parse();
17
- }
18
-
19
- public function testFaultToleranceOn() {
20
- $sFile = dirname(__FILE__) . '/../../../files' . DIRECTORY_SEPARATOR . "-fault-tolerance.css";
21
- $oParser = new Parser(file_get_contents($sFile), Settings::create()->withLenientParsing(true));
22
- $oResult = $oParser->parse();
23
- $this->assertSame('.test1 {}'."\n".'.test2 {hello: 2.2;hello: 2000000000000.2;}'."\n".'#test {}'."\n".'#test2 {help: none;}', $oResult->render());
24
- }
25
-
26
- /**
27
- * @expectedException Sabberworm\CSS\Parsing\UnexpectedTokenException
28
- */
29
- public function testEndToken() {
30
- $sFile = dirname(__FILE__) . '/../../../files' . DIRECTORY_SEPARATOR . "-end-token.css";
31
- $oParser = new Parser(file_get_contents($sFile), Settings::create()->beStrict());
32
- $oParser->parse();
33
- }
34
-
35
- /**
36
- * @expectedException Sabberworm\CSS\Parsing\UnexpectedTokenException
37
- */
38
- public function testEndToken2() {
39
- $sFile = dirname(__FILE__) . '/../../../files' . DIRECTORY_SEPARATOR . "-end-token-2.css";
40
- $oParser = new Parser(file_get_contents($sFile), Settings::create()->beStrict());
41
- $oParser->parse();
42
- }
43
-
44
- public function testEndTokenPositive() {
45
- $sFile = dirname(__FILE__) . '/../../../files' . DIRECTORY_SEPARATOR . "-end-token.css";
46
- $oParser = new Parser(file_get_contents($sFile), Settings::create()->withLenientParsing(true));
47
- $oResult = $oParser->parse();
48
- $this->assertSame("", $oResult->render());
49
- }
50
-
51
- public function testEndToken2Positive() {
52
- $sFile = dirname(__FILE__) . '/../../../files' . DIRECTORY_SEPARATOR . "-end-token-2.css";
53
- $oParser = new Parser(file_get_contents($sFile), Settings::create()->withLenientParsing(true));
54
- $oResult = $oParser->parse();
55
- $this->assertSame('#home .bg-layout {background-image: url("/bundles/main/img/bg1.png?5");}', $oResult->render());
56
- }
57
-
58
- public function testLocaleTrap() {
59
- setlocale(LC_ALL, "pt_PT", "no");
60
- $sFile = dirname(__FILE__) . '/../../../files' . DIRECTORY_SEPARATOR . "-fault-tolerance.css";
61
- $oParser = new Parser(file_get_contents($sFile), Settings::create()->withLenientParsing(true));
62
- $oResult = $oParser->parse();
63
- $this->assertSame('.test1 {}'."\n".'.test2 {hello: 2.2;hello: 2000000000000.2;}'."\n".'#test {}'."\n".'#test2 {help: none;}', $oResult->render());
64
- }
65
-
66
- public function testCaseInsensitivity() {
67
- $sFile = dirname(__FILE__) . '/../../../files' . DIRECTORY_SEPARATOR . "case-insensitivity.css";
68
- $oParser = new Parser(file_get_contents($sFile));
69
- $oResult = $oParser->parse();
70
- $this->assertSame('@charset "utf-8";
71
- @import url("test.css");
72
- @media screen {}
73
- #myid {case: insensitive !important;frequency: 30Hz;font-size: 1em;color: #ff0;color: hsl(40,40%,30%);font-family: Arial;}', $oResult->render());
74
- }
75
-
76
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/RuleSet/index.php DELETED
File without changes
vendor/sabberworm/php-css-parser/tests/Sabberworm/CSS/index.php DELETED
File without changes
vendor/sabberworm/php-css-parser/tests/Sabberworm/index.php DELETED
File without changes
vendor/sabberworm/php-css-parser/tests/bootstrap.php DELETED
@@ -1,10 +0,0 @@
1
- <?php
2
-
3
- spl_autoload_register(function($class)
4
- {
5
- $file = __DIR__.'/../lib/'.strtr($class, '\\', '/').'.php';
6
- if (file_exists($file)) {
7
- require $file;
8
- return true;
9
- }
10
- });
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/-charset-after-rule.css DELETED
@@ -1,5 +0,0 @@
1
- #id {
2
- prop: var(--val);
3
- }
4
-
5
- @charset 'utf-16';
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/-charset-in-block.css DELETED
@@ -1,3 +0,0 @@
1
- @media print {
2
- @charset 'utf-16';
3
- }
 
 
 
vendor/sabberworm/php-css-parser/tests/files/-empty.css DELETED
File without changes
vendor/sabberworm/php-css-parser/tests/files/-end-token-2.css DELETED
@@ -1 +0,0 @@
1
- #home .bg-layout { background-image: url(/bundles/main/img/bg1.png?5);};
 
vendor/sabberworm/php-css-parser/tests/files/-end-token.css DELETED
@@ -1 +0,0 @@
1
- /* Test comment
 
vendor/sabberworm/php-css-parser/tests/files/-fault-tolerance.css DELETED
@@ -1,15 +0,0 @@
1
- .test1 {
2
- //gaga: hello;
3
- }
4
-
5
- .test2 {
6
- *hello: 1;
7
- hello: 2.2;
8
- hello: 2000000000000.2;
9
- }
10
-
11
- #test {
12
- #hello: 1}
13
-
14
- #test2 {
15
- help: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/-tobedone.css DELETED
@@ -1,9 +0,0 @@
1
- .some[selectors-may='contain-a-{'] {
2
-
3
- }
4
-
5
- @media only screen and (min-width: 200px) {
6
- .test {
7
- prop: val;
8
- }
9
- }
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/1readme.css DELETED
@@ -1,10 +0,0 @@
1
- @charset "utf-8";
2
-
3
- @font-face {
4
- font-family: "CrassRoots";
5
- src: url("../media/cr.ttf")
6
- }
7
-
8
- html, body {
9
- font-size: 1.6em
10
- }
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/2readme.css DELETED
@@ -1,5 +0,0 @@
1
- #header {
2
- margin: 10px 2em 1cm 2%;
3
- font-family: Verdana, Helvetica, "Gill Sans", sans-serif;
4
- color: red !important;
5
- }
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/atrules.css DELETED
@@ -1,57 +0,0 @@
1
- @charset "utf-8";
2
-
3
- @font-face {
4
- font-family: "CrassRoots";
5
- src: url("../media/cr.ttf")
6
- }
7
-
8
- html, body {
9
- font-size: -0.6em
10
- }
11
-
12
- @keyframes mymove {
13
- from { top: 0px; }
14
- to { top: 200px; }
15
- }
16
-
17
- @-moz-keyframes some-move {
18
- from { top: 0px; }
19
- to { top: 200px; }
20
- }
21
-
22
- @supports ( (perspective: 10px) or (-moz-perspective: 10px) or (-webkit-perspective: 10px) or (-ms-perspective: 10px) or (-o-perspective: 10px) ) {
23
- body {
24
- font-family: 'Helvetica';
25
- }
26
- }
27
-
28
- @page :pseudo-class {
29
- margin:2in;
30
- }
31
-
32
- @-moz-document url(http://www.w3.org/),
33
- url-prefix(http://www.w3.org/Style/),
34
- domain(mozilla.org),
35
- regexp("https:.*") {
36
- /* CSS rules here apply to:
37
- + The page "http://www.w3.org/".
38
- + Any page whose URL begins with "http://www.w3.org/Style/"
39
- + Any page whose URL's host is "mozilla.org" or ends with
40
- ".mozilla.org"
41
- + Any page whose URL starts with "https:" */
42
-
43
- /* make the above-mentioned pages really ugly */
44
- body { color: purple; background: yellow; }
45
- }
46
-
47
- @media screen and (orientation: landscape) {
48
- @-ms-viewport {
49
- width: 1024px;
50
- height: 768px;
51
- }
52
- /* CSS for landscape layout goes here */
53
- }
54
-
55
- @region-style #intro {
56
- p { color: blue; }
57
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/case-insensitivity.css DELETED
@@ -1,15 +0,0 @@
1
- @CharSet "utf-8";
2
- @IMPORT uRL(test.css);
3
-
4
- @MEDIA screen {
5
-
6
- }
7
-
8
- #myid {
9
- CaSe: insensitive !imPORTANT;
10
- frequency: 30hz;
11
- font-size: 1EM;
12
- color: RGB(255, 255, 0);
13
- color: hSL(40, 40%, 30%);
14
- font-Family: Arial; /* The value needs to remain capitalized */
15
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/colortest.css DELETED
@@ -1,12 +0,0 @@
1
- #mine {
2
- color: red;
3
- border-color: rgb(10, 100, 230);
4
- border-color: rgba(10, 100, 231, 0.3);
5
- outline-color: #222;
6
- background-color: #232323;
7
- }
8
-
9
- #yours {
10
- background-color: hsl(220, 10%, 220%);
11
- background-color: hsla(220, 10%, 220%, 0.3);
12
- }
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/comments.css DELETED
@@ -1,17 +0,0 @@
1
- /**
2
- * Comments Hell.
3
- */
4
- @import /* Number 1 */"some/url.css"/* Number 2 */ screen/* Number 3 */;
5
-
6
- .foo, /* Number 4 */ #bar/* Number 5 */ {
7
- background-color/* Number 6 */: #000/* Number 7 */;
8
- }
9
-
10
- @media /* Number 8 */screen /* Number 9 */{
11
- /** Number 10 **/
12
- #foo.bar {
13
- /** Number 10b **/
14
- position: absolute;/**/
15
- }
16
- }
17
- /** Number 11 **/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/create-shorthands.css DELETED
@@ -1,6 +0,0 @@
1
- body {
2
- font-size: 2em; font-family: Helvetica,Arial,sans-serif; font-weight: bold;
3
- border-width: 2px; border-color: #999; border-style: dotted;
4
- background-color: #fff; background-image: url('foobar.png'); background-repeat: repeat-y;
5
- margin-top: 2px; margin-right: 3px; margin-bottom: 4px; margin-left: 5px;
6
- }
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/docuwiki.css DELETED
@@ -1 +0,0 @@
1
- div.dokuwiki div.ajax_qsearch{position:absolute;right:237px;;width:200px;opacity:0.9;display:none;font-size:80%;line-height:1.2em;border:1px solid #8cacbb;background-color:#f7f9fa;text-align:left;padding:4px;}
 
vendor/sabberworm/php-css-parser/tests/files/expand-shorthands.css DELETED
@@ -1,7 +0,0 @@
1
- body {
2
- font: italic 500 14px/1.618 "Trebuchet MS", Georgia, serif;
3
- border: 2px solid #f0f;
4
- background: #ccc url("/images/foo.png") no-repeat left top;
5
- margin: 1em !important;
6
- padding: 2px 6px 3px;
7
- }
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/functions.css DELETED
@@ -1,21 +0,0 @@
1
- div.main { background-image: linear-gradient(#000, #fff) }
2
- .collapser::before,
3
- .collapser::-moz-before,
4
- .collapser::-webkit-before {
5
- content: "»";
6
- font-size: 1.2em;
7
- margin-right: .2em;
8
- -moz-transition-property: -moz-transform;
9
- -moz-transition-duration: .2s;
10
- -moz-transform-origin: center 60%;
11
- }
12
- .collapser.expanded::before,
13
- .collapser.expanded::-moz-before,
14
- .collapser.expanded::-webkit-before { -moz-transform: rotate(90deg) }
15
- .collapser + * {
16
- height: 0;
17
- overflow: hidden;
18
- -moz-transition-property: height;
19
- -moz-transition-duration: .3s;
20
- }
21
- .collapser.expanded + * { height: auto }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/ie-hacks.css DELETED
@@ -1,9 +0,0 @@
1
- p {
2
- padding-right: .75rem \9;
3
- background-image: none \9;
4
- color:red\9\0;
5
- background-color:red \9 \0;
6
- background-color:red \9 \0 !important;
7
- content: "red \9\0";
8
- content: "red\0abc";
9
- }
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/ie.css DELETED
@@ -1,6 +0,0 @@
1
- .nav-thumb-wrapper:hover img, a.activeSlide img {
2
- filter: alpha(opacity=100);
3
- -moz-opacity: 1;
4
- -khtml-opacity: 1;
5
- opacity: 1;
6
- }
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/important.css DELETED
@@ -1,8 +0,0 @@
1
- div.rating-cancel,div.star-rating{float:left;width:17px;height:15px;text-indent:-999em;cursor:pointer;display:block;background:transparent;overflow:hidden}
2
- div.rating-cancel,div.rating-cancel a{background:url(images/delete.gif) no-repeat 0 -16px}
3
- div.star-rating,div.star-rating a{background:url(images/star.gif) no-repeat 0 0px}
4
- div.rating-cancel a,div.star-rating a{display:block;width:16px;height:100%;background-position:0 0px;border:0}
5
- div.star-rating-on a{background-position:0 -16px!important}
6
- div.star-rating-hover a{background-position:0 -32px}
7
- div.star-rating-readonly a{cursor:default !important}
8
- div.star-rating{background:transparent!important; overflow:hidden!important}
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/index.php DELETED
File without changes
vendor/sabberworm/php-css-parser/tests/files/inner-color.css DELETED
@@ -1,3 +0,0 @@
1
- test {
2
- background: -webkit-gradient(linear, 0 0, 0 bottom, from(#006cad), to(hsl(202, 100%, 49%)));
3
- }
 
 
 
vendor/sabberworm/php-css-parser/tests/files/line-numbers.css DELETED
@@ -1,32 +0,0 @@
1
- @charset "utf-8"; /* line 1 */
2
-
3
- @namespace "http://toto.example.org"; /* line 3 */
4
-
5
- @font-face { /* line 5 */
6
- font-family: "CrassRoots";
7
- src: url("http://example.com/media/cr.ttf") /* line 7 */
8
- }
9
-
10
-
11
- #header { /* line 11 */
12
- margin: 10px 2em 1cm 2%;
13
- font-family: Verdana, Helvetica, "Gill Sans", sans-serif;
14
- color: red !important;
15
- }
16
-
17
- @keyframes mymove { /* line 17 */
18
- from { top: 0px; } /* line 18 */
19
-
20
- to { top: 200px; } /* line 20 */
21
- }
22
-
23
- @IMPORT uRL(test.css); /* line 23 */
24
-
25
- body {
26
- background: #FFFFFF url("http://somesite.com/images/someimage.gif") repeat top center; /* line 25 */
27
- color: rgb( /* line 27 */
28
- 233, /* line 28 */
29
- 100, /* line 29 */
30
- 450 /* line 30 */
31
- );
32
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/namespaces.css DELETED
@@ -1,18 +0,0 @@
1
- /* From the spec at http://www.w3.org/TR/css3-namespace/ */
2
-
3
- @namespace toto "http://toto.example.org";
4
- @namespace "http://example.com/foo";
5
-
6
-
7
- /* From an introduction at http://www.blooberry.com/indexdot/css/syntax/atrules/namespace.htm */
8
- @namespace foo url("http://www.example.com/");
9
- @namespace foo url('http://www.example.com/');
10
-
11
-
12
- foo|test {
13
- gaga: 1;
14
- }
15
-
16
- |test {
17
- gaga: 2;
18
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/nested.css DELETED
@@ -1,17 +0,0 @@
1
- html {
2
- some: -test(val1);
3
- }
4
-
5
- html {
6
- some-other: -test(val1);
7
- }
8
-
9
- @media screen {
10
- html {
11
- some: -test(val2);
12
- }
13
- }
14
-
15
- #unrelated {
16
- other: yes;
17
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/slashed.css DELETED
@@ -1,4 +0,0 @@
1
- .test {
2
- font: 12px/1.5 Verdana, Arial, sans-serif;
3
- border-radius: 5px 10px 5px 10px / 10px 5px 10px 5px;
4
- }
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/specificity.css DELETED
@@ -1,7 +0,0 @@
1
- #test .help,
2
- #file,
3
- .help:hover,
4
- li.green,
5
- ol li::before {
6
- font-family: Helvetica;
7
- }
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/unicode.css DELETED
@@ -1,12 +0,0 @@
1
- .test-1 { content: "\20"; } /* Same as " " */
2
- .test-2 { content: "\E9"; } /* Same as "é" */
3
- .test-3 { content: "\0020"; } /* Same as " " */
4
- .test-5 { content: "\6C34" } /* Same as "水" */
5
- .test-6 { content: "\00A5" } /* Same as "¥" */
6
- .test-7 { content: '\a' } /* Same as "\A" (Newline) */
7
- .test-8 { content: "\"\22" } /* Same as "\"\"" */
8
- .test-9 { content: "\"\27" } /* Same as ""\"\'"" */
9
- .test-10 { content: "\'\\" } /* Same as "'\" */
10
- .test-11 { content: "\test" } /* Same as "test" */
11
-
12
- .test-4 { content: "\1D11E" } /* Beyond the Basic Multilingual Plane */
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/url.css DELETED
@@ -1,4 +0,0 @@
1
- body { background: #FFFFFF url("http://somesite.com/images/someimage.gif") repeat top center; }
2
- body {
3
- background-url: url("http://somesite.com/images/someimage.gif");
4
- }
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/values.css DELETED
@@ -1,14 +0,0 @@
1
- #header {
2
- margin: 10px 2em 1cm 2%;
3
- font-family: Verdana, Helvetica, "Gill Sans", sans-serif;
4
- font-size: 10px;
5
- color: red !important;
6
- background-color: green;
7
- background-color: rgba(0,128,0,0.7);
8
- frequency: 30Hz;
9
- }
10
-
11
- body {
12
- color: green;
13
- font: 75% "Lucida Grande", "Trebuchet MS", Verdana, sans-serif;
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
vendor/sabberworm/php-css-parser/tests/files/webkit.css DELETED
@@ -1 +0,0 @@
1
- .test { background:-webkit-linear-gradient(top right, white, black)}
 
vendor/sabberworm/php-css-parser/tests/files/whitespace.css DELETED
@@ -1,3 +0,0 @@
1
- .test {
2
- background-image : url ( 4px ) ;
3
- }
 
 
 
vendor/sabberworm/php-css-parser/tests/index.php DELETED
File without changes
vendor/sabberworm/php-css-parser/tests/phpunit.xml DELETED
@@ -1 +0,0 @@
1
- <phpunit bootstrap="bootstrap.php"></phpunit>
 
vendor/sabberworm/php-css-parser/tests/quickdump.php DELETED
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env php
2
- <?php
3
-
4
- require_once(dirname(__FILE__).'/bootstrap.php');
5
-
6
- $sSource = file_get_contents('php://stdin');
7
- $oParser = new Sabberworm\CSS\Parser($sSource);
8
-
9
- $oDoc = $oParser->parse();
10
- echo "\n".'#### Input'."\n\n```css\n";
11
- print $sSource;
12
-
13
- echo "\n```\n\n".'#### Structure (`var_dump()`)'."\n\n```php\n";
14
- var_dump($oDoc);
15
-
16
- echo "\n```\n\n".'#### Output (`render()`)'."\n\n```css\n";
17
- print $oDoc->render();
18
-
19
- echo "\n```\n";
20
-