artabro/wire/modules/Inputfield/InputfieldTinyMCE/plugins/pwlink.js
2024-08-27 11:35:37 +02:00

264 lines
No EOL
7.3 KiB
JavaScript

/**
* pwlink plugin for TinyMCE
*
* @param editor
*
*/
function pwTinyMCE_link(editor) {
var $ = jQuery;
var $iframe; // set after modalSettings
var selection = editor.selection;
var node = selection.getNode();
var nodeName = node.nodeName.toUpperCase(); // will typically be 'A', 'IMG' or 'P'
var selectionText = selection.getContent({ format: 'text' });
var selectionHtml = selection.getContent();
var labels = {
insertLink: 'Insert',
cancel: 'Cancel'
};
if(typeof ProcessWire.config.InputfieldTinyMCE.labels !== 'undefined') {
labels = ProcessWire.config.InputfieldTinyMCE.labels; // translated text labels
}
function getPageId() {
var $in = jQuery("#Inputfield_id");
var pageId;
if($in.length) {
pageId = $in.val();
} else {
pageId = $("#" + editor.id).closest('.Inputfield').attr('data-pid');
}
return pageId;
}
// action when insert link button is clicked
function clickInsert($iframe) {
var $i = $iframe.contents();
var $a = $($('#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 = $('<div />').append($a).html();
selection.setContent(html);
}
$iframe.dialog('close');
}
function getAnchorIds() {
var $content = $(editor.getContent());
var anchors = [];
$content.find('a').each(function() {
var $a = $(this);
var id = $a.attr('id');
if(id) anchors.push(id);
});
return anchors;
}
function buildModalUrl($existingLink) {
var $textarea = jQuery('#' + editor.id); // get textarea of this instance
var $langWrapper = $textarea.closest('.LanguageSupport');
var modalUrl = ProcessWire.config.urls.admin + 'page/link/?modal=1&id=' + getPageId();
var n;
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=' + $('#pw-edit-lang').val(); // front-end editor
}
}
if($existingLink != null) {
var attrs = ['href', 'title', 'class', 'rel', 'target'];
for(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
var anchors = getAnchorIds();
if(anchors.length > 0) {
for(n = 0; n < anchors.length; n++) {
modalUrl += '&anchors[]=' + encodeURIComponent(anchors[n]);
}
}
// set link text
var linkText = ($existingLink && $existingLink.text().length) ? $existingLink.text() : selectionText;
if(nodeName !== 'IMG' && linkText.length) {
modalUrl += '&text=' + encodeURIComponent(linkText);
}
return modalUrl;
}
function buildModalSettings() {
return {
title: "<i class='fa fa-link'></i> " + labels.insertLink,
open: function() {
/*
if($(".cke_maximized").length > 0) {
// the following is required when CKE is maximized to make sure dialog is on top of it
$('.ui-dialog').css('z-index', 9999);
$('.ui-widget-overlay').css('z-index', 9998);
}
*/
},
buttons: [{
'class': "pw_link_submit_insert",
'html': "<i class='fa fa-link'></i> " + labels.insertLink,
'click': function() {
clickInsert($iframe);
}
}, {
'html': "<i class='fa fa-times-circle'></i> " + labels.cancel,
'click': function() {
$iframe.dialog('close');
},
'class': 'ui-priority-secondary'
}]
};
}
function iframeLoad($iframe) {
var $i = $iframe.contents();
$i.find('#ProcessPageEditLinkForm').data('iframe', $iframe);
// capture enter key in main URL text input
$('#link_page_url_input', $i).on('keydown', function(event) {
var $this = $(this);
var val = $this.val();
val = typeof val == 'string' ? val.trim() : '';
if(event.keyCode == 13) {
event.preventDefault();
if(val.length > 0) clickInsert($iframe);
return false;
}
});
}
function init() {
var inlineNodeNames = '/em/strong/i/b/u/s/span/small/abbr/cite/figcaption/';
var $existingLink = null;
if(nodeName != 'A' && nodeName != 'IMG') {
var parentNode;
var parentNodeName;
do {
parentNode = node.parentNode;
if(!parentNode) break;
parentNodeName = parentNode.nodeName.toUpperCase();
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).text() === selectionText) {
// include certain wrapping inline elements for formatting in the selection text
node = parentNode;
selection.select(node);
} else {
node = parentNode;
}
} while(parentNode);
}
nodeName = node.nodeName.toUpperCase(); // in case it changed above
if(nodeName === 'A') {
// existing link
$existingLink = $(node);
selectionText = $existingLink.text();
selectionHtml = $existingLink.html();
selection.select(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 = $(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
}
// settings for modal window
var modalUrl = buildModalUrl($existingLink);
var modalSettings = buildModalSettings();
// create modal window
$iframe = pwModalWindow(modalUrl, modalSettings, 'medium');
// modal window load event
$iframe.on('load', function() { iframeLoad($iframe) });
}
init();
}
/**
* Add pwimage to TinyMCE plugin manager
*
*/
tinymce.PluginManager.add('pwlink', (editor, url) => {
editor.ui.registry.addButton('pwlink', {
text: '',
icon: 'link',
onAction: function() {
pwTinyMCE_link(editor);
}
});
// Adds a menu item, which can then be included in any menu via the menu/menubar configuration
editor.ui.registry.addMenuItem('pwlink', {
text: 'Link',
icon: 'link',
onAction: function() {
pwTinyMCE_link(editor);
}
});
// context menu
editor.ui.registry.addContextMenu('pwlink', {
update: (element) => !element.href ? '' : 'pwlink'
});
// double click on link loads link editor
editor.on('dblclick', function(e) {
if(e.target.nodeName === 'A') {
pwTinyMCE_link(editor);
}
});
// Return metadata for the plugin
return {
getMetadata: () => ({ name: 'Link' })
};
});