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 afd298c9..21024125 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); |
@@ -199,25 +199,42 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
199 | 199 | ||
200 | ///// Locally-scoped function to de-clutter variable declarations | 200 | ///// Locally-scoped function to de-clutter variable declarations |
201 | function getSelector(el, rule) { | 201 | function getSelector(el, rule) { |
202 | |||
203 | return this._getMostSpecificSelectorForElement(el, rule[this.CONST.SPECIFICITY_KEY]).selector; | 202 | return this._getMostSpecificSelectorForElement(el, rule[this.CONST.SPECIFICITY_KEY]).selector; |
204 | } | 203 | } |
205 | 204 | ||
206 | var selectorToOverride = getSelector.bind(this)(element, ruleToOverride), | 205 | var selectorToOverride = getSelector.bind(this)(element, ruleToOverride), |
207 | tokens = selectorToOverride.split(/\s/), | 206 | overrideData, rule; |
208 | newClass = this.generateClassName(element.nodeName), | 207 | |
209 | lastToken, pseudoSplit, base, pseudo, newToken, newSelector, rule; | 208 | ///// Get the overriding selector and className |
209 | overrideData = this.createOverrideSelector(selectorToOverride, element.nodeName); | ||
210 | |||
211 | ///// Create new rule with selector and insert it after the rule we're overriding | ||
212 | rule = this.addRule(overrideData.selector + ' { }', this.getRuleIndex(ruleToOverride)+1); | ||
213 | |||
214 | return { | ||
215 | className : overrideData.className, | ||
216 | rule : rule | ||
217 | }; | ||
218 | |||
219 | } | ||
220 | }, | ||
221 | |||
222 | createOverrideSelector : { | ||
223 | value: function(selectorToOverride, classPrefix, className) { | ||
224 | var tokens = selectorToOverride.split(/\s/), | ||
225 | newClass = className || this.generateClassName(classPrefix, true), | ||
226 | lastToken, pseudoSplit, base, pseudo, newToken, newSelector; | ||
210 | 227 | ||
211 | ///// Creating an overriding selector by replacing the last | 228 | ///// Creating an overriding selector by replacing the last |
212 | ///// class, attribute or type selector in passed-in rule's selector | 229 | ///// class, attribute or type selector in passed-in rule's selector |
213 | 230 | ||
214 | ///// Grab the last token | 231 | ///// Grab the last token |
215 | lastToken = tokens[tokens.length-1]; | 232 | lastToken = tokens[tokens.length-1]; |
216 | pseudoSplit = lastToken.split(':'); | 233 | pseudoSplit = lastToken.split(':'); |
217 | ///// The last token can have pseudo class. Let's preserve it | 234 | ///// The last token can have pseudo class. Let's preserve it |
218 | base = pseudoSplit[0]; | 235 | base = pseudoSplit[0]; |
219 | pseudo = (pseudoSplit[1]) ? ':'+pseudoSplit[1] : ''; | 236 | pseudo = (pseudoSplit[1]) ? ':'+pseudoSplit[1] : ''; |
220 | 237 | ||
221 | ///// Now, all we want to do is replace the last token with a | 238 | ///// Now, all we want to do is replace the last token with a |
222 | ///// generated class name, except if the last token is an ID selector, | 239 | ///// generated class name, except if the last token is an ID selector, |
223 | ///// in which case we append the generated class name to the ID selector | 240 | ///// in which case we append the generated class name to the ID selector |
@@ -231,18 +248,15 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
231 | ///// Append the generated class | 248 | ///// Append the generated class |
232 | newToken += '.' + newClass + pseudo; | 249 | newToken += '.' + newClass + pseudo; |
233 | } | 250 | } |
234 | 251 | ||
235 | ///// Now we can build the new selector by replacing the last token | 252 | ///// Now we can build the new selector by replacing the last token |
236 | tokens[tokens.length-1] = newToken; | 253 | tokens[tokens.length-1] = newToken; |
237 | newSelector = tokens.join(' '); | 254 | newSelector = tokens.join(' '); |
238 | 255 | ||
239 | rule = this.addRule(newSelector + ' { }', this.getRuleIndex(ruleToOverride)+1); | ||
240 | |||
241 | return { | 256 | return { |
242 | className : newClass, | 257 | className : newClass, |
243 | rule : rule | 258 | selector : newSelector |
244 | }; | 259 | }; |
245 | |||
246 | } | 260 | } |
247 | }, | 261 | }, |
248 | 262 | ||
@@ -370,7 +384,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
370 | ///// from which an overriding rule can be created. | 384 | ///// from which an overriding rule can be created. |
371 | 385 | ||
372 | getDominantRuleForGroup : { | 386 | getDominantRuleForGroup : { |
373 | value : function(elements, property) { | 387 | value : function(elements, property, forceOverride) { |
374 | var selectorsToOverride = [], | 388 | var selectorsToOverride = [], |
375 | commonRules, dominantRules, useImportant; | 389 | commonRules, dominantRules, useImportant; |
376 | 390 | ||
@@ -639,7 +653,7 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
639 | }, | 653 | }, |
640 | 654 | ||
641 | ///// Get Most Specific Selector For Element | 655 | ///// Get Most Specific Selector For Element |
642 | ///// Given a selector+specificty array, find the most specific | 656 | ///// Given a selector+specificity array, find the most specific |
643 | ///// selector for the passed-in element | 657 | ///// selector for the passed-in element |
644 | 658 | ||
645 | _getMostSpecificSelectorForElement : { | 659 | _getMostSpecificSelectorForElement : { |
@@ -721,7 +735,11 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
721 | ///// Calculate specificity | 735 | ///// Calculate specificity |
722 | ///// Returns the specificity value of passed-in selector | 736 | ///// Returns the specificity value of passed-in selector |
723 | ///// WARNING: Do not pass in grouped selectors! | 737 | ///// WARNING: Do not pass in grouped selectors! |
724 | ///// Helpful for determining precedence of style rules | 738 | ///// Helpful for determining precedence of style rules |
739 | ///// Calculation javascript code courtesy of Graham Bradley: | ||
740 | ///// http://gbradley.com/2009/10/02/css-specificity-in-javascript | ||
741 | ///// Used with author's permission | ||
742 | |||
725 | calculateSpecificity : { | 743 | calculateSpecificity : { |
726 | value : function(selector) { | 744 | value : function(selector) { |
727 | var s = selector.replace(/\([^\)]+\)/,''), | 745 | var s = selector.replace(/\([^\)]+\)/,''), |
@@ -786,7 +804,34 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
786 | return browserValues; | 804 | return browserValues; |
787 | } | 805 | } |
788 | }, | 806 | }, |
789 | 807 | ||
808 | ///// Set Keyframe Style | ||
809 | ///// For a given CSSKeyframesRule, we may add a style to the keyframe at | ||
810 | ///// given index. | ||
811 | |||
812 | setKeyframeStyle : { | ||
813 | value : function(rule, keyframeIndex, property, value, useImportant) { | ||
814 | return this.setStyle(rule.cssRules[keyframeIndex], property, value, useImportant); | ||
815 | } | ||
816 | }, | ||
817 | |||
818 | ///// Set Keyframe Styles | ||
819 | ///// For a given CSSKeyframesRule, we may add styles to the keyframe at | ||
820 | ///// given index. | ||
821 | |||
822 | setKeyframeStyle : { | ||
823 | value : function(rule, keyframeIndex, property, value, useImportant) { | ||
824 | return this.setStyles(rule.cssRules[keyframeIndex], property, value, useImportant); | ||
825 | } | ||
826 | }, | ||
827 | |||
828 | insertKeyframe : { | ||
829 | value : function() { | ||
830 | |||
831 | } | ||
832 | }, | ||
833 | |||
834 | |||
790 | ///// Delete style | 835 | ///// Delete style |
791 | ///// Removes the property from the style declaration/rule | 836 | ///// Removes the property from the style declaration/rule |
792 | ///// Returns the rule | 837 | ///// Returns the rule |
@@ -922,6 +967,43 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
922 | } | 967 | } |
923 | } | 968 | } |
924 | }, | 969 | }, |
970 | |||
971 | setGroupStyles : { | ||
972 | value : function(elements, styles) { | ||
973 | var properties = Object.keys(styles), | ||
974 | newClass = this.generateClassName(null, true), | ||
975 | selectors; | ||
976 | |||
977 | ///// TODO: move this: Locally-scoped function to de-clutter variable declarations | ||
978 | function getSelector(el, rule) { | ||
979 | return this._getMostSpecificSelectorForElement(el, rule[this.CONST.SPECIFICITY_KEY]).selector; | ||
980 | } | ||
981 | |||
982 | selectors = elements.map(function(el) { | ||
983 | ///// for each element, we want to find the most specific selector | ||
984 | var matchingRules = this.getMatchingRules(el, true); | ||
985 | |||
986 | this.addClass(el, newClass); | ||
987 | |||
988 | if(matchingRules.length === 0) { | ||
989 | return null; | ||
990 | } | ||
991 | |||
992 | var mostSpecificRule = matchingRules[0], // TODO: iterate over properties to find most specific | ||
993 | selectorToOverride = getSelector.bind(this)(el, mostSpecificRule), | ||
994 | override = this.createOverrideSelector(selectorToOverride, null, newClass); | ||
995 | |||
996 | return override.selector; | ||
997 | |||
998 | }, this); | ||
999 | |||
1000 | selectors.filter(function(item) { | ||
1001 | return item !== null; | ||
1002 | }); | ||
1003 | |||
1004 | this.addRule(selectors.join(', '), styles); | ||
1005 | } | ||
1006 | }, | ||
925 | 1007 | ||
926 | ///// Get Element Style | 1008 | ///// Get Element Style |
927 | ///// Gets the style value that is currently applied to the element | 1009 | ///// Gets the style value that is currently applied to the element |
@@ -1058,6 +1140,21 @@ var stylesController = exports.StylesController = Montage.create(Component, { | |||
1058 | } | 1140 | } |
1059 | }, | 1141 | }, |
1060 | 1142 | ||
1143 | ///// CSS From Object | ||
1144 | ///// Returns css text from object with key/value pairs | ||
1145 | ///// representing css styles | ||
1146 | |||
1147 | cssFromObject : { | <