Files

211 lines
5.2 KiB
JavaScript

/**
* Used for character counters
*/
window.CMB2 = window.CMB2 || {};
window.CMB2.charcounter = window.CMB2.charcounter || {};
(function (window, document, $, cmb, counter) {
"use strict";
if (!wp.utils || !wp.utils.WordCounter) {
return cmb.log("Cannot find wp.utils!");
}
// Private variables
counter.counters = {};
var counters = counter.counters;
var wpCounter = new wp.utils.WordCounter();
/**
* Update a field's character counter
*
* @since 2.7.0
*
* @param {string} field_id
*
* @return {int}
*/
counter.updateCounter = function (field_id) {
// No counter?
if (!counters.hasOwnProperty(field_id)) {
return null;
}
var instance = counters[field_id];
var wysiwyg = instance.editor && !instance.editor.isHidden();
// Are we dealing with WYSIWYG visual editor, or textarea / WYSIWYG textarea?
var text = wysiwyg
? instance.editor.getContent({ format: "raw" })
: cmb.$id(field_id).val().trim();
var count = wpCounter.count(text, instance.type);
var exceeded = instance.max && count > instance.max;
// Number remaining when max is defined
var val = instance.max ? instance.max - count : count;
// Over maximum?
instance.$el
.parents(".cmb2-char-counter-wrap")
[exceeded ? "addClass" : "removeClass"]("cmb2-max-exceeded");
// Update counter, and update counter input width.
instance.$el.val(val).outerWidth(8 * String(val).length + 15 + "px");
return count;
};
counter.instantiate = function ($el) {
var data = $el.data();
// Add counter details if not already done
if (!(data.fieldId in counters)) {
var instance = {
$el: $el,
max: data.max,
type:
"words" === data.counterType
? "words"
: "characters_including_spaces",
editor: false,
};
counters[data.fieldId] = instance;
// Initialise counter
counter.updateCounter(data.fieldId);
}
};
/**
* Initializes all character counters. Hooked to cmb_init.
*
* @since 2.7.0
*
* @param {bool} init First init?
*
* @return {void}
*/
counter.initAll = function () {
// Gather counters and initialise
$(".cmb2-char-counter").each(function () {
counter.instantiate($(this));
});
};
/**
* Initializes WYSIWYG editors. Hooked to tinymce-editor-init
*
* @since 2.7.0
*
* @param {object} evt
* @param {object} editor
*
* @return {void}
*/
counter.initWysiwyg = function (evt, editor) {
// Check if it's one of our WYSIWYGs
// Should have already been registered in counters via hidden textarea
if (editor.id in counters) {
// Add editor to counter
counters[editor.id].editor = editor;
// Add nodechange event
editor.on("nodechange keyup", counter.countWysiwyg);
}
};
/**
* Initializes after a new repeatable row has been added. Hooked to cmb2_add_row
*
* @since 2.7.0
*
* @param {object} evt A jQuery-normalized event object.
* @param {object} $row A jQuery dom element object for the group row.
*
* @return {void}
*/
counter.addRow = function (evt, $row) {
// Character counters in row?
$row.find(".cmb2-char-counter").each(function () {
// Update attributes
var $this = $(this);
var id = $this.attr("id");
var field_id = id.replace(/^char-counter-/, "");
$this.attr("data-field-id", field_id).data("field-id", field_id);
counter.instantiate($this);
});
};
/**
* Clean the counters array.
* Removes counters after a repeatable row has been removed. Hooked to cmb2_remove_row.
*
* @since 2.7.0
*
* @return {void}
*/
counter.cleanCounters = function () {
var field_id,
remove = [];
// Got through counters
for (field_id in counters) {
// Check for element, gather for removal
if (!document.getElementById(field_id)) {
remove.push(field_id);
}
}
// Anything to remove?
if (remove.length) {
_.each(remove, function (field_id) {
delete counters[field_id];
});
}
};
/**
* Counts the value of wysiwyg on the keyup event.
*
* @since 2.7.0
*
* @param {object} evt
*
* @return {void}
*/
counter.countWysiwyg = _.throttle(function (evt) {
// Init event
if (evt.hasOwnProperty("element")) {
return counter.updateCounter($(evt.element).data("id"));
}
// Nodechange event
if (evt.hasOwnProperty("currentTarget")) {
return counter.updateCounter($(evt.currentTarget).data("id"));
}
});
/**
* Counts the value of textarea on the keyup event.
*
* @since 2.7.0
*
* @param {object} evt
*
* @return {void}
*/
counter.countTextarea = _.throttle(function (evt) {
counter.updateCounter(evt.currentTarget.id);
}, 400);
// Hook in our event callbacks.
$(document)
.on("cmb_init", counter.initAll)
.on("tinymce-editor-init", counter.initWysiwyg)
.on("cmb2_add_row", counter.addRow)
.on("cmb2_remove_row", counter.cleanCounters)
.on("input keyup", ".cmb2-count-chars", counter.countTextarea);
})(window, document, jQuery, window.CMB2, window.CMB2.charcounter);