Files

364 lines
10 KiB
JavaScript

/**
* Used for WYSIWYG logic
*/
window.CMB2 = window.CMB2 || {};
window.CMB2.wysiwyg = window.CMB2.wysiwyg || {};
(function (window, document, $, cmb, wysiwyg, undefined) {
"use strict";
// Private variables
var toBeDestroyed = [];
var toBeInitialized = [];
var all = (wysiwyg.all = {});
// Private functions
/**
* Initializes any editors that weren't initialized because they didn't exist yet.
*
* @since 2.2.3
*
* @return {void}
*/
function delayedInit() {
// Don't initialize until they've all been destroyed.
if (0 === toBeDestroyed.length) {
toBeInitialized.forEach(function (toInit) {
toBeInitialized.splice(toBeInitialized.indexOf(toInit), 1);
wysiwyg.init.apply(wysiwyg, toInit);
});
} else {
window.setTimeout(delayedInit, 100);
}
}
/**
* Destroys any editors that weren't destroyed because they didn't exist yet.
*
* @since 2.2.3
*
* @return {void}
*/
function delayedDestroy() {
toBeDestroyed.forEach(function (id) {
toBeDestroyed.splice(toBeDestroyed.indexOf(id), 1);
wysiwyg.destroy(id);
});
}
/**
* Gets the option data for a group (and initializes that data if it doesn't exist).
*
* @since 2.2.3
*
* @param {object} data The group/field data.
*
* @return {object} Options data object for a group.
*/
function getGroupData(data) {
var groupid = data.groupid;
var fieldid = data.fieldid;
if (!all[groupid] || !all[groupid][fieldid]) {
all[groupid] = all[groupid] || {};
all[groupid][fieldid] = {
template: wp.template("cmb2-wysiwyg-" + groupid + "-" + fieldid),
defaults: {
// Get the data from the template-wysiwyg initiation.
mce: $.extend(
{},
tinyMCEPreInit.mceInit["cmb2_i_" + groupid + fieldid],
),
qt: $.extend(
{},
tinyMCEPreInit.qtInit["cmb2_i_" + groupid + fieldid],
),
},
};
// This is the template-wysiwyg data, and we do not want that to be initiated.
delete tinyMCEPreInit.mceInit["cmb2_i_" + groupid + fieldid];
delete tinyMCEPreInit.qtInit["cmb2_i_" + groupid + fieldid];
}
return all[groupid][fieldid];
}
/**
* Initiates the tinyMCEPreInit options for a wysiwyg editor instance.
*
* @since 2.2.3
*
* @param {object} options Options data object for the wysiwyg editor instance.
*
* @return {void}
*/
function initOptions(options) {
var nameRegex = new RegExp(
"cmb2_n_" + options.groupid + options.fieldid,
"g",
);
var idRegex = new RegExp(
"cmb2_i_" + options.groupid + options.fieldid,
"g",
);
var prop, newSettings, newQTS;
// If no settings for this field. Clone from placeholder.
if ("undefined" === typeof tinyMCEPreInit.mceInit[options.id]) {
newSettings = $.extend({}, options.defaults.mce);
for (prop in newSettings) {
if ("string" === typeof newSettings[prop]) {
newSettings[prop] = newSettings[prop]
.replace(idRegex, options.id)
.replace(nameRegex, options.name);
}
}
tinyMCEPreInit.mceInit[options.id] = newSettings;
}
// If no Quicktag settings for this field. Clone from placeholder.
if ("undefined" === typeof tinyMCEPreInit.qtInit[options.id]) {
newQTS = $.extend({}, options.defaults.qt);
for (prop in newQTS) {
if ("string" === typeof newQTS[prop]) {
newQTS[prop] = newQTS[prop]
.replace(idRegex, options.id)
.replace(nameRegex, options.name);
}
}
tinyMCEPreInit.qtInit[options.id] = newQTS;
}
}
/**
* Initializes all group wysiwyg editors. Hooked to cmb_init.
*
* @since 2.2.3
*
* @return {void}
*/
wysiwyg.initAll = function () {
var $this, data, initiated;
$(".cmb2-wysiwyg-placeholder").each(function () {
$this = $(this);
data = $this.data();
if (data.groupid) {
data.id = $this.attr("id");
data.name = $this.attr("name");
data.value = $this.val();
wysiwyg.init($this, data, false);
initiated = true;
}
});
if (true === initiated) {
if ("undefined" !== typeof window.QTags) {
window.QTags._buttonsInit();
}
// Hook in our event callbacks.
$(document)
.on("cmb2_add_row", wysiwyg.addRow)
.on("cmb2_remove_group_row_start", wysiwyg.destroyRowEditors)
.on("cmb2_shift_rows_start", wysiwyg.shiftStart)
.on("cmb2_shift_rows_complete", wysiwyg.shiftComplete);
}
};
/**
* Initiates wysiwyg editors in a new group row. Hooked to cmb2_add_row.
*
* @since 2.2.3
*
* @param {object} evt A jQuery-normalized event object.
* @param {object} $row A jQuery dom element object for the group row.
*
* @return {void}
*/
wysiwyg.addRow = function (evt, $row) {
wysiwyg.initRow($row, evt);
};
/**
* Destroys wysiwyg editors in a group row when that row is removed. Hooked to cmb2_remove_group_row_start.
*
* @since 2.2.3
*
* @param {object} evt A jQuery-normalized event object.
* @param {object} $btn A jQuery dom element object for the remove-row button.
*
* @return {void}
*/
wysiwyg.destroyRowEditors = function (evt, $btn) {
wysiwyg.destroy(
$btn
.parents(".cmb-repeatable-grouping")
.find(".wp-editor-area")
.attr("id"),
);
};
/**
* When a row-shift starts, we need to destroy the wysiwyg editors for the group-rows being shuffled.
*
* @since 2.2.3
*
* @param {object} evt A jQuery-normalized event object.
* @param {object} $btn A jQuery dom element object for the remove-row button.
* @param {object} $from A jQuery dom element object for the row being shifted from.
* @param {object} $to A jQuery dom element object for the row being shifted to.
*
* @return {void}
*/
wysiwyg.shiftStart = function (evt, $btn, $from, $to) {
$from
.add($to)
.find(".wp-editor-wrap textarea")
.each(function () {
wysiwyg.destroy($(this).attr("id"));
});
};
/**
* When a row-shift completes, we need to re-init the wysiwyg editors for the group-rows being shuffled.
*
* @since 2.2.3
*
* @param {object} evt A jQuery-normalized event object.
* @param {object} $btn A jQuery dom element object for the remove-row button.
* @param {object} $from A jQuery dom element object for the row being shifted from.
* @param {object} $to A jQuery dom element object for the row being shifted to.
*
* @return {void}
*/
wysiwyg.shiftComplete = function (evt, $btn, $from, $to) {
$from.add($to).each(function () {
wysiwyg.initRow($(this), evt);
});
};
/**
* Initializes editors for a new CMB row.
*
* @since 2.2.3
*
* @param {object} $row A jQuery dom element object for the group row.
* @param {object} evt A jQuery-normalized event object.
*
* @return {void}
*/
wysiwyg.initRow = function ($row, evt) {
var $toReplace, data, defVal;
$row.find(".cmb2-wysiwyg-inner-wrap").each(function () {
$toReplace = $(this);
data = $toReplace.data();
defVal = cmb.getFieldArg(data.hash, "default", "");
defVal = "undefined" !== typeof defVal && false !== defVal ? defVal : "";
data.iterator = $row.data("iterator");
data.fieldid = data.id;
data.id = data.groupid + "_" + data.iterator + "_" + data.fieldid;
data.name =
data.groupid + "[" + data.iterator + "][" + data.fieldid + "]";
data.value =
"cmb2_add_row" !== evt.type && $toReplace.find(".wp-editor-area").length
? $toReplace.find(".wp-editor-area").val()
: defVal;
// The destroys might not have happened yet. Don't init until they have.
if (0 === toBeDestroyed.length) {
wysiwyg.init($toReplace, data);
} else {
toBeInitialized.push([$toReplace, data]);
window.setTimeout(delayedInit, 100);
}
});
};
/**
* Initiates a wysiwyg editor instance and replaces the passed dom element w/ the editor html.
*
* @since 2.2.3
*
* @param {object} $toReplace A jQuery dom element which will be replaced with the wysiwyg editor.
* @param {object} data Data used to initate the editor.
* @param {bool} buttonsInit Whether to run QTags._buttonsInit()
*
* @return {void}
*/
wysiwyg.init = function ($toReplace, data, buttonsInit) {
if (!data.groupid) {
return false;
}
var mceActive = cmb.canTinyMCE();
var qtActive = "function" === typeof window.quicktags;
$.extend(data, getGroupData(data));
initOptions(data);
$toReplace.replaceWith(data.template(data));
if (mceActive) {
window.tinyMCE.init(tinyMCEPreInit.mceInit[data.id]);
}
if (qtActive) {
window.quicktags(tinyMCEPreInit.qtInit[data.id]);
}
if (mceActive) {
$(document.getElementById(data.id))
.parents(".wp-editor-wrap")
.removeClass("html-active")
.addClass("tmce-active");
}
if (false !== buttonsInit && "undefined" !== typeof window.QTags) {
window.QTags._buttonsInit();
}
};
/**
* Destroys a wysiwyg editor instance.
*
* @since 2.2.3
*
* @param {string} id Editor id.
*
* @return {void}
*/
wysiwyg.destroy = function (id) {
if (!cmb.canTinyMCE()) {
// Nothing to see here.
return;
}
// The editor might not be initialized yet. But we need to destroy it once it is.
var editor = tinyMCE.get(id);
if (editor !== null && typeof editor !== "undefined") {
editor.destroy();
if ("undefined" === typeof tinyMCEPreInit.mceInit[id]) {
delete tinyMCEPreInit.mceInit[id];
}
if ("undefined" === typeof tinyMCEPreInit.qtInit[id]) {
delete tinyMCEPreInit.qtInit[id];
}
} else if (-1 === toBeDestroyed.indexOf(id)) {
toBeDestroyed.push(id);
window.setTimeout(delayedDestroy, 100);
}
};
// Hook in our event callbacks.
$(document).on("cmb_init", wysiwyg.initAll);
})(window, document, jQuery, window.CMB2, window.CMB2.wysiwyg);