aboutsummaryrefslogtreecommitdiff
path: root/js/controllers/styles-controller.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/controllers/styles-controller.js')
-rw-r--r--js/controllers/styles-controller.js102
1 files changed, 86 insertions, 16 deletions
diff --git a/js/controllers/styles-controller.js b/js/controllers/styles-controller.js
index afd298c9..8fc90e7d 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 David Owens:
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(/\([^\)]+\)/,''),
@@ -922,6 +940,43 @@ var stylesController = exports.StylesController = Montage.create(Component, {
922 } 940 }
923 } 941 }
924 }, 942 },
943
944 setGroupStyles : {
945 value : function(elements, styles) {
946 var properties = Object.keys(styles),
947 newClass = this.generateClassName(null, true),
948 selectors;
949
950 ///// TODO: move this: Locally-scoped function to de-clutter variable declarations
951 function getSelector(el, rule) {
952 return this._getMostSpecificSelectorForElement(el, rule[this.CONST.SPECIFICITY_KEY]).selector;
953 }
954
955 selectors = elements.map(function(el) {
956 ///// for each element, we want to find the most specific selector
957 var matchingRules = this.getMatchingRules(el, true);
958
959 this.addClass(el, newClass);
960
961 if(matchingRules.length === 0) {
962 return null;
963 }
964
965 var mostSpecificRule = matchingRules[0], // TODO: iterate over properties to find most specific
966 selectorToOverride = getSelector.bind(this)(el, mostSpecificRule),
967 override = this.createOverrideSelector(selectorToOverride, null, newClass);
968
969 return override.selector;
970
971 }, this);
972
973 selectors.filter(function(item) {
974 return item !== null;
975 });
976
977 this.addRule(selectors.join(', '), styles);
978 }
979 },
925 980
926 ///// Get Element Style 981 ///// Get Element Style
927 ///// Gets the style value that is currently applied to the element 982 ///// Gets the style value that is currently applied to the element
@@ -1058,6 +1113,21 @@ var stylesController = exports.StylesController = Montage.create(Component, {
1058 } 1113 }
1059 }, 1114 },
1060 1115
1116 ///// CSS From Object
1117 ///// Returns css text from object with key/value pairs
1118 ///// representing css styles
1119
1120 cssFromObject : {
1121 value : function(obj) {
1122 var cssText = '';
1123 ///// For each key/value pair, create css text
1124 for(var prop in obj) {
1125 cssText += prop + ':' + obj[prop] + ';';
1126 }
1127 return cssText;
1128 }
1129 },
1130
1061 /* ----------------- Element model (rule cache) related methods ----------------- */ 1131 /* ----------------- Element model (rule cache) related methods ----------------- */
1062 1132
1063 ///// Get Cached Rule For Property 1133 ///// Get Cached Rule For Property