Skip to content

Instantly share code, notes, and snippets.

@rogerblanton
Created June 15, 2018 06:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rogerblanton/89f5bf6515a75850f8202dcc393dadca to your computer and use it in GitHub Desktop.
Save rogerblanton/89f5bf6515a75850f8202dcc393dadca to your computer and use it in GitHub Desktop.
A plugin that allows you to author modals based on Bootstrap 3 in AEM RTE.
(function ($) {
"use strict";
// Setup Constants
var modalPlugin = {
GROUP: "modalPlugin",
DEBUG: true,
FEATURE: "modal",
MODAL_DIALOG: "modaldialog",
MODAL_UI_SETTING: "modalPlugin#modal"
};
var logger = function(msg, callback) {
if (!modalPlugin.DEBUG || !console) {
return;
}
if (msg && (typeof msg ==='string')) {
console.log(msg);
}
if (callback) {
callback();
}
};
//returns the picker dialog html
//Handlebars doesn't do anything useful here, but the framework expects a template
var modalTemplate = function () {
CUI.rte.templates["dlg-" + modalPlugin.MODAL_DIALOG] =
Handlebars.compile(
'<div class="rte-dialog-columnContainer">'
+ '<div class="rte-dialog-column">'
+ '<label>'
+ '<input type="text" id="modalPath" placeholder="Modal Target" class="coral-Form-field coral-Textfield">'
+ '</label>'
+ '</div>'
+ '<div class="rte-dialog-column">'
+ '<button data-type="apply" class="coral-RichText-dialogButton coral-Button coral-Button--square coral-Button--primary" title="Apply">'
+ '<i class="coral-Icon coral-Icon--check coral-Icon--sizeS"></i>'
+ '</button>'
+ '</div>'
+ '<div class="rte-dialog-column">'
+ '<button data-type="cancel" class="coral-RichText-dialogButton coral-Button coral-Button--square" title="Cancel">'
+ '<i class="coral-Icon coral-Icon--close coral-Icon--sizeS"></i>'
+ '</button>'
+ '</div>'
+ '</div>'
);
CUI.rte.Templates = CUI.rte.templates || {};
};
modalTemplate();
/**
*
* @see /libs/clientlibs/granite/richtext/js/rte/ui/CuiToolbarBuilder.js for Super Class
*
* @type {Class}
* @extends CUI.rte.ui.cui.CuiToolbarBuilder
*/
modalPlugin.CuiToolbarBuilder = new Class({
toString: "ModalToolbarBuilder",
extend: CUI.rte.ui.cui.CuiToolbarBuilder,
_getUISettings: function (options) {
logger("in modalPlugin.CuiToolbarBuilder._getUISettings", function() {
console.log(options);
});
if (!this._getClassesForCommand(modalPlugin.MODAL_UI_SETTING)) {
this.registerAdditionalClasses(modalPlugin.MODAL_UI_SETTING, "coral-Icon touchui-modal coral-RichText--trigger");
}
return this.superClass._getUISettings(options);
}
});
/**
*
* @see /libs/clientlibs/granite/richtext/js/rte/ui/dialogs/AbstractBaseDialog.js
*
* @type {Class}
* @extends CUI.rte.ui.cui.AbstractBaseDialog
*/
modalPlugin.ModalDialog = new Class({
extend: CUI.rte.ui.cui.AbstractDialog,
toString: "ModalDialog",
getDataType: function () {
return modalPlugin.MODAL_DIALOG;
},
// method called everytime the dialog is closed, this is useful because sometimes the dialog can be closed
// without clicking the 'cancel' button.
onHide: function () {
//reset the popover values to empty when closed
this.$linkTitle.val("");
},
initialize: function (config) {
logger("In modalPlugin.ModalDialog.initialize", function() {
console.log(config);
});
this.exec = config.execute;
var context = this.editorKernel.editContext,
selection = CUI.rte.Selection.createProcessingSelection(context),
tag = CUI.rte.Common.getTagInPath(context, selection.startNode, "span");
this.$linkTitle = $('#modalPath');
},
attach: function (config, $container, editorKernel, enforceCreation) {
this.superClass.attach.call(this, config, $container, editorKernel);
},
// this method is called when the dialog is closed via the 'checkbox' e.g. to save the input
apply: function () {
// Getting the values of from the popover and passing them to the Command
var options,
modalPathValue = $('#modalPath').val();
if (modalPathValue !== "") {
options = options || {};
options.linkTitle = modalPathValue;
}
// this calls the execute method in teh dialogConfig object below, which in turns, calls the relayCommand to
// the command class.
this.exec(options);
// hide the dialog
this.hide();
},
// this method is called when the 'x' is clicked in the dialog, e.g. user interaction is cancelled.
cancel: function () {
// hide the dialog
this.hide();
}
});
/**
*
* @see /libs/clientlibs/granite/richtext/js/rte/ui/CuiDialogManager.js for Super class
*
* @type {Class}
* @extends CUI.rte.ui.cui.CuiDialogManager
*/
modalPlugin.DialogManager = new Class({
extend: CUI.rte.ui.cui.CuiDialogManager,
toString: "ModalDialogManager",
create: function (dialogId, config) {
logger("modalPlugin.DialogManager.create", function() {
console.log(dialogId, config);
});
if (dialogId !== modalPlugin.MODAL_DIALOG) {
return this.superClass.create.call(this, dialogId, config);
}
var context = this.editorKernel.getEditContext(),
$container = CUI.rte.UIUtils.getUIContainer($(context.root)),
dialog = new modalPlugin.ModalDialog();
dialog.attach(config, $container, this.editorKernel, true);
return dialog;
}
});
/**
*
* extend CUI toolkit impl to create instances of extended toolbar builder and dialog manager
*
* @type {Class}
* @extends CUI.rte.ui.cui.ToolkitImpl
*/
modalPlugin.ToolkitImpl = new Class({
toString: "ModalToolkitImpl",
extend: CUI.rte.ui.cui.ToolkitImpl,
createToolbarBuilder: function () {
logger("in modalPlugin.ToolkitImpl,createToolbarBuilder");
return new modalPlugin.CuiToolbarBuilder();
},
createDialogManager: function (editorKernel) {
logger("in modalPlugin.ToolkitImpl,createDialogManager");
return new modalPlugin.DialogManager(editorKernel);
}
});
// see /etc/clientlibs/granite/coralui2/optional/rte/js/core/ui/ToolkitRegistry.js
CUI.rte.ui.ToolkitRegistry.register("modal", modalPlugin.ToolkitImpl);
CUI.rte.ui.ToolkitRegistry.initialize("modal");
/**
*
* @type {Class}
* @extends CUI.rte.plugins.Plugin
*/
modalPlugin.ModalPlugin = new Class({
toString: "ModalPlugin",
extend: CUI.rte.plugins.Plugin,
modalUI: null,
getFeatures: function () {
return [modalPlugin.FEATURE];
},
initializeUI: function (toolbarGenerator) {
var plg = CUI.rte.plugins;
// Create the Toolbar Element
if (this.isFeatureEnabled(modalPlugin.FEATURE)) {
var tooltip = {};
tooltip.title="Modal";
this.modalUI = toolbarGenerator.createElement(modalPlugin.FEATURE, this, true, tooltip);
// Add the toolbar element to the toolbar
toolbarGenerator.addElement("demo", plg.Plugin.SORT_FORMAT, this.modalUI, 140);
}
},
//this method is called to determine whether or not event handlers should be applied
//if true, it assumes the plugin button clicked is an action and not a popover and applies
//no events, so setting it to false applies the events like we want to the dialog can be reused
//in the same dialog session.
isHeadless: function(cmd, value) {
return false;
},
execute: function (id, value, envOptions) {
logger("modalPlugin.ModalPlugin.execute", function() {
console.log(id, value, envOptions);
});
var editorKernel = this.editorKernel,
dialogManager = editorKernel.getDialogManager(),
context = envOptions.editContext,
selection = CUI.rte.Selection.createProcessingSelection(context),
startNode = selection.startNode;
if ((selection.startOffset === startNode.length) && (startNode != selection.endNode)) {
startNode = startNode.nextSibling;
}
if (dialogManager.isShown(this.dialog)) {
dialogManager.hide(this.dialog);
return;
}
var dialogConfig = {
execute: function (options) {
editorKernel.relayCmd(id, options);
},
parameters: {
"command": modalPlugin.MODAL_UI_SETTING
}
},
dh = CUI.rte.ui.DialogHelper;
if (!this.dialog) {
this.dialog = dialogManager.create(modalPlugin.MODAL_DIALOG, dialogConfig);
}
var tag = CUI.rte.Common.getTagInPath(context, selection.startNode, "span");
if (tag) {
this.dialog.$linkTitle.val(tag.dataset.target ? tag.dataset.target.replace("#","") : "");
}
dialogManager.prepareShow(this.dialog);
dialogManager.show(this.dialog);
},
updateState: function (selDef) {
if (this.modalUI != null && (selDef.isSelection || selDef.nodeList.commonAncestor.classList.contains("modal-plugin"))) {
this.modalUI.setDisabled(false);
this.modalUI.setSelected(false);
} else {
this.modalUI.setSelected(false);
this.modalUI.setDisabled(true);
}
}
});
CUI.rte.plugins.PluginRegistry.register(modalPlugin.GROUP, modalPlugin.ModalPlugin);
/**
* This Class is invoked by the dialog via the `apply` method, e.g. when the User saves the Dialog. This is not invoked
* when the user cancels input or closes the dialog without saving it.
*
* @see /libs/clientlibs/granite/richtext/core/js/commands/Command.js
*
* @type {Class}
* @extends CUI.rte.commands.Command
*/
modalPlugin.ModalCmd = new Class({
toString: "ModalCmd",
extend: CUI.rte.commands.Command,
// a command can have one or multiple commands, the `isCommand` method checks whether this command is the one accountable for action.
isCommand: function (cmdStr) {
return (cmdStr.toLowerCase() == modalPlugin.FEATURE);
},
getProcessingOptions: function () {
var cmd = CUI.rte.commands.Command;
return cmd.PO_SELECTION | cmd.PO_BOOKMARK | cmd.PO_NODELIST;
},
_getTagObject: function (options) {
var returnObj = {};
returnObj.attributes = {};
returnObj.tag = "span";
if (options) {
if (options.linkTitle) {
returnObj.attributes["data-target"] = "#"+options.linkTitle;
}
returnObj.attributes["data-toggle"] = "modal";
returnObj.attributes["class"] = "modal-plugin";
}
return returnObj;
},
execute: function (executionDefinition) {
var selection = executionDefinition.selection,
nodeList = executionDefinition.nodeList;
if (!selection || !nodeList) {
return;
}
//if no modal value is passed, assume delete and remove the span
if (!executionDefinition.value) {
var dpr = CUI.rte.DomProcessor;
for (var i = 0; i < nodeList.nodes.length; i++) {
dpr.removeWithoutChildren(nodeList.nodes[i].dom.parentNode);
}
return;
}
var common = CUI.rte.Common,
context = executionDefinition.editContext,
tagObj = this._getTagObject(executionDefinition.value);
// method to check whether or not the selected nodes have any existing modals in them, returns an Array[].
var tags = common.getTagInPath(context, selection.startNode, tagObj.tag);
//remove existing span before surrounding with new span
if (tags != null) {
nodeList.removeNodesByTag(executionDefinition.editContext, tagObj.tag, undefined, true);
nodeList.commonAncestor = nodeList.nodes[0].dom.parentElement;
}
//apply the markup to the selection
nodeList.surround(executionDefinition.editContext, tagObj.tag, tagObj.attributes);
}
});
// Assigning the Command Class `modalPlugin.ModalCmd` to The Feature. If your Plugin has multiple features, you will have to register multiple commands
CUI.rte.commands.CommandRegistry.register(modalPlugin.FEATURE, modalPlugin.ModalCmd);
}(jQuery));
@niksonawane
Copy link

Can you please explain how to use it? It's really urgent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment