diff options
Diffstat (limited to 'js/controllers/styles-controller.js')
-rwxr-xr-x | js/controllers/styles-controller.js | 80 |
1 files changed, 64 insertions, 16 deletions
diff --git a/js/controllers/styles-controller.js b/js/controllers/styles-controller.js index ae504f0e..f6977a00 100755 --- a/js/controllers/styles-controller.js +++ b/js/controllers/styles-controller.js | |||
@@ -82,6 +82,11 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
82 | ///// If the document is null set default stylesheets to null | 82 | ///// If the document is null set default stylesheets to null |
83 | 83 | ||
84 | if(!document) { | 84 | if(!document) { |
85 | this._activeDocument = null; | ||
86 | this._stageStylesheet = null; | ||
87 | this.defaultStylesheet = null; | ||
88 | this.userStyleSheets = []; | ||
89 | this.clearDirtyStyleSheets(); | ||
85 | return false; | 90 | return false; |
86 | } | 91 | } |
87 | 92 | ||
@@ -93,11 +98,18 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
93 | // Returns null if sheet not found (as in non-ninja projects) | 98 | // Returns null if sheet not found (as in non-ninja projects) |
94 | // Setter will handle null case | 99 | // Setter will handle null case |
95 | this.defaultStylesheet = this.getSheetFromElement(this.CONST.DEFAULT_SHEET_ID); | 100 | this.defaultStylesheet = this.getSheetFromElement(this.CONST.DEFAULT_SHEET_ID); |
96 | 101 | ||
97 | //debugger; | 102 | this.userStyleSheets = nj.toArray(document._document.styleSheets).filter(function(sheet) { |
103 | return sheet !== this._stageStylesheet; | ||
104 | }, this); | ||
105 | |||
106 | NJevent('styleSheetsReady', this); | ||
98 | }, | 107 | }, |
99 | enumerable : false | 108 | enumerable : false |
100 | }, | 109 | }, |
110 | userStyleSheets : { | ||
111 | value : null | ||
112 | }, | ||
101 | _stageStylesheet : { | 113 | _stageStylesheet : { |
102 | value : null | 114 | value : null |
103 | }, | 115 | }, |
@@ -112,7 +124,10 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
112 | if(sheet) { | 124 | if(sheet) { |
113 | this._defaultStylesheet = sheet; | 125 | this._defaultStylesheet = sheet; |
114 | } else { | 126 | } else { |
115 | 127 | if(sheet === null) { | |
128 | this._defaultStylesheet = null; | ||
129 | return false; | ||
130 | } | ||
116 | ///// Use the last stylesheet in the document as the default | 131 | ///// Use the last stylesheet in the document as the default |
117 | 132 | ||
118 | var sheets = this._activeDocument._document.styleSheets, | 133 | var sheets = this._activeDocument._document.styleSheets, |
@@ -182,6 +197,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
182 | ///// attach specificity to rule object | 197 | ///// attach specificity to rule object |
183 | ///// if rule is css keyframes, return rule and don't attach specificity | 198 | ///// if rule is css keyframes, return rule and don't attach specificity |
184 | if (rule instanceof WebKitCSSKeyframesRule) { | 199 | if (rule instanceof WebKitCSSKeyframesRule) { |
200 | |||
185 | return rule; | 201 | return rule; |
186 | } | 202 | } |
187 | rule[this.CONST.SPECIFICITY_KEY] = this.getSpecificity(rule.selectorText); | 203 | rule[this.CONST.SPECIFICITY_KEY] = this.getSpecificity(rule.selectorText); |
@@ -208,10 +224,12 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
208 | } | 224 | } |
209 | 225 | ||
210 | var selectorToOverride = getSelector.bind(this)(element, ruleToOverride), | 226 | var selectorToOverride = getSelector.bind(this)(element, ruleToOverride), |
211 | overrideData, rule; | 227 | overrideData, rule, isRuleLocked; |
228 | |||
229 | isRuleLocked = this.isSheetLocked(ruleToOverride.parentStyleSheet); | ||
212 | 230 | ||
213 | ///// Get the overriding selector and className | 231 | ///// Get the overriding selector and className |
214 | overrideData = this.createOverrideSelector(selectorToOverride, element.nodeName); | 232 | overrideData = this.createOverrideSelector(selectorToOverride, element.nodeName, isRuleLocked); |
215 | 233 | ||
216 | ///// Create new rule with selector and insert it after the rule we're overriding | 234 | ///// Create new rule with selector and insert it after the rule we're overriding |
217 | rule = this.addRule(overrideData.selector + ' { }', this.getRuleIndex(ruleToOverride)+1); | 235 | rule = this.addRule(overrideData.selector + ' { }', this.getRuleIndex(ruleToOverride)+1); |
@@ -225,7 +243,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
225 | }, | 243 | }, |
226 | 244 | ||
227 | createOverrideSelector : { | 245 | createOverrideSelector : { |
228 | value: function(selectorToOverride, classPrefix, className) { | 246 | value: function(selectorToOverride, classPrefix, increaseSpecificity, className) { |
229 | var tokens = selectorToOverride.split(/\s/), | 247 | var tokens = selectorToOverride.split(/\s/), |
230 | newClass = className || this.generateClassName(classPrefix, true), | 248 | newClass = className || this.generateClassName(classPrefix, true), |
231 | lastToken, pseudoSplit, base, pseudo, newToken, newSelector; | 249 | lastToken, pseudoSplit, base, pseudo, newToken, newSelector; |
@@ -246,10 +264,19 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
246 | if(base.indexOf('#') !== -1) { | 264 | if(base.indexOf('#') !== -1) { |
247 | newToken = base + '.' + newClass + pseudo; | 265 | newToken = base + '.' + newClass + pseudo; |
248 | } else { | 266 | } else { |
249 | ///// Replace last class or attribute selector | 267 | if(increaseSpecificity) { |
250 | ///// Get everything right before the last class or attribute selector | 268 | ///// Increases specificity by one class selector |
251 | ///// to support compound selector values: (i.e. .firstClass.secondClass) | 269 | ///// We'll do a direct append to the base class |
252 | newToken = base.substring(0, Math.max(base.lastIndexOf('.'), base.lastIndexOf('['))); | 270 | ///// if we want to increase the specificity |
271 | newToken = base; | ||
272 | } else { | ||
273 | ///// Maintains original specificity | ||
274 | ///// Replace last class or attribute selector | ||
275 | ///// Get everything right before the last class or attribute selector | ||
276 | ///// to support compound selector values: (i.e. .firstClass.secondClass) | ||
277 | newToken = base.substring(0, Math.max(base.lastIndexOf('.'), base.lastIndexOf('['))); | ||
278 | } | ||
279 | |||
253 | ///// Append the generated class | 280 | ///// Append the generated class |
254 | newToken += '.' + newClass + pseudo; | 281 | newToken += '.' + newClass + pseudo; |
255 | } | 282 | } |
@@ -970,12 +997,13 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
970 | var doc = element.ownerDocument, | 997 | var doc = element.ownerDocument, |
971 | useImportant = false, | 998 | useImportant = false, |
972 | cache = this._getCachedRuleForProperty(element, property), | 999 | cache = this._getCachedRuleForProperty(element, property), |
973 | dominantRule, override, className, browserValue; | 1000 | dominantRule, override, className, browserValue, cacheMatchesMany; |
974 | 1001 | ||
975 | if(cache) { | 1002 | if(cache) { |
976 | ///// We've cached the rule for this property! | 1003 | ///// We've cached the rule for this property! |
977 | //console.log('Styles Controller :: setElementStyle - We found the cached rule!'); | 1004 | //console.log('Styles Controller :: setElementStyle - We found the cached rule!'); |
978 | dominantRule = cache; | 1005 | dominantRule = cache; |
1006 | cacheMatchesMany = this.matchesMultipleElements(dominantRule, doc); | ||
979 | } else { | 1007 | } else { |
980 | ///// Use Dominant Rule logic to find the right place to add the style | 1008 | ///// Use Dominant Rule logic to find the right place to add the style |
981 | ///// Pass "true" to method to return an override object, which | 1009 | ///// Pass "true" to method to return an override object, which |
@@ -983,7 +1011,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
983 | dominantRule = this.getDominantRuleForElement(element, property, true, isStageElement); | 1011 | dominantRule = this.getDominantRuleForElement(element, property, true, isStageElement); |
984 | 1012 | ||
985 | } | 1013 | } |
986 | 1014 | ||
987 | ///// Did we find a dominant rule? | 1015 | ///// Did we find a dominant rule? |
988 | if(!dominantRule) { | 1016 | if(!dominantRule) { |
989 | ///// No. This means there was no rule with this property, and no | 1017 | ///// No. This means there was no rule with this property, and no |
@@ -1001,6 +1029,13 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1001 | useImportant = dominantRule.useImportant; | 1029 | useImportant = dominantRule.useImportant; |
1002 | dominantRule = override.rule; | 1030 | dominantRule = override.rule; |
1003 | this.addClass(element, override.className); | 1031 | this.addClass(element, override.className); |
1032 | } else if(cacheMatchesMany) { | ||
1033 | ///// Only happens when the cached rule applies to multiple | ||
1034 | ///// elements - we must create override | ||
1035 | override = this.createOverrideRule(dominantRule, element); | ||
1036 | useImportant = !!dominantRule.style.getPropertyPriority(property); | ||
1037 | dominantRule = override.rule; | ||
1038 | this.addClass(element, override.className); | ||
1004 | } | 1039 | } |
1005 | 1040 | ||
1006 | 1041 | ||
@@ -1008,7 +1043,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1008 | browserValue = this.setStyle(dominantRule, property, value, useImportant); | 1043 | browserValue = this.setStyle(dominantRule, property, value, useImportant); |
1009 | 1044 | ||
1010 | ///// Only cache the dominant rule if the style value was valid, and not already cached | 1045 | ///// Only cache the dominant rule if the style value was valid, and not already cached |
1011 | if(browserValue && !cache) { | 1046 | if(browserValue && (!cache || cacheMatchesMany)) { |
1012 | this._setCachedRuleForProperty(element, property, dominantRule); | 1047 | this._setCachedRuleForProperty(element, property, dominantRule); |
1013 | } | 1048 | } |
1014 | 1049 | ||
@@ -1245,8 +1280,12 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1245 | doc.head.appendChild(sheetElement); | 1280 | doc.head.appendChild(sheetElement); |
1246 | sheet = this.getSheetFromElement(sheetElement, doc); | 1281 | sheet = this.getSheetFromElement(sheetElement, doc); |
1247 | 1282 | ||
1283 | this.userStyleSheets.push(sheet); | ||
1284 | |||
1248 | this.styleSheetModified(sheet); | 1285 | this.styleSheetModified(sheet); |
1249 | 1286 | ||
1287 | NJevent('newStyleSheet', sheet); | ||
1288 | |||
1250 | return sheet; | 1289 | return sheet; |
1251 | } | 1290 | } |
1252 | }, | 1291 | }, |
@@ -1269,6 +1308,12 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1269 | } | 1308 | } |
1270 | }, | 1309 | }, |
1271 | 1310 | ||
1311 | isSheetLocked : { | ||
1312 | value: function(sheet) { | ||
1313 | return !!sheet.ownerNode.dataset['ninjaFileReadOnly']; | ||
1314 | } | ||
1315 | }, | ||
1316 | |||
1272 | ///// Style Sheet Modified | 1317 | ///// Style Sheet Modified |
1273 | ///// Method to call whenever a stylesheet change is made | 1318 | ///// Method to call whenever a stylesheet change is made |
1274 | ///// Dispatches an event, and keeps list of dirty style sheets | 1319 | ///// Dispatches an event, and keeps list of dirty style sheets |
@@ -1279,6 +1324,9 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1279 | return sheetObj.stylesheet === sheet; | 1324 | return sheetObj.stylesheet === sheet; |
1280 | }); | 1325 | }); |
1281 | 1326 | ||
1327 | ///// Dispatch modified event | ||
1328 | NJevent('styleSheetModified', eventData); | ||
1329 | |||
1282 | ///// If the sheet doesn't already exist in the list of modified | 1330 | ///// If the sheet doesn't already exist in the list of modified |