summaryrefslogtreecommitdiffstats
path: root/comm/suite/editor/components
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /comm/suite/editor/components
parentInitial commit. (diff)
downloadthunderbird-upstream.tar.xz
thunderbird-upstream.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/suite/editor/components')
-rw-r--r--comm/suite/editor/components/dialogs/content/EdAEAttributes.js973
-rw-r--r--comm/suite/editor/components/dialogs/content/EdAECSSAttributes.js146
-rw-r--r--comm/suite/editor/components/dialogs/content/EdAEHTMLAttributes.js367
-rw-r--r--comm/suite/editor/components/dialogs/content/EdAEJSEAttributes.js200
-rw-r--r--comm/suite/editor/components/dialogs/content/EdAdvancedEdit.js342
-rw-r--r--comm/suite/editor/components/dialogs/content/EdAdvancedEdit.xhtml182
-rw-r--r--comm/suite/editor/components/dialogs/content/EdButtonProps.js146
-rw-r--r--comm/suite/editor/components/dialogs/content/EdButtonProps.xhtml92
-rw-r--r--comm/suite/editor/components/dialogs/content/EdColorPicker.js297
-rw-r--r--comm/suite/editor/components/dialogs/content/EdColorPicker.xhtml56
-rw-r--r--comm/suite/editor/components/dialogs/content/EdColorProps.js476
-rw-r--r--comm/suite/editor/components/dialogs/content/EdColorProps.xhtml134
-rw-r--r--comm/suite/editor/components/dialogs/content/EdConvertToTable.js326
-rw-r--r--comm/suite/editor/components/dialogs/content/EdConvertToTable.xhtml43
-rw-r--r--comm/suite/editor/components/dialogs/content/EdDialogCommon.js1038
-rw-r--r--comm/suite/editor/components/dialogs/content/EdDialogTemplate.js45
-rw-r--r--comm/suite/editor/components/dialogs/content/EdDialogTemplate.xhtml23
-rw-r--r--comm/suite/editor/components/dialogs/content/EdDictionary.js164
-rw-r--r--comm/suite/editor/components/dialogs/content/EdDictionary.xhtml59
-rw-r--r--comm/suite/editor/components/dialogs/content/EdFieldSetProps.js196
-rw-r--r--comm/suite/editor/components/dialogs/content/EdFieldSetProps.xhtml67
-rw-r--r--comm/suite/editor/components/dialogs/content/EdFormProps.js136
-rw-r--r--comm/suite/editor/components/dialogs/content/EdFormProps.xhtml98
-rw-r--r--comm/suite/editor/components/dialogs/content/EdHLineProps.js227
-rw-r--r--comm/suite/editor/components/dialogs/content/EdHLineProps.xhtml80
-rw-r--r--comm/suite/editor/components/dialogs/content/EdImageDialog.js661
-rwxr-xr-xcomm/suite/editor/components/dialogs/content/EdImageLinkLoader.js145
-rw-r--r--comm/suite/editor/components/dialogs/content/EdImageProps.js293
-rw-r--r--comm/suite/editor/components/dialogs/content/EdImageProps.xhtml116
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInputImage.js189
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInputImage.xhtml104
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInputProps.js345
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInputProps.xhtml135
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInsSrc.js160
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInsSrc.xhtml42
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInsertChars.js409
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInsertChars.xhtml55
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInsertMath.js330
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInsertMath.xhtml60
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInsertTOC.js378
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInsertTOC.xhtml225
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInsertTable.js254
-rw-r--r--comm/suite/editor/components/dialogs/content/EdInsertTable.xhtml82
-rw-r--r--comm/suite/editor/components/dialogs/content/EdLabelProps.js118
-rw-r--r--comm/suite/editor/components/dialogs/content/EdLabelProps.xhtml66
-rw-r--r--comm/suite/editor/components/dialogs/content/EdLinkProps.js331
-rw-r--r--comm/suite/editor/components/dialogs/content/EdLinkProps.xhtml79
-rw-r--r--comm/suite/editor/components/dialogs/content/EdListProps.js455
-rw-r--r--comm/suite/editor/components/dialogs/content/EdListProps.xhtml73
-rw-r--r--comm/suite/editor/components/dialogs/content/EdNamedAnchorProps.js159
-rw-r--r--comm/suite/editor/components/dialogs/content/EdNamedAnchorProps.xhtml43
-rw-r--r--comm/suite/editor/components/dialogs/content/EdPageProps.js159
-rw-r--r--comm/suite/editor/components/dialogs/content/EdPageProps.xhtml50
-rw-r--r--comm/suite/editor/components/dialogs/content/EdReplace.js382
-rw-r--r--comm/suite/editor/components/dialogs/content/EdReplace.xhtml65
-rw-r--r--comm/suite/editor/components/dialogs/content/EdSelectProps.js770
-rw-r--r--comm/suite/editor/components/dialogs/content/EdSelectProps.xhtml143
-rw-r--r--comm/suite/editor/components/dialogs/content/EdSnapToGrid.js62
-rw-r--r--comm/suite/editor/components/dialogs/content/EdSnapToGrid.xhtml47
-rw-r--r--comm/suite/editor/components/dialogs/content/EdSpellCheck.js495
-rw-r--r--comm/suite/editor/components/dialogs/content/EdSpellCheck.xhtml113
-rw-r--r--comm/suite/editor/components/dialogs/content/EdTableProps.js1439
-rw-r--r--comm/suite/editor/components/dialogs/content/EdTableProps.xhtml287
-rw-r--r--comm/suite/editor/components/dialogs/content/EdTextAreaProps.js171
-rw-r--r--comm/suite/editor/components/dialogs/content/EdTextAreaProps.xhtml115
-rw-r--r--comm/suite/editor/components/dialogs/content/EditConflict.js42
-rw-r--r--comm/suite/editor/components/dialogs/content/EditConflict.xhtml40
-rw-r--r--comm/suite/editor/components/dialogs/content/EditorPublish.js558
-rw-r--r--comm/suite/editor/components/dialogs/content/EditorPublish.xhtml132
-rw-r--r--comm/suite/editor/components/dialogs/content/EditorPublishOverlay.xhtml66
-rw-r--r--comm/suite/editor/components/dialogs/content/EditorPublishProgress.js391
-rw-r--r--comm/suite/editor/components/dialogs/content/EditorPublishProgress.xhtml66
-rw-r--r--comm/suite/editor/components/dialogs/content/EditorPublishSettings.js343
-rw-r--r--comm/suite/editor/components/dialogs/content/EditorPublishSettings.xhtml50
-rw-r--r--comm/suite/editor/components/dialogs/content/EditorSaveAsCharset.js155
-rw-r--r--comm/suite/editor/components/dialogs/content/EditorSaveAsCharset.xhtml46
-rw-r--r--comm/suite/editor/components/dialogs/content/edImage.inc.xhtml248
-rw-r--r--comm/suite/editor/components/dialogs/jar.mn82
-rw-r--r--comm/suite/editor/components/dialogs/moz.build6
-rw-r--r--comm/suite/editor/components/moz.build10
-rw-r--r--comm/suite/editor/components/prefs/content/editorPrefsOverlay.xhtml50
-rw-r--r--comm/suite/editor/components/prefs/content/pref-composer.xhtml84
-rw-r--r--comm/suite/editor/components/prefs/content/pref-editing.js187
-rw-r--r--comm/suite/editor/components/prefs/content/pref-editing.xhtml181
-rw-r--r--comm/suite/editor/components/prefs/jar.mn11
-rw-r--r--comm/suite/editor/components/prefs/moz.build6
-rw-r--r--comm/suite/editor/components/texzilla/content/TeXZilla.js339
-rw-r--r--comm/suite/editor/components/texzilla/jar.mn6
-rw-r--r--comm/suite/editor/components/texzilla/moz.build6
89 files changed, 18623 insertions, 0 deletions
diff --git a/comm/suite/editor/components/dialogs/content/EdAEAttributes.js b/comm/suite/editor/components/dialogs/content/EdAEAttributes.js
new file mode 100644
index 0000000000..52b7e30fac
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdAEAttributes.js
@@ -0,0 +1,973 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// HTML Attributes object for "Name" menulist
+var gHTMLAttr = {};
+
+// JS Events Attributes object for "Name" menulist
+var gJSAttr = {};
+
+// Core HTML attribute values //
+// This is appended to Name menulist when "_core" is attribute name
+var gCoreHTMLAttr = ["^id", "class", "title"];
+
+// Core event attribute values //
+// This is appended to all JS menulists
+// except those elements having "noJSEvents"
+// as a value in their gJSAttr array.
+var gCoreJSEvents = [
+ "onclick",
+ "ondblclick",
+ "onmousedown",
+ "onmouseup",
+ "onmouseover",
+ "onmousemove",
+ "onmouseout",
+ "-",
+ "onkeypress",
+ "onkeydown",
+ "onkeyup",
+];
+
+// Following are commonly-used strings
+
+// Also accept: sRGB: #RRGGBB //
+var gHTMLColors = [
+ "Aqua",
+ "Black",
+ "Blue",
+ "Fuchsia",
+ "Gray",
+ "Green",
+ "Lime",
+ "Maroon",
+ "Navy",
+ "Olive",
+ "Purple",
+ "Red",
+ "Silver",
+ "Teal",
+ "White",
+ "Yellow",
+];
+
+var gHAlign = ["left", "center", "right"];
+
+var gHAlignJustify = ["left", "center", "right", "justify"];
+
+var gHAlignTableContent = ["left", "center", "right", "justify", "char"];
+
+var gVAlignTable = ["top", "middle", "bottom", "baseline"];
+
+var gTarget = ["_blank", "_self", "_parent", "_top"];
+
+// ================ HTML Attributes ================ //
+/* For each element, there is an array of attributes,
+ whose name is the element name,
+ used to fill the "Attribute Name" menulist.
+ For each of those attributes, if they have a specific
+ set of values, those are listed in an array named:
+ "elementName_attName".
+
+ In each values string, the following characters
+ are signal to do input filtering:
+ "#" Allow only integer values
+ "%" Allow integer values or a number ending in "%"
+ "+" Allow integer values and allow "+" or "-" as first character
+ "!" Allow only one character
+ "^" The first character can be only be A-Z, a-z, hyphen, underscore, colon or period
+ "$" is an attribute required by HTML DTD
+*/
+
+/*
+ Most elements have the "dir" attribute,
+ so we use this value array
+ for all elements instead of specifying
+ separately for each element
+*/
+gHTMLAttr.all_dir = ["ltr", "rtl"];
+
+gHTMLAttr.a = [
+ "charset",
+ "type",
+ "name",
+ "href",
+ "^hreflang",
+ "target",
+ "rel",
+ "rev",
+ "!accesskey",
+ "shape", // with imagemap //
+ "coords", // with imagemap //
+ "#tabindex",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.a_target = gTarget;
+
+gHTMLAttr.a_rel = [
+ "alternate",
+ "stylesheet",
+ "start",
+ "next",
+ "prev",
+ "contents",
+ "index",
+ "glossary",
+ "copyright",
+ "chapter",
+ "section",
+ "subsection",
+ "appendix",
+ "help",
+ "bookmark",
+];
+
+gHTMLAttr.a_rev = [
+ "alternate",
+ "stylesheet",
+ "start",
+ "next",
+ "prev",
+ "contents",
+ "index",
+ "glossary",
+ "copyright",
+ "chapter",
+ "section",
+ "subsection",
+ "appendix",
+ "help",
+ "bookmark",
+];
+
+gHTMLAttr.a_shape = ["rect", "circle", "poly", "default"];
+
+gHTMLAttr.abbr = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.acronym = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.address = ["_core", "-", "^lang", "dir"];
+
+// this is deprecated //
+gHTMLAttr.applet = [
+ "codebase",
+ "archive",
+ "code",
+ "object",
+ "alt",
+ "name",
+ "%$width",
+ "%$height",
+ "align",
+ "#hspace",
+ "#vspace",
+ "-",
+ "_core",
+];
+
+gHTMLAttr.applet_align = ["top", "middle", "bottom", "left", "right"];
+
+gHTMLAttr.area = [
+ "shape",
+ "coords",
+ "href",
+ "nohref",
+ "target",
+ "$alt",
+ "#tabindex",
+ "!accesskey",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.area_target = gTarget;
+
+gHTMLAttr.area_shape = ["rect", "circle", "poly", "default"];
+
+gHTMLAttr.area_nohref = ["nohref"];
+
+gHTMLAttr.b = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.base = ["href", "target"];
+
+gHTMLAttr.base_target = gTarget;
+
+// this is deprecated //
+gHTMLAttr.basefont = ["^id", "$size", "color", "face"];
+
+gHTMLAttr.basefont_color = gHTMLColors;
+
+gHTMLAttr.bdo = ["_core", "-", "^lang", "$dir"];
+
+gHTMLAttr.bdo_dir = ["ltr", "rtl"];
+
+gHTMLAttr.big = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.blockquote = ["cite", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.body = [
+ "background",
+ "bgcolor",
+ "text",
+ "link",
+ "vlink",
+ "alink",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.body_bgcolor = gHTMLColors;
+
+gHTMLAttr.body_text = gHTMLColors;
+
+gHTMLAttr.body_link = gHTMLColors;
+
+gHTMLAttr.body_vlink = gHTMLColors;
+
+gHTMLAttr.body_alink = gHTMLColors;
+
+gHTMLAttr.br = ["clear", "-", "_core"];
+
+gHTMLAttr.br_clear = ["none", "left", "all", "right"];
+
+gHTMLAttr.button = [
+ "name",
+ "value",
+ "$type",
+ "disabled",
+ "#tabindex",
+ "!accesskey",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.button_type = ["submit", "button", "reset"];
+
+gHTMLAttr.button_disabled = ["disabled"];
+
+gHTMLAttr.caption = ["align", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.caption_align = ["top", "bottom", "left", "right"];
+
+// this is deprecated //
+gHTMLAttr.center = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.cite = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.code = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.col = [
+ "#$span",
+ "%width",
+ "align",
+ "!char",
+ "#charoff",
+ "valign",
+ "char",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.col_span = [
+ "1", // default
+];
+
+gHTMLAttr.col_align = gHAlignTableContent;
+
+gHTMLAttr.col_valign = ["top", "middle", "bottom", "baseline"];
+
+gHTMLAttr.colgroup = [
+ "#$span",
+ "%width",
+ "align",
+ "!char",
+ "#charoff",
+ "valign",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.colgroup_span = [
+ "1", // default
+];
+
+gHTMLAttr.colgroup_align = gHAlignTableContent;
+
+gHTMLAttr.colgroup_valign = ["top", "middle", "bottom", "baseline"];
+
+gHTMLAttr.dd = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.del = ["cite", "datetime", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.dfn = ["_core", "-", "^lang", "dir"];
+
+// this is deprecated //
+gHTMLAttr.dir = ["compact", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.dir_compact = ["compact"];
+
+gHTMLAttr.div = ["align", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.div_align = gHAlignJustify;
+
+gHTMLAttr.dl = ["compact", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.dl_compact = ["compact"];
+
+gHTMLAttr.dt = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.em = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.fieldset = ["_core", "-", "^lang", "dir"];
+
+// this is deprecated //
+gHTMLAttr.font = ["+size", "color", "face", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.font_color = gHTMLColors;
+
+gHTMLAttr.form = [
+ "$action",
+ "$method",
+ "enctype",
+ "accept",
+ "name",
+ "accept-charset",
+ "target",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.form_method = ["get", "post"];
+
+gHTMLAttr.form_enctype = ["application/x-www-form-urlencoded"];
+
+gHTMLAttr.form_target = gTarget;
+
+gHTMLAttr.frame = [
+ "longdesc",
+ "name",
+ "src",
+ "#frameborder",
+ "#marginwidth",
+ "#marginheight",
+ "noresize",
+ "$scrolling",
+];
+
+gHTMLAttr.frame_frameborder = ["1", "0"];
+
+gHTMLAttr.frame_noresize = ["noresize"];
+
+gHTMLAttr.frame_scrolling = ["auto", "yes", "no"];
+
+gHTMLAttr.frameset = ["rows", "cols", "-", "_core"];
+
+gHTMLAttr.h1 = ["align", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.h1_align = gHAlignJustify;
+
+gHTMLAttr.h2 = ["align", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.h2_align = gHAlignJustify;
+
+gHTMLAttr.h3 = ["align", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.h3_align = gHAlignJustify;
+
+gHTMLAttr.h4 = ["align", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.h4_align = gHAlignJustify;
+
+gHTMLAttr.h5 = ["align", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.h5_align = gHAlignJustify;
+
+gHTMLAttr.h6 = ["align", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.h6_align = gHAlignJustify;
+
+gHTMLAttr.head = ["profile", "-", "^lang", "dir"];
+
+gHTMLAttr.hr = [
+ "align",
+ "noshade",
+ "#size",
+ "%width",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.hr_align = gHAlign;
+
+gHTMLAttr.hr_noshade = ["noshade"];
+
+gHTMLAttr.html = ["version", "-", "^lang", "dir"];
+
+gHTMLAttr.i = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.iframe = [
+ "longdesc",
+ "name",
+ "src",
+ "$frameborder",
+ "marginwidth",
+ "marginheight",
+ "$scrolling",
+ "align",
+ "%height",
+ "%width",
+ "-",
+ "_core",
+];
+
+gHTMLAttr.iframe_frameborder = ["1", "0"];
+
+gHTMLAttr.iframe_scrolling = ["auto", "yes", "no"];
+
+gHTMLAttr.iframe_align = ["top", "middle", "bottom", "left", "right"];
+
+gHTMLAttr.img = [
+ "$src",
+ "$alt",
+ "longdesc",
+ "name",
+ "%height",
+ "%width",
+ "usemap",
+ "ismap",
+ "align",
+ "#border",
+ "#hspace",
+ "#vspace",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.img_ismap = ["ismap"];
+
+gHTMLAttr.img_align = ["top", "middle", "bottom", "left", "right"];
+
+gHTMLAttr.input = [
+ "$type",
+ "name",
+ "value",
+ "checked",
+ "disabled",
+ "readonly",
+ "#size",
+ "#maxlength",
+ "src",
+ "alt",
+ "usemap",
+ "ismap",
+ "#tabindex",
+ "!accesskey",
+ "accept",
+ "align",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.input_type = [
+ "text",
+ "password",
+ "checkbox",
+ "radio",
+ "submit",
+ "reset",
+ "file",
+ "hidden",
+ "image",
+ "button",
+];
+
+gHTMLAttr.input_checked = ["checked"];
+
+gHTMLAttr.input_disabled = ["disabled"];
+
+gHTMLAttr.input_readonly = ["readonly"];
+
+gHTMLAttr.input_ismap = ["ismap"];
+
+gHTMLAttr.input_align = ["top", "middle", "bottom", "left", "right"];
+
+gHTMLAttr.ins = ["cite", "datetime", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.isindex = ["prompt", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.kbd = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.label = ["for", "!accesskey", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.legend = ["!accesskey", "align", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.legend_align = ["top", "bottom", "left", "right"];
+
+gHTMLAttr.li = ["type", "#value", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.li_type = ["disc", "square", "circle", "-", "1", "a", "A", "i", "I"];
+
+gHTMLAttr.link = [
+ "charset",
+ "href",
+ "^hreflang",
+ "type",
+ "rel",
+ "rev",
+ "media",
+ "target",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.link_target = gTarget;
+
+gHTMLAttr.link_rel = [
+ "alternate",
+ "stylesheet",
+ "start",
+ "next",
+ "prev",
+ "contents",
+ "index",
+ "glossary",
+ "copyright",
+ "chapter",
+ "section",
+ "subsection",
+ "appendix",
+ "help",
+ "bookmark",
+];
+
+gHTMLAttr.link_rev = [
+ "alternate",
+ "stylesheet",
+ "start",
+ "next",
+ "prev",
+ "contents",
+ "index",
+ "glossary",
+ "copyright",
+ "chapter",
+ "section",
+ "subsection",
+ "appendix",
+ "help",
+ "bookmark",
+];
+
+gHTMLAttr.map = ["$name", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.menu = ["compact", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.menu_compact = ["compact"];
+
+gHTMLAttr.meta = [
+ "http-equiv",
+ "name",
+ "$content",
+ "scheme",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.noframes = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.noscript = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.object = [
+ "declare",
+ "classid",
+ "codebase",
+ "data",
+ "type",
+ "codetype",
+ "archive",
+ "standby",
+ "%height",
+ "%width",
+ "usemap",
+ "name",
+ "#tabindex",
+ "align",
+ "#border",
+ "#hspace",
+ "#vspace",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.object_declare = ["declare"];
+
+gHTMLAttr.object_align = ["top", "middle", "bottom", "left", "right"];
+
+gHTMLAttr.ol = ["type", "compact", "#start", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.ol_type = ["1", "a", "A", "i", "I"];
+
+gHTMLAttr.ol_compact = ["compact"];
+
+gHTMLAttr.optgroup = ["disabled", "$label", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.optgroup_disabled = ["disabled"];
+
+gHTMLAttr.option = [
+ "selected",
+ "disabled",
+ "label",
+ "value",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.option_selected = ["selected"];
+
+gHTMLAttr.option_disabled = ["disabled"];
+
+gHTMLAttr.p = ["align", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.p_align = gHAlignJustify;
+
+gHTMLAttr.param = ["^id", "$name", "value", "$valuetype", "type"];
+
+gHTMLAttr.param_valuetype = ["data", "ref", "object"];
+
+gHTMLAttr.pre = ["%width", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.q = ["cite", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.s = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.samp = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.script = ["charset", "$type", "language", "src", "defer"];
+
+gHTMLAttr.script_defer = ["defer"];
+
+gHTMLAttr.select = [
+ "name",
+ "#size",
+ "multiple",
+ "disabled",
+ "#tabindex",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.select_multiple = ["multiple"];
+
+gHTMLAttr.select_disabled = ["disabled"];
+
+gHTMLAttr.small = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.span = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.strike = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.strong = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.style = ["$type", "media", "title", "-", "^lang", "dir"];
+
+gHTMLAttr.sub = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.sup = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.table = [
+ "summary",
+ "%width",
+ "#border",
+ "frame",
+ "rules",
+ "#cellspacing",
+ "#cellpadding",
+ "align",
+ "bgcolor",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.table_frame = [
+ "void",
+ "above",
+ "below",
+ "hsides",
+ "lhs",
+ "rhs",
+ "vsides",
+ "box",
+ "border",
+];
+
+gHTMLAttr.table_rules = ["none", "groups", "rows", "cols", "all"];
+
+// Note; This is alignment of the table,
+// not table contents, like all other table child elements
+gHTMLAttr.table_align = gHAlign;
+
+gHTMLAttr.table_bgcolor = gHTMLColors;
+
+gHTMLAttr.tbody = [
+ "align",
+ "!char",
+ "#charoff",
+ "valign",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.tbody_align = gHAlignTableContent;
+
+gHTMLAttr.tbody_valign = gVAlignTable;
+
+gHTMLAttr.td = [
+ "abbr",
+ "axis",
+ "headers",
+ "scope",
+ "$#rowspan",
+ "$#colspan",
+ "align",
+ "!char",
+ "#charoff",
+ "valign",
+ "nowrap",
+ "bgcolor",
+ "%width",
+ "%height",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.td_scope = ["row", "col", "rowgroup", "colgroup"];
+
+gHTMLAttr.td_rowspan = [
+ "1", // default
+];
+
+gHTMLAttr.td_colspan = [
+ "1", // default
+];
+
+gHTMLAttr.td_align = gHAlignTableContent;
+
+gHTMLAttr.td_valign = gVAlignTable;
+
+gHTMLAttr.td_nowrap = ["nowrap"];
+
+gHTMLAttr.td_bgcolor = gHTMLColors;
+
+gHTMLAttr.textarea = [
+ "name",
+ "$#rows",
+ "$#cols",
+ "disabled",
+ "readonly",
+ "#tabindex",
+ "!accesskey",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.textarea_disabled = ["disabled"];
+
+gHTMLAttr.textarea_readonly = ["readonly"];
+
+gHTMLAttr.tfoot = [
+ "align",
+ "!char",
+ "#charoff",
+ "valign",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.tfoot_align = gHAlignTableContent;
+
+gHTMLAttr.tfoot_valign = gVAlignTable;
+
+gHTMLAttr.th = [
+ "abbr",
+ "axis",
+ "headers",
+ "scope",
+ "$#rowspan",
+ "$#colspan",
+ "align",
+ "!char",
+ "#charoff",
+ "valign",
+ "nowrap",
+ "bgcolor",
+ "%width",
+ "%height",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.th_scope = ["row", "col", "rowgroup", "colgroup"];
+
+gHTMLAttr.th_rowspan = [
+ "1", // default
+];
+
+gHTMLAttr.th_colspan = [
+ "1", // default
+];
+
+gHTMLAttr.th_align = gHAlignTableContent;
+
+gHTMLAttr.th_valign = gVAlignTable;
+
+gHTMLAttr.th_nowrap = ["nowrap"];
+
+gHTMLAttr.th_bgcolor = gHTMLColors;
+
+gHTMLAttr.thead = [
+ "align",
+ "!char",
+ "#charoff",
+ "valign",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.thead_align = gHAlignTableContent;
+
+gHTMLAttr.thead_valign = gVAlignTable;
+
+gHTMLAttr.title = ["^lang", "dir"];
+
+gHTMLAttr.tr = [
+ "align",
+ "!char",
+ "#charoff",
+ "valign",
+ "bgcolor",
+ "-",
+ "_core",
+ "-",
+ "^lang",
+ "dir",
+];
+
+gHTMLAttr.tr_align = gHAlignTableContent;
+
+gHTMLAttr.tr_valign = gVAlignTable;
+
+gHTMLAttr.tr_bgcolor = gHTMLColors;
+
+gHTMLAttr.tt = ["_core", "-", "^lang", "dir"];
+
+gHTMLAttr.u = ["_core", "-", "^lang", "dir"];
+gHTMLAttr.ul = ["type", "compact", "-", "_core", "-", "^lang", "dir"];
+
+gHTMLAttr.ul_type = ["disc", "square", "circle"];
+
+gHTMLAttr.ul_compact = ["compact"];
+
+// Prefix with "_" since this is reserved (it's stripped out)
+gHTMLAttr._var = ["_core", "-", "^lang", "dir"];
+
+// ================ JS Attributes ================ //
+// These are element specific even handlers.
+/* Most all elements use gCoreJSEvents, so those
+ are assumed except for those listed here with "noEvents"
+*/
+
+gJSAttr.a = ["onfocus", "onblur"];
+
+gJSAttr.area = ["onfocus", "onblur"];
+
+gJSAttr.body = ["onload", "onupload"];
+
+gJSAttr.button = ["onfocus", "onblur"];
+
+gJSAttr.form = ["onsubmit", "onreset"];
+
+gJSAttr.frameset = ["onload", "onunload"];
+
+gJSAttr.input = ["onfocus", "onblur", "onselect", "onchange"];
+
+gJSAttr.label = ["onfocus", "onblur"];
+
+gJSAttr.select = ["onfocus", "onblur", "onchange"];
+
+gJSAttr.textarea = ["onfocus", "onblur", "onselect", "onchange"];
+
+// Elements that don't have JSEvents:
+gJSAttr.font = ["noJSEvents"];
+
+gJSAttr.applet = ["noJSEvents"];
+
+gJSAttr.isindex = ["noJSEvents"];
+
+gJSAttr.iframe = ["noJSEvents"];
diff --git a/comm/suite/editor/components/dialogs/content/EdAECSSAttributes.js b/comm/suite/editor/components/dialogs/content/EdAECSSAttributes.js
new file mode 100644
index 0000000000..977068bd70
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdAECSSAttributes.js
@@ -0,0 +1,146 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdAdvancedEdit.js */
+/* import-globals-from EdDialogCommon.js */
+
+// build attribute list in tree form from element attributes
+function BuildCSSAttributeTable() {
+ var style = gElement.style;
+ if (style == undefined) {
+ dump("Inline styles undefined\n");
+ return;
+ }
+
+ var declLength = style.length;
+
+ if (declLength == undefined || declLength == 0) {
+ if (declLength == undefined) {
+ dump("Failed to query the number of inline style declarations\n");
+ }
+
+ return;
+ }
+
+ if (declLength > 0) {
+ for (var i = 0; i < declLength; ++i) {
+ var name = style.item(i);
+ var value = style.getPropertyValue(name);
+ AddTreeItem(name, value, "CSSAList", CSSAttrs);
+ }
+ }
+
+ ClearCSSInputWidgets();
+}
+
+function onChangeCSSAttribute() {
+ var name = TrimString(gDialog.AddCSSAttributeNameInput.value);
+ if (!name) {
+ return;
+ }
+
+ var value = TrimString(gDialog.AddCSSAttributeValueInput.value);
+
+ // First try to update existing attribute
+ // If not found, add new attribute
+ if (!UpdateExistingAttribute(name, value, "CSSAList") && value) {
+ AddTreeItem(name, value, "CSSAList", CSSAttrs);
+ }
+}
+
+function ClearCSSInputWidgets() {
+ gDialog.AddCSSAttributeTree.view.selection.clearSelection();
+ gDialog.AddCSSAttributeNameInput.value = "";
+ gDialog.AddCSSAttributeValueInput.value = "";
+ SetTextboxFocus(gDialog.AddCSSAttributeNameInput);
+}
+
+function onSelectCSSTreeItem() {
+ if (!gDoOnSelectTree) {
+ return;
+ }
+
+ var tree = gDialog.AddCSSAttributeTree;
+ if (tree && tree.view.selection.count) {
+ gDialog.AddCSSAttributeNameInput.value = GetTreeItemAttributeStr(
+ getSelectedItem(tree)
+ );
+ gDialog.AddCSSAttributeValueInput.value = GetTreeItemValueStr(
+ getSelectedItem(tree)
+ );
+ }
+}
+
+function onInputCSSAttributeName() {
+ var attName = TrimString(
+ gDialog.AddCSSAttributeNameInput.value
+ ).toLowerCase();
+ var newValue = "";
+
+ var existingValue = GetAndSelectExistingAttributeValue(attName, "CSSAList");
+ if (existingValue) {
+ newValue = existingValue;
+ }
+
+ gDialog.AddCSSAttributeValueInput.value = newValue;
+}
+
+function editCSSAttributeValue(targetCell) {
+ if (IsNotTreeHeader(targetCell)) {
+ gDialog.AddCSSAttributeValueInput.inputField.select();
+ }
+}
+
+function UpdateCSSAttributes() {
+ var CSSAList = document.getElementById("CSSAList");
+ var styleString = "";
+ for (var i = 0; i < CSSAList.childNodes.length; i++) {
+ var item = CSSAList.childNodes[i];
+ var name = GetTreeItemAttributeStr(item);
+ var value = GetTreeItemValueStr(item);
+ // this code allows users to be sloppy in typing in values, and enter
+ // things like "foo: " and "bar;". This will trim off everything after the
+ // respective character.
+ if (name.includes(":")) {
+ name = name.substring(0, name.lastIndexOf(":"));
+ }
+ if (value.includes(";")) {
+ value = value.substring(0, value.lastIndexOf(";"));
+ }
+ if (i == CSSAList.childNodes.length - 1) {
+ // Last property.
+ styleString += name + ": " + value + ";";
+ } else {
+ styleString += name + ": " + value + "; ";
+ }
+ }
+ if (styleString) {
+ // Use editor transactions if modifying the element directly in the document
+ doRemoveAttribute("style");
+ doSetAttribute("style", styleString); // NOTE BUG 18894!!!
+ } else if (gElement.getAttribute("style")) {
+ doRemoveAttribute("style");
+ }
+}
+
+function RemoveCSSAttribute() {
+ // We only allow 1 selected item
+ if (gDialog.AddCSSAttributeTree.view.selection.count) {
+ // Remove the item from the tree
+ // We always rebuild complete "style" string,
+ // so no list of "removed" items
+ getSelectedItem(gDialog.AddCSSAttributeTree).remove();
+
+ ClearCSSInputWidgets();
+ }
+}
+
+function SelectCSSTree(index) {
+ gDoOnSelectTree = false;
+ try {
+ gDialog.AddCSSAttributeTree.selectedIndex = index;
+ } catch (e) {}
+ gDoOnSelectTree = true;
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdAEHTMLAttributes.js b/comm/suite/editor/components/dialogs/content/EdAEHTMLAttributes.js
new file mode 100644
index 0000000000..1f96762754
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdAEHTMLAttributes.js
@@ -0,0 +1,367 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdAdvancedEdit.js */
+/* import-globals-from EdDialogCommon.js */
+
+function BuildHTMLAttributeNameList() {
+ gDialog.AddHTMLAttributeNameInput.removeAllItems();
+
+ var elementName = gElement.localName;
+ var attNames = gHTMLAttr[elementName];
+
+ if (attNames && attNames.length) {
+ var menuitem;
+
+ for (var i = 0; i < attNames.length; i++) {
+ var name = attNames[i];
+
+ if (name == "_core") {
+ // Signal to append the common 'core' attributes.
+ for (var j = 0; j < gCoreHTMLAttr.length; j++) {
+ name = gCoreHTMLAttr[j];
+
+ // only filtering rule used for core attributes as of 8-20-01
+ // Add more rules if necessary.
+ if (name.includes("^")) {
+ name = name.replace(/\^/g, "");
+ menuitem = gDialog.AddHTMLAttributeNameInput.appendItem(name, name);
+ menuitem.setAttribute("limitFirstChar", "true");
+ } else {
+ gDialog.AddHTMLAttributeNameInput.appendItem(name, name);
+ }
+ }
+ } else if (name == "-") {
+ // Signal for separator
+ var popup = gDialog.AddHTMLAttributeNameInput.menupopup;
+ if (popup) {
+ var sep = document.createXULElement("menuseparator");
+ if (sep) {
+ popup.appendChild(sep);
+ }
+ }
+ } else {
+ // Get information about value filtering
+ let forceOneChar = name.includes("!");
+ let forceInteger = name.includes("#");
+ let forceSignedInteger = name.includes("+");
+ let forceIntOrPercent = name.includes("%");
+ let limitFirstChar = name.includes("^");
+ // let required = name.includes("$");
+
+ // Strip flag characters
+ name = name.replace(/[!^#%$+]/g, "");
+
+ menuitem = gDialog.AddHTMLAttributeNameInput.appendItem(name, name);
+ if (menuitem) {
+ // Signify "required" attributes by special style
+ // TODO: Don't do this until next version, when we add
+ // explanatory text and an 'Autofill Required Attributes' button
+ // if (required)
+ // menuitem.setAttribute("class", "menuitem-highlight-1");
+
+ // Set flags to filter value input
+ if (forceOneChar) {
+ menuitem.setAttribute("forceOneChar", "true");
+ }
+ if (limitFirstChar) {
+ menuitem.setAttribute("limitFirstChar", "true");
+ }
+ if (forceInteger) {
+ menuitem.setAttribute("forceInteger", "true");
+ }
+ if (forceSignedInteger) {
+ menuitem.setAttribute("forceSignedInteger", "true");
+ }
+ if (forceIntOrPercent) {
+ menuitem.setAttribute("forceIntOrPercent", "true");
+ }
+ }
+ }
+ }
+ }
+}
+
+// build attribute list in tree form from element attributes
+function BuildHTMLAttributeTable() {
+ var nodeMap = gElement.attributes;
+ var i;
+ if (nodeMap.length > 0) {
+ var added = false;
+ for (i = 0; i < nodeMap.length; i++) {
+ let name = nodeMap[i].name.trim().toLowerCase();
+ if (
+ CheckAttributeNameSimilarity(nodeMap[i].nodeName, HTMLAttrs) ||
+ name.startsWith("on") ||
+ name == "style"
+ ) {
+ continue; // repeated or non-HTML attribute, ignore this one and go to next
+ }
+ if (
+ !name.startsWith("_moz") &&
+ AddTreeItem(name, nodeMap[i].value, "HTMLAList", HTMLAttrs)
+ ) {
+ added = true;
+ }
+ }
+
+ if (added) {
+ SelectHTMLTree(0);
+ }
+ }
+}
+
+function ClearHTMLInputWidgets() {
+ gDialog.AddHTMLAttributeTree.view.selection.clearSelection();
+ gDialog.AddHTMLAttributeNameInput.value = "";
+ gDialog.AddHTMLAttributeValueInput.value = "";
+ SetTextboxFocus(gDialog.AddHTMLAttributeNameInput);
+}
+
+function onSelectHTMLTreeItem() {
+ if (!gDoOnSelectTree) {
+ return;
+ }
+
+ var tree = gDialog.AddHTMLAttributeTree;
+ if (tree && tree.view.selection.count) {
+ var inputName = TrimString(
+ gDialog.AddHTMLAttributeNameInput.value
+ ).toLowerCase();
+ var selectedItem = getSelectedItem(tree);
+ var selectedName = selectedItem.firstChild.firstChild.getAttribute("label");
+
+ if (inputName == selectedName) {
+ // Already editing selected name - just update the value input
+ gDialog.AddHTMLAttributeValueInput.value = GetTreeItemValueStr(
+ selectedItem
+ );
+ } else {
+ gDialog.AddHTMLAttributeNameInput.value = selectedName;
+
+ // Change value input based on new selected name
+ onInputHTMLAttributeName();
+ }
+ }
+}
+
+function onInputHTMLAttributeName() {
+ let attName = gDialog.AddHTMLAttributeNameInput.value.toLowerCase().trim();
+
+ // Clear value widget, but prevent triggering update in tree
+ gUpdateTreeValue = false;
+ gDialog.AddHTMLAttributeValueInput.value = "";
+ gUpdateTreeValue = true;
+
+ if (attName) {
+ // Get value list for current attribute name
+ var valueListName;
+
+ // Most elements have the "dir" attribute,
+ // so we have just one array for the allowed values instead
+ // requiring duplicate entries for each element in EdAEAttributes.js
+ if (attName == "dir") {
+ valueListName = "all_dir";
+ } else {
+ valueListName = gElement.localName + "_" + attName;
+ }
+
+ // Strip off leading "_" we sometimes use (when element name is reserved word)
+ if (valueListName.startsWith("_")) {
+ valueListName = valueListName.slice(1);
+ }
+
+ var newValue = "";
+ var listLen = 0;
+
+ // Index to which widget we were using to edit the value
+ var deckIndex = gDialog.AddHTMLAttributeValueDeck.getAttribute(
+ "selectedIndex"
+ );
+
+ if (valueListName in gHTMLAttr) {
+ var valueList = gHTMLAttr[valueListName];
+
+ listLen = valueList.length;
+ if (listLen == 1) {
+ newValue = valueList[0];
+ }
+
+ // Note: For case where "value list" is actually just
+ // one (default) item, don't use menulist for that
+ if (listLen > 1) {
+ gDialog.AddHTMLAttributeValueMenulist.removeAllItems();
+
+ if (deckIndex != "1") {
+ // Switch to using editable menulist
+ gDialog.AddHTMLAttributeValueInput =
+ gDialog.AddHTMLAttributeValueMenulist;
+ gDialog.AddHTMLAttributeValueDeck.setAttribute("selectedIndex", "1");
+ }
+ // Rebuild the list
+ for (var i = 0; i < listLen; i++) {
+ if (valueList[i] == "-") {
+ // Signal for separator
+ var popup = gDialog.AddHTMLAttributeValueInput.menupopup;
+ if (popup) {
+ var sep = document.createXULElement("menuseparator");
+ if (sep) {
+ popup.appendChild(sep);
+ }
+ }
+ } else {
+ gDialog.AddHTMLAttributeValueMenulist.appendItem(
+ valueList[i],
+ valueList[i]
+ );
+ }
+ }
+ }
+ }
+
+ if (listLen <= 1 && deckIndex != "0") {
+ // No list: Use textbox for input instead
+ gDialog.AddHTMLAttributeValueInput = gDialog.AddHTMLAttributeValueTextbox;
+ gDialog.AddHTMLAttributeValueDeck.setAttribute("selectedIndex", "0");
+ }
+
+ // If attribute already exists in tree, use associated value,
+ // else use default found above
+ var existingValue = GetAndSelectExistingAttributeValue(
+ attName,
+ "HTMLAList"
+ );
+ if (existingValue) {
+ newValue = existingValue;
+ }
+
+ gDialog.AddHTMLAttributeValueInput.value = newValue;
+
+ if (!existingValue) {
+ onInputHTMLAttributeValue();
+ }
+ }
+}
+
+function onInputHTMLAttributeValue() {
+ if (!gUpdateTreeValue) {
+ return;
+ }
+
+ var name = TrimString(gDialog.AddHTMLAttributeNameInput.value);
+ if (!name) {
+ return;
+ }
+
+ // Trim spaces only from left since we must allow spaces within the string
+ // (we always reset the input field's value below)
+ var value = TrimStringLeft(gDialog.AddHTMLAttributeValueInput.value);
+ if (value) {
+ // Do value filtering based on type of attribute
+ // (Do not use "forceInteger()" to avoid multiple
+ // resetting of input's value and flickering)
+ var selectedItem = gDialog.AddHTMLAttributeNameInput.selectedItem;
+
+ if (selectedItem) {
+ if (
+ selectedItem.getAttribute("forceOneChar") == "true" &&
+ value.length > 1
+ ) {
+ value = value.slice(0, 1);
+ }
+
+ if (selectedItem.getAttribute("forceIntOrPercent") == "true") {
+ // Allow integer with optional "%" as last character
+ var percent = TrimStringRight(value).slice(-1);
+ value = value.replace(/\D+/g, "");
+ if (percent == "%") {
+ value += percent;
+ }
+ } else if (selectedItem.getAttribute("forceInteger") == "true") {
+ value = value.replace(/\D+/g, "");
+ } else if (selectedItem.getAttribute("forceSignedInteger") == "true") {
+ // Allow integer with optional "+" or "-" as first character
+ var sign = value[0];
+ value = value.replace(/\D+/g, "");
+ if (sign == "+" || sign == "-") {
+ value = sign + value;
+ }
+ }
+
+ // Special case attributes
+ if (selectedItem.getAttribute("limitFirstChar") == "true") {
+ // Limit first character to letter, and all others to
+ // letters, numbers, and a few others
+ value = value
+ .replace(/^[^a-zA-Z\u0080-\uFFFF]/, "")
+ .replace(/[^a-zA-Z0-9_\.\-\:\u0080-\uFFFF]+/g, "");
+ }
+
+ // Update once only if it changed
+ if (value != gDialog.AddHTMLAttributeValueInput.value) {
+ gDialog.AddHTMLAttributeValueInput.value = value;
+ }
+ }
+ }
+
+ // Update value in the tree list
+ // If not found, add new attribute
+ if (!UpdateExistingAttribute(name, value, "HTMLAList") && value) {
+ AddTreeItem(name, value, "HTMLAList", HTMLAttrs);
+ }
+}
+
+function editHTMLAttributeValue(targetCell) {
+ if (IsNotTreeHeader(targetCell)) {
+ gDialog.AddHTMLAttributeValueInput.select();
+ }
+}
+
+// update the object with added and removed attributes
+function UpdateHTMLAttributes() {
+ var HTMLAList = document.getElementById("HTMLAList");
+ var i;
+
+ // remove removed attributes
+ for (i = 0; i < HTMLRAttrs.length; i++) {
+ var name = HTMLRAttrs[i];
+
+ if (gElement.hasAttribute(name)) {
+ doRemoveAttribute(name);
+ }
+ }
+
+ // Set added or changed attributes
+ for (i = 0; i < HTMLAList.childNodes.length; i++) {
+ var item = HTMLAList.childNodes[i];
+ doSetAttribute(GetTreeItemAttributeStr(item), GetTreeItemValueStr(item));
+ }
+}
+
+function RemoveHTMLAttribute() {
+ // We only allow 1 selected item
+ if (gDialog.AddHTMLAttributeTree.view.selection.count) {
+ var item = getSelectedItem(gDialog.AddHTMLAttributeTree);
+ var attr = GetTreeItemAttributeStr(item);
+
+ // remove the item from the attribute array
+ HTMLRAttrs[HTMLRAttrs.length] = attr;
+ RemoveNameFromAttArray(attr, HTMLAttrs);
+
+ // Remove the item from the tree
+ item.remove();
+
+ // Clear inputs and selected item in tree
+ ClearHTMLInputWidgets();
+ }
+}
+
+function SelectHTMLTree(index) {
+ gDoOnSelectTree = false;
+ try {
+ gDialog.AddHTMLAttributeTree.selectedIndex = index;
+ } catch (e) {}
+ gDoOnSelectTree = true;
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdAEJSEAttributes.js b/comm/suite/editor/components/dialogs/content/EdAEJSEAttributes.js
new file mode 100644
index 0000000000..c15c938b3e
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdAEJSEAttributes.js
@@ -0,0 +1,200 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdAdvancedEdit.js */
+/* import-globals-from EdDialogCommon.js */
+
+function BuildJSEAttributeNameList() {
+ gDialog.AddJSEAttributeNameList.removeAllItems();
+
+ // Get events specific to current element
+ var elementName = gElement.localName;
+ if (elementName in gJSAttr) {
+ var attNames = gJSAttr[elementName];
+ var i;
+ var popup;
+ var sep;
+
+ if (attNames && attNames.length) {
+ // Since we don't allow user-editable JS events yet (but we will soon)
+ // simply remove the JS tab to not allow adding JS events
+ if (attNames[0] == "noJSEvents") {
+ var tab = document.getElementById("tabJSE");
+ if (tab) {
+ tab.remove();
+ }
+
+ return;
+ }
+
+ for (i = 0; i < attNames.length; i++) {
+ gDialog.AddJSEAttributeNameList.appendItem(attNames[i], attNames[i]);
+ }
+
+ popup = gDialog.AddJSEAttributeNameList.firstChild;
+ if (popup) {
+ sep = document.createXULElement("menuseparator");
+ if (sep) {
+ popup.appendChild(sep);
+ }
+ }
+ }
+ }
+
+ // Always add core JS events unless we aborted above
+ for (i = 0; i < gCoreJSEvents.length; i++) {
+ if (gCoreJSEvents[i] == "-") {
+ if (!popup) {
+ popup = gDialog.AddJSEAttributeNameList.firstChild;
+ }
+
+ sep = document.createXULElement("menuseparator");
+
+ if (popup && sep) {
+ popup.appendChild(sep);
+ }
+ } else {
+ gDialog.AddJSEAttributeNameList.appendItem(
+ gCoreJSEvents[i],
+ gCoreJSEvents[i]
+ );
+ }
+ }
+
+ gDialog.AddJSEAttributeNameList.selectedIndex = 0;
+
+ // Use current name and value of first tree item if it exists
+ onSelectJSETreeItem();
+}
+
+// build attribute list in tree form from element attributes
+function BuildJSEAttributeTable() {
+ var nodeMap = gElement.attributes;
+ if (nodeMap.length > 0) {
+ var added = false;
+ for (var i = 0; i < nodeMap.length; i++) {
+ let name = nodeMap[i].nodeName.toLowerCase();
+ if (CheckAttributeNameSimilarity(nodeMap[i].nodeName, JSEAttrs)) {
+ // Repeated or non-JS handler, ignore this one and go to next.
+ continue;
+ }
+ if (!name.startsWith("on")) {
+ // Attribute isn't an event handler.
+ continue;
+ }
+ var value = gElement.getAttribute(nodeMap[i].nodeName);
+ if (AddTreeItem(name, value, "JSEAList", JSEAttrs)) {
+ // add item to tree
+ added = true;
+ }
+ }
+
+ // Select first item
+ if (added) {
+ gDialog.AddJSEAttributeTree.selectedIndex = 0;
+ }
+ }
+}
+
+function onSelectJSEAttribute() {
+ if (!gDoOnSelectTree) {
+ return;
+ }
+
+ gDialog.AddJSEAttributeValueInput.value = GetAndSelectExistingAttributeValue(
+ gDialog.AddJSEAttributeNameList.label,
+ "JSEAList"
+ );
+}
+
+function onSelectJSETreeItem() {
+ var tree = gDialog.AddJSEAttributeTree;
+ if (tree && tree.view.selection.count) {
+ // Select attribute name in list
+ gDialog.AddJSEAttributeNameList.value = GetTreeItemAttributeStr(
+ getSelectedItem(tree)
+ );
+
+ // Set value input to that in tree (no need to update this in the tree)
+ gUpdateTreeValue = false;
+ gDialog.AddJSEAttributeValueInput.value = GetTreeItemValueStr(
+ getSelectedItem(tree)
+ );
+ gUpdateTreeValue = true;
+ }
+}
+
+function onInputJSEAttributeValue() {
+ if (gUpdateTreeValue) {
+ var name = TrimString(gDialog.AddJSEAttributeNameList.label);
+ var value = TrimString(gDialog.AddJSEAttributeValueInput.value);
+
+ // Update value in the tree list
+ // Since we have a non-editable menulist,
+ // we MUST automatically add the event attribute if it doesn't exist
+ if (!UpdateExistingAttribute(name, value, "JSEAList") && value) {
+ AddTreeItem(name, value, "JSEAList", JSEAttrs);
+ }
+ }
+}
+
+function editJSEAttributeValue(targetCell) {
+ if (IsNotTreeHeader(targetCell)) {
+ gDialog.AddJSEAttributeValueInput.inputField.select();
+ }
+}
+
+function UpdateJSEAttributes() {
+ var JSEAList = document.getElementById("JSEAList");
+ var i;
+
+ // remove removed attributes
+ for (i = 0; i < JSERAttrs.length; i++) {
+ var name = JSERAttrs[i];
+
+ if (gElement.hasAttribute(name)) {
+ doRemoveAttribute(name);
+ }
+ }
+
+ // Add events
+ for (i = 0; i < JSEAList.childNodes.length; i++) {
+ var item = JSEAList.childNodes[i];
+
+ // set the event handler
+ doSetAttribute(GetTreeItemAttributeStr(item), GetTreeItemValueStr(item));
+ }
+}
+
+function RemoveJSEAttribute() {
+ // This differs from HTML and CSS panels:
+ // We reselect after removing, because there is not
+ // editable attribute name input, so we can't clear that
+ // like we do in other panels
+ var newIndex = gDialog.AddJSEAttributeTree.selectedIndex;
+
+ // We only allow 1 selected item
+ if (gDialog.AddJSEAttributeTree.view.selection.count) {
+ var item = getSelectedItem(gDialog.AddJSEAttributeTree);
+
+ // Name is the text of the treecell
+ var attr = GetTreeItemAttributeStr(item);
+
+ // remove the item from the attribute array
+ if (newIndex >= JSEAttrs.length - 1) {
+ newIndex--;
+ }
+
+ // remove the item from the attribute array
+ JSERAttrs[JSERAttrs.length] = attr;
+ RemoveNameFromAttArray(attr, JSEAttrs);
+
+ // Remove the item from the tree
+ item.remove();
+
+ // Reselect an item
+ gDialog.AddJSEAttributeTree.selectedIndex = newIndex;
+ }
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdAdvancedEdit.js b/comm/suite/editor/components/dialogs/content/EdAdvancedEdit.js
new file mode 100644
index 0000000000..60e9009905
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdAdvancedEdit.js
@@ -0,0 +1,342 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdAEAttributes.js */
+/* import-globals-from EdAECSSAttributes.js */
+/* import-globals-from EdAEHTMLAttributes.js */
+/* import-globals-from EdAEJSEAttributes.js */
+/* import-globals-from EdDialogCommon.js */
+
+/** ************ GLOBALS **************/
+var gElement = null; // handle to actual element edited
+
+var HTMLAttrs = []; // html attributes
+var CSSAttrs = []; // css attributes
+var JSEAttrs = []; // js events
+
+var HTMLRAttrs = []; // removed html attributes
+var JSERAttrs = []; // removed js events
+
+/* Set false to allow changing selection in tree
+ without doing "onselect" handler actions
+*/
+var gDoOnSelectTree = true;
+var gUpdateTreeValue = true;
+
+/** ************ INITIALISATION && SETUP **************/
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+/**
+ * function : void Startup();
+ * parameters : none
+ * returns : none
+ * desc. : startup and initialisation, prepares dialog.
+ **/
+function Startup() {
+ var editor = GetCurrentEditor();
+
+ // Element to edit is passed in
+ if (!editor || !window.arguments[1]) {
+ dump("Advanced Edit: No editor or element to edit not supplied\n");
+ window.close();
+ return;
+ }
+ // This is the return value for the parent,
+ // who only needs to know if OK was clicked
+ window.opener.AdvancedEditOK = false;
+
+ // The actual element edited (not a copy!)
+ gElement = window.arguments[1];
+
+ // place the tag name in the header
+ var tagLabel = document.getElementById("tagLabel");
+ tagLabel.setAttribute("value", "<" + gElement.localName + ">");
+
+ // Create dialog object to store controls for easy access
+ gDialog.AddHTMLAttributeNameInput = document.getElementById(
+ "AddHTMLAttributeNameInput"
+ );
+
+ // We use a <deck> to switch between editable menulist and textbox
+ gDialog.AddHTMLAttributeValueDeck = document.getElementById(
+ "AddHTMLAttributeValueDeck"
+ );
+ gDialog.AddHTMLAttributeValueMenulist = document.getElementById(
+ "AddHTMLAttributeValueMenulist"
+ );
+ gDialog.AddHTMLAttributeValueTextbox = document.getElementById(
+ "AddHTMLAttributeValueTextbox"
+ );
+ gDialog.AddHTMLAttributeValueInput = gDialog.AddHTMLAttributeValueTextbox;
+
+ gDialog.AddHTMLAttributeTree = document.getElementById("HTMLATree");
+ gDialog.AddCSSAttributeNameInput = document.getElementById(
+ "AddCSSAttributeNameInput"
+ );
+ gDialog.AddCSSAttributeValueInput = document.getElementById(
+ "AddCSSAttributeValueInput"
+ );
+ gDialog.AddCSSAttributeTree = document.getElementById("CSSATree");
+ gDialog.AddJSEAttributeNameList = document.getElementById(
+ "AddJSEAttributeNameList"
+ );
+ gDialog.AddJSEAttributeValueInput = document.getElementById(
+ "AddJSEAttributeValueInput"
+ );
+ gDialog.AddJSEAttributeTree = document.getElementById("JSEATree");
+ gDialog.okButton = document.documentElement.getButton("accept");
+
+ // build the attribute trees
+ BuildHTMLAttributeTable();
+ BuildCSSAttributeTable();
+ BuildJSEAttributeTable();
+
+ // Build attribute name arrays for menulists
+ BuildJSEAttributeNameList();
+ BuildHTMLAttributeNameList();
+ // No menulists for CSS panel (yet)
+
+ // Set focus to Name editable menulist in HTML panel
+ SetTextboxFocus(gDialog.AddHTMLAttributeNameInput);
+
+ // size the dialog properly
+ window.sizeToContent();
+
+ SetWindowLocation();
+}
+
+/**
+ * function : bool onAccept ( void );
+ * parameters : none
+ * returns : boolean true to close the window
+ * desc. : event handler for ok button
+ **/
+function onAccept() {
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+ try {
+ // Update our gElement attributes
+ UpdateHTMLAttributes();
+ UpdateCSSAttributes();
+ UpdateJSEAttributes();
+ } catch (ex) {
+ dump(ex);
+ }
+ editor.endTransaction();
+
+ window.opener.AdvancedEditOK = true;
+ SaveWindowLocation();
+}
+
+// Helpers for removing and setting attributes
+// Use editor transactions if modifying the element already in the document
+// (Temporary element from a property dialog won't have a parent node)
+function doRemoveAttribute(attrib) {
+ try {
+ var editor = GetCurrentEditor();
+ if (gElement.parentNode) {
+ editor.removeAttribute(gElement, attrib);
+ } else {
+ gElement.removeAttribute(attrib);
+ }
+ } catch (ex) {}
+}
+
+function doSetAttribute(attrib, value) {
+ try {
+ var editor = GetCurrentEditor();
+ if (gElement.parentNode) {
+ editor.setAttribute(gElement, attrib, value);
+ } else {
+ gElement.setAttribute(attrib, value);
+ }
+ } catch (ex) {}
+}
+
+/**
+ * function : bool CheckAttributeNameSimilarity ( string attName, array attArray );
+ * parameters : attribute to look for, array of current attributes
+ * returns : true if attribute already exists, false if it does not
+ * desc. : checks to see if any other attributes by the same name as the arg supplied
+ * already exist.
+ **/
+function CheckAttributeNameSimilarity(attName, attArray) {
+ for (var i = 0; i < attArray.length; i++) {
+ if (attName.toLowerCase() == attArray[i].toLowerCase()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * function : bool UpdateExistingAttribute ( string attName, string attValue, string treeChildrenId );
+ * parameters : attribute to look for, new value, ID of <treeChildren> node in XUL tree
+ * returns : true if attribute already exists in tree, false if it does not
+ * desc. : checks to see if any other attributes by the same name as the arg supplied
+ * already exist while setting the associated value if different from current value
+ **/
+function UpdateExistingAttribute(attName, attValue, treeChildrenId) {
+ var treeChildren = document.getElementById(treeChildrenId);
+ if (!treeChildren) {
+ return false;
+ }
+
+ var name;
+ var i;
+ attName = TrimString(attName).toLowerCase();
+ attValue = TrimString(attValue);
+
+ for (i = 0; i < treeChildren.childNodes.length; i++) {
+ var item = treeChildren.childNodes[i];
+ name = GetTreeItemAttributeStr(item);
+ if (name.toLowerCase() == attName) {
+ // Set the text in the "value' column treecell
+ SetTreeItemValueStr(item, attValue);
+
+ // Select item just changed,
+ // but don't trigger the tree's onSelect handler
+ gDoOnSelectTree = false;
+ try {
+ selectTreeItem(treeChildren, item);
+ } catch (e) {}
+ gDoOnSelectTree = true;
+
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * function : string GetAndSelectExistingAttributeValue ( string attName, string treeChildrenId );
+ * parameters : attribute to look for, ID of <treeChildren> node in XUL tree
+ * returns : value in from the tree or empty string if name not found
+ **/
+function GetAndSelectExistingAttributeValue(attName, treeChildrenId) {
+ if (!attName) {
+ return "";
+ }
+
+ var treeChildren = document.getElementById(treeChildrenId);
+ var name;
+ var i;
+
+ for (i = 0; i < treeChildren.childNodes.length; i++) {
+ var item = treeChildren.childNodes[i];
+ name = GetTreeItemAttributeStr(item);
+ if (name.toLowerCase() == attName.toLowerCase()) {
+ // Select item in the tree
+ // but don't trigger the tree's onSelect handler
+ gDoOnSelectTree = false;
+ try {
+ selectTreeItem(treeChildren, item);
+ } catch (e) {}
+ gDoOnSelectTree = true;
+
+ // Get the text in the "value' column treecell
+ return GetTreeItemValueStr(item);
+ }
+ }
+
+ // Attribute doesn't exist in tree, so remove selection
+ gDoOnSelectTree = false;
+ try {
+ treeChildren.parentNode.view.selection.clearSelection();
+ } catch (e) {}
+ gDoOnSelectTree = true;
+
+ return "";
+}
+
+/* Tree structure:
+ <treeItem>
+ <treeRow>
+ <treeCell> // Name Cell
+ <treeCell // Value Cell
+*/
+function GetTreeItemAttributeStr(treeItem) {
+ if (treeItem) {
+ return TrimString(treeItem.firstChild.firstChild.getAttribute("label"));
+ }
+
+ return "";
+}
+
+function GetTreeItemValueStr(treeItem) {
+ if (treeItem) {
+ return TrimString(treeItem.firstChild.lastChild.getAttribute("label"));
+ }
+
+ return "";
+}
+
+function SetTreeItemValueStr(treeItem, value) {
+ if (treeItem && GetTreeItemValueStr(treeItem) != value) {
+ treeItem.firstChild.lastChild.setAttribute("label", value);
+ }
+}
+
+function IsNotTreeHeader(treeCell) {
+ if (treeCell) {
+ return treeCell.parentNode.parentNode.nodeName != "treehead";
+ }
+
+ return false;
+}
+
+function RemoveNameFromAttArray(attName, attArray) {
+ for (var i = 0; i < attArray.length; i++) {
+ if (attName.toLowerCase() == attArray[i].toLowerCase()) {
+ // Remove 1 array item
+ attArray.splice(i, 1);
+ break;
+ }
+ }
+}
+
+// adds a generalised treeitem.
+function AddTreeItem(name, value, treeChildrenId, attArray) {
+ attArray[attArray.length] = name;
+ var treeChildren = document.getElementById(treeChildrenId);
+ var treeitem = document.createXULElement("treeitem");
+ var treerow = document.createXULElement("treerow");
+
+ var attrCell = document.createXULElement("treecell");
+ attrCell.setAttribute("class", "propertylist");
+ attrCell.setAttribute("label", name);
+
+ var valueCell = document.createXULElement("treecell");
+ valueCell.setAttribute("class", "propertylist");
+ valueCell.setAttribute("label", value);
+
+ treerow.appendChild(attrCell);
+ treerow.appendChild(valueCell);
+ treeitem.appendChild(treerow);
+ treeChildren.appendChild(treeitem);
+
+ // Select item just added, but suppress calling the onSelect handler.
+ gDoOnSelectTree = false;
+ try {
+ selectTreeItem(treeChildren, treeitem);
+ } catch (e) {}
+ gDoOnSelectTree = true;
+
+ return treeitem;
+}
+
+function selectTreeItem(treeChildren, item) {
+ var index = treeChildren.parentNode.view.getIndexOfItem(item);
+ treeChildren.parentNode.view.selection.select(index);
+}
+
+function getSelectedItem(tree) {
+ if (tree.view.selection.count == 1) {
+ return tree.view.getItemAtIndex(tree.currentIndex);
+ }
+ return null;
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdAdvancedEdit.xhtml b/comm/suite/editor/components/dialogs/content/EdAdvancedEdit.xhtml
new file mode 100644
index 0000000000..94942709a1
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdAdvancedEdit.xhtml
@@ -0,0 +1,182 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!-- first checkin of the year 2000! -->
+<!-- Ben Goodger, 12:50AM, 01/00/00 NZST -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+<?xml-stylesheet href="chrome://messenger/skin/menulist.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EdAdvancedEdit.dtd">
+
+<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ id="advancedEditDlg"
+ style="width: 40em;"
+ title="&WindowTitle.label;"
+ onload="Startup()">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <!-- element page functions -->
+ <script src="chrome://editor/content/EdAEHTMLAttributes.js"/>
+ <script src="chrome://editor/content/EdAECSSAttributes.js"/>
+ <script src="chrome://editor/content/EdAEJSEAttributes.js"/>
+ <script src="chrome://editor/content/EdAEAttributes.js"/>
+
+ <!-- global dialog functions -->
+ <script src="chrome://editor/content/EdAdvancedEdit.js"/>
+
+ <script src="chrome://messenger/content/customElements.js"/>
+
+ <hbox>
+ <label value="&currentattributesfor.label;"/>
+ <label class="header" id="tagLabel"/>
+ </hbox>
+
+ <separator class="thin"/>
+
+ <tabbox flex="1">
+ <tabs>
+ <tab label="&tabHTML.label;"/>
+ <tab label="&tabCSS.label;"/>
+ <tab label="&tabJSE.label;" id="tabJSE"/>
+ </tabs>
+ <tabpanels flex="1">
+ <!-- ============================================================== -->
+ <!-- HTML Attributes -->
+ <!-- ============================================================== -->
+ <vbox>
+ <tree id="HTMLATree" class="AttributesTree" flex="1"
+ hidecolumnpicker="true" seltype="single"
+ onselect="onSelectHTMLTreeItem();"
+ onclick="onSelectHTMLTreeItem();"
+ ondblclick="editHTMLAttributeValue(event.target);">
+ <treecols>
+ <treecol id="HTMLAttrCol" flex="35" label="&tree.attributeHeader.label;"/>
+ <splitter class="tree-splitter"/>
+ <treecol id="HTMLValCol" flex="65" label="&tree.valueHeader.label;"/>
+ </treecols>
+ <treechildren id="HTMLAList" flex="1"/>
+ </tree>
+ <hbox align="center">
+ <label value="&editAttribute.label;"/>
+ <spacer flex="1"/>
+ <button label="&removeAttribute.label;" oncommand="RemoveHTMLAttribute();"/>
+ </hbox>
+ <grid>
+ <columns>
+ <column flex="1"/><column flex="1"/>
+ </columns>
+ <rows>
+ <row equalsize="always">
+ <label control="AddHTMLAttributeNameInput" value="&AttName.label;"/>
+ <label control="AddHTMLAttributeValueInput" value="&AttValue.label;"/>
+ </row>
+ <row align="top" equalsize="always">
+ <!-- Lists are built at runtime -->
+ <menulist is="menulist-editable" id="AddHTMLAttributeNameInput"
+ editable="true" flex="1"
+ oninput="onInputHTMLAttributeName();"
+ oncommand="onInputHTMLAttributeName();"/>
+ <deck id="AddHTMLAttributeValueDeck" selectedIndex="0">
+ <hbox align="top">
+ <textbox id="AddHTMLAttributeValueTextbox" flex="1"
+ oninput="onInputHTMLAttributeValue();"/>
+ </hbox>
+ <hbox align="top">
+ <menulist is="menulist-editable" id="AddHTMLAttributeValueMenulist"
+ editable="true" flex="1"
+ oninput="onInputHTMLAttributeValue();"
+ oncommand="onInputHTMLAttributeValue();"/>
+ </hbox>
+ </deck>
+ </row>
+ </rows>
+ </grid>
+ </vbox>
+ <!-- ============================================================== -->
+ <!-- CSS Attributes -->
+ <!-- ============================================================== -->
+ <vbox>
+ <tree id="CSSATree" class="AttributesTree" flex="1"
+ hidecolumnpicker="true" seltype="single"
+ onselect="onSelectCSSTreeItem();"
+ onclick="onSelectCSSTreeItem();"
+ ondblclick="editCSSAttributeValue(event.target);">
+ <treecols>
+ <treecol id="CSSPropCol" flex="35" label="&tree.propertyHeader.label;"/>
+ <splitter class="tree-splitter"/>
+ <treecol id="CSSValCol" flex="65" label="&tree.valueHeader.label;"/>
+ </treecols>
+ <treechildren id="CSSAList" flex="1"/>
+ </tree>
+ <hbox align="center">
+ <label value="&editAttribute.label;"/>
+ <spacer flex="1"/>
+ <button label="&removeAttribute.label;" oncommand="RemoveCSSAttribute();"/>
+ </hbox>
+ <grid>
+ <columns>
+ <column flex="1"/><column flex="1"/>
+ </columns>
+ <rows>
+ <row equalsize="always">
+ <label value="&PropertyName.label;"/>
+ <label value="&AttValue.label;"/>
+ </row>
+ <row align="top" equalsize="always">
+ <textbox id="AddCSSAttributeNameInput" flex="1"
+ oninput="onInputCSSAttributeName();"/>
+ <textbox id="AddCSSAttributeValueInput" flex="1"
+ oninput="onChangeCSSAttribute();"/>
+ </row>
+ </rows>
+ </grid>
+ </vbox>
+ <!-- ============================================================== -->
+ <!-- JavaScript Event Handlers -->
+ <!-- ============================================================== -->
+ <vbox>
+ <tree id="JSEATree" class="AttributesTree" flex="1"
+ hidecolumnpicker="true" seltype="single"
+ onselect="onSelectJSETreeItem();"
+ onclick="onSelectJSETreeItem();"
+ ondblclick="editJSEAttributeValue(event.target);">
+ <treecols>
+ <treecol id="AttrCol" flex="35" label="&tree.attributeHeader.label;"/>
+ <splitter class="tree-splitter"/>
+ <treecol id="HeaderCol" flex="65" label="&tree.valueHeader.label;"/>
+ </treecols>
+ <treechildren id="JSEAList" flex="1"/>
+ </tree>
+ <hbox align="center">
+ <label value="&editAttribute.label;"/>
+ <spacer flex="1"/>
+ <button label="&removeAttribute.label;" oncommand="RemoveJSEAttribute()"/>
+ </hbox>
+ <grid>
+ <columns>
+ <column flex="1"/><column flex="1"/>
+ </columns>
+ <rows>
+ <row equalsize="always">
+ <label value="&AttName.label;"/>
+ <label value="&AttValue.label;"/>
+ </row>
+ <row align="top" equalsize="always">
+ <!-- List is built at runtime -->
+ <menulist id="AddJSEAttributeNameList" flex="1"
+ oncommand="onSelectJSEAttribute();"/>
+ <textbox id="AddJSEAttributeValueInput" flex="1"
+ oninput="onInputJSEAttributeValue();"/>
+ </row>
+ </rows>
+ </grid>
+ </vbox>
+ </tabpanels>
+ </tabbox>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdButtonProps.js b/comm/suite/editor/components/dialogs/content/EdButtonProps.js
new file mode 100644
index 0000000000..1cd0ee7365
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdButtonProps.js
@@ -0,0 +1,146 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var insertNew;
+var buttonElement;
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ window.close();
+ return;
+ }
+
+ gDialog = {
+ buttonType: document.getElementById("ButtonType"),
+ buttonName: document.getElementById("ButtonName"),
+ buttonValue: document.getElementById("ButtonValue"),
+ buttonDisabled: document.getElementById("ButtonDisabled"),
+ buttonTabIndex: document.getElementById("ButtonTabIndex"),
+ buttonAccessKey: document.getElementById("ButtonAccessKey"),
+ MoreSection: document.getElementById("MoreSection"),
+ MoreFewerButton: document.getElementById("MoreFewerButton"),
+ RemoveButton: document.getElementById("RemoveButton"),
+ };
+
+ // Get a single selected button element
+ const kTagName = "button";
+ try {
+ buttonElement = editor.getSelectedElement(kTagName);
+ } catch (e) {}
+
+ if (buttonElement) {
+ // We found an element and don't need to insert one
+ insertNew = false;
+ } else {
+ insertNew = true;
+
+ // We don't have an element selected,
+ // so create one with default attributes
+ try {
+ buttonElement = editor.createElementWithDefaults(kTagName);
+ } catch (e) {}
+
+ if (!buttonElement) {
+ dump("Failed to get selected element or create a new one!\n");
+ window.close();
+ return;
+ }
+ // Hide button removing existing button
+ gDialog.RemoveButton.hidden = true;
+ }
+
+ // Make a copy to use for AdvancedEdit
+ globalElement = buttonElement.cloneNode(false);
+
+ InitDialog();
+
+ InitMoreFewer();
+
+ gDialog.buttonType.focus();
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ var type = globalElement.getAttribute("type");
+ var index = 0;
+ switch (type) {
+ case "button":
+ index = 2;
+ break;
+ case "reset":
+ index = 1;
+ break;
+ }
+ gDialog.buttonType.selectedIndex = index;
+ gDialog.buttonName.value = globalElement.getAttribute("name");
+ gDialog.buttonValue.value = globalElement.getAttribute("value");
+ gDialog.buttonDisabled.setAttribute(
+ "checked",
+ globalElement.hasAttribute("disabled")
+ );
+ gDialog.buttonTabIndex.value = globalElement.getAttribute("tabindex");
+ gDialog.buttonAccessKey.value = globalElement.getAttribute("accesskey");
+}
+
+function RemoveButton() {
+ RemoveContainer(buttonElement);
+ SaveWindowLocation();
+ window.close();
+}
+
+function ValidateData() {
+ var attributes = {
+ type: ["", "reset", "button"][gDialog.buttonType.selectedIndex],
+ name: gDialog.buttonName.value,
+ value: gDialog.buttonValue.value,
+ tabindex: gDialog.buttonTabIndex.value,
+ accesskey: gDialog.buttonAccessKey.value,
+ };
+ for (var a in attributes) {
+ if (attributes[a]) {
+ globalElement.setAttribute(a, attributes[a]);
+ } else {
+ globalElement.removeAttribute(a);
+ }
+ }
+ if (gDialog.buttonDisabled.checked) {
+ globalElement.setAttribute("disabled", "");
+ } else {
+ globalElement.removeAttribute("disabled");
+ }
+ return true;
+}
+
+function onAccept() {
+ // All values are valid - copy to actual element in doc or
+ // element created to insert
+ ValidateData();
+
+ var editor = GetCurrentEditor();
+
+ editor.cloneAttributes(buttonElement, globalElement);
+
+ if (insertNew) {
+ if (!InsertElementAroundSelection(buttonElement)) {
+ /* eslint-disable-next-line no-unsanitized/property */
+ buttonElement.innerHTML = editor.outputToString(
+ "text/html",
+ kOutputSelectionOnly
+ );
+ editor.insertElementAtSelection(buttonElement, true);
+ }
+ }
+
+ SaveWindowLocation();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdButtonProps.xhtml b/comm/suite/editor/components/dialogs/content/EdButtonProps.xhtml
new file mode 100644
index 0000000000..70e4774f13
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdButtonProps.xhtml
@@ -0,0 +1,92 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edButtonProperties SYSTEM "chrome://editor/locale/EditorButtonProperties.dtd">
+%edButtonProperties;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup();"
+ buttons="accept,cancel">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdButtonProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&Settings.label;</label>
+ </hbox>
+ <grid><columns><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <label control="ButtonType" value="&ButtonType.label;" accesskey="&ButtonType.accesskey;"/>
+ <menulist id="ButtonType">
+ <menupopup>
+ <menuitem label="&submit.value;"/>
+ <menuitem label="&reset.value;"/>
+ <menuitem label="&button.value;"/>
+ </menupopup>
+ </menulist>
+ </row>
+ <row align="center">
+ <label control="ButtonName" value="&ButtonName.label;" accesskey="&ButtonName.accesskey;"/>
+ <textbox id="ButtonName"/>
+ </row>
+ <row align="center">
+ <label control="ButtonValue" value="&ButtonValue.label;" accesskey="&ButtonValue.accesskey;"/>
+ <textbox id="ButtonValue"/>
+ </row>
+ </rows>
+ </grid>
+ <hbox>
+ <button id="MoreFewerButton" oncommand="onMoreFewer();" persist="more"/>
+ </hbox>
+ <grid id="MoreSection"><columns><column/><column/></columns>
+ <rows>
+ <row>
+ <spacer/>
+ <checkbox id="ButtonDisabled" label="&ButtonDisabled.label;" accesskey="&ButtonDisabled.accesskey;"/>
+ </row>
+ <row align="center">
+ <label control="ButtonTabIndex" value="&tabIndex.label;" accesskey="&tabIndex.accesskey;"/>
+ <hbox>
+ <textbox id="ButtonTabIndex" class="narrow" oninput="forceInteger(this.id);"/>
+ </hbox>
+ </row>
+ <row align="center">
+ <label control="ButtonAccessKey" value="&AccessKey.label;" accesskey="&AccessKey.accesskey;"/>
+ <hbox>
+ <textbox id="ButtonAccessKey" class="narrow"/>
+ </hbox>
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+
+ <!-- from EdDialogOverlay -->
+ <hbox flex="1" style="margin-top: 0.2em">
+ <button id="RemoveButton" label="&RemoveButton.label;" accesskey="&RemoveButton.accesskey;" oncommand="RemoveButton();"/>
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton"
+ oncommand="onAdvancedEdit();"
+ label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;"
+ tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator class="groove"/>
+
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdColorPicker.js b/comm/suite/editor/components/dialogs/content/EdColorPicker.js
new file mode 100644
index 0000000000..95ce279368
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdColorPicker.js
@@ -0,0 +1,297 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+// Cancel() is in EdDialogCommon.js
+
+var insertNew = true;
+var tagname = "TAG NAME";
+var gColor = "";
+var LastPickedColor = "";
+var ColorType = "Text";
+var TextType = false;
+var HighlightType = false;
+var TableOrCell = false;
+var LastPickedIsDefault = true;
+var NoDefault = false;
+var gColorObj;
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancelColor);
+
+function Startup() {
+ if (!window.arguments[1]) {
+ dump("EdColorPicker: Missing color object param\n");
+ return;
+ }
+
+ // window.arguments[1] is object to get initial values and return color data
+ gColorObj = window.arguments[1];
+ gColorObj.Cancel = false;
+
+ gDialog.ColorPicker = document.getElementById("ColorPicker");
+ gDialog.ColorInput = document.getElementById("ColorInput");
+ gDialog.LastPickedButton = document.getElementById("LastPickedButton");
+ gDialog.LastPickedColor = document.getElementById("LastPickedColor");
+ gDialog.CellOrTableGroup = document.getElementById("CellOrTableGroup");
+ gDialog.TableRadio = document.getElementById("TableRadio");
+ gDialog.CellRadio = document.getElementById("CellRadio");
+ gDialog.ColorSwatch = document.getElementById("ColorPickerSwatch");
+ gDialog.Ok = document.documentElement.getButton("accept");
+
+ // The type of color we are setting:
+ // text: Text, Link, ActiveLink, VisitedLink,
+ // or background: Page, Table, or Cell
+ if (gColorObj.Type) {
+ ColorType = gColorObj.Type;
+ // Get string for dialog title from passed-in type
+ // (note constraint on editor.properties string name)
+ let IsCSSPrefChecked = Services.prefs.getBoolPref("editor.use_css");
+
+ if (GetCurrentEditor()) {
+ if (ColorType == "Page" && IsCSSPrefChecked && IsHTMLEditor()) {
+ document.title = GetString("BlockColor");
+ } else {
+ document.title = GetString(ColorType + "Color");
+ }
+ }
+ }
+
+ gDialog.ColorInput.value = "";
+ var tmpColor;
+ var haveTableRadio = false;
+
+ switch (ColorType) {
+ case "Page":
+ tmpColor = gColorObj.PageColor;
+ if (tmpColor && tmpColor.toLowerCase() != "window") {
+ gColor = tmpColor;
+ }
+ break;
+ case "Table":
+ if (gColorObj.TableColor) {
+ gColor = gColorObj.TableColor;
+ }
+ break;
+ case "Cell":
+ if (gColorObj.CellColor) {
+ gColor = gColorObj.CellColor;
+ }
+ break;
+ case "TableOrCell":
+ TableOrCell = true;
+ document.getElementById("TableOrCellGroup").collapsed = false;
+ haveTableRadio = true;
+ if (gColorObj.SelectedType == "Cell") {
+ gColor = gColorObj.CellColor;
+ gDialog.CellOrTableGroup.selectedItem = gDialog.CellRadio;
+ gDialog.CellRadio.focus();
+ } else {
+ gColor = gColorObj.TableColor;
+ gDialog.CellOrTableGroup.selectedItem = gDialog.TableRadio;
+ gDialog.TableRadio.focus();
+ }
+ break;
+ case "Highlight":
+ HighlightType = true;
+ if (gColorObj.HighlightColor) {
+ gColor = gColorObj.HighlightColor;
+ }
+ break;
+ default:
+ // Any other type will change some kind of text,
+ TextType = true;
+ tmpColor = gColorObj.TextColor;
+ if (tmpColor && tmpColor.toLowerCase() != "windowtext") {
+ gColor = gColorObj.TextColor;
+ }
+ break;
+ }
+
+ // Set initial color in input field and in the colorpicker
+ SetCurrentColor(gColor);
+ gDialog.ColorPicker.value = gColor;
+
+ // Use last-picked colors passed in, or those persistent on dialog
+ if (TextType) {
+ if (!("LastTextColor" in gColorObj) || !gColorObj.LastTextColor) {
+ gColorObj.LastTextColor = gDialog.LastPickedColor.getAttribute(
+ "LastTextColor"
+ );
+ }
+ LastPickedColor = gColorObj.LastTextColor;
+ } else if (HighlightType) {
+ if (!("LastHighlightColor" in gColorObj) || !gColorObj.LastHighlightColor) {
+ gColorObj.LastHighlightColor = gDialog.LastPickedColor.getAttribute(
+ "LastHighlightColor"
+ );
+ }
+ LastPickedColor = gColorObj.LastHighlightColor;
+ } else {
+ if (
+ !("LastBackgroundColor" in gColorObj) ||
+ !gColorObj.LastBackgroundColor
+ ) {
+ gColorObj.LastBackgroundColor = gDialog.LastPickedColor.getAttribute(
+ "LastBackgroundColor"
+ );
+ }
+ LastPickedColor = gColorObj.LastBackgroundColor;
+ }
+
+ // Set method to detect clicking on OK button
+ // so we don't get fooled by changing "default" behavior
+ gDialog.Ok.setAttribute("onclick", "SetDefaultToOk()");
+
+ if (!LastPickedColor) {
+ // Hide the button, as there is no last color available.
+ gDialog.LastPickedButton.hidden = true;
+ } else {
+ gDialog.LastPickedColor.setAttribute(
+ "style",
+ "background-color: " + LastPickedColor
+ );
+
+ // Make "Last-picked" the default button, until the user selects a color.
+ gDialog.Ok.removeAttribute("default");
+ gDialog.LastPickedButton.setAttribute("default", "true");
+ }
+
+ // Caller can prevent user from submitting an empty, i.e., default color
+ NoDefault = gColorObj.NoDefault;
+ if (NoDefault) {
+ // Hide the "Default button -- user must pick a color
+ document.getElementById("DefaultColorButton").collapsed = true;
+ }
+
+ // Set focus to colorpicker if not set to table radio buttons above
+ if (!haveTableRadio) {
+ gDialog.ColorPicker.focus();
+ }
+
+ SetWindowLocation();
+}
+
+function SelectColor() {
+ var color = gDialog.ColorPicker.value;
+ if (color) {
+ SetCurrentColor(color);
+ }
+}
+
+function RemoveColor() {
+ SetCurrentColor("");
+ gDialog.ColorInput.focus();
+ SetDefaultToOk();
+}
+
+function SelectColorByKeypress(aEvent) {
+ if (aEvent.charCode == aEvent.DOM_VK_SPACE) {
+ SelectColor();
+ SetDefaultToOk();
+ }
+}
+
+function SelectLastPickedColor() {
+ SetCurrentColor(LastPickedColor);
+ if (onAccept()) {
+ // window.close();
+ return true;
+ }
+
+ return false;
+}
+
+function SetCurrentColor(color) {
+ // TODO: Validate color?
+ if (!color) {
+ color = "";
+ }
+ gColor = TrimString(color).toLowerCase();
+ if (gColor == "mixed") {
+ gColor = "";
+ }
+ gDialog.ColorInput.value = gColor;
+ SetColorSwatch();
+}
+
+function SetColorSwatch() {
+ // TODO: DON'T ALLOW SPACES?
+ var color = TrimString(gDialog.ColorInput.value);
+ if (color) {
+ gDialog.ColorSwatch.setAttribute("style", "background-color:" + color);
+ gDialog.ColorSwatch.removeAttribute("default");
+ } else {
+ gDialog.ColorSwatch.setAttribute("style", "background-color:inherit");
+ gDialog.ColorSwatch.setAttribute("default", "true");
+ }
+}
+
+function SetDefaultToOk() {
+ gDialog.LastPickedButton.removeAttribute("default");
+ gDialog.Ok.setAttribute("default", "true");
+ LastPickedIsDefault = false;
+}
+
+function ValidateData() {
+ if (LastPickedIsDefault) {
+ gColor = LastPickedColor;
+ } else {
+ gColor = gDialog.ColorInput.value;
+ }
+
+ gColor = TrimString(gColor).toLowerCase();
+
+ // TODO: Validate the color string!
+
+ if (NoDefault && !gColor) {
+ ShowInputErrorMessage(GetString("NoColorError"));
+ SetTextboxFocus(gDialog.ColorInput);
+ return false;
+ }
+ return true;
+}
+
+function onAccept(event) {
+ if (!ValidateData()) {
+ event.preventDefault();
+ return;
+ }
+
+ // Set return values and save in persistent color attributes
+ if (TextType) {
+ gColorObj.TextColor = gColor;
+ if (gColor.length > 0) {
+ gDialog.LastPickedColor.setAttribute("LastTextColor", gColor);
+ gColorObj.LastTextColor = gColor;
+ }
+ } else if (HighlightType) {
+ gColorObj.HighlightColor = gColor;
+ if (gColor.length > 0) {
+ gDialog.LastPickedColor.setAttribute("LastHighlightColor", gColor);
+ gColorObj.LastHighlightColor = gColor;
+ }
+ } else {
+ gColorObj.BackgroundColor = gColor;
+ if (gColor.length > 0) {
+ gDialog.LastPickedColor.setAttribute("LastBackgroundColor", gColor);
+ gColorObj.LastBackgroundColor = gColor;
+ }
+ // If table or cell requested, tell caller which element to set on
+ if (TableOrCell && gDialog.TableRadio.selected) {
+ gColorObj.Type = "Table";
+ }
+ }
+ SaveWindowLocation();
+}
+
+function onCancelColor() {
+ // Tells caller that user canceled
+ gColorObj.Cancel = true;
+ SaveWindowLocation();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdColorPicker.xhtml b/comm/suite/editor/components/dialogs/content/EdColorPicker.xhtml
new file mode 100644
index 0000000000..c18bc90e62
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdColorPicker.xhtml
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EdColorPicker.dtd">
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()">
+
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdColorPicker.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <hbox id="TableOrCellGroup" align="center" collapsed="true">
+ <label control="CellOrTableGroup" value="&background.label;" accesskey="&background.accessKey;"/>
+ <radiogroup id="CellOrTableGroup" orient="horizontal">
+ <radio id="TableRadio" label="&table.label;" accesskey="&table.accessKey;"/>
+ <radio id="CellRadio" label="&cell.label;" accesskey="&cell.accessKey;"/>
+ </radiogroup>
+ </hbox>
+ <label value="&chooseColor1.label;"/>
+ <html:input type="color" id="ColorPicker"
+ onclick="SetDefaultToOk();"
+ ondblclick="if (onAccept()) { window.close(); }"
+ onkeypress="SelectColorByKeypress(event);"
+ onchange="SelectColor();"/>
+
+ <spacer class="spacer"/>
+ <vbox flex="1">
+ <button id="LastPickedButton" crop="right" oncommand="SelectLastPickedColor();">
+ <spacer id="LastPickedColor"
+ LastTextColor="" LastBackgroundColor=""
+ persist="LastTextColor LastBackgroundColor"/>
+ <label value="&lastPickedColor.label;" accesskey="&lastPickedColor.accessKey;" flex="1" style="text-align: center;"/>
+ </button>
+ <label value="&chooseColor2.label;" accesskey="&chooseColor2.accessKey;" control="ColorInput"/>
+ <label value="&setColorExample.label;"/>
+ <hbox align="center" flex="1=">
+ <textbox id="ColorInput" style="width: 8em" oninput="SetColorSwatch(); SetDefaultToOk();"/>
+ <spacer flex="1"/>
+ <spacer id="ColorPickerSwatch"/>
+ <spacer flex="1"/>
+ <button id="DefaultColorButton" label="&default.label;" accesskey="&default.accessKey;"
+ style="margin-right:0px;" oncommand="RemoveColor()"/>
+ </hbox>
+ </vbox>
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdColorProps.js b/comm/suite/editor/components/dialogs/content/EdColorProps.js
new file mode 100644
index 0000000000..62d3f29c9a
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdColorProps.js
@@ -0,0 +1,476 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ Behavior notes:
+ Radio buttons select "UseDefaultColors" vs. "UseCustomColors" modes.
+ If any color attribute is set in the body, mode is "Custom Colors",
+ even if 1 or more (but not all) are actually null (= "use default")
+ When in "Custom Colors" mode, all colors will be set on body tag,
+ even if they are just default colors, to assure compatible colors in page.
+ User cannot select "use default" for individual colors
+*/
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+// Cancel() is in EdDialogCommon.js
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+var gBodyElement;
+var prefs;
+var gBackgroundImage;
+
+// Initialize in case we can't get them from prefs???
+var defaultTextColor = "#000000";
+var defaultLinkColor = "#000099";
+var defaultActiveColor = "#000099";
+var defaultVisitedColor = "#990099";
+var defaultBackgroundColor = "#FFFFFF";
+const styleStr = "style";
+const textStr = "text";
+const linkStr = "link";
+const vlinkStr = "vlink";
+const alinkStr = "alink";
+const bgcolorStr = "bgcolor";
+const backgroundStr = "background";
+const cssColorStr = "color";
+const cssBackgroundColorStr = "background-color";
+const cssBackgroundImageStr = "background-image";
+const colorStyle = cssColorStr + ": ";
+const backColorStyle = cssBackgroundColorStr + ": ";
+const backImageStyle = "; " + cssBackgroundImageStr + ": url(";
+
+var customTextColor;
+var customLinkColor;
+var customActiveColor;
+var customVisitedColor;
+var customBackgroundColor;
+var previewBGColor;
+
+// dialog initialization code
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ window.close();
+ return;
+ }
+
+ gDialog.ColorPreview = document.getElementById("ColorPreview");
+ gDialog.NormalText = document.getElementById("NormalText");
+ gDialog.LinkText = document.getElementById("LinkText");
+ gDialog.ActiveLinkText = document.getElementById("ActiveLinkText");
+ gDialog.VisitedLinkText = document.getElementById("VisitedLinkText");
+ gDialog.PageColorGroup = document.getElementById("PageColorGroup");
+ gDialog.DefaultColorsRadio = document.getElementById("DefaultColorsRadio");
+ gDialog.CustomColorsRadio = document.getElementById("CustomColorsRadio");
+ gDialog.BackgroundImageInput = document.getElementById(
+ "BackgroundImageInput"
+ );
+
+ try {
+ gBodyElement = editor.rootElement;
+ } catch (e) {}
+
+ if (!gBodyElement) {
+ dump("Failed to get BODY element!\n");
+ window.close();
+ }
+
+ // Set element we will edit
+ globalElement = gBodyElement.cloneNode(false);
+
+ // Initialize default colors from browser prefs
+ var browserColors = GetDefaultBrowserColors();
+ if (browserColors) {
+ // Use author's browser pref colors passed into dialog
+ defaultTextColor = browserColors.TextColor;
+ defaultLinkColor = browserColors.LinkColor;
+ defaultActiveColor = browserColors.ActiveLinkColor;
+ defaultVisitedColor = browserColors.VisitedLinkColor;
+ defaultBackgroundColor = browserColors.BackgroundColor;
+ }
+
+ // We only need to test for this once per dialog load
+ gHaveDocumentUrl = GetDocumentBaseUrl();
+
+ InitDialog();
+
+ gDialog.PageColorGroup.focus();
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ // Get image from document
+ gBackgroundImage = GetHTMLOrCSSStyleValue(
+ globalElement,
+ backgroundStr,
+ cssBackgroundImageStr
+ );
+ if (/url\((.*)\)/.test(gBackgroundImage)) {
+ gBackgroundImage = RegExp.$1;
+ }
+
+ if (gBackgroundImage) {
+ // Shorten data URIs for display.
+ shortenImageData(gBackgroundImage, gDialog.BackgroundImageInput);
+ gDialog.ColorPreview.setAttribute(
+ styleStr,
+ backImageStyle + gBackgroundImage + ");"
+ );
+ }
+
+ SetRelativeCheckbox();
+
+ customTextColor = GetHTMLOrCSSStyleValue(globalElement, textStr, cssColorStr);
+ customTextColor = ConvertRGBColorIntoHEXColor(customTextColor);
+ customLinkColor = globalElement.getAttribute(linkStr);
+ customActiveColor = globalElement.getAttribute(alinkStr);
+ customVisitedColor = globalElement.getAttribute(vlinkStr);
+ customBackgroundColor = GetHTMLOrCSSStyleValue(
+ globalElement,
+ bgcolorStr,
+ cssBackgroundColorStr
+ );
+ customBackgroundColor = ConvertRGBColorIntoHEXColor(customBackgroundColor);
+
+ var haveCustomColor =
+ customTextColor ||
+ customLinkColor ||
+ customVisitedColor ||
+ customActiveColor ||
+ customBackgroundColor;
+
+ // Set default color explicitly for any that are missing
+ // PROBLEM: We are using "windowtext" and "window" for the Windows OS
+ // default color values. This works with CSS in preview window,
+ // but we should NOT use these as values for HTML attributes!
+
+ if (!customTextColor) {
+ customTextColor = defaultTextColor;
+ }
+ if (!customLinkColor) {
+ customLinkColor = defaultLinkColor;
+ }
+ if (!customActiveColor) {
+ customActiveColor = defaultActiveColor;
+ }
+ if (!customVisitedColor) {
+ customVisitedColor = defaultVisitedColor;
+ }
+ if (!customBackgroundColor) {
+ customBackgroundColor = defaultBackgroundColor;
+ }
+
+ if (haveCustomColor) {
+ // If any colors are set, then check the "Custom" radio button
+ gDialog.PageColorGroup.selectedItem = gDialog.CustomColorsRadio;
+ UseCustomColors();
+ } else {
+ gDialog.PageColorGroup.selectedItem = gDialog.DefaultColorsRadio;
+ UseDefaultColors();
+ }
+}
+
+function GetColorAndUpdate(ColorWellID) {
+ // Only allow selecting when in custom mode
+ if (!gDialog.CustomColorsRadio.selected) {
+ return;
+ }
+
+ var colorWell = document.getElementById(ColorWellID);
+ if (!colorWell) {
+ return;
+ }
+
+ // Don't allow a blank color, i.e., using the "default"
+ var colorObj = {
+ NoDefault: true,
+ Type: "",
+ TextColor: 0,
+ PageColor: 0,
+ Cancel: false,
+ };
+
+ switch (ColorWellID) {
+ case "textCW":
+ colorObj.Type = "Text";
+ colorObj.TextColor = customTextColor;
+ break;
+ case "linkCW":
+ colorObj.Type = "Link";
+ colorObj.TextColor = customLinkColor;
+ break;
+ case "activeCW":
+ colorObj.Type = "ActiveLink";
+ colorObj.TextColor = customActiveColor;
+ break;
+ case "visitedCW":
+ colorObj.Type = "VisitedLink";
+ colorObj.TextColor = customVisitedColor;
+ break;
+ case "backgroundCW":
+ colorObj.Type = "Page";
+ colorObj.PageColor = customBackgroundColor;
+ break;
+ }
+
+ window.openDialog(
+ "chrome://editor/content/EdColorPicker.xhtml",
+ "_blank",
+ "chrome,close,titlebar,modal",
+ "",
+ colorObj
+ );
+
+ // User canceled the dialog
+ if (colorObj.Cancel) {
+ return;
+ }
+
+ var color = "";
+ switch (ColorWellID) {
+ case "textCW":
+ color = customTextColor = colorObj.TextColor;
+ break;
+ case "linkCW":
+ color = customLinkColor = colorObj.TextColor;
+ break;
+ case "activeCW":
+ color = customActiveColor = colorObj.TextColor;
+ break;
+ case "visitedCW":
+ color = customVisitedColor = colorObj.TextColor;
+ break;
+ case "backgroundCW":
+ color = customBackgroundColor = colorObj.BackgroundColor;
+ break;
+ }
+
+ setColorWell(ColorWellID, color);
+ SetColorPreview(ColorWellID, color);
+}
+
+function SetColorPreview(ColorWellID, color) {
+ switch (ColorWellID) {
+ case "textCW":
+ gDialog.NormalText.setAttribute(styleStr, colorStyle + color);
+ break;
+ case "linkCW":
+ gDialog.LinkText.setAttribute(styleStr, colorStyle + color);
+ break;
+ case "activeCW":
+ gDialog.ActiveLinkText.setAttribute(styleStr, colorStyle + color);
+ break;
+ case "visitedCW":
+ gDialog.VisitedLinkText.setAttribute(styleStr, colorStyle + color);
+ break;
+ case "backgroundCW":
+ // Must combine background color and image style values
+ var styleValue = backColorStyle + color;
+ if (gBackgroundImage) {
+ styleValue += ";" + backImageStyle + gBackgroundImage + ");";
+ }
+
+ gDialog.ColorPreview.setAttribute(styleStr, styleValue);
+ previewBGColor = color;
+ break;
+ }
+}
+
+function UseCustomColors() {
+ SetElementEnabledById("TextButton", true);
+ SetElementEnabledById("LinkButton", true);
+ SetElementEnabledById("ActiveLinkButton", true);
+ SetElementEnabledById("VisitedLinkButton", true);
+ SetElementEnabledById("BackgroundButton", true);
+ SetElementEnabledById("Text", true);
+ SetElementEnabledById("Link", true);
+ SetElementEnabledById("Active", true);
+ SetElementEnabledById("Visited", true);
+ SetElementEnabledById("Background", true);
+
+ SetColorPreview("textCW", customTextColor);
+ SetColorPreview("linkCW", customLinkColor);
+ SetColorPreview("activeCW", customActiveColor);
+ SetColorPreview("visitedCW", customVisitedColor);
+ SetColorPreview("backgroundCW", customBackgroundColor);
+
+ setColorWell("textCW", customTextColor);
+ setColorWell("linkCW", customLinkColor);
+ setColorWell("activeCW", customActiveColor);
+ setColorWell("visitedCW", customVisitedColor);
+ setColorWell("backgroundCW", customBackgroundColor);
+}
+
+function UseDefaultColors() {
+ SetColorPreview("textCW", defaultTextColor);
+ SetColorPreview("linkCW", defaultLinkColor);
+ SetColorPreview("activeCW", defaultActiveColor);
+ SetColorPreview("visitedCW", defaultVisitedColor);
+ SetColorPreview("backgroundCW", defaultBackgroundColor);
+
+ // Setting to blank color will remove color from buttons,
+ setColorWell("textCW", "");
+ setColorWell("linkCW", "");
+ setColorWell("activeCW", "");
+ setColorWell("visitedCW", "");
+ setColorWell("backgroundCW", "");
+
+ // Disable color buttons and labels
+ SetElementEnabledById("TextButton", false);
+ SetElementEnabledById("LinkButton", false);
+ SetElementEnabledById("ActiveLinkButton", false);
+ SetElementEnabledById("VisitedLinkButton", false);
+ SetElementEnabledById("BackgroundButton", false);
+ SetElementEnabledById("Text", false);
+ SetElementEnabledById("Link", false);
+ SetElementEnabledById("Active", false);
+ SetElementEnabledById("Visited", false);
+ SetElementEnabledById("Background", false);
+}
+
+function chooseFile() {
+ // Get a local image file, converted into URL format
+ GetLocalFileURL("img").then(fileURL => {
+ // Always try to relativize local file URLs
+ if (gHaveDocumentUrl) {
+ fileURL = MakeRelativeUrl(fileURL);
+ }
+
+ gDialog.BackgroundImageInput.value = fileURL;
+
+ SetRelativeCheckbox();
+ ValidateAndPreviewImage(true);
+ SetTextboxFocus(gDialog.BackgroundImageInput);
+ });
+}
+
+function ChangeBackgroundImage() {
+ // Don't show error message for image while user is typing
+ ValidateAndPreviewImage(false);
+ SetRelativeCheckbox();
+}
+
+function ValidateAndPreviewImage(ShowErrorMessage) {
+ // First make a string with just background color
+ var styleValue = backColorStyle + previewBGColor + ";";
+
+ var retVal = true;
+ var image = TrimString(gDialog.BackgroundImageInput.value);
+ if (image) {
+ if (isImageDataShortened(image)) {
+ gBackgroundImage = restoredImageData(gDialog.BackgroundImageInput);
+ } else {
+ gBackgroundImage = image;
+
+ // Display must use absolute URL if possible
+ var displayImage = gHaveDocumentUrl ? MakeAbsoluteUrl(image) : image;
+ styleValue += backImageStyle + displayImage + ");";
+ }
+ } else {
+ gBackgroundImage = null;
+ }
+
+ // Set style on preview (removes image if not valid)
+ gDialog.ColorPreview.setAttribute(styleStr, styleValue);
+
+ // Note that an "empty" string is valid
+ return retVal;
+}
+
+function ValidateData() {
+ var editor = GetCurrentEditor();
+ try {
+ // Colors values are updated as they are picked, no validation necessary
+ if (gDialog.DefaultColorsRadio.selected) {
+ editor.removeAttributeOrEquivalent(globalElement, textStr, true);
+ globalElement.removeAttribute(linkStr);
+ globalElement.removeAttribute(vlinkStr);
+ globalElement.removeAttribute(alinkStr);
+ editor.removeAttributeOrEquivalent(globalElement, bgcolorStr, true);
+ } else {
+ // Do NOT accept the CSS "WindowsOS" color strings!
+ // Problem: We really should try to get the actual color values
+ // from windows, but I don't know how to do that!
+ var tmpColor = customTextColor.toLowerCase();
+ if (tmpColor != "windowtext") {
+ editor.setAttributeOrEquivalent(
+ globalElement,
+ textStr,
+ customTextColor,
+ true
+ );
+ } else {
+ editor.removeAttributeOrEquivalent(globalElement, textStr, true);
+ }
+
+ tmpColor = customBackgroundColor.toLowerCase();
+ if (tmpColor != "window") {
+ editor.setAttributeOrEquivalent(
+ globalElement,
+ bgcolorStr,
+ customBackgroundColor,
+ true
+ );
+ } else {
+ editor.removeAttributeOrEquivalent(globalElement, bgcolorStr, true);
+ }
+
+ globalElement.setAttribute(linkStr, customLinkColor);
+ globalElement.setAttribute(vlinkStr, customVisitedColor);
+ globalElement.setAttribute(alinkStr, customActiveColor);
+ }
+
+ if (ValidateAndPreviewImage(true)) {
+ // A valid image may be null for no image
+ if (gBackgroundImage) {
+ globalElement.setAttribute(backgroundStr, gBackgroundImage);
+ } else {
+ editor.removeAttributeOrEquivalent(globalElement, backgroundStr, true);
+ }
+
+ return true;
+ }
+ } catch (e) {}
+ return false;
+}
+
+function onAccept(event) {
+ // If it's a file, convert to a data URL.
+ if (gBackgroundImage && /^file:/i.test(gBackgroundImage)) {
+ let nsFile = Services.io
+ .newURI(gBackgroundImage)
+ .QueryInterface(Ci.nsIFileURL).file;
+ if (nsFile.exists()) {
+ let reader = new FileReader();
+ reader.addEventListener("load", function() {
+ gBackgroundImage = reader.result;
+ gDialog.BackgroundImageInput.value = reader.result;
+ if (onAccept(event)) {
+ window.close();
+ }
+ });
+ File.createFromNsIFile(nsFile).then(file => {
+ reader.readAsDataURL(file);
+ });
+ event.preventDefault(); // Don't close just yet...
+ return false;
+ }
+ }
+ if (ValidateData()) {
+ // Copy attributes to element we are changing
+ try {
+ GetCurrentEditor().cloneAttributes(gBodyElement, globalElement);
+ } catch (e) {}
+
+ SaveWindowLocation();
+ return true; // do close the window
+ }
+ event.preventDefault();
+ return false;
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdColorProps.xhtml b/comm/suite/editor/components/dialogs/content/EdColorProps.xhtml
new file mode 100644
index 0000000000..85393ed209
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdColorProps.xhtml
@@ -0,0 +1,134 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edColorPropertiesDTD SYSTEM "chrome://editor/locale/EditorColorProperties.dtd">
+%edColorPropertiesDTD;
+<!ENTITY % composeEditorOverlayDTD SYSTEM "chrome://messenger/locale/messengercompose/mailComposeEditorOverlay.dtd">
+%composeEditorOverlayDTD;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()">
+
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdColorProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox align="start">
+ <hbox class="groupbox-title">
+ <label class="header">&pageColors.label;</label>
+ </hbox>
+ <radiogroup id="PageColorGroup">
+ <radio id="DefaultColorsRadio" label="&defaultColorsRadio.label;" oncommand="UseDefaultColors()"
+ accesskey="&defaultColorsRadio.accessKey;"
+ tooltiptext="&defaultColorsRadio.tooltip;" />
+ <radio id="CustomColorsRadio" label="&customColorsRadio.label;" oncommand="UseCustomColors()"
+ accesskey="&customColorsRadio.accessKey;"
+ tooltiptext="&customColorsRadio.tooltip;" />
+ </radiogroup>
+ <hbox class="indent">
+ <grid>
+ <columns><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <label id="Text" control="TextButton"
+ value="&normalText.label;&colon.character;"
+ accesskey="&normalText.accessKey;"/>
+ <button id="TextButton" class="color-button" oncommand="GetColorAndUpdate('textCW');">
+ <spacer id="textCW" class="color-well"/>
+ </button>
+ </row>
+ <row align="center">
+ <label id="Link" control="LinkButton"
+ value="&linkText.label;&colon.character;"
+ accesskey="&linkText.accessKey;"/>
+ <button id="LinkButton" class="color-button" oncommand="GetColorAndUpdate('linkCW');">
+ <spacer id="linkCW" class="color-well"/>
+ </button>
+ </row>
+ <row align="center">
+ <label id="Active" control="ActiveLinkButton"
+ value="&activeLinkText.label;&colon.character;"
+ accesskey="&activeLinkText.accessKey;"/>
+ <button id="ActiveLinkButton" class="color-button" oncommand="GetColorAndUpdate('activeCW');">
+ <spacer id="activeCW" class="color-well"/>
+ </button>
+ </row>
+ <row align="center">
+ <label id="Visited" control="VisitedLinkButton"
+ value="&visitedLinkText.label;&colon.character;"
+ accesskey="&visitedLinkText.accessKey;"/>
+ <button id="VisitedLinkButton" class="color-button" oncommand="GetColorAndUpdate('visitedCW');">
+ <spacer id="visitedCW" class="color-well"/>
+ </button>
+ </row>
+ <row align="center">
+ <label id="Background" control="BackgroundButton"
+ value="&background.label;"
+ accesskey="&background.accessKey;"/>
+ <button id="BackgroundButton" class="color-button" oncommand="GetColorAndUpdate('backgroundCW');">
+ <spacer id="backgroundCW" class="color-well"/>
+ </button>
+ </row>
+ </rows>
+ </grid>
+ <vbox id="ColorPreview" flex="1">
+ <spacer flex="1"/>
+ <label class="larger" id="NormalText" value="&normalText.label;"/>
+ <spacer flex="1"/>
+ <label class="larger" id="LinkText" value="&linkText.label;"/>
+ <spacer flex="1"/>
+ <label class="larger" id="ActiveLinkText" value="&activeLinkText.label;"/>
+ <spacer flex="1"/>
+ <label class="larger" id="VisitedLinkText" value="&visitedLinkText.label;"/>
+ <spacer flex="1"/>
+ </vbox>
+ <spacer flex="1"/>
+ </hbox>
+ <spacer class="spacer"/>
+ </groupbox>
+ <spacer class="spacer"/>
+ <label control="BackgroundImageInput"
+ value="&backgroundImage.label;"
+ tooltiptext="&backgroundImage.tooltip;"
+ accesskey="&backgroundImage.accessKey;"/>
+ <tooltip id="shortenedDataURI">
+ <label value="&backgroundImage.shortenedDataURI;"/>
+ </tooltip>
+ <textbox id="BackgroundImageInput" class="uri-element" oninput="ChangeBackgroundImage()"
+ tooltiptext="&backgroundImage.tooltip;" flex="1"/>
+ <hbox align="center">
+ <checkbox id="MakeRelativeCheckbox"
+ for="BackgroundImageInput"
+ label="&makeUrlRelative.label;"
+ accesskey="&makeUrlRelative.accessKey;"
+ oncommand="MakeInputValueRelativeOrAbsolute(this);"
+ tooltiptext="&makeUrlRelative.tooltip;"/>
+ <spacer flex="1"/>
+ <button id="ChooseFile"
+ oncommand="chooseFile()"
+ label="&chooseFileButton.label;"
+ accesskey="&chooseFileButton.accessKey;"/>
+ </hbox>
+ <spacer class="smallspacer"/>
+ <hbox>
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton"
+ oncommand="onAdvancedEdit();"
+ label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;"
+ tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdConvertToTable.js b/comm/suite/editor/components/dialogs/content/EdConvertToTable.js
new file mode 100644
index 0000000000..a149e708f8
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdConvertToTable.js
@@ -0,0 +1,326 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+var gIndex;
+var gCommaIndex = "0";
+var gSpaceIndex = "1";
+var gOtherIndex = "2";
+
+// dialog initialization code
+function Startup() {
+ if (!GetCurrentEditor()) {
+ window.close();
+ return;
+ }
+
+ gDialog.sepRadioGroup = document.getElementById("SepRadioGroup");
+ gDialog.sepCharacterInput = document.getElementById("SepCharacterInput");
+ gDialog.deleteSepCharacter = document.getElementById("DeleteSepCharacter");
+ gDialog.collapseSpaces = document.getElementById("CollapseSpaces");
+
+ // We persist the user's separator character
+ gDialog.sepCharacterInput.value = gDialog.sepRadioGroup.getAttribute(
+ "character"
+ );
+
+ gIndex = gDialog.sepRadioGroup.getAttribute("index");
+
+ switch (gIndex) {
+ case gCommaIndex:
+ default:
+ gDialog.sepRadioGroup.selectedItem = document.getElementById("comma");
+ break;
+ case gSpaceIndex:
+ gDialog.sepRadioGroup.selectedItem = document.getElementById("space");
+ break;
+ case gOtherIndex:
+ gDialog.sepRadioGroup.selectedItem = document.getElementById("other");
+ break;
+ }
+
+ // Set initial enable state on character input and "collapse" checkbox
+ SelectCharacter(gIndex);
+
+ SetWindowLocation();
+}
+
+function InputSepCharacter() {
+ var str = gDialog.sepCharacterInput.value;
+
+ // Limit input to 1 character
+ if (str.length > 1) {
+ str = str.slice(0, 1);
+ }
+
+ // We can never allow tag or entity delimiters for separator character
+ if (str == "<" || str == ">" || str == "&" || str == ";" || str == " ") {
+ str = "";
+ }
+
+ gDialog.sepCharacterInput.value = str;
+}
+
+function SelectCharacter(radioGroupIndex) {
+ gIndex = radioGroupIndex;
+ SetElementEnabledById("SepCharacterInput", gIndex == gOtherIndex);
+ SetElementEnabledById("CollapseSpaces", gIndex == gSpaceIndex);
+}
+
+/* eslint-disable complexity */
+function onAccept() {
+ var sepCharacter = "";
+ switch (gIndex) {
+ case gCommaIndex:
+ sepCharacter = ",";
+ break;
+ case gSpaceIndex:
+ sepCharacter = " ";
+ break;
+ case gOtherIndex:
+ sepCharacter = gDialog.sepCharacterInput.value.slice(0, 1);
+ break;
+ }
+
+ var editor = GetCurrentEditor();
+ var str;
+ try {
+ str = editor.outputToString(
+ "text/html",
+ kOutputLFLineBreak | kOutputSelectionOnly
+ );
+ } catch (e) {}
+ if (!str) {
+ SaveWindowLocation();
+ return;
+ }
+
+ // Replace nbsp with spaces:
+ str = str.replace(/\u00a0/g, " ");
+
+ // Strip out </p> completely
+ str = str.replace(/\s*<\/p>\s*/g, "");
+
+ // Trim whitespace adjacent to <p> and <br> tags
+ // and replace <p> with <br>
+ // (which will be replaced with </tr> below)
+ str = str.replace(/\s*<p>\s*|\s*<br>\s*/g, "<br>");
+
+ // Trim leading <br>s
+ str = str.replace(/^(<br>)+/, "");
+
+ // Trim trailing <br>s
+ str = str.replace(/(<br>)+$/, "");
+
+ // Reduce multiple internal <br> to just 1
+ // TODO: Maybe add a checkbox to let user decide
+ // str = str.replace(/(<br>)+/g, "<br>");
+
+ // Trim leading and trailing spaces
+ str = str.trim();
+
+ // Remove all tag contents so we don't replace
+ // separator character within tags
+ // Also converts lists to something useful
+ var stack = [];
+ var start;
+ var end;
+ var searchStart = 0;
+ var listSeparator = "";
+ var listItemSeparator = "";
+ var endList = false;
+
+ do {
+ start = str.indexOf("<", searchStart);
+
+ if (start >= 0) {
+ end = str.indexOf(">", start + 1);
+ if (end > start) {
+ let tagContent = str.slice(start + 1, end).trim();
+
+ if (/^ol|^ul|^dl/.test(tagContent)) {
+ // Replace list tag with <BR> to start new row
+ // at beginning of second or greater list tag
+ str = str.slice(0, start) + listSeparator + str.slice(end + 1);
+ if (listSeparator == "") {
+ listSeparator = "<br>";
+ }
+
+ // Reset for list item separation into cells
+ listItemSeparator = "";
+ } else if (/^li|^dt|^dd/.test(tagContent)) {
+ // Start a new row if this is first item after the ending the last list
+ if (endList) {
+ listItemSeparator = "<br>";
+ }
+
+ // Start new cell at beginning of second or greater list items
+ str = str.slice(0, start) + listItemSeparator + str.slice(end + 1);
+
+ if (endList || listItemSeparator == "") {
+ listItemSeparator = sepCharacter;
+ }
+
+ endList = false;
+ } else {
+ // Find end tags
+ endList = /^\/ol|^\/ul|^\/dl/.test(tagContent);
+ if (endList || /^\/li|^\/dt|^\/dd/.test(tagContent)) {
+ // Strip out tag
+ str = str.slice(0, start) + str.slice(end + 1);
+ } else {
+ // Not a list-related tag: Store tag contents in an array
+ stack.push(tagContent);
+
+ // Keep the "<" and ">" while removing from source string
+ start++;
+ str = str.slice(0, start) + str.slice(end);
+ }
+ }
+ }
+ searchStart = start + 1;
+ }
+ } while (start >= 0);
+
+ // Replace separator characters with table cells
+ var replaceString;
+ if (gDialog.deleteSepCharacter.checked) {
+ replaceString = "";
+ } else {
+ // Don't delete separator character,
+ // so include it at start of string to replace
+ replaceString = sepCharacter;
+ }
+
+ replaceString += "<td>";
+
+ if (sepCharacter.length > 0) {
+ var tempStr = sepCharacter;
+ var regExpChars = ".!@#$%^&*-+[]{}()|\\/";
+ if (regExpChars.includes(sepCharacter)) {
+ tempStr = "\\" + sepCharacter;
+ }
+
+ if (gIndex == gSpaceIndex) {
+ // If checkbox is checked,
+ // one or more adjacent spaces are one separator
+ if (gDialog.collapseSpaces.checked) {
+ tempStr = "\\s+";
+ } else {
+ tempStr = "\\s";
+ }
+ }
+ var pattern = new RegExp(tempStr, "g");
+ str = str.replace(pattern, replaceString);
+ }
+
+ // Put back tag contents that we removed above
+ searchStart = 0;
+ var stackIndex = 0;
+ do {
+ start = str.indexOf("<", searchStart);
+ end = start + 1;
+ if (start >= 0 && str.charAt(end) == ">") {
+ // We really need a FIFO stack!
+ str = str.slice(0, end) + stack[stackIndex++] + str.slice(end);
+ }
+ searchStart = end;
+ } while (start >= 0);
+
+ // End table row and start another for each br or p
+ str = str.replace(/\s*<br>\s*/g, "</tr>\n<tr><td>");
+
+ // Add the table tags and the opening and closing tr/td tags
+ // Default table attributes should be same as those used in nsHTMLEditor::CreateElementWithDefaults()
+ // (Default width="100%" is used in EdInsertTable.js)
+ str =
+ '<table border="1" width="100%" cellpadding="2" cellspacing="2">\n<tr><td>' +
+ str +
+ "</tr>\n</table>\n";
+
+ editor.beginTransaction();
+
+ // Delete the selection -- makes it easier to find where table will insert
+ var nodeBeforeTable = null;
+ var nodeAfterTable = null;
+ try {
+ editor.deleteSelection(editor.eNone, editor.eStrip);
+
+ var anchorNodeBeforeInsert = editor.selection.anchorNode;
+ var offset = editor.selection.anchorOffset;
+ if (anchorNodeBeforeInsert.nodeType == Node.TEXT_NODE) {
+ // Text was split. Table should be right after the first or before
+ nodeBeforeTable = anchorNodeBeforeInsert.previousSibling;
+ nodeAfterTable = anchorNodeBeforeInsert;
+ } else {
+ // Table should be inserted right after node pointed to by selection
+ if (offset > 0) {
+ nodeBeforeTable = anchorNodeBeforeInsert.childNodes.item(offset - 1);
+ }
+
+ nodeAfterTable = anchorNodeBeforeInsert.childNodes.item(offset);
+ }
+
+ editor.insertHTML(str);
+ } catch (e) {}
+
+ var table = null;
+ if (nodeAfterTable) {
+ var previous = nodeAfterTable.previousSibling;
+ if (previous && previous.nodeName.toLowerCase() == "table") {
+ table = previous;
+ }
+ }
+ if (!table && nodeBeforeTable) {
+ var next = nodeBeforeTable.nextSibling;
+ if (next && next.nodeName.toLowerCase() == "table") {
+ table = next;
+ }
+ }
+
+ if (table) {
+ // Fixup table only if pref is set
+ var firstRow;
+ try {
+ if (Services.prefs.getBoolPref("editor.table.maintain_structure")) {
+ editor.normalizeTable(table);
+ }
+
+ firstRow = editor.getFirstRow(table);
+ } catch (e) {}
+
+ // Put caret in first cell
+ if (firstRow) {
+ var node2 = firstRow.firstChild;
+ do {
+ if (
+ node2.nodeName.toLowerCase() == "td" ||
+ node2.nodeName.toLowerCase() == "th"
+ ) {
+ try {
+ editor.selection.collapse(node2, 0);
+ } catch (e) {}
+ break;
+ }
+ node2 = node2.nextSibling;
+ } while (node2);
+ }
+ }
+
+ editor.endTransaction();
+
+ // Save persisted attributes
+ gDialog.sepRadioGroup.setAttribute("index", gIndex);
+ if (gIndex == gOtherIndex) {
+ gDialog.sepRadioGroup.setAttribute("character", sepCharacter);
+ }
+
+ SaveWindowLocation();
+}
+/* eslint-enable complexity */
diff --git a/comm/suite/editor/components/dialogs/content/EdConvertToTable.xhtml b/comm/suite/editor/components/dialogs/content/EdConvertToTable.xhtml
new file mode 100644
index 0000000000..d3d5c4a465
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdConvertToTable.xhtml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EdConvertToTable.dtd">
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload = "Startup()"
+ style="min-width:20em">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <!--- Element-specific methods -->
+ <script src="chrome://editor/content/EdConvertToTable.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+ <description class="wrap" flex="1">&instructions1.label;</description>
+ <description class="wrap" flex="1">&instructions2.label;</description>
+ <radiogroup id="SepRadioGroup" persist="index character" index="0" character="">
+ <radio id="comma" label="&commaRadio.label;" oncommand="SelectCharacter('0');"/>
+ <radio id="space" label="&spaceRadio.label;" oncommand="SelectCharacter('1');"/>
+ <hbox>
+ <spacer class="radio-spacer"/>
+ <checkbox id="CollapseSpaces" label="&collapseSpaces.label;"
+ checked="true" persist="checked"
+ tooltiptext="&collapseSpaces.tooltip;"/>
+ </hbox>
+ <hbox align="center">
+ <radio id="other" label="&otherRadio.label;" oncommand="SelectCharacter('2');"/>
+ <textbox class="narrow" id="SepCharacterInput" oninput="InputSepCharacter()"/>
+ </hbox>
+ </radiogroup>
+ <spacer class="spacer"/>
+ <checkbox id="DeleteSepCharacter" label="&deleteCharCheck.label;" persist="checked"/>
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdDialogCommon.js b/comm/suite/editor/components/dialogs/content/EdDialogCommon.js
new file mode 100644
index 0000000000..c6b7c63778
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdDialogCommon.js
@@ -0,0 +1,1038 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Each editor window must include this file
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* globals InitDialog, ChangeLinkLocation, ValidateData */
+
+// Object to attach commonly-used widgets (all dialogs should use this)
+var gDialog = {};
+
+var gHaveDocumentUrl = false;
+var gValidationError = false;
+
+// Use for 'defaultIndex' param in InitPixelOrPercentMenulist
+const gPixel = 0;
+const gPercent = 1;
+
+const gMaxPixels = 100000; // Used for image size, borders, spacing, and padding
+// Gecko code uses 1000 for maximum rowspan, colspan
+// Also, editing performance is really bad above this
+const gMaxRows = 1000;
+const gMaxColumns = 1000;
+const gMaxTableSize = 1000000; // Width or height of table or cells
+
+// For dialogs that expand in size. Default is smaller size see "onMoreFewer()" below
+var SeeMore = false;
+
+// A XUL element with id="location" for managing
+// dialog location relative to parent window
+var gLocation;
+
+// The element being edited - so AdvancedEdit can have access to it
+var globalElement;
+
+/* Validate contents of an input field
+ *
+ * inputWidget The 'textbox' XUL element for text input of the attribute's value
+ * listWidget The 'menulist' XUL element for choosing "pixel" or "percent"
+ * May be null when no pixel/percent is used.
+ * minVal minimum allowed for input widget's value
+ * maxVal maximum allowed for input widget's value
+ * (when "listWidget" is used, maxVal is used for "pixel" maximum,
+ * 100% is assumed if "percent" is the user's choice)
+ * element The DOM element that we set the attribute on. May be null.
+ * attName Name of the attribute to set. May be null or ignored if "element" is null
+ * mustHaveValue If true, error dialog is displayed if "value" is empty string
+ *
+ * This calls "ValidateNumberRange()", which puts up an error dialog to inform the user.
+ * If error, we also:
+ * Shift focus and select contents of the inputWidget,
+ * Switch to appropriate panel of tabbed dialog if user implements "SwitchToValidate()",
+ * and/or will expand the dialog to full size if "More / Fewer" feature is implemented
+ *
+ * Returns the "value" as a string, or "" if error or input contents are empty
+ * The global "gValidationError" variable is set true if error was found
+ */
+function ValidateNumber(
+ inputWidget,
+ listWidget,
+ minVal,
+ maxVal,
+ element,
+ attName,
+ mustHaveValue,
+ mustShowMoreSection
+) {
+ if (!inputWidget) {
+ gValidationError = true;
+ return "";
+ }
+
+ // Global error return value
+ gValidationError = false;
+ var maxLimit = maxVal;
+ var isPercent = false;
+
+ var numString = TrimString(inputWidget.value);
+ if (numString || mustHaveValue) {
+ if (listWidget) {
+ isPercent = listWidget.selectedIndex == 1;
+ }
+ if (isPercent) {
+ maxLimit = 100;
+ }
+
+ // This method puts up the error message
+ numString = ValidateNumberRange(numString, minVal, maxLimit, mustHaveValue);
+ if (!numString) {
+ // Switch to appropriate panel for error reporting
+ SwitchToValidatePanel();
+
+ // or expand dialog for users of "More / Fewer" button
+ if (
+ "dialog" in window &&
+ window.dialog &&
+ "MoreSection" in gDialog &&
+ gDialog.MoreSection
+ ) {
+ if (!SeeMore) {
+ onMoreFewer();
+ }
+ }
+
+ // Error - shift to offending input widget
+ SetTextboxFocus(inputWidget);
+ gValidationError = true;
+ } else {
+ if (isPercent) {
+ numString += "%";
+ }
+ if (element) {
+ GetCurrentEditor().setAttributeOrEquivalent(
+ element,
+ attName,
+ numString,
+ true
+ );
+ }
+ }
+ } else if (element) {
+ GetCurrentEditor().removeAttributeOrEquivalent(element, attName, true);
+ }
+ return numString;
+}
+
+/* Validate contents of an input field
+ *
+ * value number to validate
+ * minVal minimum allowed for input widget's value
+ * maxVal maximum allowed for input widget's value
+ * (when "listWidget" is used, maxVal is used for "pixel" maximum,
+ * 100% is assumed if "percent" is the user's choice)
+ * mustHaveValue If true, error dialog is displayed if "value" is empty string
+ *
+ * If inputWidget's value is outside of range, or is empty when "mustHaveValue" = true,
+ * an error dialog is popuped up to inform the user. The focus is shifted
+ * to the inputWidget.
+ *
+ * Returns the "value" as a string, or "" if error or input contents are empty
+ * The global "gValidationError" variable is set true if error was found
+ */
+function ValidateNumberRange(value, minValue, maxValue, mustHaveValue) {
+ // Initialize global error flag
+ gValidationError = false;
+ value = TrimString(String(value));
+
+ // We don't show error for empty string unless caller wants to
+ if (!value && !mustHaveValue) {
+ return "";
+ }
+
+ var numberStr = "";
+
+ if (value.length > 0) {
+ // Extract just numeric characters
+ var number = Number(value.replace(/\D+/g, ""));
+ if (number >= minValue && number <= maxValue) {
+ // Return string version of the number
+ return String(number);
+ }
+ numberStr = String(number);
+ }
+
+ var message = "";
+
+ if (numberStr.length > 0) {
+ // We have a number from user outside of allowed range
+ message = GetString("ValidateRangeMsg");
+ message = message.replace(/%n%/, numberStr);
+ message += "\n ";
+ }
+ message += GetString("ValidateNumberMsg");
+
+ // Replace variable placeholders in message with number values
+ message = message.replace(/%min%/, minValue).replace(/%max%/, maxValue);
+ ShowInputErrorMessage(message);
+
+ // Return an empty string to indicate error
+ gValidationError = true;
+ return "";
+}
+
+function SetTextboxFocusById(id) {
+ SetTextboxFocus(document.getElementById(id));
+}
+
+function SetTextboxFocus(textbox) {
+ if (textbox) {
+ // XXX Using the setTimeout is hacky workaround for bug 103197
+ // Must create a new function to keep "textbox" in scope
+ setTimeout(
+ function(textbox) {
+ textbox.focus();
+ textbox.select();
+ },
+ 0,
+ textbox
+ );
+ }
+}
+
+function ShowInputErrorMessage(message) {
+ Services.prompt.alert(window, GetString("InputError"), message);
+ window.focus();
+}
+
+// Get the text appropriate to parent container
+// to determine what a "%" value is referring to.
+// elementForAtt is element we are actually setting attributes on
+// (a temporary copy of element in the doc to allow canceling),
+// but elementInDoc is needed to find parent context in document
+function GetAppropriatePercentString(elementForAtt, elementInDoc) {
+ var editor = GetCurrentEditor();
+ try {
+ var name = elementForAtt.nodeName.toLowerCase();
+ if (name == "td" || name == "th") {
+ return GetString("PercentOfTable");
+ }
+
+ // Check if element is within a table cell
+ if (editor.getElementOrParentByTagName("td", elementInDoc)) {
+ return GetString("PercentOfCell");
+ }
+ return GetString("PercentOfWindow");
+ } catch (e) {
+ return "";
+ }
+}
+
+function ClearListbox(listbox) {
+ if (listbox) {
+ listbox.clearSelection();
+ while (listbox.hasChildNodes()) {
+ listbox.lastChild.remove();
+ }
+ }
+}
+
+function forceInteger(elementID) {
+ var editField = document.getElementById(elementID);
+ if (!editField) {
+ return;
+ }
+
+ var stringIn = editField.value;
+ if (stringIn && stringIn.length > 0) {
+ // Strip out all nonnumeric characters
+ stringIn = stringIn.replace(/\D+/g, "");
+ if (!stringIn) {
+ stringIn = "";
+ }
+
+ // Write back only if changed
+ if (stringIn != editField.value) {
+ editField.value = stringIn;
+ }
+ }
+}
+
+function InitPixelOrPercentMenulist(
+ elementForAtt,
+ elementInDoc,
+ attribute,
+ menulistID,
+ defaultIndex
+) {
+ if (!defaultIndex) {
+ defaultIndex = gPixel;
+ }
+
+ // var size = elementForAtt.getAttribute(attribute);
+ var size = GetHTMLOrCSSStyleValue(elementForAtt, attribute, attribute);
+ var menulist = document.getElementById(menulistID);
+ var pixelItem;
+ var percentItem;
+
+ if (!menulist) {
+ dump("NO MENULIST found for ID=" + menulistID + "\n");
+ return size;
+ }
+
+ menulist.removeAllItems();
+ pixelItem = menulist.appendItem(GetString("Pixels"));
+
+ if (!pixelItem) {
+ return 0;
+ }
+
+ percentItem = menulist.appendItem(
+ GetAppropriatePercentString(elementForAtt, elementInDoc)
+ );
+ if (size && size.length > 0) {
+ // Search for a "%" or "px"
+ if (size.includes("%")) {
+ // Strip out the %
+ size = size.substr(0, size.indexOf("%"));
+ if (percentItem) {
+ menulist.selectedItem = percentItem;
+ }
+ } else {
+ if (size.includes("px")) {
+ // Strip out the px
+ size = size.substr(0, size.indexOf("px"));
+ }
+ menulist.selectedItem = pixelItem;
+ }
+ } else {
+ menulist.selectedIndex = defaultIndex;
+ }
+
+ return size;
+}
+
+function onAdvancedEdit() {
+ // First validate data from widgets in the "simpler" property dialog
+ if (ValidateData()) {
+ // Set true if OK is clicked in the Advanced Edit dialog
+ window.AdvancedEditOK = false;
+ // Open the AdvancedEdit dialog, passing in the element to be edited
+ // (the copy named "globalElement")
+ window.openDialog(
+ "chrome://editor/content/EdAdvancedEdit.xhtml",
+ "_blank",
+ "chrome,close,titlebar,modal,resizable=yes",
+ "",
+ globalElement
+ );
+ window.focus();
+ if (window.AdvancedEditOK) {
+ // Copy edited attributes to the dialog widgets:
+ InitDialog();
+ }
+ }
+}
+
+function getColor(ColorPickerID) {
+ var colorPicker = document.getElementById(ColorPickerID);
+ var color;
+ if (colorPicker) {
+ // Extract color from colorPicker and assign to colorWell.
+ color = colorPicker.getAttribute("color");
+ if (color && color == "") {
+ return null;
+ }
+ // Clear color so next if it's called again before
+ // color picker is actually used, we dedect the "don't set color" state
+ colorPicker.setAttribute("color", "");
+ }
+
+ return color;
+}
+
+function setColorWell(ColorWellID, color) {
+ var colorWell = document.getElementById(ColorWellID);
+ if (colorWell) {
+ if (!color || color == "") {
+ // Don't set color (use default)
+ // Trigger change to not show color swatch
+ colorWell.setAttribute("default", "true");
+ // Style in CSS sets "background-color",
+ // but color won't clear unless we do this:
+ colorWell.removeAttribute("style");
+ } else {
+ colorWell.removeAttribute("default");
+ // Use setAttribute so colorwell can be a XUL element, such as button
+ colorWell.setAttribute("style", "background-color:" + color);
+ }
+ }
+}
+
+function getColorAndSetColorWell(ColorPickerID, ColorWellID) {
+ var color = getColor(ColorPickerID);
+ setColorWell(ColorWellID, color);
+ return color;
+}
+
+function InitMoreFewer() {
+ // Set SeeMore bool to the OPPOSITE of the current state,
+ // which is automatically saved by using the 'persist="more"'
+ // attribute on the gDialog.MoreFewerButton button
+ // onMoreFewer will toggle it and redraw the dialog
+ SeeMore = gDialog.MoreFewerButton.getAttribute("more") != "1";
+ onMoreFewer();
+ gDialog.MoreFewerButton.setAttribute(
+ "accesskey",
+ GetString("PropertiesAccessKey")
+ );
+}
+
+function onMoreFewer() {
+ if (SeeMore) {
+ gDialog.MoreSection.collapsed = true;
+ gDialog.MoreFewerButton.setAttribute("more", "0");
+ gDialog.MoreFewerButton.setAttribute("label", GetString("MoreProperties"));
+ SeeMore = false;
+ } else {
+ gDialog.MoreSection.collapsed = false;
+ gDialog.MoreFewerButton.setAttribute("more", "1");
+ gDialog.MoreFewerButton.setAttribute("label", GetString("FewerProperties"));
+ SeeMore = true;
+ }
+ window.sizeToContent();
+}
+
+function SwitchToValidatePanel() {
+ // no default implementation
+ // Only EdTableProps.js currently implements this
+}
+
+const nsIFilePicker = Ci.nsIFilePicker;
+
+/**
+ * @return {Promise} URL spec of the file chosen, or null
+ */
+function GetLocalFileURL(filterType) {
+ var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
+ var fileType = "html";
+
+ if (filterType == "img") {
+ fp.init(window, GetString("SelectImageFile"), nsIFilePicker.modeOpen);
+ fp.appendFilters(nsIFilePicker.filterImages);
+ fileType = "image";
+ } else if (filterType.startsWith("html")) {
+ // Current usage of this is in Link dialog,
+ // where we always want HTML first
+ fp.init(window, GetString("OpenHTMLFile"), nsIFilePicker.modeOpen);
+
+ // When loading into Composer, direct user to prefer HTML files and text files,
+ // so we call separately to control the order of the filter list
+ fp.appendFilters(nsIFilePicker.filterHTML);
+ fp.appendFilters(nsIFilePicker.filterText);
+
+ // Link dialog also allows linking to images
+ if (filterType.includes("img", 1)) {
+ fp.appendFilters(nsIFilePicker.filterImages);
+ }
+ }
+ // Default or last filter is "All Files"
+ fp.appendFilters(nsIFilePicker.filterAll);
+
+ // set the file picker's current directory to last-opened location saved in prefs
+ SetFilePickerDirectory(fp, fileType);
+
+ return new Promise(resolve => {
+ fp.open(rv => {
+ if (rv != nsIFilePicker.returnOK || !fp.file) {
+ resolve(null);
+ return;
+ }
+ SaveFilePickerDirectory(fp, fileType);
+ resolve(fp.fileURL.spec);
+ });
+ });
+}
+
+function GetMetaElementByAttribute(name, value) {
+ if (name) {
+ name = name.toLowerCase();
+ let editor = GetCurrentEditor();
+ try {
+ return editor.document.querySelector(
+ "meta[" + name + '="' + value + '"]'
+ );
+ } catch (e) {}
+ }
+ return null;
+}
+
+function CreateMetaElementWithAttribute(name, value) {
+ let editor = GetCurrentEditor();
+ try {
+ let metaElement = editor.createElementWithDefaults("meta");
+ if (name) {
+ metaElement.setAttribute(name, value);
+ }
+ return metaElement;
+ } catch (e) {}
+ return null;
+}
+
+// Change "content" attribute on a META element,
+// or delete entire element it if content is empty
+// This uses undoable editor transactions
+function SetMetaElementContent(metaElement, content, insertNew, prepend) {
+ if (metaElement) {
+ var editor = GetCurrentEditor();
+ try {
+ if (!content || content == "") {
+ if (!insertNew) {
+ editor.deleteNode(metaElement);
+ }
+ } else if (insertNew) {
+ metaElement.setAttribute("content", content);
+ if (prepend) {
+ PrependHeadElement(metaElement);
+ } else {
+ AppendHeadElement(metaElement);
+ }
+ } else {
+ editor.setAttribute(metaElement, "content", content);
+ }
+ } catch (e) {}
+ }
+}
+
+function GetHeadElement() {
+ var editor = GetCurrentEditor();
+ try {
+ return editor.document.querySelector("head");
+ } catch (e) {}
+
+ return null;
+}
+
+function PrependHeadElement(element) {
+ var head = GetHeadElement();
+ if (head) {
+ var editor = GetCurrentEditor();
+ try {
+ // Use editor's undoable transaction
+ // XXX Here tried to prevent updating Selection with unknown 4th argument,
+ // but nsIEditor.setShouldTxnSetSelection is not used for that.
+ editor.insertNode(element, head, 0);
+ } catch (e) {}
+ }
+}
+
+function AppendHeadElement(element) {
+ var head = GetHeadElement();
+ if (head) {
+ var position = 0;
+ if (head.hasChildNodes()) {
+ position = head.childNodes.length;
+ }
+
+ var editor = GetCurrentEditor();
+ try {
+ // Use editor's undoable transaction
+ // XXX Here tried to prevent updating Selection with unknown 4th argument,
+ // but nsIEditor.setShouldTxnSetSelection is not used for that.
+ editor.insertNode(element, head, position);
+ } catch (e) {}
+ }
+}
+
+function SetWindowLocation() {
+ gLocation = document.getElementById("location");
+ if (gLocation) {
+ window.screenX = Math.max(
+ 0,
+ Math.min(
+ window.opener.screenX + Number(gLocation.getAttribute("offsetX")),
+ screen.availWidth - window.outerWidth
+ )
+ );
+ window.screenY = Math.max(
+ 0,
+ Math.min(
+ window.opener.screenY + Number(gLocation.getAttribute("offsetY")),
+ screen.availHeight - window.outerHeight
+ )
+ );
+ }
+}
+
+function SaveWindowLocation() {
+ if (gLocation) {
+ gLocation.setAttribute("offsetX", window.screenX - window.opener.screenX);
+ gLocation.setAttribute("offsetY", window.screenY - window.opener.screenY);
+ }
+}
+
+function onCancel() {
+ SaveWindowLocation();
+}
+
+function SetRelativeCheckbox(checkbox) {
+ if (!checkbox) {
+ checkbox = document.getElementById("MakeRelativeCheckbox");
+ if (!checkbox) {
+ return;
+ }
+ }
+
+ var editor = GetCurrentEditor();
+ // Mail never allows relative URLs, so hide the checkbox
+ if (editor && editor.flags & Ci.nsIEditor.eEditorMailMask) {
+ checkbox.collapsed = true;
+ return;
+ }
+
+ var input = document.getElementById(checkbox.getAttribute("for"));
+ if (!input) {
+ return;
+ }
+
+ var url = TrimString(input.value);
+ var urlScheme = GetScheme(url);
+
+ // Check it if url is relative (no scheme).
+ checkbox.checked = url.length > 0 && !urlScheme;
+
+ // Now do checkbox enabling:
+ var enable = false;
+
+ var docUrl = GetDocumentBaseUrl();
+ var docScheme = GetScheme(docUrl);
+
+ if (url && docUrl && docScheme) {
+ if (urlScheme) {
+ // Url is absolute
+ // If we can make a relative URL, then enable must be true!
+ // (this lets the smarts of MakeRelativeUrl do all the hard work)
+ enable = GetScheme(MakeRelativeUrl(url)).length == 0;
+ } else if (url[0] == "#") {
+ // Url is relative
+ // Check if url is a named anchor
+ // but document doesn't have a filename
+ // (it's probably "index.html" or "index.htm",
+ // but we don't want to allow a malformed URL)
+ var docFilename = GetFilename(docUrl);
+ enable = docFilename.length > 0;
+ } else {
+ // Any other url is assumed
+ // to be ok to try to make absolute
+ enable = true;
+ }
+ }
+
+ SetElementEnabled(checkbox, enable);
+}
+
+// oncommand handler for the Relativize checkbox in EditorOverlay.xhtml
+function MakeInputValueRelativeOrAbsolute(checkbox) {
+ var input = document.getElementById(checkbox.getAttribute("for"));
+ if (!input) {
+ return;
+ }
+
+ var docUrl = GetDocumentBaseUrl();
+ if (!docUrl) {
+ // Checkbox should be disabled if not saved,
+ // but keep this error message in case we change that
+ Services.prompt.alert(window, "", GetString("SaveToUseRelativeUrl"));
+ window.focus();
+ } else {
+ // Note that "checked" is opposite of its last state,
+ // which determines what we want to do here
+ if (checkbox.checked) {
+ input.value = MakeRelativeUrl(input.value);
+ } else {
+ input.value = MakeAbsoluteUrl(input.value);
+ }
+
+ // Reset checkbox to reflect url state
+ SetRelativeCheckbox(checkbox);
+ }
+}
+
+var IsBlockParent = [
+ "applet",
+ "blockquote",
+ "body",
+ "center",
+ "dd",
+ "div",
+ "form",
+ "li",
+ "noscript",
+ "object",
+ "td",
+ "th",
+];
+
+var NotAnInlineParent = [
+ "col",
+ "colgroup",
+ "dl",
+ "dir",
+ "menu",
+ "ol",
+ "table",
+ "tbody",
+ "tfoot",
+ "thead",
+ "tr",
+ "ul",
+];
+
+function nodeIsBreak(editor, node) {
+ return !node || node.localName == "br" || editor.nodeIsBlock(node);
+}
+
+function InsertElementAroundSelection(element) {
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+
+ try {
+ // First get the selection as a single range
+ var range, start, end, offset;
+ var count = editor.selection.rangeCount;
+ if (count == 1) {
+ range = editor.selection.getRangeAt(0).cloneRange();
+ } else {
+ range = editor.document.createRange();
+ start = editor.selection.getRangeAt(0);
+ range.setStart(start.startContainer, start.startOffset);
+ end = editor.selection.getRangeAt(--count);
+ range.setEnd(end.endContainer, end.endOffset);
+ }
+
+ // Flatten the selection to child nodes of the common ancestor
+ while (range.startContainer != range.commonAncestorContainer) {
+ range.setStartBefore(range.startContainer);
+ }
+ while (range.endContainer != range.commonAncestorContainer) {
+ range.setEndAfter(range.endContainer);
+ }
+
+ if (editor.nodeIsBlock(element)) {
+ // Block element parent must be a valid block
+ while (!IsBlockParent.includes(range.commonAncestorContainer.localName)) {
+ range.selectNode(range.commonAncestorContainer);
+ }
+ } else {
+ if (!nodeIsBreak(editor, range.commonAncestorContainer)) {
+ // Fail if we're not inserting a block (use setInlineProperty instead)
+ return false;
+ }
+ if (NotAnInlineParent.includes(range.commonAncestorContainer.localName)) {
+ // Inline element parent must not be an invalid block
+ do {
+ range.selectNode(range.commonAncestorContainer);
+ } while (
+ NotAnInlineParent.includes(range.commonAncestorContainer.localName)
+ );
+ } else {
+ // Further insert block check
+ for (var i = range.startOffset; ; i++) {
+ if (i == range.endOffset) {
+ return false;
+ }
+ if (
+ nodeIsBreak(editor, range.commonAncestorContainer.childNodes[i])
+ ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // The range may be contained by body text, which should all be selected.
+ offset = range.startOffset;
+ start = range.startContainer.childNodes[offset];
+ if (!nodeIsBreak(editor, start)) {
+ while (!nodeIsBreak(editor, start.previousSibling)) {
+ start = start.previousSibling;
+ offset--;
+ }
+ }
+ end = range.endContainer.childNodes[range.endOffset];
+ if (end && !nodeIsBreak(editor, end.previousSibling)) {
+ while (!nodeIsBreak(editor, end)) {
+ end = end.nextSibling;
+ }
+ }
+
+ // Now insert the node
+ // XXX Here tried to prevent updating Selection with unknown 4th argument,
+ // but nsIEditor.setShouldTxnSetSelection is not used for that.
+ editor.insertNode(element, range.commonAncestorContainer, offset);
+ offset = element.childNodes.length;
+ if (!editor.nodeIsBlock(element)) {
+ editor.setShouldTxnSetSelection(false);
+ }
+
+ // Move all the old child nodes to the element
+ var empty = true;
+ while (start != end) {
+ var next = start.nextSibling;
+ editor.deleteNode(start);
+ editor.insertNode(start, element, element.childNodes.length);
+ empty = false;
+ start = next;
+ }
+ if (!editor.nodeIsBlock(element)) {
+ editor.setShouldTxnSetSelection(true);
+ } else {
+ // Also move a trailing <br>
+ if (start && start.localName == "br") {
+ editor.deleteNode(start);
+ editor.insertNode(start, element, element.childNodes.length);
+ empty = false;
+ }
+ // Still nothing? Insert a <br> so the node is not empty
+ if (empty) {
+ editor.insertNode(
+ editor.createElementWithDefaults("br"),
+ element,
+ element.childNodes.length
+ );
+ }
+
+ // Hack to set the selection just inside the element
+ editor.insertNode(editor.document.createTextNode(""), element, offset);
+ }
+ } finally {
+ editor.endTransaction();
+ }
+
+ return true;
+}
+
+function nodeIsBlank(node) {
+ return node && node.nodeType == Node.TEXT_NODE && !/\S/.test(node.data);
+}
+
+function nodeBeginsBlock(editor, node) {
+ while (nodeIsBlank(node)) {
+ node = node.nextSibling;
+ }
+ return nodeIsBreak(editor, node);
+}
+
+function nodeEndsBlock(editor, node) {
+ while (nodeIsBlank(node)) {
+ node = node.previousSibling;
+ }
+ return nodeIsBreak(editor, node);
+}
+
+// C++ function isn't exposed to JS :-(
+function RemoveBlockContainer(element) {
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+
+ try {
+ var range = editor.document.createRange();
+ range.selectNode(element);
+ var offset = range.startOffset;
+ var parent = element.parentNode;
+
+ // May need to insert a break after the removed element
+ if (
+ !nodeBeginsBlock(editor, element.nextSibling) &&
+ !nodeEndsBlock(editor, element.lastChild)
+ ) {
+ editor.insertNode(
+ editor.createElementWithDefaults("br"),
+ parent,
+ range.endOffset
+ );
+ }
+
+ // May need to insert a break before the removed element, or if it was empty
+ if (
+ !nodeEndsBlock(editor, element.previousSibling) &&
+ !nodeBeginsBlock(editor, element.firstChild || element.nextSibling)
+ ) {
+ editor.insertNode(
+ editor.createElementWithDefaults("br"),
+ parent,
+ offset++
+ );
+ }
+
+ // Now remove the element
+ editor.deleteNode(element);
+
+ // Need to copy the contained nodes?
+ for (var i = 0; i < element.childNodes.length; i++) {
+ editor.insertNode(
+ element.childNodes[i].cloneNode(true),
+ parent,
+ offset++
+ );
+ }
+ } finally {
+ editor.endTransaction();
+ }
+}
+
+// C++ function isn't exposed to JS :-(
+function RemoveContainer(element) {
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+
+ try {
+ var range = editor.document.createRange();
+ var parent = element.parentNode;
+ // Allow for automatic joining of text nodes
+ // so we can't delete the container yet
+ // so we need to copy the contained nodes
+ for (var i = 0; i < element.childNodes.length; i++) {
+ range.selectNode(element);
+ editor.insertNode(
+ element.childNodes[i].cloneNode(true),
+ parent,
+ range.startOffset
+ );
+ }
+ // Now remove the element
+ editor.deleteNode(element);
+ } finally {
+ editor.endTransaction();
+ }
+}
+
+function FillLinkMenulist(linkMenulist, headingsArray) {
+ var menupopup = linkMenulist.firstChild;
+ var editor = GetCurrentEditor();
+ try {
+ var treeWalker = editor.document.createTreeWalker(
+ editor.document,
+ 1,
+ null,
+ true
+ );
+ var headingList = [];
+ var anchorList = []; // for sorting
+ var anchorMap = {}; // for weeding out duplicates and making heading anchors unique
+ var anchor;
+ var i;
+ for (
+ var element = treeWalker.nextNode();
+ element;
+ element = treeWalker.nextNode()
+ ) {
+ // grab headings
+ // Skip headings that already have a named anchor as their first child
+ // (this may miss nearby anchors, but at least we don't insert another
+ // under the same heading)
+ if (
+ element instanceof HTMLHeadingElement &&
+ element.textContent &&
+ !(
+ element.firstChild instanceof HTMLAnchorElement &&
+ element.firstChild.name
+ )
+ ) {
+ headingList.push(element);
+ }
+
+ // grab named anchors
+ if (element instanceof HTMLAnchorElement && element.name) {
+ anchor = "#" + element.name;
+ if (!(anchor in anchorMap)) {
+ anchorList.push({ anchor, sortkey: anchor.toLowerCase() });
+ anchorMap[anchor] = true;
+ }
+ }
+
+ // grab IDs
+ if (element.id) {
+ anchor = "#" + element.id;
+ if (!(anchor in anchorMap)) {
+ anchorList.push({ anchor, sortkey: anchor.toLowerCase() });
+ anchorMap[anchor] = true;
+ }
+ }
+ }
+ // add anchor for headings
+ for (i = 0; i < headingList.length; i++) {
+ var heading = headingList[i];
+
+ // Use just first 40 characters, don't add "...",
+ // and replace whitespace with "_" and strip non-word characters
+ anchor =
+ "#" +
+ ConvertToCDATAString(
+ TruncateStringAtWordEnd(heading.textContent, 40, false)
+ );
+
+ // Append "_" to any name already in the list
+ while (anchor in anchorMap) {
+ anchor += "_";
+ }
+ anchorList.push({ anchor, sortkey: anchor.toLowerCase() });
+ anchorMap[anchor] = true;
+
+ // Save nodes in an array so we can create anchor node under it later
+ headingsArray[anchor] = heading;
+ }
+ if (anchorList.length) {
+ // case insensitive sort
+ anchorList.sort((a, b) => {
+ if (a.sortkey < b.sortkey) {
+ return -1;
+ }
+ if (a.sortkey > b.sortkey) {
+ return 1;
+ }
+ return 0;
+ });
+
+ for (i = 0; i < anchorList.length; i++) {
+ createMenuItem(menupopup, anchorList[i].anchor);
+ }
+ } else {
+ // Don't bother with named anchors in Mail.
+ if (editor && editor.flags & Ci.nsIEditor.eEditorMailMask) {
+ menupopup.remove();
+ linkMenulist.removeAttribute("enablehistory");
+ return;
+ }
+ var item = createMenuItem(
+ menupopup,
+ GetString("NoNamedAnchorsOrHeadings")
+ );
+ item.setAttribute("disabled", "true");
+ }
+ } catch (e) {}
+}
+
+function createMenuItem(aMenuPopup, aLabel) {
+ var menuitem = document.createXULElement("menuitem");
+ menuitem.setAttribute("label", aLabel);
+ aMenuPopup.appendChild(menuitem);
+ return menuitem;
+}
+
+// Shared by Image and Link dialogs for the "Choose" button for links
+function chooseLinkFile() {
+ GetLocalFileURL("html, img").then(fileURL => {
+ // Always try to relativize local file URLs
+ if (gHaveDocumentUrl) {
+ fileURL = MakeRelativeUrl(fileURL);
+ }
+
+ gDialog.hrefInput.value = fileURL;
+
+ // Do stuff specific to a particular dialog
+ // (This is defined separately in Image and Link dialogs)
+ ChangeLinkLocation();
+ });
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdDialogTemplate.js b/comm/suite/editor/components/dialogs/content/EdDialogTemplate.js
new file mode 100644
index 0000000000..ee74e8c871
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdDialogTemplate.js
@@ -0,0 +1,45 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+// Cancel() is in EdDialogCommon.js
+var insertNew = true;
+var tagname = "TAG NAME";
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ if (!GetCurrentEditor()) {
+ window.close();
+ return;
+ }
+ // gDialog is declared in EdDialogCommon.js
+ // Set commonly-used widgets like this:
+ gDialog.fooButton = document.getElementById("fooButton");
+
+ InitDialog();
+
+ // Set window location relative to parent window (based on persisted attributes)
+ SetWindowLocation();
+
+ // Set focus to first widget in dialog, e.g.:
+ SetTextboxFocus(gDialog.fooButton);
+}
+
+function InitDialog() {
+ // Initialize all dialog widgets here,
+ // e.g., get attributes from an element for property dialog
+}
+
+function onAccept() {
+ // 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.
+
+ SaveWindowLocation();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdDialogTemplate.xhtml b/comm/suite/editor/components/dialogs/content/EdDialogTemplate.xhtml
new file mode 100644
index 0000000000..8f76af4654
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdDialogTemplate.xhtml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EdDialogOverlay.xhtml"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/Ed?????????.dtd">
+<!-- dialog containing a control requiring initial setup -->
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/Ed?????.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdDictionary.js b/comm/suite/editor/components/dialogs/content/EdDictionary.js
new file mode 100644
index 0000000000..892e92dd1a
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdDictionary.js
@@ -0,0 +1,164 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var gSpellChecker;
+var gWordToAdd;
+
+function Startup() {
+ if (!GetCurrentEditor()) {
+ window.close();
+ return;
+ }
+ // Get the SpellChecker shell
+ if ("gSpellChecker" in window.opener && window.opener.gSpellChecker) {
+ gSpellChecker = window.opener.gSpellChecker;
+ }
+
+ if (!gSpellChecker) {
+ dump("SpellChecker not found!!!\n");
+ window.close();
+ return;
+ }
+ // The word to add word is passed as the 2nd extra parameter in window.openDialog()
+ gWordToAdd = window.arguments[1];
+
+ gDialog.WordInput = document.getElementById("WordInput");
+ gDialog.DictionaryList = document.getElementById("DictionaryList");
+
+ gDialog.WordInput.value = gWordToAdd;
+ FillDictionaryList();
+
+ // Select the supplied word if it is already in the list
+ SelectWordToAddInList();
+ SetTextboxFocus(gDialog.WordInput);
+}
+
+function ValidateWordToAdd() {
+ gWordToAdd = TrimString(gDialog.WordInput.value);
+ if (gWordToAdd.length > 0) {
+ return true;
+ }
+ return false;
+}
+
+function SelectWordToAddInList() {
+ for (var i = 0; i < gDialog.DictionaryList.getRowCount(); i++) {
+ var wordInList = gDialog.DictionaryList.getItemAtIndex(i);
+ if (wordInList && gWordToAdd == wordInList.label) {
+ gDialog.DictionaryList.selectedIndex = i;
+ break;
+ }
+ }
+}
+
+function AddWord() {
+ if (ValidateWordToAdd()) {
+ try {
+ gSpellChecker.AddWordToDictionary(gWordToAdd);
+ } catch (e) {
+ dump(
+ "Exception occurred in gSpellChecker.AddWordToDictionary\nWord to add probably already existed\n"
+ );
+ }
+
+ // Rebuild the dialog list
+ FillDictionaryList();
+
+ SelectWordToAddInList();
+ gDialog.WordInput.value = "";
+ }
+}
+
+function ReplaceWord() {
+ if (ValidateWordToAdd()) {
+ var selItem = gDialog.DictionaryList.selectedItem;
+ if (selItem) {
+ try {
+ gSpellChecker.RemoveWordFromDictionary(selItem.label);
+ } catch (e) {}
+
+ try {
+ // Add to the dictionary list
+ gSpellChecker.AddWordToDictionary(gWordToAdd);
+
+ // Just change the text on the selected item instead of rebuilding the list.
+ // The items are richlist items, so the label sits in the first child.
+ selItem.firstChild.setAttribute("value", gWordToAdd);
+ } catch (e) {
+ // Rebuild list and select the word - it was probably already in the list
+ dump("Exception occurred adding word in ReplaceWord\n");
+ FillDictionaryList();
+ SelectWordToAddInList();
+ }
+ }
+ }
+}
+
+function RemoveWord() {
+ var selIndex = gDialog.DictionaryList.selectedIndex;
+ if (selIndex >= 0) {
+ var word = gDialog.DictionaryList.selectedItem.label;
+
+ // Remove word from list
+ gDialog.DictionaryList.selectedItem.remove();
+
+ // Remove from dictionary
+ try {
+ // Not working: BUG 43348
+ gSpellChecker.RemoveWordFromDictionary(word);
+ } catch (e) {
+ dump("Failed to remove word from dictionary\n");
+ }
+
+ ResetSelectedItem(selIndex);
+ }
+}
+
+function FillDictionaryList() {
+ var selIndex = gDialog.DictionaryList.selectedIndex;
+
+ // Clear the current contents of the list
+ ClearListbox(gDialog.DictionaryList);
+
+ // Get the list from the spell checker
+ gSpellChecker.GetPersonalDictionary();
+
+ var haveList = false;
+
+ // Get words until an empty string is returned
+ do {
+ var word = gSpellChecker.GetPersonalDictionaryWord();
+ if (word != "") {
+ gDialog.DictionaryList.appendItem(word, "");
+ haveList = true;
+ }
+ } while (word != "");
+
+ // XXX: BUG 74467: If list is empty, it doesn't layout to full height correctly
+ // (ignores "rows" attribute) (bug is latered, so we are fixing here for now)
+ if (!haveList) {
+ gDialog.DictionaryList.appendItem("", "");
+ }
+
+ ResetSelectedItem(selIndex);
+}
+
+function ResetSelectedItem(index) {
+ var lastIndex = gDialog.DictionaryList.getRowCount() - 1;
+ if (index > lastIndex) {
+ index = lastIndex;
+ }
+
+ // If we didn't have a selected item,
+ // set it to the first item
+ if (index == -1 && lastIndex >= 0) {
+ index = 0;
+ }
+
+ gDialog.DictionaryList.selectedIndex = index;
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdDictionary.xhtml b/comm/suite/editor/components/dialogs/content/EdDictionary.xhtml
new file mode 100644
index 0000000000..cebbe1c192
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdDictionary.xhtml
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorPersonalDictionary.dtd">
+<dialog buttons="cancel" title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ persist="screenX screenY"
+ onload="Startup()">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdDictionary.js"/>
+
+ <grid>
+ <columns><column style="width: 15em" flex="1"/><column flex="1"/></columns>
+ <rows>
+ <row>
+ <label value="&wordEditField.label;"
+ control="WordInput"
+ accesskey="&wordEditField.accessKey;"/>
+ <spacer/>
+ </row>
+ <row>
+ <textbox id="WordInput" flex="1"/>
+ <button id="AddWord" oncommand="AddWord()" label="&AddButton.label;"
+ accesskey="&AddButton.accessKey;"/>
+ </row>
+ <row>
+ <label value="&DictionaryList.label;"
+ control="DictionaryList"
+ accesskey="&DictionaryList.accessKey;"/>
+ <spacer/>
+ </row>
+ <row>
+ <richlistbox id="DictionaryList"
+ class="theme-listbox"
+ flex="1"
+ height="150px"/>
+ <vbox flex="1">
+ <button id="ReplaceWord" oncommand="ReplaceWord()" label="&ReplaceButton.label;"
+ accesskey="&ReplaceButton.accessKey;"/>
+ <spacer class="spacer"/>
+ <button id="RemoveWord" oncommand="RemoveWord()" label="&RemoveButton.label;"
+ accesskey="&RemoveButton.accessKey;"/>
+ <spacer class="spacer"/>
+ <spacer flex="1"/>
+ <button dlgtype="cancel" class="exit-dialog" id="close" label="&CloseButton.label;"
+ default="true" oncommand="onClose();"
+ accesskey="&CloseButton.accessKey;"/>
+ </vbox>
+ </row>
+ </rows>
+ </grid>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdFieldSetProps.js b/comm/suite/editor/components/dialogs/content/EdFieldSetProps.js
new file mode 100644
index 0000000000..1799a2b28f
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdFieldSetProps.js
@@ -0,0 +1,196 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var insertNew;
+var fieldsetElement;
+var newLegend;
+var legendElement;
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ dump("Failed to get active editor!\n");
+ window.close();
+ return;
+ }
+
+ gDialog.editText = document.getElementById("EditText");
+ gDialog.legendText = document.getElementById("LegendText");
+ gDialog.legendAlign = document.getElementById("LegendAlign");
+ gDialog.RemoveFieldSet = document.getElementById("RemoveFieldSet");
+
+ // Get a single selected field set element
+ const kTagName = "fieldset";
+ try {
+ // Find a selected fieldset, or if one is at start or end of selection.
+ fieldsetElement = editor.getSelectedElement(kTagName);
+ if (!fieldsetElement) {
+ fieldsetElement = editor.getElementOrParentByTagName(
+ kTagName,
+ editor.selection.anchorNode
+ );
+ }
+ if (!fieldsetElement) {
+ fieldsetElement = editor.getElementOrParentByTagName(
+ kTagName,
+ editor.selection.focusNode
+ );
+ }
+ } catch (e) {}
+
+ if (fieldsetElement) {
+ // We found an element and don't need to insert one
+ insertNew = false;
+ } else {
+ insertNew = true;
+
+ // We don't have an element selected,
+ // so create one with default attributes
+ try {
+ fieldsetElement = editor.createElementWithDefaults(kTagName);
+ } catch (e) {}
+
+ if (!fieldsetElement) {
+ dump("Failed to get selected element or create a new one!\n");
+ window.close();
+ return;
+ }
+ // Hide button removing existing fieldset
+ gDialog.RemoveFieldSet.hidden = true;
+ }
+
+ legendElement = fieldsetElement.querySelector("legend");
+ if (legendElement) {
+ newLegend = false;
+ var range = editor.document.createRange();
+ range.selectNode(legendElement);
+ gDialog.legendText.value = range.toString();
+ if (legendElement.innerHTML.includes("<")) {
+ gDialog.editText.checked = false;
+ gDialog.editText.disabled = false;
+ gDialog.legendText.disabled = true;
+ gDialog.editText.addEventListener(
+ "command",
+ () =>
+ Services.prompt.alert(
+ window,
+ GetString("Alert"),
+ GetString("EditTextWarning")
+ ),
+ { capture: false, once: true }
+ );
+ gDialog.RemoveFieldSet.focus();
+ } else {
+ SetTextboxFocus(gDialog.legendText);
+ }
+ } else {
+ newLegend = true;
+
+ // We don't have an element selected,
+ // so create one with default attributes
+
+ legendElement = editor.createElementWithDefaults("legend");
+ if (!legendElement) {
+ dump("Failed to get selected element or create a new one!\n");
+ window.close();
+ return;
+ }
+ SetTextboxFocus(gDialog.legendText);
+ }
+
+ // Make a copy to use for AdvancedEdit
+ globalElement = legendElement.cloneNode(false);
+
+ InitDialog();
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ gDialog.legendAlign.value = GetHTMLOrCSSStyleValue(
+ globalElement,
+ "align",
+ "caption-side"
+ );
+}
+
+function RemoveFieldSet() {
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+ try {
+ if (!newLegend) {
+ editor.deleteNode(legendElement);
+ }
+ RemoveBlockContainer(fieldsetElement);
+ } finally {
+ editor.endTransaction();
+ }
+ SaveWindowLocation();
+ window.close();
+}
+
+function ValidateData() {
+ if (gDialog.legendAlign.value) {
+ globalElement.setAttribute("align", gDialog.legendAlign.value);
+ } else {
+ globalElement.removeAttribute("align");
+ }
+ return true;
+}
+
+function onAccept() {
+ // All values are valid - copy to actual element in doc
+ ValidateData();
+
+ var editor = GetCurrentEditor();
+
+ editor.beginTransaction();
+
+ try {
+ editor.cloneAttributes(legendElement, globalElement);
+
+ if (insertNew) {
+ if (gDialog.legendText.value) {
+ fieldsetElement.appendChild(legendElement);
+ legendElement.appendChild(
+ editor.document.createTextNode(gDialog.legendText.value)
+ );
+ }
+ InsertElementAroundSelection(fieldsetElement);
+ } else if (gDialog.editText.checked) {
+ editor.setShouldTxnSetSelection(false);
+
+ if (gDialog.legendText.value) {
+ if (newLegend) {
+ editor.insertNode(legendElement, fieldsetElement, 0);
+ } else {
+ while (legendElement.firstChild) {
+ editor.deleteNode(legendElement.lastChild);
+ }
+ }
+ editor.insertNode(
+ editor.document.createTextNode(gDialog.legendText.value),
+ legendElement,
+ 0
+ );
+ } else if (!newLegend) {
+ editor.deleteNode(legendElement);
+ }
+
+ editor.setShouldTxnSetSelection(true);
+ }
+ } finally {
+ editor.endTransaction();
+ }
+
+ SaveWindowLocation();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdFieldSetProps.xhtml b/comm/suite/editor/components/dialogs/content/EdFieldSetProps.xhtml
new file mode 100644
index 0000000000..0d67fad276
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdFieldSetProps.xhtml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edFieldSetProperties SYSTEM "chrome://editor/locale/EditorFieldSetProperties.dtd">
+%edFieldSetProperties;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup();"
+ buttons="accept,cancel">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdFieldSetProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header" accesskey="&Legend.accesskey;">&Legend.label;</label>
+ </hbox>
+ <grid><columns><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <checkbox id="EditText" label="&EditLegendText.label;" accesskey="&EditLegendText.accesskey;" checked="true" disabled="true"
+ oncommand="gDialog.legendText.disabled = !gDialog.editText.checked;"/>
+ <textbox id="LegendText" accesskey="&Legend.accesskey;"/>
+ </row>
+ <row align="center">
+ <label control="LegendAlign" value="&LegendAlign.label;" accesskey="&LegendAlign.accesskey;"/>
+ <menulist id="LegendAlign">
+ <menupopup>
+ <menuitem label="&AlignDefault.label;"/>
+ <menuitem label="&AlignLeft.label;" value="left"/>
+ <menuitem label="&AlignCenter.label;" value="center"/>
+ <menuitem label="&AlignRight.label;" value="right"/>
+ </menupopup>
+ </menulist>
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+
+ <!-- from EdDialogOverlay -->
+ <hbox flex="1" style="margin-top: 0.2em">
+ <button id="RemoveFieldSet" label="&RemoveFieldSet.label;" accesskey="&RemoveFieldSet.accesskey;" oncommand="RemoveFieldSet();"/>
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton"
+ oncommand="onAdvancedEdit();"
+ label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;"
+ tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator class="groove"/>
+
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdFormProps.js b/comm/suite/editor/components/dialogs/content/EdFormProps.js
new file mode 100644
index 0000000000..9391fa4316
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdFormProps.js
@@ -0,0 +1,136 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var gForm;
+var insertNew;
+var formElement;
+var formActionWarning;
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ dump("Failed to get active editor!\n");
+ window.close();
+ return;
+ }
+
+ gForm = {
+ Name: document.getElementById("FormName"),
+ Action: document.getElementById("FormAction"),
+ Method: document.getElementById("FormMethod"),
+ EncType: document.getElementById("FormEncType"),
+ Target: document.getElementById("FormTarget"),
+ };
+ gDialog.MoreSection = document.getElementById("MoreSection");
+ gDialog.MoreFewerButton = document.getElementById("MoreFewerButton");
+ gDialog.RemoveForm = document.getElementById("RemoveForm");
+
+ // Get a single selected form element
+ const kTagName = "form";
+ try {
+ formElement = editor.getSelectedElement(kTagName);
+ if (!formElement) {
+ formElement = editor.getElementOrParentByTagName(
+ kTagName,
+ editor.selection.anchorNode
+ );
+ }
+ if (!formElement) {
+ formElement = editor.getElementOrParentByTagName(
+ kTagName,
+ editor.selection.focusNode
+ );
+ }
+ } catch (e) {}
+
+ if (formElement) {
+ // We found an element and don't need to insert one
+ insertNew = false;
+ formActionWarning = formElement.hasAttribute("action");
+ } else {
+ insertNew = true;
+ formActionWarning = true;
+
+ // We don't have an element selected,
+ // so create one with default attributes
+ try {
+ formElement = editor.createElementWithDefaults(kTagName);
+ } catch (e) {}
+
+ if (!formElement) {
+ dump("Failed to get selected element or create a new one!\n");
+ window.close();
+ return;
+ }
+ // Hide button removing existing form
+ gDialog.RemoveForm.hidden = true;
+ }
+
+ // Make a copy to use for AdvancedEdit
+ globalElement = formElement.cloneNode(false);
+
+ InitDialog();
+
+ InitMoreFewer();
+
+ SetTextboxFocus(gForm.Name);
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ for (var attribute in gForm) {
+ gForm[attribute].value = globalElement.getAttribute(attribute);
+ }
+}
+
+function RemoveForm() {
+ RemoveBlockContainer(formElement);
+ SaveWindowLocation();
+ window.close();
+}
+
+function ValidateData() {
+ for (var attribute in gForm) {
+ if (gForm[attribute].value) {
+ globalElement.setAttribute(attribute, gForm[attribute].value);
+ } else {
+ globalElement.removeAttribute(attribute);
+ }
+ }
+ return true;
+}
+
+function onAccept(event) {
+ if (formActionWarning && !gForm.Action.value) {
+ Services.prompt.alert(
+ window,
+ GetString("Alert"),
+ GetString("NoFormAction")
+ );
+ gForm.Action.focus();
+ formActionWarning = false;
+ event.preventDefault();
+ return;
+ }
+ // All values are valid - copy to actual element in doc or
+ // element created to insert
+ ValidateData();
+
+ var editor = GetCurrentEditor();
+
+ editor.cloneAttributes(formElement, globalElement);
+
+ if (insertNew) {
+ InsertElementAroundSelection(formElement);
+ }
+
+ SaveWindowLocation();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdFormProps.xhtml b/comm/suite/editor/components/dialogs/content/EdFormProps.xhtml
new file mode 100644
index 0000000000..275daef785
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdFormProps.xhtml
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+<?xml-stylesheet href="chrome://messenger/skin/menulist.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edFormProperties SYSTEM "chrome://editor/locale/EditorFormProperties.dtd">
+%edFormProperties;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup();"
+ buttons="accept,cancel">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdFormProps.js"/>
+
+ <script src="chrome://messenger/content/customElements.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&Settings.label;</label>
+ </hbox>
+ <grid><columns><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <label control="FormName" value="&FormName.label;" accesskey="&FormName.accesskey;"/>
+ <textbox id="FormName"/>
+ </row>
+ <row align="center">
+ <label control="FormAction" value="&FormAction.label;" accesskey="&FormAction.accesskey;"/>
+ <textbox id="FormAction"/>
+ </row>
+ <row align="center">
+ <label control="FormMethod" value="&FormMethod.label;" accesskey="&FormMethod.accesskey;"/>
+ <hbox>
+ <menulist is="menulist-editable" id="FormMethod" editable="true" autoSelectMenuitem="true">
+ <menupopup>
+ <menuitem label="GET"/>
+ <menuitem label="POST"/>
+ </menupopup>
+ </menulist>
+ </hbox>
+ </row>
+ <hbox>
+ <button id="MoreFewerButton" oncommand="onMoreFewer();" persist="more"/>
+ </hbox>
+ <rows id="MoreSection">
+ <row align="center">
+ <label control="FormEncType" value="&FormEncType.label;" accesskey="&FormEncType.accesskey;"/>
+ <menulist is="menulist-editable" id="FormEncType" editable="true" autoSelectMenuitem="true">
+ <menupopup>
+ <menuitem label="application/x-www-form-urlencoded"/>
+ <menuitem label="multipart/form-data"/>
+ <menuitem label="text/plain"/>
+ </menupopup>
+ </menulist>
+ </row>
+ <row align="center">
+ <label control="FormTarget" value="&FormTarget.label;" accesskey="&FormTarget.accesskey;"/>
+ <menulist is="menulist-editable" id="FormTarget" editable="true" autoSelectMenuitem="true">
+ <menupopup>
+ <menuitem label="_blank"/>
+ <menuitem label="_self"/>
+ <menuitem label="_parent"/>
+ <menuitem label="_top"/>
+ </menupopup>
+ </menulist>
+ </row>
+ </rows>
+ </rows>
+ </grid>
+ </groupbox>
+
+ <!-- from EdDialogOverlay -->
+ <hbox flex="1" style="margin-top: 0.2em">
+ <button id="RemoveForm" label="&RemoveForm.label;" accesskey="&RemoveForm.accesskey;" oncommand="RemoveForm();"/>
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton"
+ oncommand="onAdvancedEdit();"
+ label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;"
+ tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdHLineProps.js b/comm/suite/editor/components/dialogs/content/EdHLineProps.js
new file mode 100644
index 0000000000..eff9c06a41
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdHLineProps.js
@@ -0,0 +1,227 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var tagName = "hr";
+var gHLineElement;
+var width;
+var height;
+var align;
+var shading;
+const gMaxHRSize = 1000; // This is hard-coded in nsHTMLHRElement::StringToAttribute()
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ window.close();
+ return;
+ }
+ try {
+ // Get the selected horizontal line
+ gHLineElement = editor.getSelectedElement(tagName);
+ } catch (e) {}
+
+ if (!gHLineElement) {
+ // We should never be here if not editing an existing HLine
+ window.close();
+ return;
+ }
+ gDialog.heightInput = document.getElementById("height");
+ gDialog.widthInput = document.getElementById("width");
+ gDialog.leftAlign = document.getElementById("leftAlign");
+ gDialog.centerAlign = document.getElementById("centerAlign");
+ gDialog.rightAlign = document.getElementById("rightAlign");
+ gDialog.alignGroup = gDialog.rightAlign.radioGroup;
+ gDialog.shading = document.getElementById("3dShading");
+ gDialog.pixelOrPercentMenulist = document.getElementById(
+ "pixelOrPercentMenulist"
+ );
+
+ // Make a copy to use for AdvancedEdit and onSaveDefault
+ globalElement = gHLineElement.cloneNode(false);
+
+ // Initialize control values based on existing attributes
+ InitDialog();
+
+ // SET FOCUS TO FIRST CONTROL
+ SetTextboxFocus(gDialog.widthInput);
+
+ // Resize window
+ window.sizeToContent();
+
+ SetWindowLocation();
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+// by AdvancedEdit(), which is shared by all property dialogs
+function InitDialog() {
+ // Just to be confusing, "size" is used instead of height because it does
+ // not accept % values, only pixels
+ var height = GetHTMLOrCSSStyleValue(globalElement, "size", "height");
+ if (height.includes("px")) {
+ height = height.substr(0, height.indexOf("px"));
+ }
+ if (!height) {
+ height = 2; // Default value
+ }
+
+ // We will use "height" here and in UI
+ gDialog.heightInput.value = height;
+
+ // Get the width attribute of the element, stripping out "%"
+ // This sets contents of menulist (adds pixel and percent menuitems elements)
+ gDialog.widthInput.value = InitPixelOrPercentMenulist(
+ globalElement,
+ gHLineElement,
+ "width",
+ "pixelOrPercentMenulist"
+ );
+
+ var marginLeft = GetHTMLOrCSSStyleValue(
+ globalElement,
+ "align",
+ "margin-left"
+ ).toLowerCase();
+ var marginRight = GetHTMLOrCSSStyleValue(
+ globalElement,
+ "align",
+ "margin-right"
+ ).toLowerCase();
+ align = marginLeft + " " + marginRight;
+ gDialog.leftAlign.checked = align == "left left" || align == "0px auto";
+ gDialog.centerAlign.checked =
+ align == "center center" || align == "auto auto" || align == " ";
+ gDialog.rightAlign.checked = align == "right right" || align == "auto 0px";
+
+ if (gDialog.centerAlign.checked) {
+ gDialog.alignGroup.selectedItem = gDialog.centerAlign;
+ } else if (gDialog.rightAlign.checked) {
+ gDialog.alignGroup.selectedItem = gDialog.rightAlign;
+ } else {
+ gDialog.alignGroup.selectedItem = gDialog.leftAlign;
+ }
+
+ gDialog.shading.checked = !globalElement.hasAttribute("noshade");
+}
+
+function onSaveDefault() {
+ // "false" means set attributes on the globalElement,
+ // not the real element being edited
+ if (ValidateData()) {
+ var alignInt;
+ if (align == "left") {
+ alignInt = 0;
+ } else if (align == "right") {
+ alignInt = 2;
+ } else {
+ alignInt = 1;
+ }
+ Services.prefs.setIntPref("editor.hrule.align", alignInt);
+
+ var percent;
+ var widthInt;
+ var heightInt;
+
+ if (width) {
+ if (width.includes("%")) {
+ percent = true;
+ widthInt = Number(width.substr(0, width.indexOf("%")));
+ } else {
+ percent = false;
+ widthInt = Number(width);
+ }
+ } else {
+ percent = true;
+ widthInt = Number(100);
+ }
+
+ heightInt = height ? Number(height) : 2;
+
+ Services.prefs.setIntPref("editor.hrule.width", widthInt);
+ Services.prefs.setBoolPref("editor.hrule.width_percent", percent);
+ Services.prefs.setIntPref("editor.hrule.height", heightInt);
+ Services.prefs.setBoolPref("editor.hrule.shading", shading);
+
+ // Write the prefs out NOW!
+ Services.prefs.savePrefFile(null);
+ }
+}
+
+// Get and validate data from widgets.
+// Set attributes on globalElement so they can be accessed by AdvancedEdit()
+function ValidateData() {
+ // Height is always pixels
+ height = ValidateNumber(
+ gDialog.heightInput,
+ null,
+ 1,
+ gMaxHRSize,
+ globalElement,
+ "size",
+ false
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ width = ValidateNumber(
+ gDialog.widthInput,
+ gDialog.pixelOrPercentMenulist,
+ 1,
+ gMaxPixels,
+ globalElement,
+ "width",
+ false
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ align = "left";
+ if (gDialog.centerAlign.selected) {
+ // Don't write out default attribute
+ align = "";
+ } else if (gDialog.rightAlign.selected) {
+ align = "right";
+ }
+ if (align) {
+ globalElement.setAttribute("align", align);
+ } else {
+ try {
+ GetCurrentEditor().removeAttributeOrEquivalent(
+ globalElement,
+ "align",
+ true
+ );
+ } catch (e) {}
+ }
+
+ if (gDialog.shading.checked) {
+ shading = true;
+ globalElement.removeAttribute("noshade");
+ } else {
+ shading = false;
+ globalElement.setAttribute("noshade", "noshade");
+ }
+ return true;
+}
+
+function onAccept(event) {
+ if (ValidateData()) {
+ // Copy attributes from the globalElement to the document element
+ try {
+ GetCurrentEditor().cloneAttributes(gHLineElement, globalElement);
+ } catch (e) {}
+ return;
+ }
+ event.preventDefault();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdHLineProps.xhtml b/comm/suite/editor/components/dialogs/content/EdHLineProps.xhtml
new file mode 100644
index 0000000000..fbcfa3b594
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdHLineProps.xhtml
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edHLineProperties SYSTEM "chrome://editor/locale/EditorHLineProperties.dtd">
+%edHLineProperties;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <!--- Element-specific methods -->
+ <script src="chrome://editor/content/EdHLineProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&dimensionsBox.label;</label>
+ </hbox>
+ <grid>
+ <columns><column/><column/><column /></columns>
+ <rows>
+ <row align="center">
+ <label control="width"
+ value="&widthEditField.label;"
+ accesskey="&widthEditField.accessKey;"/>
+ <textbox class="narrow" id="width" flex="1" oninput="forceInteger('width')"/>
+ <menulist id="pixelOrPercentMenulist" />
+ <!-- menupopup and menuitems added by JS -->
+ </row>
+ <row align="center">
+ <label control="height"
+ value="&heightEditField.label;"
+ accesskey="&heightEditField.accessKey;"/>
+ <textbox class="narrow" id="height" oninput="forceInteger('height')"/>
+ <label value="&pixelsPopup.value;" />
+ </row>
+ </rows>
+ </grid>
+ <checkbox id="3dShading" label="&threeDShading.label;" accesskey="&threeDShading.accessKey;"/>
+ </groupbox>
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&alignmentBox.label;</label>
+ </hbox>
+ <radiogroup id="alignmentGroup" orient="horizontal">
+ <spacer class="spacer"/>
+ <radio id="leftAlign" label="&leftRadio.label;" accesskey="&leftRadio.accessKey;"/>
+ <radio id="centerAlign" label="&centerRadio.label;" accesskey="&centerRadio.accessKey;"/>
+ <radio id="rightAlign" label="&rightRadio.label;" accesskey="&rightRadio.accessKey;"/>
+ </radiogroup>
+ </groupbox>
+ <spacer class="spacer"/>
+ <hbox>
+ <button id="SaveDefault" label="&saveSettings.label;"
+ accesskey="&saveSettings.accessKey;"
+ oncommand="onSaveDefault()"
+ tooltiptext="&saveSettings.tooltip;" />
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton"
+ oncommand="onAdvancedEdit();"
+ label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;"
+ tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdImageDialog.js b/comm/suite/editor/components/dialogs/content/EdImageDialog.js
new file mode 100644
index 0000000000..0e697dbd6f
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdImageDialog.js
@@ -0,0 +1,661 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ Note: We encourage non-empty alt text for images inserted into a page.
+ When there's no alt text, we always write 'alt=""' as the attribute, since "alt" is a required attribute.
+ We allow users to not have alt text by checking a "Don't use alterate text" radio button,
+ and we don't accept spaces as valid alt text. A space used to be required to avoid the error message
+ if user didn't enter alt text, but is unnecessary now that we no longer annoy the user
+ with the error dialog if alt="" is present on an img element.
+ We trim all spaces at the beginning and end of user's alt text
+*/
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var gInsertNewImage = true;
+var gDoAltTextError = false;
+var gConstrainOn = false;
+// Note used in current version, but these are set correctly
+// and could be used to reset width and height used for constrain ratio
+var gConstrainWidth = 0;
+var gConstrainHeight = 0;
+var imageElement;
+var gImageMap = 0;
+var gCanRemoveImageMap = false;
+var gRemoveImageMap = false;
+var gImageMapDisabled = false;
+var gActualWidth = "";
+var gActualHeight = "";
+var gOriginalSrc = "";
+var gTimerID;
+var gValidateTab;
+var gInsertNewIMap;
+
+// These must correspond to values in EditorDialog.css for each theme
+// (unfortunately, setting "style" attribute here doesn't work!)
+var gPreviewImageWidth = 80;
+var gPreviewImageHeight = 50;
+
+// dialog initialization code
+
+function ImageStartup() {
+ gDialog.tabBox = document.getElementById("TabBox");
+ gDialog.tabLocation = document.getElementById("imageLocationTab");
+ gDialog.tabDimensions = document.getElementById("imageDimensionsTab");
+ gDialog.tabBorder = document.getElementById("imageBorderTab");
+ gDialog.srcInput = document.getElementById("srcInput");
+ gDialog.titleInput = document.getElementById("titleInput");
+ gDialog.altTextInput = document.getElementById("altTextInput");
+ gDialog.altTextRadioGroup = document.getElementById("altTextRadioGroup");
+ gDialog.altTextRadio = document.getElementById("altTextRadio");
+ gDialog.noAltTextRadio = document.getElementById("noAltTextRadio");
+ gDialog.actualSizeRadio = document.getElementById("actualSizeRadio");
+ gDialog.constrainCheckbox = document.getElementById("constrainCheckbox");
+ gDialog.widthInput = document.getElementById("widthInput");
+ gDialog.heightInput = document.getElementById("heightInput");
+ gDialog.widthUnitsMenulist = document.getElementById("widthUnitsMenulist");
+ gDialog.heightUnitsMenulist = document.getElementById("heightUnitsMenulist");
+ gDialog.imagelrInput = document.getElementById("imageleftrightInput");
+ gDialog.imagetbInput = document.getElementById("imagetopbottomInput");
+ gDialog.border = document.getElementById("border");
+ gDialog.alignTypeSelect = document.getElementById("alignTypeSelect");
+ gDialog.ImageHolder = document.getElementById("preview-image-holder");
+ gDialog.PreviewWidth = document.getElementById("PreviewWidth");
+ gDialog.PreviewHeight = document.getElementById("PreviewHeight");
+ gDialog.PreviewSize = document.getElementById("PreviewSize");
+ gDialog.PreviewImage = null;
+ gDialog.OkButton = document.documentElement.getButton("accept");
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+// by AdvancedEdit(), which is shared by all property dialogs
+function InitImage() {
+ // Set the controls to the image's attributes
+ var src = globalElement.getAttribute("src");
+
+ // For image insertion the 'src' attribute is null.
+ if (src) {
+ // Shorten data URIs for display.
+ shortenImageData(src, gDialog.srcInput);
+ }
+
+ // Set "Relativize" checkbox according to current URL state
+ SetRelativeCheckbox();
+
+ // Force loading of image from its source and show preview image
+ LoadPreviewImage();
+
+ gDialog.titleInput.value = globalElement.getAttribute("title");
+
+ var hasAltText = globalElement.hasAttribute("alt");
+ var altText = globalElement.getAttribute("alt");
+ gDialog.altTextInput.value = altText;
+ if (altText || (!hasAltText && globalElement.hasAttribute("src"))) {
+ gDialog.altTextRadioGroup.selectedItem = gDialog.altTextRadio;
+ } else if (hasAltText) {
+ gDialog.altTextRadioGroup.selectedItem = gDialog.noAltTextRadio;
+ }
+ SetAltTextDisabled(
+ gDialog.altTextRadioGroup.selectedItem == gDialog.noAltTextRadio
+ );
+
+ // setup the height and width widgets
+ var width = InitPixelOrPercentMenulist(
+ globalElement,
+ gInsertNewImage ? null : imageElement,
+ "width",
+ "widthUnitsMenulist",
+ gPixel
+ );
+ var height = InitPixelOrPercentMenulist(
+ globalElement,
+ gInsertNewImage ? null : imageElement,
+ "height",
+ "heightUnitsMenulist",
+ gPixel
+ );
+
+ // Set actual radio button if both set values are the same as actual
+ SetSizeWidgets(width, height);
+
+ gDialog.widthInput.value = gConstrainWidth = width || gActualWidth || "";
+ gDialog.heightInput.value = gConstrainHeight = height || gActualHeight || "";
+
+ // set spacing editfields
+ gDialog.imagelrInput.value = globalElement.getAttribute("hspace");
+ gDialog.imagetbInput.value = globalElement.getAttribute("vspace");
+
+ // dialog.border.value = globalElement.getAttribute("border");
+ var bv = GetHTMLOrCSSStyleValue(globalElement, "border", "border-top-width");
+ if (bv.includes("px")) {
+ // Strip out the px
+ bv = bv.substr(0, bv.indexOf("px"));
+ } else if (bv == "thin") {
+ bv = "1";
+ } else if (bv == "medium") {
+ bv = "3";
+ } else if (bv == "thick") {
+ bv = "5";
+ }
+ gDialog.border.value = bv;
+
+ // Get alignment setting
+ var align = globalElement.getAttribute("align");
+ if (align) {
+ align = align.toLowerCase();
+ }
+
+ switch (align) {
+ case "top":
+ case "middle":
+ case "right":
+ case "left":
+ gDialog.alignTypeSelect.value = align;
+ break;
+ default:
+ // Default or "bottom"
+ gDialog.alignTypeSelect.value = "bottom";
+ }
+
+ // Get image map for image
+ gImageMap = GetImageMap();
+
+ doOverallEnabling();
+ doDimensionEnabling();
+}
+
+function SetSizeWidgets(width, height) {
+ if (
+ !(width || height) ||
+ (gActualWidth &&
+ gActualHeight &&
+ width == gActualWidth &&
+ height == gActualHeight)
+ ) {
+ gDialog.actualSizeRadio.radioGroup.selectedItem = gDialog.actualSizeRadio;
+ }
+
+ if (!gDialog.actualSizeRadio.selected) {
+ // Decide if user's sizes are in the same ratio as actual sizes
+ if (gActualWidth && gActualHeight) {
+ if (gActualWidth > gActualHeight) {
+ gDialog.constrainCheckbox.checked =
+ Math.round((gActualHeight * width) / gActualWidth) == height;
+ } else {
+ gDialog.constrainCheckbox.checked =
+ Math.round((gActualWidth * height) / gActualHeight) == width;
+ }
+ }
+ }
+}
+
+// Disable alt text input when "Don't use alt" radio is checked
+function SetAltTextDisabled(disable) {
+ gDialog.altTextInput.disabled = disable;
+}
+
+function GetImageMap() {
+ var usemap = globalElement.getAttribute("usemap");
+ if (usemap) {
+ gCanRemoveImageMap = true;
+ let mapname = usemap.substr(1);
+ try {
+ return GetCurrentEditor().document.querySelector(
+ '[name="' + mapname + '"]'
+ );
+ } catch (e) {}
+ } else {
+ gCanRemoveImageMap = false;
+ }
+
+ return null;
+}
+
+function chooseFile() {
+ if (gTimerID) {
+ clearTimeout(gTimerID);
+ }
+
+ // Put focus into the input field
+ SetTextboxFocus(gDialog.srcInput);
+
+ GetLocalFileURL("img").then(fileURL => {
+ // Always try to relativize local file URLs
+ if (gHaveDocumentUrl) {
+ fileURL = MakeRelativeUrl(fileURL);
+ }
+
+ gDialog.srcInput.value = fileURL;
+
+ SetRelativeCheckbox();
+ doOverallEnabling();
+ LoadPreviewImage();
+ });
+}
+
+function PreviewImageLoaded() {
+ if (gDialog.PreviewImage) {
+ // Image loading has completed -- we can get actual width
+ gActualWidth = gDialog.PreviewImage.naturalWidth;
+ gActualHeight = gDialog.PreviewImage.naturalHeight;
+
+ if (gActualWidth && gActualHeight) {
+ // Use actual size or scale to fit preview if either dimension is too large
+ var width = gActualWidth;
+ var height = gActualHeight;
+ if (gActualWidth > gPreviewImageWidth) {
+ width = gPreviewImageWidth;
+ height = gActualHeight * (gPreviewImageWidth / gActualWidth);
+ }
+ if (height > gPreviewImageHeight) {
+ height = gPreviewImageHeight;
+ width = gActualWidth * (gPreviewImageHeight / gActualHeight);
+ }
+ gDialog.PreviewImage.width = width;
+ gDialog.PreviewImage.height = height;
+
+ gDialog.PreviewWidth.setAttribute("value", gActualWidth);
+ gDialog.PreviewHeight.setAttribute("value", gActualHeight);
+
+ gDialog.PreviewSize.collapsed = false;
+ gDialog.ImageHolder.collapsed = false;
+
+ SetSizeWidgets(gDialog.widthInput.value, gDialog.heightInput.value);
+ }
+
+ if (gDialog.actualSizeRadio.selected) {
+ SetActualSize();
+ }
+ }
+}
+
+function LoadPreviewImage() {
+ gDialog.PreviewSize.collapsed = true;
+ // XXXbz workaround for bug 265416 / bug 266284
+ gDialog.ImageHolder.collapsed = true;
+
+ var imageSrc = TrimString(gDialog.srcInput.value);
+ if (!imageSrc) {
+ return;
+ }
+ if (isImageDataShortened(imageSrc)) {
+ imageSrc = restoredImageData(gDialog.srcInput);
+ }
+
+ 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)
+
+ // We must have an absolute URL to preview it or remove it from the cache
+ imageSrc = MakeAbsoluteUrl(imageSrc);
+
+ if (GetScheme(imageSrc)) {
+ let uri = Services.io.newURI(imageSrc);
+ if (uri) {
+ let imgCache = Cc["@mozilla.org/image/cache;1"].getService(
+ Ci.imgICache
+ );
+
+ // This returns error if image wasn't in the cache; ignore that
+ imgCache.removeEntry(uri);
+ }
+ }
+ } catch (e) {}
+
+ if (gDialog.PreviewImage) {
+ removeEventListener("load", PreviewImageLoaded, true);
+ }
+
+ if (gDialog.ImageHolder.hasChildNodes()) {
+ gDialog.ImageHolder.firstChild.remove();
+ }
+
+ gDialog.PreviewImage = document.createElementNS(
+ "http://www.w3.org/1999/xhtml",
+ "img"
+ );
+ if (gDialog.PreviewImage) {
+ // set the src before appending to the document -- see bug 198435 for why
+ // this is needed.
+ // XXXbz that bug is long-since fixed. Is this still needed?
+ gDialog.PreviewImage.addEventListener("load", PreviewImageLoaded, true);
+ gDialog.PreviewImage.src = imageSrc;
+ gDialog.ImageHolder.appendChild(gDialog.PreviewImage);
+ }
+}
+
+function SetActualSize() {
+ gDialog.widthInput.value = gActualWidth ? gActualWidth : "";
+ gDialog.widthUnitsMenulist.selectedIndex = 0;
+ gDialog.heightInput.value = gActualHeight ? gActualHeight : "";
+ gDialog.heightUnitsMenulist.selectedIndex = 0;
+ doDimensionEnabling();
+}
+
+function ChangeImageSrc() {
+ if (gTimerID) {
+ clearTimeout(gTimerID);
+ }
+
+ gTimerID = setTimeout(LoadPreviewImage, 800);
+
+ SetRelativeCheckbox();
+ doOverallEnabling();
+}
+
+function doDimensionEnabling() {
+ // Enabled unless "Actual Size" is selected
+ var enable = !gDialog.actualSizeRadio.selected;
+
+ // BUG 74145: After input field is disabled,
+ // setting it enabled causes blinking caret to appear
+ // even though focus isn't set to it.
+ SetElementEnabledById("heightInput", enable);
+ SetElementEnabledById("heightLabel", enable);
+ SetElementEnabledById("heightUnitsMenulist", enable);
+
+ SetElementEnabledById("widthInput", enable);
+ SetElementEnabledById("widthLabel", enable);
+ SetElementEnabledById("widthUnitsMenulist", enable);
+
+ var constrainEnable =
+ enable &&
+ gDialog.widthUnitsMenulist.selectedIndex == 0 &&
+ gDialog.heightUnitsMenulist.selectedIndex == 0;
+
+ SetElementEnabledById("constrainCheckbox", constrainEnable);
+}
+
+function doOverallEnabling() {
+ var enabled = TrimString(gDialog.srcInput.value) != "";
+
+ SetElementEnabled(gDialog.OkButton, enabled);
+ SetElementEnabledById("AdvancedEditButton1", enabled);
+ SetElementEnabledById("imagemapLabel", enabled);
+ SetElementEnabledById("removeImageMap", gCanRemoveImageMap);
+}
+
+function ToggleConstrain() {
+ // If just turned on, save the current width and height as basis for constrain ratio
+ // Thus clicking on/off lets user say "Use these values as aspect ration"
+ if (
+ gDialog.constrainCheckbox.checked &&
+ !gDialog.constrainCheckbox.disabled &&
+ gDialog.widthUnitsMenulist.selectedIndex == 0 &&
+ gDialog.heightUnitsMenulist.selectedIndex == 0
+ ) {
+ gConstrainWidth = Number(TrimString(gDialog.widthInput.value));
+ gConstrainHeight = Number(TrimString(gDialog.heightInput.value));
+ }
+}
+
+function constrainProportions(srcID, destID) {
+ var srcElement = document.getElementById(srcID);
+ if (!srcElement) {
+ return;
+ }
+
+ var destElement = document.getElementById(destID);
+ if (!destElement) {
+ return;
+ }
+
+ // always force an integer (whether we are constraining or not)
+ forceInteger(srcID);
+
+ if (
+ !gActualWidth ||
+ !gActualHeight ||
+ !(gDialog.constrainCheckbox.checked && !gDialog.constrainCheckbox.disabled)
+ ) {
+ return;
+ }
+
+ // double-check that neither width nor height is in percent mode; bail if so!
+ if (
+ gDialog.widthUnitsMenulist.selectedIndex != 0 ||
+ gDialog.heightUnitsMenulist.selectedIndex != 0
+ ) {
+ return;
+ }
+
+ // This always uses the actual width and height ratios
+ // which is kind of funky if you change one number without the constrain
+ // and then turn constrain on and change a number
+ // I prefer the old strategy (below) but I can see some merit to this solution
+ if (srcID == "widthInput") {
+ destElement.value = Math.round(
+ (srcElement.value * gActualHeight) / gActualWidth
+ );
+ } else {
+ destElement.value = Math.round(
+ (srcElement.value * gActualWidth) / gActualHeight
+ );
+ }
+
+ /*
+ // With this strategy, the width and height ratio
+ // can be reset to whatever the user entered.
+ if (srcID == "widthInput") {
+ destElement.value = Math.round( srcElement.value * gConstrainHeight / gConstrainWidth );
+ } else {
+ destElement.value = Math.round( srcElement.value * gConstrainWidth / gConstrainHeight );
+ }
+ */
+}
+
+function removeImageMap() {
+ gRemoveImageMap = true;
+ gCanRemoveImageMap = false;
+ SetElementEnabledById("removeImageMap", false);
+}
+
+function SwitchToValidatePanel() {
+ if (
+ gDialog.tabBox &&
+ gValidateTab &&
+ gDialog.tabBox.selectedTab != gValidateTab
+ ) {
+ gDialog.tabBox.selectedTab = gValidateTab;
+ }
+}
+
+// Get data from widgets, validate, and set for the global element
+// accessible to AdvancedEdit() [in EdDialogCommon.js]
+function ValidateImage() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ return false;
+ }
+
+ gValidateTab = gDialog.tabLocation;
+ if (!gDialog.srcInput.value) {
+ Services.prompt.alert(
+ window,
+ GetString("Alert"),
+ GetString("MissingImageError")
+ );
+ SwitchToValidatePanel();
+ gDialog.srcInput.focus();
+ return false;
+ }
+
+ // We must convert to "file:///" or "http://" format else image doesn't load!
+ let src = gDialog.srcInput.value.trim();
+
+ if (isImageDataShortened(src)) {
+ src = restoredImageData(gDialog.srcInput);
+ } else {
+ var checkbox = document.getElementById("MakeRelativeCheckbox");
+ try {
+ if (checkbox && !checkbox.checked) {
+ src = Services.uriFixup.getFixupURIInfo(
+ src,
+ Ci.nsIURIFixup.FIXUP_FLAG_NONE
+ ).preferredURI.spec;
+ }
+ } catch (e) {}
+
+ globalElement.setAttribute("src", src);
+ }
+
+ let title = gDialog.titleInput.value.trim();
+ if (title) {
+ globalElement.setAttribute("title", title);
+ } else {
+ globalElement.removeAttribute("title");
+ }
+
+ // Force user to enter Alt text only if "Alternate text" radio is checked
+ // Don't allow just spaces in alt text
+ var alt = "";
+ var useAlt = gDialog.altTextRadioGroup.selectedItem == gDialog.altTextRadio;
+ if (useAlt) {
+ alt = TrimString(gDialog.altTextInput.value);
+ }
+
+ if (alt || !useAlt) {
+ globalElement.setAttribute("alt", alt);
+ } else if (!gDoAltTextError) {
+ globalElement.removeAttribute("alt");
+ } else {
+ Services.prompt.alert(window, GetString("Alert"), GetString("NoAltText"));
+ SwitchToValidatePanel();
+ gDialog.altTextInput.focus();
+ return false;
+ }
+
+ var width = "";
+ var height = "";
+
+ gValidateTab = gDialog.tabDimensions;
+ if (!gDialog.actualSizeRadio.selected) {
+ // Get user values for width and height
+ width = ValidateNumber(
+ gDialog.widthInput,
+ gDialog.widthUnitsMenulist,
+ 1,
+ gMaxPixels,
+ globalElement,
+ "width",
+ false,
+ true
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ height = ValidateNumber(
+ gDialog.heightInput,
+ gDialog.heightUnitsMenulist,
+ 1,
+ gMaxPixels,
+ globalElement,
+ "height",
+ false,
+ true
+ );
+ if (gValidationError) {
+ return false;
+ }
+ }
+
+ // We always set the width and height attributes, even if same as actual.
+ // This speeds up layout of pages since sizes are known before image is loaded
+ if (!width) {
+ width = gActualWidth;
+ }
+ if (!height) {
+ height = gActualHeight;
+ }
+
+ // Remove existing width and height only if source changed
+ // and we couldn't obtain actual dimensions
+ var srcChanged = src != gOriginalSrc;
+ if (width) {
+ editor.setAttributeOrEquivalent(globalElement, "width", width, true);
+ } else if (srcChanged) {
+ editor.removeAttributeOrEquivalent(globalElement, "width", true);
+ }
+
+ if (height) {
+ editor.setAttributeOrEquivalent(globalElement, "height", height, true);
+ } else if (srcChanged) {
+ editor.removeAttributeOrEquivalent(globalElement, "height", true);
+ }
+
+ // spacing attributes
+ gValidateTab = gDialog.tabBorder;
+ ValidateNumber(
+ gDialog.imagelrInput,
+ null,
+ 0,
+ gMaxPixels,
+ globalElement,
+ "hspace",
+ false,
+ true,
+ true
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ ValidateNumber(
+ gDialog.imagetbInput,
+ null,
+ 0,
+ gMaxPixels,
+ globalElement,
+ "vspace",
+ false,
+ true
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ // note this is deprecated and should be converted to stylesheets
+ ValidateNumber(
+ gDialog.border,
+ null,
+ 0,
+ gMaxPixels,
+ globalElement,
+ "border",
+ false,
+ true
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ // Default or setting "bottom" means don't set the attribute
+ // Note that the attributes "left" and "right" are opposite
+ // of what we use in the UI, which describes where the TEXT wraps,
+ // not the image location (which is what the HTML describes)
+ switch (gDialog.alignTypeSelect.value) {
+ case "top":
+ case "middle":
+ case "right":
+ case "left":
+ editor.setAttributeOrEquivalent(
+ globalElement,
+ "align",
+ gDialog.alignTypeSelect.value,
+ true
+ );
+ break;
+ default:
+ try {
+ editor.removeAttributeOrEquivalent(globalElement, "align", true);
+ } catch (e) {}
+ }
+
+ return true;
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdImageLinkLoader.js b/comm/suite/editor/components/dialogs/content/EdImageLinkLoader.js
new file mode 100755
index 0000000000..5b88a5703f
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdImageLinkLoader.js
@@ -0,0 +1,145 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+var gMsgCompProcessLink = false;
+var gMsgCompInputElement = null;
+var gMsgCompPrevInputValue = null;
+var gMsgCompPrevMozDoNotSendAttribute;
+var gMsgCompAttachSourceElement = null;
+
+function OnLoadDialog() {
+ gMsgCompAttachSourceElement = document.getElementById("AttachSourceToMail");
+ var editor = GetCurrentEditor();
+ if (
+ gMsgCompAttachSourceElement &&
+ editor &&
+ editor.flags & Ci.nsIEditor.eEditorMailMask
+ ) {
+ SetRelativeCheckbox = function() {
+ SetAttachCheckbox();
+ };
+ // initialize the AttachSourceToMail checkbox
+ gMsgCompAttachSourceElement.hidden = false;
+
+ switch (document.documentElement.id) {
+ case "imageDlg":
+ gMsgCompInputElement = gDialog.srcInput;
+ gMsgCompProcessLink = false;
+ break;
+ case "linkDlg":
+ gMsgCompInputElement = gDialog.hrefInput;
+ gMsgCompProcessLink = true;
+ break;
+ }
+ if (gMsgCompInputElement) {
+ SetAttachCheckbox();
+ gMsgCompPrevMozDoNotSendAttribute = globalElement.getAttribute(
+ "moz-do-not-send"
+ );
+ }
+ }
+}
+addEventListener("load", OnLoadDialog, false);
+
+function OnAcceptDialog() {
+ // Auto-convert file URLs to data URLs. If we're in the link properties
+ // dialog convert only when requested - for the image dialog do it always.
+ if (gMsgCompInputElement &&
+ /^file:/i.test(gMsgCompInputElement.value.trim()) &&
+ (gMsgCompAttachSourceElement.checked || !gMsgCompProcessLink)) {
+ var dataURI = GenerateDataURL(gMsgCompInputElement.value.trim());
+ gMsgCompInputElement.value = dataURI;
+ gMsgCompAttachSourceElement.checked = true;
+ }
+ DoAttachSourceCheckbox();
+}
+document.addEventListener("dialogaccept", OnAcceptDialog, true);
+
+function SetAttachCheckbox() {
+ var resetCheckbox = false;
+ var mozDoNotSend = globalElement.getAttribute("moz-do-not-send");
+
+ // In case somebody played with the advanced property and changed the moz-do-not-send attribute
+ if (mozDoNotSend != gMsgCompPrevMozDoNotSendAttribute) {
+ gMsgCompPrevMozDoNotSendAttribute = mozDoNotSend;
+ resetCheckbox = true;
+ }
+
+ // Has the URL changed
+ if (
+ gMsgCompInputElement &&
+ gMsgCompInputElement.value != gMsgCompPrevInputValue
+ ) {
+ gMsgCompPrevInputValue = gMsgCompInputElement.value;
+ resetCheckbox = true;
+ }
+
+ if (gMsgCompInputElement && resetCheckbox) {
+ // Here is the rule about how to set the checkbox Attach Source To Message:
+ // If the attribute "moz-do-not-send" has not been set, we look at the scheme of the URL
+ // and at some preference to decide what is the best for the user.
+ // If it is set to "false", the checkbox is checked, otherwise unchecked.
+ var attach = false;
+ if (mozDoNotSend == null) {
+ // We haven't yet set the "moz-do-not-send" attribute.
+ var inputValue = gMsgCompInputElement.value.trim();
+ if (/^(file|data):/i.test(inputValue)) {
+ // For files or data URLs, default to attach them.
+ attach = true;
+ } else if (
+ !gMsgCompProcessLink && // Implies image dialogue.
+ /^https?:/i.test(inputValue)
+ ) {
+ // For images loaded via http(s) we default to the preference value.
+ attach = Services.prefs.getBoolPref("mail.compose.attach_http_images");
+ }
+ } else {
+ attach = mozDoNotSend == "false";
+ }
+
+ gMsgCompAttachSourceElement.checked = attach;
+ }
+}
+
+function DoAttachSourceCheckbox() {
+ gMsgCompPrevMozDoNotSendAttribute = (!gMsgCompAttachSourceElement.checked).toString();
+ globalElement.setAttribute(
+ "moz-do-not-send",
+ gMsgCompPrevMozDoNotSendAttribute
+ );
+}
+
+function GenerateDataURL(url) {
+ var file = Services.io.newURI(url).QueryInterface(Ci.nsIFileURL).file;
+ var contentType = Cc["@mozilla.org/mime;1"]
+ .getService(Ci.nsIMIMEService)
+ .getTypeFromFile(file);
+ var inputStream = Cc[
+ "@mozilla.org/network/file-input-stream;1"
+ ].createInstance(Ci.nsIFileInputStream);
+ inputStream.init(file, 0x01, 0o600, 0);
+ var stream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
+ Ci.nsIBinaryInputStream
+ );
+ stream.setInputStream(inputStream);
+ let data = "";
+ while (stream.available() > 0) {
+ data += stream.readBytes(stream.available());
+ }
+ let encoded = btoa(data);
+ stream.close();
+ return (
+ "data:" +
+ contentType +
+ ";filename=" +
+ encodeURIComponent(file.leafName) +
+ ";base64," +
+ encoded
+ );
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdImageProps.js b/comm/suite/editor/components/dialogs/content/EdImageProps.js
new file mode 100644
index 0000000000..5b73488dcb
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdImageProps.js
@@ -0,0 +1,293 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+/* import-globals-from EdImageDialog.js */
+
+var gAnchorElement = null;
+var gLinkElement = null;
+var gOriginalHref = "";
+var gHNodeArray = {};
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ window.close();
+ return;
+ }
+
+ ImageStartup();
+ gDialog.hrefInput = document.getElementById("hrefInput");
+ gDialog.makeRelativeLink = document.getElementById("MakeRelativeLink");
+ gDialog.showLinkBorder = document.getElementById("showLinkBorder");
+ gDialog.linkTab = document.getElementById("imageLinkTab");
+ gDialog.linkAdvanced = document.getElementById("LinkAdvancedEditButton");
+
+ // Get a single selected image element
+ var tagName = "img";
+ if ("arguments" in window && window.arguments[0]) {
+ imageElement = window.arguments[0];
+ // We've been called from form field properties, so we can't insert a link
+ gDialog.linkTab.remove();
+ gDialog.linkTab = null;
+ } else {
+ // First check for <input type="image">
+ try {
+ imageElement = editor.getSelectedElement("input");
+
+ if (!imageElement || imageElement.getAttribute("type") != "image") {
+ // Get a single selected image element
+ imageElement = editor.getSelectedElement(tagName);
+ if (imageElement) {
+ gAnchorElement = editor.getElementOrParentByTagName(
+ "href",
+ imageElement
+ );
+ }
+ }
+ } catch (e) {}
+ }
+
+ if (imageElement) {
+ // We found an element and don't need to insert one
+ if (imageElement.hasAttribute("src")) {
+ gInsertNewImage = false;
+ gActualWidth = imageElement.naturalWidth;
+ gActualHeight = imageElement.naturalHeight;
+ }
+ } else {
+ gInsertNewImage = true;
+
+ // We don't have an element selected,
+ // so create one with default attributes
+ try {
+ imageElement = editor.createElementWithDefaults(tagName);
+ } catch (e) {}
+
+ if (!imageElement) {
+ dump("Failed to get selected element or create a new one!\n");
+ window.close();
+ return;
+ }
+ try {
+ gAnchorElement = editor.getSelectedElement("href");
+ } catch (e) {}
+ }
+
+ // Make a copy to use for AdvancedEdit
+ globalElement = imageElement.cloneNode(false);
+
+ // We only need to test for this once per dialog load
+ gHaveDocumentUrl = GetDocumentBaseUrl();
+
+ InitDialog();
+ if (gAnchorElement) {
+ gOriginalHref = gAnchorElement.getAttribute("href");
+ // Make a copy to use for AdvancedEdit
+ gLinkElement = gAnchorElement.cloneNode(false);
+ } else {
+ gLinkElement = editor.createElementWithDefaults("a");
+ }
+ gDialog.hrefInput.value = gOriginalHref;
+
+ FillLinkMenulist(gDialog.hrefInput, gHNodeArray);
+ ChangeLinkLocation();
+
+ // Save initial source URL
+ gOriginalSrc = gDialog.srcInput.value;
+
+ // By default turn constrain on, but both width and height must be in pixels
+ gDialog.constrainCheckbox.checked =
+ gDialog.widthUnitsMenulist.selectedIndex == 0 &&
+ gDialog.heightUnitsMenulist.selectedIndex == 0;
+
+ // Start in "Link" tab if 2nd argument is true
+ if (gDialog.linkTab && "arguments" in window && window.arguments[1]) {
+ document.getElementById("TabBox").selectedTab = gDialog.linkTab;
+ SetTextboxFocus(gDialog.hrefInput);
+ } else {
+ SetTextboxFocus(gDialog.srcInput);
+ }
+
+ SetWindowLocation();
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+// by AdvancedEdit(), which is shared by all property dialogs
+function InitDialog() {
+ InitImage();
+ var border = TrimString(gDialog.border.value);
+ gDialog.showLinkBorder.checked = border != "" && border > 0;
+}
+
+function ChangeLinkLocation() {
+ var href = TrimString(gDialog.hrefInput.value);
+ SetRelativeCheckbox(gDialog.makeRelativeLink);
+ gDialog.showLinkBorder.disabled = !href;
+ gDialog.linkAdvanced.disabled = !href;
+ gLinkElement.setAttribute("href", href);
+}
+
+function ToggleShowLinkBorder() {
+ if (gDialog.showLinkBorder.checked) {
+ var border = TrimString(gDialog.border.value);
+ if (!border || border == "0") {
+ gDialog.border.value = "2";
+ }
+ } else {
+ gDialog.border.value = "0";
+ }
+}
+
+// Get data from widgets, validate, and set for the global element
+// accessible to AdvancedEdit() [in EdDialogCommon.js]
+function ValidateData() {
+ return ValidateImage();
+}
+
+function onAccept(event) {
+ // Use this now (default = false) so Advanced Edit button dialog doesn't trigger error message
+ gDoAltTextError = true;
+
+ if (ValidateData()) {
+ if ("arguments" in window && window.arguments[0]) {
+ SaveWindowLocation();
+ return;
+ }
+
+ var editor = GetCurrentEditor();
+
+ editor.beginTransaction();
+
+ try {
+ if (gRemoveImageMap) {
+ globalElement.removeAttribute("usemap");
+ if (gImageMap) {
+ editor.deleteNode(gImageMap);
+ gInsertNewIMap = true;
+ gImageMap = null;
+ }
+ } else if (gImageMap) {
+ // un-comment to see that inserting image maps does not work!
+ /*
+ gImageMap = editor.createElementWithDefaults("map");
+ gImageMap.setAttribute("name", "testing");
+ var testArea = editor.createElementWithDefaults("area");
+ testArea.setAttribute("shape", "circle");
+ testArea.setAttribute("coords", "86,102,52");
+ testArea.setAttribute("href", "test");
+ gImageMap.appendChild(testArea);
+ */
+
+ // Assign to map if there is one
+ var mapName = gImageMap.getAttribute("name");
+ if (mapName != "") {
+ globalElement.setAttribute("usemap", "#" + mapName);
+ if (globalElement.getAttribute("border") == "") {
+ globalElement.setAttribute("border", 0);
+ }
+ }
+ }
+
+ // Create or remove the link as appropriate
+ var href = gDialog.hrefInput.value;
+ if (href != gOriginalHref) {
+ if (href && !gInsertNewImage) {
+ EditorSetTextProperty("a", "href", href);
+ // gAnchorElement is needed for cloning attributes later.
+ if (!gAnchorElement) {
+ gAnchorElement = editor.getElementOrParentByTagName(
+ "href",
+ imageElement
+ );
+ }
+ } else {
+ EditorRemoveTextProperty("href", "");
+ }
+ }
+
+ // If inside a link, always write the 'border' attribute
+ if (href) {
+ if (gDialog.showLinkBorder.checked) {
+ // Use default = 2 if border attribute is empty
+ if (!globalElement.hasAttribute("border")) {
+ globalElement.setAttribute("border", "2");
+ }
+ } else {
+ globalElement.setAttribute("border", "0");
+ }
+ }
+
+ if (gInsertNewImage) {
+ if (href) {
+ gLinkElement.appendChild(imageElement);
+ editor.insertElementAtSelection(gLinkElement, true);
+ } else {
+ // 'true' means delete the selection before inserting
+ editor.insertElementAtSelection(imageElement, true);
+ }
+ }
+
+ // Check to see if the link was to a heading
+ // Do this last because it moves the caret (BAD!)
+ if (href in gHNodeArray) {
+ var anchorNode = editor.createElementWithDefaults("a");
+ if (anchorNode) {
+ anchorNode.name = href.substr(1);
+ // Remember to use editor method so it is undoable!
+ editor.insertNode(anchorNode, gHNodeArray[href], 0);
+ }
+ }
+ // All values are valid - copy to actual element in doc or
+ // element we just inserted
+ editor.cloneAttributes(imageElement, globalElement);
+ if (gAnchorElement) {
+ editor.cloneAttributes(gAnchorElement, gLinkElement);
+ }
+
+ // If document is empty, the map element won't insert,
+ // so always insert the image first
+ if (gImageMap && gInsertNewIMap) {
+ // Insert the ImageMap element at beginning of document
+ var body = editor.rootElement;
+ editor.setShouldTxnSetSelection(false);
+ editor.insertNode(gImageMap, body, 0);
+ editor.setShouldTxnSetSelection(true);
+ }
+ } catch (e) {
+ dump(e);
+ }
+
+ editor.endTransaction();
+
+ SaveWindowLocation();
+ return;
+ }
+
+ gDoAltTextError = false;
+
+ event.preventDefault();
+}
+
+function onLinkAdvancedEdit() {
+ window.AdvancedEditOK = false;
+ window.openDialog(
+ "chrome://editor/content/EdAdvancedEdit.xhtml",
+ "_blank",
+ "chrome,close,titlebar,modal,resizable=yes",
+ "",
+ gLinkElement
+ );
+ window.focus();
+ if (window.AdvancedEditOK) {
+ gDialog.hrefInput.value = gLinkElement.getAttribute("href");
+ }
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdImageProps.xhtml b/comm/suite/editor/components/dialogs/content/EdImageProps.xhtml
new file mode 100644
index 0000000000..11d7d03026
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdImageProps.xhtml
@@ -0,0 +1,116 @@
+<?xml version="1.0"?>
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edImageProperties SYSTEM "chrome://editor/locale/EditorImageProperties.dtd">
+%edImageProperties;
+<!ENTITY % composeEditorOverlayDTD SYSTEM "chrome://messenger/locale/messengercompose/mailComposeEditorOverlay.dtd">
+%composeEditorOverlayDTD;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<!-- dialog containing a control requiring initial setup -->
+<dialog id="imageDlg" title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()"
+ buttons="accept,cancel">
+
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdImageProps.js"/>
+ <script src="chrome://editor/content/EdImageDialog.js"/>
+ <script src="chrome://editor/content/EdImageLinkLoader.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <tabbox id="TabBox">
+ <tabs flex="1">
+ <tab id="imageLocationTab" label="&imageLocationTab.label;"/>
+ <tab id="imageDimensionsTab" label="&imageDimensionsTab.label;"/>
+ <tab id="imageAppearanceTab" label="&imageAppearanceTab.label;"/>
+ <tab id="imageLinkTab" label="&imageLinkTab.label;"/>
+ </tabs>
+ <tabpanels>
+#include edImage.inc.xhtml
+ <vbox>
+ <spacer class="spacer"/>
+ <vbox id="LinkLocationBox">
+ <label control="hrefInput"
+ accesskey="&LinkURLEditField2.accessKey;"
+ width="1">&LinkURLEditField2.label;</label>
+ <textbox id="hrefInput" type="text"
+ class="uri-element padded" oninput="ChangeLinkLocation();"/>
+ <hbox align="center">
+ <checkbox id="MakeRelativeLink"
+ for="hrefInput"
+ label="&makeUrlRelative.label;"
+ accesskey="&makeUrlRelative.accessKey;"
+ oncommand="MakeInputValueRelativeOrAbsolute(this);"
+ tooltiptext="&makeUrlRelative.tooltip;"/>
+ <spacer flex="1"/>
+ <button label="&chooseFileLinkButton.label;" accesskey="&chooseFileLinkButton.accessKey;"
+ oncommand="chooseLinkFile();"/>
+ </hbox>
+ </vbox>
+ <spacer class="spacer"/>
+ <hbox>
+ <checkbox id="showLinkBorder"
+ label="&showImageLinkBorder.label;"
+ accesskey="&showImageLinkBorder.accessKey;"
+ oncommand="ToggleShowLinkBorder();"/>
+ <spacer flex="1"/>
+ <button id="LinkAdvancedEditButton"
+ label="&LinkAdvancedEditButton.label;"
+ accesskey="&LinkAdvancedEditButton.accessKey;"
+ tooltiptext="&LinkAdvancedEditButton.tooltip;"
+ oncommand="onLinkAdvancedEdit();"/>
+ </hbox>
+ </vbox>
+ </tabpanels>
+ </tabbox>
+
+ <hbox align="end">
+ <groupbox id="imagePreview" orient="horizontal" flex="1">
+ <hbox class="groupbox-title">
+ <label class="header">&previewBox.label;</label>
+ </hbox>
+ <hbox id="preview-image-box" align="center">
+ <spacer flex="1"/>
+ <description id="preview-image-holder"/>
+ <spacer flex="1"/>
+ </hbox>
+ <vbox id="PreviewSize" collapsed="true">
+ <spacer flex="1"/>
+ <label value="&actualSize.label;"/>
+ <hbox>
+ <label value="&widthEditField.label;"/>
+ <spacer flex="1"/>
+ <label id="PreviewWidth"/>
+ </hbox>
+ <hbox>
+ <label value="&heightEditField.label;"/>
+ <spacer flex="1"/>
+ <label id="PreviewHeight"/>
+ </hbox>
+ <spacer flex="1"/>
+ </vbox>
+ </groupbox>
+
+ <vbox id="AdvancedEdit">
+ <hbox flex="1" style="margin-top: 0.2em" align="center">
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton1" oncommand="onAdvancedEdit()" label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;" tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ </vbox>
+ </hbox>
+ <separator class="groove"/>
+
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdInputImage.js b/comm/suite/editor/components/dialogs/content/EdInputImage.js
new file mode 100644
index 0000000000..556acc7b13
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInputImage.js
@@ -0,0 +1,189 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+/* import-globals-from EdImageDialog.js */
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ window.close();
+ return;
+ }
+
+ gDialog = {
+ inputName: document.getElementById("InputName"),
+ inputDisabled: document.getElementById("InputDisabled"),
+ inputTabIndex: document.getElementById("InputTabIndex"),
+ };
+
+ ImageStartup();
+
+ // Get a single selected input element
+ var tagName = "input";
+ try {
+ imageElement = editor.getSelectedElement(tagName);
+ } catch (e) {}
+
+ if (imageElement) {
+ // We found an element and don't need to insert one
+ gInsertNewImage = false;
+ } else {
+ gInsertNewImage = true;
+
+ // We don't have an element selected,
+ // so create one with default attributes
+ try {
+ imageElement = editor.createElementWithDefaults(tagName);
+ } catch (e) {}
+
+ if (!imageElement) {
+ dump("Failed to get selected element or create a new one!\n");
+ window.close();
+ return;
+ }
+ var imgElement;
+ try {
+ imgElement = editor.getSelectedElement("img");
+ } catch (e) {}
+
+ if (imgElement) {
+ // We found an image element, convert it to an input type="image"
+ var attributes = [
+ "src",
+ "alt",
+ "width",
+ "height",
+ "hspace",
+ "vspace",
+ "border",
+ "align",
+ "usemap",
+ "ismap",
+ ];
+ for (let i in attributes) {
+ imageElement.setAttribute(
+ attributes[i],
+ imgElement.getAttribute(attributes[i])
+ );
+ }
+ }
+ }
+
+ // Make a copy to use for AdvancedEdit
+ globalElement = imageElement.cloneNode(false);
+
+ // We only need to test for this once per dialog load
+ gHaveDocumentUrl = GetDocumentBaseUrl();
+
+ InitDialog();
+
+ // Save initial source URL
+ gOriginalSrc = gDialog.srcInput.value;
+
+ // By default turn constrain on, but both width and height must be in pixels
+ gDialog.constrainCheckbox.checked =
+ gDialog.widthUnitsMenulist.selectedIndex == 0 &&
+ gDialog.heightUnitsMenulist.selectedIndex == 0;
+
+ SetTextboxFocus(gDialog.inputName);
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ InitImage();
+ gDialog.inputName.value = globalElement.getAttribute("name");
+ gDialog.inputDisabled.setAttribute(
+ "checked",
+ globalElement.hasAttribute("disabled")
+ );
+ gDialog.inputTabIndex.value = globalElement.getAttribute("tabindex");
+}
+
+function ValidateData() {
+ if (!ValidateImage()) {
+ return false;
+ }
+ if (gDialog.inputName.value) {
+ globalElement.setAttribute("name", gDialog.inputName.value);
+ } else {
+ globalElement.removeAttribute("name");
+ }
+ if (gDialog.inputTabIndex.value) {
+ globalElement.setAttribute("tabindex", gDialog.inputTabIndex.value);
+ } else {
+ globalElement.removeAttribute("tabindex");
+ }
+ if (gDialog.inputDisabled.checked) {
+ globalElement.setAttribute("disabled", "");
+ } else {
+ globalElement.removeAttribute("disabled");
+ }
+ globalElement.setAttribute("type", "image");
+ return true;
+}
+
+function onAccept(event) {
+ // Show alt text error only once
+ // (we don't initialize doAltTextError=true
+ // so Advanced edit button dialog doesn't trigger that error message)
+ // Use this now (default = false) so Advanced Edit button dialog doesn't trigger error message
+ gDoAltTextError = true;
+
+ if (ValidateData()) {
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+
+ try {
+ if (gRemoveImageMap) {
+ globalElement.removeAttribute("usemap");
+ if (gImageMap) {
+ editor.deleteNode(gImageMap);
+ gInsertNewIMap = true;
+ gImageMap = null;
+ }
+ } else if (gImageMap) {
+ // Assign to map if there is one
+ var mapName = gImageMap.getAttribute("name");
+ if (mapName != "") {
+ globalElement.setAttribute("usemap", "#" + mapName);
+ if (globalElement.getAttribute("border") == "") {
+ globalElement.setAttribute("border", 0);
+ }
+ }
+ }
+
+ if (gInsertNewImage) {
+ // 'true' means delete the selection before inserting
+ // in case were are converting an image to an input type="image"
+ editor.insertElementAtSelection(imageElement, true);
+ }
+ editor.cloneAttributes(imageElement, globalElement);
+
+ // If document is empty, the map element won't insert,
+ // so always insert the image element first
+ if (gImageMap && gInsertNewIMap) {
+ // Insert the ImageMap element at beginning of document
+ var body = editor.rootElement;
+ editor.setShouldTxnSetSelection(false);
+ editor.insertNode(gImageMap, body, 0);
+ editor.setShouldTxnSetSelection(true);
+ }
+ } catch (e) {}
+
+ editor.endTransaction();
+
+ SaveWindowLocation();
+
+ return;
+ }
+ event.preventDefault();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdInputImage.xhtml b/comm/suite/editor/components/dialogs/content/EdInputImage.xhtml
new file mode 100644
index 0000000000..d3fc8c8270
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInputImage.xhtml
@@ -0,0 +1,104 @@
+<?xml version="1.0"?>
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edInputProperties SYSTEM "chrome://editor/locale/EditorInputProperties.dtd">
+%edInputProperties;
+<!ENTITY % edImageProperties SYSTEM "chrome://editor/locale/EditorImageProperties.dtd">
+%edImageProperties;
+<!ENTITY % composeEditorOverlayDTD SYSTEM "chrome://messenger/locale/messengercompose/mailComposeEditorOverlay.dtd">
+%composeEditorOverlayDTD;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitleImage.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup();">
+
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdInputImage.js"/>
+ <script src="chrome://editor/content/EdImageDialog.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <tabbox id="TabBox">
+ <tabs flex="1">
+ <tab id="imageInputTab" label="&imageInputTab.label;"/>
+ <tab id="imageLocationTab" label="&imageLocationTab.label;"/>
+ <tab id="imageDimensionsTab" label="&imageDimensionsTab.label;"/>
+ <tab id="imageAppearanceTab" label="&imageAppearanceTab.label;"/>
+ </tabs>
+ <tabpanels>
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&InputSettings.label;</label>
+ </hbox>
+ <grid><columns><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <label value="&InputName.label;"/>
+ <textbox id="InputName"/>
+ </row>
+ <row>
+ <spacer/>
+ <checkbox id="InputDisabled" label="&InputDisabled.label;"/>
+ </row>
+ <row align="center">
+ <label value="&tabIndex.label;"/>
+ <hbox>
+ <textbox id="InputTabIndex" class="narrow" oninput="forceInteger(this.id);"/>
+ </hbox>
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+#include edImage.inc.xhtml
+ </tabpanels>
+ </tabbox>
+
+ <hbox align="end">
+ <groupbox id="imagePreview" orient="horizontal" flex="1">
+ <hbox class="groupbox-title">
+ <label class="header">&previewBox.label;</label>
+ </hbox>
+ <hbox id="preview-image-box" align="center">
+ <spacer flex="1"/>
+ <description id="preview-image-holder"/>
+ <spacer flex="1"/>
+ </hbox>
+ <vbox id="PreviewSize" collapsed="true">
+ <spacer flex="1"/>
+ <label value="&actualSize.label;"/>
+ <hbox>
+ <label value="&widthEditField.label;"/>
+ <spacer flex="1"/>
+ <label id="PreviewWidth"/>
+ </hbox>
+ <hbox>
+ <label value="&heightEditField.label;"/>
+ <spacer flex="1"/>
+ <label id="PreviewHeight"/>
+ </hbox>
+ <spacer flex="1"/>
+ </vbox>
+ </groupbox>
+
+ <vbox id="AdvancedEdit">
+ <hbox flex="1" style="margin-top: 0.2em" align="center">
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton1" oncommand="onAdvancedEdit()" label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;" tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator id="advancedSeparator" class="groove"/>
+ </vbox>
+ </hbox>
+
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdInputProps.js b/comm/suite/editor/components/dialogs/content/EdInputProps.js
new file mode 100644
index 0000000000..a737e263c7
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInputProps.js
@@ -0,0 +1,345 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var insertNew;
+var inputElement;
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ dump("Failed to get active editor!\n");
+ window.close();
+ return;
+ }
+
+ gDialog = {
+ accept: document.documentElement.getButton("accept"),
+ inputType: document.getElementById("InputType"),
+ inputNameDeck: document.getElementById("InputNameDeck"),
+ inputName: document.getElementById("InputName"),
+ inputValueDeck: document.getElementById("InputValueDeck"),
+ inputValue: document.getElementById("InputValue"),
+ inputDeck: document.getElementById("InputDeck"),
+ inputChecked: document.getElementById("InputChecked"),
+ inputSelected: document.getElementById("InputSelected"),
+ inputReadOnly: document.getElementById("InputReadOnly"),
+ inputDisabled: document.getElementById("InputDisabled"),
+ inputTabIndex: document.getElementById("InputTabIndex"),
+ inputAccessKey: document.getElementById("InputAccessKey"),
+ inputSize: document.getElementById("InputSize"),
+ inputMaxLength: document.getElementById("InputMaxLength"),
+ inputAccept: document.getElementById("InputAccept"),
+ MoreSection: document.getElementById("MoreSection"),
+ MoreFewerButton: document.getElementById("MoreFewerButton"),
+ AdvancedEditButton: document.getElementById("AdvancedEditButton"),
+ AdvancedEditDeck: document.getElementById("AdvancedEditDeck"),
+ };
+
+ // Get a single selected input element
+ const kTagName = "input";
+ try {
+ inputElement = editor.getSelectedElement(kTagName);
+ } catch (e) {}
+
+ if (inputElement) {
+ // We found an element and don't need to insert one
+ insertNew = false;
+ } else {
+ insertNew = true;
+
+ // We don't have an element selected,
+ // so create one with default attributes
+ try {
+ inputElement = editor.createElementWithDefaults(kTagName);
+ } catch (e) {}
+
+ if (!inputElement) {
+ dump("Failed to get selected element or create a new one!\n");
+ window.close();
+ return;
+ }
+
+ var imgElement = editor.getSelectedElement("img");
+ if (imgElement) {
+ // We found an image element, convert it to an input type="image"
+ inputElement.setAttribute("type", "image");
+
+ var attributes = [
+ "src",
+ "alt",
+ "width",
+ "height",
+ "hspace",
+ "vspace",
+ "border",
+ "align",
+ ];
+ for (let i in attributes) {
+ inputElement.setAttribute(
+ attributes[i],
+ imgElement.getAttribute(attributes[i])
+ );
+ }
+ } else {
+ inputElement.setAttribute("value", GetSelectionAsText());
+ }
+ }
+
+ // Make a copy to use for AdvancedEdit
+ globalElement = inputElement.cloneNode(false);
+
+ InitDialog();
+
+ InitMoreFewer();
+
+ gDialog.inputType.focus();
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ var type = globalElement.getAttribute("type");
+ var index = 0;
+ switch (type) {
+ case "button":
+ index = 9;
+ break;
+ case "checkbox":
+ index = 2;
+ break;
+ case "file":
+ index = 6;
+ break;
+ case "hidden":
+ index = 7;
+ break;
+ case "image":
+ index = 8;
+ break;
+ case "password":
+ index = 1;
+ break;
+ case "radio":
+ index = 3;
+ break;
+ case "reset":
+ index = 5;
+ break;
+ case "submit":
+ index = 4;
+ break;
+ }
+ gDialog.inputType.selectedIndex = index;
+ gDialog.inputName.value = globalElement.getAttribute("name");
+ gDialog.inputValue.value = globalElement.getAttribute("value");
+ gDialog.inputChecked.setAttribute(
+ "checked",
+ globalElement.hasAttribute("checked")
+ );
+ gDialog.inputSelected.setAttribute(
+ "checked",
+ globalElement.hasAttribute("checked")
+ );
+ gDialog.inputReadOnly.setAttribute(
+ "checked",
+ globalElement.hasAttribute("readonly")
+ );
+ gDialog.inputDisabled.setAttribute(
+ "checked",
+ globalElement.hasAttribute("disabled")
+ );
+ gDialog.inputTabIndex.value = globalElement.getAttribute("tabindex");
+ gDialog.inputAccessKey.value = globalElement.getAttribute("accesskey");
+ gDialog.inputSize.value = globalElement.getAttribute("size");
+ gDialog.inputMaxLength.value = globalElement.getAttribute("maxlength");
+ gDialog.inputAccept.value = globalElement.getAttribute("accept");
+ SelectInputType();
+}
+
+function SelectInputType() {
+ var index = gDialog.inputType.selectedIndex;
+ gDialog.AdvancedEditDeck.setAttribute("selectedIndex", 0);
+ gDialog.inputNameDeck.setAttribute("selectedIndex", 0);
+ gDialog.inputValueDeck.setAttribute("selectedIndex", 0);
+ gDialog.inputValue.disabled = false;
+ gDialog.inputChecked.disabled = index != 2;
+ gDialog.inputSelected.disabled = index != 3;
+ gDialog.inputReadOnly.disabled = index > 1;
+ gDialog.inputTabIndex.disabled = index == 7;
+ gDialog.inputAccessKey.disabled = index == 7;
+ gDialog.inputSize.disabled = index > 1;
+ gDialog.inputMaxLength.disabled = index > 1;
+ gDialog.inputAccept.disabled = index != 6;
+ switch (index) {
+ case 0:
+ case 1:
+ gDialog.inputValueDeck.setAttribute("selectedIndex", 1);
+ gDialog.inputDeck.setAttribute("selectedIndex", 2);
+ break;
+ case 2:
+ gDialog.inputDeck.setAttribute("selectedIndex", 0);
+ break;
+ case 3:
+ gDialog.inputDeck.setAttribute("selectedIndex", 1);
+ gDialog.inputNameDeck.setAttribute("selectedIndex", 1);
+ break;
+ case 6:
+ gDialog.inputValue.disabled = true;
+ gDialog.inputAccept.disabled = false;
+ break;
+ case 8:
+ gDialog.inputValue.disabled = true;
+ gDialog.AdvancedEditDeck.setAttribute("selectedIndex", 1);
+ gDialog.inputName.removeEventListener("input", onInput);
+ break;
+ case 7:
+ gDialog.inputValueDeck.setAttribute("selectedIndex", 1);
+ break;
+ }
+ onInput();
+}
+
+function onInput() {
+ var disabled = false;
+ switch (gDialog.inputType.selectedIndex) {
+ case 3:
+ disabled = disabled || !gDialog.inputValue.value;
+ break;
+ case 4:
+ case 5:
+ break;
+ case 8:
+ disabled = !globalElement.hasAttribute("src");
+ break;
+ default:
+ disabled = !gDialog.inputName.value;
+ break;
+ }
+ if (gDialog.accept.disabled != disabled) {
+ gDialog.accept.disabled = disabled;
+ gDialog.AdvancedEditButton.disabled = disabled;
+ }
+}
+
+function doImageProperties() {
+ window.openDialog(
+ "chrome://editor/content/EdImageProps.xhtml",
+ "_blank",
+ "chrome,close,titlebar,modal",
+ globalElement
+ );
+ window.focus();
+ onInput();
+}
+
+function ValidateData() {
+ var attributes = {
+ type: "",
+ name: gDialog.inputName.value,
+ value: gDialog.inputValue.value,
+ tabindex: gDialog.inputTabIndex.value,
+ accesskey: "",
+ size: "",
+ maxlength: "",
+ accept: "",
+ };
+ var index = gDialog.inputType.selectedIndex;
+ var flags = {
+ checked: false,
+ readonly: false,
+ disabled: gDialog.inputDisabled.checked,
+ };
+ switch (index) {
+ case 1:
+ attributes.type = "password";
+ // Falls through
+ case 0:
+ flags.readonly = gDialog.inputReadOnly.checked;
+ attributes.size = gDialog.inputSize.value;
+ attributes.maxlength = gDialog.inputMaxLength.value;
+ break;
+ case 2:
+ attributes.type = "checkbox";
+ flags.checked = gDialog.inputChecked.checked;
+ break;
+ case 3:
+ attributes.type = "radio";
+ flags.checked = gDialog.inputSelected.checked;
+ break;
+ case 4:
+ attributes.type = "submit";
+ attributes.accesskey = gDialog.inputAccessKey.value;
+ break;
+ case 5:
+ attributes.type = "reset";
+ attributes.accesskey = gDialog.inputAccessKey.value;
+ break;
+ case 6:
+ attributes.type = "file";
+ attributes.accept = gDialog.inputAccept.value;
+ attributes.value = "";
+ break;
+ case 7:
+ attributes.type = "hidden";
+ attributes.tabindex = "";
+ break;
+ case 8:
+ attributes.type = "image";
+ attributes.value = "";
+ break;
+ case 9:
+ attributes.type = "button";
+ attributes.accesskey = gDialog.inputAccessKey.value;
+ break;
+ }
+ for (var a in attributes) {
+ if (attributes[a]) {
+ globalElement.setAttribute(a, attributes[a]);
+ } else {
+ globalElement.removeAttribute(a);
+ }
+ }
+ for (var f in flags) {
+ if (flags[f]) {
+ globalElement.setAttribute(f, "");
+ } else {
+ globalElement.removeAttribute(f);
+ }
+ }
+ return true;
+}
+
+function onAccept(event) {
+ if (ValidateData()) {
+ // All values are valid - copy to actual element in doc or
+ // element created to insert
+
+ var editor = GetCurrentEditor();
+
+ editor.cloneAttributes(inputElement, globalElement);
+
+ if (insertNew) {
+ try {
+ // 'true' means delete the selection before inserting
+ // in case were are converting an image to an input type="image"
+ editor.insertElementAtSelection(inputElement, true);
+ } catch (e) {
+ dump(e);
+ }
+ }
+
+ SaveWindowLocation();
+
+ return;
+ }
+ event.preventDefault();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdInputProps.xhtml b/comm/suite/editor/components/dialogs/content/EdInputProps.xhtml
new file mode 100644
index 0000000000..c6011ee896
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInputProps.xhtml
@@ -0,0 +1,135 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edInputProperties SYSTEM "chrome://editor/locale/EditorInputProperties.dtd">
+%edInputProperties;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup();"
+ buttons="accept,cancel">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdInputProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header" control="InputType" accesskey="&InputType.accesskey;">&InputType.label;</label>
+ </hbox>
+ <menulist id="InputType" oncommand="SelectInputType();">
+ <menupopup>
+ <menuitem label="&text.value;"/>
+ <menuitem label="&password.value;"/>
+ <menuitem label="&checkbox.value;"/>
+ <menuitem label="&radio.value;"/>
+ <menuitem label="&submit.value;"/>
+ <menuitem label="&reset.value;"/>
+ <menuitem label="&file.value;"/>
+ <menuitem label="&hidden.value;"/>
+ <menuitem label="&image.value;"/>
+ <menuitem label="&button.value;"/>
+ </menupopup>
+ </menulist>
+ </groupbox>
+
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&InputSettings.label;</label>
+ </hbox>
+ <grid><columns><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <deck id="InputNameDeck">
+ <label control="InputName" value="&InputName.label;" accesskey="&InputName.accesskey;"/>
+ <label control="InputName" value="&GroupName.label;" accesskey="&GroupName.accesskey;"/>
+ </deck>
+ <textbox id="InputName" oninput="onInput();"/>
+ </row>
+ <row align="center">
+ <deck id="InputValueDeck">
+ <label control="InputValue" value="&InputValue.label;" accesskey="&InputValue.accesskey;"/>
+ <label control="InputValue" value="&InitialValue.label;" accesskey="&InitialValue.accesskey;"/>
+ </deck>
+ <textbox id="InputValue" oninput="onInput();"/>
+ </row>
+ <row>
+ <spacer/>
+ <deck id="InputDeck" persist="index">
+ <checkbox id="InputChecked" label="&InputChecked.label;" accesskey="&InputChecked.accesskey;"/>
+ <checkbox id="InputSelected" label="&InputSelected.label;" accesskey="&InputSelected.accesskey;"/>
+ <checkbox id="InputReadOnly" label="&InputReadOnly.label;" accesskey="&InputReadOnly.accesskey;"/>
+ </deck>
+ </row>
+ </rows>
+ </grid>
+ <hbox>
+ <button id="MoreFewerButton" oncommand="onMoreFewer();" persist="more"/>
+ </hbox>
+ <grid id="MoreSection" align="start">
+ <columns><column/><column/></columns>
+ <rows>
+ <row>
+ <spacer/>
+ <checkbox id="InputDisabled" label="&InputDisabled.label;" accesskey="&InputDisabled.accesskey;"/>
+ </row>
+ <row align="center">
+ <label control="InputTabIndex" value="&tabIndex.label;" accesskey="&tabIndex.accesskey;"/>
+ <hbox>
+ <textbox id="InputTabIndex" class="narrow" oninput="forceInteger(this.id);"/>
+ </hbox>
+ </row>
+ <row align="center">
+ <label control="InputAccessKey" value="&AccessKey.label;" accesskey="&AccessKey.accesskey;"/>
+ <hbox>
+ <textbox id="InputAccessKey" class="narrow"/>
+ </hbox>
+ </row>
+ <row align="center">
+ <label control="InputSize" value="&TextSize.label;" accesskey="&TextSize.accesskey;"/>
+ <hbox>
+ <textbox id="InputSize" class="narrow" oninput="forceInteger(this.id);"/>
+ </hbox>
+ </row>
+ <row align="center">
+ <label control="InputMaxLength" value="&TextLength.label;" accesskey="&TextLength.accesskey;"/>
+ <hbox>
+ <textbox id="InputMaxLength" class="narrow" oninput="forceInteger(this.id);"/>
+ </hbox>
+ </row>
+ <row align="center">
+ <label control="InputAccept" value="&Accept.label;" accesskey="&Accept.accesskey;"/>
+ <textbox id="InputAccept"/>
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+
+ <!-- from EdDialogOverlay -->
+ <hbox flex="1" style="margin-top: 0.2em">
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <deck id="AdvancedEditDeck">
+ <button id="AdvancedEditButton"
+ oncommand="onAdvancedEdit();"
+ label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;"
+ tooltiptext="&AdvancedEditButton.tooltip;"/>
+ <button label="&ImageProperties.label;" accesskey="&ImageProperties.accesskey;" oncommand="doImageProperties();"/>
+ </deck>
+ </hbox>
+ <separator class="groove"/>
+
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdInsSrc.js b/comm/suite/editor/components/dialogs/content/EdInsSrc.js
new file mode 100644
index 0000000000..0f0304ef1e
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInsSrc.js
@@ -0,0 +1,160 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Insert Source HTML dialog */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var gFullDataStrings = new Map();
+var gShortDataStrings = new Map();
+var gListenerAttached = false;
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ let editor = GetCurrentEditor();
+ if (!editor) {
+ window.close();
+ return;
+ }
+
+ document.documentElement.getButton("accept").removeAttribute("default");
+
+ // Create dialog object to store controls for easy access
+ gDialog.srcInput = document.getElementById("srcInput");
+
+ // Attach a paste listener so we can detect pasted data URIs we need to shorten.
+ gDialog.srcInput.addEventListener("paste", onPaste);
+
+ let selection;
+ try {
+ selection = editor.outputToString(
+ "text/html",
+ kOutputFormatted | kOutputSelectionOnly | kOutputWrap
+ );
+ } catch (e) {}
+ if (selection) {
+ selection = selection.replace(/<body[^>]*>/, "").replace(/<\/body>/, "");
+
+ // Shorten data URIs for display.
+ selection = replaceDataURIs(selection);
+
+ if (selection) {
+ gDialog.srcInput.value = selection;
+ }
+ }
+ // Set initial focus
+ gDialog.srcInput.focus();
+ SetWindowLocation();
+}
+
+function replaceDataURIs(input) {
+ return input.replace(/(data:.+;base64,)([^"' >]+)/gi, function(
+ match,
+ nonDataPart,
+ dataPart
+ ) {
+ if (gShortDataStrings.has(dataPart)) {
+ // We found the exact same data URI, just return the shortened URI.
+ return nonDataPart + gShortDataStrings.get(dataPart);
+ }
+
+ let l = 5;
+ let key;
+ // Normally we insert the ellipsis after five characters but if it's not unique
+ // we include more data.
+ do {
+ key = dataPart.substr(0, l) + "…" + dataPart.substr(dataPart.length - 10);
+ l++;
+ } while (gFullDataStrings.has(key) && l < dataPart.length - 10);
+ gFullDataStrings.set(key, dataPart);
+ gShortDataStrings.set(dataPart, key);
+
+ // Attach listeners. In case anyone copies/cuts from the HTML window,
+ // we want to restore the data URI on the clipboard.
+ if (!gListenerAttached) {
+ gDialog.srcInput.addEventListener("copy", onCopyOrCut);
+ gDialog.srcInput.addEventListener("cut", onCopyOrCut);
+ gListenerAttached = true;
+ }
+
+ return nonDataPart + key;
+ });
+}
+
+function onCopyOrCut(event) {
+ let startPos = gDialog.srcInput.selectionStart;
+ if (startPos == undefined) {
+ return;
+ }
+ let endPos = gDialog.srcInput.selectionEnd;
+ let clipboard = gDialog.srcInput.value.substring(startPos, endPos);
+
+ // Add back the original data URIs we stashed away earlier.
+ clipboard = clipboard.replace(/(data:.+;base64,)([^"' >]+)/gi, function(
+ match,
+ nonDataPart,
+ key
+ ) {
+ if (!gFullDataStrings.has(key)) {
+ // User changed data URI.
+ return match;
+ }
+ return nonDataPart + gFullDataStrings.get(key);
+ });
+ event.clipboardData.setData("text/plain", clipboard);
+ if (event.type == "cut") {
+ // We have to cut the selection manually.
+ gDialog.srcInput.value =
+ gDialog.srcInput.value.substr(0, startPos) +
+ gDialog.srcInput.value.substr(endPos);
+ }
+ event.preventDefault();
+}
+
+function onPaste(event) {
+ let startPos = gDialog.srcInput.selectionStart;
+ if (startPos == undefined) {
+ return;
+ }
+ let endPos = gDialog.srcInput.selectionEnd;
+ let clipboard = event.clipboardData.getData("text/plain");
+
+ // We do out own paste by replacing the selection with the pre-processed
+ // clipboard data.
+ gDialog.srcInput.value =
+ gDialog.srcInput.value.substr(0, startPos) +
+ replaceDataURIs(clipboard) +
+ gDialog.srcInput.value.substr(endPos);
+ event.preventDefault();
+}
+
+function onAccept(event) {
+ let html = gDialog.srcInput.value;
+ if (!html) {
+ event.preventDefault();
+ return;
+ }
+
+ // Add back the original data URIs we stashed away earlier.
+ html = html.replace(/(data:.+;base64,)([^"' >]+)/gi, function(
+ match,
+ nonDataPart,
+ key
+ ) {
+ if (!gFullDataStrings.has(key)) {
+ // User changed data URI.
+ return match;
+ }
+ return nonDataPart + gFullDataStrings.get(key);
+ });
+
+ try {
+ GetCurrentEditor().insertHTML(html);
+ } catch (e) {}
+ SaveWindowLocation();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdInsSrc.xhtml b/comm/suite/editor/components/dialogs/content/EdInsSrc.xhtml
new file mode 100644
index 0000000000..32b89ebefd
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInsSrc.xhtml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorInsertSource.dtd">
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ onload = "Startup()"
+ buttonlabelaccept="&insertButton.label;"
+ buttonaccesskeyaccept="&insertButton.accesskey;">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://global/content/globalOverlay.js"/>
+ <script src="chrome://global/content/editMenuOverlay.js"/>
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdInsSrc.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <label id="srcMessage" value="&sourceEditField.label;"/>
+ <vbox flex="1" style="width: 30em; height: 20em;">
+ <html:textarea id="srcInput" rows="18" flex="1"/>
+ </vbox>
+ <!-- Will this accept the embedded HTML tags? -->
+ <hbox>
+ <spacer class="bigspacer"/>
+ <label value="&example.label;"/>
+ <label class="bold" value="&exampleOpenTag.label;"/>
+ <label class="bold italic" value="&exampleText.label;"/>
+ <label class="bold" value="&exampleCloseTag.label;"/>
+ </hbox>
+ <spacer class="spacer"/>
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdInsertChars.js b/comm/suite/editor/components/dialogs/content/EdInsertChars.js
new file mode 100644
index 0000000000..6ee88afcdd
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInsertChars.js
@@ -0,0 +1,409 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+// ------------------------------------------------------------------
+// From Unicode 3.0 Page 54. 3.11 Conjoining Jamo Behavior
+var SBase = 0xac00;
+var LBase = 0x1100;
+var VBase = 0x1161;
+var TBase = 0x11a7;
+var LCount = 19;
+var VCount = 21;
+var TCount = 28;
+var NCount = VCount * TCount;
+// End of Unicode 3.0
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onClose);
+
+// dialog initialization code
+function Startup() {
+ if (!GetCurrentEditor()) {
+ window.close();
+ return;
+ }
+
+ StartupLatin();
+
+ // Set a variable on the opener window so we
+ // can track ownership of close this window with it
+ window.opener.InsertCharWindow = window;
+ window.sizeToContent();
+
+ SetWindowLocation();
+}
+
+function onAccept(event) {
+ // Insert the character
+ try {
+ GetCurrentEditor().insertText(LatinM.label);
+ } catch (e) {}
+
+ // Set persistent attributes to save
+ // which category, letter, and character modifier was used
+ CategoryGroup.setAttribute("category", category);
+ CategoryGroup.setAttribute("letter_index", indexL);
+ CategoryGroup.setAttribute("char_index", indexM);
+
+ // Don't close the dialog
+ event.preventDefault();
+}
+
+// Don't allow inserting in HTML Source Mode
+function onFocus() {
+ var enable = true;
+ if ("gEditorDisplayMode" in window.opener) {
+ enable = !window.opener.IsInHTMLSourceMode();
+ }
+
+ SetElementEnabled(document.documentElement.getButton("accept"), enable);
+}
+
+function onClose() {
+ window.opener.InsertCharWindow = null;
+ SaveWindowLocation();
+}
+
+// ------------------------------------------------------------------
+var LatinL;
+var LatinM;
+var LatinL_Label;
+var LatinM_Label;
+var indexL = 0;
+var indexM = 0;
+var indexM_AU = 0;
+var indexM_AL = 0;
+var indexM_U = 0;
+var indexM_L = 0;
+var indexM_S = 0;
+var LItems = 0;
+var category;
+var CategoryGroup;
+var initialize = true;
+
+function StartupLatin() {
+ LatinL = document.getElementById("LatinL");
+ LatinM = document.getElementById("LatinM");
+ LatinL_Label = document.getElementById("LatinL_Label");
+ LatinM_Label = document.getElementById("LatinM_Label");
+
+ var Symbol = document.getElementById("Symbol");
+ var AccentUpper = document.getElementById("AccentUpper");
+ var AccentLower = document.getElementById("AccentLower");
+ var Upper = document.getElementById("Upper");
+ var Lower = document.getElementById("Lower");
+ CategoryGroup = document.getElementById("CatGrp");
+
+ // Initialize which radio button is set from persistent attribute...
+ var category = CategoryGroup.getAttribute("category");
+
+ // ...as well as indexes into the letter and character lists
+ var index = Number(CategoryGroup.getAttribute("letter_index"));
+ if (index && index >= 0) {
+ indexL = index;
+ }
+ index = Number(CategoryGroup.getAttribute("char_index"));
+ if (index && index >= 0) {
+ indexM = index;
+ }
+
+ switch (category) {
+ case "AccentUpper": // Uppercase Diacritical
+ CategoryGroup.selectedItem = AccentUpper;
+ indexM_AU = indexM;
+ break;
+ case "AccentLower": // Lowercase Diacritical
+ CategoryGroup.selectedItem = AccentLower;
+ indexM_AL = indexM;
+ break;
+ case "Upper": // Uppercase w/o Diacritical
+ CategoryGroup.selectedItem = Upper;
+ indexM_U = indexM;
+ break;
+ case "Lower": // Lowercase w/o Diacritical
+ CategoryGroup.selectedItem = Lower;
+ indexM_L = indexM;
+ break;
+ default:
+ category = "Symbol";
+ CategoryGroup.selectedItem = Symbol;
+ indexM_S = indexM;
+ break;
+ }
+
+ ChangeCategory(category);
+ initialize = false;
+}
+
+function ChangeCategory(newCategory) {
+ if (category != newCategory || initialize) {
+ category = newCategory;
+ // Note: Must do L before M to set LatinL.selectedIndex
+ UpdateLatinL();
+ UpdateLatinM();
+ UpdateCharacter();
+ }
+}
+
+function SelectLatinLetter() {
+ if (LatinL.selectedIndex != indexL) {
+ indexL = LatinL.selectedIndex;
+ UpdateLatinM();
+ UpdateCharacter();
+ }
+}
+
+function SelectLatinModifier() {
+ if (LatinM.selectedIndex != indexM) {
+ indexM = LatinM.selectedIndex;
+ UpdateCharacter();
+ }
+}
+function DisableLatinL(disable) {
+ if (disable) {
+ LatinL_Label.setAttribute("disabled", "true");
+ LatinL.setAttribute("disabled", "true");
+ } else {
+ LatinL_Label.removeAttribute("disabled");
+ LatinL.removeAttribute("disabled");
+ }
+}
+
+function UpdateLatinL() {
+ LatinL.removeAllItems();
+ if (category == "AccentUpper" || category == "AccentLower") {
+ DisableLatinL(false);
+ // No Q or q
+ var alphabet =
+ category == "AccentUpper"
+ ? "ABCDEFGHIJKLMNOPRSTUVWXYZ"
+ : "abcdefghijklmnoprstuvwxyz";
+ for (var letter = 0; letter < alphabet.length; letter++) {
+ LatinL.appendItem(alphabet.charAt(letter));
+ }
+
+ LatinL.selectedIndex = indexL;
+ } else {
+ // Other categories don't hinge on a "letter"
+ DisableLatinL(true);
+ // Note: don't change the indexL so it can be used next time
+ }
+}
+
+function UpdateLatinM() {
+ LatinM.removeAllItems();
+ var i, accent;
+ switch (category) {
+ case "AccentUpper": // Uppercase Diacritical
+ accent = upper[indexL];
+ for (i = 0; i < accent.length; i++) {
+ LatinM.appendItem(accent.charAt(i));
+ }
+
+ if (indexM_AU < accent.length) {
+ indexM = indexM_AU;
+ } else {
+ indexM = accent.length - 1;
+ }
+ indexM_AU = indexM;
+ break;
+
+ case "AccentLower": // Lowercase Diacritical
+ accent = lower[indexL];
+ for (i = 0; i < accent.length; i++) {
+ LatinM.appendItem(accent.charAt(i));
+ }
+
+ if (indexM_AL < accent.length) {
+ indexM = indexM_AL;
+ } else {
+ indexM = lower[indexL].length - 1;
+ }
+ indexM_AL = indexM;
+ break;
+
+ case "Upper": // Uppercase w/o Diacritical
+ for (i = 0; i < otherupper.length; i++) {
+ LatinM.appendItem(otherupper.charAt(i));
+ }
+
+ if (indexM_U < otherupper.length) {
+ indexM = indexM_U;
+ } else {
+ indexM = otherupper.length - 1;
+ }
+ indexM_U = indexM;
+ break;
+
+ case "Lower": // Lowercase w/o Diacritical
+ for (i = 0; i < otherlower.length; i++) {
+ LatinM.appendItem(otherlower.charAt(i));
+ }
+
+ if (indexM_L < otherlower.length) {
+ indexM = indexM_L;
+ } else {
+ indexM = otherlower.length - 1;
+ }
+ indexM_L = indexM;
+ break;
+
+ case "Symbol": // Symbol
+ for (i = 0; i < symbol.length; i++) {
+ LatinM.appendItem(symbol.charAt(i));
+ }
+
+ if (indexM_S < symbol.length) {
+ indexM = indexM_S;
+ } else {
+ indexM = symbol.length - 1;
+ }
+ indexM_S = indexM;
+ break;
+ }
+ LatinM.selectedIndex = indexM;
+}
+
+function UpdateCharacter() {
+ indexM = LatinM.selectedIndex;
+
+ switch (category) {
+ case "AccentUpper": // Uppercase Diacritical
+ indexM_AU = indexM;
+ break;
+ case "AccentLower": // Lowercase Diacritical
+ indexM_AL = indexM;
+ break;
+ case "Upper": // Uppercase w/o Diacritical
+ indexM_U = indexM;
+ break;
+ case "Lower": // Lowercase w/o Diacritical
+ indexM_L = indexM;
+ break;
+ case "Symbol":
+ indexM_S = indexM;
+ break;
+ }
+ // dump("Letter Index="+indexL+", Character Index="+indexM+", Character = "+LatinM.label+"\n");
+}
+
+const upper = [
+ // A
+ "\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5\u0100\u0102\u0104\u01cd\u01de\u01de\u01e0\u01fa\u0200\u0202\u0226\u1e00\u1ea0\u1ea2\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6",
+ // B
+ "\u0181\u0182\u0184\u1e02\u1e04\u1e06",
+ // C
+ "\u00c7\u0106\u0108\u010a\u010c\u0187\u1e08",
+ // D
+ "\u010e\u0110\u0189\u018a\u1e0a\u1e0c\u1e0e\u1e10\u1e12",
+ // E
+ "\u00C8\u00C9\u00CA\u00CB\u0112\u0114\u0116\u0118\u011A\u0204\u0206\u0228\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1eb8\u1eba\u1ebc\u1ebe\u1ec0\u1ec2\u1ec4\u1ec6",
+ // F
+ "\u1e1e",
+ // G
+ "\u011c\u011E\u0120\u0122\u01e4\u01e6\u01f4\u1e20",
+ // H
+ "\u0124\u0126\u021e\u1e22\u1e24\u1e26\u1e28\u1e2a",
+ // I
+ "\u00CC\u00CD\u00CE\u00CF\u0128\u012a\u012C\u012e\u0130\u0208\u020a\u1e2c\u1e2e\u1ec8\u1eca",
+ // J
+ "\u0134\u01f0",
+ // K
+ "\u0136\u0198\u01e8\u1e30\u1e32\u1e34",
+ // L
+ "\u0139\u013B\u013D\u013F\u0141\u1e36\u1e38\u1e3a\u1e3c",
+ // M
+ "\u1e3e\u1e40\u1e42",
+ // N
+ "\u00D1\u0143\u0145\u0147\u014A\u01F8\u1e44\u1e46\u1e48\u1e4a",
+ // O
+ "\u00D2\u00D3\u00D4\u00D5\u00D6\u014C\u014E\u0150\u01ea\u01ec\u020c\u020e\u022A\u022C\u022E\u0230\u1e4c\u1e4e\u1e50\u1e52\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede\u1ee0\u1ee2",
+ // P
+ "\u1e54\u1e56",
+ // No Q
+ // R
+ "\u0154\u0156\u0158\u0210\u0212\u1e58\u1e5a\u1e5c\u1e5e",
+ // S
+ "\u015A\u015C\u015E\u0160\u0218\u1e60\u1e62\u1e64\u1e66\u1e68",
+ // T
+ "\u0162\u0164\u0166\u021A\u1e6a\u1e6c\u1e6e\u1e70",
+ // U
+ "\u00D9\u00DA\u00DB\u00DC\u0168\u016A\u016C\u016E\u0170\u0172\u0214\u0216\u1e72\u1e74\u1e76\u1e78\u1e7a\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0",
+ // V
+ "\u1e7c\u1e7e",
+ // W
+ "\u0174\u1e80\u1e82\u1e84\u1e86\u1e88",
+ // X
+ "\u1e8a\u1e8c",
+ // Y
+ "\u00DD\u0176\u0178\u0232\u1e8e\u1ef2\u1ef4\u1ef6\u1ef8",
+ // Z
+ "\u0179\u017B\u017D\u0224\u1e90\u1e92\u1e94",
+];
+
+const lower = [
+ // a
+ "\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u0101\u0103\u0105\u01ce\u01df\u01e1\u01fb\u0201\u0203\u0227\u1e01\u1e9a\u1ea1\u1ea3\u1ea5\u1ea7\u1ea9\u1eab\u1ead\u1eaf\u1eb1\u1eb3\u1eb5\u1eb7",
+ // b
+ "\u0180\u0183\u0185\u1e03\u1e05\u1e07",
+ // c
+ "\u00e7\u0107\u0109\u010b\u010d\u0188\u1e09",
+ // d
+ "\u010f\u0111\u1e0b\u1e0d\u1e0f\u1e11\u1e13",
+ // e
+ "\u00e8\u00e9\u00ea\u00eb\u0113\u0115\u0117\u0119\u011b\u0205\u0207\u0229\u1e15\u1e17\u1e19\u1e1b\u1e1d\u1eb9\u1ebb\u1ebd\u1ebf\u1ec1\u1ec3\u1ec5\u1ec7",
+ // f
+ "\u1e1f",
+ // g
+ "\u011d\u011f\u0121\u0123\u01e5\u01e7\u01f5\u1e21",
+ // h
+ "\u0125\u0127\u021f\u1e23\u1e25\u1e27\u1e29\u1e2b\u1e96",
+ // i
+ "\u00ec\u00ed\u00ee\u00ef\u0129\u012b\u012d\u012f\u0131\u01d0\u0209\u020b\u1e2d\u1e2f\u1ec9\u1ecb",
+ // j
+ "\u0135",
+ // k
+ "\u0137\u0138\u01e9\u1e31\u1e33\u1e35",
+ // l
+ "\u013a\u013c\u013e\u0140\u0142\u1e37\u1e39\u1e3b\u1e3d",
+ // m
+ "\u1e3f\u1e41\u1e43",
+ // n
+ "\u00f1\u0144\u0146\u0148\u0149\u014b\u01f9\u1e45\u1e47\u1e49\u1e4b",
+ // o
+ "\u00f2\u00f3\u00f4\u00f5\u00f6\u014d\u014f\u0151\u01d2\u01eb\u01ed\u020d\u020e\u022b\u022d\u022f\u0231\u1e4d\u1e4f\u1e51\u1e53\u1ecd\u1ecf\u1ed1\u1ed3\u1ed5\u1ed7\u1ed9\u1edb\u1edd\u1edf\u1ee1\u1ee3",
+ // p
+ "\u1e55\u1e57",
+ // No q
+ // r
+ "\u0155\u0157\u0159\u0211\u0213\u1e59\u1e5b\u1e5d\u1e5f",
+ // s
+ "\u015b\u015d\u015f\u0161\u0219\u1e61\u1e63\u1e65\u1e67\u1e69",
+ // t
+ "\u0162\u0163\u0165\u0167\u021b\u1e6b\u1e6d\u1e6f\u1e71\u1e97",
+ // u
+ "\u00f9\u00fa\u00fb\u00fc\u0169\u016b\u016d\u016f\u0171\u0173\u01d4\u01d6\u01d8\u01da\u01dc\u0215\u0217\u1e73\u1e75\u1e77\u1e79\u1e7b\u1ee5\u1ee7\u1ee9\u1eeb\u1eed\u1eef\u1ef1",
+ // v
+ "\u1e7d\u1e7f",
+ // w
+ "\u0175\u1e81\u1e83\u1e85\u1e87\u1e89\u1e98",
+ // x
+ "\u1e8b\u1e8d",
+ // y
+ "\u00fd\u00ff\u0177\u0233\u1e8f\u1e99\u1ef3\u1ef5\u1ef7\u1ef9",
+ // z
+ "\u017a\u017c\u017e\u0225\u1e91\u1e93\u1e95",
+];
+
+const symbol =
+ "\u00a1\u00a2\u00a3\u00a4\u00a5\u20ac\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ae\u00af\u00b0\u00b1\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb\u00bc\u00bd\u00be\u00bf\u00d7\u00f7";
+
+const otherupper =
+ "\u00c6\u00d0\u00d8\u00de\u0132\u0152\u0186\u01c4\u01c5\u01c7\u01c8\u01ca\u01cb\u01F1\u01f2";
+
+const otherlower =
+ "\u00e6\u00f0\u00f8\u00fe\u00df\u0133\u0153\u01c6\u01c9\u01cc\u01f3";
diff --git a/comm/suite/editor/components/dialogs/content/EdInsertChars.xhtml b/comm/suite/editor/components/dialogs/content/EdInsertChars.xhtml
new file mode 100644
index 0000000000..4e6c1020fa
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInsertChars.xhtml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorInsertChars.dtd">
+
+<dialog id="insertCharsDlg" title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload = "Startup()"
+ onfocus = "onFocus()"
+ buttonlabelaccept="&insertButton.label;"
+ buttonlabelcancel="&closeButton.label;"
+ style = "width: 20em">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdInsertChars.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&category.label;</label>
+ </hbox>
+ <radiogroup id="CatGrp" persist="category letter_index char_index">
+ <radio id="AccentUpper" label="&accentUpper.label;" oncommand="ChangeCategory(this.id)"/>
+ <radio id="AccentLower" label="&accentLower.label;" oncommand="ChangeCategory(this.id)"/>
+ <radio id="Upper" label="&otherUpper.label;" oncommand="ChangeCategory(this.id)"/>
+ <radio id="Lower" label="&otherLower.label;" oncommand="ChangeCategory(this.id)"/>
+ <radio id="Symbol" label="&commonSymbols.label;" oncommand="ChangeCategory(this.id)"/>
+ </radiogroup>
+ <spacer class="spacer"/>
+ </groupbox>
+ <hbox equalsize="always">
+ <vbox flex="1">
+ <!-- value is set in JS from editor.properties strings -->
+ <label id="LatinL_Label" control="LatinL" value="&letter.label;" accesskey="&letter.accessKey;"/>
+ <menulist class="larger" flex="1" id="LatinL" oncommand="SelectLatinLetter()">
+ <menupopup/>
+ </menulist>
+ </vbox>
+ <vbox flex="1">
+ <label id="LatinM_Label" control="LatinM" value="&character.label;" accesskey="&character.accessKey;"/>
+ <menulist class="larger" flex="1" id="LatinM" oncommand="SelectLatinModifier()">
+ <menupopup/>
+ </menulist>
+ </vbox>
+ </hbox>
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdInsertMath.js b/comm/suite/editor/components/dialogs/content/EdInsertMath.js
new file mode 100644
index 0000000000..c99bf8edac
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInsertMath.js
@@ -0,0 +1,330 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* Insert MathML dialog */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ window.close();
+ return;
+ }
+
+ // Create dialog object for easy access
+ gDialog.accept = document.documentElement.getButton("accept");
+ gDialog.mode = document.getElementById("optionMode");
+ gDialog.direction = document.getElementById("optionDirection");
+ gDialog.input = document.getElementById("input");
+ gDialog.output = document.getElementById("output");
+ gDialog.tabbox = document.getElementById("tabboxInsertLaTeXCommand");
+
+ // Set initial focus
+ gDialog.input.focus();
+
+ // Load TeXZilla
+ // TeXZilla.js contains non-ASCII characters and explicitly sets
+ // window.TeXZilla, so we have to specify the charset parameter but don't
+ // need to worry about the targetObj parameter.
+ /* globals TeXZilla */
+ Services.scriptloader.loadSubScript(
+ "chrome://editor/content/TeXZilla.js",
+ {},
+ "UTF-8"
+ );
+
+ // Verify if the selection is on a <math> and initialize the dialog.
+ gDialog.oldMath = editor.getElementOrParentByTagName("math", null);
+ if (gDialog.oldMath) {
+ // When these attributes are absent or invalid, they default to "inline" and "ltr" respectively.
+ gDialog.mode.selectedIndex =
+ gDialog.oldMath.getAttribute("display") == "block" ? 1 : 0;
+ gDialog.direction.selectedIndex =
+ gDialog.oldMath.getAttribute("dir") == "rtl" ? 1 : 0;
+ gDialog.input.value = TeXZilla.getTeXSource(gDialog.oldMath);
+ }
+
+ // Create the tabbox with LaTeX commands.
+ createCommandPanel({
+ "√⅗²": [
+ "{⋯}^{⋯}",
+ "{⋯}_{⋯}",
+ "{⋯}_{⋯}^{⋯}",
+ "\\underset{⋯}{⋯}",
+ "\\overset{⋯}{⋯}",
+ "\\underoverset{⋯}{⋯}{⋯}",
+ "\\left(⋯\\right)",
+ "\\left[⋯\\right]",
+ "\\frac{⋯}{⋯}",
+ "\\binom{⋯}{⋯}",
+ "\\sqrt{⋯}",
+ "\\sqrt[⋯]{⋯}",
+ "\\cos\\left({⋯}\\right)",
+ "\\sin\\left({⋯}\\right)",
+ "\\tan\\left({⋯}\\right)",
+ "\\exp\\left({⋯}\\right)",
+ "\\ln\\left({⋯}\\right)",
+ "\\underbrace{⋯}",
+ "\\underline{⋯}",
+ "\\overbrace{⋯}",
+ "\\widevec{⋯}",
+ "\\widetilde{⋯}",
+ "\\widehat{⋯}",
+ "\\widecheck{⋯}",
+ "\\widebar{⋯}",
+ "\\dot{⋯}",
+ "\\ddot{⋯}",
+ "\\boxed{⋯}",
+ "\\slash{⋯}",
+ ],
+ "(▦)": [
+ "\\begin{matrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{matrix}",
+ "\\begin{pmatrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{pmatrix}",
+ "\\begin{bmatrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{bmatrix}",
+ "\\begin{Bmatrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{Bmatrix}",
+ "\\begin{vmatrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{vmatrix}",
+ "\\begin{Vmatrix} ⋯ & ⋯ \\\\ ⋯ & ⋯ \\end{Vmatrix}",
+ "\\begin{cases} ⋯ \\\\ ⋯ \\end{cases}",
+ "\\begin{aligned} ⋯ &= ⋯ \\\\ ⋯ &= ⋯ \\end{aligned}",
+ ],
+ });
+ createSymbolPanels([
+ "∏∐∑∫∬∭⨌∮⊎⊕⊖⊗⊘⊙⋀⋁⋂⋃⌈⌉⌊⌋⎰⎱⟨⟩⟪⟫∥⫼⨀⨁⨂⨄⨅⨆ðıȷℏℑℓ℘ℜℵℶ",
+ "∀∃∄∅∉∊∋∌⊂⊃⊄⊅⊆⊇⊈⊈⊉⊊⊊⊋⊋⊏⊐⊑⊒⊓⊔⊥⋐⋑⋔⫅⫆⫋⫋⫌⫌…⋮⋯⋰⋱♭♮♯∂∇",
+ "±×÷†‡•∓∔∗∘∝∠∡∢∧∨∴∵∼∽≁≃≅≇≈≈≊≍≎≏≐≑≒≓≖≗≜≡≢≬⊚⊛⊞⊡⊢⊣⊤⊥",
+ "⊨⊩⊪⊫⊬⊭⊯⊲⊲⊳⊴⊵⊸⊻⋄⋅⋇⋈⋉⋊⋋⋌⋍⋎⋏⋒⋓⌅⌆⌣△▴▵▸▹▽▾▿◂◃◊○★♠♡♢♣⧫",
+ "≦≧≨≩≩≪≫≮≯≰≱≲≳≶≷≺≻≼≽≾≿⊀⊁⋖⋗⋘⋙⋚⋛⋞⋟⋦⋧⋨⋩⩽⩾⪅⪆⪇⪈⪉⪊⪋⪌⪕⪯⪰⪷⪸⪹⪺",
+ "←↑→↓↔↕↖↗↘↙↜↝↞↠↢↣↦↩↪↫↬↭↭↰↱↼↽↾↿⇀⇁⇂⇃⇄⇆⇇⇈⇉⇊⇋⇌⇐⇑⇒⇓⇕⇖⇗⇘⇙⟺",
+ "αβγδϵ϶εζηθϑικϰλμνξℴπϖρϱσςτυϕφχψωΓΔΘΛΞΠΣϒΦΨΩϝ℧",
+ "𝕒𝕓𝕔𝕕𝕖𝕗𝕘𝕙𝕚𝕛𝕜𝕝𝕞𝕟𝕠𝕡𝕢𝕣𝕤𝕥𝕦𝕧𝕨𝕩𝕪𝕫𝔸𝔹ℂ𝔻𝔼𝔽𝔾ℍ𝕀𝕁𝕂𝕃𝕄ℕ𝕆ℙℚℝ𝕊𝕋𝕌𝕍𝕎𝕏𝕐ℤ",
+ "𝒶𝒷𝒸𝒹ℯ𝒻ℊ𝒽𝒾𝒿𝓀𝓁𝓂𝓃ℴ𝓅𝓆𝓇𝓈𝓉𝓊𝓋𝓌𝓍𝓎𝓏𝒜ℬ𝒞𝒟ℰℱ𝒢ℋℐ𝒥𝒦ℒℳ𝒩𝒪𝒫𝒬ℛ𝒮𝒯𝒰𝒱𝒲𝒳𝒴𝒵",
+ "𝔞𝔟𝔠𝔡𝔢𝔣𝔤𝔥𝔦𝔧𝔨𝔩𝔪𝔫𝔬𝔭𝔮𝔯𝔰𝔱𝔲𝔳𝔴𝔵𝔶𝔷𝔄𝔅ℭ𝔇𝔈𝔉𝔊ℌℑ𝔍𝔎𝔏𝔐𝔑𝔒𝔓𝔔ℜ𝔖𝔗𝔘𝔙𝔚𝔛𝔜ℨ",
+ ]);
+ gDialog.tabbox.selectedIndex = 0;
+
+ updateMath();
+
+ SetWindowLocation();
+}
+
+function insertLaTeXCommand(aButton) {
+ gDialog.input.focus();
+
+ // For a single math symbol, just use the insertText command.
+ if (aButton.label) {
+ gDialog.input.editor.insertText(aButton.label);
+ return;
+ }
+
+ // Otherwise, it's a LaTeX command with at least one argument...
+ var latex = TeXZilla.getTeXSource(aButton.firstChild);
+ var selectionStart = gDialog.input.selectionStart;
+ var selectionEnd = gDialog.input.selectionEnd;
+
+ // If the selection is not empty, we replace the first argument of the LaTeX
+ // command with the current selection.
+ var selection = gDialog.input.value.substring(selectionStart, selectionEnd);
+ if (selection != "") {
+ latex = latex.replace("⋯", selection);
+ }
+
+ // Try and move to the next position.
+ var latexNewStart = latex.indexOf("⋯"),
+ latexNewEnd;
+ if (latexNewStart == -1) {
+ // This is a unary function and the selection was used as an argument above.
+ // We select the expression again so that one can choose to apply further
+ // command to it or just move the caret after that text.
+ latexNewStart = 0;
+ latexNewEnd = latex.length;
+ } else {
+ // Otherwise, select the dots representing the next argument.
+ latexNewEnd = latexNewStart + 1;
+ }
+
+ // Update the input text and selection.
+ gDialog.input.editor.insertText(latex);
+ gDialog.input.setSelectionRange(
+ selectionStart + latexNewStart,
+ selectionStart + latexNewEnd
+ );
+
+ updateMath();
+}
+
+function createCommandPanel(aCommandPanelList) {
+ const columnCount = 10;
+
+ for (var label in aCommandPanelList) {
+ var commands = aCommandPanelList[label];
+
+ // Create a <rows> element with some LaTeX commands.
+ var rows = document.createXULElement("rows");
+
+ var i = 0,
+ row;
+ for (var command of commands) {
+ if (i % columnCount == 0) {
+ // Create a new row.
+ row = document.createXULElement("row");
+ rows.appendChild(row);
+ }
+
+ // Create a new button to insert the symbol.
+ var button = document.createXULElement("toolbarbutton");
+ button.setAttribute("class", "tabbable");
+ button.appendChild(TeXZilla.toMathML(command));
+ row.appendChild(button);
+
+ i++;
+ }
+
+ // Create a <columns> element with the desired number of columns.
+ var columns = document.createXULElement("columns");
+ for (i = 0; i < columnCount; i++) {
+ var column = document.createXULElement("column");
+ column.setAttribute("flex", "1");
+ columns.appendChild(column);
+ }
+
+ // Create the <grid> element with the <rows> and <columns> children.
+ var grid = document.createXULElement("grid");
+ grid.appendChild(columns);
+ grid.appendChild(rows);
+
+ // Create a new <tab> element.
+ var tab = document.createXULElement("tab");
+ tab.setAttribute("label", label);
+ gDialog.tabbox.tabs.appendChild(tab);
+
+ // Append the new tab panel.
+ gDialog.tabbox.tabpanels.appendChild(grid);
+ }
+}
+
+function createSymbolPanels(aSymbolPanelList) {
+ const columnCount = 13,
+ tabLabelLength = 3;
+
+ for (var symbols of aSymbolPanelList) {
+ // Create a <rows> element with the symbols of the i-th panel.
+ var rows = document.createXULElement("rows");
+ var i = 0,
+ tabLabel = "",
+ row;
+ for (var symbol of symbols) {
+ if (i % columnCount == 0) {
+ // Create a new row.
+ row = document.createXULElement("row");
+ rows.appendChild(row);
+ }
+
+ // Build the tab label from the first symbols of this tab.
+ if (i < tabLabelLength) {
+ tabLabel += symbol;
+ }
+
+ // Create a new button to insert the symbol.
+ var button = document.createXULElement("toolbarbutton");
+ button.setAttribute("label", symbol);
+ button.setAttribute("class", "tabbable");
+ row.appendChild(button);
+
+ i++;
+ }
+
+ // Create a <columns> element with the desired number of columns.
+ var columns = document.createXULElement("columns");
+ for (i = 0; i < columnCount; i++) {
+ var column = document.createXULElement("column");
+ column.setAttribute("flex", "1");
+ columns.appendChild(column);
+ }
+
+ // Create the <grid> element with the <rows> and <columns> children.
+ var grid = document.createXULElement("grid");
+ grid.appendChild(columns);
+ grid.appendChild(rows);
+
+ // Create a new <tab> element with the label determined above.
+ var tab = document.createXULElement("tab");
+ tab.setAttribute("label", tabLabel);
+ gDialog.tabbox.tabs.appendChild(tab);
+
+ // Append the new tab panel.
+ gDialog.tabbox.tabpanels.appendChild(grid);
+ }
+}
+
+function onAccept(event) {
+ if (gDialog.output.firstChild) {
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+
+ try {
+ var newMath = editor.document.importNode(gDialog.output.firstChild, true);
+ if (gDialog.oldMath) {
+ // Replace the old <math> element with the new one.
+ editor.selectElement(gDialog.oldMath);
+ editor.insertElementAtSelection(newMath, true);
+ } else {
+ // Insert the new <math> element.
+ editor.insertElementAtSelection(newMath, false);
+ }
+ } catch (e) {}
+
+ editor.endTransaction();
+ } else {
+ dump("Null value -- not inserting in MathML Source dialog\n");
+ event.preventDefault();
+ }
+ SaveWindowLocation();
+}
+
+function updateMath() {
+ // Remove the preview, if any.
+ if (gDialog.output.firstChild) {
+ gDialog.output.firstChild.remove();
+ }
+
+ // Try to convert the LaTeX source into MathML using TeXZilla.
+ // We use the placeholder text if no input is provided.
+ try {
+ var input = gDialog.input.value || gDialog.input.placeholder;
+ var newMath = TeXZilla.toMathML(
+ input,
+ gDialog.mode.selectedIndex,
+ gDialog.direction.selectedIndex,
+ true
+ );
+ gDialog.output.appendChild(document.importNode(newMath, true));
+ gDialog.output.style.opacity = gDialog.input.value ? 1 : 0.5;
+ } catch (e) {}
+ // Disable the accept button if parsing fails or when the placeholder is used.
+ gDialog.accept.disabled = !gDialog.input.value || !gDialog.output.firstChild;
+}
+
+function updateMode() {
+ if (gDialog.output.firstChild) {
+ gDialog.output.firstChild.setAttribute(
+ "display",
+ gDialog.mode.selectedIndex ? "block" : "inline"
+ );
+ }
+}
+
+function updateDirection() {
+ if (gDialog.output.firstChild) {
+ gDialog.output.firstChild.setAttribute(
+ "dir",
+ gDialog.direction.selectedIndex ? "rtl" : "ltr"
+ );
+ }
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdInsertMath.xhtml b/comm/suite/editor/components/dialogs/content/EdInsertMath.xhtml
new file mode 100644
index 0000000000..9138d00846
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInsertMath.xhtml
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+- License, v. 2.0. If a copy of the MPL was not distributed with this
+- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorInsertMath.dtd">
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup();"
+ buttonlabelaccept="&insertButton.label;"
+ buttonaccesskeyaccept="&insertButton.accesskey;">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://global/content/globalOverlay.js"/>
+ <script src="chrome://global/content/editMenuOverlay.js"/>
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdInsertMath.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <label id="srcMessage" value="&sourceEditField.label;"/>
+ <html:textarea id="input" rows="5" oninput="updateMath();"
+ placeholder="\sqrt{x_1} + \frac{π^3}{2}"/>
+ <vbox flex="1" style="overflow: auto; width: 30em; height: 5em;">
+ <description id="output"/>
+ </vbox>
+ <tabbox id="tabboxInsertLaTeXCommand">
+ <tabs/>
+ <tabpanels oncommand="insertLaTeXCommand(event.target);"/>
+ </tabbox>
+ <spacer class="spacer"/>
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&options.label;</label>
+ </hbox>
+ <hbox>
+ <radiogroup id="optionMode" oncommand="updateMode();">
+ <radio label="&optionInline.label;"
+ accesskey="&optionInline.accesskey;"/>
+ <radio label="&optionDisplay.label;"
+ accesskey="&optionDisplay.accesskey;"/>
+ </radiogroup>
+ <radiogroup id="optionDirection" oncommand="updateDirection();">
+ <radio label="&optionLTR.label;"
+ accesskey="&optionLTR.accesskey;"/>
+ <radio label="&optionRTL.label;"
+ accesskey="&optionRTL.accesskey;"/>
+ </radiogroup>
+ </hbox>
+ </groupbox>
+ <spacer class="spacer"/>
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdInsertTOC.js b/comm/suite/editor/components/dialogs/content/EdInsertTOC.js
new file mode 100644
index 0000000000..3ec386f7c9
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInsertTOC.js
@@ -0,0 +1,378 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+// tocHeadersArray is the array containing the pairs tag/class
+// defining TOC entries
+var tocHeadersArray = new Array(6);
+
+// a global used when building the TOC
+var currentHeaderLevel = 0;
+
+// a global set to true if the TOC is to be readonly
+var readonly = false;
+
+// a global set to true if user wants indexes in the TOC
+var orderedList = true;
+
+// constants
+const kMozToc = "mozToc";
+const kMozTocLength = 6;
+const kMozTocIdPrefix = "mozTocId";
+const kMozTocIdPrefixLength = 8;
+const kMozTocClassPrefix = "mozToc";
+const kMozTocClassPrefixLength = 6;
+
+document.addEventListener("dialogaccept", () => BuildTOC(true));
+
+// Startup() is called when EdInsertTOC.xhtml is opened
+function Startup() {
+ // early way out if if we have no editor
+ if (!GetCurrentEditor()) {
+ window.close();
+ return;
+ }
+
+ var i;
+ // clean the table of tag/class pairs we look for
+ for (i = 0; i < 6; ++i) {
+ tocHeadersArray[i] = ["", ""];
+ }
+
+ // reset all settings
+ for (i = 1; i < 7; ++i) {
+ var menulist = document.getElementById("header" + i + "Menulist");
+ var menuitem = document.getElementById("header" + i + "none");
+ var textbox = document.getElementById("header" + i + "Class");
+ menulist.selectedItem = menuitem;
+ textbox.setAttribute("disabled", "true");
+ }
+
+ var theDocument = GetCurrentEditor().document;
+
+ // do we already have a TOC in the document ? It should have "mozToc" ID
+ var toc = theDocument.getElementById(kMozToc);
+
+ // default TOC definition, use h1-h6 for TOC entry levels 1-6
+ var headers = "h1 1 h2 2 h3 3 h4 4 h5 5 h6 6";
+
+ var orderedListCheckbox = document.getElementById("orderedListCheckbox");
+ orderedListCheckbox.checked = true;
+
+ if (toc) {
+ // man, there is already a TOC here
+
+ if (toc.getAttribute("class") == "readonly") {
+ // and it's readonly
+ var checkbox = document.getElementById("readOnlyCheckbox");
+ checkbox.checked = true;
+ readonly = true;
+ }
+
+ // let's see if it's an OL or an UL
+ orderedList = toc.nodeName.toLowerCase() == "ol";
+ orderedListCheckbox.checked = orderedList;
+
+ var nodeList = toc.childNodes;
+ // let's look at the children of the TOC ; if we find a comment beginning
+ // with "mozToc", it contains the TOC definition
+ for (i = 0; i < nodeList.length; ++i) {
+ if (
+ nodeList.item(i).nodeType == Node.COMMENT_NODE &&
+ nodeList.item(i).data.startsWith(kMozToc)
+ ) {
+ // yep, there is already a definition here; parse it !
+ headers = nodeList
+ .item(i)
+ .data.substr(
+ kMozTocLength + 1,
+ nodeList.item(i).length - kMozTocLength - 1
+ );
+ break;
+ }
+ }
+ }
+
+ // let's get an array filled with the (tag.class, index level) pairs
+ var headersArray = headers.split(" ");
+
+ for (i = 0; i < headersArray.length; i += 2) {
+ var tag = headersArray[i],
+ className = "";
+ var index = headersArray[i + 1];
+ menulist = document.getElementById("header" + index + "Menulist");
+ if (menulist) {
+ var sep = tag.indexOf(".");
+ if (sep != -1) {
+ // the tag variable contains in fact "tag.className", let's parse
+ // the class and get the real tag name
+ var tmp = tag.substr(0, sep);
+ className = tag.substr(sep + 1, tag.length - sep - 1);
+ tag = tmp;
+ }
+
+ // update the dialog
+ menuitem = document.getElementById("header" + index + tag.toUpperCase());
+ textbox = document.getElementById("header" + index + "Class");
+ menulist.selectedItem = menuitem;
+ if (tag != "") {
+ textbox.removeAttribute("disabled");
+ }
+ if (className != "") {
+ textbox.value = className;
+ }
+ tocHeadersArray[index - 1] = [tag, className];
+ }
+ }
+}
+
+function BuildTOC(update) {
+ // controlClass() is a node filter that accepts a node if
+ // (a) we don't look for a class (b) we look for a class and
+ // node has it
+ function controlClass(node, index) {
+ currentHeaderLevel = index + 1;
+ if (tocHeadersArray[index][1] == "") {
+ // we are not looking for a specific class, this node is ok
+ return NodeFilter.FILTER_ACCEPT;
+ }
+ if (node.getAttribute("class")) {
+ // yep, we look for a class, let's look at all the classes
+ // the node has
+ var classArray = node.getAttribute("class").split(" ");
+ for (var j = 0; j < classArray.length; j++) {
+ if (classArray[j] == tocHeadersArray[index][1]) {
+ // hehe, we found it...
+ return NodeFilter.FILTER_ACCEPT;
+ }
+ }
+ }
+ return NodeFilter.FILTER_SKIP;
+ }
+
+ // the main node filter for our node iterator
+ // it selects the tag names as specified in the dialog
+ // then calls the controlClass filter above
+ function acceptNode(node) {
+ switch (node.nodeName.toLowerCase()) {
+ case tocHeadersArray[0][0]:
+ return controlClass(node, 0);
+ case tocHeadersArray[1][0]:
+ return controlClass(node, 1);
+ case tocHeadersArray[2][0]:
+ return controlClass(node, 2);
+ case tocHeadersArray[3][0]:
+ return controlClass(node, 3);
+ case tocHeadersArray[4][0]:
+ return controlClass(node, 4);
+ case tocHeadersArray[5][0]:
+ return controlClass(node, 5);
+ default:
+ return NodeFilter.FILTER_SKIP;
+ }
+ }
+
+ var editor = GetCurrentEditor();
+ var theDocument = editor.document;
+ // let's create a TreeWalker to look for our nodes
+ var treeWalker = theDocument.createTreeWalker(
+ theDocument.documentElement,
+ NodeFilter.SHOW_ELEMENT,
+ acceptNode,
+ true
+ );
+ // we need an array to store all TOC entries we find in the document
+ var tocArray = [];
+ if (treeWalker) {
+ var tocSourceNode = treeWalker.nextNode();
+ while (tocSourceNode) {
+ var headerIndex = currentHeaderLevel;
+
+ // we have a node, we need to get all its textual contents
+ var textTreeWalker = theDocument.createTreeWalker(
+ tocSourceNode,
+ NodeFilter.SHOW_TEXT,
+ null,
+ true
+ );
+ var textNode = textTreeWalker.nextNode(),
+ headerText = "";
+ while (textNode) {
+ headerText += textNode.data;
+ textNode = textTreeWalker.nextNode();
+ }
+
+ var anchor = tocSourceNode.firstChild,
+ id;
+ // do we have a named anchor as 1st child of our node ?
+ if (
+ anchor.nodeName.toLowerCase() == "a" &&
+ anchor.hasAttribute("name") &&
+ anchor.getAttribute("name").startsWith(kMozTocIdPrefix)
+ ) {
+ // yep, get its name
+ id = anchor.getAttribute("name");
+ } else {
+ // no we don't and we need to create one
+ anchor = theDocument.createElement("a");
+ tocSourceNode.insertBefore(anchor, tocSourceNode.firstChild);
+ // let's give it a random ID
+ var c = 1000000 * Math.random();
+ id = kMozTocIdPrefix + Math.round(c);
+ anchor.setAttribute("name", id);
+ anchor.setAttribute(
+ "class",
+ kMozTocClassPrefix + tocSourceNode.nodeName.toUpperCase()
+ );
+ }
+ // and store that new entry in our array
+ tocArray.push(headerIndex, headerText, id);
+ tocSourceNode = treeWalker.nextNode();
+ }
+ }
+
+ /* generate the TOC itself */
+ headerIndex = 0;
+ var item, toc;
+ for (var i = 0; i < tocArray.length; i += 3) {
+ if (!headerIndex) {
+ // do we need to create an ol/ul container for the first entry ?
+ ++headerIndex;
+ toc = theDocument.getElementById(kMozToc);
+ if (!toc || !update) {
+ // we need to create a list container for the table of contents
+ toc = GetCurrentEditor().createElementWithDefaults(
+ orderedList ? "ol" : "ul"
+ );
+ // grrr, we need to create a LI inside the list otherwise
+ // Composer will refuse an empty list and will remove it !
+ var pit = theDocument.createElement("li");
+ toc.appendChild(pit);
+ GetCurrentEditor().insertElementAtSelection(toc, true);
+ // ah, now it's inserted so let's remove the useless list item...
+ toc.removeChild(pit);
+ // we need to recognize later that this list is our TOC
+ toc.setAttribute("id", kMozToc);
+ } else if (orderedList != (toc.nodeName.toLowerCase() == "ol")) {
+ // we have to update an existing TOC, is the existing TOC of the
+ // desired type (ordered or not) ?
+
+ // nope, we have to recreate the list
+ var newToc = GetCurrentEditor().createElementWithDefaults(
+ orderedList ? "ol" : "ul"
+ );
+ toc.parentNode.insertBefore(newToc, toc);
+ // and remove the old one
+ toc.remove();
+ toc = newToc;
+ toc.setAttribute("id", kMozToc);
+ } else {
+ // we can keep the list itself but let's get rid of the TOC entries
+ while (toc.hasChildNodes()) {
+ toc.lastChild.remove();
+ }
+ }
+
+ var commentText = "mozToc ";
+ for (var j = 0; j < 6; j++) {
+ if (tocHeadersArray[j][0] != "") {
+ commentText += tocHeadersArray[j][0];
+ if (tocHeadersArray[j][1] != "") {
+ commentText += "." + tocHeadersArray[j][1];
+ }
+ commentText += " " + (j + 1) + " ";
+ }
+ }
+ // important, we have to remove trailing spaces
+ commentText = TrimStringRight(commentText);
+
+ // forge a comment we'll insert in the TOC ; that comment will hold
+ // the TOC definition for us
+ var ct = theDocument.createComment(commentText);
+ toc.appendChild(ct);
+
+ // assign a special class to the TOC top element if the TOC is readonly
+ // the definition of this class is in EditorOverride.css
+ if (readonly) {
+ toc.setAttribute("class", "readonly");
+ } else {
+ toc.removeAttribute("class");
+ }
+
+ // We need a new variable to hold the local ul/ol container
+ // The toplevel TOC element is not the parent element of a
+ // TOC entry if its depth is > 1...
+ var tocList = toc;
+ // create a list item
+ var tocItem = theDocument.createElement("li");
+ // and an anchor in this list item
+ var tocAnchor = theDocument.createElement("a");
+ // make it target the source of the TOC entry
+ tocAnchor.setAttribute("href", "#" + tocArray[i + 2]);
+ // and put the textual contents of the TOC entry in that anchor
+ var tocEntry = theDocument.createTextNode(tocArray[i + 1]);
+ // now, insert everything where it has to be inserted
+ tocAnchor.appendChild(tocEntry);
+ tocItem.appendChild(tocAnchor);
+ tocList.appendChild(tocItem);
+ item = tocList;
+ } else {
+ if (tocArray[i] < headerIndex) {
+ // if the depth of the new TOC entry is less than the depth of the
+ // last entry we created, find the good ul/ol ancestor
+ for (j = headerIndex - tocArray[i]; j > 0; --j) {
+ if (item != toc) {
+ item = item.parentNode.parentNode;
+ }
+ }
+ tocItem = theDocument.createElement("li");
+ } else if (tocArray[i] > headerIndex) {
+ // to the contrary, it's deeper than the last one
+ // we need to create sub ul/ol's and li's
+ for (j = tocArray[i] - headerIndex; j > 0; --j) {
+ tocList = theDocument.createElement(orderedList ? "ol" : "ul");
+ item.lastChild.appendChild(tocList);
+ tocItem = theDocument.createElement("li");
+ tocList.appendChild(tocItem);
+ item = tocList;
+ }
+ } else {
+ tocItem = theDocument.createElement("li");
+ }
+ tocAnchor = theDocument.createElement("a");
+ tocAnchor.setAttribute("href", "#" + tocArray[i + 2]);
+ tocEntry = theDocument.createTextNode(tocArray[i + 1]);
+ tocAnchor.appendChild(tocEntry);
+ tocItem.appendChild(tocAnchor);
+ item.appendChild(tocItem);
+ headerIndex = tocArray[i];
+ }
+ }
+ SaveWindowLocation();
+}
+
+function selectHeader(elt, index) {
+ var tag = elt.value;
+ tocHeadersArray[index - 1][0] = tag;
+ var textbox = document.getElementById("header" + index + "Class");
+ if (tag == "") {
+ textbox.setAttribute("disabled", "true");
+ } else {
+ textbox.removeAttribute("disabled");
+ }
+}
+
+function changeClass(elt, index) {
+ tocHeadersArray[index - 1][1] = elt.value;
+}
+
+function ToggleReadOnlyToc(elt) {
+ readonly = elt.checked;
+}
+
+function ToggleOrderedList(elt) {
+ orderedList = elt.checked;
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdInsertTOC.xhtml b/comm/suite/editor/components/dialogs/content/EdInsertTOC.xhtml
new file mode 100644
index 0000000000..8d82bac046
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInsertTOC.xhtml
@@ -0,0 +1,225 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorInsertTOC.dtd">
+
+<dialog title="&Window.title;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup();"
+ oncancel="window.close(); return true;">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdInsertTOC.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+ <spacer id="dummy" style="display:none"/>
+ <vbox flex="1">
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&buildToc.label;</label>
+ </hbox>
+ <grid>
+ <columns><column/><column style="min-width: 6em"/><column/></columns>
+ <rows>
+ <row align="center">
+ <spacer/>
+ <label value="&tag.label;"/>
+ <label value="&class.label;"/>
+ </row>
+ <row align="center">
+ <label value="&header1.label;"/>
+ <menulist id="header1Menulist">
+ <menupopup>
+ <menuitem id="header1none" label="--" value=""
+ oncommand="selectHeader(this, 1)"/>
+ <menuseparator/>
+ <menuitem id="header1H1" label="h1" value="h1"
+ oncommand="selectHeader(this, 1)"/>
+ <menuitem id="header1H2" label="h2" value="h2"
+ oncommand="selectHeader(this, 1)"/>
+ <menuitem id="header1H3" label="h3" value="h3"
+ oncommand="selectHeader(this, 1)"/>
+ <menuitem id="header1H4" label="h4" value="h4"
+ oncommand="selectHeader(this, 1)"/>
+ <menuitem id="header1H5" label="h5" value="h5"
+ oncommand="selectHeader(this, 1)"/>
+ <menuitem id="header1H6" label="h6" value="h6"
+ oncommand="selectHeader(this, 1)"/>
+ <menuitem id="header1DIV" label="div" value="div"
+ oncommand="selectHeader(this, 1)"/>
+ <menuitem id="header1P" label="p" value="p"
+ oncommand="selectHeader(this, 1)"/>
+ </menupopup>
+ </menulist>
+ <textbox id="header1Class" size="10"
+ oninput="changeClass(this, 1)"/>
+ </row>
+
+ <row align="center">
+ <label value="&header2.label;"/>
+ <menulist id="header2Menulist">
+ <menupopup>
+ <menuitem id="header2none" label="--" value=""
+ oncommand="selectHeader(this, 2)"/>
+ <menuseparator/>
+ <menuitem id="header2H1" label="h1" value="h1"
+ oncommand="selectHeader(this, 2)"/>
+ <menuitem id="header2H2" label="h2" value="h2"
+ oncommand="selectHeader(this, 2)"/>
+ <menuitem id="header2H3" label="h3" value="h3"
+ oncommand="selectHeader(this, 2)"/>
+ <menuitem id="header2H4" label="h4" value="h4"
+ oncommand="selectHeader(this, 2)"/>
+ <menuitem id="header2H5" label="h5" value="h5"
+ oncommand="selectHeader(this, 2)"/>
+ <menuitem id="header2H6" label="h6" value="h6"
+ oncommand="selectHeader(this, 2)"/>
+ <menuitem id="header2DIV" label="div" value="div"
+ oncommand="selectHeader(this, 2)"/>
+ <menuitem id="header2P" label="p" value="p"
+ oncommand="selectHeader(this, 2)"/>
+ </menupopup>
+ </menulist>
+ <textbox id="header2Class" size="10"
+ oninput="changeClass(this, 2)"/>
+ </row>
+
+ <row align="center">
+ <label value="&header3.label;"/>
+ <menulist id="header3Menulist">
+ <menupopup>
+ <menuitem id="header3none" label="--" value=""
+ oncommand="selectHeader(this, 3)"/>
+ <menuseparator/>
+ <menuitem id="header3H1" label="h1" value="h1"
+ oncommand="selectHeader(this, 3)"/>
+ <menuitem id="header3H2" label="h2" value="h2"
+ oncommand="selectHeader(this, 3)"/>
+ <menuitem id="header3H3" label="h3" value="h3"
+ oncommand="selectHeader(this, 3)"/>
+ <menuitem id="header3H4" label="h4" value="h4"
+ oncommand="selectHeader(this, 3)"/>
+ <menuitem id="header3H5" label="h5" value="h5"
+ oncommand="selectHeader(this, 3)"/>
+ <menuitem id="header3H6" label="h6" value="h6"
+ oncommand="selectHeader(this, 3)"/>
+ <menuitem id="header3DIV" label="div" value="div"
+ oncommand="selectHeader(this, 3)"/>
+ <menuitem id="header3P" label="p" value="p"
+ oncommand="selectHeader(this, 3)"/>
+ </menupopup>
+ </menulist>
+ <textbox id="header3Class" size="10"
+ oninput="changeClass(this, 3)"/>
+ </row>
+
+ <row align="center">
+ <label value="&header4.label;"/>
+ <menulist id="header4Menulist">
+ <menupopup>
+ <menuitem id="header4none" label="--" value=""
+ oncommand="selectHeader(this, 4)"/>
+ <menuseparator/>
+ <menuitem id="header4H1" label="h1" value="h1"
+ oncommand="selectHeader(this, 4)"/>
+ <menuitem id="header4H2" label="h2" value="h2"
+ oncommand="selectHeader(this, 4)"/>
+ <menuitem id="header4H3" label="h3" value="h3"
+ oncommand="selectHeader(this, 4)"/>
+ <menuitem id="header4H4" label="h4" value="h4"
+ oncommand="selectHeader(this, 4)"/>
+ <menuitem id="header4H5" label="h5" value="h5"
+ oncommand="selectHeader(this, 4)"/>
+ <menuitem id="header4H6" label="h6" value="h6"
+ oncommand="selectHeader(this, 4)"/>
+ <menuitem id="header4DIV" label="div" value="div"
+ oncommand="selectHeader(this, 4)"/>
+ <menuitem id="header4P" label="p" value="p"
+ oncommand="selectHeader(this, 4)"/>
+ </menupopup>
+ </menulist>
+ <textbox id="header4Class" size="10"
+ oninput="changeClass(this, 4)"/>
+ </row>
+
+ <row align="center">
+ <label value="&header5.label;"/>
+ <menulist id="header5Menulist">
+ <menupopup>
+ <menuitem id="header5none" label="--" value=""
+ oncommand="selectHeader(this, 5)"/>
+ <menuseparator/>
+ <menuitem id="header5H1" label="h1" value="h1"
+ oncommand="selectHeader(this, 5)"/>
+ <menuitem id="header5H2" label="h2" value="h2"
+ oncommand="selectHeader(this, 5)"/>
+ <menuitem id="header5H3" label="h3" value="h3"
+ oncommand="selectHeader(this, 5)"/>
+ <menuitem id="header5H4" label="h4" value="h4"
+ oncommand="selectHeader(this, 5)"/>
+ <menuitem id="header5H5" label="h5" value="h5"
+ oncommand="selectHeader(this, 5)"/>
+ <menuitem id="header5H6" label="h6" value="h6"
+ oncommand="selectHeader(this, 5)"/>
+ <menuitem id="header5DIV" label="div" value="div"
+ oncommand="selectHeader(this, 5)"/>
+ <menuitem id="header5P" label="p" value="p"
+ oncommand="selectHeader(this, 5)"/>
+ </menupopup>
+ </menulist>
+ <textbox id="header5Class" size="10"
+ oninput="changeClass(this, 5)"/>
+ </row>
+
+ <row align="center">
+ <label value="&header6.label;"/>
+ <menulist id="header6Menulist">
+ <menupopup>
+ <menuitem id="header6none" label="--" value=""
+ oncommand="selectHeader(this, 6)"/>
+ <menuseparator/>
+ <menuitem id="header6H1" label="h1" value="h1"
+ oncommand="selectHeader(this, 6)"/>
+ <menuitem id="header6H2" label="h2" value="h2"
+ oncommand="selectHeader(this, 6)"/>
+ <menuitem id="header6H3" label="h3" value="h3"
+ oncommand="selectHeader(this, 6)"/>
+ <menuitem id="header6H4" label="h4" value="h4"
+ oncommand="selectHeader(this, 6)"/>
+ <menuitem id="header6H5" label="h5" value="h5"
+ oncommand="selectHeader(this, 6)"/>
+ <menuitem id="header6H6" label="h6" value="h6"
+ oncommand="selectHeader(this, 6)"/>
+ <menuitem id="header6DIV" label="div" value="div"
+ oncommand="selectHeader(this, 6)"/>
+ <menuitem id="header6P" label="p" value="p"
+ oncommand="selectHeader(this, 6)"/>
+ </menupopup>
+ </menulist>
+ <textbox id="header6Class" size="10"
+ oninput="changeClass(this, 6)"/>
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+ <vbox>
+ <checkbox id="orderedListCheckbox"
+ label="&orderedList.label;"
+ oncommand="ToggleOrderedList(this)"/>
+ <checkbox id="readOnlyCheckbox"
+ label="&makeReadOnly.label;"
+ oncommand="ToggleReadOnlyToc(this)"/>
+ </vbox>
+ <separator class="groove"/>
+ </vbox>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdInsertTable.js b/comm/suite/editor/components/dialogs/content/EdInsertTable.js
new file mode 100644
index 0000000000..0053f9fd94
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInsertTable.js
@@ -0,0 +1,254 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+// Cancel() is in EdDialogCommon.js
+
+var gTableElement = null;
+var gRows;
+var gColumns;
+var gActiveEditor;
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ gActiveEditor = GetCurrentTableEditor();
+ if (!gActiveEditor) {
+ dump("Failed to get active editor!\n");
+ window.close();
+ return;
+ }
+
+ try {
+ gTableElement = gActiveEditor.createElementWithDefaults("table");
+ } catch (e) {}
+
+ if (!gTableElement) {
+ dump("Failed to create a new table!\n");
+ window.close();
+ return;
+ }
+ gDialog.rowsInput = document.getElementById("rowsInput");
+ gDialog.columnsInput = document.getElementById("columnsInput");
+ gDialog.widthInput = document.getElementById("widthInput");
+ gDialog.borderInput = document.getElementById("borderInput");
+ gDialog.widthPixelOrPercentMenulist = document.getElementById(
+ "widthPixelOrPercentMenulist"
+ );
+ gDialog.OkButton = document.documentElement.getButton("accept");
+
+ // Make a copy to use for AdvancedEdit
+ globalElement = gTableElement.cloneNode(false);
+ try {
+ if (
+ Services.prefs.getBoolPref("editor.use_css") &&
+ IsHTMLEditor() &&
+ !(gActiveEditor.flags & Ci.nsIEditor.eEditorMailMask)
+ ) {
+ // only for Composer and not for htmlmail
+ globalElement.setAttribute("style", "text-align: left;");
+ }
+ } catch (e) {}
+
+ // Initialize all widgets with image attributes
+ InitDialog();
+
+ // Set initial number to 2 rows, 2 columns:
+ // Note, these are not attributes on the table,
+ // so don't put them in InitDialog(),
+ // else the user's values will be trashed when they use
+ // the Advanced Edit dialog
+ gDialog.rowsInput.value = 2;
+ gDialog.columnsInput.value = 2;
+
+ // If no default value on the width, set to 100%
+ if (gDialog.widthInput.value.length == 0) {
+ gDialog.widthInput.value = "100";
+ gDialog.widthPixelOrPercentMenulist.selectedIndex = 1;
+ }
+
+ SetTextboxFocusById("rowsInput");
+
+ SetWindowLocation();
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+// by AdvancedEdit(), which is shared by all property dialogs
+function InitDialog() {
+ // Get default attributes set on the created table:
+ // Get the width attribute of the element, stripping out "%"
+ // This sets contents of menu combobox list
+ // 2nd param = null: Use current selection to find if parent is table cell or window
+ gDialog.widthInput.value = InitPixelOrPercentMenulist(
+ globalElement,
+ null,
+ "width",
+ "widthPixelOrPercentMenulist",
+ gPercent
+ );
+ gDialog.borderInput.value = globalElement.getAttribute("border");
+}
+
+function ChangeRowOrColumn(id) {
+ // Allow only integers
+ forceInteger(id);
+
+ // Enable OK only if both rows and columns have a value > 0
+ var enable =
+ gDialog.rowsInput.value.length > 0 &&
+ gDialog.rowsInput.value > 0 &&
+ gDialog.columnsInput.value.length > 0 &&
+ gDialog.columnsInput.value > 0;
+
+ SetElementEnabled(gDialog.OkButton, enable);
+ SetElementEnabledById("AdvancedEditButton1", enable);
+}
+
+// Get and validate data from widgets.
+// Set attributes on globalElement so they can be accessed by AdvancedEdit()
+function ValidateData() {
+ gRows = ValidateNumber(
+ gDialog.rowsInput,
+ null,
+ 1,
+ gMaxRows,
+ null,
+ null,
+ true
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ gColumns = ValidateNumber(
+ gDialog.columnsInput,
+ null,
+ 1,
+ gMaxColumns,
+ null,
+ null,
+ true
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ // Set attributes: NOTE: These may be empty strings (last param = false)
+ ValidateNumber(
+ gDialog.borderInput,
+ null,
+ 0,
+ gMaxPixels,
+ globalElement,
+ "border",
+ false
+ );
+ // TODO: Deal with "BORDER" without value issue
+ if (gValidationError) {
+ return false;
+ }
+
+ ValidateNumber(
+ gDialog.widthInput,
+ gDialog.widthPixelOrPercentMenulist,
+ 1,
+ gMaxTableSize,
+ globalElement,
+ "width",
+ false
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ return true;
+}
+
+function onAccept(event) {
+ if (ValidateData()) {
+ gActiveEditor.beginTransaction();
+ try {
+ gActiveEditor.cloneAttributes(gTableElement, globalElement);
+
+ // Create necessary rows and cells for the table
+ var tableBody = gActiveEditor.createElementWithDefaults("tbody");
+ if (tableBody) {
+ gTableElement.appendChild(tableBody);
+
+ // Create necessary rows and cells for the table
+ for (var i = 0; i < gRows; i++) {
+ var newRow = gActiveEditor.createElementWithDefaults("tr");
+ if (newRow) {
+ tableBody.appendChild(newRow);
+ for (var j = 0; j < gColumns; j++) {
+ var newCell = gActiveEditor.createElementWithDefaults("td");
+ if (newCell) {
+ newRow.appendChild(newCell);
+ }
+ }
+ }
+ }
+ }
+ // Detect when entire cells are selected:
+ // Get number of cells selected
+ var tagNameObj = { value: "" };
+ var countObj = { value: 0 };
+ var element = gActiveEditor.getSelectedOrParentTableElement(
+ tagNameObj,
+ countObj
+ );
+ var deletePlaceholder = false;
+
+ if (tagNameObj.value == "table") {
+ // Replace entire selected table with new table, so delete the table
+ gActiveEditor.deleteTable();
+ } else if (tagNameObj.value == "td") {
+ if (countObj.value >= 1) {
+ if (countObj.value > 1) {
+ // Assume user wants to replace a block of
+ // contiguous cells with a table, so
+ // join the selected cells
+ gActiveEditor.joinTableCells(false);
+
+ // Get the cell everything was merged into
+ element = gActiveEditor.getFirstSelectedCell();
+
+ // Collapse selection into just that cell
+ gActiveEditor.selection.collapse(element, 0);
+ }
+
+ if (element) {
+ // Empty just the contents of the cell
+ gActiveEditor.deleteTableCellContents();
+
+ // Collapse selection to start of empty cell...
+ gActiveEditor.selection.collapse(element, 0);
+ // ...but it will contain a <br> placeholder
+ deletePlaceholder = true;
+ }
+ }
+ }
+
+ // true means delete selection when inserting
+ gActiveEditor.insertElementAtSelection(gTableElement, true);
+
+ if (deletePlaceholder && gTableElement && gTableElement.nextSibling) {
+ // Delete the placeholder <br>
+ gActiveEditor.deleteNode(gTableElement.nextSibling);
+ }
+ } catch (e) {}
+
+ gActiveEditor.endTransaction();
+
+ SaveWindowLocation();
+ return;
+ }
+ event.preventDefault();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdInsertTable.xhtml b/comm/suite/editor/components/dialogs/content/EdInsertTable.xhtml
new file mode 100644
index 0000000000..b376d5f0be
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdInsertTable.xhtml
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edInsertTable SYSTEM "chrome://editor/locale/EditorInsertTable.dtd">
+%edInsertTable;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload = "Startup()">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdInsertTable.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&size.label;</label>
+ </hbox>
+ <grid>
+ <columns>
+ <column flex="1"/>
+ <column flex="1"/>
+ <column flex="6"/>
+ </columns>
+ <rows>
+ <row align="center">
+ <label control="rowsInput" class="align-right"
+ value="&numRowsEditField.label;"
+ accesskey="&numRowsEditField.accessKey;"/>
+ <textbox class="narrow" id="rowsInput" oninput="ChangeRowOrColumn(this.id)" />
+ <spacer/>
+ </row>
+ <row align="center">
+ <label control="columnsInput" class="align-right"
+ value="&numColumnsEditField.label;"
+ accesskey="&numColumnsEditField.accessKey;"/>
+ <textbox class="narrow" id="columnsInput" oninput="ChangeRowOrColumn(this.id)" />
+ <spacer/>
+ </row>
+ <row align="center">
+ <label control="widthInput" class="align-right"
+ value="&widthEditField.label;"
+ accesskey="&widthEditField.accessKey;"/>
+ <textbox class="narrow" id="widthInput" oninput="forceInteger(this.id)" />
+ <menulist id="widthPixelOrPercentMenulist" flex="1"/>
+ <!-- child elements are appended by JS -->
+ </row>
+ </rows>
+ </grid>
+ <spacer class="spacer"/>
+ </groupbox>
+ <spacer class="spacer"/>
+ <hbox align="center">
+ <label control="borderInput" class="align-right"
+ value="&borderEditField.label;"
+ accesskey="&borderEditField.accessKey;"
+ tooltiptext="&borderEditField.tooltip;" />
+ <textbox class="narrow" id="borderInput" oninput="forceInteger(this.id)" />
+ <label value="&pixels.label;"/>
+ </hbox>
+ <vbox id="AdvancedEdit">
+ <hbox flex="1" style="margin-top: 0.2em" align="center">
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton1" oncommand="onAdvancedEdit()" label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;" tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator id="advancedSeparator" class="groove"/>
+ </vbox>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdLabelProps.js b/comm/suite/editor/components/dialogs/content/EdLabelProps.js
new file mode 100644
index 0000000000..ec96878ea6
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdLabelProps.js
@@ -0,0 +1,118 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var labelElement;
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ dump("Failed to get active editor!\n");
+ window.close();
+ return;
+ }
+
+ gDialog.editText = document.getElementById("EditText");
+ gDialog.labelText = document.getElementById("LabelText");
+ gDialog.labelFor = document.getElementById("LabelFor");
+ gDialog.labelAccessKey = document.getElementById("LabelAccessKey");
+
+ labelElement = window.arguments[0];
+
+ // Make a copy to use for AdvancedEdit
+ globalElement = labelElement.cloneNode(false);
+
+ InitDialog();
+
+ var range = editor.document.createRange();
+ range.selectNode(labelElement);
+ gDialog.labelText.value = range.toString();
+
+ if (labelElement.innerHTML.includes("<")) {
+ gDialog.editText.checked = false;
+ gDialog.editText.disabled = false;
+ gDialog.labelText.disabled = true;
+ gDialog.editText.addEventListener(
+ "command",
+ () =>
+ Services.prompt.alert(
+ window,
+ GetString("Alert"),
+ GetString("EditTextWarning")
+ ),
+ { capture: false, once: true }
+ );
+ SetTextboxFocus(gDialog.labelFor);
+ } else {
+ SetTextboxFocus(gDialog.labelText);
+ }
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ gDialog.labelFor.value = globalElement.getAttribute("for");
+ gDialog.labelAccessKey.value = globalElement.getAttribute("accesskey");
+}
+
+function RemoveLabel() {
+ RemoveContainer(labelElement);
+ SaveWindowLocation();
+ window.close();
+}
+
+function ValidateData() {
+ if (gDialog.labelFor.value) {
+ globalElement.setAttribute("for", gDialog.labelFor.value);
+ } else {
+ globalElement.removeAttribute("for");
+ }
+ if (gDialog.labelAccessKey.value) {
+ globalElement.setAttribute("accesskey", gDialog.labelAccessKey.value);
+ } else {
+ globalElement.removeAttribute("accesskey");
+ }
+ return true;
+}
+
+function onAccept() {
+ // All values are valid - copy to actual element in doc
+ ValidateData();
+
+ var editor = GetCurrentEditor();
+
+ editor.beginTransaction();
+
+ try {
+ if (gDialog.editText.checked) {
+ editor.setShouldTxnSetSelection(false);
+
+ while (labelElement.firstChild) {
+ editor.deleteNode(labelElement.firstChild);
+ }
+ if (gDialog.labelText.value) {
+ editor.insertNode(
+ editor.document.createTextNode(gDialog.labelText.value),
+ labelElement,
+ 0
+ );
+ }
+
+ editor.setShouldTxnSetSelection(true);
+ }
+
+ editor.cloneAttributes(labelElement, globalElement);
+ } catch (e) {}
+
+ editor.endTransaction();
+
+ SaveWindowLocation();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdLabelProps.xhtml b/comm/suite/editor/components/dialogs/content/EdLabelProps.xhtml
new file mode 100644
index 0000000000..21d964f1fd
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdLabelProps.xhtml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edLabelProperties SYSTEM "chrome://editor/locale/EditorLabelProperties.dtd">
+%edLabelProperties;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup();"
+ buttons="accept,cancel">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdLabelProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header" accesskey="&Settings.accesskey;">&Settings.label;</label>
+ </hbox>
+ <grid><columns><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <checkbox id="EditText" label="&EditLabelText.label;" accesskey="&EditLabelText.accesskey;" checked="true" disabled="true"
+ oncommand="gDialog.labelText.disabled = !gDialog.editText.checked;"/>
+ <textbox id="LabelText" accesskey="&Settings.accesskey;"/>
+ </row>
+ <row align="center">
+ <label control="LabelFor" value="&LabelFor.label;" accesskey="&LabelFor.accesskey;"/>
+ <textbox id="LabelFor"/>
+ </row>
+ <row align="center">
+ <label control="LabelAccessKey" value="&AccessKey.label;" accesskey="&AccessKey.accesskey;"/>
+ <hbox>
+ <textbox id="LabelAccessKey" class="narrow"/>
+ </hbox>
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+
+ <!-- from EdDialogOverlay -->
+ <hbox flex="1" style="margin-top: 0.2em">
+ <button id="RemoveLabel" label="&RemoveLabel.label;" accesskey="&RemoveLabel.accesskey;" oncommand="RemoveLabel();"/>
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton"
+ oncommand="onAdvancedEdit();"
+ label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;"
+ tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator class="groove"/>
+
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdLinkProps.js b/comm/suite/editor/components/dialogs/content/EdLinkProps.js
new file mode 100644
index 0000000000..6504496a51
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdLinkProps.js
@@ -0,0 +1,331 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var gActiveEditor;
+var anchorElement = null;
+var imageElement = null;
+var insertNew = false;
+var replaceExistingLink = false;
+var insertLinkAtCaret;
+var needLinkText = false;
+var href;
+var newLinkText;
+var gHNodeArray = {};
+var gHaveNamedAnchors = false;
+var gHaveHeadings = false;
+var gCanChangeHeadingSelected = true;
+var gCanChangeAnchorSelected = true;
+
+// NOTE: Use "href" instead of "a" to distinguish from Named Anchor
+// The returned node is has an "a" tagName
+var tagName = "href";
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ gActiveEditor = GetCurrentEditor();
+ if (!gActiveEditor) {
+ dump("Failed to get active editor!\n");
+ window.close();
+ return;
+ }
+ // Message was wrapped in a <label> or <div>, so actual text is a child text node
+ gDialog.linkTextCaption = document.getElementById("linkTextCaption");
+ gDialog.linkTextMessage = document.getElementById("linkTextMessage");
+ gDialog.linkTextInput = document.getElementById("linkTextInput");
+ gDialog.hrefInput = document.getElementById("hrefInput");
+ gDialog.makeRelativeLink = document.getElementById("MakeRelativeLink");
+ gDialog.AdvancedEditSection = document.getElementById("AdvancedEdit");
+
+ // See if we have a single selected image
+ imageElement = gActiveEditor.getSelectedElement("img");
+
+ if (imageElement) {
+ // Get the parent link if it exists -- more efficient than GetSelectedElement()
+ anchorElement = gActiveEditor.getElementOrParentByTagName(
+ "href",
+ imageElement
+ );
+ if (anchorElement) {
+ if (anchorElement.childNodes.length > 1) {
+ // If there are other children, then we want to break
+ // this image away by inserting a new link around it,
+ // so make a new node and copy existing attributes
+ anchorElement = anchorElement.cloneNode(false);
+ // insertNew = true;
+ replaceExistingLink = true;
+ }
+ }
+ } else {
+ // Get an anchor element if caret or
+ // entire selection is within the link.
+ anchorElement = gActiveEditor.getSelectedElement(tagName);
+
+ if (anchorElement) {
+ // Select the entire link
+ gActiveEditor.selectElement(anchorElement);
+ } else {
+ // If selection starts in a link, but extends beyond it,
+ // the user probably wants to extend existing link to new selection,
+ // so check if either end of selection is within a link
+ // POTENTIAL PROBLEM: This prevents user from selecting text in an existing
+ // link and making 2 links.
+ // Note that this isn't a problem with images, handled above
+
+ anchorElement = gActiveEditor.getElementOrParentByTagName(
+ "href",
+ gActiveEditor.selection.anchorNode
+ );
+ if (!anchorElement) {
+ anchorElement = gActiveEditor.getElementOrParentByTagName(
+ "href",
+ gActiveEditor.selection.focusNode
+ );
+ }
+
+ if (anchorElement) {
+ // But clone it for reinserting/merging around existing
+ // link that only partially overlaps the selection
+ anchorElement = anchorElement.cloneNode(false);
+ // insertNew = true;
+ replaceExistingLink = true;
+ }
+ }
+ }
+
+ if (!anchorElement) {
+ // No existing link -- create a new one
+ anchorElement = gActiveEditor.createElementWithDefaults(tagName);
+ insertNew = true;
+ // Hide message about removing existing link
+ // document.getElementById("RemoveLinkMsg").hidden = true;
+ }
+ if (!anchorElement) {
+ dump("Failed to get selected element or create a new one!\n");
+ window.close();
+ return;
+ }
+
+ // We insert at caret only when nothing is selected
+ insertLinkAtCaret = gActiveEditor.selection.isCollapsed;
+
+ var selectedText;
+ if (insertLinkAtCaret) {
+ // Groupbox caption:
+ gDialog.linkTextCaption.setAttribute("label", GetString("LinkText"));
+
+ // Message above input field:
+ gDialog.linkTextMessage.setAttribute("value", GetString("EnterLinkText"));
+ gDialog.linkTextMessage.setAttribute(
+ "accesskey",
+ GetString("EnterLinkTextAccessKey")
+ );
+ } else {
+ if (!imageElement) {
+ // We get here if selection is exactly around a link node
+ // Check if selection has some text - use that first
+ selectedText = GetSelectionAsText();
+ if (!selectedText) {
+ // No text, look for first image in the selection
+ var children = anchorElement.childNodes;
+ if (children) {
+ for (var i = 0; i < children.length; i++) {
+ var nodeName = children.item(i).nodeName.toLowerCase();
+ if (nodeName == "img") {
+ imageElement = children.item(i);
+ break;
+ }
+ }
+ }
+ }
+ }
+ // Set "caption" for link source and the source text or image URL
+ if (imageElement) {
+ gDialog.linkTextCaption.setAttribute("label", GetString("LinkImage"));
+ // Link source string is the source URL of image
+ // TODO: THIS DOESN'T HANDLE MULTIPLE SELECTED IMAGES!
+ gDialog.linkTextMessage.setAttribute("value", imageElement.src);
+ } else {
+ gDialog.linkTextCaption.setAttribute("label", GetString("LinkText"));
+ if (selectedText) {
+ // Use just the first 60 characters and add "..."
+ gDialog.linkTextMessage.setAttribute(
+ "value",
+ TruncateStringAtWordEnd(
+ ReplaceWhitespace(selectedText, " "),
+ 60,
+ true
+ )
+ );
+ } else {
+ gDialog.linkTextMessage.setAttribute(
+ "value",
+ GetString("MixedSelection")
+ );
+ }
+ }
+ }
+
+ // Make a copy to use for AdvancedEdit and onSaveDefault
+ globalElement = anchorElement.cloneNode(false);
+
+ // Get the list of existing named anchors and headings
+ FillLinkMenulist(gDialog.hrefInput, gHNodeArray);
+
+ // We only need to test for this once per dialog load
+ gHaveDocumentUrl = GetDocumentBaseUrl();
+
+ // Set data for the dialog controls
+ InitDialog();
+
+ // Search for a URI pattern in the selected text
+ // as candidate href
+ selectedText = TrimString(selectedText);
+ if (!gDialog.hrefInput.value && TextIsURI(selectedText)) {
+ gDialog.hrefInput.value = selectedText;
+ }
+
+ // Set initial focus
+ if (insertLinkAtCaret) {
+ // We will be using the HREF inputbox, so text message
+ SetTextboxFocus(gDialog.linkTextInput);
+ } else {
+ SetTextboxFocus(gDialog.hrefInput);
+
+ // We will not insert a new link at caret, so remove link text input field
+ gDialog.linkTextInput.hidden = true;
+ gDialog.linkTextInput = null;
+ }
+
+ // This sets enable state on OK button
+ doEnabling();
+
+ SetWindowLocation();
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+// by AdvancedEdit(), which is shared by all property dialogs
+function InitDialog() {
+ // Must use getAttribute, not "globalElement.href",
+ // or foreign chars aren't converted correctly!
+ gDialog.hrefInput.value = globalElement.getAttribute("href");
+
+ // Set "Relativize" checkbox according to current URL state
+ SetRelativeCheckbox(gDialog.makeRelativeLink);
+}
+
+function doEnabling() {
+ // We disable Ok button when there's no href text only if inserting a new link
+ var enable = insertNew
+ ? TrimString(gDialog.hrefInput.value).length > 0
+ : true;
+
+ // anon. content, so can't use SetElementEnabledById here
+ var dialogNode = document.getElementById("linkDlg");
+ dialogNode.getButton("accept").disabled = !enable;
+
+ SetElementEnabledById("AdvancedEditButton1", enable);
+}
+
+function ChangeLinkLocation() {
+ SetRelativeCheckbox(gDialog.makeRelativeLink);
+ // Set OK button enable state
+ doEnabling();
+}
+
+// Get and validate data from widgets.
+// Set attributes on globalElement so they can be accessed by AdvancedEdit()
+function ValidateData() {
+ href = TrimString(gDialog.hrefInput.value);
+ if (href) {
+ // Set the HREF directly on the editor document's anchor node
+ // or on the newly-created node if insertNew is true
+ globalElement.setAttribute("href", href);
+ } else if (insertNew) {
+ // We must have a URL to insert a new link
+ // NOTE: We accept an empty HREF on existing link to indicate removing the link
+ ShowInputErrorMessage(GetString("EmptyHREFError"));
+ return false;
+ }
+ if (gDialog.linkTextInput) {
+ // The text we will insert isn't really an attribute,
+ // but it makes sense to validate it
+ newLinkText = TrimString(gDialog.linkTextInput.value);
+ if (!newLinkText) {
+ if (href) {
+ newLinkText = href;
+ } else {
+ ShowInputErrorMessage(GetString("EmptyLinkTextError"));
+ SetTextboxFocus(gDialog.linkTextInput);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+function onAccept(event) {
+ if (ValidateData()) {
+ if (href.length > 0) {
+ // Copy attributes to element we are changing or inserting
+ gActiveEditor.cloneAttributes(anchorElement, globalElement);
+
+ // Coalesce into one undo transaction
+ gActiveEditor.beginTransaction();
+
+ // Get text to use for a new link
+ if (insertLinkAtCaret) {
+ // Append the link text as the last child node
+ // of the anchor node
+ var textNode = gActiveEditor.document.createTextNode(newLinkText);
+ if (textNode) {
+ anchorElement.appendChild(textNode);
+ }
+ try {
+ gActiveEditor.insertElementAtSelection(anchorElement, false);
+ } catch (e) {
+ dump("Exception occurred in InsertElementAtSelection\n");
+ return;
+ }
+ } else if (insertNew || replaceExistingLink) {
+ // Link source was supplied by the selection,
+ // so insert a link node as parent of this
+ // (may be text, image, or other inline content)
+ try {
+ gActiveEditor.insertLinkAroundSelection(anchorElement);
+ } catch (e) {
+ dump("Exception occurred in InsertElementAtSelection\n");
+ return;
+ }
+ }
+ // Check if the link was to a heading
+ if (href in gHNodeArray) {
+ var anchorNode = gActiveEditor.createElementWithDefaults("a");
+ if (anchorNode) {
+ anchorNode.name = href.substr(1);
+
+ // Insert the anchor into the document,
+ // but don't let the transaction change the selection
+ gActiveEditor.setShouldTxnSetSelection(false);
+ gActiveEditor.insertNode(anchorNode, gHNodeArray[href], 0);
+ gActiveEditor.setShouldTxnSetSelection(true);
+ }
+ }
+ gActiveEditor.endTransaction();
+ } else if (!insertNew) {
+ // We already had a link, but empty HREF means remove it
+ EditorRemoveTextProperty("href", "");
+ }
+ SaveWindowLocation();
+ return;
+ }
+ event.preventDefault();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdLinkProps.xhtml b/comm/suite/editor/components/dialogs/content/EdLinkProps.xhtml
new file mode 100644
index 0000000000..04e147db4c
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdLinkProps.xhtml
@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % linkPropertiesDTD SYSTEM "chrome://editor/locale/EditorLinkProperties.dtd">
+%linkPropertiesDTD;
+<!ENTITY % composeEditorOverlayDTD SYSTEM "chrome://messenger/locale/messengercompose/mailComposeEditorOverlay.dtd">
+%composeEditorOverlayDTD;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog id="linkDlg" title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload = "Startup()">
+
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdLinkProps.js"/>
+ <script src="chrome://editor/content/EdImageLinkLoader.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <vbox style="min-width: 20em">
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label id="linkTextCaption" class="header"/>
+ </hbox>
+ <vbox>
+ <label id="linkTextMessage" control="linkTextInput"/>
+ <textbox id="linkTextInput"/>
+ </vbox>
+ </groupbox>
+
+ <groupbox id="LinkURLBox">
+ <hbox class="groupbox-title">
+ <label class="header">&LinkURLBox.label;</label>
+ </hbox>
+ <vbox id="LinkLocationBox">
+ <label control="hrefInput"
+ accesskey="&LinkURLEditField2.accessKey;"
+ width="1">&LinkURLEditField2.label;</label>
+ <textbox id="hrefInput" type="text"
+ class="uri-element padded" oninput="ChangeLinkLocation();"/>
+ <hbox align="center">
+ <checkbox id="MakeRelativeLink"
+ for="hrefInput"
+ label="&makeUrlRelative.label;"
+ accesskey="&makeUrlRelative.accessKey;"
+ oncommand="MakeInputValueRelativeOrAbsolute(this);"
+ tooltiptext="&makeUrlRelative.tooltip;"/>
+ <spacer flex="1"/>
+ <button label="&chooseFileLinkButton.label;" accesskey="&chooseFileLinkButton.accessKey;"
+ oncommand="chooseLinkFile();"/>
+ </hbox>
+ </vbox>
+ <checkbox id="AttachSourceToMail"
+ hidden="true"
+ label="&attachLinkSource.label;"
+ accesskey="&attachLinkSource.accesskey;"
+ oncommand="DoAttachSourceCheckbox()"/>
+ </groupbox>
+ </vbox>
+ <vbox id="AdvancedEdit">
+ <hbox flex="1" style="margin-top: 0.2em" align="center">
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton1" oncommand="onAdvancedEdit()" label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;" tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator id="advancedSeparator" class="groove"/>
+ </vbox>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdListProps.js b/comm/suite/editor/components/dialogs/content/EdListProps.js
new file mode 100644
index 0000000000..8d4b78536b
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdListProps.js
@@ -0,0 +1,455 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+// Cancel() is in EdDialogCommon.js
+var gBulletStyleType = "";
+var gNumberStyleType = "";
+var gListElement;
+var gOriginalListType = "";
+var gListType = "";
+var gMixedListSelection = false;
+var gStyleType = "";
+var gOriginalStyleType = "";
+const gOnesArray = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"];
+const gTensArray = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"];
+const gHundredsArray = [
+ "",
+ "C",
+ "CC",
+ "CCC",
+ "CD",
+ "D",
+ "DC",
+ "DCC",
+ "DCCC",
+ "CM",
+];
+const gThousandsArray = [
+ "",
+ "M",
+ "MM",
+ "MMM",
+ "MMMM",
+ "MMMMM",
+ "MMMMMM",
+ "MMMMMMM",
+ "MMMMMMMM",
+ "MMMMMMMMM",
+];
+const gRomanDigits = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 };
+const A = "A".charCodeAt(0);
+const gArabic = "1";
+const gUpperRoman = "I";
+const gLowerRoman = "i";
+const gUpperLetters = "A";
+const gLowerLetters = "a";
+const gDecimalCSS = "decimal";
+const gUpperRomanCSS = "upper-roman";
+const gLowerRomanCSS = "lower-roman";
+const gUpperAlphaCSS = "upper-alpha";
+const gLowerAlphaCSS = "lower-alpha";
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ window.close();
+ return;
+ }
+ gDialog.ListTypeList = document.getElementById("ListType");
+ gDialog.BulletStyleList = document.getElementById("BulletStyle");
+ gDialog.BulletStyleLabel = document.getElementById("BulletStyleLabel");
+ gDialog.StartingNumberInput = document.getElementById("StartingNumber");
+ gDialog.StartingNumberLabel = document.getElementById("StartingNumberLabel");
+ gDialog.AdvancedEditButton = document.getElementById("AdvancedEditButton1");
+ gDialog.RadioGroup = document.getElementById("RadioGroup");
+ gDialog.ChangeAllRadio = document.getElementById("ChangeAll");
+ gDialog.ChangeSelectedRadio = document.getElementById("ChangeSelected");
+
+ // Try to get an existing list(s)
+ var mixedObj = { value: null };
+ try {
+ gListType = editor.getListState(mixedObj, {}, {}, {});
+
+ // We may have mixed list and non-list, or > 1 list type in selection
+ gMixedListSelection = mixedObj.value;
+
+ // Get the list element at the anchor node
+ gListElement = editor.getElementOrParentByTagName("list", null);
+ } catch (e) {}
+
+ // The copy to use in AdvancedEdit
+ if (gListElement) {
+ globalElement = gListElement.cloneNode(false);
+ }
+
+ // Show extra options for changing entire list if we have one already.
+ gDialog.RadioGroup.collapsed = !gListElement;
+ if (gListElement) {
+ // Radio button index is persistent
+ if (gDialog.RadioGroup.getAttribute("index") == "1") {
+ gDialog.RadioGroup.selectedItem = gDialog.ChangeSelectedRadio;
+ } else {
+ gDialog.RadioGroup.selectedItem = gDialog.ChangeAllRadio;
+ }
+ }
+
+ InitDialog();
+
+ gOriginalListType = gListType;
+
+ gDialog.ListTypeList.focus();
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ // Note that if mixed, we we pay attention
+ // only to the anchor node's list type
+ // (i.e., don't confuse user with "mixed" designation)
+ if (gListElement) {
+ gListType = gListElement.nodeName.toLowerCase();
+ } else {
+ gListType = "";
+ }
+
+ gDialog.ListTypeList.value = gListType;
+ gDialog.StartingNumberInput.value = "";
+
+ // Last param = true means attribute value is case-sensitive
+ var type = globalElement
+ ? GetHTMLOrCSSStyleValue(globalElement, "type", "list-style-type")
+ : null;
+
+ if (gListType == "ul") {
+ if (type) {
+ type = type.toLowerCase();
+ gBulletStyleType = type;
+ gOriginalStyleType = type;
+ }
+ } else if (gListType == "ol") {
+ // Translate CSS property strings
+ switch (type.toLowerCase()) {
+ case gDecimalCSS:
+ type = gArabic;
+ break;
+ case gUpperRomanCSS:
+ type = gUpperRoman;
+ break;
+ case gLowerRomanCSS:
+ type = gLowerRoman;
+ break;
+ case gUpperAlphaCSS:
+ type = gUpperLetters;
+ break;
+ case gLowerAlphaCSS:
+ type = gLowerLetters;
+ break;
+ }
+ if (type) {
+ gNumberStyleType = type;
+ gOriginalStyleType = type;
+ }
+
+ // Convert attribute number to appropriate letter or roman numeral
+ gDialog.StartingNumberInput.value = ConvertStartAttrToUserString(
+ globalElement.getAttribute("start"),
+ type
+ );
+ }
+ BuildBulletStyleList();
+}
+
+// Convert attribute number to appropriate letter or roman numeral
+function ConvertStartAttrToUserString(startAttr, type) {
+ switch (type) {
+ case gUpperRoman:
+ startAttr = ConvertArabicToRoman(startAttr);
+ break;
+ case gLowerRoman:
+ startAttr = ConvertArabicToRoman(startAttr).toLowerCase();
+ break;
+ case gUpperLetters:
+ startAttr = ConvertArabicToLetters(startAttr);
+ break;
+ case gLowerLetters:
+ startAttr = ConvertArabicToLetters(startAttr).toLowerCase();
+ break;
+ }
+ return startAttr;
+}
+
+function BuildBulletStyleList() {
+ gDialog.BulletStyleList.removeAllItems();
+ var label;
+
+ if (gListType == "ul") {
+ gDialog.BulletStyleList.removeAttribute("disabled");
+ gDialog.BulletStyleLabel.removeAttribute("disabled");
+ gDialog.StartingNumberInput.setAttribute("disabled", "true");
+ gDialog.StartingNumberLabel.setAttribute("disabled", "true");
+
+ label = GetString("BulletStyle");
+
+ gDialog.BulletStyleList.appendItem(GetString("Automatic"), "");
+ gDialog.BulletStyleList.appendItem(GetString("SolidCircle"), "disc");
+ gDialog.BulletStyleList.appendItem(GetString("OpenCircle"), "circle");
+ gDialog.BulletStyleList.appendItem(GetString("SolidSquare"), "square");
+
+ gDialog.BulletStyleList.value = gBulletStyleType;
+ } else if (gListType == "ol") {
+ gDialog.BulletStyleList.removeAttribute("disabled");
+ gDialog.BulletStyleLabel.removeAttribute("disabled");
+ gDialog.StartingNumberInput.removeAttribute("disabled");
+ gDialog.StartingNumberLabel.removeAttribute("disabled");
+ label = GetString("NumberStyle");
+
+ gDialog.BulletStyleList.appendItem(GetString("Automatic"), "");
+ gDialog.BulletStyleList.appendItem(GetString("Style_1"), gArabic);
+ gDialog.BulletStyleList.appendItem(GetString("Style_I"), gUpperRoman);
+ gDialog.BulletStyleList.appendItem(GetString("Style_i"), gLowerRoman);
+ gDialog.BulletStyleList.appendItem(GetString("Style_A"), gUpperLetters);
+ gDialog.BulletStyleList.appendItem(GetString("Style_a"), gLowerLetters);
+
+ gDialog.BulletStyleList.value = gNumberStyleType;
+ } else {
+ gDialog.BulletStyleList.setAttribute("disabled", "true");
+ gDialog.BulletStyleLabel.setAttribute("disabled", "true");
+ gDialog.StartingNumberInput.setAttribute("disabled", "true");
+ gDialog.StartingNumberLabel.setAttribute("disabled", "true");
+ }
+
+ // Disable advanced edit button if changing to "normal"
+ if (gListType) {
+ gDialog.AdvancedEditButton.removeAttribute("disabled");
+ } else {
+ gDialog.AdvancedEditButton.setAttribute("disabled", "true");
+ }
+
+ if (label) {
+ gDialog.BulletStyleLabel.setAttribute("label", label);
+ }
+}
+
+function SelectListType() {
+ // Each list type is stored in the "value" of each menuitem
+ var NewType = gDialog.ListTypeList.value;
+
+ if (NewType == "ol") {
+ SetTextboxFocus(gDialog.StartingNumberInput);
+ }
+
+ if (gListType != NewType) {
+ gListType = NewType;
+
+ // Create a newlist object for Advanced Editing
+ try {
+ if (gListType) {
+ globalElement = GetCurrentEditor().createElementWithDefaults(gListType);
+ }
+ } catch (e) {}
+
+ BuildBulletStyleList();
+ }
+}
+
+function SelectBulletStyle() {
+ // Save the selected index so when user changes
+ // list style, restore index to associated list
+ // Each bullet or number type is stored in the "value" of each menuitem
+ if (gListType == "ul") {
+ gBulletStyleType = gDialog.BulletStyleList.value;
+ } else if (gListType == "ol") {
+ var type = gDialog.BulletStyleList.value;
+ if (gNumberStyleType != type) {
+ // Convert existing input value to attr number first,
+ // then convert to the appropriate format for the newly-selected
+ gDialog.StartingNumberInput.value = ConvertStartAttrToUserString(
+ ConvertUserStringToStartAttr(gNumberStyleType),
+ type
+ );
+
+ gNumberStyleType = type;
+ SetTextboxFocus(gDialog.StartingNumberInput);
+ }
+ }
+}
+
+function ValidateData() {
+ gBulletStyleType = gDialog.BulletStyleList.value;
+ // globalElement should already be of the correct type
+
+ if (globalElement) {
+ var editor = GetCurrentEditor();
+ if (gListType == "ul") {
+ if (gBulletStyleType && gDialog.ChangeAllRadio.selected) {
+ globalElement.setAttribute("type", gBulletStyleType);
+ } else {
+ try {
+ editor.removeAttributeOrEquivalent(globalElement, "type", true);
+ } catch (e) {}
+ }
+ } else if (gListType == "ol") {
+ if (gBulletStyleType) {
+ globalElement.setAttribute("type", gBulletStyleType);
+ } else {
+ try {
+ editor.removeAttributeOrEquivalent(globalElement, "type", true);
+ } catch (e) {}
+ }
+
+ var startingNumber = ConvertUserStringToStartAttr(gBulletStyleType);
+ if (startingNumber) {
+ globalElement.setAttribute("start", startingNumber);
+ } else {
+ globalElement.removeAttribute("start");
+ }
+ }
+ }
+ return true;
+}
+
+function ConvertUserStringToStartAttr(type) {
+ var startingNumber = TrimString(gDialog.StartingNumberInput.value);
+
+ switch (type) {
+ case gUpperRoman:
+ case gLowerRoman:
+ // If the input isn't an integer, assume it's a roman numeral. Convert it.
+ if (!Number(startingNumber)) {
+ startingNumber = ConvertRomanToArabic(startingNumber);
+ }
+ break;
+ case gUpperLetters:
+ case gLowerLetters:
+ // Get the number equivalent of the letters
+ if (!Number(startingNumber)) {
+ startingNumber = ConvertLettersToArabic(startingNumber);
+ }
+ break;
+ }
+ return startingNumber;
+}
+
+function ConvertRomanToArabic(num) {
+ num = num.toUpperCase();
+ if (num && !/[^MDCLXVI]/i.test(num)) {
+ var Arabic = 0;
+ var last_digit = 1000;
+ for (var i = 0; i < num.length; i++) {
+ var digit = gRomanDigits[num.charAt(i)];
+ if (last_digit < digit) {
+ Arabic -= 2 * last_digit;
+ }
+
+ last_digit = digit;
+ Arabic += last_digit;
+ }
+ return Arabic;
+ }
+
+ return "";
+}
+
+function ConvertArabicToRoman(num) {
+ if (/^\d{1,4}$/.test(num)) {
+ var digits = ("000" + num).substr(-4);
+ return (
+ gThousandsArray[digits.charAt(0)] +
+ gHundredsArray[digits.charAt(1)] +
+ gTensArray[digits.charAt(2)] +
+ gOnesArray[digits.charAt(3)]
+ );
+ }
+ return "";
+}
+
+function ConvertLettersToArabic(letters) {
+ letters = letters.toUpperCase();
+ if (!letters || /[^A-Z]/.test(letters)) {
+ return "";
+ }
+
+ var num = 0;
+ for (var i = 0; i < letters.length; i++) {
+ num = num * 26 + letters.charCodeAt(i) - A + 1;
+ }
+ return num;
+}
+
+function ConvertArabicToLetters(num) {
+ var letters = "";
+ while (num) {
+ num--;
+ letters = String.fromCharCode(A + (num % 26)) + letters;
+ num = Math.floor(num / 26);
+ }
+ return letters;
+}
+
+function onAccept(event) {
+ if (ValidateData()) {
+ // Coalesce into one undo transaction
+ var editor = GetCurrentEditor();
+
+ editor.beginTransaction();
+
+ var changeEntireList =
+ gDialog.RadioGroup.selectedItem == gDialog.ChangeAllRadio;
+
+ // Remember which radio button was selected
+ if (gListElement) {
+ gDialog.RadioGroup.setAttribute("index", changeEntireList ? "0" : "1");
+ }
+
+ var changeList;
+ if (gListElement && gDialog.ChangeAllRadio.selected) {
+ changeList = true;
+ } else {
+ changeList =
+ gMixedListSelection ||
+ gListType != gOriginalListType ||
+ gBulletStyleType != gOriginalStyleType;
+ }
+ if (changeList) {
+ try {
+ if (gListType) {
+ editor.makeOrChangeList(
+ gListType,
+ changeEntireList,
+ gBulletStyleType != gOriginalStyleType ? gBulletStyleType : null
+ );
+
+ // Get the new list created:
+ gListElement = editor.getElementOrParentByTagName(gListType, null);
+
+ editor.cloneAttributes(gListElement, globalElement);
+ } else {
+ // Remove all existing lists
+ if (gListElement && changeEntireList) {
+ editor.selectElement(gListElement);
+ }
+
+ editor.removeList("ol");
+ editor.removeList("ul");
+ editor.removeList("dl");
+ }
+ } catch (e) {}
+ }
+
+ editor.endTransaction();
+
+ SaveWindowLocation();
+
+ return;
+ }
+ event.preventDefault();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdListProps.xhtml b/comm/suite/editor/components/dialogs/content/EdListProps.xhtml
new file mode 100644
index 0000000000..cae9829c97
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdListProps.xhtml
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edListProperties SYSTEM "chrome://editor/locale/EditorListProperties.dtd">
+%edListProperties;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdListProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox flex="1">
+ <hbox class="groupbox-title">
+ <label class="header">&ListType.label;</label>
+ </hbox>
+ <menulist id="ListType" oncommand="SelectListType()">
+ <menupopup>
+ <menuitem label="&none.value;"/>
+ <menuitem value="ul" label="&bulletList.value;"/>
+ <menuitem value="ol" label="&numberList.value;"/>
+ <menuitem value="dl" label="&definitionList.value;"/>
+ </menupopup>
+ </menulist>
+ </groupbox>
+ <spacer class="spacer"/>
+
+ <!-- message text and list items are set in JS
+ text value should be identical to string with id=BulletStyle in editor.properties
+ -->
+ <groupbox flex="1">
+ <hbox class="groupbox-title">
+ <label id="BulletStyleLabel" class="header">&bulletStyle.label;</label>
+ </hbox>
+ <menulist class="MinWidth10em" id="BulletStyle" oncommand="SelectBulletStyle()">
+ <menupopup/>
+ </menulist>
+ <spacer class="spacer"/>
+ <hbox>
+ <label id="StartingNumberLabel" control="StartingNumber"
+ value="&startingNumber.label;" accesskey="&startingNumber.accessKey;"/>
+ <textbox class="narrow" id="StartingNumber"/>
+ <spacer/>
+ </hbox>
+ </groupbox>
+ <radiogroup id="RadioGroup" index="0" persist="index">
+ <radio id="ChangeAll" label="&changeEntireListRadio.label;" accesskey="&changeEntireListRadio.accessKey;"/>
+ <radio id="ChangeSelected" label="&changeSelectedRadio.label;" accesskey="&changeSelectedRadio.accessKey;"/>
+ </radiogroup>
+ <vbox id="AdvancedEdit">
+ <hbox flex="1" style="margin-top: 0.2em" align="center">
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton1" oncommand="onAdvancedEdit()" label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;" tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator id="advancedSeparator" class="groove"/>
+ </vbox>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdNamedAnchorProps.js b/comm/suite/editor/components/dialogs/content/EdNamedAnchorProps.js
new file mode 100644
index 0000000000..0433e58872
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdNamedAnchorProps.js
@@ -0,0 +1,159 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var gInsertNew = true;
+var gAnchorElement = null;
+var gOriginalName = "";
+const kTagName = "anchor";
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ window.close();
+ return;
+ }
+
+ gDialog.OkButton = document.documentElement.getButton("accept");
+ gDialog.NameInput = document.getElementById("nameInput");
+
+ // Get a single selected element of the desired type
+ gAnchorElement = editor.getSelectedElement(kTagName);
+
+ if (gAnchorElement) {
+ // We found an element and don't need to insert one
+ gInsertNew = false;
+
+ // Make a copy to use for AdvancedEdit
+ globalElement = gAnchorElement.cloneNode(false);
+ gOriginalName = ConvertToCDATAString(gAnchorElement.name);
+ } else {
+ gInsertNew = true;
+ // We don't have an element selected,
+ // so create one with default attributes
+ gAnchorElement = editor.createElementWithDefaults(kTagName);
+ if (gAnchorElement) {
+ // Use the current selection as suggested name
+ var name = GetSelectionAsText();
+ // Get 40 characters of the selected text and don't add "...",
+ // replace whitespace with "_" and strip non-word characters
+ name = ConvertToCDATAString(TruncateStringAtWordEnd(name, 40, false));
+ // Be sure the name is unique to the document
+ if (AnchorNameExists(name)) {
+ name += "_";
+ }
+
+ // Make a copy to use for AdvancedEdit
+ globalElement = gAnchorElement.cloneNode(false);
+ globalElement.setAttribute("name", name);
+ }
+ }
+ if (!gAnchorElement) {
+ dump("Failed to get selected element or create a new one!\n");
+ window.close();
+ return;
+ }
+
+ InitDialog();
+
+ DoEnabling();
+ SetTextboxFocus(gDialog.NameInput);
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ gDialog.NameInput.value = globalElement.getAttribute("name");
+}
+
+function ChangeName() {
+ if (gDialog.NameInput.value.length > 0) {
+ // Replace spaces with "_" and strip other non-URL characters
+ // Note: we could use ConvertAndEscape, but then we'd
+ // have to UnEscapeAndConvert beforehand - too messy!
+ gDialog.NameInput.value = ConvertToCDATAString(gDialog.NameInput.value);
+ }
+ DoEnabling();
+}
+
+function DoEnabling() {
+ var enable = gDialog.NameInput.value.length > 0;
+ SetElementEnabled(gDialog.OkButton, enable);
+ SetElementEnabledById("AdvancedEditButton1", enable);
+}
+
+function AnchorNameExists(name) {
+ var anchorList;
+ try {
+ anchorList = GetCurrentEditor().document.anchors;
+ } catch (e) {}
+
+ if (anchorList) {
+ for (var i = 0; i < anchorList.length; i++) {
+ if (anchorList[i].name == name) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// Get and validate data from widgets.
+// Set attributes on globalElement so they can be accessed by AdvancedEdit()
+function ValidateData() {
+ var name = TrimString(gDialog.NameInput.value);
+ if (!name) {
+ ShowInputErrorMessage(GetString("MissingAnchorNameError"));
+ SetTextboxFocus(gDialog.NameInput);
+ return false;
+ }
+ // Replace spaces with "_" and strip other characters
+ // Note: we could use ConvertAndEscape, but then we'd
+ // have to UnConverAndEscape beforehand - too messy!
+ name = ConvertToCDATAString(name);
+
+ if (gOriginalName != name && AnchorNameExists(name)) {
+ ShowInputErrorMessage(
+ GetString("DuplicateAnchorNameError").replace(/%name%/, name)
+ );
+ SetTextboxFocus(gDialog.NameInput);
+ return false;
+ }
+ globalElement.name = name;
+
+ return true;
+}
+
+function onAccept(event) {
+ if (ValidateData()) {
+ if (gOriginalName != globalElement.name) {
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+
+ try {
+ // "false" = don't delete selected text when inserting
+ if (gInsertNew) {
+ // We must insert element before copying CSS style attribute,
+ // but we must set the name else it won't insert at all
+ gAnchorElement.name = globalElement.name;
+ editor.insertElementAtSelection(gAnchorElement, false);
+ }
+
+ // Copy attributes to element we are changing or inserting
+ editor.cloneAttributes(gAnchorElement, globalElement);
+ } catch (e) {}
+
+ editor.endTransaction();
+ }
+ SaveWindowLocation();
+ return;
+ }
+ event.preventDefault();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdNamedAnchorProps.xhtml b/comm/suite/editor/components/dialogs/content/EdNamedAnchorProps.xhtml
new file mode 100644
index 0000000000..3a38256222
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdNamedAnchorProps.xhtml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edNamedAnchorProperties SYSTEM "chrome://editor/locale/EdNamedAnchorProperties.dtd">
+%edNamedAnchorProperties;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdNamedAnchorProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <label control="nameInput"
+ value="&anchorNameEditField.label;"
+ accesskey="&anchorNameEditField.accessKey;"/>
+ <textbox class="MinWidth20em" id="nameInput" oninput="ChangeName()"
+ tooltiptext="&nameInput.tooltip;"/>
+ <spacer class="spacer"/>
+ <vbox id="AdvancedEdit">
+ <hbox flex="1" style="margin-top: 0.2em" align="center">
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton1" oncommand="onAdvancedEdit()" label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;" tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator id="advancedSeparator" class="groove"/>
+ </vbox>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdPageProps.js b/comm/suite/editor/components/dialogs/content/EdPageProps.js
new file mode 100644
index 0000000000..568eff66ec
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdPageProps.js
@@ -0,0 +1,159 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var gNewTitle = "";
+var gAuthor = "";
+var gDescription = "";
+var gAuthorElement;
+var gDescriptionElement;
+var gInsertNewAuthor = false;
+var gInsertNewDescription = false;
+var gTitleWasEdited = false;
+var gAuthorWasEdited = false;
+var gDescWasEdited = false;
+
+// Cancel() is in EdDialogCommon.js
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ window.close();
+ return;
+ }
+
+ gDialog.PageLocation = document.getElementById("PageLocation");
+ gDialog.PageModDate = document.getElementById("PageModDate");
+ gDialog.TitleInput = document.getElementById("TitleInput");
+ gDialog.AuthorInput = document.getElementById("AuthorInput");
+ gDialog.DescriptionInput = document.getElementById("DescriptionInput");
+
+ // Default string for new page is set from DTD string in XUL,
+ // so set only if not new doc URL
+ var location = GetDocumentUrl();
+ var lastmodString = GetString("Unknown");
+
+ if (!IsUrlAboutBlank(location)) {
+ // NEVER show username and password in clear text
+ gDialog.PageLocation.setAttribute("value", StripPassword(location));
+
+ // Get last-modified file date+time
+ // TODO: Convert this to local time?
+ var lastmod;
+ try {
+ lastmod = editor.document.lastModified; // get string of last modified date
+ } catch (e) {}
+ // Convert modified string to date (0 = unknown date or January 1, 1970 GMT)
+ if (Date.parse(lastmod)) {
+ try {
+ const dateTimeFormatter = new Services.intl.DateTimeFormat(undefined, {
+ dateStyle: "long",
+ timeStyle: "short",
+ });
+
+ var lastModDate = new Date();
+ lastModDate.setTime(Date.parse(lastmod));
+ lastmodString = dateTimeFormatter.format(lastModDate);
+ } catch (e) {}
+ }
+ }
+ gDialog.PageModDate.value = lastmodString;
+
+ gAuthorElement = GetMetaElementByAttribute("name", "author");
+ if (!gAuthorElement) {
+ gAuthorElement = CreateMetaElementWithAttribute("name", "author");
+ if (!gAuthorElement) {
+ window.close();
+ return;
+ }
+ gInsertNewAuthor = true;
+ }
+
+ gDescriptionElement = GetMetaElementByAttribute("name", "description");
+ if (!gDescriptionElement) {
+ gDescriptionElement = CreateMetaElementWithAttribute("name", "description");
+ if (!gDescriptionElement) {
+ window.close();
+ }
+
+ gInsertNewDescription = true;
+ }
+
+ InitDialog();
+
+ SetTextboxFocus(gDialog.TitleInput);
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ gDialog.TitleInput.value = GetDocumentTitle();
+
+ var gAuthor = TrimString(gAuthorElement.getAttribute("content"));
+ if (!gAuthor) {
+ // Fill in with value from editor prefs
+ gAuthor = Services.prefs.getCharPref("editor.author");
+ }
+ gDialog.AuthorInput.value = gAuthor;
+ gDialog.DescriptionInput.value = gDescriptionElement.getAttribute("content");
+}
+
+function TextboxChanged(ID) {
+ switch (ID) {
+ case "TitleInput":
+ gTitleWasEdited = true;
+ break;
+ case "AuthorInput":
+ gAuthorWasEdited = true;
+ break;
+ case "DescriptionInput":
+ gDescWasEdited = true;
+ break;
+ }
+}
+
+function ValidateData() {
+ gNewTitle = TrimString(gDialog.TitleInput.value);
+ gAuthor = TrimString(gDialog.AuthorInput.value);
+ gDescription = TrimString(gDialog.DescriptionInput.value);
+ return true;
+}
+
+function onAccept(event) {
+ if (ValidateData()) {
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+
+ // Set title contents even if string is empty
+ // because TITLE is a required HTML element
+ if (gTitleWasEdited) {
+ SetDocumentTitle(gNewTitle);
+ }
+
+ if (gAuthorWasEdited) {
+ SetMetaElementContent(gAuthorElement, gAuthor, gInsertNewAuthor, false);
+ }
+
+ if (gDescWasEdited) {
+ SetMetaElementContent(
+ gDescriptionElement,
+ gDescription,
+ gInsertNewDescription,
+ false
+ );
+ }
+
+ editor.endTransaction();
+
+ SaveWindowLocation();
+ return; // do close the window
+ }
+ event.preventDefault();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdPageProps.xhtml b/comm/suite/editor/components/dialogs/content/EdPageProps.xhtml
new file mode 100644
index 0000000000..4891baa04a
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdPageProps.xhtml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorPageProperties.dtd">
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup();">
+
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdPageProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+ <grid>
+ <columns><column flex="1"/><column flex="2"/></columns>
+ <rows>
+ <row>
+ <label value="&location.label;"/>
+ <label value="&locationNewPage.label;" id="PageLocation"/>
+ </row>
+ <row>
+ <label value="&lastModified.label;"/>
+ <label id="PageModDate"/>
+ </row>
+ <spacer class="spacer"/>
+ <row align="center">
+ <label value="&titleInput.label;" accesskey="&titleInput.accessKey;" control="TitleInput"/>
+ <textbox class="MinWidth20em" id="TitleInput" oninput="TextboxChanged(this.id)"/>
+ </row>
+ <row align="center">
+ <label value="&authorInput.label;" accesskey="&authorInput.accessKey;" control="AuthorInput"/>
+ <textbox class="MinWidth20em" id="AuthorInput" oninput="TextboxChanged(this.id)"/>
+ </row>
+ <row align="center">
+ <label value="&descriptionInput.label;" accesskey="&descriptionInput.accessKey;" control="DescriptionInput"/>
+ <textbox class="MinWidth20em" id="DescriptionInput" oninput="TextboxChanged(this.id)"/>
+ </row>
+ </rows>
+ </grid>
+ <spacer class="bigspacer"/>
+ <label value="&EditHEADSource1.label;"/>
+ <description class="wrap" flex="1">&EditHEADSource2.label;</description>
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdReplace.js b/comm/suite/editor/components/dialogs/content/EdReplace.js
new file mode 100644
index 0000000000..c0daea29de
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdReplace.js
@@ -0,0 +1,382 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var gReplaceDialog; // Quick access to document/form elements.
+var gFindInst; // nsIWebBrowserFind that we're going to use
+var gFindService; // Global service which remembers find params
+var gEditor; // the editor we're using
+
+document.addEventListener("dialogaccept", event => {
+ onFindNext();
+ event.preventDefault();
+});
+
+function initDialogObject() {
+ // Create gReplaceDialog object and initialize.
+ gReplaceDialog = {};
+ gReplaceDialog.findInput = document.getElementById("dialog.findInput");
+ gReplaceDialog.replaceInput = document.getElementById("dialog.replaceInput");
+ gReplaceDialog.caseSensitive = document.getElementById(
+ "dialog.caseSensitive"
+ );
+ gReplaceDialog.wrap = document.getElementById("dialog.wrap");
+ gReplaceDialog.searchBackwards = document.getElementById(
+ "dialog.searchBackwards"
+ );
+ gReplaceDialog.findNext = document.getElementById("findNext");
+ gReplaceDialog.replace = document.getElementById("replace");
+ gReplaceDialog.replaceAndFind = document.getElementById("replaceAndFind");
+ gReplaceDialog.replaceAll = document.getElementById("replaceAll");
+}
+
+function loadDialog() {
+ // Set initial dialog field contents.
+ // Set initial dialog field contents. Use the gFindInst attributes first,
+ // this is necessary for window.find()
+ gReplaceDialog.findInput.value = gFindInst.searchString
+ ? gFindInst.searchString
+ : gFindService.searchString;
+ gReplaceDialog.replaceInput.value = gFindService.replaceString;
+ gReplaceDialog.caseSensitive.checked = gFindInst.matchCase
+ ? gFindInst.matchCase
+ : gFindService.matchCase;
+ gReplaceDialog.wrap.checked = gFindInst.wrapFind
+ ? gFindInst.wrapFind
+ : gFindService.wrapFind;
+ gReplaceDialog.searchBackwards.checked = gFindInst.findBackwards
+ ? gFindInst.findBackwards
+ : gFindService.findBackwards;
+
+ doEnabling();
+}
+
+function onLoad() {
+ // Get the xul <editor> element:
+ var editorElement = window.arguments[0];
+
+ // If we don't get the editor, then we won't allow replacing.
+ gEditor = editorElement.getEditor(editorElement.contentWindow);
+ if (!gEditor) {
+ window.close();
+ return;
+ }
+
+ // Get the nsIWebBrowserFind service:
+ gFindInst = editorElement.webBrowserFind;
+
+ try {
+ // get the find service, which stores global find state
+ gFindService = Cc["@mozilla.org/find/find_service;1"].getService(
+ Ci.nsIFindService
+ );
+ } catch (e) {
+ dump("No find service!\n");
+ gFindService = 0;
+ }
+
+ // Init gReplaceDialog.
+ initDialogObject();
+
+ // Change "OK" to "Find".
+ // dialog.find.label = document.getElementById("fBLT").getAttribute("label");
+
+ // Fill dialog.
+ loadDialog();
+
+ if (gReplaceDialog.findInput.value) {
+ gReplaceDialog.findInput.select();
+ } else {
+ gReplaceDialog.findInput.focus();
+ }
+}
+
+function saveFindData() {
+ // Set data attributes per user input.
+ if (gFindService) {
+ gFindService.searchString = gReplaceDialog.findInput.value;
+ gFindService.matchCase = gReplaceDialog.caseSensitive.checked;
+ gFindService.wrapFind = gReplaceDialog.wrap.checked;
+ gFindService.findBackwards = gReplaceDialog.searchBackwards.checked;
+ }
+}
+
+function setUpFindInst() {
+ gFindInst.searchString = gReplaceDialog.findInput.value;
+ gFindInst.matchCase = gReplaceDialog.caseSensitive.checked;
+ gFindInst.wrapFind = gReplaceDialog.wrap.checked;
+ gFindInst.findBackwards = gReplaceDialog.searchBackwards.checked;
+}
+
+function onFindNext() {
+ // Transfer dialog contents to the find service.
+ saveFindData();
+ // set up the find instance
+ setUpFindInst();
+
+ // Search.
+ var result = gFindInst.findNext();
+
+ if (!result) {
+ var bundle = document.getElementById("findBundle");
+ Services.prompt.alert(
+ window,
+ GetString("Alert"),
+ bundle.getString("notFoundWarning")
+ );
+ SetTextboxFocus(gReplaceDialog.findInput);
+ gReplaceDialog.findInput.select();
+ gReplaceDialog.findInput.focus();
+ return false;
+ }
+ return true;
+}
+
+function onReplace() {
+ if (!gEditor) {
+ return false;
+ }
+
+ // Does the current selection match the find string?
+ var selection = gEditor.selection;
+
+ var selStr = selection.toString();
+ var specStr = gReplaceDialog.findInput.value;
+ if (!gReplaceDialog.caseSensitive.checked) {
+ selStr = selStr.toLowerCase();
+ specStr = specStr.toLowerCase();
+ }
+ // Unfortunately, because of whitespace we can't just check
+ // whether (selStr == specStr), but have to loop ourselves.
+ // N chars of whitespace in specStr can match any M >= N in selStr.
+ var matches = true;
+ var specLen = specStr.length;
+ var selLen = selStr.length;
+ if (selLen < specLen) {
+ matches = false;
+ } else {
+ var specArray = specStr.match(/\S+|\s+/g);
+ var selArray = selStr.match(/\S+|\s+/g);
+ if (specArray.length != selArray.length) {
+ matches = false;
+ } else {
+ for (var i = 0; i < selArray.length; i++) {
+ if (selArray[i] != specArray[i]) {
+ if (/\S/.test(selArray[i][0]) || /\S/.test(specArray[i][0])) {
+ // not a space chunk -- match fails
+ matches = false;
+ break;
+ } else if (selArray[i].length < specArray[i].length) {
+ // if it's a space chunk then we only care that sel be
+ // at least as long as spec
+ matches = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // If the current selection doesn't match the pattern,
+ // then we want to find the next match, but not do the replace.
+ // That's what most other apps seem to do.
+ // So here, just return.
+ if (!matches) {
+ return false;
+ }
+
+ // Transfer dialog contents to the find service.
+ saveFindData();
+
+ // For reverse finds, need to remember the caret position
+ // before current selection
+ var newRange;
+ if (gReplaceDialog.searchBackwards.checked && selection.rangeCount > 0) {
+ newRange = selection.getRangeAt(0).cloneRange();
+ newRange.collapse(true);
+ }
+
+ // nsPlaintextEditor::InsertText fails if the string is empty,
+ // so make that a special case:
+ var replStr = gReplaceDialog.replaceInput.value;
+ if (replStr == "") {
+ gEditor.deleteSelection(gEditor.eNone, gEditor.eStrip);
+ } else {
+ gEditor.insertText(replStr);
+ }
+
+ // For reverse finds, need to move caret just before the replaced text
+ if (gReplaceDialog.searchBackwards.checked && newRange) {
+ gEditor.selection.removeAllRanges();
+ gEditor.selection.addRange(newRange);
+ }
+
+ return true;
+}
+
+function onReplaceAll() {
+ if (!gEditor) {
+ return;
+ }
+
+ var findStr = gReplaceDialog.findInput.value;
+ var repStr = gReplaceDialog.replaceInput.value;
+
+ // Transfer dialog contents to the find service.
+ saveFindData();
+
+ var finder = Cc["@mozilla.org/embedcomp/rangefind;1"]
+ .createInstance()
+ .QueryInterface(Ci.nsIFind);
+
+ finder.caseSensitive = gReplaceDialog.caseSensitive.checked;
+ finder.findBackwards = gReplaceDialog.searchBackwards.checked;
+
+ // We want the whole operation to be undoable in one swell foop,
+ // so start a transaction:
+ gEditor.beginTransaction();
+
+ // and to make sure we close the transaction, guard against exceptions:
+ try {
+ // Make a range containing the current selection,
+ // so we don't go past it when we wrap.
+ var selection = gEditor.selection;
+ var selecRange;
+ if (selection.rangeCount > 0) {
+ selecRange = selection.getRangeAt(0);
+ }
+ var origRange = selecRange.cloneRange();
+
+ // We'll need a range for the whole document:
+ var wholeDocRange = gEditor.document.createRange();
+ var rootNode = gEditor.rootElement;
+ wholeDocRange.selectNodeContents(rootNode);
+
+ // And start and end points:
+ var endPt = gEditor.document.createRange();
+
+ if (gReplaceDialog.searchBackwards.checked) {
+ endPt.setStart(wholeDocRange.startContainer, wholeDocRange.startOffset);
+ endPt.setEnd(wholeDocRange.startContainer, wholeDocRange.startOffset);
+ } else {
+ endPt.setStart(wholeDocRange.endContainer, wholeDocRange.endOffset);
+ endPt.setEnd(wholeDocRange.endContainer, wholeDocRange.endOffset);
+ }
+
+ // Find and replace from here to end (start) of document:
+ var foundRange;
+ var searchRange = wholeDocRange.cloneRange();
+ while (
+ (foundRange = finder.Find(findStr, searchRange, selecRange, endPt)) !=
+ null
+ ) {
+ gEditor.selection.removeAllRanges();
+ gEditor.selection.addRange(foundRange);
+
+ // The editor will leave the caret at the end of the replaced text.
+ // For reverse finds, we need it at the beginning,
+ // so save the next position now.
+ if (gReplaceDialog.searchBackwards.checked) {
+ selecRange = foundRange.cloneRange();
+ selecRange.setEnd(selecRange.startContainer, selecRange.startOffset);
+ }
+
+ // nsPlaintextEditor::InsertText fails if the string is empty,
+ // so make that a special case:
+ if (repStr == "") {
+ gEditor.deleteSelection(gEditor.eNone, gEditor.eStrip);
+ } else {
+ gEditor.insertText(repStr);
+ }
+
+ // If we're going forward, we didn't save selecRange before, so do it now:
+ if (!gReplaceDialog.searchBackwards.checked) {
+ selection = gEditor.selection;
+ if (selection.rangeCount <= 0) {
+ gEditor.endTransaction();
+ return;
+ }
+ selecRange = selection.getRangeAt(0).cloneRange();
+ }
+ }
+
+ // If no wrapping, then we're done
+ if (!gReplaceDialog.wrap.checked) {
+ gEditor.endTransaction();
+ return;
+ }
+
+ // If wrapping, find from start/end of document back to start point.
+ if (gReplaceDialog.searchBackwards.checked) {
+ // Collapse origRange to end
+ origRange.setStart(origRange.endContainer, origRange.endOffset);
+ // Set current position to document end
+ selecRange.setEnd(wholeDocRange.endContainer, wholeDocRange.endOffset);
+ selecRange.setStart(wholeDocRange.endContainer, wholeDocRange.endOffset);
+ } else {
+ // Collapse origRange to start
+ origRange.setEnd(origRange.startContainer, origRange.startOffset);
+ // Set current position to document start
+ selecRange.setStart(
+ wholeDocRange.startContainer,
+ wholeDocRange.startOffset
+ );
+ selecRange.setEnd(
+ wholeDocRange.startContainer,
+ wholeDocRange.startOffset
+ );
+ }
+
+ while (
+ (foundRange = finder.Find(
+ findStr,
+ wholeDocRange,
+ selecRange,
+ origRange
+ )) != null
+ ) {
+ gEditor.selection.removeAllRanges();
+ gEditor.selection.addRange(foundRange);
+
+ // Save insert point for backward case
+ if (gReplaceDialog.searchBackwards.checked) {
+ selecRange = foundRange.cloneRange();
+ selecRange.setEnd(selecRange.startContainer, selecRange.startOffset);
+ }
+
+ // nsPlaintextEditor::InsertText fails if the string is empty,
+ // so make that a special case:
+ if (repStr == "") {
+ gEditor.deleteSelection(gEditor.eNone, gEditor.eStrip);
+ } else {
+ gEditor.insertText(repStr);
+ }
+
+ // Get insert point for forward case
+ if (!gReplaceDialog.searchBackwards.checked) {
+ selection = gEditor.selection;
+ if (selection.rangeCount <= 0) {
+ gEditor.endTransaction();
+ return;
+ }
+ selecRange = selection.getRangeAt(0);
+ }
+ }
+ } catch (e) {}
+
+ gEditor.endTransaction();
+}
+
+function doEnabling() {
+ var findStr = gReplaceDialog.findInput.value;
+ gReplaceDialog.enabled = findStr;
+ gReplaceDialog.findNext.disabled = !findStr;
+ gReplaceDialog.replace.disabled = !findStr;
+ gReplaceDialog.replaceAndFind.disabled = !findStr;
+ gReplaceDialog.replaceAll.disabled = !findStr;
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdReplace.xhtml b/comm/suite/editor/components/dialogs/content/EdReplace.xhtml
new file mode 100644
index 0000000000..54a9d81ba3
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdReplace.xhtml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorReplace.dtd">
+
+<dialog id="replaceDlg" title="&replaceDialog.title;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ persist="screenX screenY"
+ buttons="cancel"
+ onload="onLoad()">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdReplace.js"/>
+ <stringbundle id="findBundle" src="chrome://global/locale/finddialog.properties"/>
+
+ <hbox>
+ <vbox>
+ <spacer class="spacer"/>
+ <grid align="start">
+ <columns><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <label value="&findField.label;" accesskey="&findField.accesskey;" control="dialog.findInput"/>
+ <textbox id="dialog.findInput" oninput="doEnabling();"/>
+ </row>
+ <row align="center">
+ <label value="&replaceField.label;" accesskey="&replaceField.accesskey;" control="dialog.replaceInput"/>
+ <textbox id="dialog.replaceInput" oninput="doEnabling();"/>
+ </row>
+ <row align="start">
+ <spacer/>
+ <vbox align="start">
+ <spacer class="bigspacer"/>
+ <checkbox id="dialog.caseSensitive" label="&caseSensitiveCheckbox.label;"
+ accesskey="&caseSensitiveCheckbox.accesskey;"/>
+ <checkbox id="dialog.wrap" label="&wrapCheckbox.label;"
+ accesskey="&wrapCheckbox.accesskey;"/>
+ <checkbox id="dialog.searchBackwards" label="&backwardsCheckbox.label;"
+ accesskey="&backwardsCheckbox.accesskey;"/>
+ </vbox>
+ </row>
+ </rows>
+ </grid>
+ </vbox>
+ <vbox>
+ <button id="findNext" label="&findNextButton.label;" accesskey="&findNextButton.accesskey;"
+ oncommand="onFindNext();" default="true"/>
+ <button id="replace" label="&replaceButton.label;" accesskey="&replaceButton.accesskey;"
+ oncommand="onReplace();"/>
+ <button id="replaceAndFind" label="&replaceAndFindButton.label;"
+ accesskey="&replaceAndFindButton.accesskey;" oncommand="onReplace(); onFindNext();"/>
+ <button id="replaceAll" label="&replaceAllButton.label;"
+ accesskey="&replaceAllButton.accesskey;" oncommand="onReplaceAll();"/>
+ <button dlgtype="cancel" label="&closeButton.label;" accesskey="&closeButton.accesskey;"/>
+ </vbox>
+ </hbox>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdSelectProps.js b/comm/suite/editor/components/dialogs/content/EdSelectProps.js
new file mode 100644
index 0000000000..c03fd73a67
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdSelectProps.js
@@ -0,0 +1,770 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+// Global variables
+
+var hasValue;
+var oldValue;
+var insertNew;
+var itemArray;
+var theTree;
+var treeSelection;
+var selectElement;
+var currentItem = null;
+var selectedOption = null;
+var selectedOptionCount = 0;
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+// Utility functions
+
+function getParentIndex(index) {
+ switch (itemArray[index].level) {
+ case 0:
+ return -1;
+ case 1:
+ return 0;
+ }
+ // eslint-disable-next-line curly
+ while (itemArray[--index].level > 1);
+ return index;
+}
+
+function UpdateSelectMultiple() {
+ if (selectedOptionCount > 1) {
+ gDialog.selectMultiple.checked = true;
+ gDialog.selectMultiple.disabled = true;
+ } else {
+ gDialog.selectMultiple.disabled = false;
+ }
+}
+
+/* wrapper objects:
+ * readonly attribute Node element; // DOM node (select/optgroup/option)
+ * readonly attribute int level; // tree depth
+ * readonly attribute boolean container; // can contain options
+ * string getCellText(string col); // tree view helper
+ * string cycleCell(int currentIndex); // tree view helper
+ * void onFocus(); // load data into deck
+ * void onBlur(); // save data from deck
+ * boolean canDestroy(boolean prompt); // NB prompt not used
+ * void destroy(); // post remove callback
+ * void moveUp();
+ * boolean canMoveDown();
+ * void moveDown();
+ * void appendOption(newElement, currentIndex);
+ */
+
+// OPTION element wrapper object
+
+// Create a wrapper for the given element at the given level
+function optionObject(option, level) {
+ // select an added option (when loading from document)
+ if (option.hasAttribute("selected")) {
+ selectedOptionCount++;
+ }
+ this.level = level;
+ this.element = option;
+}
+
+optionObject.prototype.container = false;
+
+optionObject.prototype.getCellText = function(column) {
+ if (column.id == "SelectSelCol") {
+ return "";
+ }
+ if (column.id == "SelectValCol" && this.element.hasAttribute("value")) {
+ return this.element.getAttribute("value");
+ }
+ return this.element.text;
+};
+
+optionObject.prototype.cycleCell = function(index) {
+ if (this.element.hasAttribute("selected")) {
+ this.element.removeAttribute("selected");
+ selectedOptionCount--;
+ selectedOption = null;
+ } else {
+ // Different handling for multiselect lists
+ if (gDialog.selectMultiple.checked || !selectedOption) {
+ selectedOptionCount++;
+ } else if (selectedOption) {
+ selectedOption.removeAttribute("selected");
+ let column = theTree.columns.SelectSelCol;
+ theTree.invalidateColumn(column);
+ selectedOption = null;
+ }
+ this.element.setAttribute("selected", "");
+ selectedOption = this.element;
+ let column = theTree.columns.SelectSelCol;
+ theTree.invalidateCell(index, column);
+ }
+ if (currentItem == this) {
+ // Also update the deck
+ gDialog.optionSelected.setAttribute(
+ "checked",
+ this.element.hasAttribute("selected")
+ );
+ }
+ UpdateSelectMultiple();
+};
+
+optionObject.prototype.onFocus = function() {
+ gDialog.optionText.value = this.element.text;
+ hasValue = this.element.hasAttribute("value");
+ oldValue = this.element.value;
+ gDialog.optionHasValue.checked = hasValue;
+ gDialog.optionValue.value = hasValue ? this.element.value : this.element.text;
+ gDialog.optionSelected.checked = this.element.hasAttribute("selected");
+ gDialog.optionDisabled.checked = this.element.hasAttribute("disabled");
+ gDialog.selectDeck.setAttribute("selectedIndex", "2");
+};
+
+optionObject.prototype.onBlur = function() {
+ this.element.text = gDialog.optionText.value;
+ if (gDialog.optionHasValue.checked) {
+ this.element.value = gDialog.optionValue.value;
+ } else {
+ this.element.removeAttribute("value");
+ }
+ if (gDialog.optionSelected.checked) {
+ this.element.setAttribute("selected", "");
+ } else {
+ this.element.removeAttribute("selected");
+ }
+ if (gDialog.optionDisabled.checked) {
+ this.element.setAttribute("disabled", "");
+ } else {
+ this.element.removeAttribute("disabled");
+ }
+};
+
+optionObject.prototype.canDestroy = function(prompt) {
+ return true;
+ /* return !prompt ||
+ ConfirmWithTitle(GetString("DeleteOption"),
+ GetString("DeleteOptionMsg"),
+ GetString("DeleteOption"));*/
+};
+
+optionObject.prototype.destroy = function() {
+ // Deselect a removed option
+ if (this.element.hasAttribute("selected")) {
+ selectedOptionCount--;
+ selectedOption = null;
+ UpdateSelectMultiple();
+ }
+};
+
+/* 4 cases:
+ * a) optgroup -> optgroup
+ * ... ...
+ * option option
+ * b) optgroup -> option
+ * option optgroup
+ * ... ...
+ * c) option
+ * option
+ * d) option
+ * option
+ */
+
+optionObject.prototype.moveUp = function() {
+ var index = treeSelection.currentIndex;
+ if (
+ itemArray[index].level <
+ itemArray[index - 1].level + itemArray[index - 1].container
+ ) {
+ // we need to repaint the tree's lines
+ theTree.invalidateRange(getParentIndex(index), index);
+ // a) option is just after an optgroup, so it becomes the last child
+ itemArray[index].level = 2;
+ theTree.view.selectionChanged();
+ } else {
+ // otherwise new option level is now the same as the previous item
+ itemArray[index].level = itemArray[index - 1].level;
+ // swap the option with the previous item
+ itemArray.splice(index, 0, itemArray.splice(--index, 1)[0]);
+ }
+ selectTreeIndex(index, true);
+};
+
+optionObject.prototype.canMoveDown = function() {
+ // move down is not allowed on the last option if its level is 1
+ return this.level > 1 || itemArray.length - treeSelection.currentIndex > 1;
+};
+
+optionObject.prototype.moveDown = function() {
+ var index = treeSelection.currentIndex;
+ if (
+ index + 1 == itemArray.length ||
+ itemArray[index].level > itemArray[index + 1].level
+ ) {
+ // we need to repaint the tree's lines
+ theTree.invalidateRange(getParentIndex(index), index);
+ // a) option is last child of an optgroup, so it moves just after
+ itemArray[index].level = 1;
+ theTree.view.selectionChanged();
+ } else {
+ // level increases if the option was preceding an optgroup
+ itemArray[index].level += itemArray[index + 1].container;
+ // swap the option with the next item
+ itemArray.splice(index, 0, itemArray.splice(++index, 1)[0]);
+ }
+ selectTreeIndex(index, true);
+};
+
+optionObject.prototype.appendOption = function(child, parent) {
+ // special case quick check
+ if (this.level == 1) {
+ return gDialog.appendOption(child, 0);
+ }
+
+ // append the option to the parent element
+ parent = getParentIndex(parent);
+ return itemArray[parent].appendOption(child, parent);
+};
+
+// OPTGROUP element wrapper object
+
+function optgroupObject(optgroup) {
+ this.element = optgroup;
+}
+
+optgroupObject.prototype.level = 1;
+
+optgroupObject.prototype.container = true;
+
+optgroupObject.prototype.getCellText = function(column) {
+ return column.id == "SelectTextCol" ? this.element.label : "";
+};
+
+optgroupObject.prototype.cycleCell = function(index) {};
+
+optgroupObject.prototype.onFocus = function() {
+ gDialog.optgroupLabel.value = this.element.label;
+ gDialog.optgroupDisabled.checked = this.element.disabled;
+ gDialog.selectDeck.setAttribute("selectedIndex", "1");
+};
+
+optgroupObject.prototype.onBlur = function() {
+ this.element.label = gDialog.optgroupLabel.value;
+ this.element.disabled = gDialog.optgroupDisabled.checked;
+};
+
+optgroupObject.prototype.canDestroy = function(prompt) {
+ // Only removing empty option groups for now
+ return (
+ gDialog.nextChild(treeSelection.currentIndex) -
+ treeSelection.currentIndex ==
+ 1
+ );
+ /* && (!prompt ||
+ ConfirmWithTitle(GetString("DeleteOptGroup"),
+ GetString("DeleteOptGroupMsg"),
+ GetString("DeleteOptGroup")));
+*/
+};
+
+optgroupObject.prototype.destroy = function() {};
+
+optgroupObject.prototype.moveUp = function() {
+ // Find the index of the previous and next elements at the same level
+ var index = treeSelection.currentIndex;
+ var i = index;
+ // eslint-disable-next-line curly
+ while (itemArray[--index].level > 1);
+ var j = gDialog.nextChild(i);
+ // Cut out the element, cut the array in two, then join together
+ var movedItems = itemArray.splice(i, j - i);
+ var endItems = itemArray.splice(index);
+ itemArray = itemArray.concat(movedItems).concat(endItems);
+ // Repaint the lot
+ theTree.invalidateRange(index, j);
+ selectTreeIndex(index, true);
+};
+
+optgroupObject.prototype.canMoveDown = function() {
+ return gDialog.lastChild() > treeSelection.currentIndex;
+};
+
+optgroupObject.prototype.moveDown = function() {
+ // Find the index of the next two elements at the same level
+ var index = treeSelection.currentIndex;
+ var i = gDialog.nextChild(index);
+ var j = gDialog.nextChild(i);
+ // Cut out the element, cut the array in two, then join together
+ var movedItems = itemArray.splice(i, j - 1);
+ var endItems = itemArray.splice(index);
+ itemArray = itemArray.concat(movedItems).concat(endItems);
+ // Repaint the lot
+ theTree.invalidateRange(index, j);
+ index += j - i;
+ selectTreeIndex(index, true);
+};
+
+optgroupObject.prototype.appendOption = function(child, parent) {
+ var index = gDialog.nextChild(parent);
+ // XXX need to repaint the lines, tree won't do this
+ var primaryCol = theTree.columns.getPrimaryColumn();
+ theTree.invalidateCell(index - 1, primaryCol);
+ // insert the wrapped object as the last child
+ itemArray.splice(index, 0, new optionObject(child, 2));
+ theTree.rowCountChanged(index, 1);
+ selectTreeIndex(index, false);
+};
+
+// dialog initialization code
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ dump("Failed to get active editor!\n");
+ window.close();
+ return;
+ }
+
+ // Get a single selected select element
+ const kTagName = "select";
+ try {
+ selectElement = editor.getSelectedElement(kTagName);
+ } catch (e) {}
+
+ if (selectElement) {
+ // We found an element and don't need to insert one
+ insertNew = false;
+ } else {
+ insertNew = true;
+
+ // We don't have an element selected,
+ // so create one with default attributes
+ try {
+ selectElement = editor.createElementWithDefaults(kTagName);
+ } catch (e) {}
+
+ if (!selectElement) {
+ dump("Failed to get selected element or create a new one!\n");
+ window.close();
+ return;
+ }
+ }
+
+ // SELECT element wrapper object
+ gDialog = {
+ // useful elements
+ accept: document.documentElement.getButton("accept"),
+ selectDeck: document.getElementById("SelectDeck"),
+ selectName: document.getElementById("SelectName"),
+ selectSize: document.getElementById("SelectSize"),
+ selectMultiple: document.getElementById("SelectMultiple"),
+ selectDisabled: document.getElementById("SelectDisabled"),
+ selectTabIndex: document.getElementById("SelectTabIndex"),
+ optgroupLabel: document.getElementById("OptGroupLabel"),
+ optgroupDisabled: document.getElementById("OptGroupDisabled"),
+ optionText: document.getElementById("OptionText"),
+ optionHasValue: document.getElementById("OptionHasValue"),
+ optionValue: document.getElementById("OptionValue"),
+ optionSelected: document.getElementById("OptionSelected"),
+ optionDisabled: document.getElementById("OptionDisabled"),
+ removeButton: document.getElementById("RemoveButton"),
+ previousButton: document.getElementById("PreviousButton"),
+ nextButton: document.getElementById("NextButton"),
+ tree: document.getElementById("SelectTree"),
+ // wrapper methods (except MoveUp and MoveDown)
+ element: selectElement.cloneNode(false),
+ level: 0,
+ container: true,
+ getCellText(column) {
+ return column.id == "SelectTextCol"
+ ? this.element.getAttribute("name")
+ : "";
+ },
+ cycleCell(index) {},
+ onFocus() {
+ gDialog.selectName.value = this.element.getAttribute("name");
+ gDialog.selectSize.value = this.element.getAttribute("size");
+ gDialog.selectMultiple.checked = this.element.hasAttribute("multiple");
+ gDialog.selectDisabled.checked = this.element.hasAttribute("disabled");
+ gDialog.selectTabIndex.value = this.element.getAttribute("tabindex");
+ this.selectDeck.setAttribute("selectedIndex", "0");
+ onNameInput();
+ },
+ onBlur() {
+ this.element.setAttribute("name", gDialog.selectName.value);
+ if (gDialog.selectSize.value) {
+ this.element.setAttribute("size", gDialog.selectSize.value);
+ } else {
+ this.element.removeAttribute("size");
+ }
+ if (gDialog.selectMultiple.checked) {
+ this.element.setAttribute("multiple", "");
+ } else {
+ this.element.removeAttribute("multiple");
+ }
+ if (gDialog.selectDisabled.checked) {
+ this.element.setAttribute("disabled", "");
+ } else {
+ this.element.removeAttribute("disabled");
+ }
+ if (gDialog.selectTabIndex.value) {
+ this.element.setAttribute("tabindex", gDialog.selectTabIndex.value);
+ } else {
+ this.element.removeAttribute("tabindex");
+ }
+ },
+ appendOption(child, parent) {
+ var index = itemArray.length;
+ // XXX need to repaint the lines, tree won't do this
+ theTree.invalidateRange(this.lastChild(), index);
+ // append the wrapped object
+ itemArray.push(new optionObject(child, 1));
+ theTree.rowCountChanged(index, 1);
+ selectTreeIndex(index, false);
+ },
+ canDestroy(prompt) {
+ return false;
+ },
+ canMoveDown() {
+ return false;
+ },
+ // helper methods
+ // Find the index of the next immediate child of the select
+ nextChild(index) {
+ // eslint-disable-next-line curly
+ while (++index < itemArray.length && itemArray[index].level > 1);
+ return index;
+ },
+ // Find the index of the last immediate child of the select
+ lastChild() {
+ var index = itemArray.length;
+ // eslint-disable-next-line curly
+ while (itemArray[--index].level > 1);
+ return index;
+ },
+ };
+ // Start with the <select> wrapper
+ itemArray = [gDialog];
+
+ // We modify the actual option and optgroup elements so clone them first
+ for (var child = selectElement.firstChild; child; child = child.nextSibling) {
+ if (child.tagName == "OPTION") {
+ itemArray.push(new optionObject(child.cloneNode(true), 1));
+ } else if (child.tagName == "OPTGROUP") {
+ itemArray.push(new optgroupObject(child.cloneNode(false)));
+ for (
+ var grandchild = child.firstChild;
+ grandchild;
+ grandchild = grandchild.nextSibling
+ ) {
+ if (grandchild.tagName == "OPTION") {
+ itemArray.push(new optionObject(grandchild.cloneNode(true), 2));
+ }
+ }
+ }
+ }
+
+ UpdateSelectMultiple();
+
+ // Define a custom view for the tree
+ theTree = gDialog.tree;
+ theTree.view = {
+ QueryInterface: ChromeUtils.generateQI([
+ "nsITreeView",
+ "nsISupportsWeakReference",
+ ]),
+ // useful for debugging
+ get wrappedJSObject() {
+ return this;
+ },
+ get rowCount() {
+ return itemArray.length;
+ },
+ get selection() {
+ return treeSelection;
+ },
+ set selection(selection) {
+ return (treeSelection = selection);
+ },
+ getRowProperties(index) {
+ return "";
+ },
+ // could have used a wrapper for this
+ getCellProperties(index, column) {
+ if (column.id == "SelectSelCol" && !itemArray[index].container) {
+ return "checked-" + itemArray[index].element.hasAttribute("selected");
+ }
+ return "";
+ },
+ getColumnProperties(column) {
+ return "";
+ },
+ // get info from wrapper
+ isContainer(index) {
+ return itemArray[index].container;
+ },
+ isContainerOpen(index) {
+ return true;
+ },
+ isContainerEmpty(index) {
+ return true;
+ },
+ isSeparator(index) {
+ return false;
+ },
+ isSorted() {
+ return false;
+ },
+ // d&d not implemented yet!
+ canDrop(index, orientation) {
+ return false;
+ },
+ drop(index, orientation) {
+ alert("drop:" + index + "," + orientation);
+ },
+ // same as the global helper
+ getParentIndex,
+ // tree needs to know when to paint lines
+ hasNextSibling(index, after) {
+ if (!index) {
+ return false;
+ }
+ var level = itemArray[index].level;
+ while (++after < itemArray.length) {
+ switch (level - itemArray[after].level) {
+ case 1:
+ return false;
+ case 0:
+ return true;
+ }
+ }
+ return false;
+ },
+ getLevel(index) {
+ return itemArray[index].level;
+ },
+ getImageSrc(index, column) {},
+ getProgressMode(index, column) {},
+ getCellValue(index, column) {},
+ getCellText(index, column) {
+ return itemArray[index].getCellText(column);
+ },
+ setTree(tree) {
+ this.tree = tree;
+ },
+ toggleOpenState(index) {},
+ cycleHeader(col) {},
+ selectionChanged() {
+ // Save current values and update buttons and deck
+ if (currentItem) {
+ currentItem.onBlur();
+ }
+ var currentIndex = treeSelection.currentIndex;
+ currentItem = itemArray[currentIndex];
+ gDialog.removeButton.disabled = !currentItem.canDestroy();
+ gDialog.previousButton.disabled = currentIndex < 2;
+ gDialog.nextButton.disabled = !currentItem.canMoveDown();
+ // For Advanced Edit
+ globalElement = currentItem.element;
+ currentItem.onFocus();
+ },
+ cycleCell(index, column) {
+ itemArray[index].cycleCell(index);
+ },
+ isEditable(index, column) {
+ return false;
+ },
+ };
+ treeSelection.select(0);
+ currentItem = gDialog;
+ // onNameInput();
+
+ SetTextboxFocus(gDialog.selectName);
+
+ SetWindowLocation();
+}
+
+// Called from Advanced Edit
+function InitDialog() {
+ currentItem.onFocus();
+}
+
+// Called from Advanced Edit
+function ValidateData() {
+ currentItem.onBlur();
+ return true;
+}
+
+function onAccept() {
+ // All values are valid - copy to actual element in doc or
+ // element created to insert
+ ValidateData();
+
+ var editor = GetCurrentEditor();
+
+ // Coalesce into one undo transaction
+ editor.beginTransaction();
+
+ try {
+ editor.cloneAttributes(selectElement, gDialog.element);
+
+ if (insertNew) {
+ // 'true' means delete the selection before inserting
+ editor.insertElementAtSelection(selectElement, true);
+ }
+
+ editor.setShouldTxnSetSelection(false);
+
+ while (selectElement.lastChild) {
+ editor.deleteNode(selectElement.lastChild);
+ }
+
+ var offset = 0;
+ for (var i = 1; i < itemArray.length; i++) {
+ if (itemArray[i].level > 1) {
+ selectElement.lastChild.appendChild(itemArray[i].element);
+ } else {
+ editor.insertNode(itemArray[i].element, selectElement, offset++);
+ }
+ }
+
+ editor.setShouldTxnSetSelection(true);
+ } finally {
+ editor.endTransaction();
+ }
+
+ SaveWindowLocation();
+}
+
+// Button actions
+function AddOption() {
+ currentItem.appendOption(
+ GetCurrentEditor().createElementWithDefaults("option"),
+ treeSelection.currentIndex
+ );
+ SetTextboxFocus(gDialog.optionText);
+}
+
+function AddOptGroup() {
+ var optgroupElement = GetCurrentEditor().createElementWithDefaults(
+ "optgroup"
+ );
+ var index = itemArray.length;
+ // XXX need to repaint the lines, tree won't do this
+ theTree.invalidateRange(gDialog.lastChild(), index);
+ // append the wrapped object
+ itemArray.push(new optgroupObject(optgroupElement));
+ theTree.rowCountChanged(index, 1);
+ selectTreeIndex(index, false);
+ SetTextboxFocus(gDialog.optgroupLabel);
+}
+
+function RemoveElement() {
+ if (currentItem.canDestroy(true)) {
+ // Only removing empty option groups for now
+ var index = treeSelection.currentIndex;
+ var level = itemArray[index].level;
+ // Perform necessary cleanup and remove the wrapper
+ itemArray[index].destroy();
+ itemArray.splice(index, 1);
+ --index;
+ // XXX need to repaint the lines, tree won't do this
+ if (level == 1) {
+ var last = gDialog.lastChild();
+ if (index > last) {
+ theTree.invalidateRange(last, index);
+ }
+ }
+ selectTreeIndex(index, true);
+ theTree.rowCountChanged(++index, -1);
+ }
+}
+
+// Event handler
+function onTreeKeyUp(event) {
+ if (event.keyCode == event.DOM_VK_SPACE) {
+ currentItem.cycleCell();
+ }
+}
+
+function onNameInput() {
+ var disabled = !gDialog.selectName.value;
+ if (gDialog.accept.disabled != disabled) {
+ gDialog.accept.disabled = disabled;
+ }
+ gDialog.element.setAttribute("name", gDialog.selectName.value);
+ // repaint the tree
+ var primaryCol = theTree.columns.getPrimaryColumn();
+ theTree.invalidateCell(treeSelection.currentIndex, primaryCol);
+}
+
+function onLabelInput() {
+ currentItem.element.setAttribute("label", gDialog.optgroupLabel.value);
+ // repaint the tree
+ var primaryCol = theTree.columns.getPrimaryColumn();
+ theTree.invalidateCell(treeSelection.currentIndex, primaryCol);
+}
+
+function onTextInput() {
+ currentItem.element.text = gDialog.optionText.value;
+ // repaint the tree
+ if (hasValue) {
+ var primaryCol = theTree.columns.getPrimaryColumn();
+ theTree.invalidateCell(treeSelection.currentIndex, primaryCol);
+ } else {
+ gDialog.optionValue.value = gDialog.optionText.value;
+ theTree.invalidateRow(treeSelection.currentIndex);
+ }
+}
+
+function onValueInput() {
+ gDialog.optionHasValue.checked = hasValue = true;
+ oldValue = gDialog.optionValue.value;
+ currentItem.element.setAttribute("value", oldValue);
+ // repaint the tree
+ var column = theTree.columns.SelectValCol;
+ theTree.invalidateCell(treeSelection.currentIndex, column);
+}
+
+function onHasValueClick() {
+ hasValue = gDialog.optionHasValue.checked;
+ if (hasValue) {
+ gDialog.optionValue.value = oldValue;
+ currentItem.element.setAttribute("value", oldValue);
+ } else {
+ oldValue = gDialog.optionValue.value;
+ gDialog.optionValue.value = gDialog.optionText.value;
+ currentItem.element.removeAttribute("value");
+ }
+ // repaint the tree
+ var column = theTree.columns.SelectValCol;
+ theTree.invalidateCell(treeSelection.currentIndex, column);
+}
+
+function onSelectMultipleClick() {
+ // Recalculate the unique selected option if we need it and have lost it
+ if (
+ !gDialog.selectMultiple.checked &&
+ selectedOptionCount == 1 &&
+ !selectedOption
+ ) {
+ // eslint-disable-next-line curly
+ for (
+ var i = 1;
+ !(selectedOption = itemArray[i].element).hasAttribute("selected");
+ i++
+ );
+ }
+}
+
+function selectTreeIndex(index, focus) {
+ treeSelection.select(index);
+ theTree.ensureRowIsVisible(index);
+ if (focus) {
+ gDialog.tree.focus();
+ }
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdSelectProps.xhtml b/comm/suite/editor/components/dialogs/content/EdSelectProps.xhtml
new file mode 100644
index 0000000000..ff91b02e28
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdSelectProps.xhtml
@@ -0,0 +1,143 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edSelectProperties SYSTEM "chrome://editor/locale/EditorSelectProperties.dtd">
+%edSelectProperties;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup();"
+ buttons="accept,cancel">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdSelectProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <!-- Setting rows="7" on tree isn't working, equalsize vbox sets tree height. -->
+ <vbox equalsize="always">
+ <tree id="SelectTree" onselect="treeBoxObject.view.selectionChanged();" onkeyup="onTreeKeyUp(event);">
+ <treecols id="SelectCols">
+ <treecol id="SelectTextCol" flex="3" label="&TextHeader.label;" primary="true"/>
+ <splitter class="tree-splitter"/>
+ <treecol id="SelectValCol" flex="2" label="&ValueHeader.label;"/>
+ <treecol id="SelectSelCol" label="&SelectedHeader.label;" cycler="true"/>
+ </treecols>
+
+ <treechildren id="SelectTreeChildren"/>
+ </tree>
+
+ <hbox flex="1">
+ <deck flex="1" id="SelectDeck" index="0">
+ <groupbox flex="1">
+ <hbox class="groupbox-title">
+ <label class="header">&Select.label;</label>
+ </hbox>
+ <grid flex="1"><columns><column flex="1"/><column/></columns>
+ <rows>
+ <row align="center">
+ <label control="SelectName" value="&SelectName.label;" accesskey="&SelectName.accesskey;"/>
+ <textbox id="SelectName" flex="1" oninput="onNameInput();"/>
+ </row>
+ <row align="center">
+ <label control="SelectSize" value="&SelectSize.label;" accesskey="&SelectSize.accesskey;"/>
+ <hbox>
+ <textbox id="SelectSize" class="narrow" oninput="forceInteger(this.id);"/>
+ </hbox>
+ </row>
+ <row>
+ <spacer/>
+ <checkbox id="SelectMultiple" flex="1" label="&SelectMultiple.label;" accesskey="&SelectMultiple.accesskey;" oncommand="onSelectMultipleClick();"/>
+ </row>
+ <row>
+ <spacer/>
+ <checkbox id="SelectDisabled" flex="1" label="&SelectDisabled.label;" accesskey="&SelectDisabled.accesskey;"/>
+ </row>
+ <row align="center">
+ <label control="SelectTabIndex" value="&SelectTabIndex.label;" accesskey="&SelectTabIndex.accesskey;"/>
+ <hbox>
+ <textbox id="SelectTabIndex" class="narrow" oninput="forceInteger(this.id);"/>
+ </hbox>
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+
+ <groupbox flex="1">
+ <hbox class="groupbox-title">
+ <label class="header">&OptGroup.label;</label>
+ </hbox>
+ <grid flex="1"><columns><column flex="1"/><column/></columns>
+ <rows>
+ <row align="center">
+ <label control="OptGroupLabel" value="&OptGroupLabel.label;" accesskey="&OptGroupLabel.accesskey;"/>
+ <textbox id="OptGroupLabel" oninput="onLabelInput();"/>
+ </row>
+ <row>
+ <spacer/>
+ <checkbox id="OptGroupDisabled" label="&OptGroupDisabled.label;" accesskey="&OptGroupDisabled.accesskey;"/>
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+
+ <groupbox flex="1">
+ <hbox class="groupbox-title">
+ <label class="header">&Option.label;</label>
+ </hbox>
+ <grid flex="1"><columns><column flex="1"/><column/></columns>
+ <rows>
+ <row align="center">
+ <label control="OptionText" value="&OptionText.label;" accesskey="&OptionText.accesskey;"/>
+ <textbox id="OptionText" oninput="onTextInput();"/>
+ </row>
+ <row align="center">
+ <checkbox id="OptionHasValue" label="&OptionValue.label;" accesskey="&OptionValue.accesskey;" oncommand="onHasValueClick();"/>
+ <textbox id="OptionValue" oninput="onValueInput();"/>
+ </row>
+ <row>
+ <spacer/>
+ <checkbox id="OptionSelected" label="&OptionSelected.label;" accesskey="&OptionSelected.accesskey;" oncommand="currentItem.cycleCell();"/>
+ </row>
+ <row>
+ <spacer/>
+ <checkbox id="OptionDisabled" label="&OptionDisabled.label;" accesskey="&OptionDisabled.accesskey;"/>
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+ </deck>
+
+ <vbox>
+ <button label="&AddOption.label;" accesskey="&AddOption.accesskey;" oncommand="AddOption();"/>
+ <button label="&AddOptGroup.label;" accesskey="&AddOptGroup.accesskey;" oncommand="AddOptGroup();"/>
+ <button id="RemoveButton" label="&RemoveElement.label;" accesskey="&RemoveElement.accesskey;"
+ oncommand="RemoveElement();" disabled="true"/>
+ <button id="PreviousButton" label="&MoveElementUp.label;" accesskey="&MoveElementUp.accesskey;"
+ oncommand="currentItem.moveUp();" disabled="true" type="row"/>
+ <button id="NextButton" label="&MoveElementDown.label;" accesskey="&MoveElementDown.accesskey;"
+ oncommand="currentItem.moveDown();" disabled="true" type="row"/>
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton"
+ oncommand="onAdvancedEdit();"
+ label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;"
+ tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </vbox>
+ </hbox>
+ </vbox>
+
+ <separator class="groove"/>
+
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdSnapToGrid.js b/comm/suite/editor/components/dialogs/content/EdSnapToGrid.js
new file mode 100644
index 0000000000..ed546d3540
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdSnapToGrid.js
@@ -0,0 +1,62 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var gEditor;
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup()
+{
+ gEditor = GetCurrentEditor();
+ if (!gEditor)
+ {
+ window.close();
+ return;
+ }
+
+ gEditor instanceof Ci.nsIHTMLAbsPosEditor;
+
+ gDialog.enableSnapToGrid = document.getElementById("enableSnapToGrid");
+ gDialog.sizeInput = document.getElementById("size");
+ gDialog.sizeLabel = document.getElementById("sizeLabel");
+ gDialog.unitLabel = document.getElementById("unitLabel");
+
+ // Initialize control values based on existing attributes
+ InitDialog()
+
+ // SET FOCUS TO FIRST CONTROL
+ SetTextboxFocus(gDialog.sizeInput);
+
+ // Resize window
+ window.sizeToContent();
+
+ SetWindowLocation();
+}
+
+// Set dialog widgets with attribute data
+// We get them from globalElement copy so this can be used
+// by AdvancedEdit(), which is shared by all property dialogs
+function InitDialog()
+{
+ gDialog.enableSnapToGrid.checked = gEditor.snapToGridEnabled;
+ toggleSnapToGrid();
+
+ gDialog.sizeInput.value = gEditor.gridSize;
+}
+
+function onAccept()
+{
+ gEditor.snapToGridEnabled = gDialog.enableSnapToGrid.checked;
+ gEditor.gridSize = gDialog.sizeInput.value;
+}
+
+function toggleSnapToGrid()
+{
+ SetElementEnabledById("size", gDialog.enableSnapToGrid.checked)
+ SetElementEnabledById("sizeLabel", gDialog.enableSnapToGrid.checked)
+ SetElementEnabledById("unitLabel", gDialog.enableSnapToGrid.checked)
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdSnapToGrid.xhtml b/comm/suite/editor/components/dialogs/content/EdSnapToGrid.xhtml
new file mode 100644
index 0000000000..9ae6643975
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdSnapToGrid.xhtml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorSnapToGrid.dtd">
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <!--- Element-specific methods -->
+ <script src="chrome://editor/content/EdSnapToGrid.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <checkbox id="enableSnapToGrid"
+ label="&enableSnapToGrid.label;"
+ accesskey="&enableSnapToGrid.accessKey;"
+ oncommand="toggleSnapToGrid();"/>
+
+ <spacer class="spacer"/>
+
+ <grid>
+ <columns><column/><column/><column /></columns>
+ <rows>
+ <row align="center">
+ <label value="&sizeEditField.label;"
+ id="sizeLabel"
+ control="size"
+ accesskey="&sizeEditField.accessKey;"/>
+ <textbox class="narrow" id="size" oninput="forceInteger('size')"/>
+ <label id="unitLabel"
+ value="&pixelsLabel.value;" />
+ </row>
+ </rows>
+ </grid>
+
+ <spacer class="spacer"/>
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdSpellCheck.js b/comm/suite/editor/components/dialogs/content/EdSpellCheck.js
new file mode 100644
index 0000000000..ddb23726cd
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdSpellCheck.js
@@ -0,0 +1,495 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../../../mail/base/content/utilityOverlay.js */
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var { InlineSpellChecker } = ChromeUtils.import(
+ "resource://gre/modules/InlineSpellChecker.jsm"
+);
+
+var gMisspelledWord;
+var gSpellChecker = null;
+var gAllowSelectWord = true;
+var gPreviousReplaceWord = "";
+var gFirstTime = true;
+var gLastSelectedLang = null;
+var gDictCount = 0;
+
+document.addEventListener("dialogaccept", doDefault);
+document.addEventListener("dialogcancel", CancelSpellCheck);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ window.close();
+ return;
+ }
+
+ // Get the spellChecker shell
+ gSpellChecker = Cu.createSpellChecker();
+ if (!gSpellChecker) {
+ dump("SpellChecker not found!!!\n");
+ window.close();
+ return;
+ }
+
+ // Start the spell checker module.
+ try {
+ var skipBlockQuotes = window.arguments[1];
+ var enableSelectionChecking = window.arguments[2];
+
+ gSpellChecker.setFilterType(
+ skipBlockQuotes
+ ? Ci.nsIEditorSpellCheck.FILTERTYPE_MAIL
+ : Ci.nsIEditorSpellCheck.FILTERTYPE_NORMAL
+ );
+ gSpellChecker.InitSpellChecker(
+ editor,
+ enableSelectionChecking,
+ spellCheckStarted
+ );
+ } catch (ex) {
+ dump("*** Exception error: InitSpellChecker\n");
+ window.close();
+ }
+}
+
+function spellCheckStarted() {
+ gDialog.MisspelledWordLabel = document.getElementById("MisspelledWordLabel");
+ gDialog.MisspelledWord = document.getElementById("MisspelledWord");
+ gDialog.ReplaceButton = document.getElementById("Replace");
+ gDialog.IgnoreButton = document.getElementById("Ignore");
+ gDialog.StopButton = document.getElementById("Stop");
+ gDialog.CloseButton = document.getElementById("Close");
+ gDialog.ReplaceWordInput = document.getElementById("ReplaceWordInput");
+ gDialog.SuggestedList = document.getElementById("SuggestedList");
+ gDialog.LanguageMenulist = document.getElementById("LanguageMenulist");
+
+ // Fill in the language menulist and sync it up
+ // with the spellchecker's current language.
+
+ var curLang;
+
+ try {
+ curLang = gSpellChecker.GetCurrentDictionary();
+ } catch (ex) {
+ curLang = "";
+ }
+
+ InitLanguageMenu(curLang);
+
+ // Get the first misspelled word and setup all UI
+ NextWord();
+
+ // When startup param is true, setup different UI when spell checking
+ // just before sending mail message
+ if (window.arguments[0]) {
+ // If no misspelled words found, simply close dialog and send message
+ if (!gMisspelledWord) {
+ onClose();
+ return;
+ }
+
+ // Hide "Close" button and use "Send" instead
+ gDialog.CloseButton.hidden = true;
+ gDialog.CloseButton = document.getElementById("Send");
+ gDialog.CloseButton.hidden = false;
+ } else {
+ // Normal spell checking - hide the "Stop" button
+ // (Note that this button is the "Cancel" button for
+ // Esc keybinding and related window close actions)
+ gDialog.StopButton.hidden = true;
+ }
+
+ // Clear flag that determines message when
+ // no misspelled word is found
+ // (different message when used for the first time)
+ gFirstTime = false;
+
+ window.sizeToContent();
+}
+
+function InitLanguageMenu(aCurLang) {
+ // Get the list of dictionaries from
+ // the spellchecker.
+
+ var dictList;
+ try {
+ dictList = gSpellChecker.GetDictionaryList();
+ } catch (ex) {
+ dump("Failed to get DictionaryList!\n");
+ return;
+ }
+
+ // If we're not just starting up and dictionary count
+ // hasn't changed then no need to update the menu.
+ if (gDictCount == dictList.length) {
+ return;
+ }
+
+ // Store current dictionary count.
+ gDictCount = dictList.length;
+
+ var inlineSpellChecker = new InlineSpellChecker();
+ var sortedList = inlineSpellChecker.sortDictionaryList(dictList);
+
+ // Remove any languages from the list.
+ var languageMenuPopup = gDialog.LanguageMenulist.menupopup;
+ while (languageMenuPopup.firstChild.localName != "menuseparator") {
+ languageMenuPopup.firstChild.remove();
+ }
+
+ var defaultItem = null;
+
+ for (var i = 0; i < gDictCount; i++) {
+ let item = document.createXULElement("menuitem");
+ item.setAttribute("label", sortedList[i].displayName);
+ item.setAttribute("value", sortedList[i].localeCode);
+ let beforeItem = gDialog.LanguageMenulist.getItemAtIndex(i);
+ languageMenuPopup.insertBefore(item, beforeItem);
+
+ if (aCurLang && sortedList[i].localeCode == aCurLang) {
+ defaultItem = item;
+ }
+ }
+
+ // Now make sure the correct item in the menu list is selected.
+ if (defaultItem) {
+ gDialog.LanguageMenulist.selectedItem = defaultItem;
+ gLastSelectedLang = defaultItem;
+ }
+}
+
+function DoEnabling() {
+ if (!gMisspelledWord) {
+ // No more misspelled words
+ gDialog.MisspelledWord.setAttribute(
+ "value",
+ GetString(gFirstTime ? "NoMisspelledWord" : "CheckSpellingDone")
+ );
+
+ gDialog.ReplaceButton.removeAttribute("default");
+ gDialog.IgnoreButton.removeAttribute("default");
+
+ gDialog.CloseButton.setAttribute("default", "true");
+ // Shouldn't have to do this if "default" is true?
+ gDialog.CloseButton.focus();
+
+ SetElementEnabledById("MisspelledWordLabel", false);
+ SetElementEnabledById("ReplaceWordLabel", false);
+ SetElementEnabledById("ReplaceWordInput", false);
+ SetElementEnabledById("CheckWord", false);
+ SetElementEnabledById("SuggestedListLabel", false);
+ SetElementEnabledById("SuggestedList", false);
+ SetElementEnabledById("Ignore", false);
+ SetElementEnabledById("IgnoreAll", false);
+ SetElementEnabledById("Replace", false);
+ SetElementEnabledById("ReplaceAll", false);
+ SetElementEnabledById("AddToDictionary", false);
+ } else {
+ SetElementEnabledById("MisspelledWordLabel", true);
+ SetElementEnabledById("ReplaceWordLabel", true);
+ SetElementEnabledById("ReplaceWordInput", true);
+ SetElementEnabledById("CheckWord", true);
+ SetElementEnabledById("SuggestedListLabel", true);
+ SetElementEnabledById("SuggestedList", true);
+ SetElementEnabledById("Ignore", true);
+ SetElementEnabledById("IgnoreAll", true);
+ SetElementEnabledById("AddToDictionary", true);
+
+ gDialog.CloseButton.removeAttribute("default");
+ SetReplaceEnable();
+ }
+}
+
+function NextWord() {
+ gMisspelledWord = gSpellChecker.GetNextMisspelledWord();
+ SetWidgetsForMisspelledWord();
+}
+
+function SetWidgetsForMisspelledWord() {
+ gDialog.MisspelledWord.setAttribute("value", gMisspelledWord);
+
+ // Initial replace word is misspelled word
+ gDialog.ReplaceWordInput.value = gMisspelledWord;
+ gPreviousReplaceWord = gMisspelledWord;
+
+ // This sets gDialog.ReplaceWordInput to first suggested word in list
+ FillSuggestedList(gMisspelledWord);
+
+ DoEnabling();
+
+ if (gMisspelledWord) {
+ SetTextboxFocus(gDialog.ReplaceWordInput);
+ }
+}
+
+function CheckWord() {
+ var word = gDialog.ReplaceWordInput.value;
+ if (word) {
+ if (gSpellChecker.CheckCurrentWord(word)) {
+ FillSuggestedList(word);
+ SetReplaceEnable();
+ } else {
+ ClearListbox(gDialog.SuggestedList);
+ var item = gDialog.SuggestedList.appendItem(
+ GetString("CorrectSpelling"),
+ ""
+ );
+ if (item) {
+ item.setAttribute("disabled", "true");
+ }
+ // Suppress being able to select the message text
+ gAllowSelectWord = false;
+ }
+ }
+}
+
+function SelectSuggestedWord() {
+ if (gAllowSelectWord) {
+ if (gDialog.SuggestedList.selectedItem) {
+ var selValue = gDialog.SuggestedList.selectedItem.label;
+ gDialog.ReplaceWordInput.value = selValue;
+ gPreviousReplaceWord = selValue;
+ } else {
+ gDialog.ReplaceWordInput.value = gPreviousReplaceWord;
+ }
+ SetReplaceEnable();
+ }
+}
+
+function ChangeReplaceWord() {
+ // Calling this triggers SelectSuggestedWord(),
+ // so temporarily suppress the effect of that
+ var saveAllow = gAllowSelectWord;
+ gAllowSelectWord = false;
+
+ // Select matching word in list
+ var newSelectedItem;
+ var replaceWord = TrimString(gDialog.ReplaceWordInput.value);
+ if (replaceWord) {
+ for (var i = 0; i < gDialog.SuggestedList.getRowCount(); i++) {
+ var item = gDialog.SuggestedList.getItemAtIndex(i);
+ if (item.label == replaceWord) {
+ newSelectedItem = item;
+ break;
+ }
+ }
+ }
+ gDialog.SuggestedList.selectedItem = newSelectedItem;
+
+ gAllowSelectWord = saveAllow;
+
+ // Remember the new word
+ gPreviousReplaceWord = gDialog.ReplaceWordInput.value;
+
+ SetReplaceEnable();
+}
+
+function Ignore() {
+ NextWord();
+}
+
+function IgnoreAll() {
+ if (gMisspelledWord) {
+ gSpellChecker.IgnoreWordAllOccurrences(gMisspelledWord);
+ }
+ NextWord();
+}
+
+function Replace(newWord) {
+ if (!newWord) {
+ return;
+ }
+
+ if (gMisspelledWord && gMisspelledWord != newWord) {
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+ try {
+ gSpellChecker.ReplaceWord(gMisspelledWord, newWord, false);
+ } catch (e) {}
+ editor.endTransaction();
+ }
+ NextWord();
+}
+
+function ReplaceAll() {
+ var newWord = gDialog.ReplaceWordInput.value;
+ if (gMisspelledWord && gMisspelledWord != newWord) {
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+ try {
+ gSpellChecker.ReplaceWord(gMisspelledWord, newWord, true);
+ } catch (e) {}
+ editor.endTransaction();
+ }
+ NextWord();
+}
+
+function AddToDictionary() {
+ if (gMisspelledWord) {
+ gSpellChecker.AddWordToDictionary(gMisspelledWord);
+ }
+ NextWord();
+}
+
+function EditDictionary() {
+ window.openDialog(
+ "chrome://editor/content/EdDictionary.xhtml",
+ "_blank",
+ "chrome,close,titlebar,modal",
+ "",
+ gMisspelledWord
+ );
+}
+
+function SelectLanguage() {
+ var item = gDialog.LanguageMenulist.selectedItem;
+ if (item.value != "more-cmd") {
+ gSpellChecker.SetCurrentDictionary(item.value);
+ // For compose windows we need to set the "lang" attribute so the
+ // core editor uses the correct dictionary for the inline spell check.
+ if (window.arguments[1]) {
+ if ("ComposeChangeLanguage" in window.opener) {
+ // We came here from a compose window.
+ window.opener.ComposeChangeLanguage(item.value);
+ } else {
+ window.opener.document.documentElement.setAttribute("lang", item.value);
+ }
+ }
+ gLastSelectedLang = item;
+ } else {
+ openDictionaryList();
+
+ if (gLastSelectedLang) {
+ gDialog.LanguageMenulist.selectedItem = gLastSelectedLang;
+ }
+ }
+}
+
+function Recheck() {
+ var recheckLanguage;
+
+ function finishRecheck() {
+ gSpellChecker.SetCurrentDictionary(recheckLanguage);
+ gMisspelledWord = gSpellChecker.GetNextMisspelledWord();
+ SetWidgetsForMisspelledWord();
+ }
+
+ // TODO: Should we bother to add a "Recheck" method to interface?
+ try {
+ recheckLanguage = gSpellChecker.GetCurrentDictionary();
+ gSpellChecker.UninitSpellChecker();
+ // Clear the ignore all list.
+ Cc["@mozilla.org/spellchecker/personaldictionary;1"]
+ .getService(Ci.mozIPersonalDictionary)
+ .endSession();
+ gSpellChecker.InitSpellChecker(GetCurrentEditor(), false, finishRecheck);
+ } catch (ex) {
+ Cu.reportError(ex);
+ }
+}
+
+function FillSuggestedList(misspelledWord) {
+ var list = gDialog.SuggestedList;
+
+ // Clear the current contents of the list
+ gAllowSelectWord = false;
+ ClearListbox(list);
+ var item;
+
+ if (misspelledWord.length > 0) {
+ // Get suggested words until an empty string is returned
+ var count = 0;
+ do {
+ var word = gSpellChecker.GetSuggestedWord();
+ if (word.length > 0) {
+ list.appendItem(word, "");
+ count++;
+ }
+ } while (word.length > 0);
+
+ if (count == 0) {
+ // No suggestions - show a message but don't let user select it
+ item = list.appendItem(GetString("NoSuggestedWords"));
+ if (item) {
+ item.setAttribute("disabled", "true");
+ }
+ gAllowSelectWord = false;
+ } else {
+ gAllowSelectWord = true;
+ // Initialize with first suggested list by selecting it
+ gDialog.SuggestedList.selectedIndex = 0;
+ }
+ } else {
+ item = list.appendItem("", "");
+ if (item) {
+ item.setAttribute("disabled", "true");
+ }
+ }
+}
+
+function SetReplaceEnable() {
+ // Enable "Change..." buttons only if new word is different than misspelled
+ var newWord = gDialog.ReplaceWordInput.value;
+ var enable = newWord.length > 0 && newWord != gMisspelledWord;
+ SetElementEnabledById("Replace", enable);
+ SetElementEnabledById("ReplaceAll", enable);
+ if (enable) {
+ gDialog.ReplaceButton.setAttribute("default", "true");
+ gDialog.IgnoreButton.removeAttribute("default");
+ } else {
+ gDialog.IgnoreButton.setAttribute("default", "true");
+ gDialog.ReplaceButton.removeAttribute("default");
+ }
+}
+
+function doDefault(event) {
+ if (gDialog.ReplaceButton.getAttribute("default") == "true") {
+ Replace(gDialog.ReplaceWordInput.value);
+ } else if (gDialog.IgnoreButton.getAttribute("default") == "true") {
+ Ignore();
+ } else if (gDialog.CloseButton.getAttribute("default") == "true") {
+ onClose();
+ }
+
+ event.preventDefault();
+}
+
+function ExitSpellChecker() {
+ if (gSpellChecker) {
+ try {
+ gSpellChecker.UninitSpellChecker();
+ // now check the document over again with the new dictionary
+ // if we have an inline spellchecker
+ if (
+ "InlineSpellCheckerUI" in window.opener &&
+ window.opener.InlineSpellCheckerUI.enabled
+ ) {
+ window.opener.InlineSpellCheckerUI.mInlineSpellChecker.spellCheckRange(
+ null
+ );
+ }
+ } finally {
+ gSpellChecker = null;
+ }
+ }
+}
+
+function CancelSpellCheck() {
+ ExitSpellChecker();
+
+ // Signal to calling window that we canceled
+ window.opener.cancelSendMessage = true;
+}
+
+function onClose() {
+ ExitSpellChecker();
+
+ window.opener.cancelSendMessage = false;
+ window.close();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdSpellCheck.xhtml b/comm/suite/editor/components/dialogs/content/EdSpellCheck.xhtml
new file mode 100644
index 0000000000..4cb9f49198
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdSpellCheck.xhtml
@@ -0,0 +1,113 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorSpellCheck.dtd">
+
+<!-- dialog containing a control requiring initial setup -->
+<dialog id="spellCheckDlg" buttons="cancel" title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ persist="screenX screenY"
+ onload="Startup()">
+
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://communicator/content/utilityOverlay.js"/>
+ <script src="chrome://editor/content/EdSpellCheck.js"/>
+ <script src="chrome://global/content/contentAreaUtils.js"/>
+
+ <stringbundle id="languageBundle" src="chrome://global/locale/languageNames.properties"/>
+ <stringbundle id="regionBundle" src="chrome://global/locale/regionNames.properties"/>
+
+ <grid>
+ <columns>
+ <column class="spell-check"/>
+ <column class="spell-check" flex="1"/>
+ <column class="spell-check"/>
+ </columns>
+ <rows>
+ <row align="center">
+ <label id="MisspelledWordLabel" value="&misspelledWord.label;"/>
+ <label class="bold" id="MisspelledWord" crop="end"/>
+ <button class="spell-check" label="&recheckButton2.label;" oncommand="Recheck();"
+ accesskey="&recheckButton2.accessKey;"/>
+ </row>
+ <row align="center">
+ <label id="ReplaceWordLabel" value="&wordEditField.label;"
+ control="ReplaceWordInput"
+ accesskey="&wordEditField.accessKey;"/>
+ <textbox id="ReplaceWordInput" oninput="ChangeReplaceWord()" flex="1"/>
+ <button id="CheckWord" oncommand="CheckWord()" label="&checkwordButton.label;"
+ accesskey="&checkwordButton.accessKey;"/>
+ </row>
+ </rows>
+ </grid>
+ <label id="SuggestedListLabel" value="&suggestions.label;"
+ control="SuggestedList"
+ accesskey="&suggestions.accessKey;"/>
+ <grid flex="1">
+ <columns><column flex="1"/><column/></columns>
+ <rows>
+ <row flex="1">
+ <!-- BUG! setting class="MinWidth20em" on tree doesn't work (width=0) -->
+ <richlistbox id="SuggestedList"
+ class="theme-listbox"
+ onselect="SelectSuggestedWord()"
+ ondblclick="if (gAllowSelectWord) { Replace(event.target.value); }"/>
+ <vbox>
+ <grid>
+ <columns><column class="spell-check" flex="1"/><column class="spell-check" flex="1"/></columns>
+ <rows>
+ <row>
+ <button id="Replace" label="&replaceButton.label;"
+ oncommand="Replace(gDialog.ReplaceWordInput.value);"
+ accesskey="&replaceButton.accessKey;"/>
+ <button id="Ignore" oncommand="Ignore();" label="&ignoreButton.label;"
+ accesskey="&ignoreButton.accessKey;"/>
+ </row>
+ <row>
+ <button id="ReplaceAll" oncommand="ReplaceAll();" label="&replaceAllButton.label;"
+ accesskey="&replaceAllButton.accessKey;"/>
+ <button id="IgnoreAll" oncommand="IgnoreAll();" label="&ignoreAllButton.label;"
+ accesskey="&ignoreAllButton.accessKey;"/>
+ </row>
+ </rows>
+ </grid>
+ <separator/>
+ <label value="&userDictionary.label;"/>
+ <hbox align="start">
+ <button class="spell-check" id="AddToDictionary" oncommand="AddToDictionary()" label="&addToUserDictionaryButton.label;"
+ accesskey="&addToUserDictionaryButton.accessKey;"/>
+ <button class="spell-check" id="EditDictionary" oncommand="EditDictionary()" label="&editUserDictionaryButton.label;"
+ accesskey="&editUserDictionaryButton.accessKey;"/>
+ </hbox>
+ </vbox>
+ </row>
+ <label value ="&languagePopup.label;"
+ control="LanguageMenulist"
+ accesskey="&languagePopup.accessKey;"/>
+ <row>
+ <menulist id="LanguageMenulist" oncommand="SelectLanguage()">
+ <menupopup onpopupshowing="InitLanguageMenu(gDialog.LanguageMenulist.selectedItem.value);">
+ <!-- dynamic content populated by JS -->
+ <menuseparator/>
+ <menuitem value="more-cmd" label="&moreDictionaries.label;"/>
+ </menupopup>
+ </menulist>
+ <hbox flex="1">
+ <button class="spell-check" dlgtype="cancel" id="Stop" label="&stopButton.label;" oncommand="CancelSpellCheck();"
+ accesskey="&stopButton.accessKey;"/>
+ <spacer flex="1"/>
+ <button class="spell-check" id="Close" label="&closeButton.label;" oncommand="onClose();"
+ accesskey="&closeButton.accessKey;"/>
+ <button class="spell-check" id="Send" label="&sendButton.label;" oncommand="onClose();"
+ accesskey="&sendButton.accessKey;" hidden="true"/>
+ </hbox>
+ </row>
+ </rows>
+ </grid>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdTableProps.js b/comm/suite/editor/components/dialogs/content/EdTableProps.js
new file mode 100644
index 0000000000..e78a89bc41
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdTableProps.js
@@ -0,0 +1,1439 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+// Cancel() is in EdDialogCommon.js
+
+var gTableElement;
+var gCellElement;
+var gTableCaptionElement;
+var globalCellElement;
+var globalTableElement;
+var gValidateTab;
+const defHAlign = "left";
+const centerStr = "center"; // Index=1
+const rightStr = "right"; // 2
+const justifyStr = "justify"; // 3
+const charStr = "char"; // 4
+const defVAlign = "middle";
+const topStr = "top";
+const bottomStr = "bottom";
+const bgcolor = "bgcolor";
+var gTableColor;
+var gCellColor;
+
+const cssBackgroundColorStr = "background-color";
+
+var gRowCount = 1;
+var gColCount = 1;
+var gLastRowIndex;
+var gLastColIndex;
+var gNewRowCount;
+var gNewColCount;
+var gCurRowIndex;
+var gCurColIndex;
+var gCurColSpan;
+var gSelectedCellsType = 1;
+const SELECT_CELL = 1;
+const SELECT_ROW = 2;
+const SELECT_COLUMN = 3;
+const RESET_SELECTION = 0;
+var gCellData = {
+ value: null,
+ startRowIndex: 0,
+ startColIndex: 0,
+ rowSpan: 0,
+ colSpan: 0,
+ actualRowSpan: 0,
+ actualColSpan: 0,
+ isSelected: false,
+};
+var gAdvancedEditUsed;
+var gAlignWasChar = false;
+
+/*
+From C++:
+ 0 TABLESELECTION_TABLE
+ 1 TABLESELECTION_CELL There are 1 or more cells selected
+ but complete rows or columns are not selected
+ 2 TABLESELECTION_ROW All cells are in 1 or more rows
+ and in each row, all cells selected
+ Note: This is the value if all rows (thus all cells) are selected
+ 3 TABLESELECTION_COLUMN All cells are in 1 or more columns
+*/
+
+var gSelectedCellCount = 0;
+var gApplyUsed = false;
+var gSelection;
+var gCellDataChanged = false;
+var gCanDelete = false;
+var gUseCSS = true;
+var gActiveEditor;
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogextra1", Apply);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ gActiveEditor = GetCurrentTableEditor();
+ if (!gActiveEditor) {
+ window.close();
+ return;
+ }
+
+ try {
+ gSelection = gActiveEditor.selection;
+ } catch (e) {}
+ if (!gSelection) {
+ return;
+ }
+
+ // Get dialog widgets - Table Panel
+ gDialog.TableRowsInput = document.getElementById("TableRowsInput");
+ gDialog.TableColumnsInput = document.getElementById("TableColumnsInput");
+ gDialog.TableWidthInput = document.getElementById("TableWidthInput");
+ gDialog.TableWidthUnits = document.getElementById("TableWidthUnits");
+ gDialog.TableHeightInput = document.getElementById("TableHeightInput");
+ gDialog.TableHeightUnits = document.getElementById("TableHeightUnits");
+ try {
+ if (
+ !Services.prefs.getBoolPref("editor.use_css") ||
+ gActiveEditor.flags & 1
+ ) {
+ gUseCSS = false;
+ var tableHeightLabel = document.getElementById("TableHeightLabel");
+ tableHeightLabel.remove();
+ gDialog.TableHeightInput.remove();
+ gDialog.TableHeightUnits.remove();
+ }
+ } catch (e) {}
+ gDialog.BorderWidthInput = document.getElementById("BorderWidthInput");
+ gDialog.SpacingInput = document.getElementById("SpacingInput");
+ gDialog.PaddingInput = document.getElementById("PaddingInput");
+ gDialog.TableAlignList = document.getElementById("TableAlignList");
+ gDialog.TableCaptionList = document.getElementById("TableCaptionList");
+ gDialog.TableInheritColor = document.getElementById("TableInheritColor");
+ gDialog.TabBox = document.getElementById("TabBox");
+
+ // Cell Panel
+ gDialog.SelectionList = document.getElementById("SelectionList");
+ gDialog.PreviousButton = document.getElementById("PreviousButton");
+ gDialog.NextButton = document.getElementById("NextButton");
+ // Currently, we always apply changes and load new attributes when changing selection
+ // (Let's keep this for possible future use)
+ // gDialog.ApplyBeforeMove = document.getElementById("ApplyBeforeMove");
+ // gDialog.KeepCurrentData = document.getElementById("KeepCurrentData");
+
+ gDialog.CellHeightInput = document.getElementById("CellHeightInput");
+ gDialog.CellHeightUnits = document.getElementById("CellHeightUnits");
+ gDialog.CellWidthInput = document.getElementById("CellWidthInput");
+ gDialog.CellWidthUnits = document.getElementById("CellWidthUnits");
+ gDialog.CellHAlignList = document.getElementById("CellHAlignList");
+ gDialog.CellVAlignList = document.getElementById("CellVAlignList");
+ gDialog.CellInheritColor = document.getElementById("CellInheritColor");
+ gDialog.CellStyleList = document.getElementById("CellStyleList");
+ gDialog.TextWrapList = document.getElementById("TextWrapList");
+
+ // In cell panel, user must tell us which attributes to apply via checkboxes,
+ // else we would apply values from one cell to ALL in selection
+ // and that's probably not what they expect!
+ gDialog.CellHeightCheckbox = document.getElementById("CellHeightCheckbox");
+ gDialog.CellWidthCheckbox = document.getElementById("CellWidthCheckbox");
+ gDialog.CellHAlignCheckbox = document.getElementById("CellHAlignCheckbox");
+ gDialog.CellVAlignCheckbox = document.getElementById("CellVAlignCheckbox");
+ gDialog.CellStyleCheckbox = document.getElementById("CellStyleCheckbox");
+ gDialog.TextWrapCheckbox = document.getElementById("TextWrapCheckbox");
+ gDialog.CellColorCheckbox = document.getElementById("CellColorCheckbox");
+ gDialog.TableTab = document.getElementById("TableTab");
+ gDialog.CellTab = document.getElementById("CellTab");
+ gDialog.AdvancedEditCell = document.getElementById("AdvancedEditButton2");
+ // Save "normal" tooltip message for Advanced Edit button
+ gDialog.AdvancedEditCellToolTipText = gDialog.AdvancedEditCell.getAttribute(
+ "tooltiptext"
+ );
+
+ try {
+ gTableElement = gActiveEditor.getElementOrParentByTagName("table", null);
+ } catch (e) {}
+ if (!gTableElement) {
+ dump("Failed to get table element!\n");
+ window.close();
+ return;
+ }
+ globalTableElement = gTableElement.cloneNode(false);
+
+ var tagNameObj = { value: "" };
+ var countObj = { value: 0 };
+ var tableOrCellElement;
+ try {
+ tableOrCellElement = gActiveEditor.getSelectedOrParentTableElement(
+ tagNameObj,
+ countObj
+ );
+ } catch (e) {}
+
+ if (tagNameObj.value == "td") {
+ // We are in a cell
+ gSelectedCellCount = countObj.value;
+ gCellElement = tableOrCellElement;
+ globalCellElement = gCellElement.cloneNode(false);
+
+ // Tells us whether cell, row, or column is selected
+ try {
+ gSelectedCellsType = gActiveEditor.getSelectedCellsType(gTableElement);
+ } catch (e) {}
+
+ // Ignore types except Cell, Row, and Column
+ if (
+ gSelectedCellsType < SELECT_CELL ||
+ gSelectedCellsType > SELECT_COLUMN
+ ) {
+ gSelectedCellsType = SELECT_CELL;
+ }
+
+ // Be sure at least 1 cell is selected.
+ // (If the count is 0, then we were inside the cell.)
+ if (gSelectedCellCount == 0) {
+ DoCellSelection();
+ }
+
+ // Get location in the cell map
+ var rowIndexObj = { value: 0 };
+ var colIndexObj = { value: 0 };
+ try {
+ gActiveEditor.getCellIndexes(gCellElement, rowIndexObj, colIndexObj);
+ } catch (e) {}
+ gCurRowIndex = rowIndexObj.value;
+ gCurColIndex = colIndexObj.value;
+
+ // We save the current colspan to quickly
+ // move selection from from cell to cell
+ if (GetCellData(gCurRowIndex, gCurColIndex)) {
+ gCurColSpan = gCellData.colSpan;
+ }
+
+ // Starting TabPanel name is passed in
+ if (window.arguments[1] == "CellPanel") {
+ gDialog.TabBox.selectedTab = gDialog.CellTab;
+ }
+ }
+
+ if (gDialog.TabBox.selectedTab == gDialog.TableTab) {
+ // We may call this with table selected, but no cell,
+ // so disable the Cell Properties tab
+ if (!gCellElement) {
+ // XXX: Disabling of tabs is currently broken, so for
+ // now we'll just remove the tab completely.
+ // gDialog.CellTab.disabled = true;
+ gDialog.CellTab.remove();
+ }
+ }
+
+ // Note: we must use gTableElement, not globalTableElement for these,
+ // thus we should not put this in InitDialog.
+ // Instead, monitor desired counts with separate globals
+ var rowCountObj = { value: 0 };
+ var colCountObj = { value: 0 };
+ try {
+ gActiveEditor.getTableSize(gTableElement, rowCountObj, colCountObj);
+ } catch (e) {}
+
+ gRowCount = rowCountObj.value;
+ gLastRowIndex = gRowCount - 1;
+ gColCount = colCountObj.value;
+ gLastColIndex = gColCount - 1;
+
+ // Set appropriate icons and enable state for the Previous/Next buttons
+ SetSelectionButtons();
+
+ // If only one cell in table, disable change-selection widgets
+ if (gRowCount == 1 && gColCount == 1) {
+ gDialog.SelectionList.setAttribute("disabled", "true");
+ }
+
+ // User can change these via textboxes
+ gNewRowCount = gRowCount;
+ gNewColCount = gColCount;
+
+ // This flag is used to control whether set check state
+ // on "set attribute" checkboxes
+ // (Advanced Edit dialog use calls InitDialog when done)
+ gAdvancedEditUsed = false;
+ InitDialog();
+ gAdvancedEditUsed = true;
+
+ // If first initializing, we really aren't changing anything
+ gCellDataChanged = false;
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ // Get Table attributes
+ gDialog.TableRowsInput.value = gRowCount;
+ gDialog.TableColumnsInput.value = gColCount;
+ gDialog.TableWidthInput.value = InitPixelOrPercentMenulist(
+ globalTableElement,
+ gTableElement,
+ "width",
+ "TableWidthUnits",
+ gPercent
+ );
+ if (gUseCSS) {
+ gDialog.TableHeightInput.value = InitPixelOrPercentMenulist(
+ globalTableElement,
+ gTableElement,
+ "height",
+ "TableHeightUnits",
+ gPercent
+ );
+ }
+ gDialog.BorderWidthInput.value = globalTableElement.border;
+ gDialog.SpacingInput.value = globalTableElement.cellSpacing;
+ gDialog.PaddingInput.value = globalTableElement.cellPadding;
+
+ var marginLeft = GetHTMLOrCSSStyleValue(
+ globalTableElement,
+ "align",
+ "margin-left"
+ );
+ var marginRight = GetHTMLOrCSSStyleValue(
+ globalTableElement,
+ "align",
+ "margin-right"
+ );
+ var halign = marginLeft.toLowerCase() + " " + marginRight.toLowerCase();
+ if (halign == "center center" || halign == "auto auto") {
+ gDialog.TableAlignList.value = "center";
+ } else if (halign == "right right" || halign == "auto 0px") {
+ gDialog.TableAlignList.value = "right";
+ } else {
+ // Default is left.
+ gDialog.TableAlignList.value = "left";
+ }
+
+ // Be sure to get caption from table in doc, not the copied "globalTableElement"
+ gTableCaptionElement = gTableElement.caption;
+ if (gTableCaptionElement) {
+ var align = GetHTMLOrCSSStyleValue(
+ gTableCaptionElement,
+ "align",
+ "caption-side"
+ );
+ if (align != "bottom" && align != "left" && align != "right") {
+ align = "top";
+ }
+ gDialog.TableCaptionList.value = align;
+ }
+
+ gTableColor = GetHTMLOrCSSStyleValue(
+ globalTableElement,
+ bgcolor,
+ cssBackgroundColorStr
+ );
+ gTableColor = ConvertRGBColorIntoHEXColor(gTableColor);
+ SetColor("tableBackgroundCW", gTableColor);
+
+ InitCellPanel();
+}
+
+function InitCellPanel() {
+ // Get cell attributes
+ if (globalCellElement) {
+ // This assumes order of items is Cell, Row, Column
+ gDialog.SelectionList.value = gSelectedCellsType;
+
+ var previousValue = gDialog.CellHeightInput.value;
+ gDialog.CellHeightInput.value = InitPixelOrPercentMenulist(
+ globalCellElement,
+ gCellElement,
+ "height",
+ "CellHeightUnits",
+ gPixel
+ );
+ gDialog.CellHeightCheckbox.checked =
+ gAdvancedEditUsed && previousValue != gDialog.CellHeightInput.value;
+
+ previousValue = gDialog.CellWidthInput.value;
+ gDialog.CellWidthInput.value = InitPixelOrPercentMenulist(
+ globalCellElement,
+ gCellElement,
+ "width",
+ "CellWidthUnits",
+ gPixel
+ );
+ gDialog.CellWidthCheckbox.checked =
+ gAdvancedEditUsed && previousValue != gDialog.CellWidthInput.value;
+
+ var previousIndex = gDialog.CellVAlignList.selectedIndex;
+ var valign = GetHTMLOrCSSStyleValue(
+ globalCellElement,
+ "valign",
+ "vertical-align"
+ ).toLowerCase();
+ if (valign == topStr || valign == bottomStr) {
+ gDialog.CellVAlignList.value = valign;
+ } else {
+ // Default is middle.
+ gDialog.CellVAlignList.value = defVAlign;
+ }
+
+ gDialog.CellVAlignCheckbox.checked =
+ gAdvancedEditUsed &&
+ previousIndex != gDialog.CellVAlignList.selectedIndex;
+
+ previousIndex = gDialog.CellHAlignList.selectedIndex;
+
+ gAlignWasChar = false;
+
+ var halign = GetHTMLOrCSSStyleValue(
+ globalCellElement,
+ "align",
+ "text-align"
+ ).toLowerCase();
+ switch (halign) {
+ case centerStr:
+ case rightStr:
+ case justifyStr:
+ gDialog.CellHAlignList.value = halign;
+ break;
+ case charStr:
+ // We don't support UI for this because layout doesn't work: bug 2212.
+ // Remember that's what they had so we don't change it
+ // unless they change the alignment by using the menulist
+ gAlignWasChar = true;
+ // Fall through to use show default alignment in menu
+ default:
+ // Default depends on cell type (TH is "center", TD is "left")
+ gDialog.CellHAlignList.value =
+ globalCellElement.nodeName.toLowerCase() == "th" ? "center" : "left";
+ break;
+ }
+
+ gDialog.CellHAlignCheckbox.checked =
+ gAdvancedEditUsed &&
+ previousIndex != gDialog.CellHAlignList.selectedIndex;
+
+ previousIndex = gDialog.CellStyleList.selectedIndex;
+ gDialog.CellStyleList.value = globalCellElement.nodeName.toLowerCase();
+ gDialog.CellStyleCheckbox.checked =
+ gAdvancedEditUsed && previousIndex != gDialog.CellStyleList.selectedIndex;
+
+ previousIndex = gDialog.TextWrapList.selectedIndex;
+ if (
+ GetHTMLOrCSSStyleValue(globalCellElement, "nowrap", "white-space") ==
+ "nowrap"
+ ) {
+ gDialog.TextWrapList.value = "nowrap";
+ } else {
+ gDialog.TextWrapList.value = "wrap";
+ }
+ gDialog.TextWrapCheckbox.checked =
+ gAdvancedEditUsed && previousIndex != gDialog.TextWrapList.selectedIndex;
+
+ previousValue = gCellColor;
+ gCellColor = GetHTMLOrCSSStyleValue(
+ globalCellElement,
+ bgcolor,
+ cssBackgroundColorStr
+ );
+ gCellColor = ConvertRGBColorIntoHEXColor(gCellColor);
+ SetColor("cellBackgroundCW", gCellColor);
+ gDialog.CellColorCheckbox.checked =
+ gAdvancedEditUsed && previousValue != gCellColor;
+
+ // We want to set this true in case changes came
+ // from Advanced Edit dialog session (must assume something changed)
+ gCellDataChanged = true;
+ }
+}
+
+function GetCellData(rowIndex, colIndex) {
+ // Get actual rowspan and colspan
+ var startRowIndexObj = { value: 0 };
+ var startColIndexObj = { value: 0 };
+ var rowSpanObj = { value: 0 };
+ var colSpanObj = { value: 0 };
+ var actualRowSpanObj = { value: 0 };
+ var actualColSpanObj = { value: 0 };
+ var isSelectedObj = { value: false };
+
+ try {
+ gActiveEditor.getCellDataAt(
+ gTableElement,
+ rowIndex,
+ colIndex,
+ gCellData,
+ startRowIndexObj,
+ startColIndexObj,
+ rowSpanObj,
+ colSpanObj,
+ actualRowSpanObj,
+ actualColSpanObj,
+ isSelectedObj
+ );
+ // We didn't find a cell
+ if (!gCellData.value) {
+ return false;
+ }
+ } catch (ex) {
+ return false;
+ }
+
+ gCellData.startRowIndex = startRowIndexObj.value;
+ gCellData.startColIndex = startColIndexObj.value;
+ gCellData.rowSpan = rowSpanObj.value;
+ gCellData.colSpan = colSpanObj.value;
+ gCellData.actualRowSpan = actualRowSpanObj.value;
+ gCellData.actualColSpan = actualColSpanObj.value;
+ gCellData.isSelected = isSelectedObj.value;
+ return true;
+}
+
+function SelectCellHAlign() {
+ SetCheckbox("CellHAlignCheckbox");
+ // Once user changes the alignment,
+ // we lose their original "CharAt" alignment"
+ gAlignWasChar = false;
+}
+
+function GetColorAndUpdate(ColorWellID) {
+ var colorWell = document.getElementById(ColorWellID);
+ if (!colorWell) {
+ return;
+ }
+
+ var colorObj = {
+ Type: "",
+ TableColor: 0,
+ CellColor: 0,
+ NoDefault: false,
+ Cancel: false,
+ BackgroundColor: 0,
+ };
+
+ switch (ColorWellID) {
+ case "tableBackgroundCW":
+ colorObj.Type = "Table";
+ colorObj.TableColor = gTableColor;
+ break;
+ case "cellBackgroundCW":
+ colorObj.Type = "Cell";
+ colorObj.CellColor = gCellColor;
+ break;
+ }
+ window.openDialog(
+ "chrome://editor/content/EdColorPicker.xhtml",
+ "_blank",
+ "chrome,close,titlebar,modal",
+ "",
+ colorObj
+ );
+
+ // User canceled the dialog
+ if (colorObj.Cancel) {
+ return;
+ }
+
+ switch (ColorWellID) {
+ case "tableBackgroundCW":
+ gTableColor = colorObj.BackgroundColor;
+ SetColor(ColorWellID, gTableColor);
+ break;
+ case "cellBackgroundCW":
+ gCellColor = colorObj.BackgroundColor;
+ SetColor(ColorWellID, gCellColor);
+ SetCheckbox("CellColorCheckbox");
+ break;
+ }
+}
+
+function SetColor(ColorWellID, color) {
+ // Save the color
+ if (ColorWellID == "cellBackgroundCW") {
+ if (color) {
+ try {
+ gActiveEditor.setAttributeOrEquivalent(
+ globalCellElement,
+ bgcolor,
+ color,
+ true
+ );
+ } catch (e) {}
+ gDialog.CellInheritColor.collapsed = true;
+ } else {
+ try {
+ gActiveEditor.removeAttributeOrEquivalent(
+ globalCellElement,
+ bgcolor,
+ true
+ );
+ } catch (e) {}
+ // Reveal addition message explaining "default" color
+ gDialog.CellInheritColor.collapsed = false;
+ }
+ } else {
+ if (color) {
+ try {
+ gActiveEditor.setAttributeOrEquivalent(
+ globalTableElement,
+ bgcolor,
+ color,
+ true
+ );
+ } catch (e) {}
+ gDialog.TableInheritColor.collapsed = true;
+ } else {
+ try {
+ gActiveEditor.removeAttributeOrEquivalent(
+ globalTableElement,
+ bgcolor,
+ true
+ );
+ } catch (e) {}
+ gDialog.TableInheritColor.collapsed = false;
+ }
+ SetCheckbox("CellColorCheckbox");
+ }
+
+ setColorWell(ColorWellID, color);
+}
+
+function ChangeSelectionToFirstCell() {
+ if (!GetCellData(0, 0)) {
+ dump("Can't find first cell in table!\n");
+ return;
+ }
+ gCellElement = gCellData.value;
+ globalCellElement = gCellElement;
+
+ gCurRowIndex = 0;
+ gCurColIndex = 0;
+ ChangeSelection(RESET_SELECTION);
+}
+
+function ChangeSelection(newType) {
+ newType = Number(newType);
+
+ if (gSelectedCellsType == newType) {
+ return;
+ }
+
+ if (newType == RESET_SELECTION) {
+ // Restore selection to existing focus cell
+ gSelection.collapse(gCellElement, 0);
+ } else {
+ gSelectedCellsType = newType;
+ }
+
+ // Keep the same focus gCellElement, just change the type
+ DoCellSelection();
+ SetSelectionButtons();
+
+ // Note: globalCellElement should still be a clone of gCellElement
+}
+
+function MoveSelection(forward) {
+ var newRowIndex = gCurRowIndex;
+ var newColIndex = gCurColIndex;
+ var inRow = false;
+
+ if (gSelectedCellsType == SELECT_ROW) {
+ newRowIndex += forward ? 1 : -1;
+
+ // Wrap around if before first or after last row
+ if (newRowIndex < 0) {
+ newRowIndex = gLastRowIndex;
+ } else if (newRowIndex > gLastRowIndex) {
+ newRowIndex = 0;
+ }
+ inRow = true;
+
+ // Use first cell in row for focus cell
+ newColIndex = 0;
+ } else {
+ // Cell or column:
+ if (!forward) {
+ newColIndex--;
+ }
+
+ if (gSelectedCellsType == SELECT_CELL) {
+ // Skip to next cell
+ if (forward) {
+ newColIndex += gCurColSpan;
+ }
+ } else {
+ // SELECT_COLUMN
+ // Use first cell in column for focus cell
+ newRowIndex = 0;
+
+ // Don't skip by colspan,
+ // but find first cell in next cellmap column
+ if (forward) {
+ newColIndex++;
+ }
+ }
+
+ if (newColIndex < 0) {
+ // Request is before the first cell in column
+
+ // Wrap to last cell in column
+ newColIndex = gLastColIndex;
+
+ if (gSelectedCellsType == SELECT_CELL) {
+ // If moving by cell, also wrap to previous...
+ if (newRowIndex > 0) {
+ newRowIndex -= 1;
+ } else {
+ // ...or the last row.
+ newRowIndex = gLastRowIndex;
+ }
+
+ inRow = true;
+ }
+ } else if (newColIndex > gLastColIndex) {
+ // Request is after the last cell in column
+
+ // Wrap to first cell in column
+ newColIndex = 0;
+
+ if (gSelectedCellsType == SELECT_CELL) {
+ // If moving by cell, also wrap to next...
+ if (newRowIndex < gLastRowIndex) {
+ newRowIndex++;
+ } else {
+ // ...or the first row.
+ newRowIndex = 0;
+ }
+
+ inRow = true;
+ }
+ }
+ }
+
+ // Get the cell at the new location
+ do {
+ if (!GetCellData(newRowIndex, newColIndex)) {
+ dump("MoveSelection: CELL NOT FOUND\n");
+ return;
+ }
+ if (inRow) {
+ if (gCellData.startRowIndex == newRowIndex) {
+ break;
+ } else {
+ // Cell spans from a row above, look for the next cell in row.
+ newRowIndex += gCellData.actualRowSpan;
+ }
+ } else if (gCellData.startColIndex == newColIndex) {
+ break;
+ } else {
+ // Cell spans from a Col above, look for the next cell in column
+ newColIndex += gCellData.actualColSpan;
+ }
+ } while (true);
+
+ // Save data for current selection before changing
+ if (gCellDataChanged) {
+ // && gDialog.ApplyBeforeMove.checked)
+ if (!ValidateCellData()) {
+ return;
+ }
+
+ gActiveEditor.beginTransaction();
+ // Apply changes to all selected cells
+ ApplyCellAttributes();
+ gActiveEditor.endTransaction();
+
+ SetCloseButton();
+ }
+
+ // Set cell and other data for new selection
+ gCellElement = gCellData.value;
+
+ // Save globals for new current cell
+ gCurRowIndex = gCellData.startRowIndex;
+ gCurColIndex = gCellData.startColIndex;
+ gCurColSpan = gCellData.actualColSpan;
+
+ // Copy for new global cell
+ globalCellElement = gCellElement.cloneNode(false);
+
+ // Change the selection
+ DoCellSelection();
+
+ // Scroll page so new selection is visible
+ // Using SELECTION_ANCHOR_REGION makes the upper-left corner of first selected cell
+ // the point to bring into view.
+ try {
+ var selectionController = gActiveEditor.selectionController;
+ selectionController.scrollSelectionIntoView(
+ selectionController.SELECTION_NORMAL,
+ selectionController.SELECTION_ANCHOR_REGION,
+ true
+ );
+ } catch (e) {}
+
+ // Reinitialize dialog using new cell
+ // if (!gDialog.KeepCurrentData.checked)
+ // Setting this false unchecks all "set attributes" checkboxes
+ gAdvancedEditUsed = false;
+ InitCellPanel();
+ gAdvancedEditUsed = true;
+}
+
+function DoCellSelection() {
+ // Collapse selection into to the focus cell
+ // so editor uses that as start cell
+ gSelection.collapse(gCellElement, 0);
+
+ var tagNameObj = { value: "" };
+ var countObj = { value: 0 };
+ try {
+ switch (gSelectedCellsType) {
+ case SELECT_CELL:
+ gActiveEditor.selectTableCell();
+ break;
+ case SELECT_ROW:
+ gActiveEditor.selectTableRow();
+ break;
+ default:
+ gActiveEditor.selectTableColumn();
+ break;
+ }
+ // Get number of cells selected
+ gActiveEditor.getSelectedOrParentTableElement(tagNameObj, countObj);
+ } catch (e) {}
+
+ if (tagNameObj.value == "td") {
+ gSelectedCellCount = countObj.value;
+ } else {
+ gSelectedCellCount = 0;
+ }
+
+ // Currently, we can only allow advanced editing on ONE cell element at a time
+ // else we ignore CSS, JS, and HTML attributes not already in dialog
+ SetElementEnabled(gDialog.AdvancedEditCell, gSelectedCellCount == 1);
+
+ gDialog.AdvancedEditCell.setAttribute(
+ "tooltiptext",
+ gSelectedCellCount > 1
+ ? GetString("AdvancedEditForCellMsg")
+ : gDialog.AdvancedEditCellToolTipText
+ );
+}
+
+function SetSelectionButtons() {
+ if (gSelectedCellsType == SELECT_ROW) {
+ // Trigger CSS to set images of up and down arrows
+ gDialog.PreviousButton.setAttribute("type", "row");
+ gDialog.NextButton.setAttribute("type", "row");
+ } else {
+ // or images of left and right arrows
+ gDialog.PreviousButton.setAttribute("type", "col");
+ gDialog.NextButton.setAttribute("type", "col");
+ }
+ DisableSelectionButtons(
+ (gSelectedCellsType == SELECT_ROW && gRowCount == 1) ||
+ (gSelectedCellsType == SELECT_COLUMN && gColCount == 1) ||
+ (gRowCount == 1 && gColCount == 1)
+ );
+}
+
+function DisableSelectionButtons(disable) {
+ gDialog.PreviousButton.setAttribute("disabled", disable ? "true" : "false");
+ gDialog.NextButton.setAttribute("disabled", disable ? "true" : "false");
+}
+
+function SwitchToValidatePanel() {
+ if (gDialog.TabBox.selectedTab != gValidateTab) {
+ gDialog.TabBox.selectedTab = gValidateTab;
+ }
+}
+
+function SetAlign(listID, defaultValue, element, attName) {
+ var value = document.getElementById(listID).value;
+ if (value == defaultValue) {
+ try {
+ gActiveEditor.removeAttributeOrEquivalent(element, attName, true);
+ } catch (e) {}
+ } else {
+ try {
+ gActiveEditor.setAttributeOrEquivalent(element, attName, value, true);
+ } catch (e) {}
+ }
+}
+
+function ValidateTableData() {
+ gValidateTab = gDialog.TableTab;
+ gNewRowCount = Number(
+ ValidateNumber(gDialog.TableRowsInput, null, 1, gMaxRows, null, true, true)
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ gNewColCount = Number(
+ ValidateNumber(
+ gDialog.TableColumnsInput,
+ null,
+ 1,
+ gMaxColumns,
+ null,
+ true,
+ true
+ )
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ // If user is deleting any cells, get confirmation
+ // (This is a global to the dialog and we ask only once per dialog session)
+ if (!gCanDelete && (gNewRowCount < gRowCount || gNewColCount < gColCount)) {
+ if (
+ ConfirmWithTitle(
+ GetString("DeleteTableTitle"),
+ GetString("DeleteTableMsg"),
+ GetString("DeleteCells")
+ )
+ ) {
+ gCanDelete = true;
+ } else {
+ SetTextboxFocus(
+ gNewRowCount < gRowCount
+ ? gDialog.TableRowsInput
+ : gDialog.TableColumnsInput
+ );
+ return false;
+ }
+ }
+
+ ValidateNumber(
+ gDialog.TableWidthInput,
+ gDialog.TableWidthUnits,
+ 1,
+ gMaxTableSize,
+ globalTableElement,
+ "width"
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ if (gUseCSS) {
+ ValidateNumber(
+ gDialog.TableHeightInput,
+ gDialog.TableHeightUnits,
+ 1,
+ gMaxTableSize,
+ globalTableElement,
+ "height"
+ );
+ if (gValidationError) {
+ return false;
+ }
+ }
+
+ ValidateNumber(
+ gDialog.BorderWidthInput,
+ null,
+ 0,
+ gMaxPixels,
+ globalTableElement,
+ "border"
+ );
+ // TODO: Deal with "BORDER" without value issue
+ if (gValidationError) {
+ return false;
+ }
+
+ ValidateNumber(
+ gDialog.SpacingInput,
+ null,
+ 0,
+ gMaxPixels,
+ globalTableElement,
+ "cellspacing"
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ ValidateNumber(
+ gDialog.PaddingInput,
+ null,
+ 0,
+ gMaxPixels,
+ globalTableElement,
+ "cellpadding"
+ );
+ if (gValidationError) {
+ return false;
+ }
+
+ SetAlign("TableAlignList", defHAlign, globalTableElement, "align");
+
+ // Color is set on globalCellElement immediately
+ return true;
+}
+
+function ValidateCellData() {
+ gValidateTab = gDialog.CellTab;
+
+ if (gDialog.CellHeightCheckbox.checked) {
+ ValidateNumber(
+ gDialog.CellHeightInput,
+ gDialog.CellHeightUnits,
+ 1,
+ gMaxTableSize,
+ globalCellElement,
+ "height"
+ );
+ if (gValidationError) {
+ return false;
+ }
+ }
+
+ if (gDialog.CellWidthCheckbox.checked) {
+ ValidateNumber(
+ gDialog.CellWidthInput,
+ gDialog.CellWidthUnits,
+ 1,
+ gMaxTableSize,
+ globalCellElement,
+ "width"
+ );
+ if (gValidationError) {
+ return false;
+ }
+ }
+
+ if (gDialog.CellHAlignCheckbox.checked) {
+ var hAlign = gDialog.CellHAlignList.value;
+
+ // Horizontal alignment is complicated by "char" type
+ // We don't change current values if user didn't edit alignment
+ if (!gAlignWasChar) {
+ globalCellElement.removeAttribute(charStr);
+
+ // Always set "align" attribute,
+ // so the default "left" is effective in a cell
+ // when parent row has align set.
+ globalCellElement.setAttribute("align", hAlign);
+ }
+ }
+
+ if (gDialog.CellVAlignCheckbox.checked) {
+ // Always set valign (no default in 2nd param) so
+ // the default "middle" is effective in a cell
+ // when parent row has valign set.
+ SetAlign("CellVAlignList", "", globalCellElement, "valign");
+ }
+
+ if (gDialog.TextWrapCheckbox.checked) {
+ if (gDialog.TextWrapList.value == "nowrap") {
+ try {
+ gActiveEditor.setAttributeOrEquivalent(
+ globalCellElement,
+ "nowrap",
+ "nowrap",
+ true
+ );
+ } catch (e) {}
+ } else {
+ try {
+ gActiveEditor.removeAttributeOrEquivalent(
+ globalCellElement,
+ "nowrap",
+ true
+ );
+ } catch (e) {}
+ }
+ }
+
+ return true;
+}
+
+function ValidateData() {
+ var result;
+
+ // Validate current panel first
+ if (gDialog.TabBox.selectedTab == gDialog.TableTab) {
+ result = ValidateTableData();
+ if (result) {
+ result = ValidateCellData();
+ }
+ } else {
+ result = ValidateCellData();
+ if (result) {
+ result = ValidateTableData();
+ }
+ }
+ if (!result) {
+ return false;
+ }
+
+ // Set global element for AdvancedEdit
+ if (gDialog.TabBox.selectedTab == gDialog.TableTab) {
+ globalElement = globalTableElement;
+ } else {
+ globalElement = globalCellElement;
+ }
+
+ return true;
+}
+
+function ChangeCellTextbox(textboxID) {
+ // Filter input for just integers
+ forceInteger(textboxID);
+
+ if (gDialog.TabBox.selectedTab == gDialog.CellTab) {
+ gCellDataChanged = true;
+ }
+}
+
+// Call this when a textbox or menulist is changed
+// so the checkbox is automatically set
+function SetCheckbox(checkboxID) {
+ if (checkboxID && checkboxID.length > 0) {
+ // Set associated checkbox
+ document.getElementById(checkboxID).checked = true;
+ }
+ gCellDataChanged = true;
+}
+
+function ChangeIntTextbox(textboxID, checkboxID) {
+ // Filter input for just integers
+ forceInteger(textboxID);
+
+ // Set associated checkbox
+ SetCheckbox(checkboxID);
+}
+
+function CloneAttribute(destElement, srcElement, attr) {
+ var value = srcElement.getAttribute(attr);
+ // Use editor methods since we are always
+ // modifying a table in the document and
+ // we need transaction system for undo
+ try {
+ if (!value || value.length == 0) {
+ gActiveEditor.removeAttributeOrEquivalent(destElement, attr, false);
+ } else {
+ gActiveEditor.setAttributeOrEquivalent(destElement, attr, value, false);
+ }
+ } catch (e) {}
+}
+
+/* eslint-disable complexity */
+function ApplyTableAttributes() {
+ var newAlign = gDialog.TableCaptionList.value;
+ if (!newAlign) {
+ newAlign = "";
+ }
+
+ if (gTableCaptionElement) {
+ // Get current alignment
+ var align = GetHTMLOrCSSStyleValue(
+ gTableCaptionElement,
+ "align",
+ "caption-side"
+ ).toLowerCase();
+ // This is the default
+ if (!align) {
+ align = "top";
+ }
+
+ if (newAlign == "") {
+ // Remove existing caption
+ try {
+ gActiveEditor.deleteNode(gTableCaptionElement);
+ } catch (e) {}
+ gTableCaptionElement = null;
+ } else if (newAlign != align) {
+ try {
+ if (newAlign == "top") {
+ // This is default, so don't explicitly set it
+ gActiveEditor.removeAttributeOrEquivalent(
+ gTableCaptionElement,
+ "align",
+ false
+ );
+ } else {
+ gActiveEditor.setAttributeOrEquivalent(
+ gTableCaptionElement,
+ "align",
+ newAlign,
+ false
+ );
+ }
+ } catch (e) {}
+ }
+ } else if (newAlign != "") {
+ // Create and insert a caption:
+ try {
+ gTableCaptionElement = gActiveEditor.createElementWithDefaults("caption");
+ } catch (e) {}
+ if (gTableCaptionElement) {
+ if (newAlign != "top") {
+ gTableCaptionElement.setAttribute("align", newAlign);
+ }
+
+ // Insert it into the table - caption is always inserted as first child
+ try {
+ gActiveEditor.insertNode(gTableCaptionElement, gTableElement, 0);
+ } catch (e) {}
+
+ // Put selection back where it was
+ ChangeSelection(RESET_SELECTION);
+ }
+ }
+
+ var countDelta;
+ var foundCell;
+ var i;
+
+ if (gNewRowCount != gRowCount) {
+ countDelta = gNewRowCount - gRowCount;
+ if (gNewRowCount > gRowCount) {
+ // Append new rows
+ // Find first cell in last row
+ if (GetCellData(gLastRowIndex, 0)) {
+ try {
+ // Move selection to the last cell
+ gSelection.collapse(gCellData.value, 0);
+ // Insert new rows after it
+ gActiveEditor.insertTableRow(countDelta, true);
+ gRowCount = gNewRowCount;
+ gLastRowIndex = gRowCount - 1;
+ // Put selection back where it was
+ ChangeSelection(RESET_SELECTION);
+ } catch (ex) {
+ dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
+ }
+ }
+ } else if (gCanDelete) {
+ // Delete rows
+ // Find first cell starting in first row we delete
+ var firstDeleteRow = gRowCount + countDelta;
+ foundCell = false;
+ for (i = 0; i <= gLastColIndex; i++) {
+ if (!GetCellData(firstDeleteRow, i)) {
+ // We failed to find a cell.
+ break;
+ }
+
+ if (gCellData.startRowIndex == firstDeleteRow) {
+ foundCell = true;
+ break;
+ }
+ }
+ if (foundCell) {
+ try {
+ // Move selection to the cell we found
+ gSelection.collapse(gCellData.value, 0);
+ gActiveEditor.deleteTableRow(-countDelta);
+ gRowCount = gNewRowCount;
+ gLastRowIndex = gRowCount - 1;
+ if (gCurRowIndex > gLastRowIndex) {
+ // We are deleting our selection
+ // move it to start of table
+ ChangeSelectionToFirstCell();
+ } else {
+ // Put selection back where it was.
+ ChangeSelection(RESET_SELECTION);
+ }
+ } catch (ex) {
+ dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
+ }
+ }
+ }
+ }
+
+ if (gNewColCount != gColCount) {
+ countDelta = gNewColCount - gColCount;
+
+ if (gNewColCount > gColCount) {
+ // Append new columns
+ // Find last cell in first column
+ if (GetCellData(0, gLastColIndex)) {
+ try {
+ // Move selection to the last cell
+ gSelection.collapse(gCellData.value, 0);
+ gActiveEditor.insertTableColumn(countDelta, true);
+ gColCount = gNewColCount;
+ gLastColIndex = gColCount - 1;
+ // Restore selection
+ ChangeSelection(RESET_SELECTION);
+ } catch (ex) {
+ dump("FAILED TO FIND FIRST CELL IN LAST COLUMN\n");
+ }
+ }
+ } else if (gCanDelete) {
+ // Delete columns
+ var firstDeleteCol = gColCount + countDelta;
+ foundCell = false;
+ for (i = 0; i <= gLastRowIndex; i++) {
+ // Find first cell starting in first column we delete
+ if (!GetCellData(i, firstDeleteCol)) {
+ // We failed to find a cell.
+ break;
+ }
+
+ if (gCellData.startColIndex == firstDeleteCol) {
+ foundCell = true;
+ break;
+ }
+ }
+ if (foundCell) {
+ try {
+ // Move selection to the cell we found
+ gSelection.collapse(gCellData.value, 0);
+ gActiveEditor.deleteTableColumn(-countDelta);
+ gColCount = gNewColCount;
+ gLastColIndex = gColCount - 1;
+ if (gCurColIndex > gLastColIndex) {
+ ChangeSelectionToFirstCell();
+ } else {
+ ChangeSelection(RESET_SELECTION);
+ }
+ } catch (ex) {
+ dump("FAILED TO FIND FIRST CELL IN LAST ROW\n");
+ }
+ }
+ }
+ }
+
+ // Clone all remaining attributes to pick up
+ // anything changed by Advanced Edit Dialog
+ try {
+ gActiveEditor.cloneAttributes(gTableElement, globalTableElement);
+ } catch (e) {}
+}
+/* eslint-enable complexity */
+
+function ApplyCellAttributes() {
+ var rangeObj = { value: null };
+ var selectedCell;
+ try {
+ selectedCell = gActiveEditor.getFirstSelectedCell(rangeObj);
+ } catch (e) {}
+
+ if (!selectedCell) {
+ return;
+ }
+
+ if (gSelectedCellCount == 1) {
+ // When only one cell is selected, simply clone entire element,
+ // thus CSS and JS from Advanced edit is copied
+ try {
+ gActiveEditor.cloneAttributes(selectedCell, globalCellElement);
+ } catch (e) {}
+
+ if (gDialog.CellStyleCheckbox.checked) {
+ var currentStyleIndex =
+ selectedCell.nodeName.toLowerCase() == "th" ? 1 : 0;
+ if (gDialog.CellStyleList.selectedIndex != currentStyleIndex) {
+ // Switch cell types
+ // (replaces with new cell and copies attributes and contents)
+ try {
+ selectedCell = gActiveEditor.switchTableCellHeaderType(selectedCell);
+ } catch (e) {}
+ }
+ }
+ } else {
+ // Apply changes to all selected cells
+ // XXX THIS DOESN'T COPY ADVANCED EDIT CHANGES!
+ try {
+ while (selectedCell) {
+ ApplyAttributesToOneCell(selectedCell);
+ selectedCell = gActiveEditor.getNextSelectedCell(rangeObj);
+ }
+ } catch (e) {}
+ }
+ gCellDataChanged = false;
+}
+
+function ApplyAttributesToOneCell(destElement) {
+ if (gDialog.CellHeightCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "height");
+ }
+
+ if (gDialog.CellWidthCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "width");
+ }
+
+ if (gDialog.CellHAlignCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "align");
+ CloneAttribute(destElement, globalCellElement, charStr);
+ }
+
+ if (gDialog.CellVAlignCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "valign");
+ }
+
+ if (gDialog.TextWrapCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "nowrap");
+ }
+
+ if (gDialog.CellStyleCheckbox.checked) {
+ var newStyleIndex = gDialog.CellStyleList.selectedIndex;
+ var currentStyleIndex = destElement.nodeName.toLowerCase() == "th" ? 1 : 0;
+
+ if (newStyleIndex != currentStyleIndex) {
+ // Switch cell types
+ // (replaces with new cell and copies attributes and contents)
+ try {
+ destElement = gActiveEditor.switchTableCellHeaderType(destElement);
+ } catch (e) {}
+ }
+ }
+
+ if (gDialog.CellColorCheckbox.checked) {
+ CloneAttribute(destElement, globalCellElement, "bgcolor");
+ }
+}
+
+function SetCloseButton() {
+ // Change text on "Cancel" button after Apply is used
+ if (!gApplyUsed) {
+ document.documentElement.setAttribute(
+ "buttonlabelcancel",
+ document.documentElement.getAttribute("buttonlabelclose")
+ );
+ gApplyUsed = true;
+ }
+}
+
+function Apply() {
+ if (ValidateData()) {
+ gActiveEditor.beginTransaction();
+
+ ApplyTableAttributes();
+
+ // We may have just a table, so check for cell element
+ if (globalCellElement) {
+ ApplyCellAttributes();
+ }
+
+ gActiveEditor.endTransaction();
+
+ SetCloseButton();
+ return true;
+ }
+ return false;
+}
+
+function onAccept(event) {
+ // Do same as Apply and close window if ValidateData succeeded
+ var retVal = Apply();
+ if (retVal) {
+ SaveWindowLocation();
+ } else {
+ event.preventDefault();
+ }
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdTableProps.xhtml b/comm/suite/editor/components/dialogs/content/EdTableProps.xhtml
new file mode 100644
index 0000000000..30979acb4d
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdTableProps.xhtml
@@ -0,0 +1,287 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edTableProperties SYSTEM "chrome://editor/locale/EditorTableProperties.dtd">
+%edTableProperties;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&tableWindow.title;"
+ id="tableDlg"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()"
+ buttons="accept,extra1,cancel"
+ buttonlabelclose="&closeButton.label;"
+ buttonlabelextra1="&applyButton.label;"
+ buttonaccesskeyextra1="&applyButton.accesskey;">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdTableProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <tabbox id="TabBox">
+ <tabs flex="1">
+ <tab id="TableTab" label="&tableTab.label;"/>
+ <tab id="CellTab" label="&cellTab.label;"/>
+ </tabs>
+ <tabpanels>
+
+ <!-- TABLE PANEL -->
+ <vbox>
+ <groupbox orient="horizontal">
+ <hbox class="groupbox-title">
+ <label class="header">&size.label;</label>
+ </hbox>
+ <grid>
+ <columns><column/><column/><column/><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <label value="&tableRows.label;" accesskey="&tableRows.accessKey;" control="TableRowsInput"/>
+ <textbox class="narrow" id="TableRowsInput" oninput="forceInteger(this.id);"/>
+ <spring class="bigspacer"/>
+ <label value="&tableHeight.label;" accesskey="&tableHeight.accessKey;"
+ id="TableHeightLabel" control="TableHeightInput"/>
+ <textbox class="narrow" id="TableHeightInput" oninput="forceInteger(this.id);"/>
+ <menulist id="TableHeightUnits"/>
+ </row>
+ <row align="center">
+ <label value="&tableColumns.label;" accesskey="&tableColumns.accessKey;" control="TableColumnsInput"/>
+ <textbox class="narrow" id="TableColumnsInput" oninput="forceInteger(this.id);"/>
+ <spring class="bigspacer"/>
+ <label value="&tableWidth.label;" accesskey="&tableWidth.accessKey;" control="TableWidthInput"/>
+ <textbox class="narrow" id="TableWidthInput" oninput="forceInteger(this.id);"/>
+ <menulist id="TableWidthUnits"/>
+ </row>
+ </rows>
+ <!-- KEEP GRID LAYOUT here since we will be adding back support for table HEIGHT via CSS -->
+ </grid>
+ </groupbox>
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&tableBorderSpacing.label;</label>
+ </hbox>
+ <grid>
+ <columns><column/><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <label control="BorderWidthInput"
+ value="&tableBorderWidth.label;"
+ accesskey="&tableBorderWidth.accessKey;"/>
+ <textbox class="narrow" id="BorderWidthInput" oninput="forceInteger(this.id);"/>
+ <label align="left" value="&pixels.label;"/>
+ </row>
+ <row align="center">
+ <label control="SpacingInput"
+ value="&tableSpacing.label;"
+ accesskey="&tableSpacing.accessKey;"/>
+ <textbox class="narrow" id="SpacingInput" oninput="forceInteger(this.id);"/>
+ <label value="&tablePxBetwCells.label;"/>
+ </row>
+ <row align="center">
+ <label control="PaddingInput"
+ value="&tablePadding.label;"
+ accesskey="&tablePadding.accessKey;"/>
+ <textbox class="narrow" id="PaddingInput" oninput="forceInteger(this.id);"/>
+ <label value="&tablePxBetwBrdrCellContent.label;"/>
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+ <!-- Table Alignment and Caption -->
+ <hbox flex="1" align="center">
+ <label control="TableAlignList"
+ value="&tableAlignment.label;"
+ accesskey="&tableAlignment.accessKey;"/>
+ <menulist id="TableAlignList">
+ <menupopup>
+ <menuitem label="&AlignLeft.label;" value="left"/>
+ <menuitem label="&AlignCenter.label;" value="center"/>
+ <menuitem label="&AlignRight.label;" value="right"/>
+ </menupopup>
+ </menulist>
+ <spacer class="spacer"/>
+ <label control="TableCaptionList"
+ value="&tableCaption.label;"
+ accesskey="&tableCaption.accessKey;"/>
+ <menulist id="TableCaptionList">
+ <menupopup>
+ <menuitem label="&tableCaptionNone.label;" value=""/>
+ <menuitem label="&tableCaptionAbove.label;" value="top"/>
+ <menuitem label="&tableCaptionBelow.label;" value="bottom"/>
+ <menuitem label="&tableCaptionLeft.label;" value="left"/>
+ <menuitem label="&tableCaptionRight.label;" value="right"/>
+ </menupopup>
+ </menulist>
+ </hbox>
+ <separator class="groove"/>
+ <hbox align="center">
+ <label value="&backgroundColor.label;"/>
+ <button id="tableBackground" class="color-button" oncommand="GetColorAndUpdate('tableBackgroundCW');">
+ <spacer id="tableBackgroundCW" class="color-well"/>
+ </button>
+ <spacer class="spacer"/>
+ <label id="TableInheritColor" value="&tableInheritColor.label;" collapsed="true"/>
+ </hbox>
+ <separator class="groove"/>
+ <hbox flex="1" align="center">
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton"
+ oncommand="onAdvancedEdit();"
+ label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;"
+ tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <spacer flex="1"/>
+ </vbox><!-- Table Panel -->
+
+ <!-- CELL PANEL -->
+ <vbox>
+ <groupbox orient="horizontal" align="center">
+ <hbox class="groupbox-title">
+ <label class="header">&cellSelection.label;</label>
+ </hbox>
+ <vbox>
+ <menulist id="SelectionList" oncommand="ChangeSelection(event.target.value)" flex="1">
+ <menupopup>
+ <!-- JS code assumes order is Cell, Row, Column -->
+ <menuitem label="&cellSelectCell.label;" value="1"/>
+ <menuitem label="&cellSelectRow.label;" value="2"/>
+ <menuitem label="&cellSelectColumn.label;" value="3"/>
+ </menupopup>
+ </menulist>
+ <hbox flex="1">
+ <button id="PreviousButton"
+ oncommand="MoveSelection(0)"
+ flex="1"
+ align="center">
+ <image/>
+ <label value="&cellSelectPrevious.label;"
+ accesskey="&cellSelectPrevious.accessKey;"
+ control="PreviousButton"/>
+ </button>
+ <button id="NextButton"
+ oncommand="MoveSelection(1)"
+ class="align-right"
+ flex="1"
+ align="center">
+ <image/>
+ <label value="&cellSelectNext.label;"
+ accesskey="&cellSelectNext.accessKey;"
+ control="NextButton"/>
+ </button>
+ </hbox>
+ </vbox>
+ <spacer class="bigspacer"/>
+ <description class="wrap" flex="1">&applyBeforeChange.label;</description>
+ </groupbox>
+ <hbox align="center">
+ <!-- cell size groupbox -->
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&size.label;</label>
+ </hbox>
+ <grid>
+ <columns><column/><column/><column flex="1"/></columns>
+ <rows>
+ <row align="center">
+ <checkbox id="CellHeightCheckbox" label="&tableHeight.label;" accesskey="&tableHeight.accessKey;"/>
+ <textbox class="narrow" id="CellHeightInput"
+ oninput="ChangeIntTextbox(this.id, 'CellHeightCheckbox');"/>
+ <menulist id="CellHeightUnits" oncommand="SetCheckbox('CellHeightCheckbox');"/>
+ </row>
+ <row align="center">
+ <checkbox id="CellWidthCheckbox" label="&tableWidth.label;" accesskey="&tableWidth.accessKey;"/>
+ <textbox class="narrow" id="CellWidthInput"
+ oninput="ChangeIntTextbox(this.id, 'CellWidthCheckbox');"/>
+ <menulist id="CellWidthUnits" oncommand="SetCheckbox('CellWidthCheckbox');"/>
+ </row>
+ </rows>
+ </grid>
+ <spacer class="bigspacer"/>
+ </groupbox>
+ <!-- Alignment -->
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&cellContentAlignment.label;</label>
+ </hbox>
+ <grid>
+ <columns><column/><column flex="1"/><column/></columns>
+ <rows>
+ <row align="center">
+ <checkbox id="CellVAlignCheckbox" label="&cellVertical.label;" accesskey="&cellVertical.accessKey;"/>
+ <menulist id="CellVAlignList" oncommand="SetCheckbox('CellVAlignCheckbox');">
+ <menupopup>
+ <menuitem label="&cellAlignTop.label;" value="top"/>
+ <menuitem label="&cellAlignMiddle.label;" value="middle"/>
+ <menuitem label="&cellAlignBottom.label;" value="bottom"/>
+ </menupopup>
+ </menulist>
+ </row>
+ <row align="center">
+ <checkbox id="CellHAlignCheckbox" label="&cellHorizontal.label;" accesskey="&cellHorizontal.accessKey;"/>
+ <menulist id="CellHAlignList" oncommand="SelectCellHAlign()">
+ <menupopup>
+ <menuitem label="&AlignLeft.label;" value="left"/>
+ <menuitem label="&AlignCenter.label;" value="center"/>
+ <menuitem label="&AlignRight.label;" value="right"/>
+ <menuitem label="&cellAlignJustify.label;" value="justify"/>
+ </menupopup>
+ </menulist>
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+ </hbox>
+ <spacer class="spacer"/>
+ <hbox align="center">
+ <checkbox id="CellStyleCheckbox" label="&cellStyle.label;" accesskey="&cellStyle.accessKey;"/>
+ <menulist id="CellStyleList" oncommand="SetCheckbox('CellStyleCheckbox');">
+ <menupopup>
+ <menuitem label="&cellNormal.label;" value="td"/>
+ <menuitem label="&cellHeader.label;" value="th"/>
+ </menupopup>
+ </menulist>
+ <spacer class="bigspacer"/>
+ <checkbox id="TextWrapCheckbox" label="&cellTextWrap.label;" accesskey="&cellTextWrap.accessKey;"/>
+ <menulist id="TextWrapList" oncommand="SetCheckbox('TextWrapCheckbox');">
+ <menupopup>
+ <menuitem label="&cellWrap.label;" value="wrap"/>
+ <menuitem label="&cellNoWrap.label;" value="nowrap"/>
+ </menupopup>
+ </menulist>
+ </hbox>
+ <separator class="groove"/>
+ <hbox align="center">
+ <checkbox id="CellColorCheckbox" label="&backgroundColor.label;" accesskey="&backgroundColor.accessKey;"/>
+ <button class="color-button" oncommand="GetColorAndUpdate('cellBackgroundCW');">
+ <spacer id="cellBackgroundCW" class="color-well"/>
+ </button>
+ <spacer class="spacer"/>
+ <label id="CellInheritColor" value="&cellInheritColor.label;" collapsed="true"/>
+ </hbox>
+ <separator class="groove"/>
+ <hbox align="center">
+ <description class="wrap" flex="1" style="width: 1em">&cellUseCheckboxHelp.label;</description>
+ <button id="AdvancedEditButton2"
+ oncommand="onAdvancedEdit()"
+ label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;"
+ tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <spacer flex="1"/>
+ </vbox><!-- Cell Panel -->
+ </tabpanels>
+ </tabbox>
+ <spacer class="spacer"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EdTextAreaProps.js b/comm/suite/editor/components/dialogs/content/EdTextAreaProps.js
new file mode 100644
index 0000000000..da33ab60c9
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdTextAreaProps.js
@@ -0,0 +1,171 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../composer/content/editorUtilities.js */
+/* import-globals-from EdDialogCommon.js */
+
+var insertNew;
+var textareaElement;
+
+// dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup() {
+ var editor = GetCurrentEditor();
+ if (!editor) {
+ dump("Failed to get active editor!\n");
+ window.close();
+ return;
+ }
+
+ gDialog = {
+ accept: document.documentElement.getButton("accept"),
+ textareaName: document.getElementById("TextAreaName"),
+ textareaRows: document.getElementById("TextAreaRows"),
+ textareaCols: document.getElementById("TextAreaCols"),
+ textareaWrap: document.getElementById("TextAreaWrap"),
+ textareaReadOnly: document.getElementById("TextAreaReadOnly"),
+ textareaDisabled: document.getElementById("TextAreaDisabled"),
+ textareaTabIndex: document.getElementById("TextAreaTabIndex"),
+ textareaAccessKey: document.getElementById("TextAreaAccessKey"),
+ textareaValue: document.getElementById("TextAreaValue"),
+ MoreSection: document.getElementById("MoreSection"),
+ MoreFewerButton: document.getElementById("MoreFewerButton"),
+ };
+
+ // Get a single selected text area element
+ const kTagName = "textarea";
+ try {
+ textareaElement = editor.getSelectedElement(kTagName);
+ } catch (e) {}
+
+ if (textareaElement) {
+ // We found an element and don't need to insert one
+ insertNew = false;
+
+ gDialog.textareaValue.value = textareaElement.value;
+ } else {
+ insertNew = true;
+
+ // We don't have an element selected,
+ // so create one with default attributes
+ try {
+ textareaElement = editor.createElementWithDefaults(kTagName);
+ } catch (e) {}
+
+ if (!textareaElement) {
+ dump("Failed to get selected element or create a new one!\n");
+ window.close();
+ return;
+ }
+ gDialog.textareaValue.value = GetSelectionAsText();
+ }
+
+ // Make a copy to use for AdvancedEdit
+ globalElement = textareaElement.cloneNode(false);
+
+ InitDialog();
+
+ InitMoreFewer();
+
+ SetTextboxFocus(gDialog.textareaName);
+
+ SetWindowLocation();
+}
+
+function InitDialog() {
+ gDialog.textareaName.value = globalElement.getAttribute("name");
+ gDialog.textareaRows.value = globalElement.getAttribute("rows");
+ gDialog.textareaCols.value = globalElement.getAttribute("cols");
+ gDialog.textareaWrap.value = GetHTMLOrCSSStyleValue(
+ globalElement,
+ "wrap",
+ "white-space"
+ );
+ gDialog.textareaReadOnly.checked = globalElement.hasAttribute("readonly");
+ gDialog.textareaDisabled.checked = globalElement.hasAttribute("disabled");
+ gDialog.textareaTabIndex.value = globalElement.getAttribute("tabindex");
+ gDialog.textareaAccessKey.value = globalElement.getAttribute("accesskey");
+ onInput();
+}
+
+function onInput() {
+ var disabled =
+ !gDialog.textareaName.value ||
+ !gDialog.textareaRows.value ||
+ !gDialog.textareaCols.value;
+ if (gDialog.accept.disabled != disabled) {
+ gDialog.accept.disabled = disabled;
+ }
+}
+
+function ValidateData() {
+ var attributes = {
+ name: gDialog.textareaName.value,
+ rows: gDialog.textareaRows.value,
+ cols: gDialog.textareaCols.value,
+ wrap: gDialog.textareaWrap.value,
+ tabindex: gDialog.textareaTabIndex.value,
+ accesskey: gDialog.textareaAccessKey.value,
+ };
+ var flags = {
+ readonly: gDialog.textareaReadOnly.checked,
+ disabled: gDialog.textareaDisabled.checked,
+ };
+ for (var a in attributes) {
+ if (attributes[a]) {
+ globalElement.setAttribute(a, attributes[a]);
+ } else {
+ globalElement.removeAttribute(a);
+ }
+ }
+ for (var f in flags) {
+ if (flags[f]) {
+ globalElement.setAttribute(f, "");
+ } else {
+ globalElement.removeAttribute(f);
+ }
+ }
+ return true;
+}
+
+function onAccept() {
+ // All values are valid - copy to actual element in doc or
+ // element created to insert
+ ValidateData();
+
+ var editor = GetCurrentEditor();
+
+ editor.beginTransaction();
+
+ try {
+ editor.cloneAttributes(textareaElement, globalElement);
+
+ if (insertNew) {
+ editor.insertElementAtSelection(textareaElement, true);
+ }
+
+ // undoably set value
+ var initialText = gDialog.textareaValue.value;
+ if (initialText != textareaElement.value) {
+ editor.setShouldTxnSetSelection(false);
+
+ while (textareaElement.hasChildNodes()) {
+ editor.deleteNode(textareaElement.lastChild);
+ }
+ if (initialText) {
+ var textNode = editor.document.createTextNode(initialText);
+ editor.insertNode(textNode, textareaElement, 0);
+ }
+
+ editor.setShouldTxnSetSelection(true);
+ }
+ } finally {
+ editor.endTransaction();
+ }
+
+ SaveWindowLocation();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EdTextAreaProps.xhtml b/comm/suite/editor/components/dialogs/content/EdTextAreaProps.xhtml
new file mode 100644
index 0000000000..9ab91664e8
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EdTextAreaProps.xhtml
@@ -0,0 +1,115 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % edTextAreaProperties SYSTEM "chrome://editor/locale/EditorTextAreaProperties.dtd">
+%edTextAreaProperties;
+<!ENTITY % edDialogOverlay SYSTEM "chrome://editor/locale/EdDialogOverlay.dtd">
+%edDialogOverlay;
+]>
+
+<dialog title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup();"
+ buttons="accept,cancel">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EdTextAreaProps.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&Settings.label;</label>
+ </hbox>
+ <grid><columns><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <label control="TextAreaName" value="&TextAreaName.label;" accesskey="&TextAreaName.accessKey;"/>
+ <textbox id="TextAreaName" oninput="onInput();"/>
+ </row>
+ <row align="center">
+ <label control="TextAreaRows" value="&TextAreaRows.label;" accesskey="&TextAreaRows.accessKey;"/>
+ <hbox>
+ <textbox id="TextAreaRows" class="narrow" oninput="forceInteger(this.id); onInput();"/>
+ </hbox>
+ </row>
+ <row align="center">
+ <label control="TextAreaCols" value="&TextAreaCols.label;" accesskey="&TextAreaCols.accessKey;"/>
+ <hbox>
+ <textbox id="TextAreaCols" class="narrow" oninput="forceInteger(this.id); onInput();"/>
+ </hbox>
+ </row>
+ </rows>
+ </grid>
+ <hbox>
+ <button id="MoreFewerButton" oncommand="onMoreFewer();" persist="more"/>
+ </hbox>
+ <grid id="MoreSection"><columns><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <label control="TextAreaWrap" value="&TextAreaWrap.label;" accesskey="&TextAreaWrap.accessKey;"/>
+ <menulist id="TextAreaWrap">
+ <menupopup>
+ <menuitem label="&WrapDefault.value;"/>
+ <menuitem label="&WrapOff.value;" value="off"/>
+ <menuseparator/>
+ <menuitem label="&WrapSoft.value;" value="soft"/>
+ <menuitem label="&WrapHard.value;" value="hard"/>
+ <menuseparator/>
+ <menuitem label="&WrapPhysical.value;" value="physical"/>
+ <menuitem label="&WrapVirtual.value;" value="virtual"/>
+ <menuseparator/>
+ <menuitem label="normal" value="normal"/>
+ <menuitem label="nowrap" value="nowrap"/>
+ <menuitem label="pre" value="pre"/>
+ </menupopup>
+ </menulist>
+ </row>
+ <row>
+ <spacer/>
+ <checkbox id="TextAreaReadOnly" label="&TextAreaReadOnly.label;" accesskey="&TextAreaReadOnly.accessKey;"/>
+ </row>
+ <row>
+ <spacer/>
+ <checkbox id="TextAreaDisabled" label="&TextAreaDisabled.label;" accesskey="&TextAreaDisabled.accessKey;"/>
+ </row>
+ <row align="center">
+ <label control="TextAreaTabIndex" value="&TextAreaTabIndex.label;" accesskey="&TextAreaTabIndex.accessKey;"/>
+ <hbox>
+ <textbox id="TextAreaTabIndex" class="narrow" oninput="forceInteger(this.id);"/>
+ </hbox>
+ </row>
+ <row align="center">
+ <label control="TextAreaAccessKey" value="&TextAreaAccessKey.label;" accesskey="&TextAreaAccessKey.accessKey;"/>
+ <hbox>
+ <textbox id="TextAreaAccessKey" class="narrow" maxlength="1"/>
+ </hbox>
+ </row>
+ <row>
+ <label control="TextAreaValue" value="&InitialText.label;" accesskey="&InitialText.accessKey;"/>
+ </row>
+ <html:textarea id="TextAreaValue" flex="1" rows="5"/>
+ </rows>
+ </grid>
+ </groupbox>
+
+ <vbox id="AdvancedEdit">
+ <hbox flex="1" style="margin-top: 0.2em" align="center">
+ <!-- This will right-align the button -->
+ <spacer flex="1"/>
+ <button id="AdvancedEditButton1" oncommand="onAdvancedEdit()" label="&AdvancedEditButton.label;"
+ accesskey="&AdvancedEditButton.accessKey;" tooltiptext="&AdvancedEditButton.tooltip;"/>
+ </hbox>
+ <separator id="advancedSeparator" class="groove"/>
+ </vbox>
+
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EditConflict.js b/comm/suite/editor/components/dialogs/content/EditConflict.js
new file mode 100644
index 0000000000..28611796cd
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EditConflict.js
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// dialog initialization code
+
+document.addEventListener("dialogcancel", onClose);
+
+function Startup()
+{
+ if (!GetCurrentEditor())
+ {
+ window.close();
+ return;
+ }
+
+ SetWindowLocation();
+}
+
+function KeepCurrentPage()
+{
+ // Simply close dialog and don't change current page
+ //TODO: Should we force saving of the current page?
+ SaveWindowLocation();
+ return true;
+}
+
+function UseOtherPage()
+{
+ // Reload the URL -- that will get other editor's contents
+ window.opener.setTimeout(window.opener.EditorLoadUrl, 0, GetDocumentUrl());
+ SaveWindowLocation();
+ return true;
+}
+
+function PreventCancel()
+{
+ SaveWindowLocation();
+
+ // Don't let Esc key close the dialog!
+ return false;
+}
diff --git a/comm/suite/editor/components/dialogs/content/EditConflict.xhtml b/comm/suite/editor/components/dialogs/content/EditConflict.xhtml
new file mode 100644
index 0000000000..fce32792d2
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EditConflict.xhtml
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditConflict.dtd">
+
+<dialog buttons="cancel" title="&windowTitle.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EditConflict.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <label value ="&conflictWarning.label;"/>
+ <spacer class="bigspacer"/>
+ <label value ="&conflictResolve.label;"/>
+ <spacer class="bigspacer"/>
+ <hbox flex="1">
+ <spacer class="bigspacer"/>
+ <button label="&keepCurrentPageButton.label;"
+ oncommand="KeepCurrentPage()"/>
+ <spacer class="bigspacer"/>
+ </hbox>
+ <hbox flex="1">
+ <spacer class="bigspacer"/>
+ <button dlgtype="cancel"
+ label="&useOtherPageButton.label;"
+ oncommand="UseOtherPage()"/>
+ <spacer class="bigspacer"/>
+ </hbox>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EditorPublish.js b/comm/suite/editor/components/dialogs/content/EditorPublish.js
new file mode 100644
index 0000000000..6947a439ee
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EditorPublish.js
@@ -0,0 +1,558 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var gPublishSiteData;
+var gReturnData;
+var gDefaultSiteIndex = -1;
+var gDefaultSiteName;
+var gPreviousDefaultDir;
+var gPreviousTitle;
+var gSettingsChanged = false;
+var gInitialSiteName;
+var gInitialSiteIndex = -1;
+var gPasswordManagerOn = true;
+
+// Dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup()
+{
+ window.opener.ok = false;
+
+ // Element to edit is passed in
+ gInitialSiteName = window.arguments[1];
+ gReturnData = window.arguments[2];
+ if (!gReturnData || !GetCurrentEditor())
+ {
+ dump("Publish: No editor or return data object not supplied\n");
+ window.close();
+ return;
+ }
+
+ gDialog.TabBox = document.getElementById("TabBox");
+ gDialog.PublishTab = document.getElementById("PublishTab");
+ gDialog.SettingsTab = document.getElementById("SettingsTab");
+
+ // Publish panel
+ gDialog.PageTitleInput = document.getElementById("PageTitleInput");
+ gDialog.FilenameInput = document.getElementById("FilenameInput");
+ gDialog.SiteList = document.getElementById("SiteList");
+ gDialog.DocDirList = document.getElementById("DocDirList");
+ gDialog.OtherDirCheckbox = document.getElementById("OtherDirCheckbox");
+ gDialog.OtherDirRadiogroup = document.getElementById("OtherDirRadiogroup");
+ gDialog.SameLocationRadio = document.getElementById("SameLocationRadio");
+ gDialog.UseSubdirRadio = document.getElementById("UseSubdirRadio");
+ gDialog.OtherDirList = document.getElementById("OtherDirList");
+
+ // Settings Panel
+ gDialog.SiteNameInput = document.getElementById("SiteNameInput");
+ gDialog.PublishUrlInput = document.getElementById("PublishUrlInput");
+ gDialog.BrowseUrlInput = document.getElementById("BrowseUrlInput");
+ gDialog.UsernameInput = document.getElementById("UsernameInput");
+ gDialog.PasswordInput = document.getElementById("PasswordInput");
+ gDialog.SavePassword = document.getElementById("SavePassword");
+
+ gPasswordManagerOn = Services.prefs.getBoolPref("signon.rememberSignons");
+ gDialog.SavePassword.disabled = !gPasswordManagerOn;
+
+ gPublishSiteData = GetPublishSiteData();
+ gDefaultSiteName = GetDefaultPublishSiteName();
+
+ var addNewSite = false;
+ if (gPublishSiteData)
+ {
+ FillSiteList();
+ }
+ else
+ {
+ // No current site data, start a new item in the Settings panel
+ AddNewSite();
+ addNewSite = true;
+ }
+
+ var docUrl = GetDocumentUrl();
+ var scheme = GetScheme(docUrl);
+ var filename = "";
+
+ if (scheme)
+ {
+ filename = GetFilename(docUrl);
+
+ if (scheme != "file")
+ {
+ var siteFound = false;
+
+ // Editing a remote URL.
+ // Attempt to find doc URL in Site Data
+ if (gPublishSiteData)
+ {
+ var dirObj = {};
+ var siteIndex = FindSiteIndexAndDocDir(gPublishSiteData, docUrl, dirObj);
+
+ // Select this site only if the same as user's intended site, or there wasn't one
+ if (siteIndex != -1 && (gInitialSiteIndex == -1 || siteIndex == gInitialSiteIndex))
+ {
+ siteFound = true;
+
+ // Select the site we found
+ gDialog.SiteList.selectedIndex = siteIndex;
+ var docDir = dirObj.value;
+
+ // Use the directory within site in the editable menulist
+ gPublishSiteData[siteIndex].docDir = docDir;
+
+ //XXX HOW DO WE DECIDE WHAT "OTHER" DIR TO USE?
+ //gPublishSiteData[siteIndex].otherDir = docDir;
+ }
+ }
+ if (!siteFound)
+ {
+ // Not found in site database
+ // Setup for a new site and use data from a remote URL
+ if (!addNewSite)
+ AddNewSite();
+
+ addNewSite = true;
+
+ var publishData = CreatePublishDataFromUrl(docUrl);
+ if (publishData)
+ {
+ filename = publishData.filename;
+ gDialog.SiteNameInput.value = publishData.siteName;
+ gDialog.PublishUrlInput.value = publishData.publishUrl;
+ gDialog.BrowseUrlInput.value = publishData.browseUrl;
+ gDialog.UsernameInput.value = publishData.username;
+ gDialog.PasswordInput.value = publishData.password;
+ gDialog.SavePassword.checked = false;
+ }
+ }
+ }
+ }
+ try {
+ gPreviousTitle = GetDocumentTitle();
+ } catch (e) {}
+
+ gDialog.PageTitleInput.value = gPreviousTitle;
+ gDialog.FilenameInput.value = decodeURIComponent(filename);
+
+ if (!addNewSite)
+ {
+ // If not adding a site and we haven't selected a site -- use initial or default site
+ if (gDialog.SiteList.selectedIndex == -1)
+ gDialog.SiteList.selectedIndex = (gInitialSiteIndex != -1) ? gInitialSiteIndex : gDefaultSiteIndex;
+
+ // Fill in all the site data for currently-selected site
+ SelectSiteList();
+ SetTextboxFocus(gDialog.PageTitleInput);
+ }
+
+ if (gDialog.SiteList.selectedIndex == -1)
+ {
+ // No selected site -- assume same directory
+ gDialog.OtherDirRadiogroup.selectedItem = gDialog.SameLocationRadio;
+ }
+ else if (gPublishSiteData[gDialog.SiteList.selectedIndex].docDir ==
+ gPublishSiteData[gDialog.SiteList.selectedIndex].otherDir)
+ {
+ // For now, check "same location" if dirs are already set to same directory
+ gDialog.OtherDirRadiogroup.selectedItem = gDialog.SameLocationRadio;
+ }
+ else
+ {
+ gDialog.OtherDirRadiogroup.selectedItem = gDialog.UseSubdirRadio;
+ }
+
+ doEnabling();
+
+ SetWindowLocation();
+}
+
+function FillSiteList()
+{
+ gDialog.SiteList.removeAllItems();
+ gDefaultSiteIndex = -1;
+
+ // Fill the site lists
+ var count = gPublishSiteData.length;
+ var i;
+
+ for (i = 0; i < count; i++)
+ {
+ var name = gPublishSiteData[i].siteName;
+ var menuitem = gDialog.SiteList.appendItem(name);
+ // Highlight the default site
+ if (name == gDefaultSiteName)
+ {
+ gDefaultSiteIndex = i;
+ if (menuitem)
+ {
+ menuitem.setAttribute("class", "menuitem-highlight-1");
+ menuitem.setAttribute("default", "true");
+ }
+ }
+ // Find initial site location
+ if (name == gInitialSiteName)
+ gInitialSiteIndex = i;
+ }
+}
+
+function doEnabling()
+{
+ var disableOther = !gDialog.OtherDirCheckbox.checked;
+ gDialog.SameLocationRadio.disabled = disableOther;
+ gDialog.UseSubdirRadio.disabled = disableOther;
+ gDialog.OtherDirList.disabled = (disableOther || gDialog.SameLocationRadio.selected);
+}
+
+function SelectSiteList()
+{
+ var selectedSiteIndex = gDialog.SiteList.selectedIndex;
+
+ var siteName = "";
+ var publishUrl = "";
+ var browseUrl = "";
+ var username = "";
+ var password = "";
+ var savePassword = false;
+ var publishOtherFiles = true;
+
+ gDialog.DocDirList.removeAllItems();
+ gDialog.OtherDirList.removeAllItems();
+
+ if (gPublishSiteData && selectedSiteIndex != -1)
+ {
+ siteName = gPublishSiteData[selectedSiteIndex].siteName;
+ publishUrl = gPublishSiteData[selectedSiteIndex].publishUrl;
+ browseUrl = gPublishSiteData[selectedSiteIndex].browseUrl;
+ username = gPublishSiteData[selectedSiteIndex].username;
+ savePassword = gPasswordManagerOn ? gPublishSiteData[selectedSiteIndex].savePassword : false;
+ if (savePassword)
+ password = gPublishSiteData[selectedSiteIndex].password;
+
+ // Fill the directory menulists
+ if (gPublishSiteData[selectedSiteIndex].dirList.length)
+ {
+ for (var i = 0; i < gPublishSiteData[selectedSiteIndex].dirList.length; i++)
+ {
+ gDialog.DocDirList.appendItem(gPublishSiteData[selectedSiteIndex].dirList[i]);
+ gDialog.OtherDirList.appendItem(gPublishSiteData[selectedSiteIndex].dirList[i]);
+ }
+ }
+ gDialog.DocDirList.value = FormatDirForPublishing(gPublishSiteData[selectedSiteIndex].docDir);
+ gDialog.OtherDirList.value = FormatDirForPublishing(gPublishSiteData[selectedSiteIndex].otherDir);
+ publishOtherFiles = gPublishSiteData[selectedSiteIndex].publishOtherFiles;
+
+ }
+ else
+ {
+ gDialog.DocDirList.value = "";
+ gDialog.OtherDirList.value = "";
+ }
+
+ gDialog.SiteNameInput.value = siteName;
+ gDialog.PublishUrlInput.value = publishUrl;
+ gDialog.BrowseUrlInput.value = browseUrl;
+ gDialog.UsernameInput.value = username;
+ gDialog.PasswordInput.value = password;
+ gDialog.SavePassword.checked = savePassword;
+ gDialog.OtherDirCheckbox.checked = publishOtherFiles;
+
+ doEnabling();
+}
+
+function AddNewSite()
+{
+ // Button in Publish panel allows user
+ // to automatically switch to "Settings" panel
+ // to enter data for new site
+ SwitchPanel(gDialog.SettingsTab);
+
+ gDialog.SiteList.selectedIndex = -1;
+
+ SelectSiteList();
+
+ gSettingsChanged = true;
+
+ SetTextboxFocus(gDialog.SiteNameInput);
+}
+
+function SelectPublishTab()
+{
+ if (gSettingsChanged && !ValidateSettings())
+ return;
+
+ SwitchPanel(gDialog.PublishTab);
+ SetTextboxFocus(gDialog.PageTitleInput);
+}
+
+function SelectSettingsTab()
+{
+ SwitchPanel(gDialog.SettingsTab);
+ SetTextboxFocus(gDialog.SiteNameInput);
+}
+
+function SwitchPanel(tab)
+{
+ if (gDialog.TabBox.selectedTab != tab)
+ gDialog.TabBox.selectedTab = tab;
+}
+
+function onInputSettings()
+{
+ // TODO: Save current data during SelectSite and compare here
+ // to detect if real change has occurred?
+ gSettingsChanged = true;
+}
+
+function GetPublishUrlInput()
+{
+ gDialog.PublishUrlInput.value = FormatUrlForPublishing(gDialog.PublishUrlInput.value);
+ return gDialog.PublishUrlInput.value;
+}
+
+function GetBrowseUrlInput()
+{
+ gDialog.BrowseUrlInput.value = FormatUrlForPublishing(gDialog.BrowseUrlInput.value);
+ return gDialog.BrowseUrlInput.value;
+}
+
+function GetDocDirInput()
+{
+ gDialog.DocDirList.value = FormatDirForPublishing(gDialog.DocDirList.value);
+ return gDialog.DocDirList.value;
+}
+
+function GetOtherDirInput()
+{
+ gDialog.OtherDirList.value = FormatDirForPublishing(gDialog.OtherDirList.value);
+ return gDialog.OtherDirList.value;
+}
+
+function ChooseDir(menulist)
+{
+ //TODO: For FTP publish destinations, get file listing of just dirs
+ // and build a tree to let user select dir
+}
+
+function ValidateSettings()
+{
+ var siteName = TrimString(gDialog.SiteNameInput.value);
+ if (!siteName)
+ {
+ ShowErrorInPanel(gDialog.SettingsTab, "MissingSiteNameError", gDialog.SiteNameInput);
+ return false;
+ }
+ if (PublishSiteNameExists(siteName, gPublishSiteData, gDialog.SiteList.selectedIndex))
+ {
+ SwitchPanel(gDialog.SettingsTab);
+ ShowInputErrorMessage(GetString("DuplicateSiteNameError").replace(/%name%/, siteName));
+ SetTextboxFocus(gDialog.SiteNameInput);
+ return false;
+ }
+
+ // Extract username and password while removing them from publishingUrl
+ var urlUserObj = {};
+ var urlPassObj = {};
+ var publishUrl = StripUsernamePassword(gDialog.PublishUrlInput.value, urlUserObj, urlPassObj);
+ if (publishUrl)
+ {
+ publishUrl = FormatUrlForPublishing(publishUrl);
+
+ // Assume scheme = "ftp://" if missing
+ // This compensates when user enters hostname w/o scheme (as most ISPs provide)
+ if (!GetScheme(publishUrl))
+ publishUrl = "ftp://" + publishUrl;
+
+ gDialog.PublishUrlInput.value = publishUrl;
+ }
+ else
+ {
+ ShowErrorInPanel(gDialog.SettingsTab, "MissingPublishUrlError", gDialog.PublishUrlInput);
+ return false;
+ }
+ var browseUrl = GetBrowseUrlInput();
+
+ var username = TrimString(gDialog.UsernameInput.value);
+ var savePassword = gDialog.SavePassword.checked;
+ var password = gDialog.PasswordInput.value;
+ var publishOtherFiles = gDialog.OtherDirCheckbox.checked;
+
+ //XXX If there was a username and/or password in the publishUrl
+ // AND in the input field, which do we use?
+ // Let's use those in url only if input is empty
+ if (!username)
+ {
+ username = urlUserObj.value;
+ gDialog.UsernameInput.value = username;
+ gSettingsChanged = true;
+ }
+ if (!password)
+ {
+ password = urlPassObj.value;
+ gDialog.PasswordInput.value = password;
+ gSettingsChanged = true;
+ }
+
+ // Update or add data for a site
+ var siteIndex = gDialog.SiteList.selectedIndex;
+ var newSite = false;
+
+ if (siteIndex == -1)
+ {
+ // No site is selected, add a new site at the end
+ if (gPublishSiteData)
+ {
+ siteIndex = gPublishSiteData.length;
+ }
+ else
+ {
+ // First time: start entire site array
+ gPublishSiteData = new Array(1);
+ siteIndex = 0;
+ gDefaultSiteIndex = 0;
+ gDefaultSiteName = siteName;
+ }
+ gPublishSiteData[siteIndex] = {};
+ gPublishSiteData[siteIndex].docDir = "";
+ gPublishSiteData[siteIndex].otherDir = "";
+ gPublishSiteData[siteIndex].dirList = [""];
+ gPublishSiteData[siteIndex].publishOtherFiles = true;
+ gPublishSiteData[siteIndex].previousSiteName = siteName;
+ newSite = true;
+ }
+ gPublishSiteData[siteIndex].siteName = siteName;
+ gPublishSiteData[siteIndex].publishUrl = publishUrl;
+ gPublishSiteData[siteIndex].browseUrl = browseUrl;
+ gPublishSiteData[siteIndex].username = username;
+ // Don't save password in data that will be saved in prefs
+ gPublishSiteData[siteIndex].password = savePassword ? password : "";
+ gPublishSiteData[siteIndex].savePassword = savePassword;
+
+ if (publishOtherFiles != gPublishSiteData[siteIndex].publishOtherFiles)
+ gSettingsChanged = true;
+
+ gPublishSiteData[siteIndex].publishOtherFiles = publishOtherFiles;
+
+ gDialog.SiteList.selectedIndex = siteIndex;
+ if (siteIndex == gDefaultSiteIndex)
+ gDefaultSiteName = siteName;
+
+ // Should never be empty, but be sure we have a default site
+ if (!gDefaultSiteName)
+ {
+ gDefaultSiteName = gPublishSiteData[0].siteName;
+ gDefaultSiteIndex = 0;
+ }
+
+ // Rebuild the site menulist if we added a new site
+ if (newSite)
+ {
+ FillSiteList();
+ gDialog.SiteList.selectedIndex = siteIndex;
+ }
+ else
+ {
+ // Update selected item if sitename changed
+ var selectedItem = gDialog.SiteList.selectedItem;
+ if (selectedItem)
+ {
+ var oldName = selectedItem.getAttribute("label");
+ if (oldName != siteName)
+ {
+ selectedItem.setAttribute("label", siteName);
+ gDialog.SiteList.setAttribute("label", siteName);
+ gSettingsChanged = true;
+ if (oldName == gDefaultSiteName)
+ gDefaultSiteName = siteName;
+ }
+ }
+ }
+
+ // Get the directory name in site to publish to
+ var docDir = GetDocDirInput();
+
+ gPublishSiteData[siteIndex].docDir = docDir;
+
+ // And directory for images and other files
+ var otherDir = GetOtherDirInput();
+ if (gDialog.SameLocationRadio.selected)
+ otherDir = docDir;
+ else
+ otherDir = GetOtherDirInput();
+
+ gPublishSiteData[siteIndex].otherDir = otherDir;
+
+ // Fill return data object
+ gReturnData.siteName = siteName;
+ gReturnData.previousSiteName = gPublishSiteData[siteIndex].previousSiteName;
+ gReturnData.publishUrl = publishUrl;
+ gReturnData.browseUrl = browseUrl;
+ gReturnData.username = username;
+ // Note that we use the password for the next publish action
+ // even if savePassword is false; but we won't save it in PasswordManager database
+ gReturnData.password = password;
+ gReturnData.savePassword = savePassword;
+ gReturnData.docDir = gPublishSiteData[siteIndex].docDir;
+ gReturnData.otherDir = gPublishSiteData[siteIndex].otherDir;
+ gReturnData.publishOtherFiles = publishOtherFiles;
+ gReturnData.dirList = gPublishSiteData[siteIndex].dirList;
+ return true;
+}
+
+function ValidateData()
+{
+ if (!ValidateSettings())
+ return false;
+
+ var siteIndex = gDialog.SiteList.selectedIndex;
+ if (siteIndex == -1)
+ return false;
+
+ var filename = TrimString(gDialog.FilenameInput.value);
+ if (!filename)
+ {
+ ShowErrorInPanel(gDialog.PublishTab, "MissingPublishFilename", gDialog.FilenameInput);
+ return false;
+ }
+ gReturnData.filename = filename;
+
+ return true;
+}
+
+function ShowErrorInPanel(tab, errorMsgId, widgetWithError)
+{
+ SwitchPanel(tab);
+ ShowInputErrorMessage(GetString(errorMsgId));
+ if (widgetWithError)
+ SetTextboxFocus(widgetWithError);
+}
+
+function onAccept(event)
+{
+ if (ValidateData())
+ {
+ // DON'T save the docDir and otherDir before trying to publish
+ gReturnData.saveDirs = false;
+
+ // We save new site data to prefs only if we are attempting to publish
+ if (gSettingsChanged)
+ SavePublishDataToPrefs(gReturnData);
+
+ // Set flag to resave data after publishing
+ // so we save docDir and otherDir if we published successfully
+ gReturnData.savePublishData = true;
+
+ var title = TrimString(gDialog.PageTitleInput.value);
+ if (title != gPreviousTitle)
+ SetDocumentTitle(title);
+
+ SaveWindowLocation();
+ window.opener.ok = true;
+ return;
+ }
+
+ event.preventDefault();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EditorPublish.xhtml b/comm/suite/editor/components/dialogs/content/EditorPublish.xhtml
new file mode 100644
index 0000000000..ed15c9f7d2
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EditorPublish.xhtml
@@ -0,0 +1,132 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+<?xml-stylesheet href="chrome://messenger/skin/menulist.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EditorPublishOverlay.xhtml"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorPublish.dtd">
+
+<dialog title="&windowTitle.label;"
+ id="publishDlg"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()"
+ buttons="accept,cancel"
+ buttonlabelaccept="&publishButton.label;">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EditorPublish.js"/>
+ <script src="chrome://editor/content/publishprefs.js"/>
+ <script src="chrome://messenger/content/customElements.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <tabbox id="TabBox">
+ <tabs flex="1">
+ <tab id="PublishTab" oncommand="SelectPublishTab()" label="&publishTab.label;"/>
+ <tab id="SettingsTab" oncommand="SelectSettingsTab()" label="&settingsTab.label;"/>
+ </tabs>
+ <tabpanels>
+ <!-- PUBLISH PANEL -->
+ <vbox>
+ <spacer class="spacer"/>
+ <grid pack="start">
+ <columns><column/><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <label value="&siteList.label;"
+ accesskey="&siteList.accesskey;"
+ control="SiteList"/>
+ <!-- Contents filled in at runtime -->
+ <menulist id="SiteList"
+ style="min-width:18em; max-width:18em;" crop="right"
+ tooltiptext="&siteList.tooltip;"
+ oncommand="SelectSiteList();"/>
+ <hbox>
+ <button label="&newSiteButton.label;"
+ accesskey="&newSiteButton.accesskey;"
+ oncommand="AddNewSite();"/>
+ <spacer flex="1"/>
+ </hbox>
+ </row>
+ <spacer class="spacer"/>
+ <row align="center">
+ <label value="&pageTitle.label;" accesskey="&pageTitle.accesskey;"
+ control="PageTitleInput"/>
+ <textbox id="PageTitleInput"
+ tooltiptext="&pageTitle.tooltip;" class="minWidth15"/>
+ <label value="&pageTitleExample.label;"/>
+ </row>
+ <row align="center">
+ <label value="&filename.label;" accesskey="&filename.accesskey;"
+ control="FilenameInput"/>
+ <textbox id="FilenameInput"
+ tooltiptext="&filename.tooltip;" class="minWidth15 uri-element"/>
+ <label value="&filenameExample.label;"/>
+ </row>
+ </rows>
+ </grid>
+ <spacer class="spacer"/>
+ <label value="&docDirList.label;"
+ accesskey="&docDirList.accesskey;"
+ control="DocDirList"/>
+ <hbox align="center">
+ <!-- Contents filled in at runtime -->
+ <menulist is="menulist-editable" id="DocDirList"
+ class="minWidth20 uri-element" editable="true" flex="1"
+ tooltiptext="&docDirList.tooltip;" oninput="onInputSettings();"/>
+ </hbox>
+ <spacer class="spacer"/>
+ <groupbox>
+ <caption>
+ <checkbox id="OtherDirCheckbox" label="&publishImgCheckbox.label;"
+ accesskey="&publishImgCheckbox.accesskey;"
+ tooltiptext="&publishImgCheckbox.tooltip;"
+ oncommand="doEnabling();"/>
+ </caption>
+ <vbox>
+ <radiogroup id="OtherDirRadiogroup">
+ <hbox>
+ <spacer class="checkbox-spacer"/>
+ <radio id="SameLocationRadio" label="&sameLocationRadio.label;"
+ accesskey="&sameLocationRadio.accesskey;"
+ tooltiptext="&sameLocationRadio.tooltip;"
+ oncommand="doEnabling();"/>
+ </hbox>
+ <hbox>
+ <spacer class="checkbox-spacer"/>
+ <radio id="UseSubdirRadio" label="&useSubdirRadio.label;"
+ accesskey="&useSubdirRadio.accesskey;"
+ tooltiptext="&useSubdirRadio.tooltip;"
+ oncommand="doEnabling();"/>
+ </hbox>
+ </radiogroup>
+ </vbox>
+ <hbox>
+ <spacer class="checkbox-spacer"/>
+ <spacer class="radio-spacer"/>
+ <!-- Contents filled in at runtime -->
+ <menulist is="menulist-editable" id="OtherDirList"
+ class="minWidth20 uri-element"
+ editable="true" flex="1" tooltiptext="&otherDirList.tooltip;"
+ oninput="onInputSettings();"/>
+ </hbox>
+ </groupbox>
+ <spacer flex="1"/>
+ </vbox><!-- Publish Panel -->
+
+ <!-- SETTINGS PANEL -->
+ <hbox id="SettingsPanel">
+ <!-- from EditorPublishOverlay.xhtml -->
+ <vbox id="PublishSettingsInputs" flex="1"/>
+ </hbox><!-- Settings Panel -->
+ </tabpanels>
+ </tabbox>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EditorPublishOverlay.xhtml b/comm/suite/editor/components/dialogs/content/EditorPublishOverlay.xhtml
new file mode 100644
index 0000000000..136a75623c
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EditorPublishOverlay.xhtml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/EditorPublish.dtd">
+
+<overlay id="EditorPublishOverlay"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
+
+<vbox id="PublishSettingsInputs">
+ <groupbox id="ServerSettingsBox">
+ <label class="header">&serverInfo.label;</label>
+ <hbox align="center">
+ <label value="&siteName.label;" accesskey="&siteName.accesskey;"
+ control="SiteNameInput"/>
+ <textbox id="SiteNameInput" class="MinWidth20em" flex="1"
+ tooltiptext="&siteName.tooltip;" oninput="onInputSettings();"/>
+ </hbox>
+ <spacer class="spacer"/>
+ <label value="&siteUrl.label;" accesskey="&siteUrl.accesskey;"
+ control="PublishUrlInput"/>
+ <textbox id="PublishUrlInput" class="MinWidth20em uri-element"
+ tooltiptext="&siteUrl.tooltip;" oninput="onInputSettings();"/>
+ <spacer class="spacer"/>
+ <label value="&browseUrl.label;" accesskey="&browseUrl.accesskey;"
+ control="BrowseUrlInput"/>
+ <textbox id="BrowseUrlInput" class="MinWidth20em uri-element"
+ tooltiptext="&browseUrl.tooltip;" oninput="onInputSettings();"/>
+ <spacer class="spacer"/>
+ </groupbox>
+ <groupbox id="LoginSettingsBox">
+ <label class="header">&loginInfo.label;</label>
+ <grid>
+ <columns><column flex="1"/><column flex="3"/></columns>
+ <rows>
+ <row align="center">
+ <label value="&username.label;" accesskey="&username.accesskey;"
+ control="UsernameInput"/>
+ <textbox id="UsernameInput" class="MinWidth10em" flex="1"
+ tooltiptext="&username.tooltip;" oninput="onInputSettings();"/>
+ </row>
+ <row align="center">
+ <label value="&password.label;" accesskey="&password.accesskey;"
+ control="PasswordInput"/>
+ <hbox>
+ <textbox id="PasswordInput" type="password" class="MinWidth5em"
+ oninput="onInputSettings();"
+ tooltiptext="&password.tooltip;"/>
+ <checkbox id="SavePassword" label="&savePassword.label;"
+ accesskey="&savePassword.accesskey;"
+ tooltiptext="&savePassword.tooltip;"
+ oncommand="onInputSettings();"/>
+ </hbox>
+ </row>
+ </rows>
+ </grid>
+ <spacer class="spacer"/>
+ </groupbox>
+</vbox>
+
+</overlay>
diff --git a/comm/suite/editor/components/dialogs/content/EditorPublishProgress.js b/comm/suite/editor/components/dialogs/content/EditorPublishProgress.js
new file mode 100644
index 0000000000..dafa053661
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EditorPublishProgress.js
@@ -0,0 +1,391 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var gInProgress = true;
+var gPublishData;
+var gPersistObj;
+var gTotalFileCount = 0;
+var gSucceededCount = 0;
+var gFinished = false;
+var gPublishingFailed = false;
+var gFileNotFound = false;
+var gStatusMessage="";
+
+var gTimerID;
+var gAllowEnterKey = false;
+
+// Publishing error codes
+// These are translated from C++ error code strings like this:
+// kFileNotFound = "FILE_NOT_FOUND",
+const kNetReset = 2152398868; // nsISocketTransportService.idl
+const kFileNotFound = 2152857618;
+const kNotConnected = 2152398860; // in netCore.h
+const kConnectionRefused = 2152398861; // nsISocketTransportService.idl
+const kNetTimeout = 2152398862; // nsISocketTransportService.idl
+const kNoConnectionOrTimeout = 2152398878;
+const kPortAccessNotAllowed = 2152398867; // netCore.h
+const kOffline = 2152398865; // netCore.h
+const kDiskFull = 2152857610;
+const kNoDeviceSpace = 2152857616;
+const kNameTooLong = 2152857617;
+const kAccessDenied = 2152857621;
+
+// These are more errors that I don't think we encounter during publishing,
+// so we don't have error strings yet. Let's keep them here for future reference
+//const kUnrecognizedPath = 2152857601;
+//const kUnresolvableSymlink = 2152857602;
+//const kUnknownType = 2152857604;
+//const kDestinationNotDir = 2152857605;
+//const kTargetDoesNotExist = 2152857606;
+//const kAlreadyExists = 2152857608;
+//const kInvalidPath = 2152857609;
+//const kNotDirectory = 2152857612;
+//const kIsDirectory = 2152857613;
+//const kIsLocked = 2152857614;
+//const kTooBig = 2152857615;
+//const kReadOnly = 2152857619;
+//const kDirectoryNotEmpty = 2152857620;
+//const kErrorBindingRedirected = 2152398851;
+//const kAlreadyConnected = 2152398859; // in netCore.h
+//const kInProgress = 2152398863; // netCore.h
+//const kNoContent = 2152398865; // netCore.h
+//const kUnknownProtocol = 2152398866 // netCore.h
+//const kFtpLogin = 2152398869; // ftpCore.h
+//const kFtpCWD = 2152398870; // ftpCore.h
+//const kFtpPasv = 2152398871; // ftpCore.h
+//const kFtpPwd = 2152398872; // ftpCore.h
+
+document.addEventListener("dialogaccept", onEnterKey);
+document.addEventListener("dialogcancel", onClose);
+
+function Startup()
+{
+ gPublishData = window.arguments[0];
+ if (!gPublishData)
+ {
+ dump("No publish data!\n");
+ window.close();
+ return;
+ }
+
+ gDialog.FileList = document.getElementById("FileList");
+ gDialog.FinalStatusMessage = document.getElementById("FinalStatusMessage");
+ gDialog.StatusMessage = document.getElementById("StatusMessage");
+ gDialog.KeepOpen = document.getElementById("KeepOpen");
+ gDialog.Close = document.documentElement.getButton("cancel");
+
+ SetWindowLocation();
+ var title = GetDocumentTitle();
+ if (!title)
+ title = "(" + opener.gUntitledString + ")";
+ document.title = GetString("PublishProgressCaption").replace(/%title%/, title);
+
+ document.getElementById("PublishToSite").value =
+ GetString("PublishToSite").replace(/%title%/, TruncateStringAtWordEnd(gPublishData.siteName, 25));
+
+ // Show publishing destination URL
+ document.getElementById("PublishUrl").value = gPublishData.publishUrl;
+
+ // Show subdirectories only if not empty
+ if (gPublishData.docDir || gPublishData.otherDir)
+ {
+ if (gPublishData.docDir)
+ document.getElementById("docDir").value = gPublishData.docDir;
+ else
+ document.getElementById("DocSubdir").hidden = true;
+
+ if (gPublishData.publishOtherFiles && gPublishData.otherDir)
+ document.getElementById("otherDir").value = gPublishData.otherDir;
+ else
+ document.getElementById("OtherSubdir").hidden = true;
+ }
+ else
+ document.getElementById("Subdirectories").hidden = true;
+
+ // Add the document to the "publish to" list as quick as possible!
+ SetProgressStatus(gPublishData.filename, "busy");
+
+ if (gPublishData.publishOtherFiles)
+ {
+ // When publishing images as well, expand list to show more items
+ gDialog.FileList.setAttribute("rows", 5);
+ window.sizeToContent();
+ }
+
+ // Now that dialog is initialized, we can start publishing
+ gPersistObj = window.opener.StartPublishing();
+}
+
+// this function is to be used when we cancel persist's saving
+// since not all messages will be returned to us if we cancel
+// this function changes status for all non-done/non-failure to failure
+function SetProgressStatusCancel()
+{
+ let listitems = document.querySelectorAll('listitem:not([progress="done"]):not([progress="failed"])');
+ if (!listitems)
+ return;
+
+ for (var i=0; i < listitems.length; i++)
+ {
+ listitems[i].setAttribute("progress", "failed");
+ }
+}
+
+// Add filename to list of files to publish
+// or set status for file already in the list
+// Returns true if file was in the list
+function SetProgressStatus(filename, status)
+{
+ if (!filename)
+ return false;
+
+ if (!status)
+ status = "busy";
+
+ // Just set attribute for status icon if we already have this filename.
+ let listitem = document.querySelector('listitem[label="' + filename + '"]');
+ if (listitem)
+ {
+ listitem.setAttribute("progress", status);
+ return true;
+ }
+ // We're adding a new file item to list
+ gTotalFileCount++;
+
+ listitem = document.createXULElement("listitem");
+ if (listitem)
+ {
+ listitem.setAttribute("class", "listitem-iconic progressitem");
+ // This triggers CSS to show icon for each status state
+ listitem.setAttribute("progress", status);
+ listitem.setAttribute("label", filename);
+ gDialog.FileList.appendChild(listitem);
+ }
+ return false;
+}
+
+function SetProgressFinished(filename, networkStatus)
+{
+ var abortPublishing = false;
+ if (filename)
+ {
+ var status = networkStatus ? "failed" : "done";
+ if (networkStatus == 0)
+ gSucceededCount++;
+
+ SetProgressStatus(filename, status);
+ }
+
+ if (networkStatus != 0) // Error condition
+ {
+ // We abort on all errors except if image file was not found
+ abortPublishing = networkStatus != kFileNotFound;
+
+ // Mark all remaining files as "failed"
+ if (abortPublishing)
+ {
+ gPublishingFailed = true;
+ SetProgressStatusCancel();
+ gDialog.FinalStatusMessage.value = GetString("PublishFailed");
+ }
+
+ switch (networkStatus)
+ {
+ case kFileNotFound:
+ gFileNotFound = true;
+ if (filename)
+ gStatusMessage = GetString("FileNotFound").replace(/%file%/, filename);
+ break;
+ case kNetReset:
+ // We get this when subdir doesn't exist AND
+ // if filename used is same as an existing subdir
+ var dir = (gPublishData.filename == filename) ?
+ gPublishData.docDir : gPublishData.otherDir;
+
+ if (dir)
+ {
+ // This is the ambiguous case when we can't tell if subdir or filename is bad
+ // Remove terminal "/" from dir string and insert into message
+ gStatusMessage = GetString("SubdirDoesNotExist").replace(/%dir%/, dir.slice(0, dir.length-1));
+ gStatusMessage = gStatusMessage.replace(/%file%/, filename);
+
+ // Remove directory from saved prefs
+ // XXX Note that if subdir is good,
+ // but filename = next level subdirectory name,
+ // we really shouldn't remove subdirectory,
+ // but it's impossible to differentiate this case!
+ RemovePublishSubdirectoryFromPrefs(gPublishData, dir);
+ }
+ else if (filename)
+ gStatusMessage = GetString("FilenameIsSubdir").replace(/%file%/, filename);
+
+ break;
+ case kNotConnected:
+ case kConnectionRefused:
+ case kNetTimeout:
+ case kNoConnectionOrTimeout:
+ case kPortAccessNotAllowed:
+ gStatusMessage = GetString("ServerNotAvailable");
+ break;
+ case kOffline:
+ gStatusMessage = GetString("Offline");
+ break;
+ case kDiskFull:
+ case kNoDeviceSpace:
+ if (filename)
+ gStatusMessage = GetString("DiskFull").replace(/%file%/, filename);
+ break;
+ case kNameTooLong:
+ if (filename)
+ gStatusMessage = GetString("NameTooLong").replace(/%file%/, filename);
+ break;
+ case kAccessDenied:
+ if (filename)
+ gStatusMessage = GetString("AccessDenied").replace(/%file%/, filename);
+ break;
+ case kUnknownType:
+ default:
+ gStatusMessage = GetString("UnknownPublishError")
+ break;
+ }
+ }
+ else if (!filename)
+ {
+ gFinished = true;
+
+ document.documentElement.setAttribute("buttonlabelcancel",
+ document.documentElement.getAttribute("buttonlabelclose"));
+
+ if (!gStatusMessage)
+ gStatusMessage = GetString(gPublishingFailed ? "UnknownPublishError" : "AllFilesPublished");
+
+ // Now allow "Enter/Return" key to close the dialog
+ AllowDefaultButton();
+
+ if (gPublishingFailed || gFileNotFound)
+ {
+ // Show "Troubleshooting" button to help solving problems
+ // and key for successful / failed files
+ document.getElementById("failureBox").hidden = false;
+ }
+ }
+
+ if (gStatusMessage)
+ SetStatusMessage(gStatusMessage);
+}
+
+function CheckKeepOpen()
+{
+ if (gTimerID)
+ {
+ clearTimeout(gTimerID);
+ gTimerID = null;
+ }
+}
+
+function onClose()
+{
+ if (!gFinished)
+ {
+ const buttonFlags = (Services.prompt.BUTTON_TITLE_IS_STRING *
+ Services.prompt.BUTTON_POS_0) +
+ (Services.prompt.BUTTON_TITLE_CANCEL *
+ Services.prompt.BUTTON_POS_1);
+ let button = Services.prompt.confirmEx(window,
+ GetString("CancelPublishTitle"),
+ GetString("CancelPublishMessage"),
+ buttonFlags,
+ GetString("CancelPublishContinue"),
+ null, null, null, {});
+ if (button == 0)
+ return false;
+ }
+
+ if (gTimerID)
+ {
+ clearTimeout(gTimerID);
+ gTimerID = null;
+ }
+
+ if (!gFinished && gPersistObj)
+ {
+ try {
+ gPersistObj.cancelSave();
+ } catch (e) {}
+ }
+ SaveWindowLocation();
+
+ // Tell caller so they can cleanup and restore editability
+ window.opener.FinishPublishing();
+ return true;
+}
+
+function AllowDefaultButton()
+{
+ gDialog.Close.setAttribute("default","true");
+ gAllowEnterKey = true;
+}
+
+function onEnterKey(event)
+{
+ if (gAllowEnterKey)
+ return CloseDialog();
+
+ event.preventDefault();
+}
+
+function RequestCloseDialog()
+{
+ // Finish progress messages, settings buttons etc.
+ SetProgressFinished(null, 0);
+
+ if (!gDialog.KeepOpen.checked)
+ {
+ // Leave window open a minimum amount of time
+ gTimerID = setTimeout(CloseDialog, 3000);
+ }
+
+ // Set "completed" message if we succeeded
+ // (Some image files may have failed,
+ // but we don't abort publishing for that)
+ if (!gPublishingFailed)
+ {
+ gDialog.FinalStatusMessage.value = GetString("PublishCompleted");
+ if (gFileNotFound && gTotalFileCount-gSucceededCount)
+ {
+ // Show number of files that failed to upload
+ gStatusMessage =
+ (GetString("FailedFileMsg").replace(/%x%/,(gTotalFileCount-gSucceededCount)))
+ .replace(/%total%/,gTotalFileCount);
+
+ SetStatusMessage(gStatusMessage);
+ }
+ }
+}
+
+function SetStatusMessage(message)
+{
+ // Status message is a child of <description> element
+ // so text can wrap to multiple lines if necessary
+ if (gDialog.StatusMessage.firstChild)
+ {
+ gDialog.StatusMessage.firstChild.data = message;
+ }
+ else
+ {
+ var textNode = document.createTextNode(message);
+ if (textNode)
+ gDialog.StatusMessage.appendChild(textNode);
+ }
+ window.sizeToContent();
+}
+
+function CloseDialog()
+{
+ SaveWindowLocation();
+ window.opener.FinishPublishing();
+ try {
+ window.close();
+ } catch (e) {}
+}
diff --git a/comm/suite/editor/components/dialogs/content/EditorPublishProgress.xhtml b/comm/suite/editor/components/dialogs/content/EditorPublishProgress.xhtml
new file mode 100644
index 0000000000..2cf422c8b5
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EditorPublishProgress.xhtml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorPublishProgress.dtd">
+
+<dialog title=""
+ id="publishProgressDlg"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ buttons="cancel"
+ buttonlabelclose="&closeButton.label;"
+ onload="Startup()">
+
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/publishprefs.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EditorPublishProgress.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox>
+ <caption><label id="PublishToSite"/></caption>
+ <label value="&siteUrl.label;"/>
+ <hbox>
+ <label class="indent bold" id="PublishUrl"/>
+ </hbox>
+ <spacer class="spacer"/>
+ <grid id="Subdirectories">
+ <columns><column/><column/></columns>
+ <rows>
+ <row id="DocSubdir">
+ <label value="&docSubdir.label;"/>
+ <label id="docDir"/>
+ </row>
+ <row id="OtherSubdir">
+ <label value="&otherSubdir.label;"/>
+ <label id="otherDir"/>
+ </row>
+ </rows>
+ </grid>
+ <label id="OtherUrl" class="bold" style="margin-left:3em"/>
+ </groupbox>
+ <groupbox>
+ <caption><label value="&fileList.label;"/></caption>
+ <vbox align="center" style="max-width:30em">
+ <label id="FinalStatusMessage" class="bold" value="&status.label;"/>
+ </vbox>
+ <description id="StatusMessage" class="wrap" style="max-width:30em; min-height: 1em"/>
+ <vbox flex="1">
+ <listbox id="FileList" rows="1"/>
+ </vbox>
+ <hbox align="center" id="failureBox" hidden="true">
+ <image class="progressitem" progress="done"/>
+ <label value="&succeeded.label;"/>
+ <spacer class="bigspacer"/>
+ <image class="progressitem" progress="failed"/>
+ <label value="&failed.label;"/>
+ </hbox>
+ </groupbox>
+ <checkbox id="KeepOpen" label="&keepOpen;" oncommand="CheckKeepOpen();" persist="checked"/>
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EditorPublishSettings.js b/comm/suite/editor/components/dialogs/content/EditorPublishSettings.js
new file mode 100644
index 0000000000..01677ae8c0
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EditorPublishSettings.js
@@ -0,0 +1,343 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var gPublishSiteData;
+var gPublishDataChanged = false;
+var gDefaultSiteIndex = -1;
+var gDefaultSiteName;
+var gPreviousDefaultSite;
+var gPreviousTitle;
+var gSettingsChanged = false;
+var gSiteDataChanged = false;
+var gAddNewSite = false;
+var gCurrentSiteIndex = -1;
+var gPasswordManagerOn = true;
+
+// Dialog initialization code
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+function Startup()
+{
+ if (!GetCurrentEditor())
+ {
+ window.close();
+ return;
+ }
+
+ gDialog.SiteList = document.getElementById("SiteList");
+ gDialog.SiteNameInput = document.getElementById("SiteNameInput");
+ gDialog.PublishUrlInput = document.getElementById("PublishUrlInput");
+ gDialog.BrowseUrlInput = document.getElementById("BrowseUrlInput");
+ gDialog.UsernameInput = document.getElementById("UsernameInput");
+ gDialog.PasswordInput = document.getElementById("PasswordInput");
+ gDialog.SavePassword = document.getElementById("SavePassword");
+ gDialog.SetDefaultButton = document.getElementById("SetDefaultButton");
+ gDialog.RemoveSiteButton = document.getElementById("RemoveSiteButton");
+ gDialog.OkButton = document.documentElement.getButton("accept");
+
+ gPublishSiteData = GetPublishSiteData();
+ gDefaultSiteName = GetDefaultPublishSiteName();
+ gPreviousDefaultSite = gDefaultSiteName;
+
+ gPasswordManagerOn = Services.prefs.getBoolPref("signon.rememberSignons");
+ gDialog.SavePassword.disabled = !gPasswordManagerOn;
+
+ InitDialog();
+
+ SetWindowLocation();
+}
+
+function InitDialog()
+{
+ // If there's no current site data, start a new item in the Settings panel
+ if (!gPublishSiteData)
+ {
+ AddNewSite();
+ }
+ else
+ {
+ FillSiteList();
+
+ // uncomment next code line if you want preselection of the default
+ // publishing site
+ //InitSiteSettings(gDefaultSiteIndex);
+
+ SetTextboxFocus(gDialog.SiteNameInput);
+ }
+}
+
+function FillSiteList()
+{
+ // Prevent triggering SelectSiteList() actions
+ gIsSelecting = true;
+ ClearListbox(gDialog.SiteList);
+ gIsSelecting = false;
+ gDefaultSiteIndex = -1;
+
+ // Fill the site list
+ var count = gPublishSiteData.length;
+ for (var i = 0; i < count; i++)
+ {
+ var name = gPublishSiteData[i].siteName;
+ var item = gDialog.SiteList.appendItem(name);
+ SetPublishItemStyle(item);
+ if (name == gDefaultSiteName)
+ gDefaultSiteIndex = i;
+ }
+}
+
+function SetPublishItemStyle(item)
+{
+ // Display default site with bold style
+ if (item)
+ {
+ if (item.getAttribute("label") == gDefaultSiteName)
+ item.setAttribute("class", "bold");
+ else
+ item.removeAttribute("class");
+ }
+}
+
+function AddNewSite()
+{
+ // Save any pending changes locally first
+ if (!ApplyChanges())
+ return;
+
+ // Initialize Setting widgets to none of the selected sites
+ InitSiteSettings(-1);
+ gAddNewSite = true;
+
+ SetTextboxFocus(gDialog.SiteNameInput);
+}
+
+function RemoveSite()
+{
+ if (!gPublishSiteData)
+ return;
+
+ var index = gDialog.SiteList.selectedIndex;
+ if (index != -1)
+ {
+ let item = gDialog.SiteList.selectedItem;
+ var nameToRemove = item.getAttribute("label");
+
+ // Remove one item from site data array
+ gPublishSiteData.splice(index, 1);
+ // Remove item from site list
+ gDialog.SiteList.clearSelection();
+ item.remove();
+
+ // Adjust if we removed last item and reselect a site
+ if (index >= gPublishSiteData.length)
+ index--;
+ InitSiteSettings(index);
+
+ if (nameToRemove == gDefaultSiteName)
+ {
+ // Deleting current default -- set to new selected item
+ // Arbitrary, but what else to do?
+ SetDefault();
+ }
+ gSiteDataChanged = true;
+ }
+}
+
+function SetDefault()
+{
+ if (!gPublishSiteData)
+ return;
+
+ var index = gDialog.SiteList.selectedIndex;
+ if (index != -1)
+ {
+ gDefaultSiteIndex = index;
+ gDefaultSiteName = gPublishSiteData[index].siteName;
+
+ // Set bold style on new default
+ var item = gDialog.SiteList.firstChild;
+ while (item)
+ {
+ SetPublishItemStyle(item);
+ item = item.nextSibling;
+ }
+ }
+}
+
+// Recursion prevention:
+// Use when you don't want to trigger ApplyChanges and InitSiteSettings
+var gIsSelecting = false;
+
+function SelectSiteList()
+{
+ if (gIsSelecting)
+ return;
+
+ gIsSelecting = true;
+ var newIndex = gDialog.SiteList.selectedIndex;
+
+ // Save any pending changes locally first
+ if (!ApplyChanges())
+ return;
+
+ InitSiteSettings(newIndex);
+
+ gIsSelecting = false;
+}
+
+// Use this to prevent recursion in SelectSiteList
+function SetSelectedSiteIndex(index)
+{
+ gIsSelecting = true;
+ gDialog.SiteList.selectedIndex = index;
+ gIsSelecting = false;
+}
+
+function InitSiteSettings(selectedSiteIndex)
+{
+ // Index to the site we will need to update if settings changed
+ gCurrentSiteIndex = selectedSiteIndex;
+
+ SetSelectedSiteIndex(selectedSiteIndex);
+ var haveData = (gPublishSiteData && selectedSiteIndex != -1);
+
+ gDialog.SiteNameInput.value = haveData ? gPublishSiteData[selectedSiteIndex].siteName : "";
+ gDialog.PublishUrlInput.value = haveData ? gPublishSiteData[selectedSiteIndex].publishUrl : "";
+ gDialog.BrowseUrlInput.value = haveData ? gPublishSiteData[selectedSiteIndex].browseUrl : "";
+ gDialog.UsernameInput.value = haveData ? gPublishSiteData[selectedSiteIndex].username : "";
+
+ var savePassord = haveData && gPasswordManagerOn;
+ gDialog.PasswordInput.value = savePassord ? gPublishSiteData[selectedSiteIndex].password : "";
+ gDialog.SavePassword.checked = savePassord ? gPublishSiteData[selectedSiteIndex].savePassword : false;
+
+ gDialog.SetDefaultButton.disabled = !haveData;
+ gDialog.RemoveSiteButton.disabled = !haveData;
+ gSettingsChanged = false;
+}
+
+function onInputSettings()
+{
+ // TODO: Save current data during SelectSite1 and compare here
+ // to detect if real change has occurred?
+ gSettingsChanged = true;
+}
+
+function ApplyChanges()
+{
+ if (gSettingsChanged && !UpdateSettings())
+ {
+ // Restore selection to previously current site
+ SetSelectedSiteIndex(gCurrentSiteIndex);
+ return false;
+ }
+ return true;
+}
+
+function UpdateSettings()
+{
+ // Validate and add new site
+ var newName = TrimString(gDialog.SiteNameInput.value);
+ if (!newName)
+ {
+ ShowInputErrorMessage(GetString("MissingSiteNameError"), gDialog.SiteNameInput);
+ return false;
+ }
+ if (PublishSiteNameExists(newName, gPublishSiteData, gCurrentSiteIndex))
+ {
+ ShowInputErrorMessage(GetString("DuplicateSiteNameError").replace(/%name%/, newName));
+ SetTextboxFocus(gDialog.SiteNameInput);
+ return false;
+ }
+
+ var newUrl = FormatUrlForPublishing(gDialog.PublishUrlInput.value);
+ if (!newUrl)
+ {
+ ShowInputErrorMessage(GetString("MissingPublishUrlError"), gDialog.PublishUrlInput);
+ return false;
+ }
+
+ // Start assuming we're updating existing site at gCurrentSiteIndex
+ var newSiteData = false;
+
+ if (!gPublishSiteData)
+ {
+ // First time used - Create the first site profile
+ gPublishSiteData = new Array(1);
+ gCurrentSiteIndex = 0;
+ newSiteData = true;
+ }
+ else if (gCurrentSiteIndex == -1)
+ {
+ // No currently-selected site,
+ // must be adding a new site
+ // Add new data at the end of list
+ gCurrentSiteIndex = gPublishSiteData.length;
+ newSiteData = true;
+ }
+
+ if (newSiteData)
+ {
+ // Init new site profile
+ gPublishSiteData[gCurrentSiteIndex] = {};
+ gPublishSiteData[gCurrentSiteIndex].docDir = "";
+ gPublishSiteData[gCurrentSiteIndex].otherDir = "";
+ gPublishSiteData[gCurrentSiteIndex].dirList = [""];
+ gPublishSiteData[gCurrentSiteIndex].previousSiteName = newName;
+ }
+
+ gPublishSiteData[gCurrentSiteIndex].siteName = newName;
+ gPublishSiteData[gCurrentSiteIndex].publishUrl = newUrl;
+ gPublishSiteData[gCurrentSiteIndex].browseUrl = FormatUrlForPublishing(gDialog.BrowseUrlInput.value);
+ gPublishSiteData[gCurrentSiteIndex].username = TrimString(gDialog.UsernameInput.value);
+ gPublishSiteData[gCurrentSiteIndex].password= gDialog.PasswordInput.value;
+ gPublishSiteData[gCurrentSiteIndex].savePassword = gDialog.SavePassword.checked;
+
+ if (gCurrentSiteIndex == gDefaultSiteIndex)
+ gDefaultSiteName = newName;
+
+ // When adding the very first site, assume that's the default
+ if (gPublishSiteData.length == 1 && !gDefaultSiteName)
+ {
+ gDefaultSiteName = gPublishSiteData[0].siteName;
+ gDefaultSiteIndex = 0;
+ }
+
+ FillSiteList();
+
+ // Select current site in list
+ SetSelectedSiteIndex(gCurrentSiteIndex);
+
+ // Signal saving data to prefs
+ gSiteDataChanged = true;
+
+ // Clear current site flags
+ gSettingsChanged = false;
+ gAddNewSite = false;
+
+ return true;
+}
+
+function onAccept(event)
+{
+ // Save any pending changes locally first
+ if (!ApplyChanges()) {
+ event.preventDefault();
+ return;
+ }
+
+ if (gSiteDataChanged)
+ {
+ // Save all local data to prefs
+ SavePublishSiteDataToPrefs(gPublishSiteData, gDefaultSiteName);
+ }
+ else if (gPreviousDefaultSite != gDefaultSiteName)
+ {
+ // only the default site was changed
+ SetDefaultSiteName(gDefaultSiteName);
+ }
+
+ SaveWindowLocation();
+}
diff --git a/comm/suite/editor/components/dialogs/content/EditorPublishSettings.xhtml b/comm/suite/editor/components/dialogs/content/EditorPublishSettings.xhtml
new file mode 100644
index 0000000000..ace6c2fc5d
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EditorPublishSettings.xhtml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<?xul-overlay href="chrome://editor/content/EditorPublishOverlay.xhtml"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorPublish.dtd">
+
+<dialog title="&windowTitleSettings.label;"
+ id="publishSettingsDlg"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload="Startup()"
+ buttons="accept,cancel">
+
+ <!-- Methods common to all editor dialogs -->
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EditorPublishSettings.js"/>
+ <script src="chrome://editor/content/publishprefs.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <hbox id="SettingsPanel">
+ <groupbox align="center">
+ <label class="header">&publishSites.label;</label>
+ <!-- XXX: If tree isn't wrapped in vbox, it appears BELOW next vbox -->
+ <vbox flex="1">
+ <listbox rows="4" id="SiteList" flex="1" onselect="SelectSiteList();"/>
+ </vbox>
+ <hbox pack="center">
+ <vbox>
+ <button id="NewSiteButton" label="&newSiteButton.label;"
+ accesskey="&newSiteButton.accesskey;" oncommand="AddNewSite();"/>
+ <button id="SetDefaultButton" label="&setDefaultButton.label;"
+ accesskey="&setDefaultButton.accesskey;" oncommand="SetDefault();"/>
+ <button id="RemoveSiteButton" label="&removeButton.label;"
+ accesskey="&removeButton.accesskey;" oncommand="RemoveSite();"/>
+ </vbox>
+ </hbox>
+ </groupbox>
+ <!-- from EditorPublishOverlay.xhtml -->
+ <vbox id="PublishSettingsInputs"/>
+ </hbox>
+ <spacer class="spacer"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/EditorSaveAsCharset.js b/comm/suite/editor/components/dialogs/content/EditorSaveAsCharset.js
new file mode 100644
index 0000000000..745a8bfd30
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EditorSaveAsCharset.js
@@ -0,0 +1,155 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+document.addEventListener("dialogaccept", onAccept);
+document.addEventListener("dialogcancel", onCancel);
+
+var {CharsetMenu} = ChromeUtils.import("resource://gre/modules/CharsetMenu.jsm");
+
+var gCharset="";
+var gTitleWasEdited = false;
+var gCharsetWasChanged = false;
+var gInsertNewContentType = false;
+var gContenttypeElement;
+var gInitDone = false;
+var gCharsetInfo;
+
+//Cancel() is in EdDialogCommon.js
+
+var gCharsetView = {
+ get rowCount() { return gCharsetInfo.length; },
+ selection: null,
+ getRowProperties: function(index) { return ""; },
+ getCellProperties: function(index, column) { return ""; },
+ getColumnProperties: function(columm) { return ""; },
+ isContainer: function() { return false; },
+ isContainerOpen: function() { return false; },
+ isContainerEmpty: function() { return true; },
+ isSeparator: function() { return false; },
+ isSorted: function() { return false; },
+ canDrop: function(index, orientation) { return false; },
+ drop: function(index, orientation) {},
+ getParentIndex: function(index) { return -1; },
+ hasNextSibling: function(index, after) { return false; },
+ getLevel: function(index) { return 1; },
+ getImageSrc: function(index) { return null; },
+ getProgressMode: function(index) { return 0; },
+ getCellValue: function(index) { return ""; },
+ getCellText: function(index) { return gCharsetInfo[index].label; },
+ toggleOpenState: function(index) {},
+ cycleHeader: function(column) {},
+ selectionChanged: function() {},
+ cycleCell: function(index, column) {},
+ isEditable: function isEditable(index, column) { return false; },
+};
+
+function Startup()
+{
+ var editor = GetCurrentEditor();
+ if (!editor)
+ {
+ window.close();
+ return;
+ }
+
+ gDialog.TitleInput = document.getElementById("TitleInput");
+ gDialog.charsetTree = document.getElementById('CharsetTree');
+ gDialog.exportToText = document.getElementById('ExportToText');
+
+ gContenttypeElement = GetMetaElementByAttribute("http-equiv", "content-type");
+ if (!gContenttypeElement && (editor.contentsMIMEType != 'text/plain'))
+ {
+ gContenttypeElement = CreateMetaElementWithAttribute("http-equiv", "content-type");
+ if (!gContenttypeElement )
+ {
+ window.close();
+ return;
+ }
+ gInsertNewContentType = true;
+ }
+
+ try {
+ gCharset = editor.documentCharacterSet;
+ } catch (e) {}
+
+ var data = CharsetMenu.getData();
+ var charsets = data.pinnedCharsets.concat(data.otherCharsets);
+ gCharsetInfo = CharsetMenu.getCharsetInfo(charsets.map(info => info.value));
+ gDialog.charsetTree.view = gCharsetView;
+
+ InitDialog();
+
+ // Use the same text as the messagebox for getting title by regular "Save"
+ document.getElementById("EnterTitleLabel").setAttribute("value",GetString("NeedDocTitle"));
+ // This is an <HTML> element so it wraps -- append a child textnode
+ var helpTextParent = document.getElementById("TitleHelp");
+ var helpText = document.createTextNode(GetString("DocTitleHelp"));
+ if (helpTextParent)
+ helpTextParent.appendChild(helpText);
+
+ // SET FOCUS TO FIRST CONTROL
+ SetTextboxFocus(gDialog.TitleInput);
+
+ gInitDone = true;
+
+ SetWindowLocation();
+}
+
+
+function InitDialog()
+{
+ gDialog.TitleInput.value = GetDocumentTitle();
+
+ var tree = gDialog.charsetTree;
+ var index = gCharsetInfo.map(info => info.value).indexOf(gCharset);
+ if (index >= 0) {
+ tree.view.selection.select(index);
+ tree.ensureRowIsVisible(index);
+ }
+}
+
+
+function onAccept()
+{
+ var editor = GetCurrentEditor();
+ editor.beginTransaction();
+
+ if(gCharsetWasChanged)
+ {
+ try {
+ SetMetaElementContent(gContenttypeElement, "text/html; charset=" + gCharset, gInsertNewContentType, true);
+ editor.documentCharacterSet = gCharset;
+ } catch (e) {}
+ }
+
+ editor.endTransaction();
+
+ if(gTitleWasEdited)
+ SetDocumentTitle(TrimString(gDialog.TitleInput.value));
+
+ window.opener.ok = true;
+ window.opener.exportToText = gDialog.exportToText.checked;
+ SaveWindowLocation();
+}
+
+
+function SelectCharset()
+{
+ if(gInitDone)
+ {
+ try
+ {
+ gCharset = gCharsetInfo[gDialog.charsetTree.currentIndex].value;
+ if (gCharset)
+ gCharsetWasChanged = true;
+ }
+ catch(e) {}
+ }
+}
+
+
+function TitleChanged()
+{
+ gTitleWasEdited = true;
+}
diff --git a/comm/suite/editor/components/dialogs/content/EditorSaveAsCharset.xhtml b/comm/suite/editor/components/dialogs/content/EditorSaveAsCharset.xhtml
new file mode 100644
index 0000000000..815a56dfe3
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/EditorSaveAsCharset.xhtml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/editor.css" type="text/css"?>
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://editor/locale/EditorSaveAsCharset.dtd">
+
+<dialog title="&windowTitle2.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
+ onload = "Startup()"
+ style="width: 32em;">
+
+ <script src="chrome://editor/content/editorUtilities.js"/>
+ <script src="chrome://editor/content/EdDialogCommon.js"/>
+ <script src="chrome://editor/content/EditorSaveAsCharset.js"/>
+
+ <spacer id="location" offsetY="50" persist="offsetX offsetY"/>
+
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label class="header">&documentTitleTitle.label;</label>
+ </hbox>
+ <label id="EnterTitleLabel"/>
+ <textbox id="TitleInput" oninput="TitleChanged();"/>
+ <description id="TitleHelp" class="wrap" style="width:1em" />
+ </groupbox>
+
+ <groupbox flex="1">
+ <hbox class="groupbox-title">
+ <label class="header">&documentCharsetTitle2.label;</label>
+ </hbox>
+ <label value="&documentCharsetDesc2.label;"/>
+ <tree id="CharsetTree" rows="8" hidecolumnpicker="true" onselect="SelectCharset();">
+ <treecols>
+ <treecol id="CharsetCol" flex="1" hideheader="true"/>
+ </treecols>
+ <treechildren/>
+ </tree>
+ </groupbox>
+
+ <checkbox id="ExportToText" label="&documentExportToText.label;" />
+ <separator class="groove"/>
+</dialog>
diff --git a/comm/suite/editor/components/dialogs/content/edImage.inc.xhtml b/comm/suite/editor/components/dialogs/content/edImage.inc.xhtml
new file mode 100644
index 0000000000..e80fb0457c
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/content/edImage.inc.xhtml
@@ -0,0 +1,248 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+ <vbox id="imageLocation">
+ <spacer class="spacer"/>
+ <label control = "srcInput"
+ value = "&locationEditField.label;"
+ accesskey="&locationEditField.accessKey;"
+ tooltiptext="&locationEditField.tooltip;"
+ />
+ <tooltip id="shortenedDataURI">
+ <label value="&locationEditField.shortenedDataURI;"/>
+ </tooltip>
+ <textbox id="srcInput" oninput="ChangeImageSrc();" tabindex="1" class="uri-element"
+ tooltiptext="&locationEditField.tooltip;"/>
+ <hbox id="MakeRelativeHbox">
+ <checkbox id="MakeRelativeCheckbox"
+ for="srcInput"
+ tabindex="2"
+ label="&makeUrlRelative.label;"
+ accesskey="&makeUrlRelative.accessKey;"
+ oncommand="MakeInputValueRelativeOrAbsolute(this);"
+ tooltiptext="&makeUrlRelative.tooltip;"/>
+ <checkbox id="AttachSourceToMail"
+ hidden="true"
+ label="&attachImageSource.label;"
+ accesskey="&attachImageSource.accesskey;"
+ oncommand="DoAttachSourceCheckbox()"/>
+ <spacer flex="1"/>
+ <button id="ChooseFile"
+ tabindex="3"
+ oncommand="chooseFile()"
+ label="&chooseFileButton.label;"
+ accesskey="&chooseFileButton.accessKey;"/>
+ </hbox>
+ <spacer class="spacer"/>
+ <radiogroup id="altTextRadioGroup" flex="1">
+ <grid>
+ <columns><column/><column flex="1"/></columns>
+ <rows>
+ <row align="center">
+ <label
+ style = "margin-left: 26px"
+ control = "titleInput"
+ accesskey = "&title.accessKey;"
+ value ="&title.label;"
+ tooltiptext="&title.tooltip;"
+ for = "titleInput"/>
+ <textbox flex="1"
+ id = "titleInput"
+ class = "MinWidth20em"
+ tooltiptext="&title.tooltip;"
+ tabindex="4"/>
+ </row>
+ <row align="center">
+ <radio id="altTextRadio" value="usealt-yes"
+ label="&altText.label;"
+ accesskey="&altText.accessKey;"
+ tooltiptext="&altTextEditField.tooltip;"
+#ifndef MOZ_SUITE
+ persist="selected"
+#endif
+ oncommand = "SetAltTextDisabled(false);"
+ tabindex="5"/>
+ <textbox flex="1"
+ id = "altTextInput"
+ class = "MinWidth20em"
+ tooltiptext="&altTextEditField.tooltip;"
+ oninput = "SetAltTextDisabled(false);"
+ tabindex="6"/>
+ </row>
+ </rows>
+ </grid>
+
+ <radio id="noAltTextRadio" value="usealt-no"
+ label="&noAltText.label;"
+ accesskey = "&noAltText.accessKey;"
+#ifndef MOZ_SUITE
+ persist="selected"
+#endif
+ oncommand = "SetAltTextDisabled(true);"/>
+ </radiogroup>
+ </vbox>
+
+ <vbox id="imageDimensions" align="start">
+ <spacer class="spacer"/>
+ <hbox>
+ <radiogroup id="imgSizeGroup">
+ <radio
+ id = "actualSizeRadio"
+ label = "&actualSizeRadio.label;"
+ accesskey = "&actualSizeRadio.accessKey;"
+ tooltiptext="&actualSizeRadio.tooltip;"
+ oncommand = "SetActualSize()"
+ value="actual"/>
+ <radio
+ id = "customSizeRadio"
+ label = "&customSizeRadio.label;"
+ selected = "true"
+ accesskey = "&customSizeRadio.accessKey;"
+ tooltiptext="&customSizeRadio.tooltip;"
+ oncommand = "doDimensionEnabling();"
+ value="custom"/>
+ </radiogroup>
+ <spacer flex="1"/>
+ <vbox>
+ <spacer flex="1"/>
+ <checkbox id="constrainCheckbox" label="&constrainCheckbox.label;"
+ accesskey="&constrainCheckbox.accessKey;"
+ oncommand="ToggleConstrain()"
+ tooltiptext="&constrainCheckbox.tooltip;"/>
+ </vbox>
+ <spacer flex="1"/>
+ </hbox>
+ <spacer class="spacer"/>
+ <grid class="indent">
+ <columns><column/><column/><column flex="1"/></columns>
+ <rows>
+ <row align="center">
+ <label id = "widthLabel"
+ control = "widthInput"
+ accesskey = "&widthEditField.accessKey;"
+ value = "&widthEditField.label;" />
+ <textbox
+ id = "widthInput"
+ class = "narrow"
+ oninput = "constrainProportions(this.id, 'heightInput')"/>
+ <menulist id = "widthUnitsMenulist"
+ oncommand = "doDimensionEnabling();" />
+ <!-- contents are appended by JS -->
+ </row>
+ <row align="center">
+ <label id = "heightLabel"
+ control = "heightInput"
+ accesskey = "&heightEditField.accessKey;"
+ value = "&heightEditField.label;" />
+ <textbox
+ id = "heightInput"
+ class = "narrow"
+ oninput = "constrainProportions(this.id, 'widthInput')"/>
+ <menulist id = "heightUnitsMenulist"
+ oncommand = "doDimensionEnabling();" />
+ <!-- contents are appended by JS -->
+ </row>
+ </rows>
+ </grid>
+ <spacer flex="1"/>
+ </vbox>
+
+ <hbox id="imageAppearance">
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label id="spacingLabel" class="header">&spacingBox.label;</label>
+ </hbox>
+ <grid>
+ <columns><column/><column/><column/></columns>
+ <rows>
+ <row align="center">
+ <label
+ class = "align-right"
+ id = "leftrightLabel"
+ control = "imageleftrightInput"
+ accesskey = "&leftRightEditField.accessKey;"
+ value = "&leftRightEditField.label;"/>
+ <textbox
+ class = "narrow"
+ id = "imageleftrightInput"
+ oninput = "forceInteger(this.id)"/>
+ <label
+ id = "leftrighttypeLabel"
+ value = "&pixelsPopup.value;" />
+ </row>
+ <spacer class="spacer"/>
+ <row align="center">
+ <label
+ class = "align-right"
+ id = "topbottomLabel"
+ control = "imagetopbottomInput"
+ accesskey = "&topBottomEditField.accessKey;"
+ value = "&topBottomEditField.label;"/>
+ <textbox
+ class = "narrow"
+ id = "imagetopbottomInput"
+ oninput = "forceInteger(this.id)"/>
+ <label id="topbottomtypeLabel"
+ value="&pixelsPopup.value;" />
+ </row>
+ <spacer class="spacer"/>
+ <row align="center">
+ <label class="align-right"
+ id="borderLabel"
+ control="border"
+ accesskey="&borderEditField.accessKey;"
+ value="&borderEditField.label;"/>
+ <textbox
+ class = "narrow"
+ id = "border"
+ oninput = "forceInteger(this.id)"/>
+ <label id="bordertypeLabel"
+ value="&pixelsPopup.value;" />
+ </row>
+ </rows>
+ </grid>
+ </groupbox>
+
+ <vbox>
+ <groupbox align="start">
+ <hbox class="groupbox-title">
+ <label id="alignLabel" class="header">&alignment.label;</label>
+ </hbox>
+ <menulist id="alignTypeSelect" class="align-menu">
+ <menupopup>
+ <menuitem class="align-menu menuitem-iconic"
+ value="top"
+ label="&topPopup.value;"/>
+ <menuitem class="align-menu menuitem-iconic"
+ value="middle"
+ label="&centerPopup.value;"/>
+ <menuitem class="align-menu menuitem-iconic"
+ value="bottom"
+ label="&bottomPopup.value;"/>
+ <!-- HTML attribute value is opposite of the button label on purpose -->
+ <menuitem class="align-menu menuitem-iconic"
+ value="right"
+ label="&wrapLeftPopup.value;"/>
+ <menuitem class="align-menu menuitem-iconic"
+ value="left"
+ label="&wrapRightPopup.value;"/>
+ </menupopup>
+ </menulist>
+ </groupbox>
+
+ <groupbox>
+ <hbox class="groupbox-title">
+ <label id="imagemapLabel" class="header">&imagemapBox.label;</label>
+ </hbox>
+ <hbox equalsize="always">
+ <button id="removeImageMap"
+ oncommand="removeImageMap()"
+ accesskey="&removeImageMapButton.accessKey;"
+ label="&removeImageMapButton.label;"
+ flex="1"/>
+ <spacer flex="1"/><!-- remove when we restore Image Map Editor -->
+ </hbox>
+ </groupbox>
+ </vbox>
+ </hbox>
diff --git a/comm/suite/editor/components/dialogs/jar.mn b/comm/suite/editor/components/dialogs/jar.mn
new file mode 100644
index 0000000000..705fe0068c
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/jar.mn
@@ -0,0 +1,82 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+comm.jar:
+ content/editor/EdAdvancedEdit.js (content/EdAdvancedEdit.js)
+ content/editor/EdAdvancedEdit.xhtml (content/EdAdvancedEdit.xhtml)
+ content/editor/EdAEAttributes.js (content/EdAEAttributes.js)
+ content/editor/EdAECSSAttributes.js (content/EdAECSSAttributes.js)
+ content/editor/EdAEHTMLAttributes.js (content/EdAEHTMLAttributes.js)
+ content/editor/EdAEJSEAttributes.js (content/EdAEJSEAttributes.js)
+ content/editor/EdButtonProps.js (content/EdButtonProps.js)
+ content/editor/EdButtonProps.xhtml (content/EdButtonProps.xhtml)
+ content/editor/EdColorPicker.js (content/EdColorPicker.js)
+ content/editor/EdColorPicker.xhtml (content/EdColorPicker.xhtml)
+ content/editor/EdColorProps.js (content/EdColorProps.js)
+ content/editor/EdColorProps.xhtml (content/EdColorProps.xhtml)
+ content/editor/EdConvertToTable.js (content/EdConvertToTable.js)
+ content/editor/EdConvertToTable.xhtml (content/EdConvertToTable.xhtml)
+ content/editor/EdDialogCommon.js (content/EdDialogCommon.js)
+ content/editor/EdDialogTemplate.js (content/EdDialogTemplate.js)
+ content/editor/EdDialogTemplate.xhtml (content/EdDialogTemplate.xhtml)
+ content/editor/EdDictionary.js (content/EdDictionary.js)
+ content/editor/EdDictionary.xhtml (content/EdDictionary.xhtml)
+ content/editor/EdFieldSetProps.js (content/EdFieldSetProps.js)
+ content/editor/EdFieldSetProps.xhtml (content/EdFieldSetProps.xhtml)
+ content/editor/EdFormProps.js (content/EdFormProps.js)
+ content/editor/EdFormProps.xhtml (content/EdFormProps.xhtml)
+ content/editor/EdHLineProps.js (content/EdHLineProps.js)
+ content/editor/EdHLineProps.xhtml (content/EdHLineProps.xhtml)
+ content/editor/edImage.inc.xhtml (content/edImage.inc.xhtml)
+ content/editor/EdImageDialog.js (content/EdImageDialog.js)
+ content/editor/EdImageLinkLoader.js (content/EdImageLinkLoader.js)
+ content/editor/EdImageProps.js (content/EdImageProps.js)
+* content/editor/EdImageProps.xhtml (content/EdImageProps.xhtml)
+ content/editor/EdInputImage.js (content/EdInputImage.js)
+* content/editor/EdInputImage.xhtml (content/EdInputImage.xhtml)
+ content/editor/EdInputProps.js (content/EdInputProps.js)
+ content/editor/EdInputProps.xhtml (content/EdInputProps.xhtml)
+ content/editor/EdInsertChars.js (content/EdInsertChars.js)
+ content/editor/EdInsertChars.xhtml (content/EdInsertChars.xhtml)
+ content/editor/EdInsertMath.js (content/EdInsertMath.js)
+ content/editor/EdInsertMath.xhtml (content/EdInsertMath.xhtml)
+ content/editor/EdInsertTable.js (content/EdInsertTable.js)
+ content/editor/EdInsertTable.xhtml (content/EdInsertTable.xhtml)
+ content/editor/EdInsertTOC.js (content/EdInsertTOC.js)
+ content/editor/EdInsertTOC.xhtml (content/EdInsertTOC.xhtml)
+ content/editor/EdInsSrc.js (content/EdInsSrc.js)
+ content/editor/EdInsSrc.xhtml (content/EdInsSrc.xhtml)
+ content/editor/EditConflict.js (content/EditConflict.js)
+ content/editor/EditConflict.xhtml (content/EditConflict.xhtml)
+ content/editor/EditorPublish.js (content/EditorPublish.js)
+ content/editor/EditorPublish.xhtml (content/EditorPublish.xhtml)
+ content/editor/EditorPublishOverlay.xhtml (content/EditorPublishOverlay.xhtml)
+ content/editor/EditorPublishProgress.js (content/EditorPublishProgress.js)
+ content/editor/EditorPublishProgress.xhtml (content/EditorPublishProgress.xhtml)
+ content/editor/EditorPublishSettings.js (content/EditorPublishSettings.js)
+ content/editor/EditorPublishSettings.xhtml (content/EditorPublishSettings.xhtml)
+ content/editor/EditorSaveAsCharset.js (content/EditorSaveAsCharset.js)
+ content/editor/EditorSaveAsCharset.xhtml (content/EditorSaveAsCharset.xhtml)
+ content/editor/EdLabelProps.js (content/EdLabelProps.js)
+ content/editor/EdLabelProps.xhtml (content/EdLabelProps.xhtml)
+ content/editor/EdLinkProps.js (content/EdLinkProps.js)
+ content/editor/EdLinkProps.xhtml (content/EdLinkProps.xhtml)
+ content/editor/EdListProps.js (content/EdListProps.js)
+ content/editor/EdListProps.xhtml (content/EdListProps.xhtml)
+ content/editor/EdNamedAnchorProps.js (content/EdNamedAnchorProps.js)
+ content/editor/EdNamedAnchorProps.xhtml (content/EdNamedAnchorProps.xhtml)
+ content/editor/EdPageProps.js (content/EdPageProps.js)
+ content/editor/EdPageProps.xhtml (content/EdPageProps.xhtml)
+ content/editor/EdReplace.js (content/EdReplace.js)
+ content/editor/EdReplace.xhtml (content/EdReplace.xhtml)
+ content/editor/EdSelectProps.js (content/EdSelectProps.js)
+ content/editor/EdSelectProps.xhtml (content/EdSelectProps.xhtml)
+ content/editor/EdSnapToGrid.js (content/EdSnapToGrid.js)
+ content/editor/EdSnapToGrid.xhtml (content/EdSnapToGrid.xhtml)
+ content/editor/EdSpellCheck.js (content/EdSpellCheck.js)
+ content/editor/EdSpellCheck.xhtml (content/EdSpellCheck.xhtml)
+ content/editor/EdTableProps.js (content/EdTableProps.js)
+ content/editor/EdTableProps.xhtml (content/EdTableProps.xhtml)
+ content/editor/EdTextAreaProps.js (content/EdTextAreaProps.js)
+ content/editor/EdTextAreaProps.xhtml (content/EdTextAreaProps.xhtml)
diff --git a/comm/suite/editor/components/dialogs/moz.build b/comm/suite/editor/components/dialogs/moz.build
new file mode 100644
index 0000000000..de5cd1bf81
--- /dev/null
+++ b/comm/suite/editor/components/dialogs/moz.build
@@ -0,0 +1,6 @@
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+JAR_MANIFESTS += ["jar.mn"]
diff --git a/comm/suite/editor/components/moz.build b/comm/suite/editor/components/moz.build
new file mode 100644
index 0000000000..cc5a5d1960
--- /dev/null
+++ b/comm/suite/editor/components/moz.build
@@ -0,0 +1,10 @@
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DIRS += [
+ "dialogs",
+ "prefs",
+ "texzilla",
+]
diff --git a/comm/suite/editor/components/prefs/content/editorPrefsOverlay.xhtml b/comm/suite/editor/components/prefs/content/editorPrefsOverlay.xhtml
new file mode 100644
index 0000000000..41112036ca
--- /dev/null
+++ b/comm/suite/editor/components/prefs/content/editorPrefsOverlay.xhtml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+
+<!DOCTYPE overlay [
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
+%brandDTD;
+<!ENTITY % editorPrefsOverlayDTD SYSTEM "chrome://editor/locale/editorPrefsOverlay.dtd" >
+%editorPrefsOverlayDTD;
+]>
+
+<overlay id="editorPrefsOverlay"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
+
+ <preferences id="appearance_preferences">
+ <preference id="general.startup.editor"
+ name="general.startup.editor"
+ type="bool"/>
+ </preferences>
+
+ <!-- editor startup toggle -->
+ <groupbox id="generalStartupPreferences">
+ <checkbox id="generalStartupEditor"
+ insertafter="generalStartupMail,generalStartupBrowser"
+ label="&editorCheck.label;"
+ accesskey="&editorCheck.accesskey;"
+ preference="general.startup.editor"/>
+ </groupbox>
+ <!-- category tree entries for editor -->
+ <treechildren id="prefsPanelChildren">
+ <treeitem container="true"
+ id="composerItem"
+ insertbefore="securityItem"
+ label="&compose.label;"
+ prefpane="composer_pane"
+ url="chrome://editor/content/pref-composer.xhtml"
+ helpTopic="composer_prefs_general">
+ <treechildren id="composerChildren">
+ <treeitem id="editingItem"
+ label="&editing.label;"
+ prefpane="editing_pane"
+ url="chrome://editor/content/pref-editing.xhtml"
+ helpTopic="composer_prefs_newpage"/>
+ </treechildren>
+ </treeitem>
+ </treechildren>
+
+</overlay>
diff --git a/comm/suite/editor/components/prefs/content/pref-composer.xhtml b/comm/suite/editor/components/prefs/content/pref-composer.xhtml
new file mode 100644
index 0000000000..79b4a1514c
--- /dev/null
+++ b/comm/suite/editor/components/prefs/content/pref-composer.xhtml
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/pref-composer.dtd">
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
+ <prefpane id="composer_pane" label="&pref.composer.title;">
+
+ <preferences id="composer_preferences">
+ <preference id="editor.history.url_maximum"
+ name="editor.history.url_maximum"
+ type="int"/>
+ <preference id="editor.prettyprint"
+ name="editor.prettyprint"
+ type="bool"
+ inverted="true"/>
+ <preference id="editor.save_associated_files"
+ name="editor.save_associated_files"
+ type="bool"/>
+ <preference id="editor.always_show_publish_dialog"
+ name="editor.always_show_publish_dialog"
+ type="bool"/>
+ <preference id="editor.table.maintain_structure"
+ name="editor.table.maintain_structure"
+ type="bool"/>
+ <preference id="editor.use_css"
+ name="editor.use_css"
+ type="bool"/>
+ <preference id="editor.CR_creates_new_p"
+ name="editor.CR_creates_new_p"
+ type="bool"/>
+ </preferences>
+
+ <!-- Recent files menu -->
+ <groupbox>
+ <label class="header">&recentFiles.title;</label>
+ <hbox align="center">
+ <label value="&documentsInMenu.label;"
+ accesskey="&documentsInMenu.accesskey;"
+ control="recentFiles"/>
+ <html:input id="recentFiles" type="number" class="size3"
+ min="0" max="99" value="10"
+ preference="editor.history.url_maximum"/>
+ </hbox>
+ </groupbox>
+
+ <!-- HTML formatting on output -->
+ <groupbox>
+ <label class="header">&savingFiles.title;</label>
+ <checkbox id="preserveFormatting"
+ label="&preserveExisting.label;"
+ accesskey="&preserveExisting.accesskey;"
+ tooltiptext="&preserveExisting.tooltip;"
+ preference="editor.prettyprint"/>
+ <checkbox id="saveAssociatedFiles"
+ label="&saveAssociatedFiles.label;"
+ accesskey="&saveAssociatedFiles.accesskey;"
+ preference="editor.save_associated_files"/>
+ <checkbox id="showPublishDialog"
+ label="&showPublishDialog.label;"
+ accesskey="&showPublishDialog.accesskey;"
+ preference="editor.always_show_publish_dialog"/>
+ </groupbox>
+
+ <groupbox align="start">
+ <label class="header">&composerEditing.label;</label>
+ <checkbox id="maintainTableStructure"
+ label="&maintainStructure.label;"
+ accesskey="&maintainStructure.accesskey;"
+ tooltiptext="&maintainStructure.tooltip;"
+ preference="editor.table.maintain_structure"/>
+ <checkbox id="useCSS"
+ label="&useCSS.label;"
+ accesskey="&useCSS.accesskey;"
+ preference="editor.use_css"/>
+ <checkbox id="crInPCreatesNewP"
+ label="&crInPCreatesNewP.label;"
+ accesskey="&crInPCreatesNewP.accesskey;"
+ preference="editor.CR_creates_new_p"/>
+ </groupbox>
+ </prefpane>
+</overlay>
diff --git a/comm/suite/editor/components/prefs/content/pref-editing.js b/comm/suite/editor/components/prefs/content/pref-editing.js
new file mode 100644
index 0000000000..61f4c1edef
--- /dev/null
+++ b/comm/suite/editor/components/prefs/content/pref-editing.js
@@ -0,0 +1,187 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const browserPrefsObserver =
+{
+ observe: function(aSubject, aTopic, aData)
+ {
+ if (aTopic != "nsPref:changed" || document.getElementById("editor.use_custom_colors").value)
+ return;
+
+ switch (aData)
+ {
+ case "browser.anchor_color":
+ SetColorPreview("linkText", Services.prefs.getCharPref(aData));
+ break;
+ case "browser.active_color":
+ SetColorPreview("activeLinkText", Services.prefs.getCharPref(aData));
+ break;
+ case "browser.visited_color":
+ SetColorPreview("visitedLinkText", Services.prefs.getCharPref(aData));
+ break;
+ default:
+ SetBgAndFgColors(Services.prefs.getBoolPref("browser.display.use_system_colors"))
+ }
+ }
+};
+
+function Startup()
+{
+ // Add browser prefs observers
+ Services.prefs.addObserver("browser.display.use_system_colors", browserPrefsObserver);
+ Services.prefs.addObserver("browser.display.foreground_color", browserPrefsObserver);
+ Services.prefs.addObserver("browser.display.background_color", browserPrefsObserver);
+ Services.prefs.addObserver("browser.anchor_color", browserPrefsObserver);
+ Services.prefs.addObserver("browser.active_color", browserPrefsObserver);
+ Services.prefs.addObserver("browser.visited_color", browserPrefsObserver);
+
+ // Add event listener so we can remove our observers
+ window.addEventListener("unload", WindowOnUnload, {capture: false, once: true});
+ UpdateDependent(document.getElementById("editor.use_custom_colors").value);
+}
+
+function GetColorAndUpdatePref(aType, aButtonID)
+{
+ // Don't allow a blank color, i.e., using the "default"
+ var colorObj = { NoDefault:true, Type:"", TextColor:0, PageColor:0, Cancel:false };
+ var preference = document.getElementById("editor." + aButtonID + "_color");
+
+ if (aButtonID == "background")
+ colorObj.PageColor = preference.value;
+ else
+ colorObj.TextColor = preference.value;
+
+ colorObj.Type = aType;
+
+ window.openDialog("chrome://editor/content/EdColorPicker.xhtml", "_blank", "chrome,close,titlebar,modal", "", colorObj);
+
+ // User canceled the dialog
+ if (colorObj.Cancel)
+ return;
+
+ // Update preference with picked color
+ if (aType == "Page")
+ preference.value = colorObj.BackgroundColor;
+ else
+ preference.value = colorObj.TextColor;
+}
+
+function UpdateDependent(aCustomEnabled)
+{
+ ToggleElements(aCustomEnabled);
+
+ if (aCustomEnabled)
+ { // Set current editor colors on preview and buttons
+ SetColors("textCW", "normalText", document.getElementById("editor.text_color").value);
+ SetColors("linkCW", "linkText", document.getElementById("editor.link_color").value);
+ SetColors("activeCW", "activeLinkText", document.getElementById("editor.active_link_color").value);
+ SetColors("visitedCW", "visitedLinkText", document.getElementById("editor.followed_link_color").value);
+ SetColors("backgroundCW", "ColorPreview", document.getElementById("editor.background_color").value);
+ }
+ else
+ { // Set current browser colors on preview
+ SetBgAndFgColors(Services.prefs.getBoolPref("browser.display.use_system_colors"));
+ SetColorPreview("linkText", Services.prefs.getCharPref("browser.anchor_color"));
+ SetColorPreview("activeLinkText", Services.prefs.getCharPref("browser.active_color"));
+ SetColorPreview("visitedLinkText", Services.prefs.getCharPref("browser.visited_color"));
+ }
+}
+
+function ToggleElements(aCustomEnabled)
+{
+ var buttons = document.getElementById("color-rows").getElementsByTagName("button");
+
+ for (var i = 0; i < buttons.length; i++)
+ {
+ let isLocked = CheckLocked(buttons[i].id);
+ buttons[i].disabled = !aCustomEnabled || isLocked;
+ buttons[i].previousSibling.disabled = !aCustomEnabled || isLocked;
+ buttons[i].firstChild.setAttribute("default", !aCustomEnabled || isLocked);
+ }
+}
+
+function CheckLocked(aButtonID)
+{
+ return document.getElementById("editor." + aButtonID + "_color").locked;
+}
+
+// Updates preview and button color when a editor color pref change
+function UpdateColors(aColorWellID, aPreviewID, aColor)
+{
+ // Only show editor colors from prefs if we're in custom mode
+ if (!document.getElementById("editor.use_custom_colors").value)
+ return;
+
+ SetColors(aColorWellID, aPreviewID, aColor)
+}
+
+function SetColors(aColorWellID, aPreviewID, aColor)
+{
+ SetColorWell(aColorWellID, aColor);
+ SetColorPreview(aPreviewID, aColor);
+}
+
+function SetColorWell(aColorWellID, aColor)
+{
+ document.getElementById(aColorWellID).style.backgroundColor = aColor;
+}
+
+function SetColorPreview(aPreviewID, aColor)
+{
+ if (aPreviewID == "ColorPreview")
+ document.getElementById(aPreviewID).style.backgroundColor = aColor;
+ else
+ document.getElementById(aPreviewID).style.color = aColor;
+}
+
+function UpdateBgImagePreview(aImage)
+{
+ var colorPreview = document.getElementById("ColorPreview");
+ colorPreview.style.backgroundImage = aImage && "url(" + aImage + ")";
+}
+
+// Sets browser background/foreground colors
+function SetBgAndFgColors(aSysPrefEnabled)
+{
+ if (aSysPrefEnabled)
+ { // Use system colors
+ SetColorPreview("normalText", "windowtext");
+ SetColorPreview("ColorPreview", "window");
+ }
+ else
+ {
+ SetColorPreview("normalText", Services.prefs.getCharPref("browser.display.foreground_color"));
+ SetColorPreview("ColorPreview", Services.prefs.getCharPref("browser.display.background_color"));
+ }
+}
+
+function ChooseImageFile()
+{
+ const nsIFilePicker = Ci.nsIFilePicker;
+ var fp = Cc["@mozilla.org/filepicker;1"]
+ .createInstance(nsIFilePicker);
+ var editorBundle = document.getElementById("bundle_editor");
+ var title = editorBundle.getString("SelectImageFile");
+ fp.init(window, title, nsIFilePicker.modeOpen);
+ fp.appendFilters(nsIFilePicker.filterImages);
+ fp.open(rv => {
+ if (rv != nsIFilePicker.returnOK || !fp.file) {
+ return;
+ }
+ document.getElementById("editor.default_background_image").value = fp.fileURL.spec;
+ let textbox = document.getElementById("backgroundImageInput");
+ textbox.focus();
+ textbox.select();
+ });
+}
+
+function WindowOnUnload()
+{
+ Services.prefs.removeObserver("browser.display.use_system_colors", browserPrefsObserver, false);
+ Services.prefs.removeObserver("browser.display.foreground_color", browserPrefsObserver, false);
+ Services.prefs.removeObserver("browser.display.background_color", browserPrefsObserver, false);
+ Services.prefs.removeObserver("browser.anchor_color", browserPrefsObserver, false);
+ Services.prefs.removeObserver("browser.active_color", browserPrefsObserver, false);
+ Services.prefs.removeObserver("browser.visited_color", browserPrefsObserver, false);
+}
diff --git a/comm/suite/editor/components/prefs/content/pref-editing.xhtml b/comm/suite/editor/components/prefs/content/pref-editing.xhtml
new file mode 100644
index 0000000000..140ff320ce
--- /dev/null
+++ b/comm/suite/editor/components/prefs/content/pref-editing.xhtml
@@ -0,0 +1,181 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://editor/skin/EditorDialog.css" type="text/css"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://editor/locale/pref-editing.dtd">
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
+ <prefpane id="editing_pane"
+ label="&pref.editing.title;"
+ script="chrome://editor/content/pref-editing.js">
+
+ <preferences id="editing_preferences">
+ <preference id="editor.author"
+ name="editor.author"
+ type="string"/>
+ <preference id="editor.use_custom_colors"
+ name="editor.use_custom_colors"
+ type="bool"
+ onchange="UpdateDependent(this.value);"/>
+ <preference id="editor.text_color"
+ name="editor.text_color"
+ type="string"
+ onchange="UpdateColors('textCW', 'normalText', this.value);"/>
+ <preference id="editor.link_color"
+ name="editor.link_color"
+ type="string"
+ onchange="UpdateColors('linkCW', 'linkText', this.value);"/>
+ <preference id="editor.active_link_color"
+ name="editor.active_link_color"
+ type="string"
+ onchange="UpdateColors('activeCW', 'activeLinkText', this.value);"/>
+ <preference id="editor.followed_link_color"
+ name="editor.followed_link_color"
+ type="string"
+ onchange="UpdateColors('visitedCW', 'visitedLinkText', this.value);"/>
+ <preference id="editor.background_color"
+ name="editor.background_color"
+ type="string"
+ onchange="UpdateColors('backgroundCW', 'ColorPreview', this.value);"/>
+ <preference id="editor.default_background_image"
+ name="editor.default_background_image"
+ type="string"
+ onchange="UpdateBgImagePreview(this.value);"/>
+ </preferences>
+
+ <stringbundle id="bundle_editor"
+ src="chrome://editor/locale/editor.properties"/>
+
+ <vbox>
+ <label value="&authorName.label;"
+ accesskey="&authorName.accesskey;"
+ control="editorAuthor">
+ </label>
+ <hbox>
+ <textbox id="editorAuthor"
+ flex="1"
+ preference="editor.author"/>
+ <spacer flex="1"/>
+ </hbox>
+ </vbox>
+ <spacer class="smallspacer"/>
+ <groupbox align="start">
+ <label class="header">&pageColorHeader;</label>
+ <radiogroup id="useCustomColors"
+ preference="editor.use_custom_colors">
+ <radio id="defaultColorsRadio"
+ value="false"
+ label="&defaultColors.label;"
+ accesskey="&defaultColors.accesskey;"/>
+ <radio id="customColorsRadio"
+ value="true"
+ label="&customColors.label;"
+ accesskey="&customColors.accesskey;"/>
+ </radiogroup>
+ <hbox class="indent">
+ <grid>
+ <columns><column/><column/></columns>
+ <rows id="color-rows">
+ <row align="center">
+ <label id="textLabel"
+ value="&normalText.label;&colon.character;"
+ accesskey="&normalText.accesskey;"
+ control="text"/>
+ <button id="text"
+ class="color-button"
+ oncommand="GetColorAndUpdatePref('Text', 'text');">
+ <spacer id="textCW" class="color-well"/>
+ </button>
+ </row>
+ <row align="center">
+ <label id="linkLabel"
+ value="&linkText.label;&colon.character;"
+ accesskey="&linkText.accesskey;"
+ control="link"/>
+ <button id="link"
+ class="color-button"
+ oncommand="GetColorAndUpdatePref('Link', 'link');">
+ <spacer id="linkCW" class="color-well"/>
+ </button>
+ </row>
+ <row align="center">
+ <label id="activeLinkLabel"
+ value="&activeLinkText.label;&colon.character;"
+ accesskey="&activeLinkText.accesskey;"
+ control="active_link"/>
+ <button id="active_link"
+ class="color-button"
+ oncommand="GetColorAndUpdatePref('ActiveLink', 'active_link');">
+ <spacer id="activeCW" class="color-well"/>
+ </button>
+ </row>
+ <row align="center">
+ <label id="visitedLinkLabel"
+ value ="&visitedLinkText.label;&colon.character;"
+ accesskey="&visitedLinkText.accesskey;"
+ control="followed_link"/>
+ <button id="followed_link"
+ class="color-button"
+ oncommand="GetColorAndUpdatePref('VisitedLink', 'followed_link');">
+ <spacer id="visitedCW" class="color-well"/>
+ </button>
+ </row>
+ <row align="center">
+ <label id="backgroundLabel"
+ value="&background.label;"
+ accesskey="&background.accesskey;"
+ control="background"/>
+ <button id="background"
+ class="color-button"
+ oncommand="GetColorAndUpdatePref('Page', 'background');">
+ <spacer id="backgroundCW" class="color-well"/>
+ </button>
+ </row>
+ </rows>
+ </grid>
+ <vbox id="ColorPreview"
+ flex="1">
+ <spacer flex="1"/>
+ <label id="normalText"
+ class="larger"
+ value="&normalText.label;"/>
+ <spacer flex="1"/>
+ <label id="linkText"
+ class="larger"
+ value="&linkText.label;"/>
+ <spacer flex="1"/>
+ <label id="activeLinkText"
+ class="larger"
+ value="&activeLinkText.label;"/>
+ <spacer flex="1"/>
+ <label id="visitedLinkText"
+ class="larger"
+ value="&visitedLinkText.label;"/>
+ <spacer flex="1"/>
+ </vbox>
+ <spacer flex="1"/>
+ </hbox>
+ <spacer class="spacer"/>
+ <label id="backgroundImageLabel"
+ value="&backgroundImage.label;"
+ accesskey="&backgroundImage.accesskey;"
+ control="backgroundImageInput">
+ </label>
+ <hbox align="center">
+ <textbox id="backgroundImageInput"
+ class="uri-element"
+ preference="editor.default_background_image"
+ style="min-width: 23em;"
+ flex="1"/>
+ <button label="&chooseFile.label;"
+ accesskey="&chooseFile.accesskey;"
+ oncommand="ChooseImageFile();">
+ <observes element="backgroundImageInput" attribute="disabled"/>
+ </button>
+ </hbox>
+ </groupbox>
+ </prefpane>
+</overlay>
diff --git a/comm/suite/editor/components/prefs/jar.mn b/comm/suite/editor/components/prefs/jar.mn
new file mode 100644
index 0000000000..308da7340c
--- /dev/null
+++ b/comm/suite/editor/components/prefs/jar.mn
@@ -0,0 +1,11 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+comm.jar:
+% overlay chrome://communicator/content/pref/preferences.xhtml chrome://editor/content/editorPrefsOverlay.xhtml
+% overlay chrome://communicator/content/pref/pref-appearance.xhtml chrome://editor/content/editorPrefsOverlay.xhtml
+ content/editor/editorPrefsOverlay.xhtml (content/editorPrefsOverlay.xhtml)
+ content/editor/pref-composer.xhtml (content/pref-composer.xhtml)
+ content/editor/pref-editing.js (content/pref-editing.js)
+ content/editor/pref-editing.xhtml (content/pref-editing.xhtml)
diff --git a/comm/suite/editor/components/prefs/moz.build b/comm/suite/editor/components/prefs/moz.build
new file mode 100644
index 0000000000..de5cd1bf81
--- /dev/null
+++ b/comm/suite/editor/components/prefs/moz.build
@@ -0,0 +1,6 @@
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+JAR_MANIFESTS += ["jar.mn"]
diff --git a/comm/suite/editor/components/texzilla/content/TeXZilla.js b/comm/suite/editor/components/texzilla/content/TeXZilla.js
new file mode 100644
index 0000000000..0f8e3e5b29
--- /dev/null
+++ b/comm/suite/editor/components/texzilla/content/TeXZilla.js
@@ -0,0 +1,339 @@
+/* THIS IS A GENERATED FILE. DO NOT EDIT THIS DIRECTLY. */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+(function() {
+"using strict";
+var nb=void 0,tb=!0,xb=null,yb=!1,zb=function(){function c(b,a,c){var $a;c=c||{};for($a=b.length;$a--;c[b[$a]]=a);return c}function Fb(b){return b.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function sb(b){b="negativeveryverythinmathspace negativeverythinmathspace negativemediummathspace negativethickmathspace negativeverythickmathspace negativeveryverythickmathspace veryverythinmathspace verythinmathspace thinmathspace mediummathspace thickmathspace verythickmathspace veryverythickmathspace".split(" ").indexOf(b);
+return(-1===b?0:b-6)/18}function tc(b){b=b.trim();var a=/(-?[0-9]*(?:[0-9]\.?|\.[0-9])[0-9]*)(e[mx]|in|cm|mm|p[xtc]|%)?/.exec(b);return a?(a[1]=parseFloat(a[1]),a[2]||(a[1]*=100,a[2]="%"),{i:a[1],k:a[2]}):{i:sb(b),k:"em"}}function Pb(b){var a="<"+b.tag,c;for(c in b.attributes)b.attributes[c]!==nb&&(a+=" "+c+'="'+b.attributes[c]+'"');b.content?(a+=">",Array.isArray(b.content)?b.content.forEach(function(b){a+=Pb(b)}):a+=b.content,a+="</"+b.tag+">"):a+="/>";return a}function e(b,a,c){return{tag:b,content:a,
+attributes:c}}function ab(b,a,c){return e("mo",Fb(b),{lspace:a!==nb?a+"em":nb,rspace:c!==nb?c+"em":nb})}function Ub(b,a){return e("mi",Fb(b),a?{mathvariant:"normal"}:nb)}function Gb(b){return e("mspace",xb,{width:b+"em"})}function uc(b,a){var c="bold italic bold-italic script bold-script fraktur double-struck bold-fraktur sans-serif bold-sans-serif sans-serif-italic sans-serif-bold-italic monospace initial tailed looped stretched".split(" ").indexOf(a);if(930==b)return b;if(988==b)return 0==c?120778:
+b;if(989==b)return 0==c?120779:b;if(305==b)return 1==c?120484:b;if(567==b)return 1==c?120485:b;var $a;if(65<=b&&90>=b||97<=b&&122>=b){if(12<c)return b;c=(90>=b?b-65:26+b-97)+119808+52*c;$a={119893:8462,119965:8492,119968:8496,119969:8497,119971:8459,119972:8464,119975:8466,119976:8499,119981:8475,119994:8495,119996:8458,120004:8500,120070:8493,120075:8460,120076:8465,120085:8476,120093:8488,120122:8450,120127:8461,120133:8469,120135:8473,120136:8474,120137:8477,120145:8484};return $a[c]?$a[c]:c}if(48<=
+b&&57>=b){switch(c){case 0:c=0;break;case 6:c=1;break;case 8:c=2;break;case 9:c=3;break;case 12:c=4;break;default:return b}return b-48+10*c+120782}if(1536<=b&&1791>=b){switch(c){case 13:$a={1576:126497,1578:126517,1579:126518,1580:126498,1581:126503,1582:126519,1587:126510,1588:126516,1589:126513,1590:126521,1593:126511,1594:126523,1601:126512,1602:126514,1603:126506,1604:126507,1605:126508,1606:126509,1607:126500,1610:126505};break;case 14:$a={1580:126530,1581:126535,1582:126551,1587:126542,1588:126548,
+1589:126545,1590:126553,1593:126543,1594:126555,1602:126546,1604:126539,1606:126541,1610:126537,1647:126559,1722:126557};break;case 16:$a={1576:126561,1578:126581,1579:126582,1580:126562,1581:126567,1582:126583,1587:126574,1588:126580,1589:126577,1590:126585,1591:126568,1592:126586,1593:126575,1594:126587,1601:126576,1602:126578,1603:126570,1605:126572,1606:126573,1607:126564,1610:126569,1646:126588,1697:126590};break;case 15:$a={1575:126592,1576:126593,1578:126613,1579:126614,1580:126594,1581:126599,
+1582:126615,1583:126595,1584:126616,1585:126611,1586:126598,1587:126606,1588:126612,1589:126609,1590:126617,1591:126600,1592:126618,1593:126607,1594:126619,1601:126608,1602:126610,1604:126603,1605:126604,1606:126605,1607:126596,1608:126597,1610:126601};break;case 6:$a={1576:126625,1578:126645,1579:126646,1580:126626,1581:126631,1582:126647,1583:126627,1584:126648,1585:126643,1586:126630,1587:126638,1588:126644,1589:126641,1590:126649,1591:126632,1592:126650,1593:126639,1594:126651,1601:126640,1602:126642,
+1604:126635,1605:126636,1606:126637,1608:126629,1610:126633};break;default:return b}return $a[b]?$a[b]:b}if(913<=b&&937>=b)$a=b-913;else if(945<=b&&969>=b)$a=26+b-945;else switch(b){case 1012:$a=17;break;case 8711:$a=25;break;case 8706:$a=51;break;case 1013:$a=52;break;case 977:$a=53;break;case 1008:$a=54;break;case 981:$a=55;break;case 1009:$a=56;break;case 982:$a=57;break;default:return b}switch(c){case 0:c=0;break;case 1:c=1;break;case 2:c=2;break;case 9:c=3;break;case 11:c=4;break;default:return b}return $a+
+120488+58*c}function vc(b,a){var c=tb,$a;for($a in a)-1!==["mathcolor","mathbackground","mathvariant"].indexOf($a)?"mathvariant"!==$a&&1!=b.length?c=yb:b.forEach(function(b){if(-1!==["mi","mn","mo","mtext","ms"].indexOf(b.tag)){if(b.attributes||(b.attributes={}),!b.attributes[$a])if("mathvariant"===$a){var d;if(!(d="normal"!==a[$a])){if("mi"!==b.tag)d=yb;else{d=b.content;var e=d.codePointAt(0);d=1===d.length&&65535>=e||2===d.length&&65535<e}d=!d}if(d){if(d=a[$a],"normal"!==d){for(var e=b.content,
+g="",m=0;m<e.length;m++){var s=e.codePointAt(m);65535<s?(g+=e[m],m++,g+=e[m]):g+=String.fromCodePoint(uc(s,d))}b.content=g}}else b.attributes[$a]=a[$a]}else b.attributes[$a]=a[$a]}else c=yb}):c=yb;return c}function db(b,a,c){a=a||"mrow";if("mstyle"===a){if(1==b.length&&"mrow"===b[0].tag&&!b[0].attributes)return db(b[0].content,a,c);if(vc(b,c))return db(b)}return 1==b.length&&"mrow"===a&&!c?b[0]:e(a,b,c)}function Ib(b,a,c,$a){return e("math",[e("semantics",[db(b),e("annotation",Fb($a),{encoding:"TeX"})])],
+{xmlns:Qb,display:a?"block":nb,dir:c?"rtl":nb})}function Vb(b){if(!b||b.namespaceURI!==Qb)return xb;if("semantics"===b.tagName)for(b=b.firstElementChild;b;b=b.nextElementSibling){if(b.namespaceURI===Qb&&"annotation"===b.localName&&-1!==wc.indexOf(b.getAttribute("encoding")))return b.textContent}else if(1===b.childElementCount)return Vb(b.firstElementChild);return xb}function xc(b){for(var a="",c,$a,e=0;e<b.length;e++)c=b.charCodeAt(e),128>c?a+=b.charAt(e):55296<=c&&56319>=c?(e++,$a=b.charCodeAt(e),
+a+="&#x"+(1024*(c-55296)+$a-56320+65536).toString(16)+";"):a+="&#x"+c.toString(16)+";";return a}function Rb(){this.e={}}var Wb=[1,4],Xb=[1,6],Yb=[1,7],Zb=[1,8],$b=[1,9],Ab=[68,195,198,200,202,204],m=[1,27],s=[1,124],v=[1,52],x=[1,48],h=[1,28],q=[1,29],p=[1,30],y=[1,31],f=[1,32],u=[1,33],n=[1,34],k=[1,35],r=[1,37],t=[1,38],l=[1,39],w=[1,40],z=[1,41],A=[1,42],B=[1,43],C=[1,44],D=[1,45],E=[1,46],F=[1,47],G=[1,49],H=[1,50],I=[1,51],J=[1,53],K=[1,54],L=[1,55],M=[1,56],N=[1,57],O=[1,58],P=[1,59],Q=[1,60],
+R=[1,61],S=[1,62],T=[1,63],U=[1,64],V=[1,65],W=[1,66],X=[1,67],Y=[1,68],Z=[1,69],$=[1,70],aa=[1,71],ba=[1,72],ca=[1,73],da=[1,74],ea=[1,75],fa=[1,76],ga=[1,77],ha=[1,78],ia=[1,79],ja=[1,80],ka=[1,81],la=[1,82],ma=[1,83],na=[1,84],oa=[1,85],pa=[1,86],qa=[1,87],ra=[1,88],sa=[1,89],ta=[1,90],ua=[1,91],va=[1,92],wa=[1,93],xa=[1,94],ya=[1,95],za=[1,96],Aa=[1,97],Ba=[1,98],Ca=[1,99],Da=[1,100],Ea=[1,101],Fa=[1,102],Ga=[1,103],Ha=[1,104],Ia=[1,105],Ja=[1,106],Ka=[1,107],eb=[1,24],La=[1,108],Ma=[1,109],Na=
+[1,110],Oa=[1,111],Pa=[1,112],Qa=[1,113],Ra=[1,114],Sa=[1,115],Ta=[1,116],Ua=[1,117],Va=[1,118],Wa=[1,119],Xa=[1,120],Ya=[1,121],bb=[1,122],cb=[1,123],fb=[1,16],gb=[1,17],hb=[1,18],ib=[1,19],jb=[1,20],kb=[1,21],lb=[1,22],ac=[6,10,53,64,65,66,144,146,148,150,152,154,156,158,160,162,164,189,192,199,201,203,205],Db=[8,49,50,51,56,57,58,59,60,61,62,63,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,
+114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,145,147,149,151,153,155,157,159,161,163,165,166,173,174,179,180,181,182,183,184,185],mb=[1,134],ub=[6,8,10,49,50,51,53,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,
+141,142,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,173,174,189,192,199,201,203,205],Za=[1,137],g=[6,8,10,49,50,51,53,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,138,139,141,142,144,145,146,147,148,149,150,151,152,153,154,
+155,156,157,158,159,160,161,162,163,164,165,166,169,170,171,173,174,189,192,199,201,203,205],Sb=[1,161],pb=[2,197],qb=[1,217],vb=[1,214],Eb=[6,8,10,49,50,51,53,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,144,145,146,147,148,149,150,151,152,153,154,155,156,
+157,158,159,160,161,162,163,164,165,166,169,170,173,174,189,192,199,201,203,205],bc=[1,241],Bb=[1,243],Cb=[1,244],Mb=[1,259],cc=[4,8],dc=[1,275],ec=[8,49,50,51,56,57,58,59,60,61,62,63,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,138,139,141,142,145,147,149,151,153,155,157,159,161,163,165,166],wb=[1,286],
+Nb=[10,144,146,148,150,152,154,156,158,160,162,164,192],fc=[1,288],Jb=[10,144,146,148,150,152,154,156,158,160,162,164,189,192],gc=[164,189,192],Tb=[10,189,192],Kb=[1,343],Lb=[1,344],hc=[1,352],ic=[1,353],jc=[4,8,49,50,51,56,57,58,59,60,61,62,63,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,
+145,147,149,151,153,155,157,159,161,163,165,166],Ob=[10,21,23],Hb=[10,21,23,25,27],kc=[1,399],lc=[1,400],mc=[1,401],nc=[1,402],oc=[1,403],pc=[1,404],qc=[1,405],rc=[1,406],sc=[10,19,21,23,25,27,29,31,33,35,37,39,41],ob=[10,19,21,23,29,31,33,35,37,39,41],rb={trace:function(){},e:{},la:{error:2,textOptArg:3,"[":4,TEXTOPTARG:5,"]":6,textArg:7,"{":8,TEXTARG:9,"}":10,lengthOptArg:11,lengthArg:12,attrOptArg:13,attrArg:14,tokenContent:15,arrayAlign:16,columnAlign:17,collayout:18,COLLAYOUT:19,colalign:20,
+COLALIGN:21,rowalign:22,ROWALIGN:23,rowspan:24,ROWSPAN:25,colspan:26,COLSPAN:27,align:28,ALIGN:29,eqrows:30,EQROWS:31,eqcols:32,EQCOLS:33,rowlines:34,ROWLINES:35,collines:36,COLLINES:37,frame:38,FRAME:39,padding:40,PADDING:41,cellopt:42,celloptList:43,rowopt:44,arrayopt:45,arrayoptList:46,rowoptList:47,left:48,LEFT:49,OPFS:50,".":51,right:52,RIGHT:53,closedTerm:54,styledExpression:55,BIG:56,BBIG:57,BIGG:58,BBIGG:59,BIGL:60,BBIGL:61,BIGGL:62,BBIGGL:63,TEXATOP:64,TEXOVER:65,TEXCHOOSE:66,NUM:67,TEXT:68,
+A:69,AILL:70,AIUL:71,AILG:72,AIUG:73,F:74,MI:75,MN:76,MO:77,OP:78,OPS:79,OPAS:80,MS:81,MTEXT:82,HIGH_SURROGATE:83,LOW_SURROGATE:84,BMP_CHARACTER:85,OPERATORNAME:86,MATHOP:87,MATHBIN:88,MATHREL:89,FRAC:90,ROOT:91,SQRT:92,UNDERSET:93,OVERSET:94,UNDEROVERSET:95,XARROW:96,MATHRLAP:97,MATHLLAP:98,MATHCLAP:99,PHANTOM:100,TFRAC:101,BINOM:102,TBINOM:103,PMOD:104,UNDERBRACE:105,UNDERLINE:106,OVERBRACE:107,ACCENT:108,ACCENTNS:109,BOXED:110,SLASH:111,QUAD:112,QQUAD:113,NEGSPACE:114,NEGMEDSPACE:115,NEGTHICKSPACE:116,
+THINSPACE:117,MEDSPACE:118,THICKSPACE:119,SPACE:120,MATHRAISEBOX:121,MATHBB:122,MATHBF:123,MATHBIT:124,MATHSCR:125,MATHBSCR:126,MATHSF:127,MATHFRAK:128,MATHIT:129,MATHTT:130,MATHRM:131,HREF:132,STATUSLINE:133,TOOLTIP:134,TOGGLE:135,BTOGGLE:136,closedTermList:137,ETOGGLE:138,TENSOR:139,subsupList:140,MULTI:141,BMATRIX:142,tableRowList:143,EMATRIX:144,BGATHERED:145,EGATHERED:146,BPMATRIX:147,EPMATRIX:148,BBMATRIX:149,EBMATRIX:150,BVMATRIX:151,EVMATRIX:152,BBBMATRIX:153,EBBMATRIX:154,BVVMATRIX:155,EVVMATRIX:156,
+BSMALLMATRIX:157,ESMALLMATRIX:158,BCASES:159,ECASES:160,BALIGNED:161,EALIGNED:162,BARRAY:163,EARRAY:164,SUBSTACK:165,ARRAY:166,ARRAYOPTS:167,compoundTerm:168,_:169,"^":170,OPP:171,opm:172,OPM:173,FM:174,compoundTermList:175,subsupTermScript:176,subsupTerm:177,textstyle:178,DISPLAYSTYLE:179,TEXTSTYLE:180,TEXTSIZE:181,SCRIPTSIZE:182,SCRIPTSCRIPTSIZE:183,COLOR:184,BGCOLOR:185,tableCell:186,CELLOPTS:187,tableCellList:188,COLSEP:189,tableRow:190,ROWOPTS:191,ROWSEP:192,document:193,documentItemList:194,
+EOF:195,documentItem:196,mathItem:197,STARTMATH0:198,ENDMATH0:199,STARTMATH1:200,ENDMATH1:201,STARTMATH2:202,ENDMATH2:203,STARTMATH3:204,ENDMATH3:205,$accept:0,$end:1},z:{2:"error",4:"[",5:"TEXTOPTARG",6:"]",8:"{",9:"TEXTARG",10:"}",19:"COLLAYOUT",21:"COLALIGN",23:"ROWALIGN",25:"ROWSPAN",27:"COLSPAN",29:"ALIGN",31:"EQROWS",33:"EQCOLS",35:"ROWLINES",37:"COLLINES",39:"FRAME",41:"PADDING",49:"LEFT",50:"OPFS",51:".",53:"RIGHT",56:"BIG",57:"BBIG",58:"BIGG",59:"BBIGG",60:"BIGL",61:"BBIGL",62:"BIGGL",63:"BBIGGL",
+64:"TEXATOP",65:"TEXOVER",66:"TEXCHOOSE",67:"NUM",68:"TEXT",69:"A",70:"AILL",71:"AIUL",72:"AILG",73:"AIUG",74:"F",75:"MI",76:"MN",77:"MO",78:"OP",79:"OPS",80:"OPAS",81:"MS",82:"MTEXT",83:"HIGH_SURROGATE",84:"LOW_SURROGATE",85:"BMP_CHARACTER",86:"OPERATORNAME",87:"MATHOP",88:"MATHBIN",89:"MATHREL",90:"FRAC",91:"ROOT",92:"SQRT",93:"UNDERSET",94:"OVERSET",95:"UNDEROVERSET",96:"XARROW",97:"MATHRLAP",98:"MATHLLAP",99:"MATHCLAP",100:"PHANTOM",101:"TFRAC",102:"BINOM",103:"TBINOM",104:"PMOD",105:"UNDERBRACE",
+106:"UNDERLINE",107:"OVERBRACE",108:"ACCENT",109:"ACCENTNS",110:"BOXED",111:"SLASH",112:"QUAD",113:"QQUAD",114:"NEGSPACE",115:"NEGMEDSPACE",116:"NEGTHICKSPACE",117:"THINSPACE",118:"MEDSPACE",119:"THICKSPACE",120:"SPACE",121:"MATHRAISEBOX",122:"MATHBB",123:"MATHBF",124:"MATHBIT",125:"MATHSCR",126:"MATHBSCR",127:"MATHSF",128:"MATHFRAK",129:"MATHIT",130:"MATHTT",131:"MATHRM",132:"HREF",133:"STATUSLINE",134:"TOOLTIP",135:"TOGGLE",136:"BTOGGLE",138:"ETOGGLE",139:"TENSOR",141:"MULTI",142:"BMATRIX",144:"EMATRIX",
+145:"BGATHERED",146:"EGATHERED",147:"BPMATRIX",148:"EPMATRIX",149:"BBMATRIX",150:"EBMATRIX",151:"BVMATRIX",152:"EVMATRIX",153:"BBBMATRIX",154:"EBBMATRIX",155:"BVVMATRIX",156:"EVVMATRIX",157:"BSMALLMATRIX",158:"ESMALLMATRIX",159:"BCASES",160:"ECASES",161:"BALIGNED",162:"EALIGNED",163:"BARRAY",164:"EARRAY",165:"SUBSTACK",166:"ARRAY",167:"ARRAYOPTS",169:"_",170:"^",171:"OPP",173:"OPM",174:"FM",179:"DISPLAYSTYLE",180:"TEXTSTYLE",181:"TEXTSIZE",182:"SCRIPTSIZE",183:"SCRIPTSCRIPTSIZE",184:"COLOR",185:"BGCOLOR",
+187:"CELLOPTS",189:"COLSEP",191:"ROWOPTS",192:"ROWSEP",195:"EOF",198:"STARTMATH0",199:"ENDMATH0",200:"STARTMATH1",201:"ENDMATH1",202:"STARTMATH2",203:"ENDMATH2",204:"STARTMATH3",205:"ENDMATH3"},W:[0,[3,3],[7,3],[11,3],[12,3],[13,1],[14,1],[15,1],[16,1],[17,1],[18,2],[20,2],[22,2],[24,2],[26,2],[28,2],[30,2],[32,2],[34,2],[36,2],[38,2],[40,2],[42,1],[42,1],[42,1],[42,1],[43,1],[43,2],[44,1],[44,1],[45,1],[45,1],[45,1],[45,1],[45,1],[45,1],[45,1],[45,1],[45,1],[45,1],[46,1],[46,2],[47,1],[47,2],[48,
+2],[48,2],[52,2],[52,2],[54,2],[54,3],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,3],[54,5],[54,5],[54,5],[54,5],[54,5],[54,5],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,2],[54,2],[54,2],[54,1],[54,1],[54,1],[54,1],[54,1],[54,2],[54,4],[54,2],[54,2],[54,1],[54,2],[54,2],[54,2],[54,2],[54,3],[54,3],[54,2],[54,5],[54,3],[54,3],[54,4],[54,5],[54,2],[54,2],[54,2],[54,2],[54,2],[54,3],[54,3],[54,3],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,1],[54,1],[54,
+1],[54,1],[54,1],[54,1],[54,1],[54,1],[54,4],[54,5],[54,4],[54,3],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,2],[54,3],[54,3],[54,3],[54,3],[54,3],[54,5],[54,8],[54,7],[54,7],[54,3],[54,3],[54,3],[54,3],[54,3],[54,3],[54,3],[54,3],[54,3],[54,3],[54,5],[54,4],[54,4],[54,4],[54,8],[137,1],[137,2],[168,3],[168,5],[168,4],[168,5],[168,4],[168,3],[168,3],[168,2],[168,1],[168,5],[168,5],[168,3],[168,3],[168,1],[172,1],[172,1],[175,1],[175,2],[176,1],[176,1],[177,4],[177,2],[177,
+2],[177,3],[140,1],[140,2],[178,1],[178,1],[178,1],[178,1],[178,1],[178,2],[178,2],[55,2],[55,1],[186,0],[186,5],[186,1],[188,1],[188,3],[190,5],[190,1],[143,1],[143,3],[193,2],[194,1],[194,2],[196,1],[196,1],[197,2],[197,3],[197,2],[197,3],[197,3],[197,3]],H:function(b,a,c,$a,g,d){b=d.length-1;switch(g){case 1:this.b=d[b-1].replace(/\\[\\\]]/g,function(a){return a.slice(1)});this.b=Fb(this.b);break;case 2:this.b=d[b-1].replace(/\\[\\\}]/g,function(a){return a.slice(1)});this.b=Fb(this.b);break;case 3:case 4:this.b=
+tc(d[b-1]);break;case 5:case 6:this.b=d[b].replace(/"/g,"&#x22;");break;case 7:this.b=d[b].replace(/\s+/g," ").replace(/^ | $/g," ");break;case 8:d[b]=d[b].trim();if("t"===d[b])this.b="axis 1";else if("c"===d[b])this.b="center";else if("b"===d[b])this.b="axis -1";else throw"Unknown array alignment";break;case 9:this.b="";d[b]=d[b].replace(/\s+/g,"");for($a=0;$a<d[b].length;$a++)"c"===d[b][$a]?this.b+=" center":"l"===d[b][$a]?this.b+=" left":"r"===d[b][$a]&&(this.b+=" right");if(this.b.length)this.b=
+this.b.slice(1);else throw"Invalid column alignments";break;case 10:case 11:this.b={columnalign:d[b]};break;case 12:this.b={rowalign:d[b]};break;case 13:this.b={rowspan:d[b]};break;case 14:this.b={colspan:d[b]};break;case 15:this.b={align:d[b]};break;case 16:this.b={equalrows:d[b]};break;case 17:this.b={equalcolumns:d[b]};break;case 18:this.b={rowlines:d[b]};break;case 19:this.b={columnlines:d[b]};break;case 20:this.b={frame:d[b]};break;case 21:this.b={rowspacing:d[b],columnspacing:d[b]};break;case 22:case 23:case 24:case 25:case 26:case 28:case 29:case 30:case 31:case 32:case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 42:case 170:case 175:case 180:case 181:case 186:case 196:case 207:case 209:this.b=
+d[b];break;case 27:case 41:case 43:this.b=Object.assign(d[b-1],d[b]);break;case 44:case 46:this.b=ab(d[b]);break;case 45:case 47:this.b="";break;case 48:this.b=e("mrow");break;case 49:this.b=db(d[b-1]);break;case 50:case 54:this.b=e("mo",d[b],{maxsize:"1.2em",minsize:"1.2em"});break;case 51:case 55:this.b=e("mo",d[b],{maxsize:"1.8em",minsize:"1.8em"});break;case 52:case 56:this.b=e("mo",d[b],{maxsize:"2.4em",minsize:"2.4em"});break;case 53:case 57:this.b=e("mo",d[b],{maxsize:"3em",minsize:"3em"});
+break;case 58:this.b=e("mrow",[d[b-2],db(d[b-1]),d[b]]);break;case 59:this.b=e("mfrac",[db(d[b-3]),db(d[b-1])],{linethickness:"0px"});break;case 60:this.b=e("mfrac",[db(d[b-3]),db(d[b-1])],{linethickness:"0px"});this.b=e("mrow",[d[b-4],this.b,d[b]]);break;case 61:this.b=e("mfrac",[db(d[b-3]),db(d[b-1])]);break;case 62:this.b=e("mfrac",[db(d[b-3]),db(d[b-1])]);this.b=e("mrow",[d[b-4],this.b,d[b]]);break;case 63:this.b=e("mfrac",[db(d[b-3]),db(d[b-1])],{linethickness:"0px"});this.b=e("mrow",[ab("("),
+this.b,ab(")")]);break;case 64:this.b=e("mfrac",[db(d[b-3]),db(d[b-1])],{linethickness:"0px"});this.b=e("mrow",[d[b-4],this.b,d[b]]);this.b=e("mrow",[ab("("),this.b,ab(")")]);break;case 65:case 74:this.b=e("mn",d[b]);break;case 66:case 83:case 85:this.b=e("mtext",d[b]);break;case 67:case 68:case 69:case 70:this.b=Ub(d[b]);break;case 71:this.b=Ub(d[b],tb);break;case 72:case 177:this.b=ab(d[b],0,0);break;case 73:this.b=e("mi",d[b]);break;case 75:case 76:case 77:case 176:this.b=ab(d[b]);break;case 78:case 79:case 80:this.b=
+e("mo",d[b],{stretchy:"false"});break;case 81:this.b=e("ms",d[b]);break;case 82:this.b=e("ms",d[b],{lquote:d[b-2],rquote:d[b-1]});break;case 84:this.b=e("mtext",d[b-1]+d[b]);break;case 86:this.b=ab(d[b],0,sb("thinmathspace"));break;case 87:this.b=ab(d[b],sb("thinmathspace"),sb("thinmathspace"));break;case 88:this.b=ab(d[b],sb("mediummathspace"),sb("mediummathspace"));break;case 89:this.b=ab(d[b],sb("thickmathspace"),sb("thickmathspace"));break;case 90:this.b=e("mfrac",[d[b-1],d[b]]);break;case 91:this.b=
+e("mroot",[d[b],d[b-1]]);break;case 92:this.b=e("msqrt",[d[b]]);break;case 93:this.b=e("mroot",[d[b],db(d[b-2])]);break;case 94:this.b=e("munder",[d[b],d[b-1]]);break;case 95:this.b=e("mover",[d[b],d[b-1]]);break;case 96:this.b=e("munderover",[d[b],d[b-2],d[b-1]]);break;case 97:this.b="mrow"===d[b].tag&&!d[b].content&&!d[b].attributes?e("munder",[ab(d[b-4]),db(d[b-2])]):e("munderover",[ab(d[b-4]),db(d[b-2]),d[b]]);break;case 98:this.b=e("mover",[ab(d[b-1]),d[b]]);break;case 99:this.b=e("mpadded",
+[d[b]],{width:"0em"});break;case 100:this.b=e("mpadded",[d[b]],{width:"0em",lspace:"-100%width"});break;case 101:this.b=e("mpadded",[d[b]],{width:"0em",lspace:"-50%width"});break;case 102:this.b=e("mphantom",[d[b]]);break;case 103:this.b=e("mfrac",[d[b-1],d[b]]);this.b=db([this.b],"mstyle",{displaystyle:"false"});break;case 104:this.b=e("mfrac",[d[b-1],d[b]],{linethickness:"0px"});this.b=e("mrow",[ab("("),this.b,ab(")")]);break;case 105:this.b=e("mfrac",[d[b-1],d[b]],{linethickness:"0px"});this.b=
+db([this.b],"mstyle",{displaystyle:"false"});this.b=e("mrow",[ab("("),this.b,ab(")")]);break;case 106:this.b=e("mrow",[ab("(",sb("mediummathspace")),ab("mod",nb,sb("thinmathspace")),d[b],ab(")",nb,sb("mediummathspace"))]);break;case 107:this.b=e("munder",[d[b],ab("⏟")]);break;case 108:this.b=e("munder",[d[b],ab("_")]);break;case 109:this.b=e("mover",[d[b],ab("⏞")]);break;case 110:this.b=e("mover",[d[b],ab(d[b-1])]);break;case 111:this.b=e("mover",[d[b],e("mo",d[b-1],{stretchy:"false"})]);break;case 112:this.b=
+e("menclose",[d[b]],{notation:"box"});break;case 113:this.b=e("menclose",[d[b]],{notation:"updiagonalstrike"});break;case 114:this.b=Gb(1);break;case 115:this.b=Gb(2);break;case 116:this.b=Gb(sb("negativethinmathspace"));break;case 117:this.b=Gb(sb("negativemediummathspace"));break;case 118:this.b=Gb(sb("negativethickmathspace"));break;case 119:this.b=Gb(sb("thinmathspace"));break;case 120:this.b=Gb(sb("mediummathspace"));break;case 121:this.b=Gb(sb("thickmathspace"));break;case 122:this.b=e("mspace",
+xb,{height:"."+d[b-2]+"ex",depth:"."+d[b-1]+"ex",width:"."+d[b]+"em"});break;case 123:this.b=e("mpadded",[d[b]],{voffset:d[b-3].i+d[b-3].k,height:d[b-2].i+d[b-2].k,depth:d[b-1].i+d[b-1].k});break;case 124:this.b=e("mpadded",[d[b]],{voffset:d[b-2].i+d[b-2].k,height:d[b-1].i+d[b-1].k,depth:0>d[b-2].i?"+"+-d[b-2].i+d[b-2].k:"depth"});break;case 125:$a={voffset:d[b-1].i+d[b-1].k};0<=d[b-1].i?$a.height="+"+d[b-1].i+d[b-1].k:($a.height="0pt",$a.depth="+"+-d[b-1].i+d[b-1].k);this.b=e("mpadded",[d[b]],$a);
+break;case 126:this.b=db([d[b]],"mstyle",{mathvariant:"double-struck"});break;case 127:this.b=db([d[b]],"mstyle",{mathvariant:"bold"});break;case 128:this.b=db([d[b]],"mstyle",{mathvariant:"bold-italic"});break;case 129:this.b=db([d[b]],"mstyle",{mathvariant:"script"});break;case 130:this.b=db([d[b]],"mstyle",{mathvariant:"bold-script"});break;case 131:this.b=db([d[b]],"mstyle",{mathvariant:"sans-serif"});break;case 132:this.b=db([d[b]],"mstyle",{mathvariant:"fraktur"});break;case 133:this.b=db([d[b]],
+"mstyle",{mathvariant:"italic"});break;case 134:this.b=db([d[b]],"mstyle",{mathvariant:"monospace"});break;case 135:this.b=db([d[b]],"mstyle",{mathvariant:"normal"});break;case 136:this.b=e("mrow",[d[b]],$a.v?xb:{href:d[b-1]});break;case 137:this.b=$a.v?d[b]:e("maction",[d[b],e("mtext",d[b-1])],{actiontype:"statusline"});break;case 138:this.b=$a.v?d[b]:e("maction",[d[b],e("mtext",d[b-1])],{actiontype:"tooltip"});break;case 139:this.b=$a.v?d[b]:e("maction",[d[b-1],d[b]],{actiontype:"toggle",selection:"2"});
+break;case 140:this.b=$a.v?e("mrow",d[b-1]):e("maction",d[b-1],{actiontype:"toggle"});break;case 141:case 144:this.b=e("mmultiscripts",[d[b-3]].concat(d[b-1]));break;case 142:this.b=e("mmultiscripts",[d[b-3]].concat(d[b-1]).concat(e("mprescripts")).concat(d[b-5]));break;case 143:this.b=e("mmultiscripts",[d[b-2],e("mprescripts")].concat(d[b-4]));break;case 145:this.b=e("mtable",d[b-1],{displaystyle:"false",rowspacing:"0.5ex"});break;case 146:this.b=e("mtable",d[b-1],{displaystyle:"true",rowspacing:"1.0ex"});
+break;case 147:this.b=e("mtable",d[b-1],{displaystyle:"false",rowspacing:"0.5ex"});this.b=e("mrow",[ab("("),this.b,ab(")")]);break;case 148:this.b=e("mtable",d[b-1],{displaystyle:"false",rowspacing:"0.5ex"});this.b=e("mrow",[ab("["),this.b,ab("]")]);break;case 149:this.b=e("mtable",d[b-1],{displaystyle:"false",rowspacing:"0.5ex"});this.b=e("mrow",[ab("|"),this.b,ab("|")]);break;case 150:this.b=e("mtable",d[b-1],{displaystyle:"false",rowspacing:"0.5ex"});this.b=e("mrow",[ab("{"),this.b,ab("}")]);break;
+case 151:this.b=e("mtable",d[b-1],{displaystyle:"false",rowspacing:"0.5ex"});this.b=e("mrow",[ab("‖"),this.b,ab("‖")]);break;case 152:this.b=e("mtable",d[b-1],{displaystyle:"false",rowspacing:"0.5ex"});this.b=db([this.b],"mstyle",{scriptlevel:"2"});break;case 153:this.b=e("mtable",d[b-1],{displaystyle:"false",columnalign:"left left"});this.b=e("mrow",[ab("{"),this.b]);break;case 154:this.b=e("mtable",d[b-1],{displaystyle:"true",columnalign:"right left right left right left right left right left",
+columnspacing:"0em"});break;case 155:this.b=e("mtable",d[b-1],{displaystyle:"false",rowspacing:"0.5ex",align:d[b-3],columnalign:d[b-2]});break;case 156:this.b=e("mtable",d[b-1],{displaystyle:"false",rowspacing:"0.5ex",columnalign:d[b-2]});break;case 157:this.b=e("mtable",d[b-1],{displaystyle:"false",columnalign:"center",rowspacing:"0.5ex"});break;case 158:this.b=e("mtable",d[b-1],{displaystyle:"false"});break;case 159:this.b=e("mtable",d[b-1],Object.assign(d[b-3],{displaystyle:"false"}));break;case 160:this.b=
+[d[b]];break;case 161:this.b=d[b-1].concat([d[b]]);break;case 162:this.b=e("mmultiscripts",[d[b-1]].concat(d[b]));break;case 163:this.b=e("msubsup",[d[b-4],d[b-2],d[b]]);break;case 164:this.b=e("msubsup",[d[b-3],d[b-1],ab(d[b])]);break;case 165:this.b=e("msubsup",[d[b-4],d[b],d[b-2]]);break;case 166:this.b=e("msubsup",[d[b-3],d[b],ab(d[b-2])]);break;case 167:this.b=e("msub",[d[b-2],d[b]]);break;case 168:this.b=e("msup",[d[b-2],d[b]]);break;case 169:this.b=e("msup",[d[b-1],ab(d[b])]);break;case 171:this.b=
+e("munderover",[d[b-4],d[b-2],d[b]]);break;case 172:this.b=e("munderover",[d[b-4],d[b],d[b-2]]);break;case 173:this.b=e("munder",[d[b-2],d[b]]);break;case 174:this.b=e("mover",[d[b-2],d[b]]);break;case 178:case 200:case 204:this.b=[d[b]];break;case 179:this.b=d[b-1].concat([d[b]]);break;case 182:this.b=[d[b-2],d[b]];break;case 183:this.b=[d[b],e("none")];break;case 184:case 185:this.b=[e("none"),d[b]];break;case 187:this.b=d[b-1].concat(d[b]);break;case 188:this.b={displaystyle:"true"};break;case 189:this.b=
+{displaystyle:"false"};break;case 190:this.b={scriptlevel:"0"};break;case 191:this.b={scriptlevel:"1"};break;case 192:this.b={scriptlevel:"2"};break;case 193:this.b={mathcolor:d[b]};break;case 194:this.b={mathbackground:d[b]};break;case 195:this.b=[db(d[b],"mstyle",d[b-1])];break;case 197:this.b=e("mtd",[]);break;case 198:this.b=db(d[b],"mtd",d[b-2]);break;case 199:this.b=db(d[b],"mtd");break;case 201:case 205:this.b=d[b-2].concat([d[b]]);break;case 202:this.b=this.b=e("mtr",d[b],d[b-2]);break;case 203:this.b=
+e("mtr",d[b]);break;case 206:return this.b=d[b-1];case 208:this.b=d[b-1]+d[b];break;case 210:this.b=Pb(d[b]);break;case 211:this.b=Ib([e("mrow")],yb,yb,$a.t);break;case 212:this.b=Ib(d[b-1],yb,yb,$a.t);break;case 213:this.b=Ib([e("mrow")],tb,yb,$a.t);break;case 214:this.b=Ib(d[b-1],tb,yb,$a.t);break;case 215:this.b=Ib(d[b-1],yb,yb,$a.t);break;case 216:this.b=Ib(d[b-1],tb,yb,$a.t)}},ma:[{68:Wb,193:1,194:2,196:3,197:5,198:Xb,200:Yb,202:Zb,204:$b},{1:[3]},{68:Wb,195:[1,10],196:11,197:5,198:Xb,200:Yb,
+202:Zb,204:$b},c(Ab,[2,207]),c(Ab,[2,209]),c(Ab,[2,210]),{8:m,48:36,49:s,50:v,51:x,54:25,55:13,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,
+130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,199:[1,12]},{8:m,48:36,49:s,50:v,51:x,54:25,55:126,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,
+101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,201:[1,125]},{8:m,48:36,49:s,50:v,51:x,54:25,55:127,56:h,
+57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,
+153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},{8:m,48:36,49:s,50:v,51:x,54:25,55:128,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,
+117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},{1:[2,206]},c(Ab,[2,208]),c(Ab,[2,211]),{199:[1,129]},{8:m,48:36,49:s,50:v,51:x,54:25,55:130,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,
+74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,
+173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},c(ac,[2,196],{54:25,172:26,48:36,168:131,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,
+124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb}),c(Db,[2,188]),c(Db,[2,189]),c(Db,[2,190]),c(Db,[2,191]),c(Db,[2,192]),{7:133,8:mb,14:132},{7:133,8:mb,14:135},c(ub,[2,178]),{8:m,48:36,49:s,50:v,51:x,54:136,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,
+87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(ub,[2,170],{169:[1,138],170:[1,139],171:[1,140]}),c(ub,[2,175],{169:[1,
+141],170:[1,142]}),{8:m,10:[1,143],48:36,49:s,50:v,51:x,54:25,55:144,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,
+134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},{50:[1,145]},{50:[1,146]},{50:[1,147]},{50:[1,148]},{50:[1,149]},{50:[1,150]},{50:[1,151]},{50:[1,152]},{8:m,48:36,49:s,50:v,51:x,54:25,55:153,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,
+88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,
+184:kb,185:lb},c(g,[2,65]),c(g,[2,66]),c(g,[2,67]),c(g,[2,68]),c(g,[2,69]),c(g,[2,70]),c(g,[2,71]),c(g,[2,72]),{7:155,8:mb,15:154},{7:155,8:mb,15:156},{7:155,8:mb,15:157},c(g,[2,76]),c(g,[2,77]),c(g,[2,78]),c(g,[2,79]),c(g,[2,80]),{3:160,4:Sb,7:155,8:mb,13:159,15:158},{7:155,8:mb,15:162},{84:[1,163]},c(g,[2,85]),{7:164,8:mb},{7:165,8:mb},{7:166,8:mb},{7:167,8:mb},{8:m,48:36,49:s,50:v,51:x,54:168,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,
+80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:169,56:h,57:q,
+58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,
+155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{4:[1,171],8:m,48:36,49:s,50:v,51:x,54:170,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,
+130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:172,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,
+117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:173,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,
+104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:174,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,
+87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{4:[1,175],8:m,48:36,49:s,50:v,51:x,54:176,56:h,57:q,58:p,59:y,60:f,61:u,
+62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,
+161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:177,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,
+135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:178,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,
+122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:179,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,
+109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:180,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,
+94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:181,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,
+74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,
+49:s,50:v,51:x,54:182,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,
+145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:183,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,
+127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:184,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,
+114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:185,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,
+101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:186,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,
+81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:187,56:h,57:q,58:p,
+59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,
+157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:188,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,
+133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:189,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,
+120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:190,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,
+107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:191,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,
+91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(g,[2,114]),c(g,[2,115]),c(g,[2,116]),c(g,[2,117]),c(g,[2,118]),c(g,[2,119]),c(g,[2,120]),
+c(g,[2,121]),{7:192,8:mb},{8:[1,194],12:193},{8:m,48:36,49:s,50:v,51:x,54:195,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,
+132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:196,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,
+119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:197,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,
+106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:198,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,
+89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:199,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,
+69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,
+166:Ya},{8:m,48:36,49:s,50:v,51:x,54:200,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,
+141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:201,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,
+125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:202,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,
+112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:203,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,
+98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:204,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,
+78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{7:133,8:mb,14:205},{7:206,8:mb},
+{7:207,8:mb},{8:m,48:36,49:s,50:v,51:x,54:208,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,
+139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:210,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,
+124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,137:209,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:[1,211]},c([144,189,192],pb,{178:14,175:15,168:23,54:25,172:26,48:36,143:212,190:213,188:215,186:216,55:218,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,
+94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),c([146,189,192],pb,{178:14,175:15,
+168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:219,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,
+131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),c([148,189,192],pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:220,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,
+92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),c([150,189,192],pb,
+{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:221,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,
+129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),c([152,189,192],pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:222,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,
+89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),c([154,
+189,192],pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:223,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,
+128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),c([156,189,192],pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:224,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,
+88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),
+c([158,189,192],pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:225,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,
+127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),c([160,189,192],pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:226,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,
+86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,
+191:vb}),c([162,189,192],pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:227,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,
+125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),{3:230,4:Sb,7:231,8:mb,16:228,17:229},{8:[1,232]},{8:[1,233]},c(Eb,[2,176]),c(Eb,[2,177]),{50:[1,234],51:[1,235]},c(Ab,[2,213]),{201:[1,236]},{203:[1,237]},{205:[1,238]},c(Ab,[2,212]),c(ac,[2,195]),c(ub,[2,179]),c(Db,[2,193]),c([8,10,
+19,21,23,25,27,29,31,33,35,37,39,41,49,50,51,56,57,58,59,60,61,62,63,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,145,147,149,151,153,155,157,159,161,163,165,166,173,174,179,180,181,182,183,184,185],[2,6]),{9:[1,239]},c(Db,[2,194]),{8:bc,140:240,169:Bb,170:Cb,177:242},{8:m,48:36,49:s,50:v,
+51:x,54:245,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,
+149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:246,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,
+129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:247,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,
+116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(ub,[2,169],{169:[1,248]}),{8:m,48:36,49:s,50:v,51:x,54:249,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,
+98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:250,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,
+78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(g,[2,48]),{10:[1,251],64:[1,252],
+65:[1,253],66:[1,254]},c(g,[2,50]),c(g,[2,51]),c(g,[2,52]),c(g,[2,53]),c(g,[2,54]),c(g,[2,55]),c(g,[2,56]),c(g,[2,57]),{52:255,53:Mb,64:[1,256],65:[1,257],66:[1,258]},c(g,[2,73]),c(g,[2,7]),c(g,[2,74]),c(g,[2,75]),c(g,[2,81]),{3:160,4:Sb,13:260},c(cc,[2,5]),{5:[1,261]},c(g,[2,83]),c(g,[2,84]),c(g,[2,86]),c(g,[2,87]),c(g,[2,88]),c(g,[2,89]),{8:m,48:36,49:s,50:v,51:x,54:262,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,
+86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:263,56:h,57:q,58:p,59:y,60:f,61:u,62:n,
+63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,
+161:Va,163:Wa,165:Xa,166:Ya},c(g,[2,92]),{8:m,48:36,49:s,50:v,51:x,54:25,55:264,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,
+132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},{8:m,48:36,49:s,50:v,51:x,54:265,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,
+106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:266,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,
+89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:267,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,
+69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,
+166:Ya},{8:m,48:36,49:s,50:v,51:x,54:25,55:268,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,
+139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},c(g,[2,98]),c(g,[2,99]),c(g,[2,100]),c(g,[2,101]),c(g,[2,102]),{8:m,48:36,49:s,50:v,51:x,54:269,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,
+102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:270,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,
+83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:271,56:h,57:q,58:p,59:y,60:f,
+61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,
+159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(g,[2,106]),c(g,[2,107]),c(g,[2,108]),c(g,[2,109]),c(g,[2,110]),c(g,[2,111]),c(g,[2,112]),c(g,[2,113]),{7:272,8:mb},{4:dc,8:m,11:273,48:36,49:s,50:v,51:x,54:274,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,
+115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{9:[1,276]},c(g,[2,126]),c(g,[2,127]),c(g,[2,128]),c(g,[2,129]),c(g,[2,130]),c(g,[2,131]),c(g,[2,132]),c(g,[2,133]),c(g,[2,134]),c(g,[2,135]),{8:m,48:36,49:s,50:v,51:x,54:277,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,
+73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,
+49:s,50:v,51:x,54:278,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,
+145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:279,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,
+127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:280,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,
+114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:282,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,
+101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,138:[1,281],139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(ec,[2,160]),{10:[1,284],140:283,169:Bb,170:Cb,177:242},{144:[1,285],192:wb},c(Nb,[2,204]),{8:[1,287]},c(Nb,[2,203],{189:fc}),c(Jb,
+[2,200]),{8:[1,289]},c(Jb,[2,199]),{146:[1,290],192:wb},{148:[1,291],192:wb},{150:[1,292],192:wb},{152:[1,293],192:wb},{154:[1,294],192:wb},{156:[1,295],192:wb},{158:[1,296],192:wb},{160:[1,297],192:wb},{162:[1,298],192:wb},{7:231,8:mb,17:299},c(gc,pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:300,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,
+90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),{8:[2,8]},
+c([8,49,50,51,56,57,58,59,60,61,62,63,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,145,147,149,151,153,155,157,159,161,163,164,165,166,173,174,179,180,181,182,183,184,185,187,189,191,192],[2,9]),c(Tb,pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:301,8:m,49:s,
+50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,
+149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),c(Tb,pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:302,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,
+107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,167:[1,303],173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),c(Db,[2,44]),c(Db,[2,45]),c(Ab,[2,214]),c(Ab,[2,215]),c(Ab,[2,216]),{10:[1,304]},c(ub,[2,162],{177:305,
+169:Bb,170:Cb}),{140:306,169:Bb,170:Cb,177:242},c(Eb,[2,186]),{8:m,48:36,49:s,50:v,51:x,54:309,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,
+130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,170:[1,308],172:310,173:bb,174:cb,176:307},{8:m,48:36,49:s,50:v,51:x,54:309,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,
+111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,172:310,173:bb,174:cb,176:311},{8:bc},c(ub,[2,167],{170:[1,312],171:[1,313]}),c(ub,[2,168],{169:[1,314]}),{8:m,48:36,49:s,50:v,51:x,54:315,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,
+74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(ub,[2,173],
+{170:[1,316]}),c(ub,[2,174],{169:[1,317]}),c(g,[2,49]),{8:m,48:36,49:s,50:v,51:x,54:25,55:318,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,
+130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},{8:m,48:36,49:s,50:v,51:x,54:25,55:319,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,
+103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},{8:m,48:36,49:s,50:v,51:x,54:25,55:320,56:h,57:q,58:p,59:y,60:f,61:u,
+62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,
+161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},c(g,[2,58]),{8:m,48:36,49:s,50:v,51:x,54:25,55:321,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,
+119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},{8:m,48:36,49:s,50:v,51:x,54:25,55:322,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,
+88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,
+184:kb,185:lb},{8:m,48:36,49:s,50:v,51:x,54:25,55:323,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,
+136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},{50:[1,324],51:[1,325]},{7:155,8:mb,15:326},{6:[1,327]},c(g,[2,90]),c(g,[2,91]),{6:[1,328]},c(g,[2,94]),c(g,[2,95]),{8:m,48:36,49:s,50:v,51:x,54:329,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,
+90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{6:[1,330]},c(g,[2,103]),c(g,[2,104]),c(g,[2,105]),{7:331,8:mb},{4:dc,8:m,11:332,48:36,
+49:s,50:v,51:x,54:333,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,
+145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(g,[2,125]),{5:[1,334]},{10:[1,335]},c(g,[2,136]),c(g,[2,137]),c(g,[2,138]),c(g,[2,139]),c(g,[2,140]),c(ec,[2,161]),{10:[1,336],169:Bb,170:Cb,177:305},{8:m,48:36,49:s,50:v,51:x,54:337,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,
+105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(g,[2,145]),c(Jb,pb,{178:14,175:15,168:23,54:25,172:26,48:36,188:215,186:216,55:218,190:338,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,
+71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,
+173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),{20:341,21:Kb,22:342,23:Lb,44:340,47:339},c(Jb,pb,{178:14,175:15,168:23,54:25,172:26,48:36,55:218,186:345,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,
+114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb}),{20:348,21:Kb,22:349,23:Lb,24:350,25:hc,26:351,27:ic,42:347,43:346},c(g,[2,146]),c(g,[2,147]),c(g,[2,148]),c(g,[2,149]),c(g,[2,150]),c(g,[2,151]),c(g,[2,152]),c(g,
+[2,153]),c(g,[2,154]),c(gc,pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:354,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,
+125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),{164:[1,355],192:wb},{10:[1,356],192:wb},{10:[1,357],192:wb},{8:[1,358]},c([6,8,10,19,21,23,25,27,29,31,33,35,37,39,41,49,50,51,53,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,
+91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,138,139,141,142,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,169,170,171,173,174,179,180,181,182,183,184,185,187,189,191,192,199,201,203,205],[2,2]),c(Eb,[2,187]),{10:[1,359],169:Bb,170:Cb,177:305},c([6,8,10,49,50,51,53,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,
+76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,141,142,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,169,173,174,189,192,199,201,203,205],[2,183],{170:[1,360]}),{8:m,48:36,49:s,50:v,51:x,54:309,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,
+77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,172:310,173:bb,174:cb,176:361},
+c(Eb,[2,180]),c(Eb,[2,181]),c(Eb,[2,184]),{8:m,48:36,49:s,50:v,51:x,54:362,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,
+133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(ub,[2,164]),{8:m,48:36,49:s,50:v,51:x,54:363,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,
+118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(ub,[2,166]),{8:m,48:36,49:s,50:v,51:x,54:364,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,
+103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{8:m,48:36,49:s,50:v,51:x,54:365,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,
+85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},{10:[1,366]},{10:[1,367]},{10:[1,368]},{52:369,53:Mb},{52:370,
+53:Mb},{52:371,53:Mb},c(g,[2,46]),c(g,[2,47]),c(g,[2,82]),c(cc,[2,1]),{8:m,48:36,49:s,50:v,51:x,54:372,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,
+129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(g,[2,96]),{8:m,48:36,49:s,50:v,51:x,54:373,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,
+114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(g,[2,122]),{8:m,48:36,49:s,50:v,51:x,54:374,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,
+98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},c(g,[2,124]),{6:[1,375]},c(jc,[2,4]),{8:m,48:36,49:s,50:v,51:x,54:376,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,
+71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya},
+{8:[1,377]},c(Nb,[2,205]),{10:[1,378],20:341,21:Kb,22:342,23:Lb,44:379},c(Ob,[2,42]),c(Ob,[2,28]),c(Ob,[2,29]),{7:133,8:mb,14:380},{7:133,8:mb,14:381},c(Jb,[2,201]),{10:[1,382],20:348,21:Kb,22:349,23:Lb,24:350,25:hc,26:351,27:ic,42:383},c(Hb,[2,26]),c(Hb,[2,22]),c(Hb,[2,23]),c(Hb,[2,24]),c(Hb,[2,25]),{7:133,8:mb,14:384},{7:133,8:mb,14:385},{164:[1,386],192:wb},c(g,[2,156]),c(g,[2,157]),c(g,[2,158]),{18:389,19:kc,20:390,21:Kb,22:391,23:Lb,28:392,29:lc,30:393,31:mc,32:394,33:nc,34:395,35:oc,36:396,
+37:pc,38:397,39:qc,40:398,41:rc,45:388,46:387},c(g,[2,141]),{8:m,48:36,49:s,50:v,51:x,54:309,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,
+130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:Za,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,172:310,173:bb,174:cb,176:407},c(Eb,[2,185]),c(ub,[2,163]),c(ub,[2,165]),c(ub,[2,171]),c(ub,[2,172]),c(g,[2,59]),c(g,[2,61]),c(g,[2,63]),c(g,[2,60]),c(g,[2,62]),c(g,[2,64]),c(g,[2,93]),c(g,[2,97]),c(g,[2,123]),c(jc,[2,3]),{8:[1,408]},{140:409,169:Bb,170:Cb,177:242},c(Jb,pb,{178:14,175:15,168:23,54:25,172:26,48:36,186:216,55:218,188:410,8:m,49:s,
+50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,
+149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb}),c(Ob,[2,43]),c(sc,[2,11]),c(sc,[2,12]),{8:m,48:36,49:s,50:v,51:x,54:25,55:411,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,
+112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,168:23,172:26,173:bb,174:cb,175:15,178:14,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb},c(Hb,[2,27]),c(Hb,[2,13]),c(Hb,[2,14]),c(g,[2,155]),{10:[1,412],18:389,19:kc,20:390,21:Kb,22:391,23:Lb,28:392,29:lc,30:393,31:mc,
+32:394,33:nc,34:395,35:oc,36:396,37:pc,38:397,39:qc,40:398,41:rc,45:413},c(ob,[2,40]),c(ob,[2,30]),c(ob,[2,31]),c(ob,[2,32]),c(ob,[2,33]),c(ob,[2,34]),c(ob,[2,35]),c(ob,[2,36]),c(ob,[2,37]),c(ob,[2,38]),c(ob,[2,39]),{7:133,8:mb,14:414},{7:133,8:mb,14:415},{7:133,8:mb,14:416},{7:133,8:mb,14:417},{7:133,8:mb,14:418},{7:133,8:mb,14:419},{7:133,8:mb,14:420},{7:133,8:mb,14:421},c(Eb,[2,182]),{10:[1,423],140:422,169:Bb,170:Cb,177:242},{10:[1,424],169:Bb,170:Cb,177:305},c(Nb,[2,202],{189:fc}),c(Jb,[2,198]),
+c(Tb,pb,{178:14,175:15,168:23,54:25,172:26,48:36,190:213,188:215,186:216,55:218,143:425,8:m,49:s,50:v,51:x,56:h,57:q,58:p,59:y,60:f,61:u,62:n,63:k,67:r,68:t,69:l,70:w,71:z,72:A,73:B,74:C,75:D,76:E,77:F,78:G,79:H,80:I,81:J,82:K,83:L,85:M,86:N,87:O,88:P,89:Q,90:R,91:S,92:T,93:U,94:V,95:W,96:X,97:Y,98:Z,99:$,100:aa,101:ba,102:ca,103:da,104:ea,105:fa,106:ga,107:ha,108:ia,109:ja,110:ka,111:la,112:ma,113:na,114:oa,115:pa,116:qa,117:ra,118:sa,119:ta,120:ua,121:va,122:wa,123:xa,124:ya,125:za,126:Aa,127:Ba,
+128:Ca,129:Da,130:Ea,131:Fa,132:Ga,133:Ha,134:Ia,135:Ja,136:Ka,139:eb,141:La,142:Ma,145:Na,147:Oa,149:Pa,151:Qa,153:Ra,155:Sa,157:Ta,159:Ua,161:Va,163:Wa,165:Xa,166:Ya,173:bb,174:cb,179:fb,180:gb,181:hb,182:ib,183:jb,184:kb,185:lb,187:qb,191:vb}),c(ob,[2,41]),c(ob,[2,10]),c(ob,[2,15]),c(ob,[2,16]),c(ob,[2,17]),c(ob,[2,18]),c(ob,[2,19]),c(ob,[2,20]),c(ob,[2,21]),{10:[1,426],169:Bb,170:Cb,177:305},c(g,[2,143]),c(g,[2,144]),{10:[1,427],192:wb},c(g,[2,142]),c(g,[2,159])],N:{10:[2,206],230:[2,8]},parseError:function(b,
+a){if(a.va)this.trace(b);else{var c=Error(b);c.hash=a;throw c;}},parse:function(b){var a=[0],c=[xb],e=[],g=this.ma,d="",m=0,s=0,v=0,x=e.slice.call(arguments,1),h=Object.create(this.S),q={},p;for(p in this.e)Object.prototype.hasOwnProperty.call(this.e,p)&&(q[p]=this.e[p]);h.ga(b,q);q.S=h;q.V=this;"undefined"==typeof h.c&&(h.c={});p=h.c;e.push(p);var y=h.options&&h.options.w;this.parseError="function"===typeof q.parseError?q.parseError:Object.getPrototypeOf(this).parseError;for(var f,u,n,k,r={},t,l;;){n=
+a[a.length-1];if(this.N[n])k=this.N[n];else{if(f===xb||"undefined"==typeof f)f=nb,f=h.R()||1,"number"!==typeof f&&(f=this.la[f]||f);k=g[n]&&g[n][f]}if("undefined"===typeof k||!k.length||!k[0]){var w="";l=[];for(t in g[n])this.z[t]&&2<t&&l.push("'"+this.z[t]+"'");w=h.D?"Parse error on line "+(m+1)+":\n"+h.D()+"\nExpecting "+l.join(", ")+", got '"+(this.z[f]||f)+"'":"Parse error on line "+(m+1)+": Unexpected "+(1==f?"end of input":"'"+(this.z[f]||f)+"'");this.parseError(w,{text:h.match,$:this.z[f]||
+f,T:h.f,ta:p,qa:l})}if(k[0]instanceof Array&&1<k.length)throw Error("Parse Error: multiple actions possible at state: "+n+", token: "+f);switch(k[0]){case 1:a.push(f);c.push(h.a);e.push(h.c);a.push(k[1]);f=xb;u?(f=u,u=xb):(s=h.q,d=h.a,m=h.f,p=h.c,0<v&&v--);break;case 2:l=this.W[k[1]][1];r.b=c[c.length-l];r.K={r:e[e.length-(l||1)].r,o:e[e.length-1].o,l:e[e.length-(l||1)].l,m:e[e.length-1].m};y&&(r.K.n=[e[e.length-(l||1)].n[0],e[e.length-1].n[1]]);n=this.H.apply(r,[d,s,m,q,k[1],c,e].concat(x));if("undefined"!==
+typeof n)return n;l&&(a=a.slice(0,-2*l),c=c.slice(0,-1*l),e=e.slice(0,-1*l));a.push(this.W[k[1]][0]);c.push(r.b);e.push(r.K);k=g[a[a.length-2]][a[a.length-1]];a.push(k);break;case 3:return tb}}return tb}},Qb="http://www.w3.org/1998/Math/MathML",wc="TeX LaTeX text/x-tex text/x-latex application/x-tex application/x-latex".split(" ");try{rb.C=new DOMParser}catch(yc){rb.C={parseFromString:function(){throw"DOMParser undefined. Did you call TeXZilla.setDOMParser?";}}}rb.fa=function(b){this.C=b};try{rb.G=
+new XMLSerializer}catch(zc){rb.G={serializeToString:function(){throw"XMLSerializer undefined. Did you call TeXZilla.setXMLSerializer?";}}}rb.ja=function(b){this.G=b};rb.U=function(b){return this.C.parseFromString(b,"application/xml").documentElement};rb.ia=function(b){this.e.v=b};rb.ha=function(b){this.e.da=b};rb.ca=function(b){"string"===typeof b&&(b=this.U(b));return Vb(b)};rb.Z=function(b,a,c,g){var f;try{f=this.parse("\\("+b+"\\)"),c&&(f=f.replace(/^<math/,'<math dir="rtl"')),a&&(f=f.replace(/^<math/,
+'<math display="block"'))}catch(d){if(g)throw d;f=Pb(Ib([e("merror",[e("mtext",Fb(d.message))])],a,c,b))}return f};rb.Y=function(b,a,c,e){return this.U(this.Z(b,a,c,e))};rb.na=function(b,a,c,e,f){var d,g;e===nb&&(e=64);f===nb&&(f=window.document);a=this.Y(b,tb,a);a.setAttribute("mathsize",e+"px");e=document.createElement("div");e.style.visibility="hidden";e.style.position="absolute";e.appendChild(a);f.body.appendChild(e);d=a.getBoundingClientRect();f.body.removeChild(e);e.removeChild(a);c?(c=Math.pow(2,
+Math.ceil(Math.log(d.width)/Math.LN2)),f=Math.pow(2,Math.ceil(Math.log(d.height)/Math.LN2))):(c=Math.ceil(d.width),f=Math.ceil(d.height));g=document.createElementNS("http://www.w3.org/2000/svg","svg");g.setAttribute("width",c+"px");g.setAttribute("height",f+"px");e=document.createElementNS("http://www.w3.org/2000/svg","g");e.setAttribute("transform","translate("+(c-d.width)/2+","+(f-d.height)/2+")");g.appendChild(e);e=document.createElementNS("http://www.w3.org/2000/svg","foreignObject");e.setAttribute("width",
+d.width);e.setAttribute("height",d.height);e.appendChild(a);g.firstChild.appendChild(e);a=new Image;a.src="data:image/svg+xml;base64,"+window.btoa(xc(this.G.serializeToString(g)));a.width=c;a.height=f;a.alt=Fb(b);return a};rb.Q=function(b,a){try{return this.parse(b)}catch(c){if(a)throw c;return b}};rb.P=function(b,a){var c,e,f;for(f=b.firstChild;f;f=f.nextSibling)switch(f.nodeType){case 1:this.P(f,a);break;case 3:this.e.O=tb;c=this.C.parseFromString("<root>"+zb.Q(f.data,a)+"</root>","application/xml").documentElement;
+for(this.e.O=yb;e=c.firstChild;)b.insertBefore(c.removeChild(e),f);e=f.previousSibling;b.removeChild(f);f=e}};rb.S=function(){return{J:1,parseError:function(b,a){if(this.e.V)this.e.V.parseError(b,a);else throw Error(b);},ga:function(b,a){this.e=a||this.e||{};this.g=b;this.u=this.B=this.s=yb;this.f=this.q=0;this.a=this.h=this.match="";this.d=["INITIAL"];this.c={r:1,l:0,o:1,m:0};this.options.w&&(this.c.n=[0,0]);this.offset=0;return this},input:function(){var b=this.g[0];this.a+=b;this.q++;this.offset++;
+this.match+=b;this.h+=b;b.match(/(?:\r\n?|\n).*/g)?(this.f++,this.c.o++):this.c.m++;this.options.w&&this.c.n[1]++;this.g=this.g.slice(1);return b},I:function(b){var a=b.length,c=b.split(/(?:\r\n?|\n)/g);this.g=b+this.g;this.a=this.a.substr(0,this.a.length-a);this.offset-=a;b=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1);this.h=this.h.substr(0,this.h.length-1);c.length-1&&(this.f-=c.length-1);var e=this.c.n;this.c={r:this.c.r,o:this.f+1,l:this.c.l,m:c?(c.length===
+b.length?this.c.l:0)+b[b.length-c.length].length-c[0].length:this.c.l-a};this.options.w&&(this.c.n=[e[0],e[0]+this.q-a]);this.q=this.a.length;return this},ua:function(){this.u=tb;return this},wa:function(){if(this.options.L)this.B=tb;else return this.parseError("Lexical error on line "+(this.f+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.D(),{text:"",$:xb,T:this.f});return this},sa:function(b){this.I(this.match.slice(b))},
+ea:function(){var b=this.h.substr(0,this.h.length-this.match.length);return(20<b.length?"...":"")+b.substr(-20).replace(/\n/g,"")},oa:function(){var b=this.match;20>b.length&&(b+=this.g.substr(0,20-b.length));return(b.substr(0,20)+(20<b.length?"...":"")).replace(/\n/g,"")},D:function(){var b=this.ea(),a=Array(b.length+1).join("-");return b+this.oa()+"\n"+a+"^"},X:function(b,a){var c,e;this.options.L&&(e={f:this.f,c:{r:this.c.r,o:this.o,l:this.c.l,m:this.c.m},a:this.a,match:this.match,matches:this.matches,
+h:this.h,q:this.q,offset:this.offset,u:this.u,g:this.g,e:this.e,d:this.d.slice(0),s:this.s},this.options.w&&(e.c.n=this.c.n.slice(0)));if(c=b[0].match(/(?:\r\n?|\n).*/g))this.f+=c.length;this.c={r:this.c.o,o:this.f+1,l:this.c.m,m:c?c[c.length-1].length-c[c.length-1].match(/\r?\n?/)[0].length:this.c.m+b[0].length};this.a+=b[0];this.match+=b[0];this.matches=b;this.q=this.a.length;this.options.w&&(this.c.n=[this.offset,this.offset+=this.q]);this.B=this.u=yb;this.g=this.g.slice(b[0].length);this.h+=b[0];
+c=this.H.call(this,this.e,this,a,this.d[this.d.length-1]);this.s&&this.g&&(this.s=yb);if(c)return c;if(this.B)for(var f in e)this[f]=e[f];return yb},next:function(){if(this.s)return this.J;this.g||(this.s=tb);var b,a,c;this.u||(this.match=this.a="");for(var e=this.aa(),f=0;f<e.length;f++)if((a=this.g.match(this.rules[e[f]]))&&(!b||a[0].length>b[0].length))if(b=a,c=f,this.options.L){b=this.X(a,e[f]);if(b!==yb)return b;if(this.B)b=yb;else return yb}else if(!this.options.ra)break;return b?(b=this.X(b,
+e[c]),b!==yb?b:yb):""===this.g?this.J:this.parseError("Lexical error on line "+(this.f+1)+". Unrecognized text.\n"+this.D(),{text:"",$:xb,T:this.f})},R:function(){var b=this.next();return b?b:this.R()},j:function(b){this.d.push(b)},p:function(){return 0<this.d.length-1?this.d.pop():this.d[0]},aa:function(){return this.d.length&&this.d[this.d.length-1]?this.M[this.d[this.d.length-1]].rules:this.M.INITIAL.rules},ya:function(b){b=this.d.length-1-Math.abs(b||0);return 0<=b?this.d[b]:"INITIAL"},pushState:function(b){this.j(b)},
+xa:function(){return this.d.length},options:{},H:function(b,a,c){switch(c){case 0:this.I(a.a);this.pushState("DOCUMENT");break;case 1:return this.pushState("MATH"+(0+!!b.da)),b.ka=this.h.length,"STARTMATH"+(2*("$"==a.a[0])+("$"==a.a[1]||"["==a.a[1]));case 2:return this.p(),"EOF";case 3:return a.a=a.a[1],"TEXT";case 4:return b.O&&(a.a=Fb(a.a)),"TEXT";case 5:return"TEXT";case 6:return this.p(),"[";case 7:this.I(a.a);this.p();this.p();break;case 8:return"TEXTOPTARG";case 9:return this.p(),"]";case 10:return"{";
+case 11:return"TEXTARG";case 12:return this.p(),"}";case 13:return this.p(),"]";case 15:return this.p(),b.ba=this.h.length-this.match.length,b.t=this.h.substring(b.ka,b.ba),"ENDMATH"+(2*("$"==a.a[0])+("$"==a.a[1]||"]"==a.a[1]));case 16:return"{";case 17:return"}";case 18:return"^";case 19:return"_";case 20:return".";case 21:return"COLSEP";case 22:return"ROWSEP";case 23:return"NUM";case 24:return"A";case 25:return a.a="Ζ","AIUG";case 26:return a.a="ζ","AILG";case 27:return this.pushState("OPTARG"),
+this.pushState("TRYOPTARG"),a.a="⇌","XARROW";case 28:return this.pushState("OPTARG"),this.pushState("TRYOPTARG"),a.a="⇒","XARROW";case 29:return this.pushState("OPTARG"),this.pushState("TRYOPTARG"),a.a="→","XARROW";case 30:return this.pushState("OPTARG"),this.pushState("TRYOPTARG"),a.a="↦","XARROW";case 31:return this.pushState("OPTARG"),this.pushState("TRYOPTARG"),a.a="⇋","XARROW";case 32:return this.pushState("OPTARG"),this.pushState("TRYOPTARG"),a.a="⇔","XARROW";case 33:return this.pushState("OPTARG"),
+this.pushState("TRYOPTARG"),a.a="↔","XARROW";case 34:return this.pushState("OPTARG"),this.pushState("TRYOPTARG"),a.a="⇐","XARROW";case 35:return this.pushState("OPTARG"),this.pushState("TRYOPTARG"),a.a="←","XARROW";case 36:return a.a="Ξ","AIUG";case 37:return a.a="ξ","AILG";case 38:return this.pushState("OPTARG"),this.pushState("TRYOPTARG"),a.a="↪","XARROW";case 39:return this.pushState("OPTARG"),this.pushState("TRYOPTARG"),a.a="↩","XARROW";case 40:return a.a="≀","OP";case 41:return a.a="℘","A";case 42:return a.a=
+"⇀","ACCENT";case 43:return a.a="˜","ACCENT";case 44:return a.a="^","ACCENT";case 45:return a.a="ˇ","ACCENT";case 46:return a.a="¯","ACCENT";case 47:return a.a="≙","OP";case 48:return a.a="⋀","OPM";case 49:return a.a="∧","OP";case 50:return a.a="⦀","OPFS";case 51:return a.a="⊪","OP";case 52:return a.a="‖","OPFS";case 53:return a.a="|","OPFS";case 54:return a.a="⊻","OP";case 55:return a.a="⋁","OPM";case 56:return a.a="∨","OP";case 57:return a.a="⇀","ACCENTNS";case 58:return a.a="⋮","OP";case 59:return a.a=
+"⊫","OP";case 60:return a.a="⊩","OP";case 61:return a.a="⊨","OP";case 62:return a.a="⊢","OP";case 63:return a.a="⫫","OP";case 64:return a.a="⊳","OP";case 65:return a.a="⊲","OP";case 66:return a.a="▵","OP";case 67:return a.a="ϑ","AILG";case 68:return a.a="⫌︀","OP";case 69:return a.a="⊋︀","OP";case 70:return a.a="⫋︀","OP";case 71:return a.a="⊊︀","OP";case 72:return a.a="⊊︀","OP";case 73:return a.a="ς","A";case 74:return a.a="ϱ","AILG";case 75:return a.a="∝","OP";case 76:return a.a="ϖ","AILG";case 77:return a.a=
+"φ","AILG";case 78:return a.a="∅","A";case 79:return a.a="ϰ","AILG";case 80:return a.a="ε","AILG";case 81:return a.a="⤊","OPS";case 82:return a.a="⇈","OPS";case 83:return a.a="ϒ","A";case 84:return a.a="υ","AILG";case 85:return a.a="ϒ","A";case 86:return a.a="⊎","OP";case 87:return a.a="⨛","OP";case 88:return a.a="↿","OPS";case 89:return a.a="↾","OPS";case 90:return a.a="⇕","OPS";case 91:return a.a="↕","OPS";case 92:return a.a="↕","OPS";case 93:return a.a="⇑","OPS";case 94:return a.a="↑","OPS";case 95:return a.a=
+"↑","OPS";case 96:return a.a="⊵","OP";case 97:return a.a="⊴","OP";case 98:return a.a="⋃","OPM";case 99:return a.a="∪","OP";case 100:return"UNDERSET";case 101:return"UNDEROVERSET";case 102:return"UNDERLINE";case 103:return"UNDERBRACE";case 104:return a.a="⋰","OP";case 105:return"OP";case 106:return"OP";case 107:return"OP";case 108:return"OP";case 109:return"OP";case 110:return"OP";case 111:return"OP";case 112:return"OP";case 113:return"OP";case 114:return"OP";case 115:return"OP";case 116:return"OP";
+case 117:return"OP";case 118:return"OP";case 119:return"OP";case 120:return"OP";case 121:return"OP";case 122:return"OP";case 123:return"OP";case 124:return"OP";case 125:return"OP";case 126:return"OP";case 127:return"OP";case 128:return"OP";case 129:return"OP";case 130:return"OP";case 131:return"OP";case 132:return"OP";case 133:return"OP";case 134:return"OP";case 135:return"OP";case 136:return"OP";case 137:return"OP";case 138:return"OPFS";case 139:return"OPFS";case 140:return"OP";case 141:return"OP";
+case 142:return"OP";case 143:return"OP";case 144:return"OP";case 145:return"OP";case 146:return"OP";case 147:return"OP";case 148:return"OP";case 149:return"OP";case 150:return"OP";case 151:return"OP";case 152:return"OP";case 153:return"OP";case 154:return"OP";case 155:return"OP";case 156:return"OP";case 157:return"OP";case 158:return"OP";case 159:return"OP";case 160:return"OP";case 161:return a.a="⤖","OP";case 162:return a.a="↠","OPS";case 163:return a.a="↞","OPS";case 164:return a.a="∭","OP";case 165:return a.a=
+"⊵","OP";case 166:return a.a="▹","OP";case 167:return a.a="≜","OP";case 168:return a.a="⊴","OP";case 169:return a.a="◃","OP";case 170:return a.a="▿","OP";case 171:return a.a="▵","OP";case 172:return a.a="⤪","OP";case 173:return a.a="⤩","OP";case 174:return a.a="⊤","OP";case 175:return this.pushState("TEXTARG"),"TOOLTIP";case 176:return a.a="⤧","OP";case 177:return"TOGGLE";case 178:return a.a="⤨","OP";case 179:return a.a="→","OPS";case 180:return a.a="⊠","OP";case 181:return a.a="×","OP";case 182:return a.a=
+"˜","ACCENTNS";case 183:return"THINSPACE";case 184:return"THICKSPACE";case 185:return a.a="∼","OP";case 186:return a.a="≈","OP";case 187:return a.a="Θ","AIUG";case 188:return a.a="θ","AILG";case 189:return a.a="∴","OP";case 190:return"TFRAC";case 191:return"TEXTSTYLE";case 192:return"TEXTSIZE";case 193:return a.a="”","OPF";case 194:return a.a="“","OPF";case 195:return a.a="~","OPS";case 196:return a.a="`","OP";case 197:return a.a="^","OPS";case 198:return a.a="´","OP";case 199:return this.j("TEXTARG"),
+"MTEXT";case 200:return"TENSOR";case 201:return"TBINOM";case 202:return a.a="Τ","AIUG";case 203:return a.a="τ","AILG";case 204:return a.a="⇙","OPS";case 205:return a.a="↙","OPS";case 206:return a.a="⇙","OPS";case 207:return a.a="↙","OPS";case 208:return a.a="√","OPS";case 209:return a.a="⫌","OP";case 210:return a.a="⊋","OP";case 211:return a.a="⫆","OP";case 212:return a.a="⊇","OP";case 213:return a.a="⋑","OP";case 214:return a.a="⊃","OP";case 215:return a.a="∑","OPM";case 216:return a.a="≿","OP";
+case 217:return a.a="⋩","OP";case 218:return a.a="⪶","OP";case 219:return a.a="⪺","OP";case 220:return a.a="⪰","OP";case 221:return a.a="≽","OP";case 222:return a.a="⪸","OP";case 223:return a.a="≻","OP";case 224:return"SUBSTACK";case 225:return a.a="⫋","OP";case 226:return a.a="⊊","OP";case 227:return a.a="⫅","OP";case 228:return a.a="⊆","OP";case 229:return a.a="⋐","OP";case 230:return a.a="⊂","OP";case 231:return this.pushState("TEXTARG"),"STATUSLINE";case 232:return a.a="⋆","OP";case 233:return"OVERSET";
+case 234:return a.a="⫽","OP";case 235:return a.a="□","OP";case 236:return a.a="⊒","OP";case 237:return a.a="⊐","OP";case 238:return a.a="⊑","OP";case 239:return a.a="⊏","OP";case 240:return this.pushState("OPTARG"),this.pushState("TRYOPTARG"),"SQRT";case 241:return a.a="⊔","OP";case 242:return a.a="⊓","OP";case 243:return a.a="∢","OP";case 244:return a.a="♠","OP";case 245:return this.pushState("TEXTARG"),this.pushState("TEXTARG"),this.pushState("TEXTARG"),"SPACE";case 246:return a.a="⌣","OP";case 247:return a.a=
+"⌣","OP";case 248:return a.a="∖","OP";case 249:return a.a="⌢","OP";case 250:return"SLASH";case 251:return a.a="≃","OP";case 252:return a.a="∼","OP";case 253:return a.a="Σ","AIUG";case 254:return a.a="σ","AILG";case 255:return a.a="⧢","OP";case 256:return a.a="∥","OP";case 257:return a.a="∣","OP";case 258:return a.a="♯","OP";case 259:return a.a="∖","OP";case 260:return a.a="⤭","OP";case 261:return a.a="⇘","OPS";case 262:return a.a="↘","OPS";case 263:return a.a="⇘","OPS";case 264:return a.a="↘","OPS";
+case 265:return"SCRIPTSIZE";case 266:return"SCRIPTSCRIPTSIZE";case 267:return a.a="⋊","OP";case 268:return a.a="↱","OPS";case 269:return a.a="⇛","OPS";case 270:return a.a="⟫","OPFS";case 271:return a.a="’","OPF";case 272:return this.j("TEXTARG"),"ROWSPAN";case 273:return"ROWOPTS";case 274:return this.pushState("TEXTARG"),"ROWLINES";case 275:return this.j("TEXTARG"),"ROWALIGN";case 276:return"ROOT";case 277:return a.a="⎱","OP";case 278:return a.a="≓","OP";case 279:return a.a="⟲","OP";case 280:return a.a=
+"⋌","OP";case 281:return a.a="↝","OPS";case 282:return a.a="⇉","OPS";case 283:return a.a="⇌","OPS";case 284:return a.a="⇄","OPS";case 285:return a.a="⇀","OPS";case 286:return a.a="⇁","OPS";case 287:return a.a="⇾","OPS";case 288:return a.a="↣","OPS";case 289:return a.a="⇒","OPS";case 290:return a.a="→","OPS";case 291:return"RIGHT";case 292:return a.a="Ρ","AIUG";case 293:return a.a="ρ","AILG";case 294:return a.a="⊳","OP";case 295:return a.a="⌋","OPFS";case 296:return a.a="ℜ","A";case 297:return a.a=
+"⤰","OP";case 298:return a.a="⤫","OP";case 299:return a.a="⌉","OPFS";case 300:return a.a="]","OPFS";case 301:return a.a="}","OPFS";case 302:return a.a="⟩","OPFS";case 303:return a.a="⟩","OPFS";case 304:return a.a="≟","OP";case 305:return a.a="⨌","OP";case 306:return"QUAD";case 307:return"QQUAD";case 308:return a.a="▪","OP";case 309:return a.a="Ψ","AIUG";case 310:return a.a="ψ","AILG";case 311:return a.a="∝","OP";case 312:return a.a="∏","OPM";case 313:return a.a="∏","OPM";case 314:return a.a="′","OPP";
+case 315:return a.a="≾","OP";case 316:return a.a="⋨","OP";case 317:return a.a="⪵","OP";case 318:return a.a="⪹","OP";case 319:return a.a="⪯","OP";case 320:return a.a="≼","OP";case 321:return a.a="⪷","OP";case 322:return a.a="≺","OP";case 323:return"PMOD";case 324:return a.a="±","OP";case 325:return a.a="⨥","OP";case 326:return a.a="⊞","OP";case 327:return a.a="⋔","OP";case 328:return a.a="Π","AIUG";case 329:return a.a="π","AILG";case 330:return a.a="Φ","AIUG";case 331:return a.a="ϕ","AILG";case 332:return"PHANTOM";
+case 333:return a.a="⫫","OP";case 334:return a.a="⊥","OP";case 335:return a.a="⪣","OP";case 336:return a.a="∂","OP";case 337:return a.a="⅋","OP";case 338:return a.a="∥","OP";case 339:return this.pushState("TEXTARG"),"PADDING";case 340:return"OVERSET";case 341:return a.a="¯","ACCENT";case 342:return"OVERBRACE";case 343:return"TEXOVER";case 344:return a.a="⨴","OP";case 345:return a.a="⊗","OP";case 346:return a.a="⊘","OP";case 347:return"OPS";case 348:return"OPP";case 349:return"OPM";case 350:return a.a=
+"⨭","OP";case 351:return a.a="⊕","OP";case 352:return"OPFS";case 353:return"OPF";case 354:return this.j("TEXTARG"),"OPERATORNAME";case 355:return"OP";case 356:return a.a="⊖","OP";case 357:return a.a="ℴ","A";case 358:return a.a="Ω","AIUG";case 359:return a.a="ω","AILG";case 360:return a.a="∮","OP";case 361:return a.a="∯","OP";case 362:return a.a="∰","OP";case 363:return a.a="⊙","OP";case 364:return a.a="⊝","OP";case 365:return a.a="⦸","OP";case 366:return a.a="⤲","OP";case 367:return a.a="⇖","OPS";
+case 368:return a.a="↖","OPS";case 369:return a.a="⇖","OPS";case 370:return a.a="↖","OPS";case 371:return a.a="⊯","OP";case 372:return a.a="⊮","OP";case 373:return a.a="⊭","OP";case 374:return a.a="⊬","OP";case 375:return"NUM";case 376:return a.a="Ν","AIUG";case 377:return a.a="ν","AILG";case 378:return a.a="⋭","OP";case 379:return a.a="⋫","OP";case 380:return a.a="⋬","OP";case 381:return a.a="⋪","OP";case 382:return a.a="⊉","OP";case 383:return a.a="⊅","OP";case 384:return a.a="≿̸","OP";case 385:return a.a=
+"⪰̸","OP";case 386:return a.a="⊁","OP";case 387:return a.a="⊈","OP";case 388:return a.a="⊈","OP";case 389:return a.a="⊄","OP";case 390:return a.a="≄","OP";case 391:return a.a="≁","OP";case 392:return a.a="∦","OP";case 393:return a.a="∤","OP";case 394:return a.a="⇏","OP";case 395:return a.a="↛","OP";case 396:return a.a="⪯̸","OP";case 397:return a.a="⊀","OP";case 398:return a.a="∦","OP";case 399:return a.a="∌","OP";case 400:return a.a="∉","OP";case 401:return a.a="¬","OP";case 402:return a.a="∤","OP";
+case 403:return a.a="≮","OP";case 404:return a.a="⩽̸","OP";case 405:return a.a="⩽̸","OP";case 406:return a.a="≰","OP";case 407:return a.a="⇎","OP";case 408:return a.a="↮","OP";case 409:return a.a="⇍","OP";case 410:return a.a="↚","OP";case 411:return a.a="∋","OP";case 412:return a.a="≯","OP";case 413:return a.a="⩾̸","OP";case 414:return a.a="⩾̸","OP";case 415:return a.a="≱","OP";case 416:return a.a="∄","OP";case 417:return a.a="≢","OP";case 418:return a.a="≂̸","OP";case 419:return a.a="≠","OP";case 420:return a.a=
+"⤮","OP";case 421:return a.a="⤱","OP";case 422:return"NEGTHICKSPACE";case 423:return"NEGSPACE";case 424:return"NEGMEDSPACE";case 425:return a.a="¬","OP";case 426:return a.a="⇗","OPS";case 427:return a.a="↗","OPS";case 428:return a.a="⇗","OPS";case 429:return a.a="↗","OPS";case 430:return a.a="≠","OP";case 431:return a.a="≇","OP";case 432:return a.a="≎̸","OP";case 433:return a.a="≏̸","OP";case 434:return a.a="♮","OP";case 435:return a.a="≉","OP";case 436:return a.a="∇","OP";case 437:return"MULTI";
+case 438:return a.a="⊸","OP";case 439:return a.a="Μ","AIUG";case 440:return a.a="μ","AILG";case 441:return this.j("TEXTARG"),"MTEXT";case 442:return this.pushState("TEXTARG"),this.pushState("TEXTOPTARG"),this.pushState("TRYOPTARG"),this.pushState("TEXTOPTARG"),this.pushState("TRYOPTARG"),"MS";case 443:return a.a="∓","OP";case 444:return a.a="⊧","OP";case 445:return a.a="mod","MO";case 446:return this.pushState("TEXTARG"),"MO";case 447:return this.pushState("TEXTARG"),"MN";case 448:return a.a="⫛",
+"OP";case 449:return a.a="⨪","OP";case 450:return a.a="⊟","OP";case 451:return a.a="−","OP";case 452:return a.a=a.a.slice(1),"FM";case 453:return a.a="∣","OP";case 454:return this.pushState("TEXTARG"),"MI";case 455:return a.a="℧","A";case 456:return a.a="℧","A";case 457:return"MEDSPACE";case 458:return a.a="∡","OP";case 459:return"MATHTT";case 460:return"MATHSF";case 461:return"MATHSCR";case 462:return"MATHRM";case 463:return"MATHRLAP";case 464:return this.j("TEXTARG"),"MATHREL";case 465:return this.pushState("TEXTOPTARG"),
+this.pushState("TRYOPTARG"),this.pushState("TEXTOPTARG"),this.pushState("TRYOPTARG"),this.pushState("TEXTARG"),"MATHRAISEBOX";case 466:return this.j("TEXTARG"),"MATHOP";case 467:return"MATHIT";case 468:return"MATHLLAP";case 469:return"MATHIT";case 470:return"MATHFRAK";case 471:return"MATHFRAK";case 472:return"MATHCLAP";case 473:return"MATHSCR";case 474:return"MATHBSCR";case 475:return"MATHBIT";case 476:return this.j("TEXTARG"),"MATHBIN";case 477:return"MATHBF";case 478:return"MATHBSCR";case 479:return"MATHBB";
+case 480:return a.a="⤇","OP";case 481:return a.a="↦","OPS";case 482:return a.a="⤆","OP";case 483:return a.a="↦","OPS";case 484:return a.a="≨︀","OP";case 485:return a.a="≨︀","OP";case 486:return a.a="⋉","OP";case 487:return a.a="<","OP";case 488:return a.a="↰","OPS";case 489:return a.a="‘","OPF";case 490:return a.a="◊","OP";case 491:return a.a="⨜","OP";case 492:return a.a="↬","OPS";case 493:return a.a="↫","OPS";case 494:return a.a="⟹","OPS";case 495:return a.a="⟶","OPS";case 496:return a.a="⟼","OPS";
+case 497:return a.a="⟺","OPS";case 498:return a.a="⟷","OPS";case 499:return a.a="⟸","OPS";case 500:return a.a="⟵","OPS";case 501:return a.a="⋦","OP";case 502:return a.a="≨","OP";case 503:return a.a="⪇","OP";case 504:return a.a="⪉","OP";case 505:return a.a="⎰","OP";case 506:return a.a="⋘","OP";case 507:return a.a="⇚","OPS";case 508:return a.a="⟪","OPFS";case 509:return a.a="≪","OP";case 510:return a.a="⊲","OP";case 511:return a.a="⌊","OPFS";case 512:return a.a="≲","OP";case 513:return a.a="≶","OP";
+case 514:return a.a="⪋","OP";case 515:return a.a="⋚","OP";case 516:return a.a="⋖","OP";case 517:return a.a="⪅","OP";case 518:return a.a="<","OP";case 519:return a.a="⩽","OP";case 520:return a.a="≦","OP";case 521:return a.a="≤","OP";case 522:return a.a="⟳","OP";case 523:return a.a="⋋","OP";case 524:return a.a="↜","OPS";case 525:return a.a="↭","OPS";case 526:return a.a="⇋","OPS";case 527:return a.a="⇿","OPS";case 528:return a.a="⇆","OPS";case 529:return a.a="⇔","OPS";case 530:return a.a="↔","OPS";case 531:return a.a=
+"⇇","OPS";case 532:return a.a="↼","OPS";case 533:return a.a="↽","OPS";case 534:return a.a="⇽","OPS";case 535:return a.a="↢","OPS";case 536:return a.a="⇐","OPS";case 537:return a.a="←","OPS";case 538:return"LEFT";case 539:return a.a="≤","OP";case 540:return a.a="…","OP";case 541:return a.a="⌈","OPFS";case 542:return a.a="[","OPFS";case 543:return a.a="{","OPFS";case 544:return a.a="⟨","OPFS";case 545:return a.a="⟨","OPFS";case 546:return a.a="Λ","AIUG";case 547:return a.a="λ","AILG";case 548:return a.a=
+"∻","OP";case 549:return a.a="Κ","AIUG";case 550:return a.a="κ","AILG";case 551:return a.a="ȷ","AILL";case 552:return this.pushState("TEXTARG"),"MN";case 553:return a.a="Ι","AIUG";case 554:return a.a="ι","AILG";case 555:return a.a="⅋","OP";case 556:return a.a="⨘","OP";case 557:return a.a="⨽","OP";case 558:return a.a="⨼","OP";case 559:return a.a="⋂","OPM";case 560:return a.a="∩","OP";case 561:return a.a="⫴","OP";case 562:return a.a="⊺","OP";case 563:return a.a="∫","OP";case 564:return a.a="⨚","OP";
+case 565:return a.a="⨙","OP";case 566:return a.a="⨎","OP";case 567:return a.a="⨍","OP";case 568:return a.a="∫","OP";case 569:return a.a="∞","NUM";case 570:return a.a="∞","NUM";case 571:return a.a=a.a.slice(1),"FM";case 572:return a.a="∊","OP";case 573:return a.a="⇒","OPS";case 574:return a.a="⇐","OPS";case 575:return a.a="ı","AILL";case 576:return a.a="ℑ","A";case 577:return a.a="∬","OP";case 578:return a.a="∭","OP";case 579:return a.a="⨌","OP";case 580:return a.a="⟺","OPS";case 581:return a.a="ℏ",
+"A";case 582:return this.pushState("TEXTARG"),"HREF";case 583:return a.a="↪","OPS";case 584:return a.a="↩","OPS";case 585:return a.a="⤦","OP";case 586:return a.a="⤥","OP";case 587:return a.a="♡","OP";case 588:return a.a="ℏ","A";case 589:return a.a="^","ACCENTNS";case 590:return a.a="≩︀","OP";case 591:return a.a="≩︀","OP";case 592:return a.a="≳","OP";case 593:return a.a="≷","OP";case 594:return a.a="⪌","OP";case 595:return a.a="⋛","OP";case 596:return a.a="⋗","OP";case 597:return a.a="⪆","OP";case 598:return a.a=
+">","OP";case 599:return a.a=">","OP";case 600:return a.a="⋧","OP";case 601:return a.a="≩","OP";case 602:return a.a="⪈","OP";case 603:return a.a="⪊","OP";case 604:return a.a="ℷ","A";case 605:return a.a="⋙","OP";case 606:return a.a="≫","OP";case 607:return a.a="⩾","OP";case 608:return a.a="≧","OP";case 609:return a.a="≥","OP";case 610:return a.a="≥","OP";case 611:return a.a="Γ","AIUG";case 612:return a.a="γ","AILG";case 613:return a.a="⌢","OP";case 614:return this.pushState("TEXTARG"),"FRAME";case 615:return"FRAC";
+case 616:return a.a="⫝","OP";case 617:return a.a="⫝̸","OP";case 618:return a.a="∀","OP";case 619:return a.a="♭","OP";case 620:return a.a="⤬","OP";case 621:return a.a="⤯","OP";case 622:return a.a="≒","OP";case 623:return a.a="∃","OP";case 624:return a.a="ð","A";case 625:return a.a="ð","A";case 626:return a.a="Η","AIUG";case 627:return a.a="η","AILG";case 628:return a.a="≡","OP";case 629:return this.pushState("TEXTARG"),"EQROWS";case 630:return this.pushState("TEXTARG"),"EQCOLS";case 631:return a.a=
+"⪕","OP";case 632:return a.a="⪖","OP";case 633:return a.a="≂","OP";case 634:return a.a="=∷","OP";case 635:return a.a="≕","OP";case 636:return a.a="−∷","OP";case 637:return a.a="=∷","OP";case 638:return a.a="=∷","OP";case 639:return a.a="=∷","OP";case 640:return a.a="≕","OP";case 641:return a.a="≖","OP";case 642:return a.a="ϵ","AILG";case 643:return"EVVMATRIX";case 644:return"EVMATRIX";case 645:return"ETOGGLE";case 646:return"EALIGNED";case 647:return"ESMALLMATRIX";case 648:return"EPMATRIX";case 649:return"EMATRIX";
+case 650:return"EGATHERED";case 651:return"ECASES";case 652:return"EBBMATRIX";case 653:return"EBMATRIX";case 654:return"EARRAY";case 655:return"EALIGNED";case 656:return a.a="∅","A";case 657:return a.a="∅","A";case 658:return a.a="↪","OPS";case 659:return a.a="ℓ","A";case 660:return a.a="↕","OPS";case 661:return a.a="⧟","OP";case 662:return a.a="⤐","OPS";case 663:return a.a="↕","OPS";case 664:return a.a="⇂","OPS";case 665:return a.a="⇃","OPS";case 666:return a.a="⇊","OPS";case 667:return a.a="⇓",
+"OPS";case 668:return a.a="↓","OPS";case 669:return a.a="∬","OP";case 670:return a.a="⩞","OP";case 671:return a.a="⌆","OP";case 672:return a.a="…","OP";case 673:return a.a="∔","OP";case 674:return a.a="∸","OP";case 675:return a.a="≑","OP";case 676:return a.a="≑","OP";case 677:return a.a="≐","OP";case 678:return a.a="˙","ACCENT";case 679:return a.a="⋇","OP";case 680:return a.a="÷","OP";case 681:return"DISPLAYSTYLE";case 682:return a.a="⨈","OPM";case 683:return a.a="ϝ","A";case 684:return a.a="♢","OP";
+case 685:return a.a="⋄","OP";case 686:return a.a="⋄","OP";case 687:return a.a=a.a.slice(1),"FM";case 688:return a.a="Δ","AIUG";case 689:return a.a="δ","AILG";case 690:return a.a="∇","OP";case 691:return a.a="°","OP";case 692:return a.a="⤋","OPS";case 693:return a.a="⩷","OP";case 694:return a.a="⋱","OP";case 695:return a.a="̈","ACCENT";case 696:return a.a="⃛","OP";case 697:return a.a="⃛","ACCENT";case 698:return a.a="⃜","OP";case 699:return a.a="⃜","ACCENT";case 700:return a.a="‡","OP";case 701:return a.a=
+"∷","OP";case 702:return a.a="⤏","OPS";case 703:return a.a="⫤","OP";case 704:return a.a="⫣","OP";case 705:return a.a="⊣","OP";case 706:return a.a="⤏","OPS";case 707:return a.a="⤎","OPS";case 708:return a.a="↓","OPS";case 709:return a.a="ℸ","A";case 710:return a.a="†","OP";case 711:return a.a="↷","OP";case 712:return a.a="↶","OP";case 713:return a.a="⤻","OP";case 714:return a.a="⋏","OP";case 715:return a.a="⋎","OP";case 716:return a.a="⋟","OP";case 717:return a.a="⋞","OP";case 718:return a.a="⊍","OP";
+case 719:return a.a="⋓","OP";case 720:return a.a="∪","OP";case 721:return a.a="∐","OPM";case 722:return a.a="∐","OPM";case 723:return a.a="∮","OP";case 724:return a.a="⨇","OPM";case 725:return a.a="∮","OP";case 726:return a.a="≅","OP";case 727:return a.a="∁","OP";case 728:return this.j("TEXTARG"),"COLSPAN";case 729:return this.pushState("TEXTARG"),"COLOR";case 730:return a.a="∷∼","OP";case 731:return a.a="∶∼","OP";case 732:return a.a="⩴","OP";case 733:return a.a="≔","OP";case 734:return a.a="∷−",
+"OP";case 735:return a.a="≔","OP";case 736:return a.a="∷≈","OP";case 737:return a.a="∶≈","OP";case 738:return a.a="∷","OP";case 739:return a.a=":","OP";case 740:return this.pushState("TEXTARG"),"COLLINES";case 741:return this.pushState("TEXTARG"),"COLLAYOUT";case 742:return this.j("TEXTARG"),"COLALIGN";case 743:return a.a="♣","OP";case 744:return a.a="¯","ACCENT";case 745:return a.a="⊝","OP";case 746:return a.a="⊚","OP";case 747:return a.a="⊛","OP";case 748:return a.a="⥁","OP";case 749:return a.a=
+"⥀","OP";case 750:return a.a="≗","OP";case 751:return a.a="∘","OP";case 752:return"TEXCHOOSE";case 753:return a.a="χ","AILG";case 754:return a.a="ˇ","ACCENTNS";case 755:return"CELLOPTS";case 756:return a.a="⋯","OP";case 757:return a.a="·","OP";case 758:return a.a="⋅","OP";case 759:return a.a="⋒","OP";case 760:return a.a="∩","OP";case 761:return a.a="⪮","OP";case 762:return a.a="≎","OP";case 763:return a.a="≏","OP";case 764:return a.a="•","OP";case 765:return a.a="⨲","OP";case 766:return a.a="⊠","OP";
+case 767:return a.a="⊞","OP";case 768:return a.a="⊟","OP";case 769:return"BOXED";case 770:return a.a="⊡","OP";case 771:return a.a="⧄","OP";case 772:return a.a="⧇","OP";case 773:return a.a="⧅","OP";case 774:return a.a="⧆","OP";case 775:return a.a="□","OP";case 776:return a.a="⋈","OP";case 777:return a.a="⊥","OP";case 778:return a.a="⊥","OP";case 779:return"MATHBF";case 780:return a.a="▸","OP";case 781:return a.a="◂","OP";case 782:return a.a="▾","OP";case 783:return a.a="▴","OP";case 784:return a.a=
+"■","OP";case 785:return a.a="⧫","OP";case 786:return a.a="⤍","OPS";case 787:return"BINOM";case 788:return a.a="⋀","OPM";case 789:return a.a="⋁","OPM";case 790:return a.a="⨄","OPM";case 791:return a.a="△","OP";case 792:return a.a="▽","OP";case 793:return a.a="⨉","OPM";case 794:return a.a="★","OP";case 795:return a.a="⨆","OPM";case 796:return a.a="⨅","OPM";case 797:return"BBIG";case 798:return"BIG";case 799:return a.a="⨂","OPM";case 800:return a.a="⨁","OPM";case 801:return a.a="⨀","OPM";case 802:return"BBIGL";
+case 803:return"BIGL";case 804:return a.a="⫼","OPM";case 805:return"BBIGG";case 806:return"BIGG";case 807:return"BBIGGL";case 808:return"BIGGL";case 809:return"BBIGG";case 810:return"BIGG";case 811:return a.a="⨃","OPM";case 812:return a.a="⋃","OPM";case 813:return a.a="○","OP";case 814:return a.a="⋂","OPM";case 815:return"BBIG";case 816:return"BIG";case 817:return this.pushState("TEXTARG"),"BGCOLOR";case 818:return a.a="≬","OP";case 819:return a.a="ℶ","A";case 820:return a.a="Β","AIUG";case 821:return a.a=
+"β","AILG";case 822:return"BVVMATRIX";case 823:return"BVMATRIX";case 824:return"BTOGGLE";case 825:return"BALIGNED";case 826:return"BSMALLMATRIX";case 827:return"BPMATRIX";case 828:return"BMATRIX";case 829:return"BGATHERED";case 830:return"BCASES";case 831:return"BBBMATRIX";case 832:return"BBMATRIX";case 833:return this.pushState("TEXTARG"),this.pushState("TEXTOPTARG"),this.pushState("TRYOPTARG"),"BARRAY";case 834:return"BALIGNED";case 835:return a.a="∵","OP";case 836:return a.a="ℿ","A";case 837:return a.a=
+"⌅","OP";case 838:return a.a="¯","ACCENTNS";case 839:return a.a="\\","OP";case 840:return a.a="⋍","OP";case 841:return a.a="∽","OP";case 842:return a.a="‵","OPP";case 843:return a.a="϶","OP";case 844:return"TEXATOP";case 845:return a.a="≍","OP";case 846:return a.a="∗","OP";case 847:return"ARRAYOPTS";case 848:return"ARRAY";case 849:return a.a=a.a.slice(1),"F";case 850:return a.a="≊","OP";case 851:return a.a="≈","OP";case 852:return a.a="∠","OP";case 853:return a.a="⨿","OP";case 854:return a.a="Α",
+"AIUG";case 855:return a.a="α","AILG";case 856:return this.pushState("TEXTARG"),"ALIGN";case 857:return a.a="ℵ","A";case 858:return"AIUL";case 859:return"AIUG";case 860:return"AILL";case 861:return"AILG";case 862:return a.a="⋰","OP";case 863:return a.a="Å","A";case 864:return"A";case 865:return a.a="$","A";case 866:return a.a="}","OPFS";case 867:return a.a="‖","OPFS";case 868:return a.a="{","OPFS";case 869:return"THICKSPACE";case 870:return"MEDSPACE";case 871:return"THINSPACE";case 872:return a.a=
+"&","A";case 873:return a.a="%","A";case 874:return a.a="#","OP";case 875:return"NEGSPACE";case 876:return a.a="−","OP";case 877:return a.a="⁗","OPP";case 878:return a.a="‴","OPP";case 879:return a.a="″","OPP";case 880:return a.a="′","OPP";case 881:return"HIGH_SURROGATE";case 882:return"LOW_SURROGATE";case 883:return"BMP_CHARACTER"}},rules:[/^(?:.)/,/^(?:\$\$|\\\[|\$|\\\()/,/^(?:$)/,/^(?:\\[$\\])/,/^(?:[<&>])/,/^(?:[^])/,/^(?:\s*\[)/,/^(?:.)/,/^(?:([^\\\]]|(\\[\\\]]))+)/,/^(?:\])/,/^(?:\s*\{)/,/^(?:([^\\\}]|(\\[\\\}]))+)/,
+/^(?:\})/,/^(?:\])/,/^(?:\s+)/,/^(?:\$\$|\\\]|\$|\\\))/,/^(?:\{)/,/^(?:\})/,/^(?:\^)/,/^(?:_)/,/^(?:\.)/,/^(?:&)/,/^(?:\\\\)/,/^(?:[0-9]+(?:\.[0-9]+)?|[\u0660-\u0669]+(?:\u066B[\u0660-\u0669]+)?|(?:\uD835[\uDFCE-\uDFD7])+|(?:\uD835[\uDFD8-\uDFE1])+|(?:\uD835[\uDFE2-\uDFEB])+|(?:\uD835[\uDFEC-\uDFF5])+|(?:\uD835[\uDFF6-\uDFFF])+)/,/^(?:[a-zA-Z]+)/,/^(?:\\Zeta)/,/^(?:\\zeta)/,/^(?:\\xrightleftharpoons)/,/^(?:\\xRightarrow)/,/^(?:\\xrightarrow)/,/^(?:\\xmapsto)/,/^(?:\\xleftrightharpoons)/,/^(?:\\xLeftrightarrow)/,
+/^(?:\\xleftrightarrow)/,/^(?:\\xLeftarrow)/,/^(?:\\xleftarrow)/,/^(?:\\Xi)/,/^(?:\\xi)/,/^(?:\\xhookrightarrow)/,/^(?:\\xhookleftarrow)/,/^(?:\\wr)/,/^(?:\\wp)/,/^(?:\\widevec)/,/^(?:\\widetilde)/,/^(?:\\widehat)/,/^(?:\\widecheck)/,/^(?:\\widebar)/,/^(?:\\wedgeq)/,/^(?:\\Wedge)/,/^(?:\\wedge)/,/^(?:\\Vvert)/,/^(?:\\Vvdash)/,/^(?:\\Vert)/,/^(?:\\vert)/,/^(?:\\veebar)/,/^(?:\\Vee)/,/^(?:\\vee)/,/^(?:\\vec)/,/^(?:\\vdots)/,/^(?:\\VDash)/,/^(?:\\Vdash)/,/^(?:\\vDash)/,/^(?:\\vdash)/,/^(?:\\Vbar)/,/^(?:\\vartriangleright)/,
+/^(?:\\vartriangleleft)/,/^(?:\\vartriangle)/,/^(?:\\vartheta)/,/^(?:\\varsupsetneqq)/,/^(?:\\varsupsetneq)/,/^(?:\\varsubsetneqq)/,/^(?:\\varsubsetneqq)/,/^(?:\\varsubsetneq)/,/^(?:\\varsigma)/,/^(?:\\varrho)/,/^(?:\\varpropto)/,/^(?:\\varpi)/,/^(?:\\varphi)/,/^(?:\\varnothing)/,/^(?:\\varkappa)/,/^(?:\\varepsilon)/,/^(?:\\Uuparrow)/,/^(?:\\upuparrows)/,/^(?:\\Upsilon)/,/^(?:\\upsilon)/,/^(?:\\Upsi)/,/^(?:\\uplus)/,/^(?:\\upint)/,/^(?:\\upharpoonright)/,/^(?:\\upharpoonleft)/,/^(?:\\Updownarrow)/,
+/^(?:\\updownarrow)/,/^(?:\\updarr)/,/^(?:\\Uparrow)/,/^(?:\\uparrow)/,/^(?:\\uparr)/,/^(?:\\unrhd)/,/^(?:\\unlhd)/,/^(?:\\Union)/,/^(?:\\union)/,/^(?:\\underset)/,/^(?:\\underoverset)/,/^(?:\\underline)/,/^(?:\\underbrace)/,/^(?:\\udots)/,/^(?:\u2ADD\u0338)/,/^(?:\u2ACC\uFE00)/,/^(?:\u2ACB\uFE00)/,/^(?:\u2AB0\u0338)/,/^(?:\u2AAF\u0338)/,/^(?:\u2AA2\u0338)/,/^(?:\u2AA1\u0338)/,/^(?:\u2A7E\u0338)/,/^(?:\u2A7D\u0338)/,/^(?:\u29D0\u0338)/,/^(?:\u29CF\u0338)/,/^(?:\u2290\u0338)/,/^(?:\u228F\u0338)/,/^(?:\u228B\uFE00)/,
+/^(?:\u228A\uFE00)/,/^(?:\u2283\u20D2)/,/^(?:\u2282\u20D2)/,/^(?:\u227F\u0338)/,/^(?:\u226B\u0338)/,/^(?:\u226A\u0338)/,/^(?:\u2269\uFE00)/,/^(?:\u2268\uFE00)/,/^(?:\u2266\u0338)/,/^(?:\u224F\u0338)/,/^(?:\u224E\u0338)/,/^(?:\u2242\u0338)/,/^(?:\u223D\u0331)/,/^(?:\u2237\u2248)/,/^(?:\u2237\u223C)/,/^(?:\u2237\u2212)/,/^(?:\u2236\u2248)/,/^(?:\u2236\u223C)/,/^(?:\u2212\u2237)/,/^(?:\u007C\u007C\u007C)/,/^(?:\u007C\u007C)/,/^(?:\u003E\u003D)/,/^(?:\u003D\u2237)/,/^(?:\u003D\u2237)/,/^(?:\u003D\u003D)/,
+/^(?:\u003C\u003E)/,/^(?:\u003C\u003D)/,/^(?:\u003A\u003D)/,/^(?:\u002F\u003D)/,/^(?:\u002F\u002F)/,/^(?:\u002E\u002E\u002E)/,/^(?:\u002E\u002E)/,/^(?:\u002D\u003E)/,/^(?:\u002D\u003D)/,/^(?:\u002D\u002D)/,/^(?:\u002B\u003D)/,/^(?:\u002B\u002B)/,/^(?:\u002A\u003D)/,/^(?:\u002A\u002A)/,/^(?:\u0026\u0026)/,/^(?:\u0021\u003D)/,/^(?:\u0021\u0021)/,/^(?:\\twoheadrightarrowtail)/,/^(?:\\twoheadrightarrow)/,/^(?:\\twoheadleftarrow)/,/^(?:\\tripleintegral)/,/^(?:\\trianglerighteq)/,/^(?:\\triangleright)/,
+/^(?:\\triangleq)/,/^(?:\\trianglelefteq)/,/^(?:\\triangleleft)/,/^(?:\\triangledown)/,/^(?:\\triangle)/,/^(?:\\towa)/,/^(?:\\tosa)/,/^(?:\\top)/,/^(?:\\tooltip)/,/^(?:\\tona)/,/^(?:\\toggle)/,/^(?:\\toea)/,/^(?:\\to)/,/^(?:\\timesb)/,/^(?:\\times)/,/^(?:\\tilde)/,/^(?:\\thinspace)/,/^(?:\\thickspace)/,/^(?:\\thicksim)/,/^(?:\\thickapprox)/,/^(?:\\Theta)/,/^(?:\\theta)/,/^(?:\\therefore)/,/^(?:\\tfrac)/,/^(?:\\textstyle)/,/^(?:\\textsize)/,/^(?:\\textquotedblright)/,/^(?:\\textquotedblleft)/,/^(?:\\textasciitilde)/,
+/^(?:\\textasciigrave)/,/^(?:\\textasciicircumflex)/,/^(?:\\textasciiacute)/,/^(?:\\text)/,/^(?:\\tensor)/,/^(?:\\tbinom)/,/^(?:\\Tau)/,/^(?:\\tau)/,/^(?:\\swArrow)/,/^(?:\\swarrow)/,/^(?:\\swArr)/,/^(?:\\swarr)/,/^(?:\\surd)/,/^(?:\\supsetneqq)/,/^(?:\\supsetneq)/,/^(?:\\supseteqq)/,/^(?:\\supseteq)/,/^(?:\\Supset)/,/^(?:\\supset)/,/^(?:\\sum)/,/^(?:\\succsim)/,/^(?:\\succnsim)/,/^(?:\\succneqq)/,/^(?:\\succnapprox)/,/^(?:\\succeq)/,/^(?:\\succcurlyeq)/,/^(?:\\succapprox)/,/^(?:\\succ)/,/^(?:\\substack)/,
+/^(?:\\subsetneqq)/,/^(?:\\subsetneq)/,/^(?:\\subseteqq)/,/^(?:\\subseteq)/,/^(?:\\Subset)/,/^(?:\\subset)/,/^(?:\\statusline)/,/^(?:\\star)/,/^(?:\\stackrel)/,/^(?:\\sslash)/,/^(?:\\square)/,/^(?:\\sqsupseteq)/,/^(?:\\sqsupset)/,/^(?:\\sqsubseteq)/,/^(?:\\sqsubset)/,/^(?:\\sqrt)/,/^(?:\\sqcup)/,/^(?:\\sqcap)/,/^(?:\\sphericalangle)/,/^(?:\\spadesuit)/,/^(?:\\space)/,/^(?:\\smile)/,/^(?:\\smallsmile)/,/^(?:\\smallsetminus)/,/^(?:\\smallfrown)/,/^(?:\\slash)/,/^(?:\\simeq)/,/^(?:\\sim)/,/^(?:\\Sigma)/,
+/^(?:\\sigma)/,/^(?:\\shuffle)/,/^(?:\\shortparallel)/,/^(?:\\shortmid)/,/^(?:\\sharp)/,/^(?:\\setminus)/,/^(?:\\seovnearrow)/,/^(?:\\seArrow)/,/^(?:\\searrow)/,/^(?:\\seArr)/,/^(?:\\searr)/,/^(?:\\scriptsize)/,/^(?:\\scriptscriptsize)/,/^(?:\\rtimes)/,/^(?:\\Rsh)/,/^(?:\\Rrightarrow)/,/^(?:\\rrangle)/,/^(?:\\rq)/,/^(?:\\rowspan)/,/^(?:\\rowopts)/,/^(?:\\rowlines)/,/^(?:\\rowalign)/,/^(?:\\root)/,/^(?:\\rmoustache)/,/^(?:\\risingdotseq)/,/^(?:\\righttoleftarrow)/,/^(?:\\rightthreetimes)/,/^(?:\\rightsquigarrow)/,
+/^(?:\\rightrightarrows)/,/^(?:\\rightleftharpoons)/,/^(?:\\rightleftarrows)/,/^(?:\\rightharpoonup)/,/^(?:\\rightharpoondown)/,/^(?:\\rightarrowtriangle)/,/^(?:\\rightarrowtail)/,/^(?:\\Rightarrow)/,/^(?:\\rightarrow)/,/^(?:\\right)/,/^(?:\\Rho)/,/^(?:\\rho)/,/^(?:\\rhd)/,/^(?:\\rfloor)/,/^(?:\\Re)/,/^(?:\\rdiagovsearrow)/,/^(?:\\rdiagovfdiag)/,/^(?:\\rceil)/,/^(?:\\rbrack)/,/^(?:\\rbrace)/,/^(?:\\rangle)/,/^(?:\\rang)/,/^(?:\\questeq)/,/^(?:\\quadrupleintegral)/,/^(?:\\quad)/,/^(?:\\qquad)/,/^(?:\\qed)/,
+/^(?:\\Psi)/,/^(?:\\psi)/,/^(?:\\propto)/,/^(?:\\product)/,/^(?:\\prod)/,/^(?:\\prime)/,/^(?:\\precsim)/,/^(?:\\precnsim)/,/^(?:\\precneqq)/,/^(?:\\precnapprox)/,/^(?:\\preceq)/,/^(?:\\preccurlyeq)/,/^(?:\\precapprox)/,/^(?:\\prec)/,/^(?:\\pmod)/,/^(?:\\pm)/,/^(?:\\plusdot)/,/^(?:\\plusb)/,/^(?:\\pitchfork)/,/^(?:\\Pi)/,/^(?:\\pi)/,/^(?:\\Phi)/,/^(?:\\phi)/,/^(?:\\phantom)/,/^(?:\\Perp)/,/^(?:\\perp)/,/^(?:\\partialmeetcontraction)/,/^(?:\\partial)/,/^(?:\\parr)/,/^(?:\\parallel)/,/^(?:\\padding)/,
+/^(?:\\overset)/,/^(?:\\overline)/,/^(?:\\overbrace)/,/^(?:\\over)/,/^(?:\\Otimes)/,/^(?:\\otimes)/,/^(?:\\oslash)/,/^(?:[\u007E\u00AF\u02C6\u02C7\u02C9\u02CD\u02DC\u02F7\u0302\u203E\u2044\u2190-\u2199\u219C-\u21AD\u21AF-\u21B5\u21B9\u21BC-\u21CC\u21D0-\u21DD\u21E0-\u21F0\u21F3\u21F5\u21F6\u21FD-\u21FF\u2215\u221A\u23B4\u23B5\u23DC-\u23E1\u27F0\u27F1\u27F5-\u27FF\u290A-\u2910\u2912\u2913\u2921\u2922\u294E-\u2961\u296E\u296F\u2B45\u2B46])/,/^(?:[\u2032-\u2035\u2057])/,/^(?:[\u220F-\u2211\u22C0-\u22C3\u2A00-\u2A0A\u2A10-\u2A14\u2AFC\u2AFF])/,
+/^(?:\\Oplus)/,/^(?:\\oplus)/,/^(?:[\u0028\u0029\u005B\u005D\u007C\u2016\u2308-\u230B\u2329\u232A\u2772\u2773\u27E6-\u27EF\u2980\u2983-\u2998\u29FC\u29FD])/,/^(?:[\u2018\u2019\u201C\u201D])/,/^(?:\\operatorname)/,/^(?:[\u0021-\u0023\u002A-\u002C\u002F\u003A-\u0040\u0060\u00A8\u00AA\u00AC\u00B0-\u00B4\u00B7-\u00BA\u00D7\u00F7\u02CA\u02CB\u02D8-\u02DA\u02DD\u0311\u03F6\u201A\u201B\u201E-\u2022\u2026\u2036\u2037\u2043\u2061-\u2064\u20DB\u20DC\u2145\u2146\u214B\u219A\u219B\u21AE\u21B6-\u21B8\u21BA\u21BB\u21CD-\u21CF\u21DE\u21DF\u21F1\u21F2\u21F4\u21F7-\u21FC\u2200-\u2204\u2206-\u220E\u2212-\u2214\u2216-\u2219\u221B-\u221D\u221F-\u22BF\u22C4-\u22FF\u2305\u2306\u2322\u2323\u23B0\u23B1\u25A0\u25A1\u25AA\u25AB\u25AD-\u25B9\u25BC-\u25CF\u25D6\u25D7\u25E6\u2605\u2660-\u2663\u266D-\u266F\u2758\u27F2\u27F3\u2900-\u2909\u2911\u2914-\u2920\u2923-\u294D\u2962-\u296D\u2970-\u297F\u2981\u2982\u2999-\u29D9\u29DB-\u29FB\u29FE\u29FF\u2A0B-\u2A0F\u2A15-\u2ADB\u2ADD-\u2AFB\u2AFD\u2AFE])/,
+/^(?:\\ominus)/,/^(?:\\omicron)/,/^(?:\\Omega)/,/^(?:\\omega)/,/^(?:\\oint)/,/^(?:\\oiint)/,/^(?:\\oiiint)/,/^(?:\\odot)/,/^(?:\\odash)/,/^(?:\\obslash)/,/^(?:\\nwovnearrow)/,/^(?:\\nwArrow)/,/^(?:\\nwarrow)/,/^(?:\\nwArr)/,/^(?:\\nwarr)/,/^(?:\\nVDash)/,/^(?:\\nVdash)/,/^(?:\\nvDash)/,/^(?:\\nvdash)/,/^(?:\u221E)/,/^(?:\\Nu)/,/^(?:\\nu)/,/^(?:\\ntrianglerighteq)/,/^(?:\\ntriangleright)/,/^(?:\\ntrianglelefteq)/,/^(?:\\ntriangleleft)/,/^(?:\\nsupseteq)/,/^(?:\\nsupset)/,/^(?:\\nsuccsim)/,/^(?:\\nsucceq)/,
+/^(?:\\nsucc)/,/^(?:\\nsubseteqq)/,/^(?:\\nsubseteq)/,/^(?:\\nsubset)/,/^(?:\\nsime)/,/^(?:\\nsim)/,/^(?:\\nshortparallel)/,/^(?:\\nshortmid)/,/^(?:\\nRightarrow)/,/^(?:\\nrightarrow)/,/^(?:\\npreceq)/,/^(?:\\nprec)/,/^(?:\\nparallel)/,/^(?:\\notni)/,/^(?:\\notin)/,/^(?:\\not)/,/^(?:\\nmid)/,/^(?:\\nless)/,/^(?:\\nleqslant)/,/^(?:\\nleqq)/,/^(?:\\nleq)/,/^(?:\\nLeftrightarrow)/,/^(?:\\nleftrightarrow)/,/^(?:\\nLeftarrow)/,/^(?:\\nleftarrow)/,/^(?:\\ni)/,/^(?:\\ngtr)/,/^(?:\\ngeqslant)/,/^(?:\\ngeqq)/,
+/^(?:\\ngeq)/,/^(?:\\nexists)/,/^(?:\\nequiv)/,/^(?:\\neqsim)/,/^(?:\\neq)/,/^(?:\\neovsearrow)/,/^(?:\\neovnwarrow)/,/^(?:\\negthickspace)/,/^(?:\\negspace)/,/^(?:\\negmedspace)/,/^(?:\\neg)/,/^(?:\\neArrow)/,/^(?:\\nearrow)/,/^(?:\\neArr)/,/^(?:\\nearr)/,/^(?:\\ne)/,/^(?:\\ncong)/,/^(?:\\nBumpeq)/,/^(?:\\nbumpeq)/,/^(?:\\natural)/,/^(?:\\napprox)/,/^(?:\\nabla)/,/^(?:\\multiscripts)/,/^(?:\\multimap)/,/^(?:\\Mu)/,/^(?:\\mu)/,/^(?:\\mtext)/,/^(?:\\ms)/,/^(?:\\mp)/,/^(?:\\models)/,/^(?:\\mod)/,/^(?:\\mo)/,
+/^(?:\\mn)/,/^(?:\\mlcp)/,/^(?:\\minusdot)/,/^(?:\\minusb)/,/^(?:\\minus)/,/^(?:\\min)/,/^(?:\\mid)/,/^(?:\\mi)/,/^(?:\\mho)/,/^(?:\\mho)/,/^(?:\\medspace)/,/^(?:\\measuredangle)/,/^(?:\\mathtt)/,/^(?:\\mathsf)/,/^(?:\\mathscr)/,/^(?:\\mathrm)/,/^(?:\\mathrlap)/,/^(?:\\mathrel)/,/^(?:\\mathraisebox)/,/^(?:\\mathop)/,/^(?:\\mathmit)/,/^(?:\\mathllap)/,/^(?:\\mathit)/,/^(?:\\mathfrak)/,/^(?:\\mathfr)/,/^(?:\\mathclap)/,/^(?:\\mathcal)/,/^(?:\\mathbscr)/,/^(?:\\mathbit)/,/^(?:\\mathbin)/,/^(?:\\mathbf)/,
+/^(?:\\mathbcal)/,/^(?:\\mathbb)/,/^(?:\\Mapsto)/,/^(?:\\mapsto)/,/^(?:\\Mapsfrom)/,/^(?:\\map)/,/^(?:\\lvertneqq)/,/^(?:\\lvertneqq)/,/^(?:\\ltimes)/,/^(?:\\lt)/,/^(?:\\Lsh)/,/^(?:\\lq)/,/^(?:\\lozenge)/,/^(?:\\lowint)/,/^(?:\\looparrowright)/,/^(?:\\looparrowleft)/,/^(?:\\Longrightarrow)/,/^(?:\\longrightarrow)/,/^(?:\\longmapsto)/,/^(?:\\Longleftrightarrow)/,/^(?:\\longleftrightarrow)/,/^(?:\\Longleftarrow)/,/^(?:\\longleftarrow)/,/^(?:\\lnsim)/,/^(?:\\lneqq)/,/^(?:\\lneq)/,/^(?:\\lnapprox)/,/^(?:\\lmoustache)/,
+/^(?:\\lll)/,/^(?:\\Lleftarrow)/,/^(?:\\llangle)/,/^(?:\\ll)/,/^(?:\\lhd)/,/^(?:\\lfloor)/,/^(?:\\lesssim)/,/^(?:\\lessgtr)/,/^(?:\\lesseqqgtr)/,/^(?:\\lesseqgtr)/,/^(?:\\lessdot)/,/^(?:\\lessapprox)/,/^(?:\\less)/,/^(?:\\leqslant)/,/^(?:\\leqq)/,/^(?:\\leq)/,/^(?:\\lefttorightarrow)/,/^(?:\\leftthreetimes)/,/^(?:\\leftsquigarrow)/,/^(?:\\leftrightsquigarrow)/,/^(?:\\leftrightharpoons)/,/^(?:\\leftrightarrowtria\*)/,/^(?:\\leftrightarrows)/,/^(?:\\Leftrightarrow)/,/^(?:\\leftrightarrow)/,/^(?:\\leftleftarrows)/,
+/^(?:\\leftharpoonup)/,/^(?:\\leftharpoondown)/,/^(?:\\leftarrowtriangle)/,/^(?:\\leftarrowtail)/,/^(?:\\Leftarrow)/,/^(?:\\leftarrow)/,/^(?:\\left)/,/^(?:\\le)/,/^(?:\\ldots)/,/^(?:\\lceil)/,/^(?:\\lbrack)/,/^(?:\\lbrace)/,/^(?:\\langle)/,/^(?:\\lang)/,/^(?:\\Lambda)/,/^(?:\\lambda)/,/^(?:\\kernelcontraction)/,/^(?:\\Kappa)/,/^(?:\\kappa)/,/^(?:\\jmath)/,/^(?:\\itexnum)/,/^(?:\\Iota)/,/^(?:\\iota)/,/^(?:\\invamp)/,/^(?:\\intx)/,/^(?:\\intprodr)/,/^(?:\\intprod)/,/^(?:\\Intersection)/,/^(?:\\intersection)/,
+/^(?:\\interleave)/,/^(?:\\intercal)/,/^(?:\\integral)/,/^(?:\\intcup)/,/^(?:\\intcap)/,/^(?:\\intBar)/,/^(?:\\intbar)/,/^(?:\\int)/,/^(?:\\infty)/,/^(?:\\infinity)/,/^(?:\\inf)/,/^(?:\\in)/,/^(?:\\implies)/,/^(?:\\impliedby)/,/^(?:\\imath)/,/^(?:\\Im)/,/^(?:\\iint)/,/^(?:\\iiint)/,/^(?:\\iiiint)/,/^(?:\\iff)/,/^(?:\\hslash)/,/^(?:\\href)/,/^(?:\\hookrightarrow)/,/^(?:\\hookleftarrow)/,/^(?:\\hkswarow)/,/^(?:\\hksearow)/,/^(?:\\heartsuit)/,/^(?:\\hbar)/,/^(?:\\hat)/,/^(?:\\gvertneqq)/,/^(?:\\gvertneqq)/,
+/^(?:\\gtrsim)/,/^(?:\\gtrless)/,/^(?:\\gtreqqless)/,/^(?:\\gtreqless)/,/^(?:\\gtrdot)/,/^(?:\\gtrapprox)/,/^(?:\\gt)/,/^(?:\\greater)/,/^(?:\\gnsim)/,/^(?:\\gneqq)/,/^(?:\\gneq)/,/^(?:\\gnapprox)/,/^(?:\\gimel)/,/^(?:\\ggg)/,/^(?:\\gg)/,/^(?:\\geqslant)/,/^(?:\\geqq)/,/^(?:\\geq)/,/^(?:\\ge)/,/^(?:\\Gamma)/,/^(?:\\gamma)/,/^(?:\\frown)/,/^(?:\\frame)/,/^(?:\\frac)/,/^(?:\\forksnot)/,/^(?:\\forks)/,/^(?:\\forall)/,/^(?:\\flat)/,/^(?:\\fdiagovrdiag)/,/^(?:\\fdiagovnearrow)/,/^(?:\\fallingdotseq)/,
+/^(?:\\exists)/,/^(?:\\eth)/,/^(?:\\eth)/,/^(?:\\Eta)/,/^(?:\\eta)/,/^(?:\\equiv)/,/^(?:\\equalrows)/,/^(?:\\equalcols)/,/^(?:\\eqslantless)/,/^(?:\\eqslantgtr)/,/^(?:\\eqsim)/,/^(?:\\Eqqcolon)/,/^(?:\\eqqcolon)/,/^(?:\\Eqcolon)/,/^(?:\\Eqcolon)/,/^(?:\\Eqcolon)/,/^(?:\\Eqcolon)/,/^(?:\\eqcolon)/,/^(?:\\eqcirc)/,/^(?:\\epsilon)/,/^(?:\\end\{Vmatrix\})/,/^(?:\\end\{vmatrix\})/,/^(?:\\endtoggle)/,/^(?:\\end\{split\})/,/^(?:\\end\{smallmatrix\})/,/^(?:\\end\{pmatrix\})/,/^(?:\\end\{matrix\})/,/^(?:\\end\{gathered\})/,
+/^(?:\\end\{cases\})/,/^(?:\\end\{Bmatrix\})/,/^(?:\\end\{bmatrix\})/,/^(?:\\end\{array\})/,/^(?:\\end\{aligned\})/,/^(?:\\emptyset)/,/^(?:\\empty)/,/^(?:\\embedsin)/,/^(?:\\ell)/,/^(?:\\duparr)/,/^(?:\\dualmap)/,/^(?:\\drbkarrow)/,/^(?:\\downuparrow)/,/^(?:\\downharpoonright)/,/^(?:\\downharpoonleft)/,/^(?:\\downdownarrows)/,/^(?:\\Downarrow)/,/^(?:\\downarrow)/,/^(?:\\doubleintegral)/,/^(?:\\doublebarwedge)/,/^(?:\\doublebarwedge)/,/^(?:\\dots)/,/^(?:\\dotplus)/,/^(?:\\dotminus)/,/^(?:\\doteqdot)/,
+/^(?:\\Doteq)/,/^(?:\\doteq)/,/^(?:\\dot)/,/^(?:\\divideontimes)/,/^(?:\\div)/,/^(?:\\displaystyle)/,/^(?:\\disjquant)/,/^(?:\\digamma)/,/^(?:\\diamondsuit)/,/^(?:\\Diamond)/,/^(?:\\diamond)/,/^(?:\\det|\\gcd|\\liminf|\\limsup|\\lim|\\max|\\Pr|\\sup)/,/^(?:\\Delta)/,/^(?:\\delta)/,/^(?:\\Del)/,/^(?:\\degree)/,/^(?:\\Ddownarrow)/,/^(?:\\ddotseq)/,/^(?:\\ddots)/,/^(?:\\ddot)/,/^(?:\\dddot)/,/^(?:\\dddot)/,/^(?:\\ddddot)/,/^(?:\\ddddot)/,/^(?:\\ddagger)/,/^(?:\\dblcolon)/,/^(?:\\dbkarow)/,/^(?:\\Dashv)/,
+/^(?:\\dashV)/,/^(?:\\dashv)/,/^(?:\\dashrightarrow)/,/^(?:\\dashleftarrow)/,/^(?:\\darr)/,/^(?:\\daleth)/,/^(?:\\dagger)/,/^(?:\\curvearrowright)/,/^(?:\\curvearrowleft)/,/^(?:\\curvearrowbotright)/,/^(?:\\curlywedge)/,/^(?:\\curlyvee)/,/^(?:\\curlyeqsucc)/,/^(?:\\curlyeqprec)/,/^(?:\\cupdot)/,/^(?:\\Cup)/,/^(?:\\cup)/,/^(?:\\coproduct)/,/^(?:\\coprod)/,/^(?:\\contourintegral)/,/^(?:\\conjquant)/,/^(?:\\conint)/,/^(?:\\cong)/,/^(?:\\complement)/,/^(?:\\colspan)/,/^(?:\\color)/,/^(?:\\Colonsim)/,
+/^(?:\\colonsim)/,/^(?:\\Coloneqq)/,/^(?:\\coloneqq)/,/^(?:\\Coloneq)/,/^(?:\\coloneq)/,/^(?:\\Colonapprox)/,/^(?:\\colonapprox)/,/^(?:\\Colon)/,/^(?:\\colon)/,/^(?:\\collines)/,/^(?:\\collayout)/,/^(?:\\colalign)/,/^(?:\\clubsuit)/,/^(?:\\closure)/,/^(?:\\circleddash)/,/^(?:\\circledcirc)/,/^(?:\\circledast)/,/^(?:\\circlearrowright)/,/^(?:\\circlearrowleft)/,/^(?:\\circeq)/,/^(?:\\circ)/,/^(?:\\choose)/,/^(?:\\chi)/,/^(?:\\check)/,/^(?:\\cellopts)/,/^(?:\\cdots)/,/^(?:\\cdotp)/,/^(?:\\cdot)/,/^(?:\\Cap)/,
+/^(?:\\cap)/,/^(?:\\bumpeqq)/,/^(?:\\Bumpeq)/,/^(?:\\bumpeq)/,/^(?:\\bullet)/,/^(?:\\btimes)/,/^(?:\\boxtimes)/,/^(?:\\boxplus)/,/^(?:\\boxminus)/,/^(?:\\boxed)/,/^(?:\\boxdot)/,/^(?:\\boxdiag)/,/^(?:\\boxcircle)/,/^(?:\\boxbslash)/,/^(?:\\boxast)/,/^(?:\\Box)/,/^(?:\\bowtie)/,/^(?:\\bottom)/,/^(?:\\bot)/,/^(?:\\boldsymbol)/,/^(?:\\blacktriangleright)/,/^(?:\\blacktriangleleft)/,/^(?:\\blacktriangledown)/,/^(?:\\blacktriangle)/,/^(?:\\blacksquare)/,/^(?:\\blacklozenge)/,/^(?:\\bkarow)/,/^(?:\\binom)/,
+/^(?:\\bigwedge)/,/^(?:\\bigvee)/,/^(?:\\biguplus)/,/^(?:\\bigtriangleup)/,/^(?:\\bigtriangledown)/,/^(?:\\bigtimes)/,/^(?:\\bigstar)/,/^(?:\\bigsqcup)/,/^(?:\\bigsqcap)/,/^(?:\\Bigr)/,/^(?:\\bigr)/,/^(?:\\bigotimes)/,/^(?:\\bigoplus)/,/^(?:\\bigodot)/,/^(?:\\Bigl)/,/^(?:\\bigl)/,/^(?:\\biginterleave)/,/^(?:\\Biggr)/,/^(?:\\biggr)/,/^(?:\\Biggl)/,/^(?:\\biggl)/,/^(?:\\Bigg)/,/^(?:\\bigg)/,/^(?:\\bigcupdot)/,/^(?:\\bigcup)/,/^(?:\\bigcirc)/,/^(?:\\bigcap)/,/^(?:\\Big)/,/^(?:\\big)/,/^(?:\\bgcolor)/,
+/^(?:\\between)/,/^(?:\\beth)/,/^(?:\\Beta)/,/^(?:\\beta)/,/^(?:\\begin\{Vmatrix\})/,/^(?:\\begin\{vmatrix\})/,/^(?:\\begintoggle)/,/^(?:\\begin\{split\})/,/^(?:\\begin\{smallmatrix\})/,/^(?:\\begin\{pmatrix\})/,/^(?:\\begin\{matrix\})/,/^(?:\\begin\{gathered\})/,/^(?:\\begin\{cases\})/,/^(?:\\begin\{Bmatrix\})/,/^(?:\\begin\{bmatrix\})/,/^(?:\\begin\{array\})/,/^(?:\\begin\{aligned\})/,/^(?:\\because)/,/^(?:\\BbbPi)/,/^(?:\\barwedge)/,/^(?:\\bar)/,/^(?:\\backslash)/,/^(?:\\backsimeq)/,/^(?:\\backsim)/,
+/^(?:\\backprime)/,/^(?:\\backepsilon)/,/^(?:\\atop)/,/^(?:\\asymp)/,/^(?:\\ast)/,/^(?:\\arrayopts)/,/^(?:\\array)/,/^(?:\\arccos|\\arcsin|\\arctan|\\arg|\\cosh|\\cos|\\coth|\\cot|\\csc|\\deg|\\dim|\\exp|\\hom|\\ker|\\lg|\\ln|\\log|\\sec|\\sinh|\\sin|\\tanh|\\tan)/,/^(?:\\approxeq)/,/^(?:\\approx)/,/^(?:\\angle)/,/^(?:\\amalg)/,/^(?:\\Alpha)/,/^(?:\\alpha)/,/^(?:\\align)/,/^(?:\\aleph)/,/^(?:[\u0041-\u005A])/,/^(?:[\u0391-\u03A1\u03A3\u03A4\u03A6-\u03A9])/,/^(?:[\u0061-\u007A\u0131\u0237])/,/^(?:[\u03B1-\u03C1\u03C3-\u03C9\u03D1\u03D5\u03D6\u03F0\u03F1\u03F4\u03F5])/,
+/^(?:\\adots)/,/^(?:\\AA)/,/^(?:[\u00F0\u03C2\u03D0\u03D2\u03DA-\u03DD\u03E0\u03E1\u0428\u0608\u0627-\u063A\u2102\u210A-\u210D\u210F-\u2113\u2115\u2118-\u211D\u2124\u2127\u2128\u212B-\u212D\u212F-\u2131\u2133-\u2138\u213C\u213D\u213F\u2205]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB\uDEF0\uDEF1]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDFCB])/,
+/^(?:\\\$)/,/^(?:\\\})/,/^(?:\\\|)/,/^(?:\\\{)/,/^(?:\\;)/,/^(?:\\:)/,/^(?:\\,)/,/^(?:\\&)/,/^(?:\\%)/,/^(?:\\#)/,/^(?:\\!)/,/^(?:-)/,/^(?:'''')/,/^(?:''')/,/^(?:'')/,/^(?:')/,/^(?:[\uD800-\uDBFF])/,/^(?:[\uDC00-\uDFFF])/,/^(?:.)/],M:{MATH0:{rules:[14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,
+99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,
+225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,
+351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,
+477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,
+603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,
+729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,
+855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883],inclusive:tb},MATH1:{rules:[14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,
+125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,
+251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,
+377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,
+503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,
+629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,
+755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,
+881,882,883],inclusive:tb},OPTARG:{rules:[13,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,
+151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,
+277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,
+403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,
+529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,
+655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,
+781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883],inclusive:tb},DOCUMENT:{rules:[1,2,3,4,5],inclusive:yb},TRYOPTARG:{rules:[6,7],inclusive:yb},
+TEXTOPTARG:{rules:[8,9],inclusive:yb},TEXTARG:{rules:[10,11,12],inclusive:yb},INITIAL:{rules:[0,14,15,16,17,18,19,20,21,22,23,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,
+138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,
+264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,
+390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,
+516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,
+642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,
+768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883],inclusive:tb}}}}();Rb.prototype=rb;rb.pa=
+Rb;return new Rb}();window.TeXZilla=zb;window.TeXZilla.setDOMParser=zb.fa;window.TeXZilla.setXMLSerializer=zb.ja;window.TeXZilla.setSafeMode=zb.ia;window.TeXZilla.setItexIdentifierMode=zb.ha;window.TeXZilla.getTeXSource=zb.ca;window.TeXZilla.toMathMLString=zb.Z;window.TeXZilla.toMathML=zb.Y;window.TeXZilla.toImage=zb.na;window.TeXZilla.filterString=zb.Q;window.TeXZilla.filterElement=zb.P;
+})();
diff --git a/comm/suite/editor/components/texzilla/jar.mn b/comm/suite/editor/components/texzilla/jar.mn
new file mode 100644
index 0000000000..28d5a4cc3e
--- /dev/null
+++ b/comm/suite/editor/components/texzilla/jar.mn
@@ -0,0 +1,6 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+comm.jar:
+ content/editor/TeXZilla.js (content/TeXZilla.js)
diff --git a/comm/suite/editor/components/texzilla/moz.build b/comm/suite/editor/components/texzilla/moz.build
new file mode 100644
index 0000000000..de5cd1bf81
--- /dev/null
+++ b/comm/suite/editor/components/texzilla/moz.build
@@ -0,0 +1,6 @@
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+JAR_MANIFESTS += ["jar.mn"]