less 2.5.1 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/.travis.yml +3 -2
  2. package/CHANGELOG.md +41 -0
  3. package/Gruntfile.js +5 -10
  4. package/README.md +3 -3
  5. package/appveyor.yml +2 -2
  6. package/bin/lessc +1 -0
  7. package/bower.json +1 -2
  8. package/dist/less.js +969 -605
  9. package/dist/less.min.js +13 -9
  10. package/gradlew +0 -0
  11. package/lib/less/contexts.js +0 -1
  12. package/lib/less/functions/color.js +5 -2
  13. package/lib/less/functions/math-helper.js +16 -0
  14. package/lib/less/functions/math.js +4 -16
  15. package/lib/less/functions/number.js +7 -2
  16. package/lib/less/index.js +1 -1
  17. package/lib/less/parser/parser-input.js +68 -68
  18. package/lib/less/parser/parser.js +159 -75
  19. package/lib/less/transform-tree.js +1 -0
  20. package/lib/less/tree/anonymous.js +4 -2
  21. package/lib/less/tree/color.js +4 -1
  22. package/lib/less/tree/comment.js +2 -6
  23. package/lib/less/tree/directive.js +3 -18
  24. package/lib/less/tree/element.js +9 -2
  25. package/lib/less/tree/extend.js +10 -5
  26. package/lib/less/tree/import.js +23 -5
  27. package/lib/less/tree/media.js +4 -2
  28. package/lib/less/tree/mixin-call.js +31 -18
  29. package/lib/less/tree/mixin-definition.js +19 -7
  30. package/lib/less/tree/node.js +49 -0
  31. package/lib/less/tree/rule.js +1 -1
  32. package/lib/less/tree/ruleset.js +107 -125
  33. package/lib/less/tree/selector.js +4 -9
  34. package/lib/less/tree/unit.js +2 -2
  35. package/lib/less/visitors/extend-visitor.js +17 -8
  36. package/lib/less/visitors/import-visitor.js +5 -0
  37. package/lib/less/visitors/index.js +1 -0
  38. package/lib/less/visitors/set-tree-visibility-visitor.js +38 -0
  39. package/lib/less/visitors/to-css-visitor.js +181 -98
  40. package/lib/less-browser/bootstrap.js +28 -2
  41. package/lib/less-browser/cache.js +11 -4
  42. package/lib/less-browser/error-reporting.js +10 -10
  43. package/lib/less-browser/file-manager.js +1 -1
  44. package/lib/less-browser/image-size.js +28 -0
  45. package/lib/less-browser/index.js +9 -10
  46. package/package.json +14 -14
  47. package/test/browser/less/errors/image-height-error.less +3 -0
  48. package/test/browser/less/errors/image-height-error.txt +4 -0
  49. package/test/browser/less/errors/image-size-error.less +3 -0
  50. package/test/browser/less/errors/image-size-error.txt +4 -0
  51. package/test/browser/less/errors/image-width-error.less +3 -0
  52. package/test/browser/less/errors/image-width-error.txt +4 -0
  53. package/test/browser/less.js +23 -19
  54. package/test/css/comments2.css +7 -1
  55. package/test/css/compression/compression.css +1 -1
  56. package/test/css/css-3.css +6 -0
  57. package/test/css/extend-selector.css +7 -0
  58. package/test/css/extract-and-length.css +1 -1
  59. package/test/css/functions.css +3 -3
  60. package/test/css/import-reference-issues.css +24 -0
  61. package/test/css/import-reference.css +5 -1
  62. package/test/css/include-path/include-path.css +1 -1
  63. package/test/css/include-path-string/include-path-string.css +1 -1
  64. package/test/css/mixins-args.css +51 -1
  65. package/test/css/mixins-guards.css +36 -0
  66. package/test/css/no-strict-math/mixins-guards.css +12 -0
  67. package/test/css/no-strict-math/no-sm-operations.css +12 -0
  68. package/test/css/operations.css +1 -0
  69. package/test/css/scope.css +1 -1
  70. package/test/css/strings.css +1 -1
  71. package/test/css/url-args/urls.css +5 -5
  72. package/test/css/urls.css +8 -8
  73. package/test/css/variables.css +5 -5
  74. package/test/data/image.jpg +0 -0
  75. package/test/data/image.svg +2 -1
  76. package/test/data/page.html +1 -1
  77. package/test/index.js +1 -0
  78. package/test/less/comments2.less +11 -0
  79. package/test/less/css-3.less +10 -2
  80. package/test/less/errors/at-rules-undefined-var.txt +4 -4
  81. package/test/less/errors/css-guard-default-func.txt +4 -4
  82. package/test/less/errors/javascript-undefined-var.txt +4 -4
  83. package/test/less/errors/mixins-guards-default-func-1.txt +4 -4
  84. package/test/less/errors/mixins-guards-default-func-2.txt +4 -4
  85. package/test/less/errors/mixins-guards-default-func-3.txt +4 -4
  86. package/test/less/errors/parse-error-media-no-block-1.txt +1 -1
  87. package/test/less/errors/parse-error-media-no-block-2.txt +1 -1
  88. package/test/less/errors/parse-error-media-no-block-3.txt +1 -1
  89. package/test/less/errors/percentage-non-number-argument.less +3 -0
  90. package/test/less/errors/percentage-non-number-argument.txt +4 -0
  91. package/test/less/errors/property-interp-not-defined.txt +2 -2
  92. package/test/less/extend-selector.less +12 -1
  93. package/test/less/import/import-inline-invalid-css.less +1 -0
  94. package/test/less/import/import-reference.less +10 -1
  95. package/test/less/import-reference-issues/appender-reference-1968.less +6 -0
  96. package/test/less/import-reference-issues/global-scope-import.less +13 -0
  97. package/test/less/import-reference-issues/global-scope-nested.less +3 -0
  98. package/test/less/import-reference-issues/mixin-1968.less +8 -0
  99. package/test/less/import-reference-issues/multiple-import-nested.less +12 -0
  100. package/test/less/import-reference-issues/multiple-import.less +10 -0
  101. package/test/less/import-reference-issues/simple-mixin.css +3 -0
  102. package/test/less/import-reference-issues/simple-ruleset-2162.less +3 -0
  103. package/test/less/import-reference-issues.less +50 -0
  104. package/test/less/import-reference.less +2 -0
  105. package/test/less/mixins-args.less +48 -0
  106. package/test/less/mixins-guards.less +78 -0
  107. package/test/less/no-strict-math/mixins-guards.less +25 -0
  108. package/test/less/no-strict-math/no-sm-operations.less +10 -0
  109. package/test/less/operations.less +1 -0
  110. package/test/less-bom/comments2.less +11 -0
  111. package/test/less-bom/css-3.less +10 -2
  112. package/test/less-bom/errors/at-rules-undefined-var.txt +4 -4
  113. package/test/less-bom/errors/css-guard-default-func.txt +4 -4
  114. package/test/less-bom/errors/javascript-undefined-var.txt +4 -4
  115. package/test/less-bom/errors/mixins-guards-default-func-1.txt +4 -4
  116. package/test/less-bom/errors/mixins-guards-default-func-2.txt +4 -4
  117. package/test/less-bom/errors/mixins-guards-default-func-3.txt +4 -4
  118. package/test/less-bom/errors/parse-error-media-no-block-1.txt +1 -1
  119. package/test/less-bom/errors/parse-error-media-no-block-2.txt +1 -1
  120. package/test/less-bom/errors/parse-error-media-no-block-3.txt +1 -1
  121. package/test/less-bom/errors/percentage-non-number-argument.less +3 -0
  122. package/test/less-bom/errors/percentage-non-number-argument.txt +4 -0
  123. package/test/less-bom/errors/property-interp-not-defined.txt +2 -2
  124. package/test/less-bom/extend-selector.less +12 -1
  125. package/test/less-bom/import/import-inline-invalid-css.less +1 -0
  126. package/test/less-bom/import/import-reference.less +10 -1
  127. package/test/less-bom/import-reference-issues/appender-reference-1968.less +6 -0
  128. package/test/less-bom/import-reference-issues/global-scope-import.less +13 -0
  129. package/test/less-bom/import-reference-issues/global-scope-nested.less +3 -0
  130. package/test/less-bom/import-reference-issues/mixin-1968.less +8 -0
  131. package/test/less-bom/import-reference-issues/multiple-import-nested.less +12 -0
  132. package/test/less-bom/import-reference-issues/multiple-import.less +10 -0
  133. package/test/less-bom/import-reference-issues/simple-mixin.css +3 -0
  134. package/test/less-bom/import-reference-issues/simple-ruleset-2162.less +3 -0
  135. package/test/less-bom/import-reference-issues.less +50 -0
  136. package/test/less-bom/import-reference.less +2 -0
  137. package/test/less-bom/mixins-args.less +48 -0
  138. package/test/less-bom/mixins-guards.less +78 -0
  139. package/test/less-bom/no-strict-math/mixins-guards.less +25 -0
  140. package/test/less-bom/no-strict-math/no-sm-operations.less +10 -0
  141. package/test/less-bom/operations.less +1 -0
  142. package/test/less-test.js +6 -1
  143. package/.idea/.name +0 -1
  144. package/.idea/jsLibraryMappings.xml +0 -6
  145. package/.idea/less.js.iml +0 -9
  146. package/.idea/libraries/less_js_node_modules.xml +0 -14
  147. package/.idea/misc.xml +0 -14
  148. package/.idea/modules.xml +0 -8
  149. package/.idea/vcs.xml +0 -6
  150. package/.idea/workspace.xml +0 -281
@@ -1,9 +1,97 @@
1
1
  var tree = require("../tree"),
2
2
  Visitor = require("./visitor");
3
3
 
4
+ var CSSVisitorUtils = function(context) {
5
+ this._visitor = new Visitor(this);
6
+ this._context = context;
7
+ };
8
+
9
+ CSSVisitorUtils.prototype = {
10
+ containsSilentNonBlockedChild: function(bodyRules) {
11
+ var rule;
12
+ if (bodyRules == null) {
13
+ return false;
14
+ }
15
+ for (var r = 0; r < bodyRules.length; r++) {
16
+ rule = bodyRules[r];
17
+ if (rule.isSilent && rule.isSilent(this._context) && !rule.blocksVisibility()) {
18
+ //the directive contains something that was referenced (likely by extend)
19
+ //therefore it needs to be shown in output too
20
+ return true;
21
+ }
22
+ }
23
+ return false;
24
+ },
25
+
26
+ keepOnlyVisibleChilds: function(owner) {
27
+ if (owner == null || owner.rules == null) {
28
+ return ;
29
+ }
30
+
31
+ owner.rules = owner.rules.filter(function(thing) {
32
+ return thing.isVisible();
33
+ }
34
+ );
35
+ },
36
+
37
+ isEmpty: function(owner) {
38
+ if (owner == null || owner.rules == null) {
39
+ return true;
40
+ }
41
+ return owner.rules.length === 0;
42
+ },
43
+
44
+ hasVisibleSelector: function(rulesetNode) {
45
+ if (rulesetNode == null || rulesetNode.paths == null) {
46
+ return false;
47
+ }
48
+ return rulesetNode.paths.length > 0;
49
+ },
50
+
51
+ resolveVisibility: function (node, originalRules) {
52
+ if (!node.blocksVisibility()) {
53
+ if (this.isEmpty(node) && !this.containsSilentNonBlockedChild(originalRules)) {
54
+ return ;
55
+ }
56
+
57
+ return node;
58
+ }
59
+
60
+ var compiledRulesBody = node.rules[0];
61
+ this.keepOnlyVisibleChilds(compiledRulesBody);
62
+
63
+ if (this.isEmpty(compiledRulesBody)) {
64
+ return ;
65
+ }
66
+
67
+ node.ensureVisibility();
68
+ node.removeVisibilityBlock();
69
+
70
+ return node;
71
+ },
72
+
73
+ isVisibleRuleset: function(rulesetNode) {
74
+ if (rulesetNode.firstRoot) {
75
+ return true;
76
+ }
77
+
78
+ if (this.isEmpty(rulesetNode)) {
79
+ return false;
80
+ }
81
+
82
+ if (!rulesetNode.root && !this.hasVisibleSelector(rulesetNode)) {
83
+ return false;
84
+ }
85
+
86
+ return true;
87
+ }
88
+
89
+ };
90
+
4
91
  var ToCSSVisitor = function(context) {
5
92
  this._visitor = new Visitor(this);
6
93
  this._context = context;
94
+ this.utils = new CSSVisitorUtils(context);
7
95
  };
8
96
 
9
97
  ToCSSVisitor.prototype = {
@@ -13,7 +101,7 @@ ToCSSVisitor.prototype = {
13
101
  },
14
102
 
15
103
  visitRule: function (ruleNode, visitArgs) {
16
- if (ruleNode.variable) {
104
+ if (ruleNode.blocksVisibility() || ruleNode.variable) {
17
105
  return;
18
106
  }
19
107
  return ruleNode;
@@ -29,34 +117,71 @@ ToCSSVisitor.prototype = {
29
117
  },
30
118
 
31
119
  visitComment: function (commentNode, visitArgs) {
32
- if (commentNode.isSilent(this._context)) {
120
+ if (commentNode.blocksVisibility() || commentNode.isSilent(this._context)) {
33
121
  return;
34
122
  }
35
123
  return commentNode;
36
124
  },
37
125
 
38
126
  visitMedia: function(mediaNode, visitArgs) {
127
+ var originalRules = mediaNode.rules[0].rules;
39
128
  mediaNode.accept(this._visitor);
40
129
  visitArgs.visitDeeper = false;
41
130
 
42
- if (!mediaNode.rules.length) {
43
- return;
44
- }
45
- return mediaNode;
131
+ return this.utils.resolveVisibility(mediaNode, originalRules);
46
132
  },
47
133
 
48
134
  visitImport: function (importNode, visitArgs) {
49
- if (importNode.path.currentFileInfo.reference !== undefined && importNode.css) {
50
- return;
135
+ if (importNode.blocksVisibility()) {
136
+ return ;
51
137
  }
52
138
  return importNode;
53
139
  },
54
140
 
55
141
  visitDirective: function(directiveNode, visitArgs) {
56
- if (directiveNode.name === "@charset") {
57
- if (!directiveNode.getIsReferenced()) {
58
- return;
142
+ if (directiveNode.rules && directiveNode.rules.length) {
143
+ return this.visitDirectiveWithBody(directiveNode, visitArgs);
144
+ } else {
145
+ return this.visitDirectiveWithoutBody(directiveNode, visitArgs);
146
+ }
147
+ return directiveNode;
148
+ },
149
+
150
+ visitDirectiveWithBody: function(directiveNode, visitArgs) {
151
+ //if there is only one nested ruleset and that one has no path, then it is
152
+ //just fake ruleset
153
+ function hasFakeRuleset(directiveNode) {
154
+ var bodyRules = directiveNode.rules;
155
+ return bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0);
156
+ }
157
+ function getBodyRules(directiveNode) {
158
+ var nodeRules = directiveNode.rules;
159
+ if (hasFakeRuleset(directiveNode)) {
160
+ return nodeRules[0].rules;
59
161
  }
162
+
163
+ return nodeRules;
164
+ }
165
+ //it is still true that it is only one ruleset in array
166
+ //this is last such moment
167
+ //process childs
168
+ var originalRules = getBodyRules(directiveNode);
169
+ directiveNode.accept(this._visitor);
170
+ visitArgs.visitDeeper = false;
171
+
172
+ if (!this.utils.isEmpty(directiveNode)) {
173
+ this._mergeRules(directiveNode.rules[0].rules);
174
+ }
175
+
176
+ return this.utils.resolveVisibility(directiveNode, originalRules);
177
+ },
178
+
179
+ visitDirectiveWithoutBody: function(directiveNode, visitArgs) {
180
+ if (directiveNode.blocksVisibility()) {
181
+ return;
182
+ }
183
+
184
+ if (directiveNode.name === "@charset") {
60
185
  // Only output the debug info together with subsequent @charset definitions
61
186
  // a comment (or @media statement) before the actual @charset directive would
62
187
  // be considered illegal css as it has to be on the first line
@@ -70,59 +195,7 @@ ToCSSVisitor.prototype = {
70
195
  }
71
196
  this.charset = true;
72
197
  }
73
- function hasVisibleChild(directiveNode) {
74
- //prepare list of childs
75
- var rule, bodyRules = directiveNode.rules;
76
- //if there is only one nested ruleset and that one has no path, then it is
77
- //just fake ruleset that got not replaced and we need to look inside it to
78
- //get real childs
79
- if (bodyRules.length === 1 && (!bodyRules[0].paths || bodyRules[0].paths.length === 0)) {
80
- bodyRules = bodyRules[0].rules;
81
- }
82
- for (var r = 0; r < bodyRules.length; r++) {
83
- rule = bodyRules[r];
84
- if (rule.getIsReferenced && rule.getIsReferenced()) {
85
- //the directive contains something that was referenced (likely by extend)
86
- //therefore it needs to be shown in output too
87
- return true;
88
- }
89
- }
90
- return false;
91
- }
92
-
93
- if (directiveNode.rules && directiveNode.rules.length) {
94
- //it is still true that it is only one ruleset in array
95
- //this is last such moment
96
- this._mergeRules(directiveNode.rules[0].rules);
97
- //process childs
98
- directiveNode.accept(this._visitor);
99
- visitArgs.visitDeeper = false;
100
-
101
- // the directive was directly referenced and therefore needs to be shown in the output
102
- if (directiveNode.getIsReferenced()) {
103
- return directiveNode;
104
- }
105
-
106
- if (!directiveNode.rules || !directiveNode.rules.length) {
107
- return ;
108
- }
109
-
110
- //the directive was not directly referenced - we need to check whether some of its childs
111
- //was referenced
112
- if (hasVisibleChild(directiveNode)) {
113
- //marking as referenced in case the directive is stored inside another directive
114
- directiveNode.markReferenced();
115
- return directiveNode;
116
- }
117
198
 
118
- //The directive was not directly referenced and does not contain anything that
119
- //was referenced. Therefore it must not be shown in output.
120
- return ;
121
- } else {
122
- if (!directiveNode.getIsReferenced()) {
123
- return;
124
- }
125
- }
126
199
  return directiveNode;
127
200
  },
128
201
 
@@ -138,28 +211,16 @@ ToCSSVisitor.prototype = {
138
211
  },
139
212
 
140
213
  visitRuleset: function (rulesetNode, visitArgs) {
214
+ //at this point rulesets are nested into each other
141
215
  var rule, rulesets = [];
142
216
  if (rulesetNode.firstRoot) {
143
217
  this.checkPropertiesInRoot(rulesetNode.rules);
144
218
  }
145
219
  if (! rulesetNode.root) {
146
- if (rulesetNode.paths) {
147
- rulesetNode.paths = rulesetNode.paths
148
- .filter(function(p) {
149
- var i;
150
- if (p[0].elements[0].combinator.value === ' ') {
151
- p[0].elements[0].combinator = new(tree.Combinator)('');
152
- }
153
- for (i = 0; i < p.length; i++) {
154
- if (p[i].getIsReferenced() && p[i].getIsOutput()) {
155
- return true;
156
- }
157
- }
158
- return false;
159
- });
160
- }
220
+ //remove invisible paths
221
+ this._compileRulesetPaths(rulesetNode);
161
222
 
162
- // Compile rules and rulesets
223
+ // remove rulesets from this ruleset body and compile them separately
163
224
  var nodeRules = rulesetNode.rules, nodeRuleCnt = nodeRules ? nodeRules.length : 0;
164
225
  for (var i = 0; i < nodeRuleCnt; ) {
165
226
  rule = nodeRules[i];
@@ -173,7 +234,8 @@ ToCSSVisitor.prototype = {
173
234
  i++;
174
235
  }
175
236
  // accept the visitor to remove rules and refactor itself
176
- // then we can decide now whether we want it or not
237
+ // then we can decide nogw whether we want it or not
238
+ // compile body
177
239
  if (nodeRuleCnt > 0) {
178
240
  rulesetNode.accept(this._visitor);
179
241
  } else {
@@ -181,33 +243,46 @@ ToCSSVisitor.prototype = {
181
243
  }
182
244
  visitArgs.visitDeeper = false;
183
245
 
184
- nodeRules = rulesetNode.rules;
185
- if (nodeRules) {
186
- this._mergeRules(nodeRules);
187
- nodeRules = rulesetNode.rules;
188
- }
189
- if (nodeRules) {
190
- this._removeDuplicateRules(nodeRules);
191
- nodeRules = rulesetNode.rules;
192
- }
193
-
194
- // now decide whether we keep the ruleset
195
- if (nodeRules && nodeRules.length > 0 && rulesetNode.paths.length > 0) {
196
- rulesets.splice(0, 0, rulesetNode);
197
- }
198
- } else {
246
+ } else { //if (! rulesetNode.root) {
199
247
  rulesetNode.accept(this._visitor);
200
248
  visitArgs.visitDeeper = false;
201
- if (rulesetNode.firstRoot || (rulesetNode.rules && rulesetNode.rules.length > 0)) {
202
- rulesets.splice(0, 0, rulesetNode);
203
- }
204
249
  }
250
+
251
+ if (rulesetNode.rules) {
252
+ this._mergeRules(rulesetNode.rules);
253
+ this._removeDuplicateRules(rulesetNode.rules);
254
+ }
255
+
256
+ //now decide whether we keep the ruleset
257
+ if (this.utils.isVisibleRuleset(rulesetNode)) {
258
+ rulesetNode.ensureVisibility();
259
+ rulesets.splice(0, 0, rulesetNode);
260
+ }
261
+
205
262
  if (rulesets.length === 1) {
206
263
  return rulesets[0];
207
264
  }
208
265
  return rulesets;
209
266
  },
210
267
 
268
+ _compileRulesetPaths: function(rulesetNode) {
269
+ if (rulesetNode.paths) {
270
+ rulesetNode.paths = rulesetNode.paths
271
+ .filter(function(p) {
272
+ var i;
273
+ if (p[0].elements[0].combinator.value === ' ') {
274
+ p[0].elements[0].combinator = new(tree.Combinator)('');
275
+ }
276
+ for (i = 0; i < p.length; i++) {
277
+ if (p[i].isVisible() && p[i].getIsOutput()) {
278
+ return true;
279
+ }
280
+ }
281
+ return false;
282
+ });
283
+ }
284
+ },
285
+
211
286
  _removeDuplicateRules: function(rules) {
212
287
  if (!rules) { return; }
213
288
 
@@ -294,6 +369,14 @@ ToCSSVisitor.prototype = {
294
369
  rule.value = toValue(spacedGroups);
295
370
  }
296
371
  });
372
+ },
373
+
374
+ visitAnonymous: function(anonymousNode, visitArgs) {
375
+ if (anonymousNode.blocksVisibility()) {
376
+ return ;
377
+ }
378
+ anonymousNode.accept(this._visitor);
379
+ return anonymousNode;
297
380
  }
298
381
  };
299
382
 
@@ -3,7 +3,7 @@
3
3
  * used in the browser distributed version of less
4
4
  * to kick-start less using the browser api
5
5
  */
6
- /*global window */
6
+ /*global window, document */
7
7
 
8
8
  // shim Promise if required
9
9
  require('promise/polyfill.js');
@@ -15,11 +15,37 @@ var less = module.exports = require("./index")(window, options);
15
15
 
16
16
  window.less = less;
17
17
 
18
+ var css, head, style;
19
+
20
+ // Always restore page visibility
21
+ function resolveOrReject(data) {
22
+ if (data.filename) {
23
+ console.warn(data);
24
+ }
25
+ if (!options.async) {
26
+ head.removeChild(style);
27
+ }
28
+ }
29
+
18
30
  if (options.onReady) {
19
31
  if (/!watch/.test(window.location.hash)) {
20
32
  less.watch();
21
33
  }
34
+ // Simulate synchronous stylesheet loading by blocking page rendering
35
+ if (!options.async) {
36
+ css = 'body { display: none !important }';
37
+ head = document.head || document.getElementsByTagName('head')[0];
38
+ style = document.createElement('style');
39
+
40
+ style.type = 'text/css';
41
+ if (style.styleSheet) {
42
+ style.styleSheet.cssText = css;
43
+ } else {
44
+ style.appendChild(document.createTextNode(css));
45
+ }
22
46
 
47
+ head.appendChild(style);
48
+ }
23
49
  less.registerStylesheetsImmediately();
24
- less.pageLoadFinished = less.refresh(less.env === 'development');
50
+ less.pageLoadFinished = less.refresh(less.env === 'development').then(resolveOrReject, resolveOrReject);
25
51
  }
@@ -8,25 +8,32 @@ module.exports = function(window, options, logger) {
8
8
  } catch (_) {}
9
9
  }
10
10
  return {
11
- setCSS: function(path, lastModified, styles) {
11
+ setCSS: function(path, lastModified, modifyVars, styles) {
12
12
  if (cache) {
13
13
  logger.info('saving ' + path + ' to cache.');
14
14
  try {
15
15
  cache.setItem(path, styles);
16
16
  cache.setItem(path + ':timestamp', lastModified);
17
+ if (modifyVars) {
18
+ cache.setItem(path + ':vars', JSON.stringify(modifyVars));
19
+ }
17
20
  } catch(e) {
18
21
  //TODO - could do with adding more robust error handling
19
22
  logger.error('failed to save "' + path + '" to local storage for caching.');
20
23
  }
21
24
  }
22
25
  },
23
- getCSS: function(path, webInfo) {
26
+ getCSS: function(path, webInfo, modifyVars) {
24
27
  var css = cache && cache.getItem(path),
25
- timestamp = cache && cache.getItem(path + ':timestamp');
28
+ timestamp = cache && cache.getItem(path + ':timestamp'),
29
+ vars = cache && cache.getItem(path + ':vars');
30
+
31
+ modifyVars = modifyVars || {};
26
32
 
27
33
  if (timestamp && webInfo.lastModified &&
28
34
  (new Date(webInfo.lastModified).valueOf() ===
29
- new Date(timestamp).valueOf())) {
35
+ new Date(timestamp).valueOf()) &&
36
+ (!modifyVars && !vars || JSON.stringify(modifyVars) === vars)) {
30
37
  // Use local copy
31
38
  return css;
32
39
  }
@@ -104,16 +104,6 @@ module.exports = function(window, less, options) {
104
104
  }
105
105
  }
106
106
 
107
- function error(e, rootHref) {
108
- if (!options.errorReporting || options.errorReporting === "html") {
109
- errorHTML(e, rootHref);
110
- } else if (options.errorReporting === "console") {
111
- errorConsole(e, rootHref);
112
- } else if (typeof options.errorReporting === 'function') {
113
- options.errorReporting("add", e, rootHref);
114
- }
115
- }
116
-
117
107
  function removeErrorHTML(path) {
118
108
  var node = window.document.getElementById('less-error-message:' + utils.extractId(path));
119
109
  if (node) {
@@ -163,6 +153,16 @@ module.exports = function(window, less, options) {
163
153
  less.logger.error(content);
164
154
  }
165
155
 
156
+ function error(e, rootHref) {
157
+ if (!options.errorReporting || options.errorReporting === "html") {
158
+ errorHTML(e, rootHref);
159
+ } else if (options.errorReporting === "console") {
160
+ errorConsole(e, rootHref);
161
+ } else if (typeof options.errorReporting === 'function') {
162
+ options.errorReporting("add", e, rootHref);
163
+ }
164
+ }
165
+
166
166
  return {
167
167
  add: error,
168
168
  remove: removeError
@@ -39,7 +39,7 @@ module.exports = function(options, logger) {
39
39
  FileManager.prototype.doXHR = function doXHR(url, type, callback, errback) {
40
40
 
41
41
  var xhr = getXMLHttpRequest();
42
- var async = options.isFileProtocol ? options.fileAsync : options.async;
42
+ var async = options.isFileProtocol ? options.fileAsync : true;
43
43
 
44
44
  if (typeof xhr.overrideMimeType === 'function') {
45
45
  xhr.overrideMimeType('text/css');
@@ -0,0 +1,28 @@
1
+ module.exports = function() {
2
+
3
+ var functionRegistry = require("./../less/functions/function-registry");
4
+
5
+ function imageSize() {
6
+ throw {
7
+ type: "Runtime",
8
+ message: "Image size functions are not supported in browser version of less"
9
+ };
10
+ }
11
+
12
+ var imageFunctions = {
13
+ "image-size": function(filePathNode) {
14
+ imageSize(this, filePathNode);
15
+ return -1;
16
+ },
17
+ "image-width": function(filePathNode) {
18
+ imageSize(this, filePathNode);
19
+ return -1;
20
+ },
21
+ "image-height": function(filePathNode) {
22
+ imageSize(this, filePathNode);
23
+ return -1;
24
+ }
25
+ };
26
+
27
+ functionRegistry.addMultiple(imageFunctions);
28
+ };
@@ -8,6 +8,7 @@ var addDataAttr = require("./utils").addDataAttr,
8
8
  module.exports = function(window, options) {
9
9
  var document = window.document;
10
10
  var less = require('../less')();
11
+
11
12
  //module.exports = less;
12
13
  less.options = options;
13
14
  var environment = less.environment,
@@ -19,6 +20,7 @@ module.exports = function(window, options) {
19
20
  require("./log-listener")(less, options);
20
21
  var errors = require("./error-reporting")(window, less, options);
21
22
  var cache = less.cache = options.cache || require("./cache")(window, options, less.logger);
23
+ require('./image-size')(less.environment);
22
24
 
23
25
  //Setup user functions
24
26
  if (options.functions) {
@@ -112,14 +114,13 @@ module.exports = function(window, options) {
112
114
  if (webInfo) {
113
115
  webInfo.remaining = remaining;
114
116
 
115
- if (!instanceOptions.modifyVars) {
116
- var css = cache.getCSS(path, webInfo);
117
- if (!reload && css) {
118
- webInfo.local = true;
119
- callback(null, css, data, sheet, webInfo, path);
120
- return;
121
- }
117
+ var css = cache.getCSS(path, webInfo, instanceOptions.modifyVars);
118
+ if (!reload && css) {
119
+ webInfo.local = true;
120
+ callback(null, css, data, sheet, webInfo, path);
121
+ return;
122
122
  }
123
+
123
124
  }
124
125
 
125
126
  //TODO add tests around how this behaves when reloading
@@ -132,9 +133,7 @@ module.exports = function(window, options) {
132
133
  callback(e);
133
134
  } else {
134
135
  result.css = postProcessCSS(result.css);
135
- if (!instanceOptions.modifyVars) {
136
- cache.setCSS(sheet.href, webInfo.lastModified, result.css);
137
- }
136
+ cache.setCSS(sheet.href, webInfo.lastModified, instanceOptions.modifyVars, result.css);
138
137
  callback(null, result.css, data, sheet, webInfo, path);
139
138
  }
140
139
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "less",
3
- "version": "2.5.1",
3
+ "version": "2.6.1",
4
4
  "description": "Leaner CSS",
5
5
  "homepage": "http://lesscss.org",
6
6
  "author": {
@@ -37,26 +37,26 @@
37
37
  },
38
38
  "optionalDependencies": {
39
39
  "errno": "^0.1.1",
40
- "graceful-fs": "^3.0.5",
41
- "image-size": "~0.3.5",
40
+ "graceful-fs": "^4.1.2",
41
+ "image-size": "~0.4.0",
42
42
  "mime": "^1.2.11",
43
43
  "mkdirp": "^0.5.0",
44
- "promise": "^6.0.1",
44
+ "promise": "^7.1.1",
45
45
  "request": "^2.51.0",
46
- "source-map": "^0.4.2"
46
+ "source-map": "^0.5.3"
47
47
  },
48
48
  "devDependencies": {
49
- "diff": "^1.0",
49
+ "diff": "^2.2.1",
50
50
  "grunt": "^0.4.5",
51
- "grunt-contrib-clean": "^0.6.0",
52
- "grunt-contrib-concat": "^0.5.0",
53
- "grunt-contrib-connect": "^0.9.0",
54
- "grunt-contrib-jasmine": "^0.8.2",
55
- "grunt-contrib-jshint": "^0.11.0",
56
- "grunt-contrib-uglify": "^0.8.0",
57
- "grunt-jscs": "^1.6.0",
51
+ "grunt-contrib-clean": "^1.0.0",
52
+ "grunt-contrib-concat": "^1.0.0",
53
+ "grunt-contrib-connect": "^0.11.2",
54
+ "grunt-contrib-jasmine": "^1.0.0",
55
+ "grunt-contrib-jshint": "^1.0.0",
56
+ "grunt-contrib-uglify": "^0.11.0",
57
+ "grunt-jscs": "^2.7.0",
58
58
  "grunt-shell": "^1.1.1",
59
- "grunt-browserify": "~3.5.0",
59
+ "grunt-browserify": "~4.0.1",
60
60
  "jit-grunt": "^0.9.1",
61
61
  "time-grunt": "^1.0.0",
62
62
  "grunt-saucelabs": "^8.3.2"
@@ -0,0 +1,3 @@
1
+ .test-height{
2
+ height: image-height("../data/image.jpg")
3
+ }
@@ -0,0 +1,4 @@
1
+ RuntimeError: error evaluating function `image-height`: Image size functions are not supported in browser version of less in image-height-error.less on line 2, column 11:
2
+ 1 .test-height{
3
+ 2 height: image-height("../data/image.jpg")
4
+ 3 }
@@ -0,0 +1,3 @@
1
+ .test-size{
2
+ size: image-size("../data/image.jpg")
3
+ }
@@ -0,0 +1,4 @@
1
+ RuntimeError: error evaluating function `image-size`: Image size functions are not supported in browser version of less in image-size-error.less on line 2, column 9:
2
+ 1 .test-size{
3
+ 2 size: image-size("../data/image.jpg")
4
+ 3 }
@@ -0,0 +1,3 @@
1
+ .test-width{
2
+ width: image-width("../data/image.jpg")
3
+ }
@@ -0,0 +1,4 @@
1
+ RuntimeError: error evaluating function `image-width`: Image size functions are not supported in browser version of less in image-width-error.less on line 2, column 10:
2
+ 1 .test-width{
3
+ 2 width: image-width("../data/image.jpg")
4
+ 3 }