[ Index ]
 

Code source de Kupu-1.3.5

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/common/ -> kupucontentfilters.js (source)

   1  /*****************************************************************************
   2   *
   3   * Copyright (c) 2003-2004 Kupu Contributors. All rights reserved.
   4   *
   5   * This software is distributed under the terms of the Kupu
   6   * License. See LICENSE.txt for license text. For a list of Kupu
   7   * Contributors see CREDITS.txt.
   8   *
   9   *****************************************************************************/
  10  
  11  // $Id: kupucontentfilters.js 18097 2005-10-03 09:51:28Z duncan $
  12  
  13  
  14  //----------------------------------------------------------------------------
  15  // 
  16  // ContentFilters
  17  //
  18  //  These are (or currently 'this is') filters for HTML cleanup and 
  19  //  conversion. Kupu filters should be classes that should get registered to
  20  //  the editor using the registerFilter method with 2 methods: 'initialize'
  21  //  and 'filter'. The first will be called with the editor as its only
  22  //  argument and the latter with a reference to the ownerdoc (always use 
  23  //  that to create new nodes and such) and the root node of the HTML DOM as 
  24  //  its arguments.
  25  //
  26  //----------------------------------------------------------------------------
  27  
  28  function NonXHTMLTagFilter() {
  29      /* filter out non-XHTML tags*/
  30      
  31      // A mapping from element name to whether it should be left out of the 
  32      // document entirely. If you want an element to reappear in the resulting 
  33      // document *including* it's contents, add it to the mapping with a 1 value.
  34      // If you want an element not to appear but want to leave it's contents in 
  35      // tact, add it to the mapping with a 0 value. If you want an element and
  36      // it's contents to be removed from the document, don't add it.
  37      if (arguments.length) {
  38          // allow an optional filterdata argument
  39          this.filterdata = arguments[0];
  40      } else {
  41          // provide a default filterdata dict
  42          this.filterdata = {'html': 1,
  43                              'body': 1,
  44                              'head': 1,
  45                              'title': 1,
  46                              
  47                              'a': 1,
  48                              'abbr': 1,
  49                              'acronym': 1,
  50                              'address': 1,
  51                              'b': 1,
  52                              'base': 1,
  53                              'blockquote': 1,
  54                              'br': 1,
  55                              'caption': 1,
  56                              'cite': 1,
  57                              'code': 1,
  58                              'col': 1,
  59                              'colgroup': 1,
  60                              'dd': 1,
  61                              'dfn': 1,
  62                              'div': 1,
  63                              'dl': 1,
  64                              'dt': 1,
  65                              'em': 1,
  66                              'h1': 1,
  67                              'h2': 1,
  68                              'h3': 1,
  69                              'h4': 1,
  70                              'h5': 1,
  71                              'h6': 1,
  72                              'h7': 1,
  73                              'i': 1,
  74                              'img': 1,
  75                              'kbd': 1,
  76                              'li': 1,
  77                              'link': 1,
  78                              'meta': 1,
  79                              'ol': 1,
  80                              'p': 1,
  81                              'pre': 1,
  82                              'q': 1,
  83                              'samp': 1,
  84                              'script': 1,
  85                              'span': 1,
  86                              'strong': 1,
  87                              'style': 1,
  88                              'sub': 1,
  89                              'sup': 1,
  90                              'table': 1,
  91                              'tbody': 1,
  92                              'td': 1,
  93                              'tfoot': 1,
  94                              'th': 1,
  95                              'thead': 1,
  96                              'tr': 1,
  97                              'ul': 1,
  98                              'u': 1,
  99                              'var': 1,
 100  
 101                              // even though they're deprecated we should leave
 102                              // font tags as they are, since Kupu sometimes
 103                              // produces them itself.
 104                              'font': 1,
 105                              'center': 0
 106                              };
 107      };
 108                          
 109      this.initialize = function(editor) {
 110          /* init */
 111          this.editor = editor;
 112      };
 113  
 114      this.filter = function(ownerdoc, htmlnode) {
 115          return this._filterHelper(ownerdoc, htmlnode);
 116      };
 117  
 118      this._filterHelper = function(ownerdoc, node) {
 119          /* filter unwanted elements */
 120          if (node.nodeType == 3) {
 121              return ownerdoc.createTextNode(node.nodeValue);
 122          } else if (node.nodeType == 4) {
 123              return ownerdoc.createCDATASection(node.nodeValue);
 124          };
 125          // create a new node to place the result into
 126          // XXX this can be severely optimized by doing stuff inline rather 
 127          // than on creating new elements all the time!
 128          var newnode = ownerdoc.createElement(node.nodeName);
 129          // copy the attributes
 130          for (var i=0; i < node.attributes.length; i++) {
 131              var attr = node.attributes[i];
 132              newnode.setAttribute(attr.nodeName, attr.nodeValue);
 133          };
 134          for (var i=0; i < node.childNodes.length; i++) {
 135              var child = node.childNodes[i];
 136              var nodeType = child.nodeType;
 137              var nodeName = child.nodeName.toLowerCase();
 138              if (nodeType == 3 || nodeType == 4) {
 139                  newnode.appendChild(this._filterHelper(ownerdoc, child));
 140              };
 141              if (nodeName in this.filterdata && this.filterdata[nodeName]) {
 142                  newnode.appendChild(this._filterHelper(ownerdoc, child));
 143              } else if (nodeName in this.filterdata) {
 144                  for (var j=0; j < child.childNodes.length; j++) {
 145                      newnode.appendChild(this._filterHelper(ownerdoc, 
 146                          child.childNodes[j]));
 147                  };
 148              };
 149          };
 150          return newnode;
 151      };
 152  };
 153  
 154  //-----------------------------------------------------------------------------
 155  //
 156  // XHTML validation support
 157  //
 158  // This class is the XHTML 1.0 transitional DTD expressed as Javascript
 159  // data structures.
 160  //
 161  function XhtmlValidation(editor) {
 162      // Support functions
 163      this.Set = function(ary) {
 164          if (typeof(ary)==typeof('')) ary = [ary];
 165          if (ary instanceof Array) {
 166              for (var i = 0; i < ary.length; i++) {
 167                  this[ary[i]] = 1;
 168              }
 169          }
 170          else {
 171              for (var v in ary) { // already a set?
 172                  this[v] = 1;
 173              }
 174          }
 175      }
 176  
 177      this._exclude = function(array, exceptions) {
 178          var ex;
 179          if (exceptions.split) {
 180              ex = exceptions.split("|");
 181          } else {
 182              ex = exceptions;
 183          }
 184          var exclude = new this.Set(ex);
 185          var res = [];
 186          for (var k=0; k < array.length;k++) {
 187              if (!exclude[array[k]]) res.push(array[k]);
 188          }
 189          return res;
 190      }
 191      this.setAttrFilter = function(attributes, filter) {
 192          for (var j = 0; j < attributes.length; j++) {
 193              var attr = attributes[j];
 194              this.attrFilters[attr] = filter || this._defaultCopyAttribute;
 195          }
 196      }
 197  
 198      this.setTagAttributes = function(tags, attributes) {
 199          for (var j = 0; j < tags.length; j++) {
 200              this.tagAttributes[tags[j]] = attributes;
 201          }
 202      }
 203  
 204      // define some new attributes for existing tags
 205      this.includeTagAttributes = function(tags, attributes) {
 206          for (var j = 0; j < tags.length; j++) {
 207              var tag = tags[j];
 208              this.tagAttributes[tag] = this.tagAttributes[tag].concat(attributes);
 209          }
 210      }
 211  
 212      this.excludeTagAttributes = function(tags, attributes) {
 213          var bad = new this.Set(attributes);
 214          var tagset = new this.Set(tags);
 215          for (var tag in tagset) {
 216              var val = this.tagAttributes[tag];
 217              for (var i = val.length; i >= 0; i--) {
 218                  if (bad[val[i]]) {
 219                      val = val.concat(); // Copy
 220                      val.splice(i,1);
 221                  }
 222              }
 223              this.tagAttributes[tag] = val;
 224              // have to store this to allow filtering for nodes on which
 225              // '*' is set as allowed, this allows using '*' for the attributes
 226              // but also filtering some out
 227              this.badTagAttributes[tag] = attributes;
 228          }
 229      }
 230  
 231      this.excludeTags = function(badtags) {
 232          if (typeof(badtags)==typeof('')) badtags = [badtags];
 233          for (var i = 0; i < badtags.length; i++) {
 234              delete this.tagAttributes[badtags[i]];
 235          }
 236      }
 237  
 238      this.excludeAttributes = function(badattrs) {
 239          this.excludeTagAttributes(this.tagAttributes, badattrs);
 240          for (var i = 0; i < badattrs.length; i++) {
 241              delete this.attrFilters[badattrs[i]];
 242          }
 243      }
 244      if (editor.getBrowserName()=="IE") {
 245          this._getTagName = function(htmlnode) {
 246              var nodename = htmlnode.nodeName.toLowerCase();
 247              if (htmlnode.scopeName && htmlnode.scopeName != "HTML") {
 248                  nodename = htmlnode.scopeName+':'+nodename;
 249              }
 250              return nodename;
 251          }
 252      } else {
 253          this._getTagName = function(htmlnode) {
 254              return htmlnode.nodeName.toLowerCase();
 255          }
 256      };
 257  
 258      // Supporting declarations
 259      this.elements = new function(validation) {
 260          // A list of all attributes
 261          this.attributes = [
 262              'abbr','accept','accept-charset','accesskey','action','align','alink',
 263              'alt','archive','axis','background','bgcolor','border','cellpadding',
 264              'cellspacing','char','charoff','charset','checked','cite','class',
 265              'classid','clear','code','codebase','codetype','color','cols','colspan',
 266              'compact','content','coords','data','datetime','declare','defer','dir',
 267              'disabled','enctype','face','for','frame','frameborder','headers',
 268              'height','href','hreflang','hspace','http-equiv','id','ismap','label',
 269              'lang','language','link','longdesc','marginheight','marginwidth',
 270              'maxlength','media','method','multiple','name','nohref','noshade','nowrap',
 271              'object','onblur','onchange','onclick','ondblclick','onfocus','onkeydown',
 272              'onkeypress','onkeyup','onload','onmousedown','onmousemove','onmouseout',
 273              'onmouseover','onmouseup','onreset','onselect','onsubmit','onunload',
 274              'profile','prompt','readonly','rel','rev','rows','rowspan','rules',
 275              'scheme','scope','scrolling','selected','shape','size','span','src',
 276              'standby','start','style','summary','tabindex','target','text','title',
 277              'type','usemap','valign','value','valuetype','vlink','vspace','width',
 278              'xml:lang','xml:space','xmlns'];
 279  
 280          // Core attributes
 281          this.coreattrs = ['id', 'title', 'style', 'class'];
 282          this.i18n = ['lang', 'dir', 'xml:lang'];
 283          // All event attributes are here but commented out so we don't
 284          // have to remove them later.
 285          this.events = []; // 'onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup'.split('|');
 286          this.focusevents = []; // ['onfocus','onblur']
 287          this.loadevents = []; // ['onload', 'onunload']
 288          this.formevents = []; // ['onsubmit','onreset']
 289          this.inputevents = [] ; // ['onselect', 'onchange']
 290          this.focus = ['accesskey', 'tabindex'].concat(this.focusevents);
 291          this.attrs = [].concat(this.coreattrs, this.i18n, this.events);
 292  
 293          // entities
 294          this.special_extra = ['object','applet','img','map','iframe'];
 295          this.special_basic=['br','span','bdo'];
 296          this.special = [].concat(this.special_basic, this.special_extra);
 297          this.fontstyle_extra = ['big','small','font','basefont'];
 298          this.fontstyle_basic = ['tt','i','b','u','s','strike'];
 299          this.fontstyle = [].concat(this.fontstyle_basic, this.fontstyle_extra);
 300          this.phrase_extra = ['sub','sup'];
 301          this.phrase_basic=[
 302                            'em','strong','dfn','code','q',
 303                            'samp','kbd','var', 'cite','abbr','acronym'];
 304          this.inline_forms = ['input','select','textarea','label','button'];
 305          this.misc_inline = ['ins','del'];
 306          this.misc = ['noscript'].concat(this.misc_inline);
 307          this.inline = ['a'].concat(this.special, this.fontstyle, this.phrase, this.inline_forms);
 308  
 309          this.Inline = ['#PCDATA'].concat(this.inline, this.misc_inline);
 310  
 311          this.heading = ['h1','h2','h3','h4','h5','h6'];
 312          this.lists = ['ul','ol','dl','menu','dir'];
 313          this.blocktext = ['pre','hr','blockquote','address','center','noframes'];
 314          this.block = ['p','div','isindex','fieldset','table'].concat(
 315                       this.heading, this.lists, this.blocktext);
 316  
 317          this.Flow = ['#PCDATA','form'].concat(this.block, this.inline);
 318      }(this);
 319  
 320      this._commonsetting = function(self, names, value) {
 321          for (var n = 0; n < names.length; n++) {
 322              self[names[n]] = value;
 323          }
 324      }
 325      
 326      // The tagAttributes class returns all valid attributes for a tag,
 327      // e.g. a = this.tagAttributes.head
 328      // a.head -> [ 'lang', 'xml:lang', 'dir', 'id', 'profile' ]
 329      this.tagAttributes = new function(el, validation) {
 330          this.title = el.i18n.concat('id');
 331          this.html = this.title.concat('xmlns');
 332          this.head = this.title.concat('profile');
 333          this.base = ['id', 'href', 'target'];
 334          this.meta =  this.title.concat('http-equiv','name','content', 'scheme');
 335          this.link = el.attrs.concat('charset','href','hreflang','type', 'rel','rev','media','target');
 336          this.style = this.title.concat('type','media','title', 'xml:space');
 337          this.script = ['id','charset','type','language','src','defer', 'xml:space'];
 338          this.iframe = [
 339                        'longdesc','name','src','frameborder','marginwidth',
 340                        'marginheight','scrolling','align','height','width'].concat(el.coreattrs);
 341          this.body = ['background','bgcolor','text','link','vlink','alink'].concat(el.attrs, el.loadevents);
 342          validation._commonsetting(this,
 343                                    ['p','div'].concat(el.heading),
 344                                    ['align'].concat(el.attrs));
 345          this.dl = this.dir = this.menu = el.attrs.concat('compact');
 346          this.ul = this.menu.concat('type');
 347          this.ol = this.ul.concat('start');
 348          this.li = el.attrs.concat('type','value');
 349          this.hr = el.attrs.concat('align','noshade','size','width');
 350          this.pre = el.attrs.concat('width','xml:space');
 351          this.blockquote = this.q = el.attrs.concat('cite');
 352          this.ins = this.del = this.blockquote.concat('datetime');
 353          this.a = el.attrs.concat(el.focus,'charset','type','name','href','hreflang','rel','rev','shape','coords','target');
 354          this.bdo = el.coreattrs.concat(el.events, 'lang','xml:lang','dir');
 355          this.br = el.coreattrs.concat('clear');
 356          validation._commonsetting(this,
 357                                    ['noscript','noframes','dt', 'dd', 'address','center','span','em', 'strong', 'dfn','code',
 358                                    'samp','kbd','var','cite','abbr','acronym','sub','sup','tt',
 359                                    'i','b','big','small','u','s','strike', 'fieldset'],
 360                                    el.attrs);
 361  
 362          this.basefont = ['id','size','color','face'];
 363          this.font = el.coreattrs.concat(el.i18n, 'size','color','face');
 364          this.object = el.attrs.concat('declare','classid','codebase','data','type','codetype','archive','standby','height','width','usemap','name','tabindex','align','border','hspace','vspace');
 365          this.param = ['id','name','value','valuetype','type'];
 366          this.applet = el.coreattrs.concat('codebase','archive','code','object','alt','name','width','height','align','hspace','vspace');
 367          this.img = el.attrs.concat('src','alt','name','longdesc','height','width','usemap','ismap','align','border','hspace','vspace');
 368          this.map = this.title.concat('title','name', 'style', 'class', el.events);
 369          this.area = el.attrs.concat('shape','coords','href','nohref','alt','target', el.focus);
 370          this.form = el.attrs.concat('action','method','name','enctype',el.formevents,'accept','accept-charset','target');
 371          this.label = el.attrs.concat('for','accesskey', el.focusevents);
 372          this.input = el.attrs.concat('type','name','value','checked','disabled','readonly','size','maxlength','src','alt','usemap',el.input,'accept','align', el.focus);
 373          this.select = el.attrs.concat('name','size','multiple','disabled','tabindex', el.focusevents,el.input);
 374          this.optgroup = el.attrs.concat('disabled','label');
 375          this.option = el.attrs.concat('selected','disabled','label','value');
 376          this.textarea = el.attrs.concat('name','rows','cols','disabled','readonly', el.inputevents, el.focus);
 377          this.legend = el.attrs.concat('accesskey','align');
 378          this.button = el.attrs.concat('name','value','type','disabled',el.focus);
 379          this.isindex = el.coreattrs.concat('prompt', el.i18n);
 380          this.table = el.attrs.concat('summary','width','border','frame','rules','cellspacing','cellpadding','align','bgcolor');
 381          this.caption = el.attrs.concat('align');
 382          this.col = this.colgroup = el.attrs.concat('span','width','align','char','charoff','valign');
 383          this.thead =  el.attrs.concat('align','char','charoff','valign');
 384          this.tfoot = this.tbody = this.thead;
 385          this.tr = this.thead.concat('bgcolor');
 386          this.td = this.th = this.tr.concat('abbr','axis','headers','scope','rowspan','colspan','nowrap','width','height');
 387      }(this.elements, this);
 388  
 389      this.badTagAttributes = new this.Set({});
 390  
 391      // State array. For each tag identifies what it can contain.
 392      // I'm not attempting to check the order or number of contained
 393      // tags (yet).
 394      this.States = new function(el, validation) {
 395  
 396          var here = this;
 397          function setStates(tags, value) {
 398              var valset = new validation.Set(value);
 399  
 400              for (var i = 0; i < tags.length; i++) {
 401                  here[tags[i]] = valset;
 402              }
 403          }
 404          
 405          setStates(['html'], ['head','body']);
 406          setStates(['head'], ['title','base','script','style', 'meta','link','object','isindex']);
 407          setStates([
 408              'base', 'meta', 'link', 'hr', 'param', 'img', 'area', 'input',
 409              'br', 'basefont', 'isindex', 'col',
 410              ], []);
 411  
 412          setStates(['title','style','script','option','textarea'], ['#PCDATA']);
 413          setStates([ 'noscript', 'iframe', 'noframes', 'body', 'div',
 414              'li', 'dd', 'blockquote', 'center', 'ins', 'del', 'td', 'th',
 415              ], el.Flow);
 416  
 417          setStates(el.heading, el.Inline);
 418          setStates([ 'p', 'dt', 'address', 'span', 'bdo', 'caption',
 419              'em', 'strong', 'dfn','code','samp','kbd','var',
 420              'cite','abbr','acronym','q','sub','sup','tt','i',
 421              'b','big','small','u','s','strike','font','label',
 422              'legend'], el.Inline);
 423  
 424          setStates(['ul', 'ol', 'menu', 'dir', 'ul', ], ['li']);
 425          setStates(['dl'], ['dt','dd']);
 426          setStates(['pre'], validation._exclude(el.Inline, "img|object|applet|big|small|sub|sup|font|basefont"));
 427          setStates(['a'], validation._exclude(el.Inline, "a"));
 428          setStates(['applet', 'object'], ['#PCDATA', 'param','form'].concat(el.block, el.inline, el.misc));
 429          setStates(['map'], ['form', 'area'].concat(el.block, el.misc));
 430          setStates(['form'], validation._exclude(el.Flow, ['form']));
 431          setStates(['select'], ['optgroup','option']);
 432          setStates(['optgroup'], ['option']);
 433          setStates(['fieldset'], ['#PCDATA','legend','form'].concat(el.block,el.inline,el.misc));
 434          setStates(['button'], validation._exclude(el.Flow, ['a','form','iframe'].concat(el.inline_forms)));
 435          setStates(['table'], ['caption','col','colgroup','thead','tfoot','tbody','tr']);
 436          setStates(['thead', 'tfoot', 'tbody'], ['tr']);
 437          setStates(['colgroup'], ['col']);
 438          setStates(['tr'], ['th','td']);
 439      }(this.elements, this);
 440  
 441      // Permitted elements for style.
 442      this.styleWhitelist = new this.Set(['text-align', 'list-style-type', 'float']);
 443      this.classBlacklist = new this.Set(['MsoNormal', 'MsoTitle', 'MsoHeader', 'MsoFootnoteText',
 444          'Bullet1', 'Bullet2']);
 445  
 446      this.classFilter = function(value) {
 447          var classes = value.split(' ');
 448          var filtered = [];
 449          for (var i = 0; i < classes.length; i++) {
 450              var c = classes[i];
 451              if (c && !this.classBlacklist[c]) {
 452                  filtered.push(c);
 453              }
 454          }
 455          return filtered.join(' ');
 456      }
 457      this._defaultCopyAttribute = function(name, htmlnode, xhtmlnode) {
 458          var val = htmlnode.getAttribute(name);
 459          if (val) xhtmlnode.setAttribute(name, val);
 460      }
 461      // Set up filters for attributes.
 462      var filter = this;
 463      this.attrFilters = new function(validation, editor) {
 464          var attrs = validation.elements.attributes;
 465          for (var i=0; i < attrs.length; i++) {
 466              this[attrs[i]] = validation._defaultCopyAttribute;
 467          }
 468          this['class'] = function(name, htmlnode, xhtmlnode) {
 469              var val = htmlnode.getAttribute('class');
 470              if (val) val = validation.classFilter(val);
 471              if (val) xhtmlnode.setAttribute('class', val);
 472          }
 473          // allow a * wildcard to make all attributes valid in the filter
 474          // note that this is pretty slow on IE
 475          this['*'] = function(name, htmlnode, xhtmlnode) {
 476              var nodeName = filter._getTagName(htmlnode);
 477              var bad = filter.badTagAttributes[nodeName];
 478              for (var i=0; i < htmlnode.attributes.length; i++) {
 479                  var attr = htmlnode.attributes[i];
 480                  if (bad && bad.contains(attr.name)) {
 481                      continue;
 482                  };
 483                  if (attr.value !== null && attr.value !== undefined) {
 484                      xhtmlnode.setAttribute(attr.name, attr.value);
 485                  };
 486              };
 487          }
 488          if (editor.getBrowserName()=="IE") {
 489              this['class'] = function(name, htmlnode, xhtmlnode) {
 490                  var val = htmlnode.className;
 491                  if (val) val = validation.classFilter(val);
 492                  if (val) xhtmlnode.setAttribute('class', val);
 493              }
 494              this['http-equiv'] = function(name, htmlnode, xhtmlnode) {
 495                  var val = htmlnode.httpEquiv;
 496                  if (val) xhtmlnode.setAttribute('http-equiv', val);
 497              }
 498              this['xml:lang'] = this['xml:space'] = function(name, htmlnode, xhtmlnode) {
 499                  try {
 500                      var val = htmlnode.getAttribute(name);
 501                      if (val) xhtmlnode.setAttribute(name, val);
 502                  } catch(e) {
 503                  }
 504              }
 505          }
 506          this.rowspan = this.colspan = function(name, htmlnode, xhtmlnode) {
 507              var val = htmlnode.getAttribute(name);
 508              if (val && val != '1') xhtmlnode.setAttribute(name, val);
 509          }
 510          this.style = function(name, htmlnode, xhtmlnode) {
 511              var val = htmlnode.style.cssText;
 512              if (val) {
 513                  var styles = val.split(/; */);
 514                  for (var i = styles.length; i >= 0; i--) if (styles[i]) {
 515                      var parts = /^([^:]+): *(.*)$/.exec(styles[i]);
 516                      var name = parts[1].toLowerCase();
 517                      if (validation.styleWhitelist[name]) {
 518                          styles[i] = name+': '+parts[2];
 519                      } else {
 520                          styles.splice(i,1); // delete
 521                      }
 522                  }
 523                  if (styles[styles.length-1]) styles.push('');
 524                  val = styles.join('; ').strip();
 525              }
 526              if (val) xhtmlnode.setAttribute('style', val);
 527          }
 528      }(this, editor);
 529  
 530      // Exclude unwanted tags.
 531      this.excludeTags(['center']);
 532  
 533      if (editor.config && editor.config.htmlfilter) {
 534          this.filterStructure = editor.config.htmlfilter.filterstructure;
 535          
 536          var exclude = editor.config.htmlfilter;
 537          if (exclude.a)
 538              this.excludeAttributes(exclude.a);
 539          if (exclude.t)
 540              this.excludeTags(exclude.t);
 541          if (exclude.c) {
 542              var c = exclude.c;
 543              if (!c.length) c = [c];
 544              for (var i = 0; i < c.length; i++) {
 545                  this.excludeTagAttributes(c[i].t, c[i].a);
 546              }
 547          }
 548          if (exclude.xstyle) {
 549              var s = exclude.xstyle;
 550              for (var i = 0; i < s.length; i++) {
 551                  this.styleWhitelist[s[i]] = 1;
 552              }
 553          }
 554          if (exclude['class']) {
 555              var c = exclude['class'];
 556              for (var i = 0; i < c.length; i++) {
 557                  this.classBlacklist[c[i]] = 1;
 558              }
 559          }
 560      };
 561  
 562      // Copy all valid attributes from htmlnode to xhtmlnode.
 563      this._copyAttributes = function(htmlnode, xhtmlnode, valid) {
 564          if (valid.contains('*')) {
 565              // allow all attributes on this tag
 566              this.attrFilters['*'](name, htmlnode, xhtmlnode);
 567              return;
 568          };
 569          for (var i = 0; i < valid.length; i++) {
 570              var name = valid[i];
 571              var filter = this.attrFilters[name];
 572              if (filter) filter(name, htmlnode, xhtmlnode);
 573          }
 574      }
 575  
 576      this._convertToSarissaNode = function(ownerdoc, htmlnode, xhtmlparent) {
 577          return this._convertNodes(ownerdoc, htmlnode, xhtmlparent, new this.Set(['html']));
 578      };
 579      
 580      this._convertNodes = function(ownerdoc, htmlnode, xhtmlparent, permitted) {
 581          var name, parentnode = xhtmlparent;
 582          var nodename = this._getTagName(htmlnode);
 583          var nostructure = !this.filterstructure;
 584  
 585          // TODO: This permits valid tags anywhere. it should use the state
 586          // table in xhtmlvalid to only permit tags where the XHTML DTD
 587          // says they are valid.
 588          var validattrs = this.tagAttributes[nodename];
 589          if (validattrs && (nostructure || permitted[nodename])) {
 590              try {
 591                  var xhtmlnode = ownerdoc.createElement(nodename);
 592                  parentnode = xhtmlnode;
 593              } catch (e) { };
 594  
 595              if (validattrs && xhtmlnode)
 596                  this._copyAttributes(htmlnode, xhtmlnode, validattrs);
 597          }
 598  
 599          var kids = htmlnode.childNodes;
 600          var permittedChildren = this.States[parentnode.tagName] || permitted;
 601  
 602          if (kids.length == 0) {
 603              if (htmlnode.text && htmlnode.text != "" &&
 604                  (nostructure || permittedChildren['#PCDATA'])) {
 605                  var text = htmlnode.text;
 606                  var tnode = ownerdoc.createTextNode(text);
 607                  parentnode.appendChild(tnode);
 608              }
 609          } else {
 610              for (var i = 0; i < kids.length; i++) {
 611                  var kid = kids[i];
 612  
 613                  if (kid.parentNode !== htmlnode) {
 614                      if (kid.tagName == 'BODY') {
 615                          if (nodename != 'html') continue;
 616                      } else if (kid.parentNode.tagName === htmlnode.tagName) {
 617                          continue; // IE bug: nodes appear multiple places
 618                      }
 619                  }
 620                  
 621                  if (kid.nodeType == 1) {
 622                      var newkid = this._convertNodes(ownerdoc, kid, parentnode, permittedChildren);
 623                      if (newkid != null) {
 624                          parentnode.appendChild(newkid);
 625                      };
 626                  } else if (kid.nodeType == 3) {
 627                      if (nostructure || permittedChildren['#PCDATA'])
 628                          parentnode.appendChild(ownerdoc.createTextNode(kid.nodeValue));
 629                  } else if (kid.nodeType == 4) {
 630                      if (nostructure || permittedChildren['#PCDATA'])
 631                          parentnode.appendChild(ownerdoc.createCDATASection(kid.nodeValue));
 632                  }
 633              }
 634          } 
 635          return xhtmlnode;
 636      };
 637  }
 638  
 639  


Généré le : Sun Feb 25 15:30:41 2007 par Balluche grâce à PHPXref 0.7