mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-14 11:40:13 +01:00
1715 lines
64 KiB
JavaScript
1715 lines
64 KiB
JavaScript
|
/* ***** 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);
|
||
|
}
|
||
|
|