/* 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 ../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.firstElementChild.firstElementChild.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); } let useMenulist = false; // Editable menulist vs. input for the value. var newValue = ""; if (valueListName in gHTMLAttr) { var valueList = gHTMLAttr[valueListName]; let listLen = valueList.length; useMenulist = listLen > 1; 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 (useMenulist) { gDialog.AddHTMLAttributeValueMenulist.removeAllItems(); // 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 (useMenulist) { // Switch to using editable menulist instead of the input. gDialog.AddHTMLAttributeValueMenulist.parentElement.collapsed = false; gDialog.AddHTMLAttributeValueTextbox.parentElement.collapsed = true; gDialog.AddHTMLAttributeValueInput = gDialog.AddHTMLAttributeValueMenulist; } else { // No list: Use input instead of editable menulist. gDialog.AddHTMLAttributeValueMenulist.parentElement.collapsed = true; gDialog.AddHTMLAttributeValueTextbox.parentElement.collapsed = false; gDialog.AddHTMLAttributeValueInput = gDialog.AddHTMLAttributeValueTextbox; } // 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.children.length; i++) { var item = HTMLAList.children[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; }