!import
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is Mozilla Communicator client code, released
15 * March 31, 1998.
16 *
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-1999
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 * Ben "Count XULula" Goodger
24 *
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
36 *
37 * ***** END LICENSE BLOCK ***** */
38
BuildHTMLAttributeNameList
39 function BuildHTMLAttributeNameList()
40 {
41 gDialog.AddHTMLAttributeNameInput.removeAllItems();
42
43 var elementName = gElement.localName.toLowerCase();
44 var attNames = gHTMLAttr[elementName];
45
46 if (attNames && attNames.length)
47 {
48 var menuitem;
49
50 for (var i = 0; i < attNames.length; i++)
51 {
52 var name = attNames[i];
53 var limitFirstChar;
54
55 if (name == "_core")
56 {
57 // Signal to append the common 'core' attributes.
58 for (var j = 0; j < gCoreHTMLAttr.length; j++)
59 {
60 name = gCoreHTMLAttr[j];
61
62 // "limitFirstChar" is the only filtering rule used for core attributes as of 8-20-01
63 // Add more rules if necessary
64 limitFirstChar = name.indexOf("^") >= 0;
65 if (limitFirstChar)
66 {
67 menuitem = gDialog.AddHTMLAttributeNameInput.appendItem(name.replace(/\^/g, ""));
68 menuitem.setAttribute("limitFirstChar", "true");
69 }
70 else
71 gDialog.AddHTMLAttributeNameInput.appendItem(name);
72 }
73 }
74 else if (name == "-")
75 {
76 // Signal for separator
77 var popup = gDialog.AddHTMLAttributeNameInput.firstChild;
78 if (popup)
79 {
80 var sep = document.createElementNS(XUL_NS, "menuseparator");
81 if (sep)
82 popup.appendChild(sep);
83 }
84 }
85 else
86 {
87 // Get information about value filtering
88 var forceOneChar = name.indexOf("!") >= 0;
89 var forceInteger = name.indexOf("#") >= 0;
90 var forceSignedInteger = name.indexOf("+") >= 0;
91 var forceIntOrPercent = name.indexOf("%") >= 0;
92 limitFirstChar = name.indexOf("\^") >= 0;
93 //var required = name.indexOf("$") >= 0;
94
95 // Strip flag characters
96 name = name.replace(/[!^#%$+]/g, "");
97
98 menuitem = gDialog.AddHTMLAttributeNameInput.appendItem(name);
99 if (menuitem)
100 {
101 // Signify "required" attributes by special style
102 //TODO: Don't do this until next version, when we add
103 // explanatory text and an 'Autofill Required Attributes' button
104 //if (required)
105 // menuitem.setAttribute("class", "menuitem-highlight-1");
106
107 // Set flags to filter value input
108 if (forceOneChar)
109 menuitem.setAttribute("forceOneChar","true");
110 if (limitFirstChar)
111 menuitem.setAttribute("limitFirstChar", "true");
112 if (forceInteger)
113 menuitem.setAttribute("forceInteger", "true");
114 if (forceSignedInteger)
115 menuitem.setAttribute("forceSignedInteger", "true");
116 if (forceIntOrPercent)
117 menuitem.setAttribute("forceIntOrPercent", "true");
118 }
119 }
120 }
121 }
122 }
123
124 // build attribute list in tree form from element attributes
BuildHTMLAttributeTable
125 function BuildHTMLAttributeTable()
126 {
127 var nodeMap = gElement.attributes;
128 var i;
129 if (nodeMap.length > 0)
130 {
131 var added = false;
132 for(i = 0; i < nodeMap.length; i++)
133 {
134 if ( CheckAttributeNameSimilarity( nodeMap[i].nodeName, HTMLAttrs ) ||
135 IsEventHandler( nodeMap[i].nodeName ) ||
136 TrimString( nodeMap[i].nodeName.toLowerCase() ) == "style" ) {
137 continue; // repeated or non-HTML attribute, ignore this one and go to next
138 }
139 var name = nodeMap[i].name.toLowerCase();
140 if ( name.indexOf("_moz") != 0 &&
141 AddTreeItem(name, nodeMap[i].value, "HTMLAList", HTMLAttrs) )
142 {
143 added = true;
144 }
145 }
146
147 if (added)
148 SelectHTMLTree(0);
149 }
150 }
151
152 // add or select an attribute in the tree widget
onChangeHTMLAttribute
153 function onChangeHTMLAttribute()
154 {
155 var name = TrimString(gDialog.AddHTMLAttributeNameInput.value);
156 if (!name)
157 return;
158
159 var value = TrimString(gDialog.AddHTMLAttributeValueInput.value);
160
161 // First try to update existing attribute
162 // If not found, add new attribute
163 if (!UpdateExistingAttribute( name, value, "HTMLAList" ) && value)
164 AddTreeItem (name, value, "HTMLAList", HTMLAttrs);
165 }
166
ClearHTMLInputWidgets
167 function ClearHTMLInputWidgets()
168 {
169 gDialog.AddHTMLAttributeTree.view.selection.clearSelection();
170 gDialog.AddHTMLAttributeNameInput.value ="";
171 gDialog.AddHTMLAttributeValueInput.value = "";
172 SetTextboxFocus(gDialog.AddHTMLAttributeNameInput);
173 }
174
onSelectHTMLTreeItem
175 function onSelectHTMLTreeItem()
176 {
177 if (!gDoOnSelectTree)
178 return;
179
180 var tree = gDialog.AddHTMLAttributeTree;
181 if (tree && tree.view.selection.count)
182 {
183 var inputName = TrimString(gDialog.AddHTMLAttributeNameInput.value).toLowerCase();
184 var selectedItem = getSelectedItem(tree);
185 var selectedName = selectedItem.firstChild.firstChild.getAttribute("label");
186
187 if (inputName == selectedName)
188 {
189 // Already editing selected name - just update the value input
190 gDialog.AddHTMLAttributeValueInput.value = GetTreeItemValueStr(selectedItem);
191 }
192 else
193 {
194 gDialog.AddHTMLAttributeNameInput.value = selectedName;
195
196 // Change value input based on new selected name
197 onInputHTMLAttributeName();
198 }
199 }
200 }
201
onInputHTMLAttributeName
202 function onInputHTMLAttributeName()
203 {
204 var attName = TrimString(gDialog.AddHTMLAttributeNameInput.value).toLowerCase();
205
206 // Clear value widget, but prevent triggering update in tree
207 gUpdateTreeValue = false;
208 gDialog.AddHTMLAttributeValueInput.value = "";
209 gUpdateTreeValue = true;
210
211 if (attName)
212 {
213 // Get value list for current attribute name
214 var valueListName;
215
216 // Most elements have the "dir" attribute,
217 // so we have just one array for the allowed values instead
218 // requiring duplicate entries for each element in EdAEAttributes.js
219 if (attName == "dir")
220 valueListName = "all_dir";
221 else
222 valueListName = gElement.localName.toLowerCase() + "_" + attName;
223
224 // Strip off leading "_" we sometimes use (when element name is reserved word)
225 if (valueListName[0] == "_")
226 valueListName = valueListName.slice(1);
227
228 var newValue = "";
229 var listLen = 0;
230
231 // Index to which widget we were using to edit the value
232 var deckIndex = gDialog.AddHTMLAttributeValueDeck.getAttribute("selectedIndex");
233
234 if (valueListName in gHTMLAttr)
235 {
236 var valueList = gHTMLAttr[valueListName];
237
238 listLen = valueList.length;
239 if (listLen > 0)
240 newValue = valueList[0];
241
242 // Note: For case where "value list" is actually just
243 // one (default) item, don't use menulist for that
244 if (listLen > 1)
245 {
246 gDialog.AddHTMLAttributeValueMenulist.removeAllItems();
247
248 if (deckIndex != "1")
249 {
250 // Switch to using editable menulist
251 gDialog.AddHTMLAttributeValueInput = gDialog.AddHTMLAttributeValueMenulist;
252 gDialog.AddHTMLAttributeValueDeck.setAttribute("selectedIndex", "1");
253 }
254 // Rebuild the list
255 for (var i = 0; i < listLen; i++)
256 {
257 if (valueList[i] == "-")
258 {
259 // Signal for separator
260 var popup = gDialog.AddHTMLAttributeValueInput.firstChild;
261 if (popup)
262 {
263 var sep = document.createElementNS(XUL_NS, "menuseparator");
264 if (sep)
265 popup.appendChild(sep);
266 }
267 } else {
268 gDialog.AddHTMLAttributeValueMenulist.appendItem(valueList[i]);
269 }
270 }
271 }
272 }
273
274 if (listLen <= 1 && deckIndex != "0")
275 {
276 // No list: Use textbox for input instead
277 gDialog.AddHTMLAttributeValueInput = gDialog.AddHTMLAttributeValueTextbox;
278 gDialog.AddHTMLAttributeValueDeck.setAttribute("selectedIndex", "0");
279 }
280
281 // If attribute already exists in tree, use associated value,
282 // else use default found above
283 var existingValue = GetAndSelectExistingAttributeValue(attName, "HTMLAList");
284 if (existingValue)
285 newValue = existingValue;
286
287 gDialog.AddHTMLAttributeValueInput.value = newValue;
288 }
289 }
290
onInputHTMLAttributeValue
291 function onInputHTMLAttributeValue()
292 {
293 if (!gUpdateTreeValue)
294 return;
295
296 var name = TrimString(gDialog.AddHTMLAttributeNameInput.value);
297 if (!name)
298 return;
299
300 // Trim spaces only from left since we must allow spaces within the string
301 // (we always reset the input field's value below)
302 var value = TrimStringLeft(gDialog.AddHTMLAttributeValueInput.value);
303 if (value)
304 {
305 // Do value filtering based on type of attribute
306 // (Do not use "LimitStringLength()" and "forceInteger()"
307 // to avoid multiple reseting of input's value and flickering)
308 var selectedItem = gDialog.AddHTMLAttributeNameInput.selectedItem;
309
310 if (selectedItem)
311 {
312 if ( selectedItem.getAttribute("forceOneChar") == "true" &&
313 value.length > 1 )
314 value = value.slice(0, 1);
315
316 if ( selectedItem.getAttribute("forceIntOrPercent") == "true" )
317 {
318 // Allow integer with optional "%" as last character
319 var percent = TrimStringRight(value).slice(-1);
320 value = value.replace(/\D+/g,"");
321 if (percent == "%")
322 value += percent;
323 }
324 else if ( selectedItem.getAttribute("forceInteger") == "true" )
325 {
326 value = value.replace(/\D+/g,"");
327 }
328 else if ( selectedItem.getAttribute("forceSignedInteger") == "true" )
329 {
330 // Allow integer with optional "+" or "-" as first character
331 var sign = value[0];
332 value = value.replace(/\D+/g,"");
333 if (sign == "+" || sign == "-")
334 value = sign + value;
335 }
336
337 // Special case attributes
338 if (selectedItem.getAttribute("limitFirstChar") == "true")
339 {
340 // Limit first character to letter, and all others to
341 // letters, numbers, and a few others
342 value = value.replace(/^[^a-zA-Z\u0080-\uFFFF]/, "").replace(/[^a-zA-Z0-9_\.\-\:\u0080-\uFFFF]+/g,'');
343 }
344
345 // Update once only if it changed
346 if (value != gDialog.AddHTMLAttributeValueInput.value)
347 gDialog.AddHTMLAttributeValueInput.value = value;
348 }
349 }
350
351 // Update value in the tree list
352 // If not found, add new attribute
353 if ( !UpdateExistingAttribute(name, value, "HTMLAList" ) && value)
354 AddTreeItem(name, value, "HTMLAList", HTMLAttrs);
355 }
356
editHTMLAttributeValue
357 function editHTMLAttributeValue(targetCell)
358 {
359 if (IsNotTreeHeader(targetCell))
360 gDialog.AddHTMLAttributeValueInput.inputField.select();
361 }
362
363
364 // update the object with added and removed attributes
UpdateHTMLAttributes
365 function UpdateHTMLAttributes()
366 {
367 var HTMLAList = document.getElementById("HTMLAList");
368 var i;
369
370 // remove removed attributes
371 for (i = 0; i < HTMLRAttrs.length; i++)
372 {
373 var name = HTMLRAttrs[i];
374
375 if (gElement.hasAttribute(name))
376 doRemoveAttribute(name);
377 }
378
379 // Set added or changed attributes
380 for( i = 0; i < HTMLAList.childNodes.length; i++)
381 {
382 var item = HTMLAList.childNodes[i];
383 doSetAttribute( GetTreeItemAttributeStr(item), GetTreeItemValueStr(item));
384 }
385 }
386
RemoveHTMLAttribute
387 function RemoveHTMLAttribute()
388 {
389 var treechildren = gDialog.AddHTMLAttributeTree.lastChild;
390
391 // We only allow 1 selected item
392 if (gDialog.AddHTMLAttributeTree.view.selection.count)
393 {
394 var item = getSelectedItem(gDialog.AddHTMLAttributeTree);
395 var attr = GetTreeItemAttributeStr(item);
396
397 // remove the item from the attribute array
398 HTMLRAttrs[HTMLRAttrs.length] = attr;
399 RemoveNameFromAttArray(attr, HTMLAttrs);
400
401 // Remove the item from the tree
402 treechildren.removeChild(item);
403
404 // Clear inputs and selected item in tree
405 ClearHTMLInputWidgets();
406 }
407 }
408
SelectHTMLTree
409 function SelectHTMLTree( index )
410 {
411
412 gDoOnSelectTree = false;
413 try {
414 gDialog.AddHTMLAttributeTree.selectedIndex = index;
415 } catch (e) {}
416 gDoOnSelectTree = true;
417 }