1 | /*
|
---|
2 | * file: DTDUtil.js
|
---|
3 | *
|
---|
4 | * @BEGINLICENSE
|
---|
5 | * Copyright 2010 Brook Novak (email : [email protected])
|
---|
6 | * This program is free software; you can redistribute it and/or modify
|
---|
7 | * it under the terms of the GNU General Public License as published by
|
---|
8 | * the Free Software Foundation; either version 2 of the License, or
|
---|
9 | * (at your option) any later version.
|
---|
10 | * This program is distributed in the hope that it will be useful,
|
---|
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
13 | * GNU General Public License for more details.
|
---|
14 | * You should have received a copy of the GNU General Public License
|
---|
15 | * along with this program; if not, write to the Free Software
|
---|
16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
---|
17 | * @ENDLICENSE
|
---|
18 | */
|
---|
19 |
|
---|
20 |
|
---|
21 | /* @DEPENDS: Util */
|
---|
22 | bootstrap.provides("DTDUtil");
|
---|
23 |
|
---|
24 | /* HTML 4.01 Spec maps */
|
---|
25 | var _HTML_401_MAPS = {
|
---|
26 |
|
---|
27 | /* Generic block level */
|
---|
28 | GB: "address,blockquote,center,del,div,h1,h2,h3,h4,h5,h6,hr,ins,isindex,noscript,p,pre",
|
---|
29 |
|
---|
30 | /* Special inline level */
|
---|
31 | SI: "a,applet,basefont,bdo,br,font,iframe,img,map,area,object,param,q,script,span,sub,sup",
|
---|
32 |
|
---|
33 | /* Phrase level */
|
---|
34 | PH: "abbr,acronym,cite,code,del,dfn,em,ins,kbd,samp,strong,var",
|
---|
35 |
|
---|
36 | /* Font level */
|
---|
37 | F: "b,big,i,s,small,strike,tt,u",
|
---|
38 |
|
---|
39 | /* Table elements */
|
---|
40 | TE: "table,caption,colgroup,col,thead,tfoot,tbody,tr,td,th",
|
---|
41 |
|
---|
42 | /* Form elements */
|
---|
43 | // FE : "form,button,fieldset,legend,input,label,select,optgroup,option,textarea",
|
---|
44 |
|
---|
45 | /* Elements which to do support non-whitespace text as immediate children. */
|
---|
46 | NT : "table,textarea,tr,thead,tbody,tfoot,dl,ul,ol,menu,select,optgroup,option,script,style"
|
---|
47 | };
|
---|
48 |
|
---|
49 | // Build maps
|
---|
50 | for (var mem in _HTML_401_MAPS) {
|
---|
51 | _HTML_401_MAPS[mem] = $createLookupMap(_HTML_401_MAPS[mem]);
|
---|
52 | }
|
---|
53 |
|
---|
54 | $extend(_HTML_401_MAPS, {
|
---|
55 | /* Block level */
|
---|
56 | B: $extend($createLookupMap("dir,dl,fieldset,form,menu,noframes,ol,table,ul,dd,dt,frameset,li,tbody,td,tfoot,thead,th,tr"), _HTML_401_MAPS.GB),
|
---|
57 |
|
---|
58 | /* Inline level */
|
---|
59 | I: $extend($extend($createLookupMap("abbr,acronym,cite,code,dfn,em,kbd,samp,strong,var"), _HTML_401_MAPS.F), _HTML_401_MAPS.SI)
|
---|
60 | });
|
---|
61 |
|
---|
62 | /* A map of maps containing valid immediate child relationships according to HTML 4.01 transactional. */
|
---|
63 | var _HTML_401_VALIDATION_MAP = function(){
|
---|
64 |
|
---|
65 | function cloneSubset(map, exclude){
|
---|
66 | var arr = exclude.split(","), clone = _clone(map);
|
---|
67 | for (var i in arr) {
|
---|
68 | delete clone[arr[i]];
|
---|
69 | }
|
---|
70 | return clone;
|
---|
71 | }
|
---|
72 |
|
---|
73 | var BLOCKINLINEMAP = $extend(_clone(_HTML_401_MAPS.B), _HTML_401_MAPS.I);
|
---|
74 |
|
---|
75 | return {
|
---|
76 |
|
---|
77 | // Body
|
---|
78 | body: $extend($createLookupMap("script,ins,del"), BLOCKINLINEMAP),
|
---|
79 |
|
---|
80 | // Generic block level
|
---|
81 | address: $extend($createLookupMap("p"), BLOCKINLINEMAP),
|
---|
82 | blockquote: BLOCKINLINEMAP,
|
---|
83 | centre: BLOCKINLINEMAP,
|
---|
84 | del: BLOCKINLINEMAP,
|
---|
85 | h1: _HTML_401_MAPS.I,
|
---|
86 | h2: _HTML_401_MAPS.I,
|
---|
87 | h3: _HTML_401_MAPS.I,
|
---|
88 | h4: _HTML_401_MAPS.I,
|
---|
89 | h5: _HTML_401_MAPS.I,
|
---|
90 | h6: _HTML_401_MAPS.I,
|
---|
91 | hr: {},
|
---|
92 | ins: BLOCKINLINEMAP,
|
---|
93 | isindex: {},
|
---|
94 | noscript: BLOCKINLINEMAP,
|
---|
95 | p: _HTML_401_MAPS.I,
|
---|
96 | pre: cloneSubset(_HTML_401_MAPS.I, "img,object,applet,big,small,sub,sup,font,basefont"),
|
---|
97 |
|
---|
98 | // Lists
|
---|
99 | dir: $createLookupMap("li"),
|
---|
100 | dl: $createLookupMap("dd,dt"),
|
---|
101 | dt: _HTML_401_MAPS.I,
|
---|
102 | dd: BLOCKINLINEMAP,
|
---|
103 | li: BLOCKINLINEMAP,
|
---|
104 | menu: $createLookupMap("li"),
|
---|
105 | ol: $createLookupMap("li"),
|
---|
106 | ul: $createLookupMap("li"),
|
---|
107 |
|
---|
108 | // Tables
|
---|
109 | table: $createLookupMap("caption,col,colgroup,thead,tfoot,tbody"),
|
---|
110 | caption: _HTML_401_MAPS.I,
|
---|
111 | colgroup: $createLookupMap("col"),
|
---|
112 | col: {},
|
---|
113 | thead: $createLookupMap("tr"),
|
---|
114 | tfoot: $createLookupMap("tr"),
|
---|
115 | tbody: $createLookupMap("tr"),
|
---|
116 | tr: $createLookupMap("td,th"),
|
---|
117 | td: BLOCKINLINEMAP,
|
---|
118 | th: BLOCKINLINEMAP,
|
---|
119 |
|
---|
120 | // Forms
|
---|
121 | form: cloneSubset(BLOCKINLINEMAP, "form"),
|
---|
122 | button: cloneSubset(BLOCKINLINEMAP, "a,input,select,textarea,label,button,iframe,form,isindex,fieldset"),
|
---|
123 | fieldset: $extend($createLookupMap("legend"), BLOCKINLINEMAP),
|
---|
124 | legend: _HTML_401_MAPS.I,
|
---|
125 | input: {},
|
---|
126 | label: cloneSubset(_HTML_401_MAPS.I, "label"),
|
---|
127 | select: $createLookupMap("optgroup,option"),
|
---|
128 | optgroup: $createLookupMap("option"),
|
---|
129 | option: {},
|
---|
130 | textarea: {},
|
---|
131 |
|
---|
132 | // Special inline elements
|
---|
133 | a: cloneSubset(_HTML_401_MAPS.I, "a"),
|
---|
134 | applet: $extend($createLookupMap("param"), BLOCKINLINEMAP),
|
---|
135 | basefont: {},
|
---|
136 | bdo: _HTML_401_MAPS.I,
|
---|
137 | br: {},
|
---|
138 | font: _HTML_401_MAPS.I,
|
---|
139 | iframe: BLOCKINLINEMAP,
|
---|
140 | img: {},
|
---|
141 | map: $extend($createLookupMap("area"), _HTML_401_MAPS.B),
|
---|
142 | area: {},
|
---|
143 | object: $extend($createLookupMap("param"), BLOCKINLINEMAP),
|
---|
144 | param: {},
|
---|
145 | q: _HTML_401_MAPS.I,
|
---|
146 | script: {},
|
---|
147 | span: _HTML_401_MAPS.I,
|
---|
148 | sub: _HTML_401_MAPS.I,
|
---|
149 | sup: _HTML_401_MAPS.I,
|
---|
150 |
|
---|
151 | // Phrase level
|
---|
152 | abbr: _HTML_401_MAPS.I,
|
---|
153 | acroynm: _HTML_401_MAPS.I,
|
---|
154 | cite: _HTML_401_MAPS.I,
|
---|
155 | code: _HTML_401_MAPS.I,
|
---|
156 | dfn: _HTML_401_MAPS.I,
|
---|
157 | em: _HTML_401_MAPS.I,
|
---|
158 | kbd: _HTML_401_MAPS.I,
|
---|
159 | samp: _HTML_401_MAPS.I,
|
---|
160 | strong: _HTML_401_MAPS.I,
|
---|
161 | 'var': _HTML_401_MAPS.I,
|
---|
162 |
|
---|
163 | // Font level
|
---|
164 | b: _HTML_401_MAPS.I,
|
---|
165 | big: _HTML_401_MAPS.I,
|
---|
166 | i: _HTML_401_MAPS.I,
|
---|
167 | s: _HTML_401_MAPS.I,
|
---|
168 | small: _HTML_401_MAPS.I,
|
---|
169 | strike: _HTML_401_MAPS.I,
|
---|
170 | tt: _HTML_401_MAPS.I,
|
---|
171 | u: _HTML_401_MAPS.I
|
---|
172 |
|
---|
173 | };
|
---|
174 |
|
---|
175 | }();
|
---|
176 |
|
---|
177 | function _isNodeAtLevel(domNode, mapName) {
|
---|
178 | if (domNode.nodeType == Node.ELEMENT_NODE)
|
---|
179 | return _HTML_401_MAPS[mapName][_nodeName(domNode)] ? true : false;
|
---|
180 | return false;
|
---|
181 | }
|
---|
182 |
|
---|
183 | /**
|
---|
184 | * Determines if an Element or Text node can be a parent of another given Element/Text/Body node.
|
---|
185 | * Note: the contents of text nodes are not analysed, the relationship is valid for the type, but
|
---|
186 | * if the text node contains non-whitespace symbols the relationship may not be valid.
|
---|
187 | *
|
---|
188 | * Only configured for HTML 4.01 trans .. TODO: Other specs
|
---|
189 | *
|
---|
190 | * @see _doesTextSupportNonWS
|
---|
191 | *
|
---|
192 | * @param {Node} child The child to test
|
---|
193 | * @param {Node} parent The parent of the child to test
|
---|
194 | * @return {Boolean} True if child can be a child of Parent according to HTML 4.0 Transactional specification
|
---|
195 | */
|
---|
196 | function _isValidRelationship(child, parent){
|
---|
197 | if (child.nodeType == Node.TEXT_NODE)
|
---|
198 | return true;
|
---|
199 |
|
---|
200 | var vmap = _HTML_401_VALIDATION_MAP[_nodeName(parent)];
|
---|
201 | if (vmap)
|
---|
202 | return vmap[_nodeName(child)];
|
---|
203 |
|
---|
204 | return true; // Allow any custom nodes to be added
|
---|
205 | }
|
---|
206 |
|
---|
207 | /*
|
---|
208 | * TODO: SUPPORT OF OTHER DOC TYPES.
|
---|
209 | */
|
---|
210 |
|
---|
211 | /**
|
---|
212 | * @param {Node} domNode A dom node to test
|
---|
213 | * @return {Boolean} True iff domNode is a block level element.
|
---|
214 | */
|
---|
215 | function _isBlockLevel(domNode) {
|
---|
216 | return _isNodeAtLevel(domNode, "B");
|
---|
217 | }
|
---|
218 |
|
---|
219 | /**
|
---|
220 | * @param {Node} domNode A dom node to test
|
---|
221 | * @return {Boolean} True iff domNode is a block level element.
|
---|
222 | */
|
---|
223 | function _isGenericBlockLevel(domNode) {
|
---|
224 | return _isNodeAtLevel(domNode, "GB");
|
---|
225 | }
|
---|
226 |
|
---|
227 | /**
|
---|
228 | * @param {Node} domNode A dom node to test
|
---|
229 | * @return {Boolean} True iff domNode is a inline level element.
|
---|
230 | */
|
---|
231 | function _isInlineLevel(domNode) {
|
---|
232 | return _isNodeAtLevel(domNode, "I");
|
---|
233 | }
|
---|
234 |
|
---|
235 | /**
|
---|
236 | * @param {Node} domNode A dom node to test
|
---|
237 | * @return {Boolean} True iff domNode is a inline level element.
|
---|
238 | */
|
---|
239 | function _isSpecialInlineLevel(domNode) {
|
---|
240 | return _isNodeAtLevel(domNode, "SI");
|
---|
241 | }
|
---|
242 |
|
---|
243 | /**
|
---|
244 | * @param {Node} domNode A dom node to test
|
---|
245 | * @return {Boolean} True iff domNode is a phrase level element.
|
---|
246 | */
|
---|
247 | function _isPhraseLevel(domNode) {
|
---|
248 | return _isNodeAtLevel(domNode, "PH");
|
---|
249 | }
|
---|
250 |
|
---|
251 | /**
|
---|
252 | * @param {Node} domNode A dom node to test
|
---|
253 | * @return {Boolean} True iff domNode is a font level element.
|
---|
254 | */
|
---|
255 | function _isFontLevel(domNode) {
|
---|
256 | return _isNodeAtLevel(domNode, "F");
|
---|
257 | }
|
---|
258 |
|
---|
259 | /**
|
---|
260 | * @param {Node} domNode A dom node to test
|
---|
261 | * @return {Boolean} True iff domNode is a table element. E.G. "tr", "thead" or "table" elements
|
---|
262 | */
|
---|
263 | function _isTableElement(domNode) {
|
---|
264 | return _isNodeAtLevel(domNode, "TE");
|
---|
265 | }
|
---|
266 |
|
---|
267 | /*
|
---|
268 | * @param {Node} domNode A dom node to test
|
---|
269 | * @return {Boolean} True iff domNode is a form element. E.G. "input", "textarea" or "form" elements
|
---|
270 | */
|
---|
271 | /*function _isFormElement(domNode) {
|
---|
272 | return _isNodeAtLevel(domNode, "FE");
|
---|
273 | }*/
|
---|
274 |
|
---|
275 |
|
---|
276 | /**
|
---|
277 | * @param {String} str A string
|
---|
278 | * @return {Boolean} True iff str contains nothing but whitespace charactors.
|
---|
279 | */
|
---|
280 | function _isAllWhiteSpace(str) {
|
---|
281 | return /^[\t\n\r ]+$/.test(str);
|
---|
282 | }
|
---|
283 |
|
---|
284 | /**
|
---|
285 | * @param {Node} textNode A text node which has a parent node.
|
---|
286 | * @return {Boolean} True iff the text node is allowed to contain non whitespace symbols.
|
---|
287 | */
|
---|
288 | function _doesTextSupportNonWS(textNode){
|
---|
289 | return !_isNodeAtLevel(textNode.parentNode, "NT");
|
---|
290 | }
|
---|
291 |
|
---|
292 | /**
|
---|
293 | * Ready only. UTF encoding for the non breaking backspace entity (" ")'
|
---|
294 | */
|
---|
295 | var _NBSP = _parseHTMLString(" ");
|
---|
296 |
|
---|
297 | $extend(de, {
|
---|
298 | isBlock : _isBlockLevel
|
---|
299 | });
|
---|