primo commit
This commit is contained in:
175
media/system/js/editors/editor-api.js
Normal file
175
media/system/js/editors/editor-api.js
Normal file
@ -0,0 +1,175 @@
|
||||
import JoomlaEditorDecorator from 'editor-decorator';
|
||||
export { default as JoomlaEditorDecorator } from 'editor-decorator';
|
||||
|
||||
/**
|
||||
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
* Editor API.
|
||||
*/
|
||||
const JoomlaEditor = {
|
||||
/**
|
||||
* Internal! The property should not be accessed directly.
|
||||
*
|
||||
* List of registered editors.
|
||||
*/
|
||||
instances: {},
|
||||
/**
|
||||
* Internal! The property should not be accessed directly.
|
||||
*
|
||||
* An active editor instance.
|
||||
*/
|
||||
active: null,
|
||||
/**
|
||||
* Register editor instance.
|
||||
*
|
||||
* @param {JoomlaEditorDecorator} editor The editor instance.
|
||||
*
|
||||
* @returns {JoomlaEditor}
|
||||
*/
|
||||
register(editor) {
|
||||
if (!(editor instanceof JoomlaEditorDecorator)) {
|
||||
throw new Error('Unexpected editor instance');
|
||||
}
|
||||
this.instances[editor.getId()] = editor;
|
||||
|
||||
// For backward compatibility
|
||||
Joomla.editors.instances[editor.getId()] = editor;
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Unregister editor instance.
|
||||
*
|
||||
* @param {JoomlaEditorDecorator|string} editor The editor instance or ID.
|
||||
*
|
||||
* @returns {JoomlaEditor}
|
||||
*/
|
||||
unregister(editor) {
|
||||
let id;
|
||||
if (editor instanceof JoomlaEditorDecorator) {
|
||||
id = editor.getId();
|
||||
} else if (typeof editor === 'string') {
|
||||
id = editor;
|
||||
} else {
|
||||
throw new Error('Unexpected editor instance or identifier');
|
||||
}
|
||||
if (this.active && this.active === this.instances[id]) {
|
||||
this.active = null;
|
||||
}
|
||||
delete this.instances[id];
|
||||
|
||||
// For backward compatibility
|
||||
delete Joomla.editors.instances[id];
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Return editor instance by ID.
|
||||
*
|
||||
* @param {String} id
|
||||
*
|
||||
* @returns {JoomlaEditorDecorator|boolean}
|
||||
*/
|
||||
get(id) {
|
||||
return this.instances[id] || false;
|
||||
},
|
||||
/**
|
||||
* Set currently active editor, the editor that in focus.
|
||||
*
|
||||
* @param {JoomlaEditorDecorator|string} editor The editor instance or ID.
|
||||
*
|
||||
* @returns {JoomlaEditor}
|
||||
*/
|
||||
setActive(editor) {
|
||||
if (editor instanceof JoomlaEditorDecorator) {
|
||||
this.active = editor;
|
||||
} else if (this.instances[editor]) {
|
||||
this.active = this.instances[editor];
|
||||
} else {
|
||||
throw new Error('The editor instance not found or it is incorrect');
|
||||
}
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Return active editor, if there exist eny.
|
||||
*
|
||||
* @returns {JoomlaEditorDecorator}
|
||||
*/
|
||||
getActive() {
|
||||
return this.active;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Editor Buttons API.
|
||||
*/
|
||||
const JoomlaEditorButton = {
|
||||
/**
|
||||
* Internal! The property should not be accessed directly.
|
||||
*
|
||||
* A collection of button actions.
|
||||
*/
|
||||
actions: {},
|
||||
/**
|
||||
* Register new button action, or override existing.
|
||||
*
|
||||
* @param {String} name Action name
|
||||
* @param {Function} handler Callback that will be executed.
|
||||
*
|
||||
* @returns {JoomlaEditorButton}
|
||||
*/
|
||||
registerAction(name, handler) {
|
||||
if (!name || !handler) {
|
||||
throw new Error('Missed values for Action registration');
|
||||
}
|
||||
if (!(handler instanceof Function)) {
|
||||
throw new Error(`Unexpected handler for action "${name}", expecting Function`);
|
||||
}
|
||||
this.actions[name] = handler;
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Get registered handler by action name.
|
||||
*
|
||||
* @param {String} name Action name
|
||||
*
|
||||
* @returns {Function|false}
|
||||
*/
|
||||
getActionHandler(name) {
|
||||
return this.actions[name] || false;
|
||||
},
|
||||
/**
|
||||
* Execute action.
|
||||
*
|
||||
* @param {String} name Action name
|
||||
* @param {Object} options An options object
|
||||
* @param {HTMLElement} button An optional element, that triggers the action
|
||||
*
|
||||
* @returns {*}
|
||||
*/
|
||||
runAction(name, options, button) {
|
||||
const handler = this.getActionHandler(name);
|
||||
let editor = JoomlaEditor.getActive();
|
||||
if (!handler) {
|
||||
throw new Error(`Handler for "${name}" action not found`);
|
||||
}
|
||||
// Try to find a legacy editor
|
||||
// @TODO: Remove this section in Joomla 6
|
||||
if (!editor && button) {
|
||||
const parent = button.closest('fieldset, div:not(.editor-xtd-buttons)');
|
||||
const textarea = parent ? parent.querySelector('textarea[id]') : false;
|
||||
editor = textarea && Joomla.editors.instances[textarea.id] ? Joomla.editors.instances[textarea.id] : false;
|
||||
if (editor) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Legacy editors is deprecated. Set active editor instance with JoomlaEditor.setActive().');
|
||||
}
|
||||
}
|
||||
if (!editor) {
|
||||
throw new Error('An active editor are not available');
|
||||
}
|
||||
return handler(editor, options);
|
||||
}
|
||||
};
|
||||
|
||||
export { JoomlaEditor, JoomlaEditorButton };
|
||||
4
media/system/js/editors/editor-api.min.js
vendored
Normal file
4
media/system/js/editors/editor-api.min.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import r from"editor-decorator";export{default as JoomlaEditorDecorator}from"editor-decorator";/**
|
||||
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/const c={instances:{},active:null,register(t){if(!(t instanceof r))throw new Error("Unexpected editor instance");return this.instances[t.getId()]=t,Joomla.editors.instances[t.getId()]=t,this},unregister(t){let e;if(t instanceof r)e=t.getId();else if(typeof t=="string")e=t;else throw new Error("Unexpected editor instance or identifier");return this.active&&this.active===this.instances[e]&&(this.active=null),delete this.instances[e],delete Joomla.editors.instances[e],this},get(t){return this.instances[t]||!1},setActive(t){if(t instanceof r)this.active=t;else if(this.instances[t])this.active=this.instances[t];else throw new Error("The editor instance not found or it is incorrect");return this},getActive(){return this.active}},l={actions:{},registerAction(t,e){if(!t||!e)throw new Error("Missed values for Action registration");if(!(e instanceof Function))throw new Error(`Unexpected handler for action "${t}", expecting Function`);return this.actions[t]=e,this},getActionHandler(t){return this.actions[t]||!1},runAction(t,e,o){const s=this.getActionHandler(t);let i=c.getActive();if(!s)throw new Error(`Handler for "${t}" action not found`);if(!i&&o){const a=o.closest("fieldset, div:not(.editor-xtd-buttons)"),n=a?a.querySelector("textarea[id]"):!1;i=n&&Joomla.editors.instances[n.id]?Joomla.editors.instances[n.id]:!1,i&&console.warn("Legacy editors is deprecated. Set active editor instance with JoomlaEditor.setActive().")}if(!i)throw new Error("An active editor are not available");return s(i,e)}};export{c as JoomlaEditor,l as JoomlaEditorButton};
|
||||
BIN
media/system/js/editors/editor-api.min.js.gz
Normal file
BIN
media/system/js/editors/editor-api.min.js.gz
Normal file
Binary file not shown.
137
media/system/js/editors/editor-decorator.js
Normal file
137
media/system/js/editors/editor-decorator.js
Normal file
@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
* A decorator for Editor instance.
|
||||
*/
|
||||
class JoomlaEditorDecorator {
|
||||
/**
|
||||
* Internal! The property should not be accessed directly.
|
||||
* The editor instance.
|
||||
* @type {Object}
|
||||
*/
|
||||
// instance = null;
|
||||
|
||||
/**
|
||||
* Internal! The property should not be accessed directly.
|
||||
* The editor type/name, eg: tinymce, codemirror, none etc.
|
||||
* @type {string}
|
||||
*/
|
||||
// type = '';
|
||||
|
||||
/**
|
||||
* Internal! The property should not be accessed directly.
|
||||
* HTML ID of the editor.
|
||||
* @type {string}
|
||||
*/
|
||||
// id = '';
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param {Object} instance The editor instance
|
||||
* @param {string} type The editor type/name
|
||||
* @param {string} id The editor ID
|
||||
*/
|
||||
constructor(instance, type, id) {
|
||||
if (!instance || !type || !id) {
|
||||
throw new Error('Missed values for class constructor');
|
||||
}
|
||||
this.instance = instance;
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the editor instance object.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
getRawInstance() {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the editor type/name.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the editor id.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the complete data from the editor.
|
||||
* Should be implemented by editor provider.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
getValue() {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the complete data of the editor
|
||||
* Should be implemented by editor provider.
|
||||
*
|
||||
* @param {string} value Value to set.
|
||||
*
|
||||
* @returns {JoomlaEditorDecorator}
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this, no-unused-vars
|
||||
setValue(value) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the selected text from the editor.
|
||||
* Should be implemented by editor provider.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
getSelection() {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the selected text. If nothing selected, will insert the data at the cursor.
|
||||
* Should be implemented by editor provider.
|
||||
*
|
||||
* @param {string} value
|
||||
*
|
||||
* @returns {JoomlaEditorDecorator}
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this, no-unused-vars
|
||||
replaceSelection(value) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the editor disabled mode. When the editor is active then everything should be usable.
|
||||
* When inactive the editor should be unusable AND disabled for form validation.
|
||||
* Should be implemented by editor provider.
|
||||
*
|
||||
* @param {boolean} enable True to enable, false or undefined to disable.
|
||||
*
|
||||
* @returns {JoomlaEditorDecorator}
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this, no-unused-vars
|
||||
disable(enable) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
export { JoomlaEditorDecorator as default };
|
||||
4
media/system/js/editors/editor-decorator.min.js
vendored
Normal file
4
media/system/js/editors/editor-decorator.min.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/class o{constructor(e,t,r){if(!e||!t||!r)throw new Error("Missed values for class constructor");this.instance=e,this.type=t,this.id=r}getRawInstance(){return this.instance}getType(){return this.type}getId(){return this.id}getValue(){throw new Error("Not implemented")}setValue(e){throw new Error("Not implemented")}getSelection(){throw new Error("Not implemented")}replaceSelection(e){throw new Error("Not implemented")}disable(e){throw new Error("Not implemented")}}export{o as default};
|
||||
BIN
media/system/js/editors/editor-decorator.min.js.gz
Normal file
BIN
media/system/js/editors/editor-decorator.min.js.gz
Normal file
Binary file not shown.
102
media/system/js/editors/editors.js
Normal file
102
media/system/js/editors/editors.js
Normal file
@ -0,0 +1,102 @@
|
||||
import { JoomlaEditorDecorator, JoomlaEditorButton } from 'editor-api';
|
||||
import JoomlaDialog from 'joomla.dialog';
|
||||
|
||||
/**
|
||||
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
if (!window.Joomla) {
|
||||
throw new Error('JoomlaEditors API require Joomla to be loaded.');
|
||||
}
|
||||
|
||||
// === The code for keep backward compatibility ===
|
||||
// Joomla.editors is deprecated use Joomla.Editor instead.
|
||||
// @TODO: Remove this section in Joomla 6.
|
||||
|
||||
// Only define editors if not defined
|
||||
Joomla.editors = Joomla.editors || {};
|
||||
|
||||
// An object to hold each editor instance on page, only define if not defined.
|
||||
Joomla.editors.instances = new Proxy({}, {
|
||||
set(target, p, editor) {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
if (!(editor instanceof JoomlaEditorDecorator)) {
|
||||
// Add missed method in Legacy editor
|
||||
editor.getId = () => p;
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Legacy editors is deprecated. Register the editor instance with JoomlaEditor.register().', p, editor);
|
||||
}
|
||||
target[p] = editor;
|
||||
return true;
|
||||
},
|
||||
get(target, p) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('Direct access to Joomla.editors.instances is deprecated. Use JoomlaEditor.getActive() or JoomlaEditor.get(id) to retrieve the editor instance.');
|
||||
return target[p];
|
||||
}
|
||||
});
|
||||
// === End of code for keep backward compatibility ===
|
||||
|
||||
// Register couple default actions for Editor Buttons
|
||||
// Insert static content on cursor
|
||||
JoomlaEditorButton.registerAction('insert', (editor, options) => {
|
||||
const content = options.content || '';
|
||||
editor.replaceSelection(content);
|
||||
});
|
||||
// Display modal dialog
|
||||
JoomlaEditorButton.registerAction('modal', (editor, options) => {
|
||||
if (options.src && options.src[0] !== '#' && options.src[0] !== '.') {
|
||||
// Replace editor parameter to actual editor ID
|
||||
const url = options.src.indexOf('http') === 0 ? new URL(options.src) : new URL(options.src, window.location.origin);
|
||||
url.searchParams.set('editor', editor.getId());
|
||||
if (url.searchParams.has('e_name')) {
|
||||
url.searchParams.set('e_name', editor.getId());
|
||||
}
|
||||
options.src = url.toString();
|
||||
}
|
||||
|
||||
// Create a dialog popup
|
||||
const dialog = new JoomlaDialog(options);
|
||||
|
||||
// Listener for postMessage
|
||||
const msgListener = event => {
|
||||
// Avoid cross origins
|
||||
if (event.origin !== window.location.origin) return;
|
||||
// Check message type
|
||||
if (event.data.messageType === 'joomla:content-select') {
|
||||
editor.replaceSelection(event.data.html || event.data.text);
|
||||
dialog.close();
|
||||
} else if (event.data.messageType === 'joomla:cancel') {
|
||||
dialog.close();
|
||||
}
|
||||
};
|
||||
// Use a JoomlaExpectingPostMessage flag to be able to distinct legacy methods
|
||||
// @TODO: This should be removed after full transition to postMessage()
|
||||
window.JoomlaExpectingPostMessage = true;
|
||||
window.addEventListener('message', msgListener);
|
||||
|
||||
// Clean up on close
|
||||
dialog.addEventListener('joomla-dialog:close', () => {
|
||||
delete window.JoomlaExpectingPostMessage;
|
||||
window.removeEventListener('message', msgListener);
|
||||
Joomla.Modal.setCurrent(null);
|
||||
dialog.destroy();
|
||||
});
|
||||
Joomla.Modal.setCurrent(dialog);
|
||||
// Show the popup
|
||||
dialog.show();
|
||||
});
|
||||
|
||||
// Listen to click on Editor button, and run action.
|
||||
const btnDelegateSelector = '[data-joomla-editor-button-action]';
|
||||
const btnActionDataAttr = 'joomlaEditorButtonAction';
|
||||
const btnConfigDataAttr = 'joomlaEditorButtonOptions';
|
||||
document.addEventListener('click', event => {
|
||||
const btn = event.target.closest(btnDelegateSelector);
|
||||
if (!btn) return;
|
||||
const action = btn.dataset[btnActionDataAttr];
|
||||
const options = btn.dataset[btnConfigDataAttr] ? JSON.parse(btn.dataset[btnConfigDataAttr]) : {};
|
||||
if (action) {
|
||||
JoomlaEditorButton.runAction(action, options, btn);
|
||||
}
|
||||
});
|
||||
4
media/system/js/editors/editors.min.js
vendored
Normal file
4
media/system/js/editors/editors.min.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import{JoomlaEditorDecorator as i,JoomlaEditorButton as n}from"editor-api";import c from"joomla.dialog";/**
|
||||
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/if(!window.Joomla)throw new Error("JoomlaEditors API require Joomla to be loaded.");Joomla.editors=Joomla.editors||{},Joomla.editors.instances=new Proxy({},{set(o,e,t){return t instanceof i||(t.getId=()=>e,console.warn("Legacy editors is deprecated. Register the editor instance with JoomlaEditor.register().",e,t)),o[e]=t,!0},get(o,e){return console.warn("Direct access to Joomla.editors.instances is deprecated. Use JoomlaEditor.getActive() or JoomlaEditor.get(id) to retrieve the editor instance."),o[e]}}),n.registerAction("insert",(o,e)=>{const t=e.content||"";o.replaceSelection(t)}),n.registerAction("modal",(o,e)=>{if(e.src&&e.src[0]!=="#"&&e.src[0]!=="."){const a=e.src.indexOf("http")===0?new URL(e.src):new URL(e.src,window.location.origin);a.searchParams.set("editor",o.getId()),a.searchParams.has("e_name")&&a.searchParams.set("e_name",o.getId()),e.src=a.toString()}const t=new c(e),r=a=>{a.origin===window.location.origin&&(a.data.messageType==="joomla:content-select"?(o.replaceSelection(a.data.html||a.data.text),t.close()):a.data.messageType==="joomla:cancel"&&t.close())};window.JoomlaExpectingPostMessage=!0,window.addEventListener("message",r),t.addEventListener("joomla-dialog:close",()=>{delete window.JoomlaExpectingPostMessage,window.removeEventListener("message",r),Joomla.Modal.setCurrent(null),t.destroy()}),Joomla.Modal.setCurrent(t),t.show()});const l="[data-joomla-editor-button-action]",d="joomlaEditorButtonAction",s="joomlaEditorButtonOptions";document.addEventListener("click",o=>{const e=o.target.closest(l);if(!e)return;const t=e.dataset[d],r=e.dataset[s]?JSON.parse(e.dataset[s]):{};t&&n.runAction(t,r,e)});
|
||||
BIN
media/system/js/editors/editors.min.js.gz
Normal file
BIN
media/system/js/editors/editors.min.js.gz
Normal file
Binary file not shown.
Reference in New Issue
Block a user