suneditor
Version:
Pure JavaScript based WYSIWYG web editor
287 lines (242 loc) • 11.5 kB
JavaScript
/*
* wysiwyg web editor
*
* suneditor.js
* Copyright 2017 JiHong Lee.
* MIT license.
*/
'use strict';
import dialog from '../modules/dialog';
export default {
name: 'link',
display: 'dialog',
add: function (core) {
core.addModule([dialog]);
const context = core.context;
context.link = {
focusElement: null,
linkNewWindowCheck: null,
linkAnchorText: null,
_linkAnchor: null
};
/** link dialog */
let link_dialog = this.setDialog.call(core);
context.link.modal = link_dialog;
context.link.focusElement = link_dialog.querySelector('._se_link_url');
context.link.linkAnchorText = link_dialog.querySelector('._se_link_text');
context.link.linkNewWindowCheck = link_dialog.querySelector('._se_link_check');
/** link controller */
let link_controller = this.setController_LinkButton.call(core);
context.link.linkController = link_controller;
context.link._linkAnchor = null;
link_controller.addEventListener('mousedown', function (e) { e.stopPropagation(); }, false);
/** add event listeners */
link_dialog.querySelector('.se-btn-primary').addEventListener('click', this.submit.bind(core));
link_controller.addEventListener('click', this.onClick_linkController.bind(core));
/** append html */
context.dialog.modal.appendChild(link_dialog);
/** append controller */
context.element.relative.appendChild(link_controller);
/** empty memory */
link_dialog = null, link_controller = null;
},
/** dialog */
setDialog: function () {
const lang = this.lang;
const dialog = this.util.createElement('DIV');
dialog.className = 'se-dialog-content';
dialog.style.display = 'none';
dialog.innerHTML = '' +
'<form class="editor_link">' +
'<div class="se-dialog-header">' +
'<button type="button" data-command="close" class="se-btn se-dialog-close" aria-label="Close" title="' + lang.dialogBox.close + '">' +
this.icons.cancel +
'</button>' +
'<span class="se-modal-title">' + lang.dialogBox.linkBox.title + '</span>' +
'</div>' +
'<div class="se-dialog-body">' +
'<div class="se-dialog-form">' +
'<label>' + lang.dialogBox.linkBox.url + '</label>' +
'<input class="se-input-form _se_link_url" type="text" />' +
'</div>' +
'<div class="se-dialog-form">' +
'<label>' + lang.dialogBox.linkBox.text + '</label><input class="se-input-form _se_link_text" type="text" />' +
'</div>' +
'<div class="se-dialog-form-footer">' +
'<label><input type="checkbox" class="se-dialog-btn-check _se_link_check" /> ' + lang.dialogBox.linkBox.newWindowCheck + '</label>' +
'</div>' +
'</div>' +
'<div class="se-dialog-footer">' +
'<button type="submit" class="se-btn-primary" title="' + lang.dialogBox.submitButton + '"><span>' + lang.dialogBox.submitButton + '</span></button>' +
'</div>' +
'</form>';
return dialog;
},
/** modify controller button */
setController_LinkButton: function () {
const lang = this.lang;
const icons = this.icons;
const link_btn = this.util.createElement('DIV');
link_btn.className = 'se-controller se-controller-link';
link_btn.innerHTML = '' +
'<div class="se-arrow se-arrow-up"></div>' +
'<div class="link-content"><span><a target="_blank" href=""></a> </span>' +
'<div class="se-btn-group">' +
'<button type="button" data-command="update" tabindex="-1" class="se-btn se-tooltip">' +
icons.edit +
'<span class="se-tooltip-inner"><span class="se-tooltip-text">' + lang.controller.edit + '</span></span>' +
'</button>' +
'<button type="button" data-command="unlink" tabindex="-1" class="se-btn se-tooltip">' +
icons.unlink +
'<span class="se-tooltip-inner"><span class="se-tooltip-text">' + lang.controller.unlink + '</span></span>' +
'</button>' +
'<button type="button" data-command="delete" tabindex="-1" class="se-btn se-tooltip">' +
icons.delete +
'<span class="se-tooltip-inner"><span class="se-tooltip-text">' + lang.controller.remove + '</span></span>' +
'</button>' +
'</div>' +
'</div>';
return link_btn;
},
/**
* @overriding dialog
*/
open: function () {
this.plugins.dialog.open.call(this, 'link', 'link' === this.currentControllerName);
},
submit: function (e) {
this.showLoading();
e.preventDefault();
e.stopPropagation();
const submitAction = function () {
if (this.context.link.focusElement.value.trim().length === 0) return false;
const contextLink = this.context.link;
const url = contextLink.focusElement.value;
const anchor = contextLink.linkAnchorText;
const anchorText = anchor.value.length === 0 ? url : anchor.value;
if (!this.context.dialog.updateModal) {
const oA = this.util.createElement('A');
oA.href = url;
oA.textContent = anchorText;
oA.target = (contextLink.linkNewWindowCheck.checked ? '_blank' : '');
const selectedFormats = this.getSelectedElements();
if (selectedFormats.length > 1) {
const oFormat = this.util.createElement(selectedFormats[0].nodeName);
oFormat.appendChild(oA);
this.insertNode(oFormat);
} else {
this.insertNode(oA);
}
this.setRange(oA.childNodes[0], 0, oA.childNodes[0], oA.textContent.length);
} else {
contextLink._linkAnchor.href = url;
contextLink._linkAnchor.textContent = anchorText;
contextLink._linkAnchor.target = (contextLink.linkNewWindowCheck.checked ? '_blank' : '');
// set range
const textNode = contextLink._linkAnchor.childNodes[0];
this.setRange(textNode, 0, textNode, textNode.textContent.length);
}
// history stack
this.history.push(false);
contextLink.focusElement.value = '';
contextLink.linkAnchorText.value = '';
}.bind(this);
try {
submitAction();
} finally {
this.plugins.dialog.close.call(this);
this.closeLoading();
this.focus();
}
return false;
},
/**
* @overriding core
*/
active: function (element) {
if (!element) {
if (this.controllerArray.indexOf(this.context.link.linkController) > -1) {
this.controllersOff();
}
} else if (this.util.isAnchor(element) && element.getAttribute('data-image-link') === null) {
if (this.controllerArray.indexOf(this.context.link.linkController) < 0) {
this.plugins.link.call_controller.call(this, element);
}
return true;
}
return false;
},
/**
* @overriding dialog
*/
on: function (update) {
if (!update) {
this.plugins.link.init.call(this);
this.context.link.linkAnchorText.value = this.getSelection().toString();
} else if (this.context.link._linkAnchor) {
this.context.dialog.updateModal = true;
this.context.link.focusElement.value = this.context.link._linkAnchor.href;
this.context.link.linkAnchorText.value = this.context.link._linkAnchor.textContent;
this.context.link.linkNewWindowCheck.checked = (/_blank/i.test(this.context.link._linkAnchor.target) ? true : false);
}
},
call_controller: function (selectionATag) {
this.editLink = this.context.link._linkAnchor = selectionATag;
const linkBtn = this.context.link.linkController;
const link = linkBtn.querySelector('a');
link.href = selectionATag.href;
link.title = selectionATag.textContent;
link.textContent = selectionATag.textContent;
const offset = this.util.getOffset(selectionATag, this.context.element.wysiwygFrame);
linkBtn.style.top = (offset.top + selectionATag.offsetHeight + 10) + 'px';
linkBtn.style.left = (offset.left - this.context.element.wysiwygFrame.scrollLeft) + 'px';
linkBtn.style.display = 'block';
const overLeft = this.context.element.wysiwygFrame.offsetWidth - (linkBtn.offsetLeft + linkBtn.offsetWidth);
if (overLeft < 0) {
linkBtn.style.left = (linkBtn.offsetLeft + overLeft) + 'px';
linkBtn.firstElementChild.style.left = (20 - overLeft) + 'px';
} else {
linkBtn.firstElementChild.style.left = '20px';
}
this.controllersOn(linkBtn, selectionATag, 'link');
},
onClick_linkController: function (e) {
e.stopPropagation();
const command = e.target.getAttribute('data-command') || e.target.parentNode.getAttribute('data-command');
if (!command) return;
e.preventDefault();
if (/update/.test(command)) {
const contextLink = this.context.link;
contextLink.focusElement.value = contextLink._linkAnchor.href;
contextLink.linkAnchorText.value = contextLink._linkAnchor.textContent;
contextLink.linkNewWindowCheck.checked = (/_blank/i.test(contextLink._linkAnchor.target) ? true : false);
this.plugins.dialog.open.call(this, 'link', true);
}
else if (/unlink/.test(command)) {
const sc = this.util.getChildElement(this.context.link._linkAnchor, function (current) { return current.childNodes.length === 0 || current.nodeType === 3; }, false);
const ec = this.util.getChildElement(this.context.link._linkAnchor, function (current) { return current.childNodes.length === 0 || current.nodeType === 3; }, true);
this.setRange(sc, 0, ec, ec.textContent.length);
this.nodeChange(null, null, ['A'], false);
}
else {
/** delete */
this.util.removeItem(this.context.link._linkAnchor);
this.context.link._linkAnchor = null;
this.focus();
// history stack
this.history.push(false);
}
this.controllersOff();
},
/**
* @overriding dialog
*/
init: function () {
const contextLink = this.context.link;
contextLink.linkController.style.display = 'none';
contextLink._linkAnchor = null;
contextLink.focusElement.value = '';
contextLink.linkAnchorText.value = '';
contextLink.linkNewWindowCheck.checked = false;
}
};