]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/javascript/tiny_mce/classes/html/Schema.js
Release 6.2.3
[Github/sugarcrm.git] / include / javascript / tiny_mce / classes / html / Schema.js
1 /**
2  * Schema.js
3  *
4  * Copyright 2010, Moxiecode Systems AB
5  * Released under LGPL License.
6  *
7  * License: http://tinymce.moxiecode.com/license
8  * Contributing: http://tinymce.moxiecode.com/contributing
9  */
10
11 (function(tinymce) {
12         var transitional = {}, boolAttrMap, blockElementsMap, shortEndedElementsMap, nonEmptyElementsMap, customElementsMap = {},
13                 whiteSpaceElementsMap, selfClosingElementsMap, makeMap = tinymce.makeMap, each = tinymce.each;
14
15         function split(str, delim) {
16                 return str.split(delim || ',');
17         };
18
19         /**
20          * Unpacks the specified lookup and string data it will also parse it into an object
21          * map with sub object for it's children. This will later also include the attributes.
22          */
23         function unpack(lookup, data) {
24                 var key, elements = {};
25
26                 function replace(value) {
27                         return value.replace(/[A-Z]+/g, function(key) {
28                                 return replace(lookup[key]);
29                         });
30                 };
31
32                 // Unpack lookup
33                 for (key in lookup) {
34                         if (lookup.hasOwnProperty(key))
35                                 lookup[key] = replace(lookup[key]);
36                 }
37
38                 // Unpack and parse data into object map
39                 replace(data).replace(/#/g, '#text').replace(/(\w+)\[([^\]]+)\]\[([^\]]*)\]/g, function(str, name, attributes, children) {
40                         attributes = split(attributes, '|');
41
42                         elements[name] = {
43                                 attributes : makeMap(attributes),
44                                 attributesOrder : attributes,
45                                 children : makeMap(children, '|', {'#comment' : {}})
46                         }
47                 });
48
49                 return elements;
50         };
51
52         // Build a lookup table for block elements both lowercase and uppercase
53         blockElementsMap = 'h1,h2,h3,h4,h5,h6,hr,p,div,address,pre,form,table,tbody,thead,tfoot,' + 
54                                                 'th,tr,td,li,ol,ul,caption,blockquote,center,dl,dt,dd,dir,fieldset,' + 
55                                                 'noscript,menu,isindex,samp,header,footer,article,section,hgroup';
56         blockElementsMap = makeMap(blockElementsMap, ',', makeMap(blockElementsMap.toUpperCase()));
57
58         // This is the XHTML 1.0 transitional elements with it's attributes and children packed to reduce it's size
59         transitional = unpack({
60                 Z : 'H|K|N|O|P',
61                 Y : 'X|form|R|Q',
62                 ZG : 'E|span|width|align|char|charoff|valign',
63                 X : 'p|T|div|U|W|isindex|fieldset|table',
64                 ZF : 'E|align|char|charoff|valign',
65                 W : 'pre|hr|blockquote|address|center|noframes',
66                 ZE : 'abbr|axis|headers|scope|rowspan|colspan|align|char|charoff|valign|nowrap|bgcolor|width|height',
67                 ZD : '[E][S]',
68                 U : 'ul|ol|dl|menu|dir',
69                 ZC : 'p|Y|div|U|W|table|br|span|bdo|object|applet|img|map|K|N|Q',
70                 T : 'h1|h2|h3|h4|h5|h6',
71                 ZB : 'X|S|Q',
72                 S : 'R|P',
73                 ZA : 'a|G|J|M|O|P',
74                 R : 'a|H|K|N|O',
75                 Q : 'noscript|P',
76                 P : 'ins|del|script',
77                 O : 'input|select|textarea|label|button',
78                 N : 'M|L',
79                 M : 'em|strong|dfn|code|q|samp|kbd|var|cite|abbr|acronym',
80                 L : 'sub|sup',
81                 K : 'J|I',
82                 J : 'tt|i|b|u|s|strike',
83                 I : 'big|small|font|basefont',
84                 H : 'G|F',
85                 G : 'br|span|bdo',
86                 F : 'object|applet|img|map|iframe',
87                 E : 'A|B|C',
88                 D : 'accesskey|tabindex|onfocus|onblur',
89                 C : 'onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup',
90                 B : 'lang|xml:lang|dir',
91                 A : 'id|class|style|title'
92         }, 'script[id|charset|type|language|src|defer|xml:space][]' + 
93                 'style[B|id|type|media|title|xml:space][]' + 
94                 'object[E|declare|classid|codebase|data|type|codetype|archive|standby|width|height|usemap|name|tabindex|align|border|hspace|vspace][#|param|Y]' + 
95                 'param[id|name|value|valuetype|type][]' + 
96                 'p[E|align][#|S]' + 
97                 'a[E|D|charset|type|name|href|hreflang|rel|rev|shape|coords|target][#|Z]' + 
98                 'br[A|clear][]' + 
99                 'span[E][#|S]' + 
100                 'bdo[A|C|B][#|S]' + 
101                 'applet[A|codebase|archive|code|object|alt|name|width|height|align|hspace|vspace][#|param|Y]' + 
102                 'h1[E|align][#|S]' + 
103                 'img[E|src|alt|name|longdesc|width|height|usemap|ismap|align|border|hspace|vspace][]' + 
104                 'map[B|C|A|name][X|form|Q|area]' + 
105                 'h2[E|align][#|S]' + 
106                 'iframe[A|longdesc|name|src|frameborder|marginwidth|marginheight|scrolling|align|width|height][#|Y]' + 
107                 'h3[E|align][#|S]' + 
108                 'tt[E][#|S]' + 
109                 'i[E][#|S]' + 
110                 'b[E][#|S]' + 
111                 'u[E][#|S]' + 
112                 's[E][#|S]' + 
113                 'strike[E][#|S]' + 
114                 'big[E][#|S]' + 
115                 'small[E][#|S]' + 
116                 'font[A|B|size|color|face][#|S]' + 
117                 'basefont[id|size|color|face][]' + 
118                 'em[E][#|S]' + 
119                 'strong[E][#|S]' + 
120                 'dfn[E][#|S]' + 
121                 'code[E][#|S]' + 
122                 'q[E|cite][#|S]' + 
123                 'samp[E][#|S]' + 
124                 'kbd[E][#|S]' + 
125                 'var[E][#|S]' + 
126                 'cite[E][#|S]' + 
127                 'abbr[E][#|S]' + 
128                 'acronym[E][#|S]' + 
129                 'sub[E][#|S]' + 
130                 'sup[E][#|S]' + 
131                 'input[E|D|type|name|value|checked|disabled|readonly|size|maxlength|src|alt|usemap|onselect|onchange|accept|align][]' + 
132                 'select[E|name|size|multiple|disabled|tabindex|onfocus|onblur|onchange][optgroup|option]' + 
133                 'optgroup[E|disabled|label][option]' + 
134                 'option[E|selected|disabled|label|value][]' + 
135                 'textarea[E|D|name|rows|cols|disabled|readonly|onselect|onchange][]' + 
136                 'label[E|for|accesskey|onfocus|onblur][#|S]' + 
137                 'button[E|D|name|value|type|disabled][#|p|T|div|U|W|table|G|object|applet|img|map|K|N|Q]' + 
138                 'h4[E|align][#|S]' + 
139                 'ins[E|cite|datetime][#|Y]' + 
140                 'h5[E|align][#|S]' + 
141                 'del[E|cite|datetime][#|Y]' + 
142                 'h6[E|align][#|S]' + 
143                 'div[E|align][#|Y]' + 
144                 'ul[E|type|compact][li]' + 
145                 'li[E|type|value][#|Y]' + 
146                 'ol[E|type|compact|start][li]' + 
147                 'dl[E|compact][dt|dd]' + 
148                 'dt[E][#|S]' + 
149                 'dd[E][#|Y]' + 
150                 'menu[E|compact][li]' + 
151                 'dir[E|compact][li]' + 
152                 'pre[E|width|xml:space][#|ZA]' + 
153                 'hr[E|align|noshade|size|width][]' + 
154                 'blockquote[E|cite][#|Y]' + 
155                 'address[E][#|S|p]' + 
156                 'center[E][#|Y]' + 
157                 'noframes[E][#|Y]' + 
158                 'isindex[A|B|prompt][]' + 
159                 'fieldset[E][#|legend|Y]' + 
160                 'legend[E|accesskey|align][#|S]' + 
161                 'table[E|summary|width|border|frame|rules|cellspacing|cellpadding|align|bgcolor][caption|col|colgroup|thead|tfoot|tbody|tr]' + 
162                 'caption[E|align][#|S]' + 
163                 'col[ZG][]' + 
164                 'colgroup[ZG][col]' + 
165                 'thead[ZF][tr]' + 
166                 'tr[ZF|bgcolor][th|td]' + 
167                 'th[E|ZE][#|Y]' + 
168                 'form[E|action|method|name|enctype|onsubmit|onreset|accept|accept-charset|target][#|X|R|Q]' + 
169                 'noscript[E][#|Y]' + 
170                 'td[E|ZE][#|Y]' + 
171                 'tfoot[ZF][tr]' + 
172                 'tbody[ZF][tr]' + 
173                 'area[E|D|shape|coords|href|nohref|alt|target][]' + 
174                 'base[id|href|target][]' + 
175                 'body[E|onload|onunload|background|bgcolor|text|link|vlink|alink][#|Y]'
176         );
177
178         boolAttrMap = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected,autoplay,loop,controls');
179         shortEndedElementsMap = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,source');
180         nonEmptyElementsMap = tinymce.extend(makeMap('td,th,iframe,video,audio,object'), shortEndedElementsMap);
181         whiteSpaceElementsMap = makeMap('pre,script,style,textarea');
182         selfClosingElementsMap = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
183
184         /**
185          * Schema validator class.
186          *
187          * @class tinymce.html.Schema
188          * @example
189          *  if (tinymce.activeEditor.schema.isValidChild('p', 'span'))
190          *    alert('span is valid child of p.');
191          *
192          *  if (tinymce.activeEditor.schema.getElementRule('p'))
193          *    alert('P is a valid element.');
194          *
195          * @class tinymce.html.Schema
196          * @version 3.4
197          */
198
199         /**
200          * Constructs a new Schema instance.
201          *
202          * @constructor
203          * @method Schema
204          * @param {Object} settings Name/value settings object.
205          */
206         tinymce.html.Schema = function(settings) {
207                 var self = this, elements = {}, children = {}, patternElements = [], validStyles;
208
209                 settings = settings || {};
210
211                 // Allow all elements and attributes if verify_html is set to false
212                 if (settings.verify_html === false)
213                         settings.valid_elements = '*[*]';
214
215                 // Build styles list
216                 if (settings.valid_styles) {
217                         validStyles = {};
218
219                         // Convert styles into a rule list
220                         each(settings.valid_styles, function(value, key) {
221                                 validStyles[key] = tinymce.explode(value);
222                         });
223                 }
224
225                 // Converts a wildcard expression string to a regexp for example *a will become /.*a/.
226                 function patternToRegExp(str) {
227                         return new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
228                 };
229
230                 // Parses the specified valid_elements string and adds to the current rules
231                 // This function is a bit hard to read since it's heavily optimized for speed
232                 function addValidElements(valid_elements) {
233                         var ei, el, ai, al, yl, matches, element, attr, attrData, elementName, attrName, attrType, attributes, attributesOrder,
234                                 prefix, outputName, globalAttributes, globalAttributesOrder, transElement, key, childKey, value,
235                                 elementRuleRegExp = /^([#+-])?([^\[\/]+)(?:\/([^\[]+))?(?:\[([^\]]+)\])?$/,
236                                 attrRuleRegExp = /^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,
237                                 hasPatternsRegExp = /[*?+]/;
238
239                         if (valid_elements) {
240                                 // Split valid elements into an array with rules
241                                 valid_elements = split(valid_elements);
242
243                                 if (elements['@']) {
244                                         globalAttributes = elements['@'].attributes;
245                                         globalAttributesOrder = elements['@'].attributesOrder;
246                                 }
247
248                                 // Loop all rules
249                                 for (ei = 0, el = valid_elements.length; ei < el; ei++) {
250                                         // Parse element rule
251                                         matches = elementRuleRegExp.exec(valid_elements[ei]);
252                                         if (matches) {
253                                                 // Setup local names for matches
254                                                 prefix = matches[1];
255                                                 elementName = matches[2];
256                                                 outputName = matches[3];
257                                                 attrData = matches[4];
258
259                                                 // Create new attributes and attributesOrder
260                                                 attributes = {};
261                                                 attributesOrder = [];
262
263                                                 // Create the new element
264                                                 element = {
265                                                         attributes : attributes,
266                                                         attributesOrder : attributesOrder
267                                                 };
268
269                                                 // Padd empty elements prefix
270                                                 if (prefix === '#')
271                                                         element.paddEmpty = true;
272
273                                                 // Remove empty elements prefix
274                                                 if (prefix === '-')
275                                                         element.removeEmpty = true;
276
277                                                 // Copy attributes from global rule into current rule
278                                                 if (globalAttributes) {
279                                                         for (key in globalAttributes)
280                                                                 attributes[key] = globalAttributes[key];
281
282                                                         attributesOrder.push.apply(attributesOrder, globalAttributesOrder);
283                                                 }
284
285                                                 // Attributes defined
286                                                 if (attrData) {
287                                                         attrData = split(attrData, '|');
288                                                         for (ai = 0, al = attrData.length; ai < al; ai++) {
289                                                                 matches = attrRuleRegExp.exec(attrData[ai]);
290                                                                 if (matches) {
291                                                                         attr = {};
292                                                                         attrType = matches[1];
293                                                                         attrName = matches[2].replace(/::/g, ':');
294                                                                         prefix = matches[3];
295                                                                         value = matches[4];
296
297                                                                         // Required
298                                                                         if (attrType === '!') {
299                                                                                 element.attributesRequired = element.attributesRequired || [];
300                                                                                 element.attributesRequired.push(attrName);
301                                                                                 attr.required = true;
302                                                                         }
303
304                                                                         // Denied from global
305                                                                         if (attrType === '-') {
306                                                                                 delete attributes[attrName];
307                                                                                 attributesOrder.splice(tinymce.inArray(attributesOrder, attrName), 1);
308                                                                                 continue;
309                                                                         }
310
311                                                                         // Default value
312                                                                         if (prefix) {
313                                                                                 // Default value
314                                                                                 if (prefix === '=') {
315                                                                                         element.attributesDefault = element.attributesDefault || [];
316                                                                                         element.attributesDefault.push({name: attrName, value: value});
317                                                                                         attr.defaultValue = value;
318                                                                                 }
319
320                                                                                 // Forced value
321                                                                                 if (prefix === ':') {
322                                                                                         element.attributesForced = element.attributesForced || [];
323                                                                                         element.attributesForced.push({name: attrName, value: value});
324                                                                                         attr.forcedValue = value;
325                                                                                 }
326
327                                                                                 // Required values
328                                                                                 if (prefix === '<')
329                                                                                         attr.validValues = makeMap(value, '?');
330                                                                         }
331
332                                                                         // Check for attribute patterns
333                                                                         if (hasPatternsRegExp.test(attrName)) {
334                                                                                 element.attributePatterns = element.attributePatterns || [];
335                                                                                 attr.pattern = patternToRegExp(attrName);
336                                                                                 element.attributePatterns.push(attr);
337                                                                         } else {
338                                                                                 // Add attribute to order list if it doesn't already exist
339                                                                                 if (!attributes[attrName])
340                                                                                         attributesOrder.push(attrName);
341
342                                                                                 attributes[attrName] = attr;
343                                                                         }
344                                                                 }
345                                                         }
346                                                 }
347
348                                                 // Global rule, store away these for later usage
349                                                 if (!globalAttributes && elementName == '@') {
350                                                         globalAttributes = attributes;
351                                                         globalAttributesOrder = attributesOrder;
352                                                 }
353
354                                                 // Handle substitute elements such as b/strong
355                                                 if (outputName) {
356                                                         element.outputName = elementName;
357                                                         elements[outputName] = element;
358                                                 }
359
360                                                 // Add pattern or exact element
361                                                 if (hasPatternsRegExp.test(elementName)) {
362                                                         element.pattern = patternToRegExp(elementName);
363                                                         patternElements.push(element);
364                                                 } else
365                                                         elements[elementName] = element;
366                                         }
367                                 }
368                         }
369                 };
370
371                 function setValidElements(valid_elements) {
372                         elements = {};
373                         patternElements = [];
374
375                         addValidElements(valid_elements);
376
377                         each(transitional, function(element, name) {
378                                 children[name] = element.children;
379                         });
380                 };
381
382                 // Adds custom non HTML elements to the schema
383                 function addCustomElements(custom_elements) {
384                         var customElementRegExp = /^(~)?(.+)$/;
385
386                         if (custom_elements) {
387                                 each(split(custom_elements), function(rule) {
388                                         var matches = customElementRegExp.exec(rule),
389                                                 inline = matches[1] === '~',
390                                                 cloneName = inline ? 'span' : 'div',
391                                                 name = matches[2];
392
393                                         children[name] = children[cloneName];
394                                         customElementsMap[name] = cloneName;
395
396                                         // If it's not marked as inline then add it to valid block elements
397                                         if (!inline)
398                                                 blockElementsMap[name] = {};
399
400                                         // Add custom elements at span/div positions
401                                         each(children, function(element, child) {
402                                                 if (element[cloneName])
403                                                         element[name] = element[cloneName];
404                                         });
405                                 });
406                         }
407                 };
408
409                 // Adds valid children to the schema object
410                 function addValidChildren(valid_children) {
411                         var childRuleRegExp = /^([+\-]?)(\w+)\[([^\]]+)\]$/;
412
413                         if (valid_children) {
414                                 each(split(valid_children), function(rule) {
415                                         var matches = childRuleRegExp.exec(rule), parent, prefix;
416
417                                         if (matches) {
418                                                 prefix = matches[1];
419
420                                                 // Add/remove items from default
421                                                 if (prefix)
422                                                         parent = children[matches[2]];
423                                                 else
424                                                         parent = children[matches[2]] = {'#comment' : {}};
425
426                                                 parent = children[matches[2]];
427
428                                                 each(split(matches[3], '|'), function(child) {
429                                                         if (prefix === '-')
430                                                                 delete parent[child];
431                                                         else
432                                                                 parent[child] = {};
433                                                 });
434                                         }
435                                 });
436                         }
437                 };
438
439                 function getElementRule(name) {
440                         var element = elements[name], i;
441
442                         // Exact match found
443                         if (element)
444                                 return element;
445
446                         // No exact match then try the patterns
447                         i = patternElements.length;
448                         while (i--) {
449                                 element = patternElements[i];
450
451                                 if (element.pattern.test(name))
452                                         return element;
453                         }
454                 };
455
456                 if (!settings.valid_elements) {
457                         // No valid elements defined then clone the elements from the transitional spec
458                         each(transitional, function(element, name) {
459                                 elements[name] = {
460                                         attributes : element.attributes,
461                                         attributesOrder : element.attributesOrder
462                                 };
463
464                                 children[name] = element.children;
465                         });
466
467                         // Switch these
468                         each(split('strong/b,em/i'), function(item) {
469                                 item = split(item, '/');
470                                 elements[item[1]].outputName = item[0];
471                         });
472
473                         // Add default alt attribute for images
474                         elements.img.attributesDefault = [{name: 'alt', value: ''}];
475
476                         // Remove these if they are empty by default
477                         each(split('ol,ul,sub,sup,blockquote,span,font,a,table,tbody,tr'), function(name) {
478                                 elements[name].removeEmpty = true;
479                         });
480
481                         // Padd these by default
482                         each(split('p,h1,h2,h3,h4,h5,h6,th,td,pre,div,address,caption'), function(name) {
483                                 elements[name].paddEmpty = true;
484                         });
485                 } else
486                         setValidElements(settings.valid_elements);
487
488                 addCustomElements(settings.custom_elements);
489                 addValidChildren(settings.valid_children);
490                 addValidElements(settings.extended_valid_elements);
491
492                 // Todo: Remove this when we fix list handling to be valid
493                 addValidChildren('+ol[ul|ol],+ul[ul|ol]');
494
495                 // If the user didn't allow span only allow internal spans
496                 if (!getElementRule('span'))
497                         addValidElements('span[!data-mce-type|*]');
498
499                 // Delete invalid elements
500                 if (settings.invalid_elements) {
501                         tinymce.each(tinymce.explode(settings.invalid_elements), function(item) {
502                                 if (elements[item])
503                                         delete elements[item];
504                         });
505                 }
506
507                 /**
508                  * Name/value map object with valid parents and children to those parents.
509                  *
510                  * @example
511                  * children = {
512                  *    div:{p:{}, h1:{}}
513                  * };
514                  * @field children
515                  * @type {Object}
516                  */
517                 self.children = children;
518
519                 /**
520                  * Name/value map object with valid styles for each element.
521                  *
522                  * @field styles
523                  * @type {Object}
524                  */
525                 self.styles = validStyles;
526
527                 /**
528                  * Returns a map with boolean attributes.
529                  *
530                  * @method getBoolAttrs
531                  * @return {Object} Name/value lookup map for boolean attributes.
532                  */
533                 self.getBoolAttrs = function() {
534                         return boolAttrMap;
535                 };
536
537                 /**
538                  * Returns a map with block elements.
539                  *
540                  * @method getBoolAttrs
541                  * @return {Object} Name/value lookup map for block elements.
542                  */
543                 self.getBlockElements = function() {
544                         return blockElementsMap;
545                 };
546
547                 /**
548                  * Returns a map with short ended elements such as BR or IMG.
549                  *
550                  * @method getShortEndedElements
551                  * @return {Object} Name/value lookup map for short ended elements.
552                  */
553                 self.getShortEndedElements = function() {
554                         return shortEndedElementsMap;
555                 };
556
557                 /**
558                  * Returns a map with self closing tags such as <li>.
559                  *
560                  * @method getSelfClosingElements
561                  * @return {Object} Name/value lookup map for self closing tags elements.
562                  */
563                 self.getSelfClosingElements = function() {
564                         return selfClosingElementsMap;
565                 };
566
567                 /**
568                  * Returns a map with elements that should be treated as contents regardless if it has text
569                  * content in them or not such as TD, VIDEO or IMG.
570                  *
571                  * @method getNonEmptyElements
572                  * @return {Object} Name/value lookup map for non empty elements.
573                  */
574                 self.getNonEmptyElements = function() {
575                         return nonEmptyElementsMap;
576                 };
577
578                 /**
579                  * Returns a map with elements where white space is to be preserved like PRE or SCRIPT.
580                  *
581                  * @method getWhiteSpaceElements
582                  * @return {Object} Name/value lookup map for white space elements.
583                  */
584                 self.getWhiteSpaceElements = function() {
585                         return whiteSpaceElementsMap;
586                 };
587
588                 /**
589                  * Returns true/false if the specified element and it's child is valid or not
590                  * according to the schema.
591                  *
592                  * @method isValidChild
593                  * @param {String} name Element name to check for.
594                  * @param {String} child Element child to verify.
595                  * @return {Boolean} True/false if the element is a valid child of the specified parent.
596                  */
597                 self.isValidChild = function(name, child) {
598                         var parent = children[name];
599
600                         return !!(parent && parent[child]);
601                 };
602
603                 /**
604                  * Returns true/false if the specified element is valid or not
605                  * according to the schema.
606                  *
607                  * @method getElementRule
608                  * @param {String} name Element name to check for.
609                  * @return {Object} Element object or undefined if the element isn't valid.
610                  */
611                 self.getElementRule = getElementRule;
612
613                 /**
614                  * Returns an map object of all custom elements.
615                  *
616                  * @method getCustomElements
617                  * @return {Object} Name/value map object of all custom elements.
618                  */
619                 self.getCustomElements = function() {
620                         return customElementsMap;
621                 };
622
623                 /**
624                  * Parses a valid elements string and adds it to the schema. The valid elements format is for example "element[attr=default|otherattr]".
625                  * Existing rules will be replaced with the ones specified, so this extends the schema.
626                  *
627                  * @method addValidElements
628                  * @param {String} valid_elements String in the valid elements format to be parsed.
629                  */
630                 self.addValidElements = addValidElements;
631
632                 /**
633                  * Parses a valid elements string and sets it to the schema. The valid elements format is for example "element[attr=default|otherattr]".
634                  * Existing rules will be replaced with the ones specified, so this extends the schema.
635                  *
636                  * @method setValidElements
637                  * @param {String} valid_elements String in the valid elements format to be parsed.
638                  */
639                 self.setValidElements = setValidElements;
640
641                 /**
642                  * Adds custom non HTML elements to the schema.
643                  *
644                  * @method addCustomElements
645                  * @param {String} custom_elements Comma separated list of custom elements to add.
646                  */
647                 self.addCustomElements = addCustomElements;
648
649                 /**
650                  * Parses a valid children string and adds them to the schema structure. The valid children format is for example: "element[child1|child2]".
651                  *
652                  * @method addValidChildren
653                  * @param {String} valid_children Valid children elements string to parse
654                  */
655                 self.addValidChildren = addValidChildren;
656         };
657
658         // Expose boolMap and blockElementMap as static properties for usage in DOMUtils
659         tinymce.html.Schema.boolAttrMap = boolAttrMap;
660         tinymce.html.Schema.blockElementsMap = blockElementsMap;
661 })(tinymce);