diff options
Diffstat (limited to 'js/controllers/styles-controller.js')
-rwxr-xr-x | js/controllers/styles-controller.js | 121 |
1 files changed, 100 insertions, 21 deletions
diff --git a/js/controllers/styles-controller.js b/js/controllers/styles-controller.js index ae504f0e..00d67b89 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, |
@@ -158,13 +173,17 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
158 | 173 | ||
159 | addRule : { | 174 | addRule : { |
160 | value : function(selector, declaration, stylesheet, index) { | 175 | value : function(selector, declaration, stylesheet, index) { |
161 | //console.log("Add rule"); | 176 | stylesheet = stylesheet || this._defaultStylesheet; |
177 | |||
178 | if(stylesheet === null) { | ||
179 | stylesheet = this.defaultStylesheet = this.createStylesheet(); | ||
180 | } | ||
181 | |||
162 | var rulesLength = this._defaultStylesheet.rules.length, | 182 | var rulesLength = this._defaultStylesheet.rules.length, |
163 | argType = (typeof declaration), | 183 | argType = (typeof declaration), |
164 | ruleText = selector, | 184 | ruleText = selector, |
165 | stylesheet = stylesheet || this._defaultStylesheet, | 185 | rule; |
166 | property, rule; | 186 | |
167 | |||
168 | index = index || (argType === 'number') ? declaration : rulesLength; | 187 | index = index || (argType === 'number') ? declaration : rulesLength; |
169 | 188 | ||
170 | if(argType === 'string') { | 189 | if(argType === 'string') { |
@@ -182,6 +201,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
182 | ///// attach specificity to rule object | 201 | ///// attach specificity to rule object |
183 | ///// if rule is css keyframes, return rule and don't attach specificity | 202 | ///// if rule is css keyframes, return rule and don't attach specificity |
184 | if (rule instanceof WebKitCSSKeyframesRule) { | 203 | if (rule instanceof WebKitCSSKeyframesRule) { |
204 | |||
185 | return rule; | 205 | return rule; |
186 | } | 206 | } |
187 | rule[this.CONST.SPECIFICITY_KEY] = this.getSpecificity(rule.selectorText); | 207 | rule[this.CONST.SPECIFICITY_KEY] = this.getSpecificity(rule.selectorText); |
@@ -208,10 +228,12 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
208 | } | 228 | } |
209 | 229 | ||
210 | var selectorToOverride = getSelector.bind(this)(element, ruleToOverride), | 230 | var selectorToOverride = getSelector.bind(this)(element, ruleToOverride), |
211 | overrideData, rule; | 231 | overrideData, rule, isRuleLocked; |
232 | |||
233 | isRuleLocked = this.isSheetLocked(ruleToOverride.parentStyleSheet); | ||
212 | 234 | ||
213 | ///// Get the overriding selector and className | 235 | ///// Get the overriding selector and className |
214 | overrideData = this.createOverrideSelector(selectorToOverride, element.nodeName); | 236 | overrideData = this.createOverrideSelector(selectorToOverride, element.nodeName, isRuleLocked); |
215 | 237 | ||
216 | ///// Create new rule with selector and insert it after the rule we're overriding | 238 | ///// Create new rule with selector and insert it after the rule we're overriding |
217 | rule = this.addRule(overrideData.selector + ' { }', this.getRuleIndex(ruleToOverride)+1); | 239 | rule = this.addRule(overrideData.selector + ' { }', this.getRuleIndex(ruleToOverride)+1); |
@@ -225,7 +247,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
225 | }, | 247 | }, |
226 | 248 | ||
227 | createOverrideSelector : { | 249 | createOverrideSelector : { |
228 | value: function(selectorToOverride, classPrefix, className) { | 250 | value: function(selectorToOverride, classPrefix, increaseSpecificity, className) { |
229 | var tokens = selectorToOverride.split(/\s/), | 251 | var tokens = selectorToOverride.split(/\s/), |
230 | newClass = className || this.generateClassName(classPrefix, true), | 252 | newClass = className || this.generateClassName(classPrefix, true), |
231 | lastToken, pseudoSplit, base, pseudo, newToken, newSelector; | 253 | lastToken, pseudoSplit, base, pseudo, newToken, newSelector; |
@@ -246,10 +268,19 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
246 | if(base.indexOf('#') !== -1) { | 268 | if(base.indexOf('#') !== -1) { |
247 | newToken = base + '.' + newClass + pseudo; | 269 | newToken = base + '.' + newClass + pseudo; |
248 | } else { | 270 | } else { |
249 | ///// Replace last class or attribute selector | 271 | if(increaseSpecificity) { |
250 | ///// Get everything right before the last class or attribute selector | 272 | ///// Increases specificity by one class selector |
251 | ///// to support compound selector values: (i.e. .firstClass.secondClass) | 273 | ///// We'll do a direct append to the base class |
252 | newToken = base.substring(0, Math.max(base.lastIndexOf('.'), base.lastIndexOf('['))); | 274 | ///// if we want to increase the specificity |
275 | newToken = base; | ||
276 | } else { | ||
277 | ///// Maintains original specificity | ||
278 | ///// Replace last class or attribute selector | ||
279 | ///// Get everything right before the last class or attribute selector | ||
280 | ///// to support compound selector values: (i.e. .firstClass.secondClass) | ||
281 | newToken = base.substring(0, Math.max(base.lastIndexOf('.'), base.lastIndexOf('['))); | ||
282 | } | ||
283 | |||
253 | ///// Append the generated class | 284 | ///// Append the generated class |
254 | newToken += '.' + newClass + pseudo; | 285 | newToken += '.' + newClass + pseudo; |
255 | } | 286 | } |
@@ -794,7 +825,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
794 | ///// method to apply/test the new value | 825 | ///// method to apply/test the new value |
795 | dec.setProperty(property, value, priority); | 826 | dec.setProperty(property, value, priority); |
796 | 827 | ||
797 | if(rule.parentStyleSheet) { | 828 | if(rule.type !== 'inline' && rule.parentStyleSheet) { |
798 | this.styleSheetModified(rule.parentStyleSheet); | 829 | this.styleSheetModified(rule.parentStyleSheet); |
799 | } | 830 | } |
800 | 831 | ||
@@ -970,12 +1001,13 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
970 | var doc = element.ownerDocument, | 1001 | var doc = element.ownerDocument, |
971 | useImportant = false, | 1002 | useImportant = false, |
972 | cache = this._getCachedRuleForProperty(element, property), | 1003 | cache = this._getCachedRuleForProperty(element, property), |
973 | dominantRule, override, className, browserValue; | 1004 | dominantRule, override, className, browserValue, cacheMatchesMany; |
974 | 1005 | ||
975 | if(cache) { | 1006 | if(cache) { |
976 | ///// We've cached the rule for this property! | 1007 | ///// We've cached the rule for this property! |
977 | //console.log('Styles Controller :: setElementStyle - We found the cached rule!'); | 1008 | //console.log('Styles Controller :: setElementStyle - We found the cached rule!'); |
978 | dominantRule = cache; | 1009 | dominantRule = cache; |
1010 | cacheMatchesMany = this.matchesMultipleElements(dominantRule, doc); | ||
979 | } else { | 1011 | } else { |
980 | ///// Use Dominant Rule logic to find the right place to add the style | 1012 | ///// Use Dominant Rule logic to find the right place to add the style |
981 | ///// Pass "true" to method to return an override object, which | 1013 | ///// Pass "true" to method to return an override object, which |
@@ -983,7 +1015,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
983 | dominantRule = this.getDominantRuleForElement(element, property, true, isStageElement); | 1015 | dominantRule = this.getDominantRuleForElement(element, property, true, isStageElement); |
984 | 1016 | ||
985 | } | 1017 | } |
986 | 1018 | ||
987 | ///// Did we find a dominant rule? | 1019 | ///// Did we find a dominant rule? |
988 | if(!dominantRule) { | 1020 | if(!dominantRule) { |
989 | ///// No. This means there was no rule with this property, and no | 1021 | ///// No. This means there was no rule with this property, and no |
@@ -1001,6 +1033,13 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1001 | useImportant = dominantRule.useImportant; | 1033 | useImportant = dominantRule.useImportant; |
1002 | dominantRule = override.rule; | 1034 | dominantRule = override.rule; |
1003 | this.addClass(element, override.className); | 1035 | this.addClass(element, override.className); |
1036 | } else if(cacheMatchesMany) { | ||
1037 | ///// Only happens when the cached rule applies to multiple | ||
1038 | ///// elements - we must create override | ||
1039 | override = this.createOverrideRule(dominantRule, element); | ||
1040 | useImportant = !!dominantRule.style.getPropertyPriority(property); | ||
1041 | dominantRule = override.rule; | ||
1042 | this.addClass(element, override.className); | ||
1004 | } | 1043 | } |
1005 | 1044 | ||
1006 | 1045 | ||
@@ -1008,7 +1047,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1008 | browserValue = this.setStyle(dominantRule, property, value, useImportant); | 1047 | browserValue = this.setStyle(dominantRule, property, value, useImportant); |
1009 | 1048 | ||
1010 | ///// Only cache the dominant rule if the style value was valid, and not already cached | 1049 | ///// Only cache the dominant rule if the style value was valid, and not already cached |
1011 | if(browserValue && !cache) { | 1050 | if(browserValue && (!cache || cacheMatchesMany)) { |
1012 | this._setCachedRuleForProperty(element, property, dominantRule); | 1051 | this._setCachedRuleForProperty(element, property, dominantRule); |
1013 | } | 1052 | } |
1014 | 1053 | ||
@@ -1245,11 +1284,42 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1245 | doc.head.appendChild(sheetElement); | 1284 | doc.head.appendChild(sheetElement); |
1246 | sheet = this.getSheetFromElement(sheetElement, doc); | 1285 | sheet = this.getSheetFromElement(sheetElement, doc); |
1247 | 1286 |