/* --------------------------------------------------------------
filemanager.js 2020-06-26
Gambio GmbH
http://www.gambio.de
Copyright (c) 2020 Gambio GmbH
Released under the GNU General Public License (Version 2)
[http://www.gnu.org/licenses/gpl-2.0.html]
--------------------------------------------------------------
*/
/**
* ## Filemanager Widget
*
* Creates an input field and a button in order to make it possible to upload files or to select already
* uploaded files. This widget checks if the responsive filemanager is present, if it is, the responsive
* filemanager will be used, else a fallback will be used, which is an input field of type 'file'.
*
* ### Options
*
* **Type | `data-filemanager-type` | String | Optional**
*
* Provide the allowed file upload type. Currently there are 3 options which are:
* * 'all' - All file types are allowed
* * 'videos' - Only video files are allowed
* * 'images' - Only images are allowed
* If you don't provide any type, the filemanager will default to 'all'.
*
* **Content Directory | `data-filemanager-content-directory` | String | Required**
*
* Provide the directory which should be opened when the filemanager gets opened, e.g. 'media'.
* You can also provide a path from the root of your shop e.g 'images/slider_images'.
*
* **Name | `data-filemanager-name` | String | Required**
*
* The name of the input field. It will be set as the HTML name attribute.
*
* **Previous File | `data-filemanager-previous-file` | String | Optional**
*
* Name of the previous file. The name will be used in order to auto fill the input field.
*
* **Page | `data-filemanager-page` | String | Optional**
*
* The name of the current page in snake case, for example: new_category or responsive_filemanager.
* This option will be used in order to load custom configuration files for the responsive file manager like
* responsive_filemanager.config.php. These custom configuration files will be available or should be created
* in the 'page' directory of the responsive file manager.
*
* **Page Active | `data-filemanager-page-active` | Boolean | Required**
*
* This option is required in order to check whether the file manager module is active, and if the configuration
* option from the file manager is set to active, for the current page. If the module is not active, or active
* in general but not active for the current page, the fallback will be used, which is a standard input field.
*
* ### Example
*
* ```html
* <div data-gx-widget="filemanager"
* data-filemanager-name="categories_icon" // Required
* data-filemanager-type="images" // Optional
* data-filemanager-content-directory="images/categories/icons" // Required
* data-filemanager-previous-file="filename.extension" // Optional
* data-filemanager-page="responsive_filemanager" // Optional
* data-filemanager-page-active="true"> // Required
* </div>
* ```
*
* @module Admin/Widgets/filemanager
*/
gx.widgets.module(
'filemanager',
['xhr', 'modal'],
/** @lends module:Widgets/filemanager */
function (data) {
'use strict';
// ------------------------------------------------------------------------
// VARIABLE DEFINITION
// ------------------------------------------------------------------------
/**
* Widget Reference
*
* @type {object}
*/
const $this = $(this);
/**
* Default Widget Options
*
* @type {object}
*/
const defaults = {};
/**
* Final Widget Options
*
* @type {object}
*/
const options = $.extend(true, {}, defaults, data);
/**
* Module Object
*
* @type {object}
*/
const module = {};
/**
* Id of the file manager input field.
*
* @type {string}
*/
let fieldId;
/**
* Ajax request url fetch the file managers configuration settings.
*
* @type {string}
*/
const fileManagerConfigurationUrl = jse.core.config.get('appUrl')
+ '/admin/admin.php?do=ResponsiveFileManagerModuleCenterModule/GetConfiguration';
/**
* Cache key.
*
* @type {string}
*/
const cacheKey = 'responsiveFileManager';
// ------------------------------------------------------------------------
// FUNCTIONS
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// FILE MANAGER CONFIGURATIONS
// ------------------------------------------------------------------------
/**
* Returns the allowed file type as an integer, which is mapped
* for the external Responsive Filemanager plugin. It will be used
* as a GET parameter in the URL for the file manager.
*
* @returns {number} Flag integer value between 0 and 3.
*/
const _getFMType = () => {
switch (options.type) {
case 'images':
return 1;
case 'all':
return 2;
case 'videos':
return 3;
default:
return 0;
}
};
/**
* File managers request url.
*
* @returns {string} Request url of file manager.
*/
const _getFMUrl = () => {
// Language parameter used for the file manager
const lang = jse.core.registry.get('languageId') === 2 ? 'de' : 'en_EN';
// Don't use the popup mode if the file manager will be opened in a modal.
const popUp = _isCompatibilityModeEnabled() ? 1 : '';
return jse.core.config.get('appUrl') + '/'
+ 'ResponsiveFilemanager/filemanager/filemanager.php?type=' + _getFMType()
+ _getSubDirectoryQueryString() + '&field_id=' + fieldId
+ '&popup=' + popUp + '&relative_url=1&lang=' + lang
+ _getPageQueryString();
};
/**
* Returns the 'sub_folder' query argument for the file manager request.
*
* @returns {string} Query parameter for file manager request to set the root directory.
*/
const _getSubDirectoryQueryString = () => {
if (options.contentDirectory !== undefined) {
return '&sub_folder=' + options.contentDirectory;
}
return '';
};
/**
* Returns the 'page' query string for the file manager request.
*
* @returns {string} Query parameter for the file manager request to load a custom configuration file.
*/
const _getPageQueryString = () => {
if (options.page !== undefined) {
return '&page=' + options.page;
}
return '';
};
/**
* Generates a global unique identifier for each input that is generated by this widget.
* This ID will be used in order to identify an input fields. With the help of this ID,
* the widget knows, in which input field the file name of the chose file should be entered.
*
* @returns {string} Global unique identifier as string.
*/
const guidGenerator = () => {
const s4 = () => (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
return (s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4());
};
// ------------------------------------------------------------------------
// CREATING THE FILE MANAGER
// ------------------------------------------------------------------------
/**
* Factory, which creates either the responsive file manager or the fallback,
* which is a standard input field of the type 'file'.
*
* @type {{responsive: (function()), fallback: (function())}}
*/
const factory = {
responsive: () => {
const $uploadIcon = $('<i/>', {
'class': 'fa fa-upload',
'aria-hidden': true
});
const $removeIcon = $('<i/>', {
'class': 'fa fa-remove',
'aria-hidden': true
});
const $input = $('<input/>', {
'type': 'text',
'name': options.name,
'id': fieldId,
'class': 'form-control',
'readonly': 'readonly'
});
// Auto fill the input field with the previous file name
if (options.previousFile) {
$input.val(options.previousFile);
}
const $uploadButton = $('<a/>', {
'class': 'btn responsive-file-manager',
'type': 'button',
'html': $uploadIcon,
'on': {
'click': () => _openFileManager()
}
});
const $removeButton = $('<a/>', {
'class': 'btn responsive-file-manager',
'type': 'button',
'html': $removeIcon,
'on': {
'click': () => $input.val('')
}
});
const $span = $('<span/>', {
'class': 'input-group-btn'
});
const $container = $('<div/>', {
'class': 'input-group responsive-file-manager'
});
$span.append($uploadButton);
$span.append($removeButton);
$container.append($input).append($span);
$this.append($container);
},
fallback: () => {
const $input = $('<input/>', {
'name': options.name,
'type': 'file'
});
$this.append($input);
}
};
/**
/**
* Creates the widget after the request the responsive file manager
* request is being made. After the request, either the 'responsive'
* widget is created or the fallback, depending on if the file manager
* is available.
*
* @param done Done callback function for module.init.
*/
const _createWidget = done => {
jse.libs.xhr.get({url: fileManagerConfigurationUrl})
.done(response => jse.core.registry.set(cacheKey, response.isInstalled ? 'responsive' : 'fallback'))
.fail(() => jse.core.registry.set(cacheKey, 'fallback'))
.always(() => {
// Create the file manager or fallback.
factory[jse.core.registry.get(cacheKey)]();
done();
});
};
/**
* Creates the widget when the cache key changes from pending.
* After the cache key changed to either the 'responsive' or 'fallback',
* the according widget will be created, depending on if the file manager
* is available.
*
* @param done Done callback function for module.init.
*/
const _createWidgetWhenCacheKeyAvailable = done => {
const interval = setInterval(() => {
if (jse.core.registry.get(cacheKey) !== 'pending') {
clearInterval(interval);
// Create the file manager or fallback.
factory[jse.core.registry.get(cacheKey)]();
done();
}
}, 100);
};
// ------------------------------------------------------------------------
// OPENING THE FILE MANAGER
// ------------------------------------------------------------------------
/**
* Opens the file manager in a new window popup.
*/
const _openFMPopup = () => {
const w = 990;
const h = 600;
const l = Math.floor((screen.width - w) / 2);
const t = Math.floor((screen.height - h) / 2);
window.open(_getFMUrl(), 'ResponsiveFilemanager', "scrollbars=1,width=" + w + ",height=" + h
+ ",top="
+ t + ",left=" + l);
};
/**
* Opens the file manager in a bootstrap modal.
*/
const _openFMModal = () => {
// Use the fallback if bootstraps modal function is not available.
if ($.fn.modal === undefined) {
return _openFMPopup();
}
const iFrame = `<iframe src="${_getFMUrl()}" width="100%" height="550" frameborder="0"
class="responsive-filemanager"></iframe>`;
jse.libs.modal.showMessage('Filemanager', iFrame);
_makeModalLarge();
};
/**
* Makes the modal large by adding the modal-lg css class.
*/
const _makeModalLarge = () => {
$('.modal-dialog:last').addClass('modal-lg');
};
/**
* Checks if compatibility mode is active.
*
* @returns {boolean} True on compatibility mode, false otherwise.
*/
const _isCompatibilityModeEnabled = () => {
return $('body.gx-compatibility').length !== 0;
};
/**
* Opens the file manager in a modal, dialog or window with the priority in
* the same order. If bootstrap is not available, the file
* manager will be opened in a new window.
*/
const _openFileManager = () => {
if (_isCompatibilityModeEnabled()) {
return _openFMPopup();
}
_openFMModal();
};
// ------------------------------------------------------------------------
// INITIALIZATION
// ------------------------------------------------------------------------
/**
* Initialize method of the widget, called by the engine.
*/
module.init = done => {
fieldId = guidGenerator();
// Required option not provided
if (options.contentDirectory === undefined || options.contentDirectory === '') {
jse.core.debug.error('content-directory attribute was not provided for the "filemanager" widget.');
return;
}
// Required option not provided
if (options.name === undefined || options.name === '') {
jse.core.debug.error('name attribute was not provided for the "filemanager" widget.');
return;
}
// Required option not provided
if (options.pageActive === undefined) {
jse.core.debug.error('page-active attribute was not provided for the "filemanager" widget.');
return;
}
// Module is not active at all or not active for the used page.
if (!options.pageActive) {
factory.fallback();
done();
return;
}
// No cache key available yet. Create the widget and set the cache key to 'fallback' or 'responsive'
// after the responsive has arrived (done by the _createWidget function).
if (jse.core.registry.get(cacheKey) === undefined) {
jse.core.registry.set(cacheKey, 'pending');
_createWidget(done);
return;
}
// Cache key is on 'pending' which means we have to wait until the key changes (done by the _createWidget function).
// Afterwards we can create the correct widget.
if (jse.core.registry.get(cacheKey) === 'pending') {
_createWidgetWhenCacheKeyAvailable(done);
return;
}
// Build the fallback or responsive file manager.
factory[jse.core.registry.get(cacheKey)]();
};
// Return data to module engine.
return module;
});