forked from fanruan/fineui
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
9.0 KiB
289 lines
9.0 KiB
/** |
|
* 富文本编辑器 |
|
* |
|
* Created by GUY on 2017/9/15. |
|
* @class BI.NicEditor |
|
* @extends BI.Widget |
|
*/ |
|
!(function () { |
|
BI.NicEditor = BI.inherit(BI.Widget, { |
|
_defaultConfig: function () { |
|
return BI.extend(BI.NicEditor.superclass._defaultConfig.apply(this, arguments), { |
|
baseCls: "bi-nic-editor" |
|
}); |
|
}, |
|
_init: function () { |
|
BI.NicEditor.superclass._init.apply(this, arguments); |
|
var o = this.options; |
|
$(document).bind("mousedown." + this.getName(), BI.bind(this.selectCheck, this)); |
|
BI.createWidget({ |
|
type: "bi.vertical", |
|
element: this, |
|
items: [this.instance = this.addInstance()] |
|
}); |
|
}, |
|
|
|
addInstance: function () { |
|
var o = this.options; |
|
var conf = { |
|
ne: this, |
|
height: o.height, |
|
maxHeight: o.maxHeight ? o.maxHeight : null |
|
}; |
|
if (this.element[0].contentEditable || !!window.opera) { |
|
var newInstance = new nicEditorInstance(conf); |
|
} else { |
|
console.error("不支持此浏览器"); |
|
} |
|
if(o.readOnly) { |
|
newInstance.disable(); |
|
} |
|
return newInstance; |
|
}, |
|
|
|
nicCommand: function (cmd, args) { |
|
if (this.selectedInstance) { |
|
this.selectedInstance.nicCommand(cmd, args); |
|
} |
|
}, |
|
|
|
selectCheck: function (e) { |
|
var t = e.target; |
|
var found = false; |
|
do { |
|
if (t.nodeName !== "svg" && t.className && t.className.indexOf(prefix) != -1) { |
|
return; |
|
// return false; |
|
} |
|
} while (t = t.parentNode); |
|
this.fireEvent("blur", t); |
|
this.lastSelectedInstance = this.selectedInstance; |
|
this.selectedInstance = null; |
|
// return false; |
|
}, |
|
|
|
focus: function () { |
|
this.instance.focus(); |
|
}, |
|
|
|
setValue: function (v) { |
|
this.instance.setContent(v); |
|
}, |
|
|
|
getValue: function () { |
|
return this.instance.getContent(); |
|
}, |
|
|
|
destroyed: function () { |
|
$(document).unbind("mousedown." + this.getName()); |
|
} |
|
}); |
|
BI.NicEditor.EVENT_SELECTED = "selected"; |
|
BI.NicEditor.EVENT_BLUR = "blur"; |
|
BI.NicEditor.EVENT_FOCUS = "focus"; |
|
BI.NicEditor.EVENT_KEYDOWN = "keydown"; |
|
BI.shortcut("bi.nic_editor", BI.NicEditor); |
|
|
|
var prefix = "niceditor-"; |
|
|
|
var nicEditorInstance = BI.inherit(BI.Layout, { |
|
isSelected: false, |
|
_init: function () { |
|
nicEditorInstance.superclass._init.apply(this, arguments); |
|
var o = this.options; |
|
this.ne = this.options.ne; |
|
this.elm = BI.createWidget({ |
|
type: "bi.layout", |
|
width: o.width - 8, |
|
scrollable: false |
|
}); |
|
this.elm.element.css({ |
|
minHeight: BI.isNumber(o.height) ? (o.height - 8) + "px" : o.height, |
|
outline: "none" |
|
}).html(o.value); |
|
|
|
this.element.css("maxHeight", (o.maxHeight) ? o.maxHeight + "px" : null); |
|
|
|
this.e = BI.createWidget({ |
|
type: "bi.layout", |
|
invisible: true, |
|
tagName: "textarea" |
|
}); |
|
BI.createWidget({ |
|
type: "bi.default", |
|
element: this, |
|
scrolly: true, |
|
items: [this.elm, this.e] |
|
}); |
|
|
|
this.ne.on("blur", BI.bind(this.blur, this)); |
|
|
|
this.start(); |
|
this.blur(); |
|
}, |
|
|
|
start: function () { |
|
this.elm.element.attr("contentEditable", true); |
|
if (this.getContent() == "") { |
|
// this.setContent("<br />"); |
|
} |
|
this.instanceDoc = document.defaultView; |
|
this.elm.element.on("mousedown", BI.bind(this.selected, this)); |
|
this.elm.element.on("keyup", BI.bind(this.keyDown, this)); |
|
// this.elm.element.on("keydown", BI.bind(this.keyDown, this)); |
|
this.elm.element.on("focus", BI.bind(this.selected, this)); |
|
this.elm.element.on("blur", BI.bind(this.blur, this)); |
|
this.elm.element.on("keyup", BI.bind(this.selected, this)); |
|
this.ne.fireEvent("add"); |
|
}, |
|
|
|
disable: function () { |
|
this.elm.element.attr("contentEditable", false); |
|
}, |
|
|
|
getSel: function () { |
|
return (window.getSelection) ? window.getSelection() : document.selection; |
|
}, |
|
|
|
getRng: function () { |
|
var s = this.getSel(); |
|
if (!s || s.rangeCount === 0) { |
|
return; |
|
} |
|
return (s.rangeCount > 0) ? s.getRangeAt(0) : s.createRange(); |
|
}, |
|
|
|
selRng: function (rng, s) { |
|
if (window.getSelection) { |
|
s.removeAllRanges(); |
|
s.addRange(rng); |
|
} else { |
|
rng.select(); |
|
} |
|
}, |
|
|
|
selElm: function () { |
|
var r = this.getRng(); |
|
if (!r) { |
|
return; |
|
} |
|
if (r.startContainer) { |
|
var contain = r.startContainer; |
|
if (r.cloneContents().childNodes.length == 1) { |
|
for (var i = 0; i < contain.childNodes.length; i++) { |
|
var rng = contain.childNodes[i].ownerDocument.createRange(); |
|
rng.selectNode(contain.childNodes[i]); |
|
if (r.compareBoundaryPoints(Range.START_TO_START, rng) != 1 && |
|
r.compareBoundaryPoints(Range.END_TO_END, rng) != -1) { |
|
return contain.childNodes[i]; |
|
} |
|
} |
|
} |
|
return contain; |
|
} |
|
return (this.getSel().type == "Control") ? r.item(0) : r.parentElement(); |
|
|
|
}, |
|
|
|
saveRng: function () { |
|
this.savedRange = this.getRng(); |
|
this.savedSel = this.getSel(); |
|
}, |
|
|
|
setFocus: function (el) { |
|
try { |
|
el.focus(); |
|
} catch (e) { |
|
|
|
} |
|
if (!window.getSelection) { |
|
var rng; |
|
try { |
|
el.focus(); |
|
} catch (e) { |
|
|
|
} |
|
rng = document.selection.createRange(); |
|
rng.moveStart("character", -el.innerText.length); |
|
var text = rng.text; |
|
for (var i = 0; i < el.innerText.length; i++) { |
|
if (el.innerText.substring(0, i + 1) == text.substring(text.length - i - 1, text.length)) { |
|
result = i + 1; |
|
} |
|
} |
|
} else { |
|
var range = document.createRange(); |
|
range.selectNodeContents(el); |
|
range.collapse(false); |
|
var sel = window.getSelection(); |
|
sel.removeAllRanges(); |
|
sel.addRange(range); |
|
} |
|
}, |
|
|
|
restoreRng: function () { |
|
if (this.savedRange) { |
|
this.selRng(this.savedRange, this.savedSel); |
|
} |
|
}, |
|
|
|
keyDown: function (e, t) { |
|
this.ne.fireEvent("keydown", e); |
|
}, |
|
|
|
selected: function (e) { |
|
var t = e.target; |
|
if (!t && !(t = this.selElm())) { |
|
t = this.selElm(); |
|
} |
|
if (!e.ctrlKey) { |
|
var selInstance = this.ne.selectedInstance; |
|
if (selInstance != this) { |
|
if (selInstance) { |
|
this.ne.fireEvent("blur", e); |
|
} |
|
this.ne.selectedInstance = this; |
|
this.ne.fireEvent("focus", e); |
|
} |
|
this.ne.fireEvent("selected", e); |
|
this.isFocused = true; |
|
this.elm.element.addClass(prefix + "selected"); |
|
} |
|
// return false; |
|
}, |
|
|
|
focus: function () { |
|
this.setFocus(this.elm.element[0]); |
|
}, |
|
|
|
blur: function () { |
|
this.isFocused = false; |
|
this.elm.element.removeClass(prefix + "selected"); |
|
}, |
|
|
|
saveContent: function () { |
|
this.ne.fireEvent("save"); |
|
this.e.element.value(this.getContent()); |
|
}, |
|
|
|
getElm: function () { |
|
return this.elm; |
|
}, |
|
|
|
getContent: function () { |
|
this.content = this.getElm().element.html(); |
|
this.ne.fireEvent("get"); |
|
return this.content; |
|
}, |
|
|
|
setContent: function (e) { |
|
this.content = e; |
|
this.ne.fireEvent("set"); |
|
this.elm.element.html(this.content); |
|
}, |
|
|
|
nicCommand: function (cmd, args) { |
|
document.execCommand(cmd, false, args); |
|
} |
|
}); |
|
}());
|
|
|