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