diff options
Diffstat (limited to 'js/controllers/styles-controller.js')
-rw-r--r-- | js/controllers/styles-controller.js | 159 |
1 files changed, 138 insertions, 21 deletions
diff --git a/js/controllers/styles-controller.js b/js/controllers/styles-controller.js index 51b81204..a38984e7 100644 --- a/js/controllers/styles-controller.js +++ b/js/controllers/styles-controller.js | |||
@@ -171,7 +171,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
171 | if(argType === 'string') { | 171 | if(argType === 'string') { |
172 | ruleText += '{' + declaration + '}'; | 172 | ruleText += '{' + declaration + '}'; |
173 | } else if(argType === 'object') { | 173 | } else if(argType === 'object') { |
174 | ruleText += '{' + nj.cssFromObject(declaration) + '}'; | 174 | ruleText += '{' + this.cssFromObject(declaration) + '}'; |
175 | } | 175 | } |
176 | 176 | ||
177 | stylesheet.insertRule(ruleText, index); | 177 | stylesheet.insertRule(ruleText, index); |
@@ -203,25 +203,42 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
203 | 203 | ||
204 | ///// Locally-scoped function to de-clutter variable declarations | 204 | ///// Locally-scoped function to de-clutter variable declarations |
205 | function getSelector(el, rule) { | 205 | function getSelector(el, rule) { |
206 | |||
207 | return this._getMostSpecificSelectorForElement(el, rule[this.CONST.SPECIFICITY_KEY]).selector; | 206 | return this._getMostSpecificSelectorForElement(el, rule[this.CONST.SPECIFICITY_KEY]).selector; |
208 | } | 207 | } |
209 | 208 | ||
210 | var selectorToOverride = getSelector.bind(this)(element, ruleToOverride), | 209 | var selectorToOverride = getSelector.bind(this)(element, ruleToOverride), |
211 | tokens = selectorToOverride.split(/\s/), | 210 | overrideData, rule; |
212 | newClass = this.generateClassName(element.nodeName), | 211 | |
213 | lastToken, pseudoSplit, base, pseudo, newToken, newSelector, rule; | 212 | ///// Get the overriding selector and className |
213 | overrideData = this.createOverrideSelector(selectorToOverride, element.nodeName); | ||
214 | |||
215 | ///// Create new rule with selector and insert it after the rule we're overriding | ||
216 | rule = this.addRule(overrideData.selector + ' { }', this.getRuleIndex(ruleToOverride)+1); | ||
217 | |||
218 | return { | ||
219 | className : overrideData.className, | ||
220 | rule : rule | ||
221 | }; | ||
222 | |||
223 | } | ||
224 | }, | ||
225 | |||
226 | createOverrideSelector : { | ||
227 | value: function(selectorToOverride, classPrefix, className) { | ||
228 | var tokens = selectorToOverride.split(/\s/), | ||
229 | newClass = className || this.generateClassName(classPrefix, true), | ||
230 | lastToken, pseudoSplit, base, pseudo, newToken, newSelector; | ||
214 | 231 | ||
215 | ///// Creating an overriding selector by replacing the last | 232 | ///// Creating an overriding selector by replacing the last |
216 | ///// class, attribute or type selector in passed-in rule's selector | 233 | ///// class, attribute or type selector in passed-in rule's selector |
217 | 234 | ||
218 | ///// Grab the last token | 235 | ///// Grab the last token |
219 | lastToken = tokens[tokens.length-1]; | 236 | lastToken = tokens[tokens.length-1]; |
220 | pseudoSplit = lastToken.split(':'); | 237 | pseudoSplit = lastToken.split(':'); |
221 | ///// The last token can have pseudo class. Let's preserve it | 238 | ///// The last token can have pseudo class. Let's preserve it |
222 | base = pseudoSplit[0]; | 239 | base = pseudoSplit[0]; |
223 | pseudo = (pseudoSplit[1]) ? ':'+pseudoSplit[1] : ''; | 240 | pseudo = (pseudoSplit[1]) ? ':'+pseudoSplit[1] : ''; |
224 | 241 | ||
225 | ///// Now, all we want to do is replace the last token with a | 242 | ///// Now, all we want to do is replace the last token with a |
226 | ///// generated class name, except if the last token is an ID selector, | 243 | ///// generated class name, except if the last token is an ID selector, |
227 | ///// in which case we append the generated class name to the ID selector | 244 | ///// in which case we append the generated class name to the ID selector |
@@ -235,18 +252,15 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
235 | ///// Append the generated class | 252 | ///// Append the generated class |
236 | newToken += '.' + newClass + pseudo; | 253 | newToken += '.' + newClass + pseudo; |
237 | } | 254 | } |
238 | 255 | ||
239 | ///// Now we can build the new selector by replacing the last token | 256 | ///// Now we can build the new selector by replacing the last token |
240 | tokens[tokens.length-1] = newToken; | 257 | tokens[tokens.length-1] = newToken; |
241 | newSelector = tokens.join(' '); | 258 | newSelector = tokens.join(' '); |
242 | 259 | ||
243 | rule = this.addRule(newSelector + ' { }', this.getRuleIndex(ruleToOverride)+1); | ||
244 | |||
245 | return { | 260 | return { |
246 | className : newClass, | 261 | className : newClass, |
247 | rule : rule | 262 | selector : newSelector |
248 | }; | 263 | }; |
249 | |||
250 | } | 264 | } |
251 | }, | 265 | }, |
252 | 266 | ||
@@ -374,7 +388,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
374 | ///// from which an overriding rule can be created. | 388 | ///// from which an overriding rule can be created. |
375 | 389 | ||
376 | getDominantRuleForGroup : { | 390 | getDominantRuleForGroup : { |
377 | value : function(elements, property) { | 391 | value : function(elements, property, forceOverride) { |
378 | var selectorsToOverride = [], | 392 | var selectorsToOverride = [], |
379 | commonRules, dominantRules, useImportant; | 393 | commonRules, dominantRules, useImportant; |
380 | 394 | ||
@@ -643,7 +657,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
643 | }, | 657 | }, |
644 | 658 | ||
645 | ///// Get Most Specific Selector For Element | 659 | ///// Get Most Specific Selector For Element |
646 | ///// Given a selector+specificty array, find the most specific | 660 | ///// Given a selector+specificity array, find the most specific |
647 | ///// selector for the passed-in element | 661 | ///// selector for the passed-in element |
648 | 662 | ||
649 | _getMostSpecificSelectorForElement : { | 663 | _getMostSpecificSelectorForElement : { |
@@ -725,7 +739,11 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
725 | ///// Calculate specificity | 739 | ///// Calculate specificity |
726 | ///// Returns the specificity value of passed-in selector | 740 | ///// Returns the specificity value of passed-in selector |
727 | ///// WARNING: Do not pass in grouped selectors! | 741 | ///// WARNING: Do not pass in grouped selectors! |
728 | ///// Helpful for determining precedence of style rules | 742 | ///// Helpful for determining precedence of style rules |
743 | ///// Calculation javascript code courtesy of Graham Bradley: | ||
744 | ///// http://gbradley.com/2009/10/02/css-specificity-in-javascript | ||
745 | ///// Used with author's permission | ||
746 | |||
729 | calculateSpecificity : { | 747 | calculateSpecificity : { |
730 | value : function(selector) { | 748 | value : function(selector) { |
731 | var s = selector.replace(/\([^\)]+\)/,''), | 749 | var s = selector.replace(/\([^\)]+\)/,''), |
@@ -790,7 +808,34 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
790 | return browserValues; | 808 | return browserValues; |
791 | } | 809 | } |
792 | }, | 810 | }, |
793 | 811 | ||
812 | ///// Set Keyframe Style | ||
813 | ///// For a given CSSKeyframesRule, we may add a style to the keyframe at | ||
814 | ///// given index. | ||
815 | |||
816 | setKeyframeStyle : { | ||
817 | value : function(rule, keyframeIndex, property, value, useImportant) { | ||
818 | return this.setStyle(rule.cssRules[keyframeIndex], property, value, useImportant); | ||
819 | } | ||
820 | }, | ||
821 | |||
822 | ///// Set Keyframe Styles | ||
823 | ///// For a given CSSKeyframesRule, we may add styles to the keyframe at | ||
824 | ///// given index. | ||
825 | |||
826 | setKeyframeStyle : { | ||
827 | value : function(rule, keyframeIndex, property, value, useImportant) { | ||
828 | return this.setStyles(rule.cssRules[keyframeIndex], property, value, useImportant); | ||
829 | } | ||
830 | }, | ||
831 | |||
832 | insertKeyframe : { | ||
833 | value : function() { | ||
834 | |||
835 | } | ||
836 | }, | ||
837 | |||
838 | |||
794 | ///// Delete style | 839 | ///// Delete style |
795 | ///// Removes the property from the style declaration/rule | 840 | ///// Removes the property from the style declaration/rule |
796 | ///// Returns the rule | 841 | ///// Returns the rule |
@@ -926,6 +971,43 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
926 | } | 971 | } |
927 | } | 972 | } |
928 | }, | 973 | }, |
974 | |||
975 | setGroupStyles : { | ||
976 | value : function(elements, styles) { | ||
977 | var properties = Object.keys(styles), | ||
978 | newClass = this.generateClassName(null, true), | ||
979 | selectors; | ||
980 | |||
981 | ///// TODO: move this: Locally-scoped function to de-clutter variable declarations | ||
982 | function getSelector(el, rule) { | ||
983 | return this._getMostSpecificSelectorForElement(el, rule[this.CONST.SPECIFICITY_KEY]).selector; | ||
984 | } | ||
985 | |||
986 | selectors = elements.map(function(el) { | ||
987 | ///// for each element, we want to find the most specific selector | ||
988 | var matchingRules = this.getMatchingRules(el, true); | ||
989 | |||
990 | this.addClass(el, newClass); | ||
991 | |||
992 | if(matchingRules.length === 0) { | ||
993 | return null; | ||
994 | } | ||
995 | |||
996 | var mostSpecificRule = matchingRules[0], // TODO: iterate over properties to find most specific | ||
997 | selectorToOverride = getSelector.bind(this)(el, mostSpecificRule), | ||
998 | override = this.createOverrideSelector(selectorToOverride, null, newClass); | ||
999 | |||
1000 | return override.selector; | ||
1001 | |||
1002 | }, this); | ||
1003 | |||
1004 | selectors.filter(function(item) { | ||
1005 | return item !== null; | ||
1006 | }); | ||
1007 | |||
1008 | this.addRule(selectors.join(', '), styles); | ||
1009 | } | ||
1010 | }, | ||
929 | 1011 | ||
930 | ///// Get Element Style | 1012 | ///// Get Element Style |
931 | ///// Gets the style value that is currently applied to the element | 1013 | ///// Gets the style value that is currently applied to the element |
@@ -1062,6 +1144,21 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1062 | } | 1144 | } |
1063 | }, | 1145 | }, |
1064 | 1146 | ||
1147 | ///// CSS From Object | ||
1148 | ///// Returns css text from object with key/value pairs | ||
1149 | ///// representing css styles | ||
1150 | |||
1151 |