/** * Schema.js * * Copyright 2009, Moxiecode Systems AB * Released under LGPL License. * * License: http://tinymce.moxiecode.com/license * Contributing: http://tinymce.moxiecode.com/contributing */ (function() { var transitional = {}; /** * Unpacks the specified lookup and string data it will also parse it into an object * map with sub object for it's children. This will later also include the attributes. */ function unpack(lookup, data) { var key; function replace(value) { return value.replace(/[A-Z]+/g, function(key) { return replace(lookup[key]); }); }; // Unpack lookup for (key in lookup) { if (lookup.hasOwnProperty(key)) lookup[key] = replace(lookup[key]); } // Unpack and parse data into object map replace(data).replace(/#/g, '#text').replace(/(\w+)\[([^\]]+)\]/g, function(str, name, children) { var i, map = {}; children = children.split(/\|/); for (i = children.length - 1; i >= 0; i--) map[children[i]] = 1; transitional[name] = map; }); }; // This is the XHTML 1.0 transitional elements with it's children packed to reduce it's size // we will later include the attributes here and use it as a default for valid elements but it // requires us to rewrite the serializer engine unpack({ Z : '#|H|K|N|O|P', Y : '#|X|form|R|Q', X : 'p|T|div|U|W|isindex|fieldset|table', W : 'pre|hr|blockquote|address|center|noframes', U : 'ul|ol|dl|menu|dir', ZC : '#|p|Y|div|U|W|table|br|span|bdo|object|applet|img|map|K|N|Q', T : 'h1|h2|h3|h4|h5|h6', ZB : '#|X|S|Q', S : 'R|P', ZA : '#|a|G|J|M|O|P', R : '#|a|H|K|N|O', Q : 'noscript|P', P : 'ins|del|script', O : 'input|select|textarea|label|button', N : 'M|L', M : 'em|strong|dfn|code|q|samp|kbd|var|cite|abbr|acronym', L : 'sub|sup', K : 'J|I', J : 'tt|i|b|u|s|strike', I : 'big|small|font|basefont', H : 'G|F', G : 'br|span|bdo', F : 'object|applet|img|map|iframe' }, 'script[]' + 'style[]' + 'object[#|param|X|form|a|H|K|N|O|Q]' + 'param[]' + 'p[S]' + 'a[Z]' + 'br[]' + 'span[S]' + 'bdo[S]' + 'applet[#|param|X|form|a|H|K|N|O|Q]' + 'h1[S]' + 'img[]' + 'map[X|form|Q|area]' + 'h2[S]' + 'iframe[#|X|form|a|H|K|N|O|Q]' + 'h3[S]' + 'tt[S]' + 'i[S]' + 'b[S]' + 'u[S]' + 's[S]' + 'strike[S]' + 'big[S]' + 'small[S]' + 'font[S]' + 'basefont[]' + 'em[S]' + 'strong[S]' + 'dfn[S]' + 'code[S]' + 'q[S]' + 'samp[S]' + 'kbd[S]' + 'var[S]' + 'cite[S]' + 'abbr[S]' + 'acronym[S]' + 'sub[S]' + 'sup[S]' + 'input[]' + 'select[optgroup|option]' + 'optgroup[option]' + 'option[]' + 'textarea[]' + 'label[S]' + 'button[#|p|T|div|U|W|table|G|object|applet|img|map|K|N|Q]' + 'h4[S]' + 'ins[#|X|form|a|H|K|N|O|Q]' + 'h5[S]' + 'del[#|X|form|a|H|K|N|O|Q]' + 'h6[S]' + 'div[#|X|form|a|H|K|N|O|Q]' + 'ul[li]' + 'li[#|X|form|a|H|K|N|O|Q]' + 'ol[li]' + 'dl[dt|dd]' + 'dt[S]' + 'dd[#|X|form|a|H|K|N|O|Q]' + 'menu[li]' + 'dir[li]' + 'pre[ZA]' + 'hr[]' + 'blockquote[#|X|form|a|H|K|N|O|Q]' + 'address[S|p]' + 'center[#|X|form|a|H|K|N|O|Q]' + 'noframes[#|X|form|a|H|K|N|O|Q]' + 'isindex[]' + 'fieldset[#|legend|X|form|a|H|K|N|O|Q]' + 'legend[S]' + 'table[caption|col|colgroup|thead|tfoot|tbody|tr]' + 'caption[S]' + 'col[]' + 'colgroup[col]' + 'thead[tr]' + 'tr[th|td]' + 'th[#|X|form|a|H|K|N|O|Q]' + 'form[#|X|a|H|K|N|O|Q]' + 'noscript[#|X|form|a|H|K|N|O|Q]' + 'td[#|X|form|a|H|K|N|O|Q]' + 'tfoot[tr]' + 'tbody[tr]' + 'area[]' + 'base[]' + 'body[#|X|form|a|H|K|N|O|Q]' ); /** * Schema validator class. * * @class tinymce.dom.Schema * @example * if (tinymce.activeEditor.schema.isValid('p', 'span')) * alert('span is valid child of p.'); */ tinymce.dom.Schema = function() { var t = this, elements = transitional; /** * Returns true/false if the specified element and optionally it's child is valid or not * according to the XHTML transitional DTD. * * @method isValid * @param {String} name Element name to check for. * @param {String} child_name Element child name to check for. * @return {boolean} true/false if the element is valid or not. */ t.isValid = function(name, child_name) { var element = elements[name]; return !!(element && (!child_name || element[child_name])); }; }; })();