artabro/wire/modules/Inputfield/InputfieldCKEditor/plugins/pwlink/plugin.js

278 lines
9.2 KiB
JavaScript
Raw Normal View History

2024-08-27 11:35:37 +02:00
(function() {
CKEDITOR.plugins.add('pwlink', {
requires: 'dialog,fakeobjects',
init: function(editor) {
var allowed = 'a[!href,target,name,title,rel]';
var required = 'a[href]';
var classOptions = ProcessWire.config.InputfieldCKEditor.pwlink.classOptions;
if(classOptions.length) allowed += "(" + classOptions + ")";
/*
if ( CKEDITOR.dialog.isTabEnabled( editor, 'link', 'advanced' ) )
allowed = allowed.replace( ']', ',accesskey,charset,dir,id,lang,name,rel,tabindex,title,type]{*}(*)' );
if ( CKEDITOR.dialog.isTabEnabled( editor, 'link', 'target' ) )
allowed = allowed.replace( ']', ',target,onclick]' );
*/
// Add the link and unlink buttons.
editor.addCommand('pwlink', {
allowedContent: allowed,
requiredContent: required,
exec: loadIframeLinkPicker
});
editor.addCommand('anchor', new CKEDITOR.dialogCommand( 'anchor', {
allowedContent: 'a[!name,id]',
requiredContent: 'a[name]'
}));
editor.addCommand('unlink', new CKEDITOR.unlinkCommand());
editor.addCommand('removeAnchor', new CKEDITOR.removeAnchorCommand());
editor.setKeystroke( CKEDITOR.CTRL + 76 /*L*/, 'pwlink' );
if ( editor.ui.addButton ) {
editor.ui.addButton( 'PWLink', {
label: editor.lang.link.toolbar,
command: 'pwlink',
toolbar: 'links,10',
hidpi: true,
icon: (CKEDITOR.env.hidpi ? this.path + 'images/hidpi/pwlink.png' : this.path + 'images/pwlink.png')
});
editor.ui.addButton( 'Unlink', {
label: editor.lang.link.unlink,
command: 'unlink',
toolbar: 'links,20'
});
editor.ui.addButton( 'Anchor', {
label: editor.lang.link.anchor.toolbar,
command: 'anchor',
toolbar: 'links,30'
});
}
// On double click we execute the command (= we open modal)
editor.on( 'doubleclick', function( evt ) {
var element = CKEDITOR.plugins.link.getSelectedLink( editor ) || evt.data.element;
if ( element.is( 'a' ) && !element.getAttribute('name') && !element.isReadOnly() ) {
var $a = jQuery(element.$);
if($a.children('img').length == 0) {
evt.cancel(); // prevent CKE's link dialog
editor.commands.pwlink.exec();
}
}
});
// prevent CKE's default "Edit Link" from showing in context menu
editor.on('instanceReady', function(ck) {
ck.editor.removeMenuItem('link');
});
// add context menu item
if (editor.contextMenu) {
editor.addMenuItem('pwlinkitem', {
label: ProcessWire.config.InputfieldCKEditor.pwlink.edit,
command: 'pwlink',
group: 'link',
icon: (CKEDITOR.env.hidpi ? this.path + 'images/hidpi/pwlink.png' : this.path + 'images/pwlink.png')
});
editor.contextMenu.addListener(function(element) {
if ( !element || element.isReadOnly() ) return null;
var anchor = CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, element );
var menu = {};
if ( !anchor && !( anchor = CKEDITOR.plugins.link.getSelectedLink( editor ) ) ) return null;
if ( anchor.getAttribute( 'href' ) && anchor.getChildCount() ) menu = { pwlinkitem: CKEDITOR.TRISTATE_OFF };
return menu;
});
}
}
}); // ckeditor.plugins.add
function loadIframeLinkPicker(editor) {
var $in = jQuery("#Inputfield_id");
var pageID;
if($in.length) {
//if($in.hasClass('PageFrontEdit')) {
// var pageID = jQuery("#" + editor.name).closest('.pw-edit').attr('data-page');
//} else {
pageID = $in.val();
//}
} else {
pageID = jQuery("#" + editor.name).closest('.Inputfield').attr('data-pid');
}
// language support
var $textarea = jQuery('#' + editor.name); // get textarea of this instance
var selection = editor.getSelection(true);
var node = selection.getStartElement();
var nodeName = node.getName(); // will typically be 'a', 'img' or 'p'
var selectionText = selection.getSelectedText();
var selectionHtml = editor.getSelectedHtml(true); // true=return string
var $existingLink = null;
var anchors = CKEDITOR.plugins.link.getEditorAnchors(editor);
var inlineNodeNames = '/em/strong/i/b/u/s/span/small/abbr/cite/figcaption/';
if(nodeName != 'a' && nodeName != 'img') {
var parentNodes = node.getParents();
for(var n = 0; n < parentNodes.length; n++) {
var parentNode = parentNodes[n];
var parentNodeName = parentNode.getName();
if(parentNodeName === 'a') {
// if there is a parent <a> element then expand selection to include all of it
// this prevents double click on the <em> part of <a href='./'>foo <em>bar</em> baz</a> from
// just including the 'bar' as the link text
node = parentNode;
break;
} else if(inlineNodeNames.indexOf('/' + parentNodeName + '/') > -1 && node.getText() === selectionText) {
// include certain wrapping inline elements for formatting in the selection text
node = parentNode;
selection.selectElement(node);
}
}
}
nodeName = node.getName(); // in case it changed above
if(nodeName == 'a') {
// existing link
$existingLink = jQuery(node.$);
selectionText = node.getText();
selectionHtml = node.getHtml();
selection.selectElement(node);
} else if(nodeName == 'td' || nodeName == 'th' || nodeName == 'tr') {
var firstChar = selectionText.substring(0,1);
if(firstChar == "\n" || firstChar == "\r") {
ProcessWire.alert('Your selection includes part of the table. Please try selecting the text again.');
return;
}
} else if(nodeName == 'img') {
// linked image
var $img = jQuery(node.$);
$existingLink = $img.parent('a');
selectionText = node.$.outerHTML;
selectionHtml = selectionText;
} else if (selectionText.length < 1) {
// If not on top of link and there is no text selected - just return (don't load iframe at all)
return;
} else {
// new link
}
// build the modal URL
var modalUrl = ProcessWire.config.urls.admin + 'page/link/?id=' + pageID + '&modal=1';
var $langWrapper = $textarea.closest('.LanguageSupport');
if($langWrapper.length) {
// multi-language field
modalUrl += "&lang=" + $langWrapper.data("language");
} else {
// multi-language field in Table
$langWrapper = $textarea.parents('.InputfieldTable_langTabs').find('li.ui-state-active a')
if($langWrapper.length && typeof $langWrapper.data('lang') != "undefined") {
modalUrl += "&lang=" + $langWrapper.data('lang');
} else if(jQuery('#pw-edit-lang').length) {
modalUrl += "&lang=" + jQuery('#pw-edit-lang').val(); // front-end editor
}
}
if($existingLink != null) {
var attrs = ['href', 'title', 'class', 'rel', 'target'];
for(var n = 0; n < attrs.length; n++) {
var val = $existingLink.attr(attrs[n]);
if(val && val.length) modalUrl += "&" + attrs[n] + "=" + encodeURIComponent(val);
}
}
// add any anchors to the modal URL
if(anchors.length > 0) {
for(var n = 0; n < anchors.length; n++) {
modalUrl += '&anchors[]=' + encodeURIComponent(anchors[n].id);
}
}
// set link text
var linkText = ($existingLink && $existingLink.text().length) ? $existingLink.text() : selectionText;
if(nodeName !== 'img' && linkText.length) {
modalUrl += '&text=' + encodeURIComponent(linkText);
}
// labels
var insertLinkLabel = ProcessWire.config.InputfieldCKEditor.pwlink.label;
var cancelLabel = ProcessWire.config.InputfieldCKEditor.pwlink.cancel;
var $iframe; // set after modalSettings down
// action when insert link button is clicked
function clickInsert() {
var $i = $iframe.contents();
var $a = jQuery(jQuery("#link_markup", $i).text());
if($a.attr('href') && $a.attr('href').length) {
if($a.text() === selectionText || !$a.text().length) {
// if input text has not changed from original, then use the original HTML rather than the text
$a.html(selectionHtml);
}
var html = jQuery("<div />").append($a).html();
var el = CKEDITOR.dom.element.createFromHtml(html);
editor.insertElement(el); // was: editor.insertHtml(html);
}
$iframe.dialog("close");
}
// settings for modal window
var modalSettings = {
title: "<i class='fa fa-link'></i> " + insertLinkLabel,
open: function() {
if(jQuery(".cke_maximized").length > 0) {
// the following is required when CKE is maximized to make sure dialog is on top of it
jQuery('.ui-dialog').css('z-index', 9999);
jQuery('.ui-widget-overlay').css('z-index', 9998);
}
},
buttons: [ {
'class': "pw_link_submit_insert",
'html': "<i class='fa fa-link'></i> " + insertLinkLabel,
'click': clickInsert
}, {
'html': "<i class='fa fa-times-circle'></i> " + cancelLabel,
'click': function() { $iframe.dialog("close"); },
'class': 'ui-priority-secondary'
}
]
};
// create modal window
var $iframe = pwModalWindow(modalUrl, modalSettings, 'medium');
// modal window load event
$iframe.on('load', function() {
var $i = $iframe.contents();
$i.find("#ProcessPageEditLinkForm").data('iframe', $iframe);
// capture enter key in main URL text input
jQuery("#link_page_url_input", $i).keydown(function(event) {
var $this = jQuery(this);
var val = $this.val().trim();
if (event.keyCode == 13) {
event.preventDefault();
if(val.length > 0) clickInsert();
return false;
}
});
}); // load
} // function loadIframeLinkPicker(editor) {
})();