/*
YUI 3.17.2 (build 9c3c78e)
Copyright 2014 Yahoo! Inc. All rights reserved.
Licensed under the BSD License.
http://yuilibrary.com/license/
*/
YUI.add('editor-para', function (Y, NAME) {
/**
* Plugin for Editor to paragraph auto wrapping and correction.
* @class Plugin.EditorPara
* @extends Plugin.EditorParaBase
* @constructor
* @module editor
* @submodule editor-para
*/
var EditorPara = function() {
EditorPara.superclass.constructor.apply(this, arguments);
}, HOST = 'host', NODE_CHANGE = 'nodeChange', PARENT_NODE = 'parentNode',
FIRST_P = '> p', P = 'p', BR = '
', FC = 'firstChild', LI = 'li';
Y.extend(EditorPara, Y.Plugin.EditorParaBase, {
/**
* Resolves the ROOT editor element.
* @method _getRoot
* @private
*/
_getRoot: function() {
return this.get(HOST).getInstance().EditorSelection.ROOT;
},
/**
* nodeChange handler to handle fixing an empty document.
* @private
* @method _onNodeChange
*/
_onNodeChange: function(e) {
var host = this.get(HOST), inst = host.getInstance(),
html, txt, par , d, sel, btag = inst.EditorSelection.DEFAULT_BLOCK_TAG,
inHTML, txt2, childs, aNode, node2, top, n, sib, para2, prev,
ps, br, item, p, imgs, t, LAST_CHILD = ':last-child', para, b, dir,
lc, lc2, found = false, root = this._getRoot(), start;
switch (e.changedType) {
case 'enter-up':
para = ((this._lastPara) ? this._lastPara : e.changedNode);
b = para.one('br.yui-cursor');
if (this._lastPara) {
delete this._lastPara;
}
if (b) {
if (b.previous() || b.next()) {
if (b.ancestor(P)) {
b.remove();
}
}
}
if (!para.test(btag)) {
para2 = para.ancestor(btag);
if (para2) {
para = para2;
para2 = null;
}
}
if (para.test(btag)) {
prev = para.previous();
if (prev) {
lc = prev.one(LAST_CHILD);
while (!found) {
if (lc) {
lc2 = lc.one(LAST_CHILD);
if (lc2) {
lc = lc2;
} else {
found = true;
}
} else {
found = true;
}
}
if (lc) {
host.copyStyles(lc, para);
}
}
}
break;
case 'enter':
if (Y.UA.webkit) {
//Webkit doesn't support shift+enter as a BR, this fixes that.
if (e.changedEvent.shiftKey) {
host.execCommand('insertbr');
e.changedEvent.preventDefault();
}
}
if (e.changedNode.test('li') && !Y.UA.ie) {
html = inst.EditorSelection.getText(e.changedNode);
if (html === '') {
par = e.changedNode.ancestor('ol,ul');
dir = par.getAttribute('dir');
if (dir !== '') {
dir = ' dir = "' + dir + '"';
}
par = e.changedNode.ancestor(inst.EditorSelection.BLOCKS);
d = inst.Node.create('
' + inst.EditorSelection.CURSOR + '
'); par.insert(d, 'after'); e.changedNode.remove(); e.changedEvent.halt(); sel = new inst.EditorSelection(); sel.selectNode(d, true, false); } } //TODO Move this to a GECKO MODULE - Can't for the moment, requires no change to metadata (YMAIL) if (Y.UA.gecko && host.get('defaultblock') !== 'p') { par = e.changedNode; if (!par.test(LI) && !par.ancestor(LI)) { if (!par.test(btag)) { par = par.ancestor(btag); } d = inst.Node.create('<' + btag + '>' + btag + '>'); par.insert(d, 'after'); sel = new inst.EditorSelection(); if (sel.anchorOffset) { inHTML = sel.anchorNode.get('textContent'); txt = inst.one(inst.config.doc.createTextNode(inHTML.substr(0, sel.anchorOffset))); txt2 = inst.one(inst.config.doc.createTextNode(inHTML.substr(sel.anchorOffset))); aNode = sel.anchorNode; aNode.setContent(''); //I node2 = aNode.cloneNode(); //I node2.append(txt2); //text top = false; sib = aNode; //I while (!top) { sib = sib.get(PARENT_NODE); //B if (sib && !sib.test(btag)) { n = sib.cloneNode(); n.set('innerHTML', ''); n.append(node2); //Get children.. childs = sib.get('childNodes'); start = false; /*jshint loopfunc: true */ childs.each(function(c) { if (start) { n.append(c); } if (c === aNode) { start = true; } }); aNode = sib; //Top sibling node2 = n; } else { top = true; } } txt2 = node2; sel.anchorNode.append(txt); if (txt2) { d.append(txt2); } } if (d.get(FC)) { d = d.get(FC); } d.prepend(inst.EditorSelection.CURSOR); sel.focusCursor(true, true); html = inst.EditorSelection.getText(d); if (html !== '') { inst.EditorSelection.cleanCursor(); } e.changedEvent.preventDefault(); } } break; case 'keyup': if (Y.UA.gecko) { if (root && root.getHTML().length < 20) { if (!root.one(FIRST_P)) { this._fixFirstPara(); } } } break; case 'backspace-up': case 'backspace-down': case 'delete-up': if (!Y.UA.ie) { ps = root.all(FIRST_P); item = root; if (ps.item(0)) { item = ps.item(0); } br = item.one('br'); if (br) { br.removeAttribute('id'); br.removeAttribute('class'); } txt = inst.EditorSelection.getText(item); txt = txt.replace(/ /g, '').replace(/\n/g, ''); imgs = item.all('img'); if (txt.length === 0 && !imgs.size()) { //God this is horrible.. if (!item.test(P)) { this._fixFirstPara(); } p = null; if (e.changedNode && e.changedNode.test(P)) { p = e.changedNode; } if (!p && host._lastPara && host._lastPara.inDoc()) { p = host._lastPara; } if (p && !p.test(P)) { p = p.ancestor(P); } if (p) { if (!p.previous() && p.get(PARENT_NODE) && p.get(PARENT_NODE).compareTo(root)) { e.changedEvent.frameEvent.halt(); e.preventDefault(); } } } if (Y.UA.webkit) { if (e.changedNode) { //All backspace calls in Webkit need a preventDefault to //stop history navigation #2531299 e.preventDefault(); item = e.changedNode; if (item.test('li') && (!item.previous() && !item.next())) { html = item.get('innerHTML').replace(BR, ''); if (html === '') { if (item.get(PARENT_NODE)) { item.get(PARENT_NODE).replace(inst.Node.create(BR)); e.changedEvent.frameEvent.halt(); inst.EditorSelection.filterBlocks(); } } } } } } if (Y.UA.gecko) { /* * This forced FF to redraw the content on backspace. * On some occasions FF will leave a cursor residue after content has been deleted. * Dropping in the empty textnode and then removing it causes FF to redraw and * remove the "ghost cursors" */ // d = e.changedNode; // t = inst.config.doc.createTextNode(' '); // d.appendChild(t); // d.removeChild(t); this._fixGeckoOnBackspace(inst); } break; } if (Y.UA.gecko) { if (e.changedNode && !e.changedNode.test(btag)) { p = e.changedNode.ancestor(btag); if (p) { this._lastPara = p; } } } }, //If we just backspaced into a P on FF, we have to put the cursor //before the BR that FF (usually) had injected when we used