home *** CD-ROM | disk | FTP | other *** search
Text File | 2004-03-09 | 63.5 KB | 1,715 lines |
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is CaScadeS, a stylesheet editor for Composer.
- *
- * The Initial Developer of the Original Code is
- * Daniel Glazman.
- * Portions created by the Initial Developer are Copyright (C) 2002
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Original author: Daniel Glazman <daniel@glazman.org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
- const SHEET = 1;
- const STYLE_RULE = 2;
- const IMPORT_RULE = 3;
- const MEDIA_RULE = 4;
- const CHARSET_RULE = 5;
- const PAGE_RULE = 6;
- const OWNER_NODE = 7;
-
- // const COMPATIBILITY_TAB = 1;
- const GENERAL_TAB = 2;
- const TEXT_TAB = 3;
- const BACKGROUND_TAB = 4;
- const BORDER_TAB = 5;
- const BOX_TAB = 6;
- const AURAL_TAB = 7;
-
- const GENERIC_SELECTOR = 0;
- const TYPE_ELEMENT_SELECTOR = 1;
- const CLASS_SELECTOR = 2;
-
- const kAsyncTimeout = 1500; // 1.5 second
-
- var objectsArray = null;
- var gTimerID;
- var gAsyncLoadingTimerID;
-
- // needed for commonCssProps.js
- var gHaveDocumentUrl = false;
-
- var gInsertIndex = -1;
-
- // * dialog initialization code
- function Startup()
- {
- // are we in a pre-1.3 Mozilla ?
- if (typeof window.InitEditorShell == "function") {
- // yes, so let's get an editorshell
- if (!InitEditorShell())
- return;
- }
- else if (typeof window.GetCurrentEditor != "function" || !GetCurrentEditor()) {
- window.close();
- return;
- }
-
- // gDialog is declared in EdDialogCommon.js
-
- gDialog.selectionBased = false;
-
- // Set commonly-used widgets like this:
- gDialog.selectedTab = TEXT_TAB;
- gDialog.sheetsTreechildren = document.getElementById("stylesheetsTree");
- gDialog.sheetsTree = document.getElementById("sheetsTree");
- gDialog.sheetInfoTab = document.getElementById("sheetInfoTab");
- gDialog.atimportButton = document.getElementById("atimportButton");
- gDialog.atmediaButton = document.getElementById("atmediaButton");
- gDialog.linkButton = document.getElementById("linkButton");
- gDialog.styleButton = document.getElementById("styleButton");
- gDialog.ruleButton = document.getElementById("ruleButton");
- gDialog.removeButton = document.getElementById("removeButton");
- gDialog.upButton = document.getElementById("upButton");
- gDialog.downButton = document.getElementById("downButton");
-
- gDialog.selectedTab = GENERAL_TAB;
- gDialog.sheetInfoTabPanelTitle = document.getElementById("sheetInfoTabPanelTitle");
- gDialog.textTab = document.getElementById("textTab");
- gDialog.brownFoxLabel = document.getElementById("brownFoxLabel");
- gDialog.backgroundImageInput = document.getElementById("backgroundImageInput");
- gDialog.backgroundPreview = document.getElementById("backgroundPreview");
- gDialog.sheetTabbox = document.getElementById("sheetTabbox");
- gDialog.backgroundColorInput = document.getElementById("backgroundColorInput");
- gDialog.textColorInput = document.getElementById("textColorInput");
- gDialog.backgroundRepeatMenulist = document.getElementById("backgroundRepeatMenulist");
- gDialog.backgroundAttachmentCheckbox = document.getElementById("backgroundAttachmentCheckbox");
- gDialog.xBackgroundPositionRadiogroup = document.getElementById("xBackgroundPositionRadiogroup");
- gDialog.yBackgroundPositionRadiogroup = document.getElementById("yBackgroundPositionRadiogroup");
- gDialog.fontFamilyRadiogroup = document.getElementById("fontFamilyRadiogroup");
- gDialog.customFontFamilyInput = document.getElementById("customFontFamilyInput");
- gDialog.predefFontFamilyMenulist = document.getElementById("predefFontFamilyMenulist");
- gDialog.fontSizeInput = document.getElementById("fontSizeInput");
- gDialog.lineHeightInput = document.getElementById("lineHeightInput");
- gDialog.textUnderlineCheckbox = document.getElementById("underlineTextDecorationCheckbox");
- gDialog.textOverlineCheckbox = document.getElementById("overlineTextDecorationCheckbox");
- gDialog.textLinethroughCheckbox = document.getElementById("linethroughTextDecorationCheckbox");
- gDialog.textBlinkCheckbox = document.getElementById("blinkTextDecorationCheckbox");
- gDialog.noDecorationCheckbox = document.getElementById("noneTextDecorationCheckbox");
-
- gDialog.topBorderStyleMenulist = document.getElementById("topBorderStyleMenulist");
- gDialog.topBorderWidthInput = document.getElementById("topBorderWidthInput");
- gDialog.topBorderColorInput = document.getElementById("topBorderColorInput");
-
- gDialog.leftBorderStyleMenulist = document.getElementById("leftBorderStyleMenulist");
- gDialog.leftBorderWidthInput = document.getElementById("leftBorderWidthInput");
- gDialog.leftBorderColorInput = document.getElementById("leftBorderColorInput");
-
- gDialog.rightBorderStyleMenulist = document.getElementById("rightBorderStyleMenulist");
- gDialog.rightBorderWidthInput = document.getElementById("rightBorderWidthInput");
- gDialog.rightBorderColorInput = document.getElementById("rightBorderColorInput");
-
- gDialog.bottomBorderStyleMenulist = document.getElementById("bottomBorderStyleMenulist");
- gDialog.bottomBorderWidthInput = document.getElementById("bottomBorderWidthInput");
- gDialog.bottomBorderColorInput = document.getElementById("bottomBorderColorInput");
-
- gDialog.allFourBordersSame = document.getElementById("allFourBordersSame");
- gDialog.borderPreview = document.getElementById("borderPreview");
-
- gDialog.volumeScrollbar = document.getElementById("volumeScrollbar");
- gDialog.volumeMenulist = document.getElementById("volumeMenulist");
- gDialog.muteVolumeCheckbox = document.getElementById("muteVolumeCheckbox");
-
- gDialog.opacityScrollbar = document.getElementById("opacityScrollbar");
- gDialog.opacityLabel = document.getElementById("opacityLabel");
-
- gDialog.sheetInfoTabGridRows = document.getElementById("sheetInfoTabGridRows");
- gDialog.sheetInfoTabGrid = document.getElementById("sheetInfoTabGrid");
-
- gDialog.expertMode = true;
- gDialog.modified = false;
- gDialog.selectedIndex = -1;
-
- gHaveDocumentUrl = GetDocumentBaseUrl();
-
- // Initialize all dialog widgets here,
- // e.g., get attributes from an element for property dialog
- InitSheetsTree(gDialog.sheetsTreechildren);
-
- // Set window location relative to parent window (based on persisted attributes)
- SetWindowLocation();
- }
-
- // * Toggles on/off expert mode. In expert mode, all buttons are enabled
- // including buttons for stylesheet creation. When the mode is off, only
- // the "create rule" button is enabled, a stylesheet being created to contain
- // the new rule if necessary
- function toggleExpertMode()
- {
- // toggle the boolean
- gDialog.expertMode = !gDialog.expertMode;
-
- if (gDialog.expertMode) {
- if (gDialog.selectedIndex == -1) {
- // if expert mode is on but no selection in the tree, only
- // sheet creation buttons are enabled
- UpdateButtons(false, false, true, true, false, false);
- }
- else {
- // if expert mode is on and we have something selected in the tree,
- // the state of the buttons depend on the type of the selection
- var external = objectsArray[gDialog.selectedIndex].external;
- var type = objectsArray[gDialog.selectedIndex].type;
- UpdateButtons(!external, !external, true, true, !external, (!external || (type == SHEET)) );
- }
- }
- else {
- // if we're not in expert mode, allow only rule creation button
- UpdateButtons(!gDialog.atimportButton.hasAttribute("disabled"),
- !gDialog.atmediaButton.hasAttribute("disabled"),
- !gDialog.linkButton.hasAttribute("disabled"),
- !gDialog.styleButton.hasAttribute("disabled"),
- !gDialog.ruleButton.hasAttribute("disabled"),
- !gDialog.removeButton.hasAttribute("disabled"));
- }
- }
-
- // * This function recreates the contents of the STYLE elements and
- // of the stylesheets local to the filesystem
- function FlushChanges()
- {
- if (gDialog.modified) {
- // let's make sure the editor is going to require save on exit
- getCurrentEditor().incrementModificationCount(1);
- }
- // Validate all user data and set attributes and possibly insert new element here
- // If there's an error the user must correct, return false to keep dialog open.
- var sheet;
- for (var i = 0; i < objectsArray.length; i++) {
- if (objectsArray[i].modified && !objectsArray[i].external &&
- objectsArray[i].type == SHEET) {
- /* let's serialize this stylesheet ! */
- sheet = objectsArray[i].cssElt;
- if (sheet.ownerNode.nodeName.toLowerCase() == "link")
- SerializeExternalSheet(sheet, null);
- else
- SerializeEmbeddedSheet(sheet);
- }
- }
- SaveWindowLocation();
- return true; // do close the window
- }
-
- // * removes all the content in a tree
- // param XULElement sheetsTree
- function CleanSheetsTree(sheetsTreeChildren)
- {
- // we need to clear the selection in the tree otherwise the onselect
- // action on the tree will be fired when we removed the selected entry
- ClearTreeSelection(gDialog.sheetsTree);
-
- var elt = sheetsTreeChildren.firstChild;
- while (elt) {
- var tmp = elt.nextSibling;
- sheetsTreeChildren.removeChild(elt);
- elt = tmp;
- }
- }
-
- function AddSheetEntryToTree(sheetsTree, ownerNode)
- {
- if (ownerNode.nodeType == Node.ELEMENT_NODE) {
- var ownerTag = ownerNode.nodeName.toLowerCase()
- var relType = ownerNode.getAttribute("rel");
- if (relType) relType = relType.toLowerCase();
- if (ownerTag == "style" ||
- (ownerTag == "link" && relType.indexOf("stylesheet") != -1)) {
-
- var treeitem = document.createElementNS(XUL_NS, "treeitem");
- var treerow = document.createElementNS(XUL_NS, "treerow");
- var treecell = document.createElementNS(XUL_NS, "treecell");
-
- // what kind of owner node do we have here ?
- // a style element indicates an embedded stylesheet,
- // while a link element indicates an external stylesheet;
- // the case of an XML Processing Instruction is not handled, we
- // are supposed to be in HTML 4
- var external = false;
- if (ownerTag == "style") {
- treecell.setAttribute("label", "internal stylesheet");
- }
- else if (ownerTag == "link") {
- // external stylesheet, let's present its URL to user
- treecell.setAttribute("label", ownerNode.href);
- external = true;
- if ( /(\w*):.*/.test(ownerNode.href) ) {
- if (RegExp.$1 == "file") {
- external = false;
- }
- }
- else
- external = false;
- }
- // add a new entry to the tree
- var o = newObject( treeitem, external, SHEET, ownerNode.sheet, false, 0 );
- PushInObjectsArray(o);
-
- treerow.appendChild(treecell);
- treeitem.appendChild(treerow);
- treeitem.setAttribute("container", "true");
- // add enties to the tree for the rules in the current stylesheet
- var rules = null;
- if (ownerNode.sheet)
- rules = ownerNode.sheet.cssRules;
- AddRulesToTreechildren(treeitem, rules, external, 1);
-
- sheetsTree.appendChild(treeitem);
- }
- }
- }
-
- function PushInObjectsArray(o)
- {
- if (gInsertIndex == -1)
- objectsArray.push(o);
- else {
- objectsArray.splice(gInsertIndex, 0, o);
- gInsertIndex++;
- }
- }
-
- // * populates the tree in the dialog with entries
- // corresponding to all stylesheets and css rules attached to
- // document
- // param XULElement sheetsTree
- function InitSheetsTree(sheetsTree)
- {
- // remove all entries in the tree
- CleanSheetsTree(sheetsTree);
- // Look for the stylesheets attached to the current document
- // Get them from the STYLE and LINK elements because of async sheet loading :
- // the LINK element is always here while the corresponding sheet might be
- // delayed by network
- var headNode = GetHeadElement();
- if ( headNode && headNode.hasChildNodes() ) {
- var ssn = headNode.childNodes.length;
- objectsArray = new Array();
- if (ssn) {
- var i;
- gInsertIndex = -1;
- for (i=0; i<ssn; i++) {
- var ownerNode = headNode.childNodes[i];
- AddSheetEntryToTree(sheetsTree, ownerNode);
- }
- }
- }
- }
-
- // * create a new "object" corresponding to an entry in the tree
- // unfortunately, it's still impossible to attach a JS object to
- // a treecell :-(
- // param XULElement xulElt
- // param boolean external
- // param integer type
- // param (DOMNode|DOMCSSStyleSheet|DOMCSSRule) cssElt
- // param boolean modified
- // param integer depth
- function newObject( xulElt, external, type, cssElt, modified, depth)
- {
- return {xulElt:xulElt,
- external:external,
- type:type,
- cssElt:cssElt,
- modified:modified,
- depth:depth};
- }
-
- function AddStyleRuleToTreeChildren(rule, external, depth)
- {
- var subtreeitem = document.createElementNS(XUL_NS, "treeitem");
- var subtreerow = document.createElementNS(XUL_NS, "treerow");
- var subtreecell = document.createElementNS(XUL_NS, "treecell");
- // show the selector attached to the rule
- subtreecell.setAttribute("label", rule.selectorText);
- var o = newObject( subtreeitem, external, STYLE_RULE, rule, false, depth );
- PushInObjectsArray(o);
- if (external) {
- subtreecell.setAttribute("properties", "external");
- }
- subtreerow.appendChild(subtreecell);
- subtreeitem.appendChild(subtreerow);
-
- return subtreeitem;
- }
-
- function AddPageRuleToTreeChildren(rule, external, depth)
- {
- var subtreeitem = document.createElementNS(XUL_NS, "treeitem");
- var subtreerow = document.createElementNS(XUL_NS, "treerow");
- var subtreecell = document.createElementNS(XUL_NS, "treecell");
- // show the selector attached to the rule
- subtreecell.setAttribute("label", "@page " + rule.selectorText);
- var o = newObject( subtreeitem, external, PAGE_RULE, rule, false, depth );
- PushInObjectsArray(o);
- if (external) {
- subtreecell.setAttribute("properties", "external");
- }
- subtreerow.appendChild(subtreecell);
- subtreeitem.appendChild(subtreerow);
-
- return subtreeitem;
- }
-
- function AddImportRuleToTreeChildren(rule, external, depth)
- {
- var subtreeitem = document.createElementNS(XUL_NS, "treeitem");
- var subtreerow = document.createElementNS(XUL_NS, "treerow");
- var subtreecell = document.createElementNS(XUL_NS, "treecell");
- // show "@import" and the URL
- subtreecell.setAttribute("label", "@import "+rule.href, external);
- var o = newObject( subtreeitem, external, IMPORT_RULE, rule, false, depth );
- PushInObjectsArray(o);
- if (external) {
- subtreecell.setAttribute("properties", "external");
- }
- subtreerow.appendChild(subtreecell);
- subtreeitem.appendChild(subtreerow);
- subtreeitem.setAttribute("container", "true");
- if (rule.styleSheet) {
- // if we have a stylesheet really imported, let's browse it too
- // increasing the depth and marking external
- AddRulesToTreechildren(subtreeitem , rule.styleSheet.cssRules, true, depth+1);
- }
- return subtreeitem;
- }
-
- // * adds subtreeitems for the CSS rules found
- // into rules; in case of an at-rule, the method calls itself with
- // a subtreeitem, the rules in the at-rule, a boolean specifying if
- // the rules are external to the document or not, and an increased
- // depth.
- // param XULElement treeItem
- // param CSSRuleList rules
- // param boolean external
- // param integer depth
- function AddRulesToTreechildren(treeItem, rules, external, depth)
- {
- // is there any rule in the stylesheet ; earlay way out if not
- if (rules && rules.length) {
- var subtreechildren = document.createElementNS(XUL_NS, "treechildren");
- var j, o;
- var subtreeitem, subtreerow, subtreecell;
- // let's browse all the rules
- for (j=0; j< rules.length; j++) {
- switch (rules[j].type) {
- case CSSRule.STYLE_RULE:
- // this is a CSSStyleRule
- subtreeitem = AddStyleRuleToTreeChildren(rules[j], external, depth);
- subtreechildren.appendChild(subtreeitem);
- break;
- case CSSRule.PAGE_RULE:
- // this is a CSSStyleRule
- subtreeitem = AddPageRuleToTreeChildren(rules[j], external, depth);
- subtreechildren.appendChild(subtreeitem);
- break;
- case CSSRule.IMPORT_RULE:
- // this is CSSImportRule for @import
- subtreeitem = AddImportRuleToTreeChildren(rules[j], external, depth);
- subtreechildren.appendChild(subtreeitem);
- break;
- case CSSRule.MEDIA_RULE:
- // this is a CSSMediaRule @media
- subtreeitem = document.createElementNS(XUL_NS, "treeitem");
- subtreerow = document.createElementNS(XUL_NS, "treerow");
- subtreecell = document.createElementNS(XUL_NS, "treecell");
- // show "@media" and media list
- subtreecell.setAttribute("label", "@media "+rules[j].media.mediaText, external);
- o = newObject( subtreeitem, external, MEDIA_RULE, rules[j], false, depth );
- PushInObjectsArray(o);
- if (external) {
- subtreecell.setAttribute("properties", "external");
- }
- subtreerow.appendChild(subtreecell);
- subtreeitem.appendChild(subtreerow);
- subtreeitem.setAttribute("container", "true");
- // let's browse the rules attached to this CSSMediaRule, keeping the
- // current external and increasing depth
- AddRulesToTreechildren(subtreeitem, rules[j].cssRules, external, depth+1);
- subtreechildren.appendChild(subtreeitem);
- break;
- case CSSRule.CHARSET_RULE:
- // this is a CSSCharsetRule
- subtreeitem = document.createElementNS(XUL_NS, "treeitem");
- subtreerow = document.createElementNS(XUL_NS, "treerow");
- subtreecell = document.createElementNS(XUL_NS, "treecell");
- // show "@charset" and the encoding
- subtreecell.setAttribute("label", "@charset "+rules[j].encoding, external);
- o = newObject( subtreeitem, external, CHARSET_RULE, rules[j], false, depth );
- PushInObjectsArray(o);
- if (external) {
- subtreecell.setAttribute("properties", "external");
- }
- subtreerow.appendChild(subtreecell);
- subtreeitem.appendChild(subtreerow);
- subtreechildren.appendChild(subtreeitem);
- break;
- }
- }
- treeItem.appendChild(subtreechildren);
- }
- }
-
- function GetSelectedItemData()
- {
- // get the selected tree item (if any)
- var selectedItem = getSelectedItem(gDialog.sheetsTree);
- gDialog.selectedIndex = -1;
- gDialog.selectedObject = null;
-
- if (!objectsArray)
- return;
- // look for the object in objectsArray corresponding to the
- // selectedItem
- var i, l = objectsArray.length;
- if (selectedItem) {
- for (i=0; i<l; i++) {
- if (objectsArray[i].xulElt == selectedItem) {
- gDialog.selectedIndex = i;
- gDialog.treeItem = objectsArray[i].xulElt;
- gDialog.externalObject = objectsArray[i].external;
- gDialog.selectedType = objectsArray[i].type;
- gDialog.selectedObject = objectsArray[i].cssElt;
- gDialog.modifiedObject = objectsArray[i].modified;
- gDialog.depthObject = objectsArray[i].depth;
- break;
- }
- }
- }
- }
-
- // * selects either a tree item (sheet, rule) or a tab
- // in the former case, the parameter is null ; in the latter,
- // the parameter is a string containing the name of the selected tab
- // param String tab
- function onSelectCSSTreeItem(tab)
- {
- // convert the tab string into a tab id
- if (tab == "general") tab = GENERAL_TAB;
- else if (tab == "text") tab = TEXT_TAB;
- else if (tab == "background") tab = BACKGROUND_TAB;
- else if (tab == "border") tab = BORDER_TAB;
- else if (tab == "box") tab = BOX_TAB;
- else if (tab == "aural") tab = AURAL_TAB;
-
- GetSelectedItemData();
-
- if (gDialog.selectedIndex == -1) {
- // there is no tree item selected, let's fallback to the Info tab
- // but there is nothing we can display in that tab...
- gDialog.sheetTabbox.selectedTab = gDialog.sheetInfoTab;
- return;
- }
-
- var external = objectsArray[gDialog.selectedIndex].external;
- var type = objectsArray[gDialog.selectedIndex].type;
- var cssObject = gDialog.selectedObject;
- // Let's update the buttons depending on what kind of object is
- // selected in the tree
- UpdateButtons(!external, !external, true, true, !external, (!external || (type == SHEET)) );
-
- if (gDialog.selectedType != STYLE_RULE) {
- // user did not select a CSSStyleRule, let's fallback to Info tab
- tab = GENERAL_TAB;
- }
- if (!tab) {
- // this method gets called by a selection in the tree. Is there a
- // tab already selected ? If yes, keep it; if no, fallback to the
- // Info tab
- tab = gDialog.selectedTab ? gDialog.selectedTab : GENERAL_TAB;
- }
- switch (tab) {
- case TEXT_TAB:
- // we have to update the text preview, let's remove its style attribute
- gDialog.brownFoxLabel.removeAttribute("style");
- InitTextTabPanel();
- return;
- break;
- case BACKGROUND_TAB:
- InitBackgroundTabPanel();
- return;
- break;
- case BORDER_TAB:
- InitBorderTabPanel();
- return;
- break;
- case BOX_TAB:
- InitBoxTabPanel();
- return;
- break;
- case AURAL_TAB:
- InitAuralTabPanel();
- return;
- break;
- }
-
- // if we are here, the Info tab is our choice
- gDialog.selectedTab = GENERAL_TAB;
- gDialog.sheetTabbox.selectedTab = gDialog.sheetInfoTab;
-
- var gridrows = gDialog.sheetInfoTabGridRows;
- var grid = gDialog.sheetInfoTabGrid;
-
- if (gridrows) {
- // first, remove all information present in the Info tab
- grid.removeChild(gridrows);
- }
-
- gridrows = document.createElementNS(XUL_NS, "rows");
- gDialog.sheetInfoTabGridRows = gridrows;
- gridrows.setAttribute("id", "sheetInfoTabGridRows");
- grid.appendChild(gridrows);
- grid.removeAttribute("style");
-
- switch (type) {
- case OWNER_NODE:
- // this case is a workaround when we have a LINK element but the
- // corresponding stylesheet is not loaded yet
- if (gDialog.selectedObject.sheet) {
- var index = gDialog.selectedIndex;
- sheetLoadedTimeoutCallback(index);
- onSelectCSSTreeItem(tab);
- return;
- }
- break;
- case SHEET:
- if (cssObject) {
- var alternate = "";
- if (external &&
- cssObject.ownerNode.getAttribute("rel").toLowerCase().indexOf("alternate") != -1) {
- alternate = " (alternate)";
- }
- gDialog.sheetInfoTabPanelTitle.setAttribute("value", "Stylesheet"+alternate);
- AddLabelToInfobox(gridrows, "Type:", cssObject.type, null, false);
- AddCheckboxToInfobox(gridrows, "Disabled:", "check to disable stylesheet (cannot be saved)",
- cssObject.disabled, "onStylesheetDisabledChange");
- var href;
- if (cssObject.ownerNode.nodeName.toLowerCase() == "link") {
- href = cssObject.href;
- }
- else {
- href = "none (embedded into the document)";
- }
- AddLabelToInfobox(gridrows, "URL:", href, null, false);
- var mediaList = cssObject.media.mediaText;
- if (!mediaList || mediaList == "") {
- mediaList = "all";
- }
- AddEditableZoneToInfobox(gridrows, "Media list:", mediaList, "onStylesheetMediaChange", false);
- if (cssObject.title) {
- AddEditableZoneToInfobox(gridrows, "Title:", cssObject.title, "onStylesheetTitleChange", false);
- }
-
- if (cssObject.cssRules) {
- AddLabelToInfobox(gridrows, "Number of rules:", cssObject.cssRules.length, null, false);
- }
- if (!external && cssObject.ownerNode.nodeName.toLowerCase() == "style")
- // we can export only embedded stylesheets
- AddSingleButtonToInfobox(gridrows, "Export stylesheet and switch to exported version", "onExportStylesheet")
- }
- else
- AddLabelToInfobox(gridrows, "Unable to retrieve stylesheet", null, null, false);
- break;
- case STYLE_RULE:
- case PAGE_RULE:
- var h = document.defaultView.getComputedStyle(grid.parentNode, "").getPropertyValue("height");
- // let's prepare the grid for the case the rule has a laaaaarge number
- // of property declarations
- grid.setAttribute("style", "overflow: auto; height: "+h);
- gDialog.sheetInfoTabPanelTitle.setAttribute("value",
- (type == STYLE_RULE) ? "Style rule" : "Page rule" );
-
- AddLabelToInfobox(gridrows, "Selector:", cssObject.selectorText, null, false);
- if (cssObject.style.length) {
- AddLabelToInfobox(gridrows, "Declarations:", " ", "Importance", false);
- for (var i=0; i<cssObject.style.length; i++) {
- AddDeclarationToInfobox(gridrows, cssObject, i, false);
- }
- }
- // TO BE DONE : need a way of changing the importance of a given declaration
- break;
- case MEDIA_RULE:
- gDialog.sheetInfoTabPanelTitle.setAttribute("value", "Media rule");
- AddLabelToInfobox(gridrows, "Media list:", cssObject.media.mediaText, null, false);
- AddLabelToInfobox(gridrows, "Number of rules:", cssObject.cssRules.length, null, false);
- break;
- case IMPORT_RULE:
- gDialog.sheetInfoTabPanelTitle.setAttribute("value", "Import rule");
- AddLabelToInfobox(gridrows, "URL:", cssObject.href, null, false);
- AddLabelToInfobox(gridrows, "Media list:", cssObject.media.mediaText, null, false);
- break;
- // TO BE DONE : @charset and other exotic rules
- }
- }
-
- // * updates the UI buttons with the given states
- // param boolean importState
- // param mediaState
- // param boolean linkState
- // param boolean styleState
- // param boolean ruleState
- // param boolean removeState
- function UpdateButtons(importState, mediaState, linkState, styleState, ruleState, removeState)
- {
- if (!gDialog.expertMode) {
- importState = false;
- mediaState = false;
- linkState = false;
- styleState = false;
- ruleState = true;
- }
- if (!gDialog.selectedObject) {
- importState = false;
- mediaState = false;
- if (gDialog.selectedIndex != -1)
- ruleState = false;
- }
- EnableUI(gDialog.atimportButton, importState);
- EnableUI(gDialog.atmediaButton, mediaState);
- EnableUI(gDialog.linkButton, linkState);
- EnableUI(gDialog.styleButton, styleState);
- EnableUI(gDialog.ruleButton, ruleState);
- EnableUI(gDialog.removeButton, removeState);
- EnableUI(gDialog.upButton, removeState);
- EnableUI(gDialog.downButton, removeState);
- }
-
- // * adds a button to the given treerow
- // param XULElement rows
- // param String label
- // param String callback
- function AddSingleButtonToInfobox(rows, label, callback)
- {
- var row = document.createElementNS(XUL_NS, "row");
- row.setAttribute("align", "center");
- var spacer = document.createElementNS(XUL_NS, "spacer");
- var hbox = document.createElementNS(XUL_NS, "hbox");
- var button = document.createElementNS(XUL_NS, "button");
- button.setAttribute("label", label);
- button.setAttribute("class", "align-right");
- button.setAttribute("oncommand", callback+"();");
- row.appendChild(spacer);
- hbox.appendChild(button);
- row.appendChild(hbox);
- rows.appendChild(row);
- }
-
- // * adds a textarea to the given treerow, allows to assign the
- // initial value and specify that it should acquire the focus
- // param XULElement rows
- // param String label
- // param String value
- // param String callback
- // param boolean focus
- function AddEditableZoneToInfobox(rows, label, value, callback, focus)
- {
- var labelLabel = document.createElementNS(XUL_NS, "label");
- var row = document.createElementNS(XUL_NS, "row");
- row.setAttribute("align", "center");
- labelLabel.setAttribute("value", label);
- row.appendChild(labelLabel);
-
- var textbox = document.createElementNS(XUL_NS, "textbox");
- if (callback != "")
- textbox.setAttribute("oninput", callback+"(this)");
- textbox.setAttribute("value", value);
- textbox.setAttribute("size", 20);
- row.appendChild(textbox);
- rows.appendChild(row);
- if (focus)
- SetTextboxFocus(textbox);
- return textbox;
- }
-
- // * adds a radiogroup to the given treerow
- // param XULElement rows
- // param String label
- function AddRadioGroupToInfoBox(rows, label)
- {
- var row = document.createElementNS(XUL_NS, "row");
- row.setAttribute("align", "center");
-
- var labelLabel = document.createElementNS(XUL_NS, "label");
- labelLabel.setAttribute("value", label);
- row.appendChild(labelLabel);
-
- var radiogroup = document.createElementNS(XUL_NS, "radiogroup");
- row.appendChild(radiogroup);
- rows.appendChild(row);
- return radiogroup;
- }
-
- // * adds a radio button to a previously created radiogroup
- // param XULElement radiogroup
- // param String label
- // param String callback
- // param integer selectorType
- // param boolean selected
- function AddRadioToRadioGroup(radiogroup, label, callback, selectorType, selected)
- {
- var radio = document.createElementNS(XUL_NS, "radio");
- radio.setAttribute("label", label);
- radio.setAttribute("oncommand", callback + "(" + selectorType + ");" );
- if (selected)
- radio.setAttribute("selected", "true");
- radiogroup.appendChild(radio);
- }
-
- // * adds a label and a checkbox to a given treerows
- // param XULElement rows
- // param String label
- // param String checkboxLabel
- // param String value
- // param String callback
- function AddCheckboxToInfobox(rows, label, checkboxLabel, value, callback)
- {
- var row = document.createElementNS(XUL_NS, "row");
- row.setAttribute("align", "center");
-
- var labelLabel = document.createElementNS(XUL_NS, "label");
- labelLabel.setAttribute("value", label);
- row.appendChild(labelLabel);
-
- var checkbox = document.createElementNS(XUL_NS, "checkbox");
- checkbox.setAttribute("label", checkboxLabel);
- checkbox.setAttribute("checked", value);
- checkbox.setAttribute("oncommand", callback+"()");
- row.appendChild(checkbox);
-
- rows.appendChild(row);
- }
-
- // * adds a label to a given treerows; strong indicates a bold font
- // param XULElement rows
- // param String label
- // param String value
- // param boolean strong
- function AddLabelToInfobox(rows, firstLabel, flexibleLabel, lastLabel, strong)
- {
- var labelLabel = document.createElementNS(XUL_NS, "label");
- var row = document.createElementNS(XUL_NS, "row");
- row.setAttribute("align", "center");
- labelLabel.setAttribute("value", firstLabel);
- if (strong) {
- labelLabel.setAttribute("class", "titleLabel");
- }
- row.appendChild(labelLabel);
-
- if (flexibleLabel) {
- var valueLabel = document.createElementNS(XUL_NS, "label");
- valueLabel.setAttribute("value", flexibleLabel);
- if (strong) {
- valueLabel.setAttribute("class", "titleLabel");
- }
- row.appendChild(valueLabel);
- }
-
- if (lastLabel) {
- valueLabel = document.createElementNS(XUL_NS, "label");
- valueLabel.setAttribute("value", lastLabel);
- if (strong) {
- valueLabel.setAttribute("class", "titleLabel");
- }
- row.appendChild(valueLabel);
- }
-
- rows.appendChild(row);
- }
-
- // * adds a declaration's importance to a given treerows
- // param XULElement rows
- // param String label
- // param String value
- // param String importance
- function AddDeclarationToInfobox(rows, cssObject, i, importance)
- {
- var labelLabel = document.createElementNS(XUL_NS, "label");
- var row = document.createElementNS(XUL_NS, "row");
- row.setAttribute("align", "center");
- labelLabel.setAttribute("value", "");
- row.appendChild(labelLabel);
-
- var valueLabel = document.createElementNS(XUL_NS, "label");
- valueLabel.setAttribute("value", GetDeclarationText(cssObject, i));
- row.appendChild(valueLabel);
-
- var importanceLabel = document.createElementNS(XUL_NS, "checkbox");
- if (GetDeclarationImportance(cssObject, i) == "important") {
- importanceLabel.setAttribute("checked", true);
- }
- importanceLabel.setAttribute("oncommand", "TogglePropertyImportance(\"" + cssObject.style.item(i) + "\")" );
- row.appendChild(importanceLabel);
-
- rows.appendChild(row);
- }
-
- function TogglePropertyImportance(property)
- {
- var cssObject = gDialog.selectedObject;
- dump("IMPORTANCE = " + cssObject.style.getPropertyPriority(property) + "\n");
- var newImportance = (cssObject.style.getPropertyPriority(property) == "important") ? "" : "important" ;
- dump("NEW IMPORTANCE = " + newImportance + "\n");
- cssObject.style.setProperty(property, cssObject.style.getPropertyValue(property), newImportance);
- }
-
- // * retrieves the index-nth style declaration in a rule
- // param DOMCSSRule styleRule
- // param integer index
- // return String
- function GetDeclarationText(styleRule, index)
- {
- var pName = styleRule.style.item(index);
- return pName + ": " + styleRule.style.getPropertyValue(pName);
- }
-
- // * retrieves the stylesheet containing the selected tree entry
- // return integer
- function GetSheetContainer()
- {
- var index = gDialog.selectedIndex;
- while (index >= 0 && objectsArray[index].type != SHEET) {
- index--;
- }
- return index;
- }
-
- // * declares that the stylesheet containing the selected tree entry
- // has been modified
- function SetModifiedFlagOnStylesheet()
- {
- var index = GetSheetContainer();
- if (index != -1) {
- objectsArray[index].modified = true;
- gDialog.modified = true;
- }
- }
-
- // * we are about to put some info about the selected entry into
- // the Info tab
- // return XULElement
- function PrepareInfoGridForCreation()
- {
- gDialog.sheetTabbox.selectedTab = gDialog.sheetInfoTab;
-
- var gridrows = gDialog.sheetInfoTabGridRows;
- var grid = gDialog.sheetInfoTabGrid;
-
- if (gridrows) {
- grid.removeChild(gridrows);
- }
-
- gridrows = document.createElementNS(XUL_NS, "rows");
- gDialog.sheetInfoTabGridRows = gridrows;
- gridrows.setAttribute("id", "sheetInfoTabGridRows");
- grid.appendChild(gridrows);
- grid.removeAttribute("style");
- return gridrows;
- }
-
- // * user wants to create a @import rule
- function CreateNewAtimportRule()
- {
- var gridrows = PrepareInfoGridForCreation();
-
- gDialog.newType = IMPORT_RULE;
- gDialog.newMediaList = "";
- gDialog.newURL = "";
- gDialog.sheetInfoTabPanelTitle.setAttribute("value", "New Import At-rule");
- AddEditableZoneToInfobox(gridrows, "URL:", gDialog.newURL, "onNewURLChange", true);
- AddEditableZoneToInfobox(gridrows, "Media list:", gDialog.newMediaList, "onNewMediaListChange", false);
- AddSingleButtonToInfobox(gridrows, "Create Import At-rule", "onConfirmCreateNewObject", false);
- }
-
- // * user wants to create a new style rule
- function CreateNewStyleRule()
- {
- var gridrows = PrepareInfoGridForCreation();
-
- gDialog.newExternal = false;
- gDialog.newType = STYLE_RULE;
- gDialog.newSelector = "";
- gDialog.sheetInfoTabPanelTitle.setAttribute("value", "New Style Rule");
- gDialog.newSelectorType = CLASS_SELECTOR;
-
- var radiogroup = AddRadioGroupToInfoBox(gridrows, "Create a new:");
- // offer choice between class selector and type element selector
- AddRadioToRadioGroup(radiogroup, "named style (enter class name below)",
- "onCreationStyleRuleTypeChange", CLASS_SELECTOR, true);
- AddRadioToRadioGroup(radiogroup, "style applied to all elements of type (enter type below)",
- "onCreationStyleRuleTypeChange", TYPE_ELEMENT_SELECTOR, false);
- // oh, and in expert mode, allow of course any selector
- if (gDialog.expertMode) {
- AddRadioToRadioGroup(radiogroup, "style applied to all elements matching the following selector",
- "onCreationStyleRuleTypeChange", GENERIC_SELECTOR, false);
- }
- AddEditableZoneToInfobox(gridrows, " ", gDialog.newSelector, "onNewSelectorChange", true);
-
- AddSingleButtonToInfobox(gridrows, "Create Style Rule", "onConfirmCreateNewObject");
- }
-
- // * user changed the type of style rule (s)he wants to create
- // param integer type
- function onCreationStyleRuleTypeChange(type)
- {
- gDialog.newSelectorType = type;
- }
-
- // * user wants to create a new embedded stylesheet
- function CreateNewStyleElement()
- {
- var gridrows = PrepareInfoGridForCreation();
-
- gDialog.newExternal = false;
- gDialog.newType = SHEET;
- gDialog.newMediaList = "";
- gDialog.newTitle = "";
- gDialog.sheetInfoTabPanelTitle.setAttribute("value", "New Stylesheet");
- AddLabelToInfobox(gridrows, "Type:", "text/css", null, false);
- AddEditableZoneToInfobox(gridrows, "Media list:", gDialog.newMediaList, "onNewMediaListChange", true);
- AddEditableZoneToInfobox(gridrows, "Title:", gDialog.newTitle, "onNewTitleChange", false);
-
- AddSingleButtonToInfobox(gridrows, "Create Stylesheet", "onConfirmCreateNewObject")
- }
-
- // * user wants to attach an external stylesheet
- function CreateNewLinkedSheet()
- {
- var gridrows = PrepareInfoGridForCreation();
-
- gDialog.newExternal = true;
- gDialog.newType = SHEET;
- gDialog.newAlternate = false;
- gDialog.newURL = "";
- gDialog.newMediaList = "";
- gDialog.newTitle = "";
- gDialog.sheetInfoTabPanelTitle.setAttribute("value", "New Linked Stylesheet");
- AddLabelToInfobox(gridrows, "Type:", "text/css", null, false);
- // alternate stylesheet ?
- AddCheckboxToInfobox(gridrows, "Alternate:", "check to create alternate stylesheet", gDialog.newAlternate,
- "onNewAlternateChange");
- gDialog.URLtextbox = AddEditableZoneToInfobox(gridrows, "URL:", gDialog.newURL, "onNewURLChange", true);
- AddSingleButtonToInfobox(gridrows, "Choose file", "onChooseLocalFile")
-
- AddEditableZoneToInfobox(gridrows, "Media list:", gDialog.newMediaList, "onNewMediaListChange", false);
- AddEditableZoneToInfobox(gridrows, "Title:", gDialog.newTitle, "onNewTitleChange", false);
-
- AddSingleButtonToInfobox(gridrows, "Create Stylesheet", "onConfirmCreateNewObject")
-
- // the two following labels are unfortunately useful...
- AddLabelToInfobox(gridrows, "", "(Warning : save document *before* attaching local stylesheet)", null, false);
- AddLabelToInfobox(gridrows, "", "(use Refresh button if stylesheet is not immediately downloaded)", null, false);
- }
-
- // * forget about everything, and let's redo it
- function Restart()
- {
- // delete all objects we keep track of
- var l = objectsArray.length;
- for (var i=0; i<l; i++) {
- delete objectsArray[i];
- }
- delete objectsArray;
-
- // now, let's clear the tree
- var gridrows = gDialog.sheetInfoTabGridRows;
- if (gridrows) {
- var elt = gridrows.lastChild;
- while (elt) {
- var tmp = elt.previousSibling;
- gridrows.removeChild(elt);
- elt = tmp;
- }
- }
-
- // switch to default Info tab
- gDialog.selectedTab = GENERAL_TAB;
- gDialog.sheetInfoTabPanelTitle.setAttribute("value", "");
-
- // let's recreate the tree
- InitSheetsTree(gDialog.sheetsTreechildren);
- // and update the buttons
- UpdateButtons(false, false, true, true, false, false);
- }
-
- // * does less than Restart(). We only regenerate the tree, keeping track
- // of the selection
- function Refresh()
- {
- var index = gDialog.selectedIndex;
- Restart();
- if (index != -1)
- selectTreeItem(objectsArray[index].xulElt);
- }
-
- /* CALLBACKS */
-
- // * user toggled the "Alternate Stylesheet" checkbox
- function onNewAlternateChange()
- {
- gDialog.newAlternate = !gDialog.newAlternate;
- }
-
- // * user changed the URL of an external stylesheet; elt is the textarea
- // param XULElement elt
- function onNewURLChange(elt)
- {
- gDialog.newURL = elt.value;
- }
-
- // * user changed the selector for a rule; elt is the textarea
- // param XULElement elt
- function onNewSelectorChange(elt)
- {
- gDialog.newSelector = elt.value;
- }
-
- // * user changed the list of medias for a new rule; elt is the textarea
- // param XULElement elt
- function onNewMediaListChange(elt)
- {
- gDialog.newMediaList = elt.value;
- }
-
- // * user changed the title of a new stylesheet; elt is the textarea
- // param XULElement elt
- function onNewTitleChange(elt)
- {
- gDialog.newTitle = elt.value;
- }
-
- // * user disables/enabled the stylesheet
- function onStylesheetDisabledChange()
- {
- gDialog.selectedObject.disabled = !gDialog.selectedObject.disabled;
- }
-
- // * user changed the title of an existing stylesheet; elt is the textarea
- // param XULElement elt
- function onStylesheetTitleChange(elt)
- {
- var titleText = elt.value;
- gDialog.selectedObject.ownerNode.setAttribute("title", titleText);
- SetModifiedFlagOnStylesheet();
- }
-
- // * user changed the list of medias of an existing stylesheet; elt is the textarea
- // param XULElement elt
- function onStylesheetMediaChange(elt)
- {
- var mediaText= elt.value;
- gDialog.selectedObject.ownerNode.setAttribute("media", mediaText);
- SetModifiedFlagOnStylesheet();
- }
-
- function GetSubtreeChildren(elt)
- {
- var subtreechildren = null;
- if (!elt) return null;
- if (elt.hasChildNodes()) {
- subtreechildren = elt.lastChild;
- while (subtreechildren && subtreechildren .nodeName.toLowerCase() != "treechildren") {
- subtreechildren = subtreechildren .previousSibling;
- }
- }
- if (!subtreechildren) {
- subtreechildren = document.createElementNS(XUL_NS, "treechildren");
- elt.appendChild(subtreechildren);
- }
- return subtreechildren;
- }
-
- // * here, we create a new sheet or rule
- function onConfirmCreateNewObject()
- {
- // first, let's declare we modify the document
- gDialog.modified = true;
- var selector;
-
- // if we are requested to create a style rule in expert mode,
- // let's find the last embedded stylesheet
- if (!gDialog.expertMode && gDialog.newType == STYLE_RULE) {
- var indexLastEmbeddedStylesheet = -1;
- for (var i = objectsArray.length-1; i >= 0 ; i--) {
- if (objectsArray[i].type == SHEET && ! objectsArray[i].external) {
- indexLastEmbeddedStylesheet = i;
- break;
- }
- }
- if (indexLastEmbeddedStylesheet != -1) {
- gDialog.selectedIndex = indexLastEmbeddedStylesheet;
- }
- else {
- // there is no stylesheet ! let's create one that will contain our rule
- gDialog.newExternal = false;
- gDialog.newMediaList = "";
- gDialog.newTitle = "";
- gDialog.newType = SHEET;
- var selectorType = gDialog.newSelectorType;
- selector = gDialog.newSelector;
- onConfirmCreateNewObject();
-
- // now, create the rule...
- gDialog.newType = STYLE_RULE;
- gDialog.newSelectorType = selectorType;
- gDialog.newSelector = selector;
- }
- }
- var containerIndex, sheetIndex;
- var cssObject;
- var l;
- var ruleIndex;
- var newSheetOwnerNode;
- var headNode;
- var newCssRule;
- switch (gDialog.newType) {
- case STYLE_RULE:
- if (gDialog.newSelector != "") {
- containerIndex = gDialog.selectedIndex;
- while (objectsArray[containerIndex].type != SHEET &&
- objectsArray[containerIndex].type != MEDIA_RULE)
- containerIndex--;
-
- switch (gDialog.newSelectorType) {
- case TYPE_ELEMENT_SELECTOR:
- case GENERIC_SELECTOR:
- selector = gDialog.newSelector;
- break;
- case CLASS_SELECTOR:
- selector = "." + gDialog.newSelector;
- break;
- }
- cssObject = objectsArray[containerIndex].cssElt;
- l = cssObject.cssRules.length;
- cssObject.insertRule(selector + " { }", l);
-
- if (cssObject.cssRules.length > l) {
- // hmmm, there's always the bad case of a wrong rule, dropped by the
- // parser ; that's why we need to check we really inserted something
-
- /* find inserted rule's index in objectsArray */
- var depth = objectsArray[containerIndex].depth;
- var external = objectsArray[containerIndex].external;
-
- ruleIndex = containerIndex + 1;
- while (ruleIndex < objectsArray.length &&
- objectsArray[ruleIndex].depth > depth) {
- ruleIndex++;
- }
- var subtreechildren = GetSubtreeChildren(objectsArray[containerIndex].xulElt);
- gInsertIndex = ruleIndex;
- var subtreeitem = AddStyleRuleToTreeChildren(cssObject.cssRules[l], external, depth);
- subtreechildren.appendChild(subtreeitem);
- selectTreeItem(subtreeitem);
- SetModifiedFlagOnStylesheet();
- }
- }
- break;
- case IMPORT_RULE:
- if (gDialog.newURL != "") {
-
- containerIndex = GetSheetContainer();
- // **must** clear the selection before changing the tree
- ClearTreeSelection(gDialog.sheetsTree);
-
- var containerCssObject = objectsArray[containerIndex].cssElt;
- var containerDepth = objectsArray[containerIndex].depth;
- var containerExternal = objectsArray[containerIndex].external;
-
- var cssRuleIndex = -1;
- if (containerCssObject.cssRules)
- for (i=0; i < containerCssObject.cssRules.length; i++)
- if (containerCssObject.cssRules[i].type != CSSRule.IMPORT_RULE &&
- containerCssObject.cssRules[i].type != CSSRule.CHARSET_RULE) {
- cssRuleIndex = i;
- break;
- }
- if (cssRuleIndex == -1) {
- // no rule in the sheet for the moment or only charset and import rules
- containerCssObject.insertRule('@import url("'+ gDialog.newURL + '") ' + gDialog.newMediaList + ";",
- containerCssObject.cssRules.length);
- newCssRule = containerCssObject.cssRules[containerCssObject.cssRules.length - 1];
-
- subtreechildren = GetSubtreeChildren(objectsArray[containerIndex].xulElt);
-
- gInsertIndex = ruleIndex;
- subtreeitem = AddImportRuleToTreeChildren(newCssRule,
- containerExternal,
- containerDepth + 1);
-
- subtreechildren.appendChild(subtreeitem);
- ruleIndex = FindObjectIndexInObjectsArray(newCssRule);
- }
- else {
- // cssRuleIndex is the index of the first not charset and not import rule in the sheet
- ruleIndex = FindObjectIndexInObjectsArray(containerCssObject.cssRules[cssRuleIndex]);
- // and ruleIndex represents the index of the corresponding object in objectsArray
- var refObject = objectsArray[ruleIndex];
-
- containerCssObject.insertRule('@import url("'+ gDialog.newURL + '") ' + gDialog.newMediaList + ";",
- cssRuleIndex);
- newCssRule = containerCssObject.cssRules[cssRuleIndex];
- gInsertIndex = ruleIndex;
- subtreeitem = AddImportRuleToTreeChildren(newCssRule, containerExternal, containerDepth + 1);
-
- var refNode = refObject.xulElt;
- refNode.parentNode.insertBefore(subtreeitem, refNode);
- }
-
-
- selectTreeItem(subtreeitem);
- SetModifiedFlagOnStylesheet();
- if (gAsyncLoadingTimerID)
- clearTimeout(gAsyncLoadingTimerID);
- if (!newCssRule.styleSheet)
- gAsyncLoadingTimerID = setTimeout("sheetLoadedTimeoutCallback(" + ruleIndex + ")", kAsyncTimeout);
- }
- break;
- case SHEET:
- gInsertIndex = -1;
-
- ClearTreeSelection(gDialog.sheetsTree);
-
- if (gDialog.newExternal && gDialog.newURL != "") {
- subtreeitem = document.createElementNS(XUL_NS, "treeitem");
- var subtreerow = document.createElementNS(XUL_NS, "treerow");
- var subtreecell = document.createElementNS(XUL_NS, "treecell");
- subtreeitem.setAttribute("container", "true");
- subtreerow.appendChild(subtreecell);
- subtreeitem.appendChild(subtreerow);
- gDialog.sheetsTreechildren.appendChild(subtreeitem);
-
- newSheetOwnerNode = getCurrentEditor().document.createElement("link");
- newSheetOwnerNode.setAttribute("type", "text/css");
- newSheetOwnerNode.setAttribute("href", gDialog.newURL);
- if (gDialog.newAlternate) {
- newSheetOwnerNode.setAttribute("rel", "alternate stylesheet");
- }
- else {
- newSheetOwnerNode.setAttribute("rel", "stylesheet");
- }
- if (gDialog.newMediaList != "") {
- newSheetOwnerNode.setAttribute("media", gDialog.newMediaList);
- }
- if (gDialog.newTitle != "") {
- newSheetOwnerNode.setAttribute("title", gDialog.newTitle);
- }
- headNode = GetHeadElement();
- headNode.appendChild(newSheetOwnerNode);
-
- subtreecell.setAttribute("label", gDialog.newURL);
- external = true;
- if ( /(\w*):.*/.test(gDialog.newURL) ) {
- if (RegExp.$1 == "file") {
- external = false;
- }
- }
- if (external)
- subtreecell.setAttribute("properties", "external");
-
- if (!newSheetOwnerNode.sheet) {
- /* hack due to asynchronous load of external stylesheet */
- var o = newObject( subtreeitem, external, OWNER_NODE, newSheetOwnerNode, false, 0 );
- PushInObjectsArray(o)
- if (gAsyncLoadingTimerID)
- clearTimeout(gAsyncLoadingTimerID);
- sheetIndex = objectsArray.length - 1;
-
- gAsyncLoadingTimerID = setTimeout("sheetLoadedTimeoutCallback(" + sheetIndex + ")", kAsyncTimeout);
- }
- else {
- o = newObject( subtreeitem, external, SHEET, newSheetOwnerNode.sheet, false, 0 );
- PushInObjectsArray(o)
- AddRulesToTreechildren(subtreeitem, newSheetOwnerNode.sheet.cssRules, external, 1);
- }
- }
- else if (!gDialog.newExternal) {
- newSheetOwnerNode = getCurrentEditor().document.createElement("style");
- newSheetOwnerNode.setAttribute("type", "text/css");
- if (gDialog.newMediaList != "") {
- newSheetOwnerNode.setAttribute("media", gDialog.newMediaList);
- }
- if (gDialog.newTitle != "") {
- newSheetOwnerNode.setAttribute("title", gDialog.newTitle);
- }
- headNode = GetHeadElement();
- headNode.appendChild(newSheetOwnerNode);
- AddSheetEntryToTree(gDialog.sheetsTreechildren, newSheetOwnerNode);
-
- selectTreeItem(objectsArray[objectsArray.length - 1].xulElt);
- }
- selectTreeItem(subtreeitem);
- break;
- }
- }
-
- // * we need that to refresh the tree after async sheet load
- // param integer index
- function sheetLoadedTimeoutCallback(index)
- {
- var subtreeitem = objectsArray[index].xulElt;
- gInsertIndex = index+1;
- ClearTreeSelection(gDialog.sheetsTree);
- if (objectsArray[index].type == OWNER_NODE && objectsArray[index].cssElt.sheet != null) {
- var sheet = objectsArray[index].cssElt.sheet;
- AddRulesToTreechildren(subtreeitem , sheet.cssRules, objectsArray[index].external,
- objectsArray[index].depth+1);
- objectsArray[index].type = SHEET;
- objectsArray[index].cssElt = sheet;
- }
- else if (objectsArray[index].type == IMPORT_RULE && objectsArray[index].cssElt.styleSheet != null) {
- AddRulesToTreechildren(subtreeitem , objectsArray[index].cssElt.styleSheet.cssRules, true,
- objectsArray[index].depth+1)
- }
- else
- return;
- selectTreeItem(subtreeitem);
- }
-
- // * gets the object's index corresponding to an entry in the tree
- // param XULElement object
- // return integer
- function FindObjectIndexInObjectsArray(object)
- {
- var i, l = objectsArray.length;
- for (i=0; i<l; i++)
- if (objectsArray[i].cssElt == object)
- return i;
- return -1;
- }
-
- // * removes the selected entry from the tree and deletes the corresponding
- // object ; does some magic if we remove a container like a stylesheet or
- // an @import rule to remove all the contained rules
- function RemoveObject()
- {
- GetSelectedItemData();
- var objectIndex = gDialog.selectedIndex;
- if (objectIndex == -1) return;
- var depth = gDialog.depthObject;
-
- var ruleIndex, i, ruleIndexInTree, toSplice;
-
- switch (gDialog.selectedType) {
- case SHEET:
- var ownerNode = gDialog.selectedObject.ownerNode;
- ownerNode.parentNode.removeChild(ownerNode);
-
- for (i=objectIndex+1; i<objectsArray.length && objectsArray[i].depth > depth; i++);
- toSplice = i - objectIndex;
- break;
-
- case IMPORT_RULE:
- case MEDIA_RULE:
- for (ruleIndexInTree=objectIndex-1; objectsArray[ruleIndexInTree].depth >= depth; ruleIndexInTree--);
-
- objectsArray[ruleIndexInTree].modified = true;
- ruleIndex = getRuleIndexInRulesList(gDialog.selectedObject.parentStyleSheet.cssRules,
- gDialog.selectedObject);
- if (ruleIndex != -1) {
- gDialog.selectedObject.parentStyleSheet.deleteRule(ruleIndex);
- }
- for (i=objectIndex+1; i<objectsArray.length && objectsArray[i].depth > depth; i++);
- toSplice = i - objectIndex;
- break;
-
- case STYLE_RULE:
- for (ruleIndexInTree=objectIndex-1; objectsArray[ruleIndexInTree].depth; ruleIndexInTree--);
- objectsArray[ruleIndexInTree].modified = true;
- if (gDialog.selectedObject.parentRule) {
- /* this style rule is contained in an at-rule */
- /* need to remove the rule only from the at-rule listing it */
- ruleIndex = getRuleIndexInRulesList(gDialog.selectedObject.parentRule.cssRules,
- gDialog.selectedObject);
- if (ruleIndex != -1) {
- gDialog.selectedObject.parentRule.deleteRule(ruleIndex);
- }
- }
- else {
- ruleIndex = getRuleIndexInRulesList(gDialog.selectedObject.parentStyleSheet.cssRules,
- gDialog.selectedObject);
- if (ruleIndex != -1) {
- gDialog.selectedObject.parentStyleSheet.deleteRule(ruleIndex);
- }
- }
- toSplice = 1;
- break;
- }
- // let's remove the whole treeitem
- gDialog.treeItem.parentNode.removeChild(gDialog.treeItem);
- // and then remove the objects from our array
- objectsArray.splice(objectIndex, toSplice);
- // can we select an item ?
- if (objectsArray.length)
- selectTreeItem(objectsArray[Math.min(objectIndex, objectsArray.length - 1)].xulElt);
- }
-
- // * moves a sheet/rule up in the tree
- function MoveObjectUp()
- {
- GetSelectedItemData();
- var index = gDialog.selectedIndex;
- if (index <= 0) return;
- var sheetIndex = GetSheetContainer();
-
- switch (gDialog.selectedType) {
- case SHEET:
- var ownerNode = gDialog.selectedObject.ownerNode;
- ClearTreeSelection(gDialog.sheetsTree)
- index--;
- while (index && objectsArray[index].type != SHEET)
- index--;
- if (index == -1) return;
- ownerNode.parentNode.insertBefore(ownerNode, objectsArray[index].cssElt.ownerNode);
- Restart();
- selectTreeItem(objectsArray[index].xulElt);
- gDialog.modified = true;
- break;
-
- case OWNER_NODE:
- ownerNode = gDialog.selectedObject;
- ClearTreeSelection(gDialog.sheetsTree)
- index--;
- while (index && objectsArray[index].type != SHEET)
- index--;
- if (index == -1) return;
- ownerNode.parentNode.insertBefore(ownerNode, objectsArray[index].cssElt.ownerNode);
- Restart();
- selectTreeItem(objectsArray[index].xulElt);
- gDialog.modified = true;
- break;
-
- case STYLE_RULE:
- case PAGE_RULE:
- var rule = gDialog.selectedObject;
- objectsArray[sheetIndex].modified = true;
-
- ClearTreeSelection(gDialog.sheetsTree)
- var ruleText = rule.cssText;
- var subtreeitem;
- var newRule;
- if (rule.parentRule) {
- var ruleIndex = getRuleIndexInRulesList(rule.parentRule.cssRules, rule);
- var parentRule = rule.parentRule;
-
- if (ruleIndex == -1) return;
-
- if (!ruleIndex) {
- // we have to move the rule just before its parent rule
- parentRule.deleteRule(0);
- var parentRuleIndex;
-
- parentRuleIndex = getRuleIndexInRulesList(parentRule.parentStyleSheet.cssRules, parentRule);
- parentRule.parentStyleSheet.insertRule(ruleText, parentRuleIndex);
- newRule = parentRule.parentStyleSheet.cssRules[parentRuleIndex];
- }
- else {
- // we just move the rule in its parentRule
- parentRule.deleteRule(ruleIndex);
- parentRule.insertRule(ruleText, ruleIndex - 1);
- newRule = parentRule.cssRules.item(ruleIndex - 1);
- }
- // remove the tree entry
- objectsArray[index].xulElt.parentNode.removeChild(objectsArray[index].xulElt);
- // delete the object
- objectsArray.splice(index, 1);
- // position the insertion index
- gInsertIndex = index - 1;
- subtreeitem = AddStyleRuleToTreeChildren(newRule,
- objectsArray[index-1].external,
- objectsArray[index-1].depth);
- // make the new tree entry
- objectsArray[index].xulElt.parentNode.insertBefore(subtreeitem,
- objectsArray[index].xulElt);
- selectTreeItem(subtreeitem);
-
- }
- else {
- // standard case, the parent of the rule is the stylesheet itself
- ruleIndex = getRuleIndexInRulesList(rule.parentStyleSheet.cssRules, rule);
- var refStyleSheet = rule.parentStyleSheet;
- if (ruleIndex == -1) return;
- if (ruleIndex) {
- // we just move the rule in the sheet
- refStyleSheet.deleteRule(ruleIndex);
- var targetRule = refStyleSheet.cssRules.item(ruleIndex - 1);
-
- if (targetRule.type == CSSRule.MEDIA_RULE) {
- targetRule.insertRule(ruleText, targetRule.cssRules.length);
- var targetRuleIndex = FindObjectIndexInObjectsArray(targetRule);
- newRule = targetRule.cssRules.item(targetRule.cssRules.length - 1);
- var subtreechildren = GetSubtreeChildren(objectsArray[targetRuleIndex].xulElt);
-
- // in this case, the target treeitem is at same location but one level deeper
- // remove the tree entry
- objectsArray[index].xulElt.parentNode.removeChild(objectsArray[index].xulElt);
- // delete the object
- objectsArray.splice(index, 1);
- // position the insertion index
- gInsertIndex = index;
- subtreeitem = AddStyleRuleToTreeChildren(newRule,
- objectsArray[targetRuleIndex].external,
- objectsArray[targetRuleIndex].depth + 1);
- // make the new tree entry
- subtreechildren.appendChild(subtreeitem);
- selectTreeItem(subtreeitem);
- return;
- }
- else if (targetRule.type != CSSRule.IMPORT_RULE &&
- targetRule.type != CSSRule.CHARSET_RULE) {
- // we can move the rule before its predecessor only if that one is
- // not an @import rule nor an @charset rule
- refStyleSheet.insertRule(ruleText, ruleIndex - 1);
- newRule = refStyleSheet.cssRules[ruleIndex - 1];
- // remove the tree entry
- objectsArray[index].xulElt.parentNode.removeChild(objectsArray[index].xulElt);
- // delete the object
- objectsArray.splice(index, 1);
- // position the insertion index
- gInsertIndex = index - 1;
- subtreeitem = AddStyleRuleToTreeChildren(newRule,
- objectsArray[index-1].external,
- objectsArray[index-1].depth);
- // make the new tree entry
- objectsArray[index].xulElt.parentNode.insertBefore(subtreeitem,
- objectsArray[index].xulElt);
- selectTreeItem(subtreeitem);
- return;
- }
- }
- // At this point, we need to move the rule from one sheet to another one, if it
- // exists...
- // First, let's if there is another candidate stylesheet before the current one
- // for the style rule's ownership
- var refSheetIndex = FindObjectIndexInObjectsArray(refStyleSheet);
- sheetIndex = refSheetIndex;
-
- if (!sheetIndex) return; // early way out
- sheetIndex--;
- while (sheetIndex && (objectsArray[sheetIndex].type != SHEET ||
- objectsArray[sheetIndex])) {
- sheetIndex--;
- }
- if (sheetIndex == -1) return; // no embedded or local stylesheet available
- var newStyleSheet = objectsArray[sheetIndex].cssElt;
- // we need to check the type of the last rule in the sheet, if it exists
- if (newStyleSheet.cssRules.length &&
- newStyleSheet.cssRules[newStyleSheet.cssRules.length - 1].type == CSSRule.MEDIA_RULE) {
- // this media rule is our target
- var refMediaRule = newStyleSheet.cssRules[newStyleSheet.cssRules.length - 1];
- var refMediaRuleIndex = FindObjectIndexInObjectsArray(refMediaRule );
- var refRuleIndex = refMediaRuleIndex++;
- while (refRuleIndex < objectsArray.length && objectsArray[refRuleIndex].depth > 1)
- refRuleIndex++;
- // refRuleIndex represents where we should insert the new object
- }
- else {
- // we just append the rule to the list of rules of the sheet
- }
- }
- break;
- }
- }
-
- // * moves a sheet/rule down in the tree
- function MoveObjectDown()
- {
- /* NOT YET IMPLEMENTED */
- var objectIndex = FindObjectIndexInObjectsArray(gDialog.selectedObject);
- if (objectIndex == -1) return;
- }
-
- // * opens a file picker and returns the file:/// URL in gDialog.newURL
- function onChooseLocalFile() {
- // Get a local file, converted into URL format
- var fileName = getLocalFileURL(true);
- if (fileName)
- {
- gDialog.URLtextbox.setAttribute("value", fileName);
- gDialog.newURL = fileName;
- }
- }
-
- // * opens a file picker for a *.css filename, exports the selected stylesheet
- // in that file, and replace the selected embedded sheet by its external, but
- // local to the filesystem, new counterpart
- function onExportStylesheet() {
- var fileName = getLocalFileURL(false);
- SerializeExternalSheet(gDialog.selectedObject, fileName);
- var ownerNode = gDialog.selectedObject.ownerNode;
- var newSheetOwnerNode = ownerNode.ownerDocument.createElement("link");
- newSheetOwnerNode.setAttribute("type", "text/css");
- newSheetOwnerNode.setAttribute("href", fileName);
- newSheetOwnerNode.setAttribute("rel", "stylesheet");
- var mediaList = ownerNode.getAttribute("media");
- if (mediaList && mediaList != "")
- newSheetOwnerNode.setAttribute("media", mediaList);
- ownerNode.parentNode.insertBefore(newSheetOwnerNode, ownerNode);
- ownerNode.parentNode.removeChild(ownerNode);
-
- // we still have to wait for async sheet loading's completion
- if (gAsyncLoadingTimerID)
- clearTimeout(gAsyncLoadingTimerID);
- gAsyncLoadingTimerID = setTimeout("Refresh()", 500);
- }
-
- function getCurrentEditor() {
- if (typeof window.InitEditorShell == "function")
- return editorShell.editor;
- else
- return GetCurrentEditor();
- }
-
- function AddCSSLevelChoice(rows)
- {
- var labelLabel = document.createElementNS(XUL_NS, "label");
- var row = document.createElementNS(XUL_NS, "row");
- row.setAttribute("align", "center");
- labelLabel.setAttribute("value", "CSS Level");
-
- row.appendChild(labelLabel);
-
- var level;
- for (level = 1; level < 4; level++) {
- var levelCheckbox = document.createElementNS(XUL_NS, "checkbox");
- levelCheckbox.setAttribute("label", level);
- row.appendChild(levelCheckbox);
- }
-
- rows.appendChild(row);
- }
-
-