Revision control
Copy as Markdown
Other Tools
/* 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
/* 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
const forceOneChar = name.includes("!");
const forceInteger = name.includes("#");
const forceSignedInteger = name.includes("+");
const forceIntOrPercent = name.includes("%");
const 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++) {
const 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() {
const 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];
const 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;
}