RetroZilla/extensions/editor/cascades/resources/content/commonCssProps.js
2015-10-20 23:03:22 -04:00

1257 lines
44 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>
* Charley Manske <cmanske@netscape.com>, for local fonts access
*
* 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 ***** */
var gTimerID;
var textColor, backgroundColor, borderColor;
var gLocalFonts = null;
const kUrlString = "url(";
// * if |value| is not empty, sets the CSS property |property| to |value|
// in |elt| element's inline styles ; otherwise removes the property
// param XULElement elt
// param String property
// param String value
function AddStyleToElement(elt, property, value)
{
if (!elt || !elt.style) return;
if (value == "") {
elt.style.removeProperty(property);
}
else {
try {
elt.style.setProperty(property, value,
elt.style.getPropertyPriority(property));
}
catch (ex) { }
}
}
// * Callback from font-family selection XUL elts
// param String fontFamily
function onFontFamilySelect(fontFamily)
{
if (!gDialog.selectedObject) return;
var enableCustomInput = false;
var enablePredefMenu = false;
if (fontFamily == "") {
// nothing to do here
}
else if (fontFamily == "-user-defined") {
// user wants to select a font that is not pre-defined
// so let's get that user defined name from the textarea
enableCustomInput = true;
fontFamily = gDialog.customFontFamilyInput.value;
}
else if (fontFamily == "-predefined"){
fontFamily = "";
enablePredefMenu = true;
// user wants a predefined font family
var valueElt = gDialog.predefFontFamilyMenulist.selectedItem;
if (valueElt) {
fontFamily = valueElt.value;
}
}
else {
// all other cases are user defined fonts
enablePredefMenu = true;
}
EnableUI(gDialog.predefFontFamilyMenulist, enablePredefMenu);
EnableUI(gDialog.customFontFamilyInput, enableCustomInput);
AddStyleToElement(gDialog.brownFoxLabel, "font-family", fontFamily);
AddStyleToElement(gDialog.selectedObject, "font-family", fontFamily);
SetModifiedFlagOnStylesheet();
}
// * Callback when the color textarea's value is changed
// it sets the correspondinf property/value on the element elt
// and sets the color of the corresponding UI button
// param XULElement elt
// param String property
// param String id
// param String ColorWellID
function onColorZoneInput(elt, property, id, ColorWellID)
{
ChangeValueOnInput(elt, property, id);
setColorWell(ColorWellID, elt.value);
}
// * Opens a color picker for the requested property and handles
// the result
// param String ColorWellID
function GetColorAndUpdate(ColorWellID)
{
var colorObj = new Object;
var colorWell = document.getElementById(ColorWellID);
if (!colorWell) return;
// Don't allow a blank color, i.e., using the "default"
colorObj.NoDefault = true;
switch( ColorWellID )
{
case "textCW":
colorObj.Type = "Text";
colorObj.TextColor = textColor;
break;
case "backgroundCW":
colorObj.Type = "Page";
colorObj.PageColor = backgroundColor;
break;
case "bordertopCW":
case "borderleftCW":
case "borderrightCW":
case "borderbottomCW":
colorObj.Type = "Text";
colorObj.TextColor = borderColor;
break;
}
window.openDialog("chrome://editor/content/EdColorPicker.xul", "_blank", "chrome,close,titlebar,modal", "", colorObj);
// User canceled the dialog
if (colorObj.Cancel)
return;
var color = "";
var property = "";
var textZone = null;
switch( ColorWellID )
{
case "textCW":
color = textColor = colorObj.TextColor;
property = "color";
AddStyleToElement(gDialog.brownFoxLabel, "color", color);
textZone = gDialog.textColorInput;
break;
case "backgroundCW":
color = backgroundColor = colorObj.BackgroundColor;
property = "background-color";
textZone = gDialog.backgroundColorInput;
break;
case "bordertopCW":
color = textColor = colorObj.TextColor;
property = "border-top-color";
AddStyleToElement(gDialog.borderPreview, "border-top-color", color);
textZone = gDialog.topBorderColorInput;
break;
case "borderleftCW":
color = textColor = colorObj.TextColor;
property = "border-left-color";
AddStyleToElement(gDialog.borderPreview, "border-left-color", color);
textZone = gDialog.leftBorderColorInput;
break;
case "borderrightCW":
color = textColor = colorObj.TextColor;
property = "border-right-color";
AddStyleToElement(gDialog.borderPreview, "border-right-color", color);
textZone = gDialog.rightBorderColorInput;
break;
case "borderbottomCW":
color = textColor = colorObj.TextColor;
property = "border-bottom-color";
AddStyleToElement(gDialog.borderPreview, "border-bottom-color", color);
textZone = gDialog.bottomBorderColorInput;
break;
}
setColorWell(ColorWellID, color);
if (textZone != null) {
textZone.value = color;
if (ColorWellID == "bordertopCW")
IfFourSidesSameStyle('border', 'color', color, 'allFourBordersSame', 'borderPreview', null);
else if (ColorWellID == "backgroundCW")
AddStyleToElement(gDialog.backgroundPreview, "background-color", color);
}
try {
gDialog.selectedObject.style.setProperty(property,
color,
gDialog.selectedObject.style.getPropertyPriority(property));
}
catch (ex) {}
SetModifiedFlagOnStylesheet();
}
// * Callback when a textarea's value is changed
// it sets the corresponding property/value on the element elt
// param XULElement elt
// param String property
// param String id
function ChangeValueOnInput(elt, property, id)
{
if (!gDialog.selectedObject) return;
var value = elt.value;
if (id != null) {
elt = document.getElementById(id);
if (elt) {
AddStyleToElement(elt, property, value);
}
}
AddStyleToElement(gDialog.selectedObject, property, value);
SetModifiedFlagOnStylesheet();
}
// * Callback when a pulldown menu entry is selected
// param String property
// param String value
// param String id
function onPullDownChanged(property, value, id)
{
if (!gDialog.selectedObject) return;
if (id != null) {
var elt = document.getElementById(id);
if (elt) {
AddStyleToElement(elt, property, value);
}
}
AddStyleToElement(gDialog.selectedObject, property, value);
SetModifiedFlagOnStylesheet();
}
// * Callback when the 'none' value is selected for the
// 'text-decoration' property; it unchecks all other checkboxes
// if the 'none' checkbox is checked
function onNoneTextDecorationChange()
{
if (!gDialog.selectedObject) return;
var textDecoration = "";
if (gDialog.noDecorationCheckbox.checked) {
// uncheck other possible values for the property if 'none' is checked
gDialog.textUnderlineCheckbox.checked = false;
gDialog.textOverlineCheckbox.checked = false;
gDialog.textLinethroughCheckbox.checked = false;
gDialog.textBlinkCheckbox.checked = false;
textDecoration = "none";
}
AddStyleToElement(gDialog.selectedObject, "text-decoration", textDecoration);
AddStyleToElement(gDialog.brownFoxLabel, "text-decoration", textDecoration);
SetModifiedFlagOnStylesheet();
}
// * Callback when one of the chekboxes but for 'none' for
// 'text-decoration' property sees his state changed ; it
// recomputes the value of the property appending the various
// individual values
function onTextDecorationChange()
{
if (!gDialog.selectedObject) return;
var textDecoration = "";
if (gDialog.textUnderlineCheckbox.checked) textDecoration += "underline ";
if (gDialog.textOverlineCheckbox.checked) textDecoration += "overline ";
if (gDialog.textLinethroughCheckbox.checked) textDecoration += "line-through ";
if (gDialog.textBlinkCheckbox.checked) textDecoration += "blink ";
if (textDecoration != "") {
gDialog.noDecorationCheckbox.checked = false;
}
AddStyleToElement(gDialog.selectedObject, "text-decoration", textDecoration);
AddStyleToElement(gDialog.brownFoxLabel, "text-decoration", textDecoration);
SetModifiedFlagOnStylesheet();
}
// * This function sets a timer when the user changes an image URL
// in a textarea. This leaves the user enough time to complete the
// URL and avoids Gecko trying to load an incomplete URL
function ChangeImageSrc()
{
if (gTimerID)
clearTimeout(gTimerID);
gTimerID = setTimeout("onBgImageUrlChanged()", 800);
}
// * This is the callback from ChangeImageSrc(). It loads an image and uses
// the cache.
function onBgImageUrlChanged()
{
var property = "background-image";
var id = "backgroundPreview";
if (!gDialog.selectedObject) return;
var value = gDialog.backgroundImageInput.value;
if (value != "" && value != "none") {
try {
// Remove the image URL from image cache so it loads fresh
// (if we don't do this, loads after the first will always use image cache
// and we won't see image edit changes or be able to get actual width and height)
var IOService = GetIOService();
if (IOService)
{
// We must have an absolute URL to preview it or remove it from the cache
value = MakeAbsoluteUrl(value);
if (GetScheme(value))
{
var uri = IOService.newURI(value, null, null);
if (uri)
{
var imgCacheService = Components.classes["@mozilla.org/image/cache;1"].getService();
var imgCache = imgCacheService.QueryInterface(Components.interfaces.imgICache);
// This returns error if image wasn't in the cache; ignore that
imgCache.removeEntry(uri);
}
}
}
} catch(e) {}
value = kUrlString + value + ")";
}
if (id != null) {
var xulElt = document.getElementById(id);
if (xulElt) {
AddStyleToElement(xulElt, property, value);
}
}
AddStyleToElement(gDialog.selectedObject, property, value);
SetModifiedFlagOnStylesheet();
if (property == "background-image") {
enableBackgroundProps((value != ""));
}
}
// * This function enable some of the background-* properties that
// only make sense if there is a background image specified
// param boolean enable
function enableBackgroundProps(enable)
{
var idArray = [ "backgroundRepeatLabel", "backgroundRepeatMenulist", "backgroundAttachmentCheckbox",
"backgroundPositionLabel", "xBackgroundPositionRadiogroup",
"yBackgroundPositionRadiogroup" ];
var i, elt, lookAtNextSibling;
for (i = 0; i < idArray.length; i++) {
elt = document.getElementById(idArray[i]);
lookAtNextSibling = false;
if (elt.nodeName.toLowerCase() == "radiogroup") {
elt = elt.firstChild;
lookAtNextSibling = true;
}
while (elt) {
EnableUI(elt, enable);
if (lookAtNextSibling) {
elt = elt.nextSibling;
}
else {
elt = null;
}
}
}
}
// * open a file picker dialog for the requested file filter and
// returns the corresponding file URL into the element of ID id
// param String filterType
// param String id
function chooseFile(filterType, id)
{
// Get a local image file, converted into URL format
var fileName = GetLocalFileURL(filterType);
var elt = document.getElementById(id);
if (fileName)
{
// Always try to relativize local file URLs
if (gHaveDocumentUrl)
fileName = MakeRelativeUrl(fileName);
elt.value = fileName;
onBgImageUrlChanged();
}
SetTextboxFocus(elt);
}
// * Callback when the user changes the value for background-attachment
function onBackgroundAttachmentChange()
{
if (!gDialog.selectedObject) return;
// the checkbox is checked if the background scrolls with the page
var value = gDialog.backgroundAttachmentCheckbox.checked ? "" : "fixed";
AddStyleToElement(gDialog.selectedObject, "background-attachment", value);
SetModifiedFlagOnStylesheet();
}
// * Callback when one of the background positions (x or y) is changed
function onBackGroundPositionSelect()
{
var xPosition = gDialog.xBackgroundPositionRadiogroup.selectedItem.value;
var yPosition = gDialog.yBackgroundPositionRadiogroup.selectedItem.value;
var value = xPosition + " " + yPosition;
AddStyleToElement(gDialog.backgroundPreview, "background-position", value);
AddStyleToElement(gDialog.selectedObject, "background-position", value);
SetModifiedFlagOnStylesheet();
}
// * Inits the values shown in the Text tab panel
function InitTextTabPanel()
{
gDialog.selectedTab = TEXT_TAB;
if (!gDialog.selectedObject || !gDialog.selectedObject.style)
return;
/* INIT FONT-FAMILY */
var fontFamily = getSpecifiedStyle("font-family");
AddStyleToElement(gDialog.brownFoxLabel, "font-family", fontFamily);
var fontFamilyChoice = "noFontFamilyRadio";
var predefFontFamilyChoice = "";
var enableCustomInput = false;
var enablePredefMenu = false;
if (fontFamily == "arial,helvetica,sans-serif") {
fontFamilyChoice = "predefFontFamilyRadio";
predefFontFamilyChoice = "sansSerifFontFamilyMenuitem";
enablePredefMenu = true;
}
else if (fontFamily == "times new roman,times,serif") {
fontFamilyChoice = "predefFontFamilyRadio";
predefFontFamilyChoice = "serifFontFamilyMenuitem";
enablePredefMenu = true;
}
else if (fontFamily == "courier new,courier,monospace") {
fontFamilyChoice = "predefFontFamilyRadio";
predefFontFamilyChoice = "monospaceFontFamilyMenuitem";
enablePredefMenu = true;
}
else if (fontFamily != "") {
fontFamilyChoice = "customFontFamilyRadio";
gDialog.customFontFamilyInput.value = fontFamily;
enableCustomInput = true;
}
/* selects the radio button */
var fontFamilyItem = document.getElementById(fontFamilyChoice);
gDialog.fontFamilyRadiogroup.selectedItem = fontFamilyItem;
/* enablers/disablers */
if (enablePredefMenu) {
gDialog.predefFontFamilyMenulist.removeAttribute("disabled");
}
else {
gDialog.predefFontFamilyMenulist.setAttribute("disabled", "true");
}
if (enableCustomInput) {
gDialog.customFontFamilyInput.removeAttribute("disabled");
}
else {
gDialog.customFontFamilyInput.setAttribute("disabled", "true");
}
if (predefFontFamilyChoice != "") {
var predefFontFamilyMenuitem = document.getElementById(predefFontFamilyChoice);
gDialog.predefFontFamilyMenulist.selectedItem = predefFontFamilyMenuitem;
}
/* INIT COLOR */
textColor = ConvertRGBColorIntoHEXColor(getSpecifiedStyle("color"));
backgroundColor = ConvertRGBColorIntoHEXColor(getSpecifiedStyle("background-color"));
gDialog.textColorInput.setAttribute("value", textColor);
AddStyleToElement(gDialog.brownFoxLabel, "color", textColor);
if (backgroundColor == "")
backgroundColor = "white";
AddStyleToElement(gDialog.brownFoxLabel, "background-color", backgroundColor);
setColorWell("textCW", textColor);
/* INIT FONT-STYLE */
SelectsOneChoice("font-style", "fontStyleMenulist", "FontStyleMenu", gDialog.brownFoxLabel)
/* INIT FONT-WEIGHT */
SelectsOneChoice("font-weight", "fontWeightMenulist", "FontWeightMenu", gDialog.brownFoxLabel)
/* INIT TEXT-TRANSFORM */
SelectsOneChoice("text-transform", "textTransformMenulist", "TextTransformMenu", gDialog.brownFoxLabel)
/* INIT TEXT-ALIGN */
SelectsOneChoice("text-align", "textAlignMenulist", "TextAlignMenu", gDialog.brownFoxLabel)
/* INIT TEXT-DECORATION */
var textDecoration = getSpecifiedStyle("text-decoration");
AddStyleToElement(gDialog.brownFoxLabel, "text-decoration", textDecoration);
SelectsCheckboxIfValueContains(textDecoration, "underline", "underlineTextDecorationCheckbox");
SelectsCheckboxIfValueContains(textDecoration, "overline", "overlineTextDecorationCheckbox");
SelectsCheckboxIfValueContains(textDecoration, "line-through", "linethroughTextDecorationCheckbox");
SelectsCheckboxIfValueContains(textDecoration, "blink", "blinkTextDecorationCheckbox");
SelectsCheckboxIfValueContains(textDecoration, "none", "noneTextDecorationCheckbox");
/* INIT FONT SIZE */
var fontSize = getSpecifiedStyle("font-size");
if (!fontSize || fontSize == "")
gDialog.fontSizeInput.value = "";
else
gDialog.fontSizeInput.value = fontSize;
AddStyleToElement(gDialog.brownFoxLabel, "font-size", fontSize);
/* INIT LINE-HEIGHT */
var lineHeight = getSpecifiedStyle("line-height");
if (!lineHeight || lineHeight == "")
gDialog.lineHeightInput.value = "";
else
gDialog.lineHeightInput.value = lineHeight;
}
// * Utility function to check if the four side values of a property
// are equal so we an show a shorthand in the dialog
// param String top
// param String left
// param String right
// param String bottom
// return boolean
function AreAllFourValuesEqual(top, left, right, bottom)
{
return (top == left && top == right && top == bottom);
}
// * Retrieves the specified style for the property |prop| and
// makes it become the value of the XUL element of ID |id|
// param String id
// param String prop
function SetTextzoneValue(id, prop)
{
var elt = document.getElementById(id);
if (elt) {
var value = getSpecifiedStyle(prop);
if (!value)
elt.value = "";
else
elt.value = value;
}
}
// * Inits the values shown in the Aural tab panel
function InitAuralTabPanel()
{
gDialog.selectedTab = AURAL_TAB;
if (!gDialog.selectedObject || !gDialog.selectedObject.style)
return;
// observe the scrollbar and call onScrollbarAttrModified when an attribute is modified
gDialog.volumeScrollbar.removeEventListener("DOMAttrModified", onVolumeScrollbarAttrModified, false);
var volume = getSpecifiedStyle("volume");
if (volume == "silent") {
gDialog.muteVolumeCheckbox.checked = true;
gDialog.volumeScrollbar.setAttribute("disabled", "true");
}
else {
gDialog.muteVolumeCheckbox.checked = false;
gDialog.volumeScrollbar.removeAttribute("disabled");
}
// if no volume specified, display medium value
if (!volume)
volume = "50";
gDialog.volumeMenulist.value = volume;
UpdateScrollbar(gDialog.volumeMenulist, 'volumeScrollbar');
gDialog.volumeScrollbar.addEventListener("DOMAttrModified", onVolumeScrollbarAttrModified, false);
SelectsOneChoice("speak", "speakMenulist", "SpeakMenu", null);
SelectsOneChoice("speech-rate", "speechRateMenulist", "SpeechRateMenu", null);
}
// * this is a callback of a listener set on the scrollbar for volume setting
// param DOMMutationEvent aEvent
function onVolumeScrollbarAttrModified(aEvent)
{
if (aEvent.attrName == "curpos") {
var e = gDialog.volumeMenulist;
if (e.value == "silent") return;
var v = Math.floor(aEvent.newValue / 10);
e.value = v;
AddStyleToElement(gDialog.selectedObject, "volume", v);
SetModifiedFlagOnStylesheet();
}
}
function onOpacityScrollbarAttrModified(aEvent)
{
if (aEvent.attrName == "curpos") {
var v = aEvent.newValue / 1000;
if (v == 1)
gDialog.opacityLabel.setAttribute("value", "transparent");
else
gDialog.opacityLabel.setAttribute("value", v);
AddStyleToElement(gDialog.selectedObject, "opacity", v);
SetModifiedFlagOnStylesheet();
}
}
// * when the user checks the "mute" checkbox, 'silent' should become
// the new value of the 'volume' property. If the user unchecks it
// the value should be computed from the volume scrollbar's position
// param XULElement elt
function MuteVolume(elt)
{
var v;
if (elt.checked) {
v = "silent";
gDialog.volumeScrollbar.setAttribute("disable", "true");
}
else {
v = Math.floor(gDialog.volumeScrollbar.getAttribute("curpos") / 10);
gDialog.volumeScrollbar.removeAttribute("disable");
}
gDialog.volumeMenulist.value = v;
AddStyleToElement(gDialog.selectedObject, "volume", v);
SetModifiedFlagOnStylesheet();
}
// * updates the volume's scrollbar position using the value of the
// 'volume' property stored in the value of the XUL element |elt|.
// It also converts pre-defined volume names to the equivalent
// numerical value (defined in CSS 2 spec)
// param XULElement elt
// param String id
function UpdateScrollbar(elt, id)
{
var v = elt.value, x = 0;
if (v == "silent") return;
var e = document.getElementById(id);
switch (v) {
case "x-soft": x=0; break;
case "soft": x=250; break;
case "medium": x=500; break;
case "loud": x=750; break;
case "x-loud": x=1000; break;
default:
x = parseInt(v) * 10;
// if we don't have a number, it must be a pre-defined keyword
// and it can't be one because we checked that above
if (isNaN(x)) x = 0;
break;
}
// let's update the scrollbar's position
e.setAttribute("curpos", x);
}
// * Inits the values shown in the Box model tab panel
function InitBoxTabPanel()
{
gDialog.selectedTab = BOX_TAB;
if (!gDialog.selectedObject || !gDialog.selectedObject.style)
return;
SelectsOneChoice("display", "displayMenulist", "DisplayMenuitem", null);
SelectsOneChoice("visibility", "visibilityMenulist", "VisibilityMenuitem", null);
SelectsOneChoice("float", "floatMenulist", "FloatMenuitem", null);
SelectsOneChoice("clear", "clearMenulist", "ClearMenuitem", null);
SelectsOneChoice("position", "positionMenulist", "PositionMenuitem", null);
SelectsOneChoice("overflow", "overflowMenulist", "OverflowMenuitem", null);
SetTextzoneValue("zindexInput", "z-index");
SetTextzoneValue("margintopEditableMenulist", "margin-top");
SetTextzoneValue("paddingtopEditableMenulist", "padding-top");
SetTextzoneValue("topEditableMenulist", "top");
SetTextzoneValue("marginleftEditableMenulist", "margin-left");
SetTextzoneValue("paddingleftEditableMenulist", "padding-left");
SetTextzoneValue("leftEditableMenulist", "left");
SetTextzoneValue("marginrightEditableMenulist", "margin-right");
SetTextzoneValue("paddingrightEditableMenulist", "padding-right");
SetTextzoneValue("rightEditableMenulist", "right");
SetTextzoneValue("marginbottomEditableMenulist", "margin-bottom");
SetTextzoneValue("paddingbottomEditableMenulist","padding-bottom");
SetTextzoneValue("bottomEditableMenulist", "bottom");
SetTextzoneValue("widthEditableMenulist", "width");
SetTextzoneValue("minwidthEditableMenulist", "min-width");
SetTextzoneValue("maxwidthEditableMenulist", "max-width");
SetTextzoneValue("heightEditableMenulist", "height");
SetTextzoneValue("minheightEditableMenulist", "min-height");
SetTextzoneValue("maxheightEditableMenulist", "max-height");
}
// * Inits the values shown in the Border tab panel
function InitBorderTabPanel()
{
gDialog.selectedTab = BORDER_TAB;
if (!gDialog.selectedObject || !gDialog.selectedObject.style)
return;
/* INIT */
var style = [ getSpecifiedStyle("border-top-style"),
getSpecifiedStyle("border-left-style"),
getSpecifiedStyle("border-right-style"),
getSpecifiedStyle("border-bottom-style")
];
var width = [ getSpecifiedStyle("border-top-width"),
getSpecifiedStyle("border-left-width"),
getSpecifiedStyle("border-right-width"),
getSpecifiedStyle("border-bottom-width")
];
var color = [ ConvertRGBColorIntoHEXColor(getSpecifiedStyle("border-top-color")),
ConvertRGBColorIntoHEXColor(getSpecifiedStyle("border-left-color")),
ConvertRGBColorIntoHEXColor(getSpecifiedStyle("border-right-color")),
ConvertRGBColorIntoHEXColor(getSpecifiedStyle("border-bottom-color"))
];
var sameFourSides = false;
// let's see if we have same style/color/width for all four borders
if (AreAllFourValuesEqual(style[0], style[1], style[2], style[3]) &&
AreAllFourValuesEqual(width[0], width[1], width[2], width[3]) &&
AreAllFourValuesEqual(getHexColorFromColorName(color[0]),
getHexColorFromColorName(color[1]),
getHexColorFromColorName(color[2]),
getHexColorFromColorName(color[3]))) {
sameFourSides = true;
}
var sideArray = [ "top", "left", "right", "bottom" ];
for (var i=0; i<sideArray.length; i++) {
var styleMenu = document.getElementById( sideArray[i]+"BorderStyleMenulist" );
var colorInput = document.getElementById( sideArray[i]+"BorderColorInput" );
var widthInput = document.getElementById( sideArray[i]+"BorderWidthInput" );
if (!i || !sameFourSides) {
EnableUI(styleMenu, true);
EnableUI(colorInput, true);
EnableUI(widthInput, true);
SelectsOneChoice("border-"+sideArray[i]+"-style",
sideArray[i]+"BorderStyleMenulist",
sideArray[i]+"BorderStyle", gDialog.borderPreview)
colorInput.value = color[i];
setColorWell("border"+sideArray[i]+"CW", color[i]);
AddStyleToElement(gDialog.borderPreview, "border-"+sideArray[i]+"-color", color[i]);
widthInput.value = width[i];
AddStyleToElement(gDialog.borderPreview, "border-"+sideArray[i]+"-width", width[i]);
}
else {
EnableUI(styleMenu, false);
EnableUI(colorInput, false);
EnableUI(widthInput, false);
colorInput.value = "";
setColorWell("border"+sideArray[i]+"CW", "");
widthInput.value = "";
styleMenu.selectedItem = document.getElementById("unspecified" + sideArray[i] + "BorderStyle");
AddStyleToElement(gDialog.borderPreview, "border-"+sideArray[i]+"-color", color[0]);
AddStyleToElement(gDialog.borderPreview, "border-"+sideArray[i]+"-style", style[0]);
AddStyleToElement(gDialog.borderPreview, "border-"+sideArray[i]+"-width", width[0]);
}
}
if (sameFourSides)
gDialog.allFourBordersSame.setAttribute("checked", "true");
else
gDialog.allFourBordersSame.removeAttribute("checked");
}
// * Inits the values shown in the Background tab panel
function InitBackgroundTabPanel()
{
gDialog.selectedTab = BACKGROUND_TAB;
if (!gDialog.selectedObject || !gDialog.selectedObject.style)
return;
gDialog.opacityScrollbar.removeEventListener("DOMAttrModified", onOpacityScrollbarAttrModified, false);
var opacity = getSpecifiedStyle("opacity");
if (opacity == "")
opacity = 1;
gDialog.opacityScrollbar.setAttribute("curpos", opacity*1000);
gDialog.opacityScrollbar.addEventListener("DOMAttrModified", onOpacityScrollbarAttrModified, false);
/* INIT BACKGROUND-COLOR */
backgroundColor = ConvertRGBColorIntoHEXColor(getSpecifiedStyle("background-color"));
gDialog.backgroundColorInput.setAttribute("value", backgroundColor);
if (backgroundColor == "")
backgroundColor = "white";
setColorWell("backgroundCW", backgroundColor);
AddStyleToElement(gDialog.backgroundPreview, "background-color", backgroundColor);
/* INIT BACKGROUND-REPEAT */
var backgroundRepeat = getSpecifiedStyle("background-repeat");
var choice = "repeatBackgroundRepeatMenu";
if (backgroundRepeat == "no-repeat") {
choice = "norepeatBackgroundRepeatMenu";
}
else if (backgroundRepeat == "repeat-x") {
choice = "horizontallyBackgroundRepeatMenu";
}
else if (backgroundRepeat == "repeat-y") {
choice = "verticallyBackgroundRepeatMenu";
}
else if (backgroundRepeat == "repeat") {
choice = "repeatBackgroundRepeatMenu";
}
AddStyleToElement(gDialog.backgroundPreview, "background-repeat", backgroundRepeat);
var choiceItem = document.getElementById(choice);
gDialog.backgroundRepeatMenulist.selectedItem = choiceItem;
/* INIT BACKGROUND-IMAGE */
var backgroundImage = getSpecifiedStyle("background-image");
gDialog.backgroundImageInput.setAttribute("value", backgroundImage);
enableBackgroundProps( (backgroundImage != "none" && backgroundImage != "") );
AddStyleToElement(gDialog.backgroundPreview, "background-image", backgroundImage);
/* INIT BACKGROUND-ATTACHMENT */
var backgroundAttachment = getSpecifiedStyle("background-attachment");
gDialog.backgroundAttachmentCheckbox.checked = ( (backgroundAttachment == "fixed") ? false : true );
AddStyleToElement(gDialog.backgroundPreview, "background-attachment", backgroundAttachment);
/* INIT BACKGROUND-POSITION */
var xBackgroundPosition = getSpecifiedStyle("-x-background-x-position");
var yBackgroundPosition = getSpecifiedStyle("-x-background-y-position");
var xRadio, yRadio;
if (xBackgroundPosition == "100%" || xBackgroundPosition == "right")
xRadio = "rightXBackgroundPositionRadio";
else if (xBackgroundPosition == "50%" || xBackgroundPosition == "center")
xRadio = "centerXBackgroundPositionRadio";
else
xRadio = "leftXBackgroundPositionRadio";
if (yBackgroundPosition == "100%" || yBackgroundPosition == "bottom")
yRadio = "bottomYBackgroundPositionRadio";
else if (xBackgroundPosition == "50%" || yBackgroundPosition == "center")
yRadio = "centerYBackgroundPositionRadio";
else
yRadio = "topYBackgroundPositionRadio";
gDialog.xBackgroundPositionRadiogroup.selectedItem = document.getElementById(xRadio);
gDialog.yBackgroundPositionRadiogroup.selectedItem = document.getElementById(yRadio);
AddStyleToElement(gDialog.backgroundPreview, "background-attachment",
xBackgroundPosition + " " + yBackgroundPosition);
}
// * if the string |value| contains the substring |searchedString|, the
// checkbox of id |id| is checked ; it's unchecked otherwise.
// param String value
// param String searchedString
// param String id
function SelectsCheckboxIfValueContains(value, searchedString, id)
{
if (checkbox) {
var state = (value.indexOf(searchedString) != -1);
var checkbox = document.getElementById(id);
checkbox.checked = state;
}
}
// * First, if |xulElt| is not null, this function copies the
// specified style for the CSS property |property| to the inline
// styles carried by |xulElt|. Then it retrieves the property's
// value, remove possible dashes, and append |idSuffix| to it.
// It forms the ID of a menu item that will be selected in the
// menulist |idMenuList|.
// param String property
// param String idMenuList
// param String idSuffix
// param XULElement xulElt
function SelectsOneChoice(property, idMenulist, idSuffix, xulElt)
{
var propertyValue = getSpecifiedStyle(property);
if (xulElt) {
AddStyleToElement(xulElt, property, propertyValue);
}
propertyValue = TrimDashes(propertyValue);
var menulist = document.getElementById(idMenulist);
var choice = "unspecified" + idSuffix;
if (propertyValue && propertyValue != "") {
choice = propertyValue + idSuffix;
}
var choiceItem = document.getElementById(choice);
menulist.selectedItem = choiceItem;
}
// * utility function to convert predefined HTML4 color names
// into their #rrggbb equivalent
// param String color
// return String
function getHexColorFromColorName(color)
{
var namedColorsArray = [
{ name:"aqua", value:"#00ffff" },
{ name:"black", value:"#000000" },
{ name:"blue", value:"#0000ff" },
{ name:"fuchsia", value:"#ff00ff" },
{ name:"gray", value:"#808080" },
{ name:"green", value:"#008000" },
{ name:"lime", value:"#00ff00" },
{ name:"maroon", value:"#800000" },
{ name:"navy", value:"#000080" },
{ name:"olive", value:"#808000" },
{ name:"purple", value:"#800080" },
{ name:"red", value:"#ff0000" },
{ name:"silver", value:"#c0c0c0" },
{ name:"teal", value:"#008080" },
{ name:"white", value:"#ffffff" },
{ name:"yellow", value:"#ffff00" }
];
for (var i=0; i< namedColorsArray.length; i++) {
if (color == namedColorsArray[i].name) {
color = namedColorsArray[i].value;
break;
}
}
return color;
}
// * retrieve the specified value for the CSS property |property|.
// The beauty of the CSS OM is that the same exact function can be
// used for both inline styles carried by an element, and rules in a
// stylesheet
// param String property
// return String
function getSpecifiedStyle(property)
{
if (gDialog.selectedObject && gDialog.selectedObject.style) {
return gDialog.selectedObject.style.getPropertyValue(property).toLowerCase();
}
return null;
}
// * This recreates the textual content of an embedded stylesheet
// param DOMCSSStyleSheet sheet
function SerializeEmbeddedSheet(sheet)
{
var ownerNode = sheet.ownerNode;
var cssText = "\n";
var l = sheet.cssRules.length;
var tmp;
for (var j = 0; j< l; j++) {
tmp = sheet.cssRules.item(j).cssText;
var re = /;\s*/;
var cssTextSplitted = tmp.split(re);
cssText += " ";
for (var k=0; k<cssTextSplitted.length; k++) {
cssText += cssTextSplitted[k];
if (k != cssTextSplitted.length-1)
cssText += ";\n ";
}
if (l > 1) cssText += "\n\n";
}
var child = ownerNode.lastChild;
while (child) {
tmp = child.previousSibling;
ownerNode.removeChild(child);
child = tmp;
}
var textNode = document.createTextNode(cssText + "\n");
ownerNode.appendChild(textNode);
}
// * This recreates the textual content of an external stylesheet
// param DOMCSSStyleSheet sheet
// param String href
function SerializeExternalSheet(sheet, href)
{
const classes = Components.classes;
const interfaces = Components.interfaces;
const nsILocalFile = interfaces.nsILocalFile;
const nsIFileOutputStream = interfaces.nsIFileOutputStream;
const FILEOUT_CTRID = '@mozilla.org/network/file-output-stream;1';
var fileHandler = GetFileProtocolHandler();
var localFile;
if (href)
localFile = fileHandler.getFileFromURLSpec(href).QueryInterface(nsILocalFile);
else
localFile = fileHandler.getFileFromURLSpec(sheet.href).QueryInterface(nsILocalFile);
var fileOuputStream = classes[FILEOUT_CTRID].createInstance(nsIFileOutputStream);
try {
fileOuputStream.init(localFile, -1, -1, 0);
var cssText = "/* Generated by CaScadeS, a stylesheet editor for Mozilla Composer */\n\n";
var l = sheet.cssRules.length, tmp;
var re = /;\s*/;
var cssTextSplitted, ruleIndex, singleDeclIndex;
for (ruleIndex = 0; ruleIndex< l; ruleIndex++) {
tmp = sheet.cssRules.item(ruleIndex).cssText;
cssTextSplitted = tmp.split(re);
cssText += " ";
for (singleDeclIndex=0; singleDeclIndex<cssTextSplitted.length; singleDeclIndex++) {
cssText += cssTextSplitted[singleDeclIndex];
if (singleDeclIndex != cssTextSplitted.length-1)
cssText += ";\n ";
}
if (l > 1) cssText += "\n\n";
}
var textNode = document.createTextNode(cssText + "\n");
fileOuputStream.write(cssText, cssText.length);
fileOuputStream.close();
}
catch (ex) {}
}
// * if the checkbox of ID |checkboxID| is checked, copies the value |value|,
// supposed to be the one for the top side, to the other three sides, makes
// the XUL Element |elt| have that value. |propertyBase| and |propertySuffix|
// are used to create side properties like in border-*-style.
// The property and value are also added to the styles of the element of ID
// |previewID| if it not null.
// param String propertyBase
// param String propertySuffix
// param String value
// param String checkboxID
// param String previewID
// param XULElement elt
function IfFourSidesSameStyle(propertyBase, propertySuffix, value, checkboxID, previewID, elt)
{
// value is the value of the '*-top' property
var checkbox = document.getElementById(checkboxID);
if (!checkbox || !checkbox.checked) return;
if (!value) {
if (elt) {
value = elt.value;
}
}
var xulElt = document.getElementById(previewID);
var sideArray = [ "left", "right", "bottom" ];
for (var i=0; i<sideArray.length; i++) {
var property = propertyBase + "-" + sideArray[i] + "-" + propertySuffix;
if (xulElt) {
AddStyleToElement(xulElt, property, value);
}
AddStyleToElement(gDialog.selectedObject, property, value);
}
}
// * Callback when the user clicks on the "use same style for
// the four borders" checkbox. |elt| is that checkbox.
// param XULElement elt
function ToggleFourBorderSidesSameStyle(elt)
{
var sameStyle = elt.checked;
var sideArray = [ "left", "right", "bottom" ];
var style = getSpecifiedStyle("border-top-style");
if (!sameStyle && !style)
style = "unspecified";
var color = gDialog.topBorderColorInput.value;
var width = getSpecifiedStyle("border-top-width");
for (var i=0; i<sideArray.length; i++) {
var styleMenulist = document.getElementById( sideArray[i] + "BorderStyleMenulist" );
var widthInput = document.getElementById( sideArray[i] + "BorderWidthInput" );
var colorInput = document.getElementById( sideArray[i] + "BorderColorInput" );
var colorButton = document.getElementById( sideArray[i] + "BorderColorButton" );
if (sameStyle) {
styleMenulist.selectedItem = document.getElementById("unspecified" + sideArray[i] + "BorderStyle");
widthInput.value = "";
colorInput.value = "";
colorInput.setAttribute("disabled", "true");
setColorWell("border"+sideArray[i]+"CW", "");
widthInput.setAttribute("disabled", "true");
styleMenulist.setAttribute("disabled", "true");
colorButton.setAttribute("disabled", "true");
AddStyleToElement(gDialog.borderPreview, "border-"+sideArray[i]+"-color", color);
AddStyleToElement(gDialog.borderPreview, "border-"+sideArray[i]+"-style", style);
AddStyleToElement(gDialog.borderPreview, "border-"+sideArray[i]+"-width", width);
AddStyleToElement(gDialog.selectedObject, "border-"+sideArray[i]+"-color", color);
AddStyleToElement(gDialog.selectedObject, "border-"+sideArray[i]+"-style", style);
AddStyleToElement(gDialog.selectedObject, "border-"+sideArray[i]+"-width", width);
}
else {
styleMenulist.removeAttribute("disabled");
widthInput.removeAttribute("disabled");
colorInput.removeAttribute("disabled");
colorButton.removeAttribute("disabled");
colorInput.value = color;
setColorWell("border"+sideArray[i]+"CW", color);
widthInput.value = width;
var styleMenuitem = document.getElementById( style+sideArray[i]+"BorderStyle" );
styleMenulist.selectedItem = styleMenuitem;
}
}
}
// * Enable a XUL element depending on a boolean value
// param XULElement elt
// param boolean enabled
function EnableUI(elt, enabled)
{
if (enabled) {
elt.removeAttribute("disabled");
}
else {
elt.setAttribute("disabled", "true");
}
}
// * Initializes a menupopup containing length units. It looks for
// the current value of the property and if it is already a length,
// build the menu keeping the same numeric part and browsing all the
// possible units.
function InitLengthUnitMenuPopup(elt, property, id, allowsPercentages)
{
var value = elt.parentNode.value;
var re = /([+-]?\d*\.\d+|[+-]?\d+)\D*/ ;
var found = value.match(re);
var numPart = "0";
if (found && found.length != 0)
numPart = RegExp.$1;
var child = elt.firstChild, tmp;
while (child && child.nodeName.toLowerCase() != "menuseparator") {
tmp = child.nextSibling;
elt.removeChild(child);
child = tmp;
}
// below is an array of all valid CSS length units
var unitsArray = [ "%", "px", "pt", "cm", "in", "mm", "pc", "em", "ex" ];
var j, newitem, start = 0;
if (!allowsPercentages)
start = 1;
for (j=start; j<unitsArray.length; j++) {
var itemValue = numPart + unitsArray[j];
newitem = document.createElementNS(XUL_NS, "menuitem");
newitem.setAttribute("label", itemValue);
newitem.setAttribute("value", itemValue);
if (child)
elt.insertBefore(newitem, child);
else
elt.appendChild(newitem);
}
}
// * Removes all dashes from a string
// param String s
// return String
function TrimDashes(s)
{
var r = "", i;
for (i=0; i<s.length; i++)
if (s[i] != '-')
r += s[i];
return r;
}
// * Callback for spinbuttons. Increments of |increment| the length value of
// the XUL element of ID |id|.
// param integer increment
// param String id
function Spinbutton(increment, id)
{
var elt = document.getElementById(id);
if (elt) {
var value = elt.value;
var re = /([+-]?\d*\.\d+|[+-]?\d+)(\D*)/ ;
var found = value.match(re);
if (found && found.length != 0) {
var numPart = RegExp.$1;
var unitPart = RegExp.$2;
var unitIncrement;
switch (unitPart) {
case "cm":
case "in":
unitIncrement = 0.01;
break;
default:
unitIncrement = 1;
break;
}
elt.value = (Math.round(100 * (parseFloat(numPart) + (increment * unitIncrement)))/100) + unitPart;
}
else
elt.value = increment + "px";
elt.oninput();
}
}
// * code for initLocalFontFaceMenu shamelessly stolen from
// Charley Manske <cmanske@netscape.com>
// param XULElement menuPopup
function initLocalFontFaceMenu(menuPopup)
{
if (!menuPopup) return;
var menu = menuPopup.parentNode;
if (!gLocalFonts)
{
// Build list of all local fonts once per editor
try
{
var enumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"].createInstance();
if( enumerator )
enumerator = enumerator.QueryInterface(Components.interfaces.nsIFontEnumerator);
var localFontCount = { value: 0 }
var localFontsString = enumerator.EnumerateAllFonts(localFontCount);
if (localFontsString)
gLocalFonts = localFontsString.toString().split(",");
if (gLocalFonts)
{
// faces.sort(); Array is already sorted
for( var i = 0; i < gLocalFonts.length; i++ )
{
if( gLocalFonts[i] != "" )
{
var itemNode = document.createElement("menuitem");
itemNode.setAttribute("label", gLocalFonts[i]);
//itemNode.value = gLocalFonts[i];
itemNode.setAttribute("value", gLocalFonts[i]);
menuPopup.appendChild(itemNode);
}
}
}
}
catch(e) { }
}
//SetElementEnabledById("localFontFaceMenu", gLocalFonts != 0);
}
// * Handles a command in a menulist
// param XULElement elt
// param String property
// param String id
function DoMenulistCommand(elt, property, id) {
var choice = elt.selectedItem;
var value = choice.value;
onPullDownChanged(property, value, id);
if (property == "border-top-style") {
// this one is a special case : we need to check if the checkbox
// "all sides have same style" is checked ; if it's checked, make
// the other 3 sides acquire the style assigned to the top border
IfFourSidesSameStyle('border', 'style', value,
'allFourBordersSame', id, null);
}
}