[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/editor-para/ -> editor-para.js (source)

   1  /*
   2  YUI 3.17.2 (build 9c3c78e)
   3  Copyright 2014 Yahoo! Inc. All rights reserved.
   4  Licensed under the BSD License.
   5  http://yuilibrary.com/license/
   6  */
   7  
   8  YUI.add('editor-para', function (Y, NAME) {
   9  
  10  
  11      /**
  12       * Plugin for Editor to paragraph auto wrapping and correction.
  13       * @class Plugin.EditorPara
  14       * @extends Plugin.EditorParaBase
  15       * @constructor
  16       * @module editor
  17       * @submodule editor-para
  18       */
  19  
  20  
  21      var EditorPara = function() {
  22          EditorPara.superclass.constructor.apply(this, arguments);
  23      }, HOST = 'host', NODE_CHANGE = 'nodeChange', PARENT_NODE = 'parentNode',
  24      FIRST_P = '> p', P = 'p', BR = '<br>', FC = 'firstChild', LI = 'li';
  25  
  26  
  27      Y.extend(EditorPara, Y.Plugin.EditorParaBase, {
  28          /**
  29          * Resolves the ROOT editor element.
  30          * @method _getRoot
  31          * @private
  32          */
  33          _getRoot: function() {
  34              return this.get(HOST).getInstance().EditorSelection.ROOT;
  35          },
  36  
  37          /**
  38          * nodeChange handler to handle fixing an empty document.
  39          * @private
  40          * @method _onNodeChange
  41          */
  42          _onNodeChange: function(e) {
  43              var host = this.get(HOST), inst = host.getInstance(),
  44                  html, txt, par , d, sel, btag = inst.EditorSelection.DEFAULT_BLOCK_TAG,
  45                  inHTML, txt2, childs, aNode, node2, top, n, sib, para2, prev,
  46                  ps, br, item, p, imgs, t, LAST_CHILD = ':last-child', para, b, dir,
  47                  lc, lc2, found = false, root = this._getRoot(), start;
  48  
  49              switch (e.changedType) {
  50                  case 'enter-up':
  51                      para = ((this._lastPara) ? this._lastPara : e.changedNode);
  52                      b = para.one('br.yui-cursor');
  53  
  54                      if (this._lastPara) {
  55                          delete this._lastPara;
  56                      }
  57  
  58                      if (b) {
  59                          if (b.previous() || b.next()) {
  60                              if (b.ancestor(P)) {
  61                                  b.remove();
  62                              }
  63                          }
  64                      }
  65                      if (!para.test(btag)) {
  66                          para2 = para.ancestor(btag);
  67                          if (para2) {
  68                              para = para2;
  69                              para2 = null;
  70                          }
  71                      }
  72                      if (para.test(btag)) {
  73                          prev = para.previous();
  74                          if (prev) {
  75                              lc = prev.one(LAST_CHILD);
  76                              while (!found) {
  77                                  if (lc) {
  78                                      lc2 = lc.one(LAST_CHILD);
  79                                      if (lc2) {
  80                                          lc = lc2;
  81                                      } else {
  82                                          found = true;
  83                                      }
  84                                  } else {
  85                                      found = true;
  86                                  }
  87                              }
  88                              if (lc) {
  89                                  host.copyStyles(lc, para);
  90                              }
  91                          }
  92                      }
  93                      break;
  94                  case 'enter':
  95                      if (Y.UA.webkit) {
  96                          //Webkit doesn't support shift+enter as a BR, this fixes that.
  97                          if (e.changedEvent.shiftKey) {
  98                              host.execCommand('insertbr');
  99                              e.changedEvent.preventDefault();
 100                          }
 101                      }
 102                      if (e.changedNode.test('li') && !Y.UA.ie) {
 103                          html = inst.EditorSelection.getText(e.changedNode);
 104                          if (html === '') {
 105                              par = e.changedNode.ancestor('ol,ul');
 106                              dir = par.getAttribute('dir');
 107                              if (dir !== '') {
 108                                  dir = ' dir = "' + dir + '"';
 109                              }
 110                              par = e.changedNode.ancestor(inst.EditorSelection.BLOCKS);
 111                              d = inst.Node.create('<p' + dir + '>' + inst.EditorSelection.CURSOR + '</p>');
 112                              par.insert(d, 'after');
 113                              e.changedNode.remove();
 114                              e.changedEvent.halt();
 115  
 116                              sel = new inst.EditorSelection();
 117                              sel.selectNode(d, true, false);
 118                          }
 119                      }
 120                      //TODO Move this to a GECKO MODULE - Can't for the moment, requires no change to metadata (YMAIL)
 121                      if (Y.UA.gecko && host.get('defaultblock') !== 'p') {
 122                          par = e.changedNode;
 123  
 124                          if (!par.test(LI) && !par.ancestor(LI)) {
 125                              if (!par.test(btag)) {
 126                                  par = par.ancestor(btag);
 127                              }
 128                              d = inst.Node.create('<' + btag + '></' + btag + '>');
 129                              par.insert(d, 'after');
 130                              sel = new inst.EditorSelection();
 131                              if (sel.anchorOffset) {
 132                                  inHTML = sel.anchorNode.get('textContent');
 133  
 134                                  txt = inst.one(inst.config.doc.createTextNode(inHTML.substr(0, sel.anchorOffset)));
 135                                  txt2 = inst.one(inst.config.doc.createTextNode(inHTML.substr(sel.anchorOffset)));
 136  
 137                                  aNode = sel.anchorNode;
 138                                  aNode.setContent(''); //I
 139                                  node2 = aNode.cloneNode(); //I
 140                                  node2.append(txt2); //text
 141                                  top = false;
 142                                  sib = aNode; //I
 143                                  while (!top) {
 144                                      sib = sib.get(PARENT_NODE); //B
 145                                      if (sib && !sib.test(btag)) {
 146                                          n = sib.cloneNode();
 147                                          n.set('innerHTML', '');
 148                                          n.append(node2);
 149  
 150                                          //Get children..
 151                                          childs = sib.get('childNodes');
 152                                          start = false;
 153                                          /*jshint loopfunc: true */
 154                                          childs.each(function(c) {
 155                                              if (start) {
 156                                                  n.append(c);
 157                                              }
 158                                              if (c === aNode) {
 159                                                  start = true;
 160                                              }
 161                                          });
 162  
 163                                          aNode = sib; //Top sibling
 164                                          node2 = n;
 165                                      } else {
 166                                          top = true;
 167                                      }
 168                                  }
 169                                  txt2 = node2;
 170                                  sel.anchorNode.append(txt);
 171  
 172                                  if (txt2) {
 173                                      d.append(txt2);
 174                                  }
 175                              }
 176                              if (d.get(FC)) {
 177                                  d = d.get(FC);
 178                              }
 179                              d.prepend(inst.EditorSelection.CURSOR);
 180                              sel.focusCursor(true, true);
 181                              html = inst.EditorSelection.getText(d);
 182                              if (html !== '') {
 183                                  inst.EditorSelection.cleanCursor();
 184                              }
 185                              e.changedEvent.preventDefault();
 186                          }
 187                      }
 188                      break;
 189                  case 'keyup':
 190                      if (Y.UA.gecko) {
 191                          if (root && root.getHTML().length < 20) {
 192                              if (!root.one(FIRST_P)) {
 193                                  this._fixFirstPara();
 194                              }
 195                          }
 196                      }
 197                      break;
 198                  case 'backspace-up':
 199                  case 'backspace-down':
 200                  case 'delete-up':
 201                      if (!Y.UA.ie) {
 202                          ps = root.all(FIRST_P);
 203                          item = root;
 204                          if (ps.item(0)) {
 205                              item = ps.item(0);
 206                          }
 207                          br = item.one('br');
 208                          if (br) {
 209                              br.removeAttribute('id');
 210                              br.removeAttribute('class');
 211                          }
 212  
 213                          txt = inst.EditorSelection.getText(item);
 214                          txt = txt.replace(/ /g, '').replace(/\n/g, '');
 215                          imgs = item.all('img');
 216  
 217                          if (txt.length === 0 && !imgs.size()) {
 218                              //God this is horrible..
 219                              if (!item.test(P)) {
 220                                  this._fixFirstPara();
 221                              }
 222                              p = null;
 223                              if (e.changedNode && e.changedNode.test(P)) {
 224                                  p = e.changedNode;
 225                              }
 226                              if (!p && host._lastPara && host._lastPara.inDoc()) {
 227                                  p = host._lastPara;
 228                              }
 229                              if (p && !p.test(P)) {
 230                                  p = p.ancestor(P);
 231                              }
 232                              if (p) {
 233                                  if (!p.previous() && p.get(PARENT_NODE) && p.get(PARENT_NODE).compareTo(root)) {
 234                                      e.changedEvent.frameEvent.halt();
 235                                      e.preventDefault();
 236                                  }
 237                              }
 238                          }
 239                          if (Y.UA.webkit) {
 240                              if (e.changedNode) {
 241                                  //All backspace calls in Webkit need a preventDefault to
 242                                  //stop history navigation #2531299
 243                                  e.preventDefault();
 244                                  item = e.changedNode;
 245                                  if (item.test('li') && (!item.previous() && !item.next())) {
 246                                      html = item.get('innerHTML').replace(BR, '');
 247                                      if (html === '') {
 248                                          if (item.get(PARENT_NODE)) {
 249                                              item.get(PARENT_NODE).replace(inst.Node.create(BR));
 250                                              e.changedEvent.frameEvent.halt();
 251                                              inst.EditorSelection.filterBlocks();
 252                                          }
 253                                      }
 254                                  }
 255                              }
 256                          }
 257                      }
 258  
 259                      if (Y.UA.gecko) {
 260                         /*
 261                          * This forced FF to redraw the content on backspace.
 262                          * On some occasions FF will leave a cursor residue after content has been deleted.
 263                          * Dropping in the empty textnode and then removing it causes FF to redraw and
 264                          * remove the "ghost cursors"
 265                          */
 266                          // d = e.changedNode;
 267                          // t = inst.config.doc.createTextNode(' ');
 268                          // d.appendChild(t);
 269                          // d.removeChild(t);
 270  
 271                          this._fixGeckoOnBackspace(inst);
 272                      }
 273                      break;
 274              }
 275              if (Y.UA.gecko) {
 276                  if (e.changedNode && !e.changedNode.test(btag)) {
 277                      p = e.changedNode.ancestor(btag);
 278                      if (p) {
 279                          this._lastPara = p;
 280                      }
 281                  }
 282              }
 283  
 284          },
 285  
 286          //If we just backspaced into a P on FF, we have to put the cursor
 287          //before the BR that FF (usually) had injected when we used <ENTER> to
 288          //leave the P.
 289          _fixGeckoOnBackspace: function (inst) {
 290              var sel = new inst.EditorSelection(),
 291                  node,
 292                  childNodes;
 293  
 294              //not a cursor, not in a paragraph, or anchored at paragraph start.
 295              if (!sel.isCollapsed || sel.anchorNode.get('nodeName') !== 'P' ||
 296                  sel.anchorOffset === 0) {
 297                  return;
 298              }
 299  
 300              //cursor not on the injected final BR
 301              childNodes = sel.anchorNode.get('childNodes');
 302              node = sel.anchorNode.get('lastChild');
 303              if (sel.anchorOffset !== childNodes.size() || node.get('nodeName') !== 'BR') {
 304                  return;
 305              }
 306  
 307              //empty P (only contains BR)
 308              if (sel.anchorOffset === 1) {
 309                  sel.selectNode(sel.anchorNode, true);
 310                  return;
 311              }
 312  
 313              //We only expect injected BR behavior when last Node is text
 314              node = node.get('previousSibling');
 315              if (node.get('nodeType') !== Node.TEXT_NODE) {
 316                  return;
 317              }
 318  
 319              offset = node.get('length');
 320  
 321              // the cursor's position is strictly
 322              // at the offset when this bug occurs
 323              if (sel.getEditorOffset() === offset) {
 324                  sel.selectNode(node, true, offset);
 325              }
 326          },
 327  
 328          initializer: function() {
 329              var host = this.get(HOST);
 330              if (host.editorBR) {
 331                  Y.error('Can not plug EditorPara and EditorBR at the same time.');
 332                  return;
 333              }
 334  
 335              host.on(NODE_CHANGE, Y.bind(this._onNodeChange, this));
 336          }
 337      }, {
 338          /**
 339          * editorPara
 340          * @static
 341          * @property NAME
 342          */
 343          NAME: 'editorPara',
 344          /**
 345          * editorPara
 346          * @static
 347          * @property NS
 348          */
 349          NS: 'editorPara',
 350          ATTRS: {
 351              host: {
 352                  value: false
 353              }
 354          }
 355      });
 356  
 357      Y.namespace('Plugin');
 358  
 359      Y.Plugin.EditorPara = EditorPara;
 360  
 361  
 362  }, '3.17.2', {"requires": ["editor-para-base"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1