2018-11-02 01:41:57 +01:00
|
|
|
/* global tinymce, editorIdentifier, ss */
|
2017-05-25 07:29:32 +02:00
|
|
|
import i18n from 'i18n';
|
|
|
|
import TinyMCEActionRegistrar from 'lib/TinyMCEActionRegistrar';
|
|
|
|
import React from 'react';
|
|
|
|
import ReactDOM from 'react-dom';
|
|
|
|
import { ApolloProvider } from 'react-apollo';
|
2018-05-21 10:52:48 +02:00
|
|
|
import { Provider } from 'react-redux';
|
2017-05-25 07:29:32 +02:00
|
|
|
import jQuery from 'jquery';
|
|
|
|
import ShortcodeSerialiser from 'lib/ShortcodeSerialiser';
|
|
|
|
import { createInsertLinkModal } from 'containers/InsertLinkModal/InsertLinkModal';
|
|
|
|
import { provideInjector } from 'lib/Injector';
|
|
|
|
|
2017-07-14 04:59:07 +02:00
|
|
|
const commandName = 'sslinkinternal';
|
|
|
|
|
2017-05-25 07:29:32 +02:00
|
|
|
// Link to external url
|
2017-07-14 04:59:07 +02:00
|
|
|
TinyMCEActionRegistrar
|
2018-11-02 01:41:57 +01:00
|
|
|
.addAction(
|
|
|
|
'sslink',
|
|
|
|
{
|
|
|
|
text: i18n._t('CMS.LINKLABEL_PAGE', 'Page on this site'),
|
|
|
|
onclick: (activeEditor) => activeEditor.execCommand(commandName),
|
|
|
|
priority: 53,
|
|
|
|
},
|
|
|
|
editorIdentifier,
|
|
|
|
)
|
2017-09-05 04:38:38 +02:00
|
|
|
.addCommandWithUrlTest(commandName, /^\[sitetree_link.+]$/);
|
2017-05-25 07:29:32 +02:00
|
|
|
|
|
|
|
const plugin = {
|
|
|
|
init(editor) {
|
2017-07-14 04:59:07 +02:00
|
|
|
editor.addCommand(commandName, () => {
|
2017-05-25 07:29:32 +02:00
|
|
|
const field = jQuery(`#${editor.id}`).entwine('ss');
|
|
|
|
|
|
|
|
field.openLinkInternalDialog();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const modalId = 'insert-link__dialog-wrapper--internal';
|
|
|
|
const sectionConfigKey = 'SilverStripe\\CMS\\Controllers\\CMSPageEditController';
|
|
|
|
const formName = 'editorInternalLink';
|
|
|
|
const InsertLinkInternalModal = provideInjector(createInsertLinkModal(sectionConfigKey, formName));
|
|
|
|
|
|
|
|
jQuery.entwine('ss', ($) => {
|
|
|
|
$('textarea.htmleditor').entwine({
|
|
|
|
openLinkInternalDialog() {
|
|
|
|
let dialog = $(`#${modalId}`);
|
|
|
|
|
|
|
|
if (!dialog.length) {
|
|
|
|
dialog = $(`<div id="${modalId}" />`);
|
|
|
|
$('body').append(dialog);
|
|
|
|
}
|
|
|
|
dialog.addClass('insert-link__dialog-wrapper');
|
|
|
|
|
|
|
|
dialog.setElement(this);
|
|
|
|
dialog.open();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Assumes that $('.insert-link__dialog-wrapper').entwine({}); is defined for shared functions
|
|
|
|
*/
|
|
|
|
$(`#${modalId}`).entwine({
|
2018-02-28 02:03:01 +01:00
|
|
|
renderModal(isOpen) {
|
2017-05-25 07:29:32 +02:00
|
|
|
const store = ss.store;
|
|
|
|
const client = ss.apolloClient;
|
|
|
|
const handleHide = () => this.close();
|
|
|
|
const handleInsert = (...args) => this.handleInsert(...args);
|
|
|
|
const attrs = this.getOriginalAttributes();
|
2017-10-25 00:40:35 +02:00
|
|
|
const requireLinkText = this.getRequireLinkText();
|
2017-05-25 07:29:32 +02:00
|
|
|
|
|
|
|
// create/update the react component
|
|
|
|
ReactDOM.render(
|
2018-05-21 10:52:48 +02:00
|
|
|
<ApolloProvider client={client}>
|
|
|
|
<Provider store={store}>
|
|
|
|
<InsertLinkInternalModal
|
|
|
|
isOpen={isOpen}
|
|
|
|
onInsert={handleInsert}
|
|
|
|
onClosed={handleHide}
|
|
|
|
title={i18n._t('CMS.LINK_PAGE', 'Link to a page')}
|
|
|
|
bodyClassName="modal__dialog"
|
|
|
|
className="insert-link__dialog-wrapper--internal"
|
|
|
|
fileAttributes={attrs}
|
|
|
|
identifier="Admin.InsertLinkInternalModal"
|
|
|
|
requireLinkText={requireLinkText}
|
|
|
|
/>
|
|
|
|
</Provider>
|
2017-05-25 07:29:32 +02:00
|
|
|
</ApolloProvider>,
|
|
|
|
this[0]
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
2017-10-25 00:40:35 +02:00
|
|
|
/**
|
|
|
|
* Determine whether to show the link text field
|
|
|
|
*
|
|
|
|
* @return {Boolean}
|
|
|
|
*/
|
|
|
|
getRequireLinkText() {
|
|
|
|
const selection = this.getElement().getEditor().getInstance().selection;
|
|
|
|
const selectionContent = selection.getContent() || '';
|
|
|
|
const tagName = selection.getNode().tagName;
|
|
|
|
const requireLinkText = tagName !== 'A' && selectionContent.trim() === '';
|
|
|
|
|
|
|
|
return requireLinkText;
|
|
|
|
},
|
|
|
|
|
2017-05-25 07:29:32 +02:00
|
|
|
/**
|
|
|
|
* @param {Object} data - Posted data
|
|
|
|
* @return {Object}
|
|
|
|
*/
|
|
|
|
buildAttributes(data) {
|
|
|
|
const shortcode = ShortcodeSerialiser.serialise({
|
|
|
|
name: 'sitetree_link',
|
|
|
|
properties: { id: data.PageID },
|
|
|
|
}, true);
|
|
|
|
|
|
|
|
// Add anchor
|
|
|
|
const anchor = data.Anchor && data.Anchor.length ? `#${data.Anchor}` : '';
|
|
|
|
const href = `${shortcode}${anchor}`;
|
|
|
|
|
|
|
|
return {
|
|
|
|
href,
|
|
|
|
target: data.TargetBlank ? '_blank' : '',
|
|
|
|
title: data.Description,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
getOriginalAttributes() {
|
|
|
|
const editor = this.getElement().getEditor();
|
|
|
|
const node = $(editor.getSelectedNode());
|
|
|
|
|
|
|
|
// Get href
|
|
|
|
const hrefParts = (node.attr('href') || '').split('#');
|
|
|
|
if (!hrefParts[0]) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if page is safe
|
|
|
|
const shortcode = ShortcodeSerialiser.match('sitetree_link', false, hrefParts[0]);
|
|
|
|
if (!shortcode) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
PageID: shortcode.properties.id ? parseInt(shortcode.properties.id, 10) : 0,
|
|
|
|
Anchor: hrefParts[1] || '',
|
|
|
|
Description: node.attr('title'),
|
|
|
|
TargetBlank: !!node.attr('target'),
|
|
|
|
};
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Adds the plugin class to the list of available TinyMCE plugins
|
2017-07-14 04:59:07 +02:00
|
|
|
tinymce.PluginManager.add(commandName, (editor) => plugin.init(editor));
|
2017-05-25 07:29:32 +02:00
|
|
|
|
|
|
|
export default plugin;
|