Changeset 780 for trunk/plugins


Ignore:
Timestamp:
03/14/07 15:11:03 (12 years ago)
Author:
ray
Message:
  • Ticket #543 Stylist Panel overflow broken
  • Ticket #30 about memory use
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/plugins/Stylist/stylist.js

    r626 r780  
    44 */ 
    55 
    6 HTMLArea.Config.prototype.css_style = { }; 
     6Xinha.Config.prototype.css_style = { }; 
    77 
    88/** 
    99 * This method loads an external stylesheet and uses it in the stylist 
    1010 */ 
    11 HTMLArea.Config.prototype.stylistLoadStylesheet = function(url, altnames) 
     11Xinha.Config.prototype.stylistLoadStylesheet = function(url, altnames) 
    1212{ 
    1313  if(!altnames) altnames = { }; 
    14   var newStyles = HTMLArea.ripStylesFromCSSFile(url); 
     14  var newStyles = Xinha.ripStylesFromCSSFile(url); 
    1515  for(var i in newStyles) 
    1616  { 
     
    3030 * This method takes raw style definitions and uses them in the stylist 
    3131 */ 
    32 HTMLArea.Config.prototype.stylistLoadStyles = function(styles, altnames) 
     32Xinha.Config.prototype.stylistLoadStyles = function(styles, altnames) 
    3333{ 
    3434  if(!altnames) altnames = { }; 
    35   var newStyles = HTMLArea.ripStylesFromCSSString(styles); 
     35  var newStyles = Xinha.ripStylesFromCSSString(styles); 
    3636  for(var i in newStyles) 
    3737  { 
     
    5252/** 
    5353 * Fill the stylist panel with styles that may be applied to the current selection.  Styles 
    54  * are supplied in the css_style property of the HTMLArea.Config object, which is in the format 
     54 * are supplied in the css_style property of the Xinha.Config object, which is in the format 
    5555 * { '.className' : 'Description' } 
    5656 * classes that are defined on a specific tag (eg 'a.email_link') are only shown in the panel 
     
    6464 * spans will be added where no single _and_entire_ element is selected 
    6565 */ 
    66 HTMLArea.prototype._fillStylist = function() 
     66Xinha.prototype._fillStylist = function() 
    6767{ 
    6868  if(!this._stylist) return false; 
    69   this._stylist.innerHTML = '<h1>'+HTMLArea._lc('Styles', 'Stylist')+'</h1>'; 
     69  this.plugins.Stylist.instance.main.innerHTML = ''; 
    7070 
    7171  var may_apply = true; 
     
    8383    var className = x.trim(); 
    8484    var applicable = true; 
     85    var idApplicable = false; 
    8586    var apply_to   = active_elem; 
    8687 
     
    9697      // No class name, just redefines a tag 
    9798      applicable = false; 
     99   
     100      if (className.indexOf('#') >= 0) 
     101      { 
     102        idApplicable = true; 
     103      } 
    98104    } 
    99105 
     
    147153    } 
    148154 
    149     if(applicable) 
    150     { 
    151       // Remove the first . 
    152       className = className.substring(className.indexOf('.'), className.length); 
    153  
    154       // Replace any futher ones with spaces (for multiple class definitions) 
    155       className = className.replace('.', ' '); 
     155    if (idApplicable) // IDs 
     156    { 
     157       // requires specific html tag 
     158      tag = className.substring(0, className.indexOf('#')).toLowerCase(); 
     159      var idName = className.substring(className.indexOf('#'), className.length); 
     160   
     161      // To apply we must have an ancestor tag that is the right type 
     162      if(active_elem != null && active_elem.tagName.toLowerCase() == tag) 
     163      { 
     164        idApplicable = true; 
     165        apply_to = active_elem; 
     166      } 
     167      else 
     168      { 
     169        if(this._getFirstAncestor(this._getSelection(), [tag]) != null) 
     170        { 
     171          idApplicable = true; 
     172          apply_to = this._getFirstAncestor(this._getSelection(), [tag]); 
     173        } 
     174        else 
     175        { 
     176          // alert (this._getFirstAncestor(this._getSelection(), tag)); 
     177          // If we don't have an ancestor, but it's a div/span/p/hx stle, we can make one 
     178          if(( tag == 'div' || tag == 'span' || tag == 'p' 
     179              || (tag.substr(0,1) == 'h' && tag.length == 2 && tag != 'hr'))) 
     180          { 
     181            if(!this._selectionEmpty(this._getSelection())) 
     182            { 
     183              idApplicable = true; 
     184              apply_to = 'new'; 
     185            } 
     186            else 
     187            { 
     188              // See if we can get a paragraph or header that can be converted 
     189              apply_to = this._getFirstAncestor(sel, ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']); 
     190              if(apply_to != null) 
     191              { 
     192                idApplicable = true; 
     193              } 
     194            } 
     195          } 
     196          else 
     197          { 
     198            idApplicable = false; 
     199          } 
     200        } 
     201      }     
     202    } 
     203 
     204 
     205    if(applicable || idApplicable) 
     206    { 
     207 
     208      if (idApplicable) 
     209      { 
     210        // Remove the first . 
     211        idName = idName.substring(idName.indexOf('#'), idName.length); 
     212 
     213        // Replace any futher ones with spaces (for multiple id definitions (yes it happens)) 
     214        idName = idName.replace('#', ' '); 
     215      } 
     216      else 
     217      { 
     218        // Remove the first . 
     219        className = className.substring(className.indexOf('.'), className.length); 
     220 
     221        // Replace any futher ones with spaces (for multiple class definitions) 
     222        className = className.replace('.', ' '); 
     223      } 
    156224 
    157225      if(apply_to == null) 
     
    170238    } 
    171239 
    172     var applied    = (this._ancestorsWithClasses(sel, tag, className).length > 0 ? true : false); 
    173     var applied_to = this._ancestorsWithClasses(sel, tag, className); 
    174  
    175     if(applicable) 
     240    if (idApplicable) 
     241    { 
     242      var applied    = (this._ancestorsWithIDs(sel, tag, idName).length > 0 ? true : false); 
     243      var applied_to = this._ancestorsWithIDs(sel, tag, idName); 
     244    } 
     245    else 
     246    { 
     247      var applied    = (this._ancestorsWithClasses(sel, tag, className).length > 0 ? true : false); 
     248      var applied_to = this._ancestorsWithClasses(sel, tag, className); 
     249    } 
     250 
     251    if(applicable || idApplicable) 
    176252    { 
    177253      var anch = document.createElement('a'); 
    178       anch._stylist_className = className.trim(); 
     254      if (idApplicable) 
     255        anch._stylist_idName = idName.trim();   
     256      else 
     257        anch._stylist_className = className.trim(); 
    179258      anch._stylist_applied   = applied; 
    180259      anch._stylist_appliedTo = applied_to; 
     
    185264      anch.href = 'javascript:void(0)'; 
    186265      var editor = this; 
    187       anch.onclick = function() 
    188       { 
    189         if(this._stylist_applied == true) 
    190         { 
    191           editor._stylistRemoveClasses(this._stylist_className, this._stylist_appliedTo); 
    192         } 
    193         else 
    194         { 
    195           editor._stylistAddClasses(this._stylist_applyTo, this._stylist_applyTag, this._stylist_className); 
    196         } 
    197         return false; 
     266      if (idApplicable) 
     267      {   
     268        anch.onclick = function() 
     269        { 
     270          if(this._stylist_applied == true) 
     271          { 
     272            editor._stylistRemoveIDs(this._stylist_idName, this._stylist_appliedTo); 
     273          } 
     274          else 
     275          { 
     276            editor._stylistAddIDs(this._stylist_applyTo, this._stylist_applyTag, this._stylist_idName); 
     277          } 
     278          return false; 
     279        } 
     280      } 
     281      else 
     282      { 
     283        anch.onclick = function() 
     284        { 
     285          if(this._stylist_applied == true) 
     286          { 
     287            editor._stylistRemoveClasses(this._stylist_className, this._stylist_appliedTo); 
     288          } 
     289          else 
     290          { 
     291            editor._stylistAddClasses(this._stylist_applyTo, this._stylist_applyTag, this._stylist_className); 
     292          } 
     293          return false; 
     294        } 
    198295      } 
    199296 
     
    210307      } 
    211308 
    212       this._stylist.appendChild(anch); 
     309      this.plugins.Stylist.instance.main.appendChild(anch); 
    213310    } 
    214311  } 
     
    220317 * (will add a span if none selected) 
    221318 */ 
    222 HTMLArea.prototype._stylistAddClasses = function(el, tag, classes) 
     319Xinha.prototype._stylistAddClasses = function(el, tag, classes) 
    223320  { 
    224321    if(el == 'new') 
     
    243340        } 
    244341 
    245         HTMLArea.addClasses(new_el, classes); 
     342        Xinha.addClasses(new_el, classes); 
    246343      } 
    247344      else 
    248345      { 
    249         HTMLArea._addClasses(el, classes); 
     346        Xinha._addClasses(el, classes); 
    250347      } 
    251348    } 
     
    253350    this.updateToolbar(); 
    254351  }; 
     352   
     353Xinha.prototype._stylistAddIDs = function(el, tag, ids) 
     354  { 
     355    if(el == 'new') 
     356    { 
     357      this.insertHTML('<' + tag + ' id="' + ids + '">' + this.getSelectedHTML() + '</' + tag + '>'); 
     358    } 
     359    else 
     360    { 
     361      if(tag != null && el.tagName.toLowerCase() != tag) 
     362      { 
     363        // Have to change the tag! 
     364        var new_el = this.switchElementTag(el, tag); 
     365 
     366        if(typeof el._stylist_usedToBe != 'undefined') 
     367        { 
     368          new_el._stylist_usedToBe = el._stylist_usedToBe; 
     369          new_el._stylist_usedToBe[new_el._stylist_usedToBe.length] = {'tagName' : el.tagName, 'id' : el.getAttribute('id')}; 
     370        } 
     371        else 
     372        { 
     373          new_el._stylist_usedToBe = [{'tagName' : el.tagName, 'id' : el.getAttribute('id')}]; 
     374        } 
     375 
     376        Xinha.addIDs(new_el, ids); 
     377      } 
     378      else 
     379      { 
     380        Xinha._addIDs(el, ids); 
     381      } 
     382    } 
     383    this.focusEditor(); 
     384    this.updateToolbar(); 
     385  };   
    255386 
    256387/** 
    257388 * Remove the given classes (space seperated list) from the given elements (array of elements) 
    258389 */ 
    259 HTMLArea.prototype._stylistRemoveClasses = function(classes, from) 
     390Xinha.prototype._stylistRemoveClasses = function(classes, from) 
    260391  { 
    261392    for(var x = 0; x < from.length; x++) 
     
    266397    this.updateToolbar(); 
    267398  }; 
    268  
    269 HTMLArea.prototype._stylistRemoveClassesFull = function(el, classes) 
     399   
     400Xinha.prototype._stylistRemoveIDs = function(ids, from) 
     401  { 
     402    for(var x = 0; x < from.length; x++) 
     403    { 
     404      this._stylistRemoveIDsFull(from[x], ids); 
     405    } 
     406    this.focusEditor(); 
     407    this.updateToolbar(); 
     408  };   
     409 
     410Xinha.prototype._stylistRemoveClassesFull = function(el, classes) 
    270411{ 
    271412  if(el != null) 
     
    294435      // Revert back to what we were IF the classes are identical 
    295436      var last_el = el._stylist_usedToBe[el._stylist_usedToBe.length - 1]; 
    296       var last_classes = HTMLArea.arrayFilter(last_el.className.trim().split(' '), function(c) { if (c == null || c.trim() == '') { return false;} return true; }); 
     437      var last_classes = Xinha.arrayFilter(last_el.className.trim().split(' '), function(c) { if (c == null || c.trim() == '') { return false;} return true; }); 
    297438 
    298439      if( 
     
    300441        || 
    301442        ( 
    302         HTMLArea.arrayContainsArray(new_thiers, last_classes) 
    303         && HTMLArea.arrayContainsArray(last_classes, new_thiers) 
     443        Xinha.arrayContainsArray(new_thiers, last_classes) 
     444        && Xinha.arrayContainsArray(last_classes, new_thiers) 
    304445        ) 
    305446      ) 
     
    336477}; 
    337478 
     479Xinha.prototype._stylistRemoveIDsFull = function(el, ids) 
     480{ 
     481  if(el != null) 
     482  { 
     483    var thiers = el.id.trim().split(' '); 
     484    var new_thiers = [ ]; 
     485    var ours   = ids.split(' '); 
     486    for(var x = 0; x < thiers.length; x++) 
     487    { 
     488      var exists = false; 
     489      for(var i = 0; exists == false && i < ours.length; i++) 
     490      { 
     491        if(ours[i] == thiers[x]) 
     492        { 
     493          exists = true; 
     494        } 
     495      } 
     496      if(exists == false) 
     497      { 
     498        new_thiers[new_thiers.length] = thiers[x]; 
     499      } 
     500    } 
     501 
     502    if(new_thiers.length == 0 && el._stylist_usedToBe && el._stylist_usedToBe.length > 0 && el._stylist_usedToBe[el._stylist_usedToBe.length - 1].id != null) 
     503    { 
     504      // Revert back to what we were IF the classes are identical 
     505      var last_el = el._stylist_usedToBe[el._stylist_usedToBe.length - 1]; 
     506      var last_ids = Xinha.arrayFilter(last_el.id.trim().split(' '), function(c) { if (c == null || c.trim() == '') { return false;} return true; }); 
     507 
     508      if( 
     509        (new_thiers.length == 0) 
     510        || 
     511        ( 
     512        Xinha.arrayContainsArray(new_thiers, last_ids) 
     513        && Xinha.arrayContainsArray(last_ids, new_thiers) 
     514        ) 
     515      ) 
     516      { 
     517        el = this.switchElementTag(el, last_el.tagName); 
     518        new_thiers = last_ids; 
     519      } 
     520      else 
     521      { 
     522        // We can't rely on the remembered tags any more 
     523        el._stylist_usedToBe = [ ]; 
     524      } 
     525    } 
     526 
     527    if(     new_thiers.length > 0 
     528        ||  el.tagName.toLowerCase() != 'span' 
     529        || (el.id && el.id != '') 
     530      ) 
     531    { 
     532      el.id = new_thiers.join(' ').trim(); 
     533    } 
     534    else 
     535    { 
     536      // Must be a span with no classes and no id, so we can splice it out 
     537      var prnt = el.parentNode; 
     538      var childs = el.childNodes; 
     539      for(var x = 0; x < childs.length; x++) 
     540      { 
     541        prnt.insertBefore(childs[x], el); 
     542      } 
     543      prnt.removeChild(el); 
     544    } 
     545  } 
     546}; 
     547 
    338548/** 
    339549 * Change the tag of an element 
    340550 */ 
    341 HTMLArea.prototype.switchElementTag = function(el, tag) 
     551Xinha.prototype.switchElementTag = function(el, tag) 
    342552{ 
    343553  var prnt = el.parentNode; 
    344554  var new_el = this._doc.createElement(tag); 
    345555 
    346   if(HTMLArea.is_ie || el.hasAttribute('id'))    new_el.setAttribute('id', el.getAttribute('id')); 
    347   if(HTMLArea.is_ie || el.hasAttribute('style')) new_el.setAttribute('style', el.getAttribute('style')); 
     556  if(Xinha.is_ie || el.hasAttribute('id'))    new_el.setAttribute('id', el.getAttribute('id')); 
     557  if(Xinha.is_ie || el.hasAttribute('style')) new_el.setAttribute('style', el.getAttribute('style')); 
    348558 
    349559  var childs = el.childNodes; 
     
    360570}; 
    361571 
    362 HTMLArea.prototype._getAncestorsClassNames = function(sel) 
     572Xinha.prototype._getAncestorsClassNames = function(sel) 
    363573{ 
    364574  // Scan upwards to find a block level element that we can change or apply to 
     
    366576  if(prnt == null) 
    367577  { 
    368     prnt = (HTMLArea.is_ie ? this._createRange(sel).parentElement() : this._createRange(sel).commonAncestorContainer); 
     578    prnt = (Xinha.is_ie ? this._createRange(sel).parentElement() : this._createRange(sel).commonAncestorContainer); 
    369579  } 
    370580 
     
    389599}; 
    390600 
    391 HTMLArea.prototype._ancestorsWithClasses = function(sel, tag, classes) 
     601Xinha.prototype._ancestorsWithClasses = function(sel, tag, classes) 
    392602{ 
    393603  var ancestors = [ ]; 
     
    397607    try 
    398608    { 
    399       prnt = (HTMLArea.is_ie ? this._createRange(sel).parentElement() : this._createRange(sel).commonAncestorContainer); 
     609      prnt = (Xinha.is_ie ? this._createRange(sel).parentElement() : this._createRange(sel).commonAncestorContainer); 
    400610    } 
    401611    catch(e) 
     
    444654}; 
    445655 
    446  
    447 HTMLArea.ripStylesFromCSSFile = function(URL) 
    448 { 
    449   var css = HTMLArea._geturlcontent(URL); 
    450   return HTMLArea.ripStylesFromCSSString(css); 
    451 }; 
    452  
    453 HTMLArea.ripStylesFromCSSString = function(css) 
     656Xinha.prototype._ancestorsWithIDs = function(sel, tag, ids) 
     657{ 
     658  var ancestors = [ ]; 
     659  var prnt = this._activeElement(sel); 
     660  if(prnt == null) 
     661  { 
     662    try 
     663    { 
     664      prnt = (Xinha.is_ie ? this._createRange(sel).parentElement() : this._createRange(sel).commonAncestorContainer); 
     665    } 
     666    catch(e) 
     667    { 
     668      return ancestors; 
     669    } 
     670  } 
     671  var search_ids = ids.trim().split(' '); 
     672 
     673  while(prnt) 
     674  { 
     675    if(prnt.nodeType == 1 && prnt.id) 
     676    { 
     677      if(tag == null || prnt.tagName.toLowerCase() == tag) 
     678      { 
     679        var ids = prnt.id.trim().split(' '); 
     680        var found_all = true; 
     681        for(var i = 0; i < search_ids.length; i++) 
     682        { 
     683          var found_id = false; 
     684          for(var x = 0; x < ids.length; x++) 
     685          { 
     686            if(search_ids[i] == ids[x]) 
     687            { 
     688              found_id = true; 
     689              break; 
     690            } 
     691          } 
     692 
     693          if(!found_id) 
     694          { 
     695            found_all = false; 
     696            break; 
     697          } 
     698        } 
     699 
     700        if(found_all) ancestors[ancestors.length] = prnt; 
     701      } 
     702      if(prnt.tagName.toLowerCase() == 'body')    break; 
     703      if(prnt.tagName.toLowerCase() == 'table'  ) break; 
     704    } 
     705    prnt = prnt.parentNode; 
     706  } 
     707 
     708  return ancestors; 
     709}; 
     710 
     711 
     712Xinha.ripStylesFromCSSFile = function(URL) 
     713{ 
     714  var css = Xinha._geturlcontent(URL); 
     715  return Xinha.ripStylesFromCSSString(css); 
     716}; 
     717 
     718Xinha.ripStylesFromCSSString = function(css) 
    454719{ 
    455720  // We are only interested in the selectors, the rules are not important 
     
    481746{ 
    482747  this.editor = editor; 
    483   editor._stylist = null; // This needs to be changes to be Stylist::_stylist sometime 
    484   editor._stylist = editor.addPanel('right'); 
    485   HTMLArea.addClass(editor._stylist, 'stylist'); 
    486  
     748  
    487749  var stylist = this; 
    488   editor.notifyOn('modechange', 
    489                   function(e,args) 
    490                   { 
    491                     switch(args.mode) 
    492                     { 
    493                       case 'text': 
    494                       { 
    495                         editor.hidePanel(editor._stylist); 
    496                         break; 
    497                       } 
    498                       case 'wysiwyg': 
    499                       { 
    500                         editor.showPanel(editor._stylist); 
    501                         break; 
    502                       } 
    503                     } 
    504                   } 
    505                   ); 
     750 
    506751} 
    507752 
     
    521766{ 
    522767  var editor = this.editor; 
    523   if(typeof editor.config.css_style == 'undefined' || HTMLArea.objectProperties(editor.config.css_style).length == 0) 
    524   { 
    525     editor.removePanel(editor._stylist); 
    526     editor._stylist = null; 
    527   } 
    528 }; 
     768  var stylist = this; 
     769  if(typeof editor.config.css_style != 'undefined' && Xinha.objectProperties(editor.config.css_style).length != 0) 
     770  { 
     771    editor._stylist = null; // This needs to be changes to be Stylist::_stylist sometime 
     772    editor._stylist = editor.addPanel('right'); 
     773    Xinha.addClass(editor._stylist, 'stylist'); 
     774 
     775    this.caption = document.createElement("h1"); 
     776    this.caption.innerHTML = Xinha._lc('Styles', 'Stylist'); 
     777    editor._stylist.appendChild(this.caption); 
     778    this.main = document.createElement("div"); 
     779    this.main.style.overflow = "auto"; 
     780    this.main.style.height = this.editor._framework.ed_cell.offsetHeight - this.caption.offsetHeight + 'px'; 
     781 
     782    editor._stylist.appendChild(this.main); 
     783 
     784    Xinha.freeLater(this,"caption"); 
     785    Xinha.freeLater(this,"main"); 
     786 
     787    editor.notifyOn('modechange', 
     788      function(e,args) 
     789      { 
     790        switch(args.mode) 
     791        { 
     792          case 'text': 
     793          { 
     794            editor.hidePanel(editor._stylist); 
     795            break; 
     796          } 
     797          case 'wysiwyg': 
     798          { 
     799            editor.showPanel(editor._stylist); 
     800            break; 
     801          } 
     802        } 
     803      } 
     804    ); 
     805    editor.notifyOn('panel_change', 
     806      function(e,args) 
     807      { 
     808        switch (args.action) 
     809        { 
     810          case 'show': 
     811          var newHeight = stylist.main.offsetHeight - args.panel.offsetHeight; 
     812          stylist.main.style.height = ((newHeight > 0) ?  stylist.main.offsetHeight - args.panel.offsetHeight : 0) + 'px'; 
     813          editor._stylist.style.height = stylist.caption.offsetHeight + "px"; 
     814          editor.sizeEditor(); 
     815          break; 
     816          case 'hide': 
     817          stylist.resize(); 
     818          break; 
     819        } 
     820      } 
     821    ); 
     822    editor.notifyOn('before_resize', 
     823    function() 
     824      { 
     825        editor._stylist.style.height = stylist.caption.offsetHeight + "px"; 
     826      } 
     827    ); 
     828    editor.notifyOn('resize', 
     829      function() 
     830      { 
     831        stylist.resize(); 
     832      } 
     833    ); 
     834  } 
     835 
     836}; 
     837Stylist.prototype.resize = function() 
     838{ 
     839  var editor = this.editor; 
     840  var panelContainer = editor._stylist.parentNode; 
     841 
     842  var newSize = panelContainer.offsetHeight; 
     843  for (var i=0; i < panelContainer.childNodes.length;++i) 
     844  { 
     845    if (panelContainer.childNodes[i]==editor._stylist || !panelContainer.childNodes[i].offsetHeight) 
     846    { 
     847      continue; 
     848    } 
     849    newSize -= panelContainer.childNodes[i].offsetHeight; 
     850  } 
     851  editor._stylist.style.height = newSize-5 + 'px'; 
     852  this.main.style.height = newSize - this.caption.offsetHeight -5 + 'px'; 
     853} 
    529854 
    530855Stylist.prototype.onUpdateToolbar = function() 
Note: See TracChangeset for help on using the changeset viewer.