diff options
Diffstat (limited to 'js/controllers/styles-controller.js')
-rwxr-xr-x | js/controllers/styles-controller.js | 70 |
1 files changed, 54 insertions, 16 deletions
diff --git a/js/controllers/styles-controller.js b/js/controllers/styles-controller.js index 647c0870..cbc00676 100755 --- a/js/controllers/styles-controller.js +++ b/js/controllers/styles-controller.js | |||
@@ -94,11 +94,18 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
94 | // Returns null if sheet not found (as in non-ninja projects) | 94 | // Returns null if sheet not found (as in non-ninja projects) |
95 | // Setter will handle null case | 95 | // Setter will handle null case |
96 | this.defaultStylesheet = this.getSheetFromElement(this.CONST.DEFAULT_SHEET_ID); | 96 | this.defaultStylesheet = this.getSheetFromElement(this.CONST.DEFAULT_SHEET_ID); |
97 | 97 | ||
98 | //debugger; | 98 | this.userStyleSheets = nj.toArray(document._document.styleSheets).filter(function(sheet) { |
99 | return sheet !== this._stageStylesheet; | ||
100 | }, this); | ||
101 | |||
102 | NJevent('styleSheetsReady', this); | ||
99 | }, | 103 | }, |
100 | enumerable : false | 104 | enumerable : false |
101 | }, | 105 | }, |
106 | userStyleSheets : { | ||
107 | value : null | ||
108 | }, | ||
102 | _stageStylesheet : { | 109 | _stageStylesheet : { |
103 | value : null | 110 | value : null |
104 | }, | 111 | }, |
@@ -183,6 +190,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
183 | ///// attach specificity to rule object | 190 | ///// attach specificity to rule object |
184 | ///// if rule is css keyframes, return rule and don't attach specificity | 191 | ///// if rule is css keyframes, return rule and don't attach specificity |
185 | if (rule instanceof WebKitCSSKeyframesRule) { | 192 | if (rule instanceof WebKitCSSKeyframesRule) { |
193 | |||
186 | return rule; | 194 | return rule; |
187 | } | 195 | } |
188 | rule[this.CONST.SPECIFICITY_KEY] = this.getSpecificity(rule.selectorText); | 196 | rule[this.CONST.SPECIFICITY_KEY] = this.getSpecificity(rule.selectorText); |
@@ -209,10 +217,12 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
209 | } | 217 | } |
210 | 218 | ||
211 | var selectorToOverride = getSelector.bind(this)(element, ruleToOverride), | 219 | var selectorToOverride = getSelector.bind(this)(element, ruleToOverride), |
212 | overrideData, rule; | 220 | overrideData, rule, isRuleLocked; |
221 | |||
222 | isRuleLocked = this.isSheetLocked(ruleToOverride.parentStyleSheet); | ||
213 | 223 | ||
214 | ///// Get the overriding selector and className | 224 | ///// Get the overriding selector and className |
215 | overrideData = this.createOverrideSelector(selectorToOverride, element.nodeName); | 225 | overrideData = this.createOverrideSelector(selectorToOverride, element.nodeName, isRuleLocked); |
216 | 226 | ||
217 | ///// Create new rule with selector and insert it after the rule we're overriding | 227 | ///// Create new rule with selector and insert it after the rule we're overriding |
218 | rule = this.addRule(overrideData.selector + ' { }', this.getRuleIndex(ruleToOverride)+1); | 228 | rule = this.addRule(overrideData.selector + ' { }', this.getRuleIndex(ruleToOverride)+1); |
@@ -226,7 +236,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
226 | }, | 236 | }, |
227 | 237 | ||
228 | createOverrideSelector : { | 238 | createOverrideSelector : { |
229 | value: function(selectorToOverride, classPrefix, className) { | 239 | value: function(selectorToOverride, classPrefix, increaseSpecificity, className) { |
230 | var tokens = selectorToOverride.split(/\s/), | 240 | var tokens = selectorToOverride.split(/\s/), |
231 | newClass = className || this.generateClassName(classPrefix, true), | 241 | newClass = className || this.generateClassName(classPrefix, true), |
232 | lastToken, pseudoSplit, base, pseudo, newToken, newSelector; | 242 | lastToken, pseudoSplit, base, pseudo, newToken, newSelector; |
@@ -247,10 +257,19 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
247 | if(base.indexOf('#') !== -1) { | 257 | if(base.indexOf('#') !== -1) { |
248 | newToken = base + '.' + newClass + pseudo; | 258 | newToken = base + '.' + newClass + pseudo; |
249 | } else { | 259 | } else { |
250 | ///// Replace last class or attribute selector | 260 | if(increaseSpecificity) { |
251 | ///// Get everything right before the last class or attribute selector | 261 | ///// Increases specificity by one class selector |
252 | ///// to support compound selector values: (i.e. .firstClass.secondClass) | 262 | ///// We'll do a direct append to the base class |
253 | newToken = base.substring(0, Math.max(base.lastIndexOf('.'), base.lastIndexOf('['))); | 263 | ///// if we want to increase the specificity |
264 | newToken = base; | ||
265 | } else { | ||
266 | ///// Maintains original specificity | ||
267 | ///// Replace last class or attribute selector | ||
268 | ///// Get everything right before the last class or attribute selector | ||
269 | ///// to support compound selector values: (i.e. .firstClass.secondClass) | ||
270 | newToken = base.substring(0, Math.max(base.lastIndexOf('.'), base.lastIndexOf('['))); | ||
271 | } | ||
272 | |||
254 | ///// Append the generated class | 273 | ///// Append the generated class |
255 | newToken += '.' + newClass + pseudo; | 274 | newToken += '.' + newClass + pseudo; |
256 | } | 275 | } |
@@ -795,7 +814,9 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
795 | ///// method to apply/test the new value | 814 | ///// method to apply/test the new value |
796 | dec.setProperty(property, value, priority); | 815 | dec.setProperty(property, value, priority); |
797 | 816 | ||
798 | this.styleSheetModified(rule.parentStyleSheet); | 817 | if(rule.parentStyleSheet) { |
818 | this.styleSheetModified(rule.parentStyleSheet); | ||
819 | } | ||
799 | 820 | ||
800 | ///// Return browser value for value we just set | 821 | ///// Return browser value for value we just set |
801 | return dec.getPropertyValue(property); | 822 | return dec.getPropertyValue(property); |
@@ -969,12 +990,13 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
969 | var doc = element.ownerDocument, | 990 | var doc = element.ownerDocument, |
970 | useImportant = false, | 991 | useImportant = false, |
971 | cache = this._getCachedRuleForProperty(element, property), | 992 | cache = this._getCachedRuleForProperty(element, property), |
972 | dominantRule, override, className, browserValue; | 993 | dominantRule, override, className, browserValue, cacheMatchesMany; |
973 | 994 | ||
974 | if(cache) { | 995 | if(cache) { |
975 | ///// We've cached the rule for this property! | 996 | ///// We've cached the rule for this property! |
976 | //console.log('Styles Controller :: setElementStyle - We found the cached rule!'); | 997 | //console.log('Styles Controller :: setElementStyle - We found the cached rule!'); |
977 | dominantRule = cache; | 998 | dominantRule = cache; |
999 | cacheMatchesMany = this.matchesMultipleElements(dominantRule, doc); | ||
978 | } else { | 1000 | } else { |
979 | ///// Use Dominant Rule logic to find the right place to add the style | 1001 | ///// Use Dominant Rule logic to find the right place to add the style |
980 | ///// Pass "true" to method to return an override object, which | 1002 | ///// Pass "true" to method to return an override object, which |
@@ -982,7 +1004,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
982 | dominantRule = this.getDominantRuleForElement(element, property, true, isStageElement); | 1004 | dominantRule = this.getDominantRuleForElement(element, property, true, isStageElement); |
983 | 1005 | ||
984 | } | 1006 | } |
985 | 1007 | ||
986 | ///// Did we find a dominant rule? | 1008 | ///// Did we find a dominant rule? |
987 | if(!dominantRule) { | 1009 | if(!dominantRule) { |
988 | ///// No. This means there was no rule with this property, and no | 1010 | ///// No. This means there was no rule with this property, and no |
@@ -1000,6 +1022,13 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1000 | useImportant = dominantRule.useImportant; | 1022 | useImportant = dominantRule.useImportant; |
1001 | dominantRule = override.rule; | 1023 | dominantRule = override.rule; |
1002 | this.addClass(element, override.className); | 1024 | this.addClass(element, override.className); |
1025 | } else if(cacheMatchesMany) { | ||
1026 | ///// Only happens when the cached rule applies to multiple | ||
1027 | ///// elements - we must create override | ||
1028 | override = this.createOverrideRule(dominantRule, element); | ||
1029 | useImportant = !!dominantRule.style.getPropertyPriority(property); | ||
1030 | dominantRule = override.rule; | ||
1031 | this.addClass(element, override.className); | ||
1003 | } | 1032 | } |
1004 | 1033 | ||
1005 | 1034 | ||
@@ -1007,7 +1036,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1007 | browserValue = this.setStyle(dominantRule, property, value, useImportant); | 1036 | browserValue = this.setStyle(dominantRule, property, value, useImportant); |
1008 | 1037 | ||
1009 | ///// Only cache the dominant rule if the style value was valid, and not already cached | 1038 | ///// Only cache the dominant rule if the style value was valid, and not already cached |
1010 | if(browserValue && !cache) { | 1039 | if(browserValue && (!cache || cacheMatchesMany)) { |
1011 | this._setCachedRuleForProperty(element, property, dominantRule); | 1040 | this._setCachedRuleForProperty(element, property, dominantRule); |
1012 | } | 1041 | } |
1013 | 1042 | ||
@@ -1242,8 +1271,12 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1242 | doc.head.appendChild(sheetElement); | 1271 | doc.head.appendChild(sheetElement); |
1243 | sheet = this.getSheetFromElement(sheetElement, doc); | 1272 | sheet = this.getSheetFromElement(sheetElement, doc); |
1244 | 1273 | ||
1274 | this.userStyleSheets.push(sheet); | ||
1275 | |||
1245 | this.styleSheetModified(sheet); | 1276 | this.styleSheetModified(sheet); |
1246 | 1277 | ||
1278 | NJevent('newStyleSheet', sheet); | ||
1279 | |||
1247 | return sheet; | 1280 | return sheet; |
1248 | } | 1281 | } |
1249 | }, | 1282 | }, |
@@ -1266,6 +1299,12 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1266 | } | 1299 | } |
1267 | }, | 1300 | }, |
1268 | 1301 | ||
1302 | isSheetLocked : { | ||
1303 | value: function(sheet) { | ||
1304 | return !!sheet.ownerNode.dataset['ninjaFileReadOnly']; | ||
1305 | } | ||
1306 | }, | ||
1307 | |||
1269 | ///// Style Sheet Modified | 1308 | ///// Style Sheet Modified |
1270 | ///// Method to call whenever a stylesheet change is made | 1309 | ///// Method to call whenever a stylesheet change is made |
1271 | ///// Dispatches an event, and keeps list of dirty style sheets | 1310 | ///// Dispatches an event, and keeps list of dirty style sheets |
@@ -1306,11 +1345,10 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1306 | this.dirtyStyleSheets.length = 0; | 1345 | this.dirtyStyleSheets.length = 0; |
1307 | 1346 | ||
1308 | if(doc) { | 1347 | if(doc) { |
1309 | var stillDirty = this.dirtyStyleSheets.filter(function(sheet) { | 1348 | this.dirtyStyleSheets = null; |
1349 | this.dirtyStyleSheets = this.dirtyStyleSheets.filter(function(sheet) { | ||
1310 | return sheet.document !== doc; | 1350 | return sheet.document !== doc; |
1311 | }); | 1351 | }); |
1312 | this.dirtyStyleSheets = null; | ||
1313 | this.dirtyStyleSheets = stillDirty; | ||
1314 | } | 1352 | } |
1315 | 1353 | ||
1316 | 1354 | ||