/* * file: DTDUtil.js * * @BEGINLICENSE * Copyright 2010 Brook Novak (email : brooknovak@seaweed-editor.com) * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * @ENDLICENSE */ /* @DEPENDS: Util */ bootstrap.provides("DTDUtil"); /* HTML 4.01 Spec maps */ var _HTML_401_MAPS = { /* Generic block level */ GB: "address,blockquote,center,del,div,h1,h2,h3,h4,h5,h6,hr,ins,isindex,noscript,p,pre", /* Special inline level */ SI: "a,applet,basefont,bdo,br,font,iframe,img,map,area,object,param,q,script,span,sub,sup", /* Phrase level */ PH: "abbr,acronym,cite,code,del,dfn,em,ins,kbd,samp,strong,var", /* Font level */ F: "b,big,i,s,small,strike,tt,u", /* Table elements */ TE: "table,caption,colgroup,col,thead,tfoot,tbody,tr,td,th", /* Form elements */ // FE : "form,button,fieldset,legend,input,label,select,optgroup,option,textarea", /* Elements which to do support non-whitespace text as immediate children. */ NT : "table,textarea,tr,thead,tbody,tfoot,dl,ul,ol,menu,select,optgroup,option,script,style" }; // Build maps for (var mem in _HTML_401_MAPS) { _HTML_401_MAPS[mem] = $createLookupMap(_HTML_401_MAPS[mem]); } $extend(_HTML_401_MAPS, { /* Block level */ 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), /* Inline level */ I: $extend($extend($createLookupMap("abbr,acronym,cite,code,dfn,em,kbd,samp,strong,var"), _HTML_401_MAPS.F), _HTML_401_MAPS.SI) }); /* A map of maps containing valid immediate child relationships according to HTML 4.01 transactional. */ var _HTML_401_VALIDATION_MAP = function(){ function cloneSubset(map, exclude){ var arr = exclude.split(","), clone = _clone(map); for (var i in arr) { delete clone[arr[i]]; } return clone; } var BLOCKINLINEMAP = $extend(_clone(_HTML_401_MAPS.B), _HTML_401_MAPS.I); return { // Body body: $extend($createLookupMap("script,ins,del"), BLOCKINLINEMAP), // Generic block level address: $extend($createLookupMap("p"), BLOCKINLINEMAP), blockquote: BLOCKINLINEMAP, centre: BLOCKINLINEMAP, del: BLOCKINLINEMAP, h1: _HTML_401_MAPS.I, h2: _HTML_401_MAPS.I, h3: _HTML_401_MAPS.I, h4: _HTML_401_MAPS.I, h5: _HTML_401_MAPS.I, h6: _HTML_401_MAPS.I, hr: {}, ins: BLOCKINLINEMAP, isindex: {}, noscript: BLOCKINLINEMAP, p: _HTML_401_MAPS.I, pre: cloneSubset(_HTML_401_MAPS.I, "img,object,applet,big,small,sub,sup,font,basefont"), // Lists dir: $createLookupMap("li"), dl: $createLookupMap("dd,dt"), dt: _HTML_401_MAPS.I, dd: BLOCKINLINEMAP, li: BLOCKINLINEMAP, menu: $createLookupMap("li"), ol: $createLookupMap("li"), ul: $createLookupMap("li"), // Tables table: $createLookupMap("caption,col,colgroup,thead,tfoot,tbody"), caption: _HTML_401_MAPS.I, colgroup: $createLookupMap("col"), col: {}, thead: $createLookupMap("tr"), tfoot: $createLookupMap("tr"), tbody: $createLookupMap("tr"), tr: $createLookupMap("td,th"), td: BLOCKINLINEMAP, th: BLOCKINLINEMAP, // Forms form: cloneSubset(BLOCKINLINEMAP, "form"), button: cloneSubset(BLOCKINLINEMAP, "a,input,select,textarea,label,button,iframe,form,isindex,fieldset"), fieldset: $extend($createLookupMap("legend"), BLOCKINLINEMAP), legend: _HTML_401_MAPS.I, input: {}, label: cloneSubset(_HTML_401_MAPS.I, "label"), select: $createLookupMap("optgroup,option"), optgroup: $createLookupMap("option"), option: {}, textarea: {}, // Special inline elements a: cloneSubset(_HTML_401_MAPS.I, "a"), applet: $extend($createLookupMap("param"), BLOCKINLINEMAP), basefont: {}, bdo: _HTML_401_MAPS.I, br: {}, font: _HTML_401_MAPS.I, iframe: BLOCKINLINEMAP, img: {}, map: $extend($createLookupMap("area"), _HTML_401_MAPS.B), area: {}, object: $extend($createLookupMap("param"), BLOCKINLINEMAP), param: {}, q: _HTML_401_MAPS.I, script: {}, span: _HTML_401_MAPS.I, sub: _HTML_401_MAPS.I, sup: _HTML_401_MAPS.I, // Phrase level abbr: _HTML_401_MAPS.I, acroynm: _HTML_401_MAPS.I, cite: _HTML_401_MAPS.I, code: _HTML_401_MAPS.I, dfn: _HTML_401_MAPS.I, em: _HTML_401_MAPS.I, kbd: _HTML_401_MAPS.I, samp: _HTML_401_MAPS.I, strong: _HTML_401_MAPS.I, 'var': _HTML_401_MAPS.I, // Font level b: _HTML_401_MAPS.I, big: _HTML_401_MAPS.I, i: _HTML_401_MAPS.I, s: _HTML_401_MAPS.I, small: _HTML_401_MAPS.I, strike: _HTML_401_MAPS.I, tt: _HTML_401_MAPS.I, u: _HTML_401_MAPS.I }; }(); function _isNodeAtLevel(domNode, mapName) { if (domNode.nodeType == Node.ELEMENT_NODE) return _HTML_401_MAPS[mapName][_nodeName(domNode)] ? true : false; return false; } /** * Determines if an Element or Text node can be a parent of another given Element/Text/Body node. * Note: the contents of text nodes are not analysed, the relationship is valid for the type, but * if the text node contains non-whitespace symbols the relationship may not be valid. * * Only configured for HTML 4.01 trans .. TODO: Other specs * * @see _doesTextSupportNonWS * * @param {Node} child The child to test * @param {Node} parent The parent of the child to test * @return {Boolean} True if child can be a child of Parent according to HTML 4.0 Transactional specification */ function _isValidRelationship(child, parent){ if (child.nodeType == Node.TEXT_NODE) return true; var vmap = _HTML_401_VALIDATION_MAP[_nodeName(parent)]; if (vmap) return vmap[_nodeName(child)]; return true; // Allow any custom nodes to be added } /* * TODO: SUPPORT OF OTHER DOC TYPES. */ /** * @param {Node} domNode A dom node to test * @return {Boolean} True iff domNode is a block level element. */ function _isBlockLevel(domNode) { return _isNodeAtLevel(domNode, "B"); } /** * @param {Node} domNode A dom node to test * @return {Boolean} True iff domNode is a block level element. */ function _isGenericBlockLevel(domNode) { return _isNodeAtLevel(domNode, "GB"); } /** * @param {Node} domNode A dom node to test * @return {Boolean} True iff domNode is a inline level element. */ function _isInlineLevel(domNode) { return _isNodeAtLevel(domNode, "I"); } /** * @param {Node} domNode A dom node to test * @return {Boolean} True iff domNode is a inline level element. */ function _isSpecialInlineLevel(domNode) { return _isNodeAtLevel(domNode, "SI"); } /** * @param {Node} domNode A dom node to test * @return {Boolean} True iff domNode is a phrase level element. */ function _isPhraseLevel(domNode) { return _isNodeAtLevel(domNode, "PH"); } /** * @param {Node} domNode A dom node to test * @return {Boolean} True iff domNode is a font level element. */ function _isFontLevel(domNode) { return _isNodeAtLevel(domNode, "F"); } /** * @param {Node} domNode A dom node to test * @return {Boolean} True iff domNode is a table element. E.G. "tr", "thead" or "table" elements */ function _isTableElement(domNode) { return _isNodeAtLevel(domNode, "TE"); } /* * @param {Node} domNode A dom node to test * @return {Boolean} True iff domNode is a form element. E.G. "input", "textarea" or "form" elements */ /*function _isFormElement(domNode) { return _isNodeAtLevel(domNode, "FE"); }*/ /** * @param {String} str A string * @return {Boolean} True iff str contains nothing but whitespace charactors. */ function _isAllWhiteSpace(str) { return /^[\t\n\r ]+$/.test(str); } /** * @param {Node} textNode A text node which has a parent node. * @return {Boolean} True iff the text node is allowed to contain non whitespace symbols. */ function _doesTextSupportNonWS(textNode){ return !_isNodeAtLevel(textNode.parentNode, "NT"); } /** * Ready only. UTF encoding for the non breaking backspace entity (" ")' */ var _NBSP = _parseHTMLString(" "); $extend(de, { isBlock : _isBlockLevel });