first commit
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* @file js/controllers/form/MultilingualInputHandler.js
|
||||
*
|
||||
* Copyright (c) 2014-2021 Simon Fraser University
|
||||
* Copyright (c) 2000-2021 John Willinsky
|
||||
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
||||
*
|
||||
* @class MultilingualInputHandler
|
||||
* @ingroup js_controllers_form
|
||||
*
|
||||
* @brief Handler for toggling the pop-over on multi lingual inputs (text
|
||||
* inputs and text areas, mostly).
|
||||
*/
|
||||
(function($) {
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @extends $.pkp.classes.Handler
|
||||
*
|
||||
* @param {jQueryObject} $popover the wrapped HTML element.
|
||||
* @param {Object} options options to be passed
|
||||
* into the validator plug-in.
|
||||
*/
|
||||
$.pkp.controllers.form.MultilingualInputHandler = function($popover, options) {
|
||||
this.parent($popover, options);
|
||||
|
||||
// Bind to the focus of the primary language (the first input)
|
||||
// open the pop-over
|
||||
var $popoverNode = null;
|
||||
|
||||
if ($popover.hasClass('pkpTagit')) {
|
||||
$popoverNode = $popover.find(':input').filter(':visible');
|
||||
} else {
|
||||
$popoverNode = $popover.find(':input').first();
|
||||
}
|
||||
|
||||
$popoverNode
|
||||
.focus(this.callbackWrapper(this.focusHandler_));
|
||||
// Bind to the blur of any of the inputs to check if we should close.
|
||||
$popover.find(':input').
|
||||
blur(this.callbackWrapper(this.blurHandler_));
|
||||
|
||||
this.publishEvent('tinyMCEInitialized');
|
||||
|
||||
this.tinyMCEInitHandler_();
|
||||
|
||||
setTimeout(this.callbackWrapper(this.isIncomplete_), 500);
|
||||
};
|
||||
$.pkp.classes.Helper.inherits(
|
||||
$.pkp.controllers.form.MultilingualInputHandler,
|
||||
$.pkp.classes.Handler);
|
||||
|
||||
|
||||
//
|
||||
// Private helper methods.
|
||||
//
|
||||
/**
|
||||
* Focus event handler. This is attached to all primary inputs.
|
||||
*
|
||||
* @param {HTMLElement} multilingualInput The primary multilingual
|
||||
* element.
|
||||
* @param {Event} event The focus event.
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.form.MultilingualInputHandler.prototype.focusHandler_ =
|
||||
function(multilingualInput, event) {
|
||||
|
||||
this.showPopover_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Blur event handler. This is attached to all inputs inside this
|
||||
* popover element.
|
||||
*
|
||||
* @param {HTMLElement} multilingualInput The element in the
|
||||
* multilingual set to hide.
|
||||
* @param {Event} event The event that triggered the action.
|
||||
* @return {boolean} Return true to continue the event handling.
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.form.MultilingualInputHandler.prototype.blurHandler_ =
|
||||
function(multilingualInput, event) {
|
||||
|
||||
// Use a timeout to give the other element a chance to acquire the focus.
|
||||
setTimeout(this.callbackWrapper(function() {
|
||||
if (!this.hasElementInFocus_()) {
|
||||
this.hidePopover_();
|
||||
}
|
||||
}), 100);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Hide this popover.
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.form.MultilingualInputHandler.prototype.hidePopover_ =
|
||||
function() {
|
||||
var $popover = this.getHtmlElement();
|
||||
$popover.removeClass('localization_popover_container_focus');
|
||||
$popover.find('.localization_popover').hide();
|
||||
this.isIncomplete_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Show this popover.
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.form.MultilingualInputHandler.prototype.showPopover_ =
|
||||
function() {
|
||||
var $popover = this.getHtmlElement();
|
||||
$popover.addClass('localization_popover_container_focus');
|
||||
|
||||
// Hack alert: setting width in JS because they do not line up otherwise.
|
||||
$popover.find('.localization_popover').width(
|
||||
/** @type {number} */ ($popover.width()));
|
||||
|
||||
// Show the pop over.
|
||||
$popover.find('.localization_popover').show();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Test if any of the elements inside this popover has focus.
|
||||
* @return {boolean} True iff an element is in focus.
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.form.MultilingualInputHandler.prototype.hasElementInFocus_ =
|
||||
function() {
|
||||
|
||||
var $popover = this.getHtmlElement();
|
||||
|
||||
// Do the test.
|
||||
if ($popover.has(document.activeElement).length) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if the field is missing a localization
|
||||
*
|
||||
* Fields are not considered to be missing a localization unless at least
|
||||
* one of the localizations has an entry.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.form.MultilingualInputHandler.prototype.isIncomplete_ =
|
||||
function() {
|
||||
|
||||
var $popover = this.getHtmlElement(),
|
||||
$inputs = [],
|
||||
valuesCount = 0;
|
||||
|
||||
if (typeof tinyMCE === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Track current values in the tinyMCE control
|
||||
if (this.getHtmlElement().find('.richContent').length) {
|
||||
$popover.find('textarea').each(function() {
|
||||
var id = $(this).attr('id'),
|
||||
tinymce;
|
||||
|
||||
$inputs.push($(this));
|
||||
tinymce = tinyMCE.EditorManager.get(/** @type {string} */(
|
||||
$(this).attr('id')));
|
||||
if (tinymce.getContent()) {
|
||||
valuesCount++;
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
$inputs = $popover.find(':input');
|
||||
$inputs.each(function() {
|
||||
if ($(this).val()) {
|
||||
valuesCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (valuesCount > 0 && valuesCount < $inputs.length) {
|
||||
$popover.removeClass('localizationComplete')
|
||||
.addClass('localizationIncomplete');
|
||||
} else if (valuesCount === $inputs.length) {
|
||||
$popover.removeClass('localizationIncomplete')
|
||||
.addClass('localizationComplete');
|
||||
} else {
|
||||
$popover.removeClass('localizationIncomplete localizationComplete');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Attach focus and blur event handlers to the tinyMCE window element, which
|
||||
* show and hide the localization popover
|
||||
* @private
|
||||
*/
|
||||
$.pkp.controllers.form.MultilingualInputHandler.prototype.tinyMCEInitHandler_ =
|
||||
function() {
|
||||
|
||||
if (!this.getHtmlElement().find('.richContent').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof tinyMCE === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
var htmlElement = this.getHtmlElement(),
|
||||
tinyMCEObject = tinyMCE.EditorManager.get(/** @type {string} */(
|
||||
htmlElement.find('textarea').first().attr('id')));
|
||||
|
||||
tinyMCEObject.on('focus', this.callbackWrapper(function() {
|
||||
// We need also to close the multilingual popover when user clicks
|
||||
// outside the popover element. The blur event is not enough because
|
||||
// sometimes (with text selected in editor) Chrome will consider the
|
||||
// tinyMCE editor as still active and that will avoid the popover to
|
||||
// close (see the first check of the blur handler, just above).
|
||||
//
|
||||
// Firefox will also not completely focus on tinyMCE editors after
|
||||
// coming back from fullscreen mode (the callback to focus the
|
||||
// editor when set content will only trigger the focus handler that
|
||||
// we attach here, but will not move the cursor inside the tinyMCE
|
||||
// editor). Then, if user clicks outside the popover, it will not
|
||||
// close because no blur event will be triggered.
|
||||
this.trigger('callWhenClickOutside', {
|
||||
container: this.getHtmlElement(),
|
||||
callback: this.callbackWrapper(this.hidePopover_)
|
||||
});
|
||||
|
||||
this.showPopover_();
|
||||
}));
|
||||
|
||||
tinyMCEObject.on('blur', this.callbackWrapper(function() {
|
||||
// Check if the active document element is still the tinyMCE
|
||||
// editor. If true, return false. This will avoid closing the
|
||||
// popover if user is just inserting an image or editing the
|
||||
// html source, for example (both actions open a new window).
|
||||
if ($(tinyMCEObject.getContainer()).find('iframe').attr('id') ==
|
||||
$(document.activeElement).attr('id')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use a timeout to give the other element a chance to acquire the
|
||||
// focus.
|
||||
setTimeout(this.callbackWrapper(function() {
|
||||
if (!this.hasElementInFocus_()) {
|
||||
this.hidePopover_();
|
||||
}
|
||||
}), 0);
|
||||
}));
|
||||
};
|
||||
|
||||
|
||||
}(jQuery));
|
||||
Reference in New Issue
Block a user