UNPKG

dojox

Version:

Dojo eXtensions, a rollup of many useful sub-projects and varying states of maturity – from very stable and robust, to alpha and experimental. See individual projects contain README files for details.

311 lines (291 loc) 10.1 kB
define(["dojo/_base/lang", "dojo/_base/array", "dojo/_base/window", "dojo/_base/sniff"], function(lang, ArrayUtil, Window, has) { // summary: // Methods for creating and manipulating dynamic CSS Styles and Style Sheets // example: // | dojox.html.createStyle("#myDiv input", "font-size:24px"); // Creates Style #myDiv input, which can now be applied to myDiv, and // the inner input will be targeted // | dojox.html.createStyle(".myStyle", "color:#FF0000"); // Now the class myStyle can be assigned to a node's className var dh = lang.getObject("dojox.html", true); var dynamicStyleMap = {}; var pageStyleSheets = {}; var titledSheets = []; dh.insertCssRule = function(/*String*/selector, /*String*/declaration, /*String?*/styleSheetName){ // summary: // Creates a style and attaches it to a dynamically created stylesheet // selector: // A fully qualified class name, as it would appear in // a CSS dojo.doc. Start classes with periods, target // nodes with '#'. Large selectors can also be created // like: // | "#myDiv.myClass span input" // declaration: // A single string that would make up a style block, not // including the curly braces. Include semi-colons between // statements. Do not use JavaScript style declarations // in camel case, use as you would in a CSS dojo.doc: // | "color:#ffoooo;font-size:12px;margin-left:5px;" // styleSheetName: // Name of the dynamic style sheet this rule should be // inserted into. If is not found by that name, it is // created. If no name is passed, the name "default" is // used. var ss = dh.getDynamicStyleSheet(styleSheetName); var styleText = selector + " {" + declaration + "}"; console.log("insertRule:", styleText); if(has("ie")){ // Note: check for if(ss.cssText) does not work ss.cssText+=styleText; console.log("ss.cssText:", ss.cssText); }else if(ss.sheet){ ss.sheet.insertRule(styleText, ss._indicies.length); }else{ ss.appendChild(Window.doc.createTextNode(styleText)); } ss._indicies.push(selector+" "+declaration); return selector; // String }; dh.removeCssRule = function(/*String*/selector, /*String*/declaration, /*String*/styleSheetName){ // summary: // Removes a cssRule base on the selector and declaration passed // The declaration is needed for cases of dupe selectors // description: Only removes DYNAMICALLY created cssRules. If you // created it with dh.insertCssRule, it can be removed. var ss; var index=-1; var nm; var i; for(nm in dynamicStyleMap){ if(styleSheetName && styleSheetName !== nm) {continue;} ss = dynamicStyleMap[nm]; for(i=0;i<ss._indicies.length;i++){ if(selector+" "+declaration === ss._indicies[i]){ index = i; break; } } if(index>-1) { break; } } if(!ss){ console.warn("No dynamic style sheet has been created from which to remove a rule."); return false; } if(index===-1){ console.warn("The css rule was not found and could not be removed."); return false; } ss._indicies.splice(index, 1); if(has("ie")){ // Note: check for if(ss.removeRule) does not work ss.removeRule(index); }else if(ss.sheet){ ss.sheet.deleteRule(index); } return true; //Boolean }; dh.modifyCssRule = function(selector, declaration, styleSheetName){ // summary: // Not implemented - it seems to have some merit for changing some complex // selectors. It's not much use for changing simple ones like "span". // For now, simply write a new rule which will cascade over the first. // // Modifies an existing cssRule }; dh.getStyleSheet = function(/*String?*/styleSheetName){ // summary: // Returns a style sheet based on the argument. // Searches dynamic style sheets first. If no matches, // searches document style sheets. // styleSheetName: // A title or an href to a style sheet. Title can be // an attribute in a tag, or a dynamic style sheet // reference. Href can be the name of the file. // If no argument, the assumed created dynamic style // sheet is used. // try dynamic sheets first if(dynamicStyleMap[styleSheetName || "default"]){ return dynamicStyleMap[styleSheetName || "default"]; } if(!styleSheetName){ // no arg is nly good for the default style sheet // and it has not been created yet. return false; } var allSheets = dh.getStyleSheets(); // now try document style sheets by name if(allSheets[styleSheetName]){ return dh.getStyleSheets()[styleSheetName]; } // check for partial matches in hrefs (so that a fully //qualified name does not have to be passed) var nm; for ( nm in allSheets){ if( allSheets[nm].href && allSheets[nm].href.indexOf(styleSheetName)>-1){ return allSheets[nm]; } } return false; //StyleSheet or false }; dh.getDynamicStyleSheet = function(/*String?*/styleSheetName){ // summary: // Creates and returns a dynamically created style sheet // used for dynamic styles // styleSheetName: // The name given the style sheet so that multiple // style sheets can be created and referenced. If // no argument is given, the name "default" is used. if(!styleSheetName){ styleSheetName="default"; } if(!dynamicStyleMap[styleSheetName]){ if(Window.doc.createStyleSheet){ //IE dynamicStyleMap[styleSheetName] = Window.doc.createStyleSheet(); if(has("ie") < 9) { // IE9 calls this read-only. Loving the new browser so far. dynamicStyleMap[styleSheetName].title = styleSheetName; } }else{ dynamicStyleMap[styleSheetName] = Window.doc.createElement("style"); dynamicStyleMap[styleSheetName].setAttribute("type", "text/css"); Window.doc.getElementsByTagName("head")[0].appendChild(dynamicStyleMap[styleSheetName]); console.log(styleSheetName, " ss created: ", dynamicStyleMap[styleSheetName].sheet); } dynamicStyleMap[styleSheetName]._indicies = []; } return dynamicStyleMap[styleSheetName]; //StyleSheet }; dh.enableStyleSheet = function(/*String*/styleSheetName){ // summary: // Enables the style sheet with the name passed in the // argument. Deafults to the default style sheet. // var ss = dh.getStyleSheet(styleSheetName); if(ss){ if(ss.sheet){ ss.sheet.disabled = false; }else{ ss.disabled = false; } } }; dh.disableStyleSheet = function(/* String */styleSheetName){ // summary: // Disables the dynamic style sheet with the name passed in the // argument. If no arg is passed, defaults to the default style sheet. var ss = dh.getStyleSheet(styleSheetName); if(ss){ if(ss.sheet){ ss.sheet.disabled = true; }else{ ss.disabled = true; } } }; dh.activeStyleSheet = function(/*String?*/title){ // summary: // Getter/Setter // description: // If passed a title, enables a that style sheet. All other // toggle-able style sheets are disabled. // If no argument is passed, returns currently enabled // style sheet. var sheets = dh.getToggledStyleSheets(); var i; if(arguments.length === 1){ //console.log("sheets:", sheets); ArrayUtil.forEach(sheets, function(s){ s.disabled = (s.title === title) ? false : true; }); }else{ for(i=0;i<sheets.length;i++){ if(sheets[i].disabled === false){ return sheets[i]; } } } return true; //StyleSheet or Boolean - FIXME - doesn't make a lot of sense }; dh.getPreferredStyleSheet = function(){ // summary: // Returns the style sheet that was initially enabled // on document launch. // TODO, does not work. }; // TODO: Sets of style sheets could be grouped according to // an ID and used in sets, much like different // groups of radio buttons. It would not however be // according to W3C spec // dh.getToggledStyleSheets = function(){ // summary: // Searches HTML for style sheets that are "toggle-able" - // can be enabled and disabled. These would include sheets // with the title attribute, as well as the REL attribute. // returns: // An array of all toggle-able style sheets var nm; if(!titledSheets.length){ var sObjects = dh.getStyleSheets(); for(nm in sObjects){ if(sObjects[nm].title){ titledSheets.push(sObjects[nm]); } } } return titledSheets; //Array }; //TODO: Does not recursively search for @imports, so it will // only go one level deep. dh.getStyleSheets = function(){ // summary: // Collects all the style sheets referenced in the HTML page, // including any included via @import. // returns: // An hash map of all the style sheets. if(pageStyleSheets.collected) {return pageStyleSheets;} var sheets = Window.doc.styleSheets; ArrayUtil.forEach(sheets, function(n){ var s = (n.sheet) ? n.sheet : n; var name = s.title || s.href; if(has("ie")){ // IE attaches a style sheet for VML - do not include this if(s.cssText.indexOf("#default#VML") === -1){ if(s.href){ // linked pageStyleSheets[name] = s; }else if(s.imports.length){ // Imported via @import ArrayUtil.forEach(s.imports, function(si){ pageStyleSheets[si.title || si.href] = si; }); }else{ //embedded within page pageStyleSheets[name] = s; } } }else{ //linked or embedded pageStyleSheets[name] = s; pageStyleSheets[name].id = s.ownerNode.id; var rules = []; try { rules = s[s.cssRules?"cssRules":"rules"]; } catch(err) { // issue a warning that stylesheet couldn't be loaded, but continue console.warn("Reading css rules from stylesheet "+s.href+" is forbidden due to same-origin policy. See http://www.w3.org/TR/CSP/#cascading-style-sheet-css-parsing",s); } ArrayUtil.forEach(rules, function(r){ if(r.href){ // imported pageStyleSheets[r.href] = r.styleSheet; pageStyleSheets[r.href].id = s.ownerNode.id; } }); } }); //console.log("pageStyleSheets:", pageStyleSheets); pageStyleSheets.collected = true; return pageStyleSheets; //Object }; return dh; });