| Server IP : 85.158.181.41 / Your IP : 216.73.217.12 Web Server : Apache System : Linux cloud9-vm129 6.1.178+1-ph #ph SMP PREEMPT_DYNAMIC Wed Jul 29 09:00:54 UTC 2026 x86_64 User : moncbefd ( 1024) PHP Version : 7.3.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/moncbefd/www.moneta.at/StyleEdit3/javascript/controllers/ |
Upload File : |
/* --------------------------------------------------------------
EditStyleView.js 2019-06-07
Gambio GmbH
http://www.gambio.de
Copyright (c) 2019 Gambio GmbH
Released under the GNU General Public License (Version 2)
[http://www.gnu.org/licenses/gpl-2.0.html]
--------------------------------------------------------------*/
/* globals -Modal */
'use strict';
import JsonParser from '../libs/JsonParser';
import Modal from '../libs/Modal';
import Router from '../libs/Router';
import EventsEmitter from '../libs/EventsEmitter';
import WidgetConverter from '../libs/WidgetConverter';
import StyleApi from '../api/StyleApi';
import CacheApi from '../api/CacheApi';
import FilterBox from '../widgets/FilterBox';
/**
* Edit Style View Controller
*
* This controller is responsible for the style editing view of the page. It will fetch the
* styles configuration data from the server and display them to the UI.
*/
export default class EditStyleView {
/**
* Class Constructor
*
* @param {String} styleName The style name to be edited.
*/
constructor(styleName) {
StyleEdit.Validator.isString(styleName);
/**
* The name of the loaded style.
*
* @type {String}
*/
this.styleName = styleName;
/**
* Style Configuration Entity
*
* @type {StyleConfiguration}
*/
this.styleConfiguration = null;
/**
* The original JSON string used for determining changes.
*
* @type {String}
*/
this.originalStyleJson = null;
/**
* Contains a list with the template image file names.
*
* @type {String[]}
*/
this.templateImages = null;
}
/**
* Initialize Controller
*
* @return {jQuery.Promise} Will be resolved once the method is ready.
*/
initialize() {
const deferred = $.Deferred();
StyleApi.get(this.styleName).done(response => {
// Add the template translations to the Language object.
StyleEdit.Language.addSection('template', response.lang);
// Store the template images for future reference.
this.templateImages = response.images;
// Parse the JSON data and display the setting widgets.
this.styleConfiguration = JsonParser.decodeStyleConfiguration(response.config);
// Store the response for future reference (see _onClickBack function).
this.originalStyleJson = JsonParser.encodeStyleConfiguration(this.styleConfiguration);
this._loadViewTemplate();
EventsEmitter.triggerControllerInitialized($('.style-edit-view'), ['EditStyleView']);
deferred.resolve();
});
return deferred.promise();
}
/**
* Destroy Controller
*
* @return {jQuery.Promise} Will be resolved once the method is ready.
*/
destroy() {
const deferred = $.Deferred();
const $styleEditView = $('.style-edit-view');
$('.edit-options-container').perfectScrollbar('destroy');
$styleEditView.fadeOut(300, () => {
$styleEditView.html(''); // Remove the HTML code.
deferred.resolve();
EventsEmitter.triggerControllerDestroyed($styleEditView, ['EditStyleView']);
});
$('.edit-style-view, .edit-options-container .option').off();
$(window)
.off('resize')
.off('beforeunload')
.off('StyleEdit.CustomStylesChanged');
return deferred.promise();
}
/**
* Event: Save Button Click
*
* Save the current style configuration settings and display a success notification.
*
* @private
*/
_onClickSave() {
StyleApi.save(this.styleConfiguration).done(() => {
// Display dialog with success message.
const title = StyleEdit.Language.translate('title_style_saved_successfully', 'style_edit');
const message = StyleEdit.Language.translate('message_style_saved_successfully', 'style_edit');
let interval;
Modal.message(title, message).done(() => {
clearInterval(interval);
});
// The modal will close automatically in 3 seconds.
const $modal = $('.style-edit-modal:visible');
const buttonText = $modal.find('.btn.ok').text();
let secondsLeft = 3;
$modal.find('.btn.ok').text(buttonText + ' (' + secondsLeft + ')');
interval = setInterval(() => {
secondsLeft--;
if (secondsLeft === 0) {
$modal.find('.btn.ok').click();
return;
}
$modal.find('.btn.ok').text(buttonText + ' (' + secondsLeft + ')');
}, 1000);
// Save a copy of the current style for later use.
this.originalStyleJson = JsonParser.encodeStyleConfiguration(this.styleConfiguration);
// We need to clear the cache of the saved style. This can only be done by making a GET request to the
// "gm_dynamic.css.php" with the "renew_cache" parameter. Once the request is done the iframe preview
// needs to be reloaded.
const mainCssUrl = StyleEdit.Config.get('previewUrl') + '/'
+ $('#main-css', $('.style-edit-preview iframe').contents()).attr('href');
CacheApi.renew(mainCssUrl, this.styleConfiguration.getName()).done(() => {
this._reloadTemplatePreview(this.styleConfiguration.getName());
});
// If the current style is active, refresh its cache through another GET request.
if (this.styleConfiguration.isActive()) {
CacheApi.renew(mainCssUrl);
}
});
}
/**
* Event: Preview Button Click
*
* This callback must refresh the template preview based on the current settings.
*
* @private
*/
_onClickPreview() {
StyleApi.save(this.styleConfiguration, StyleEdit.Config.get('tempStyleName')).done(() => {
const mainCssUrl = StyleEdit.Config.get('previewUrl') + '/'
+ $('#main-css', $('.style-edit-preview iframe').contents()).attr('href');
CacheApi.renew(mainCssUrl, StyleEdit.Config.get('tempStyleName')).done(() => {
this._reloadTemplatePreview(StyleEdit.Config.get('tempStyleName'));
});
});
}
/**
* Event: Back Button Click
*
* This method must return the StyleEdit back to the styles list view. It must display a warning
* if the user has unsaved changes.
*
* @private
*/
_onClickBack() {
this._validateUnsavedChanges().done(() => this._goBackToMyStylesView());
}
/**
* Event: Add Custom CSS Click
*
* This callback must display the custom styles modal where the user is able to write
* his own CSS or SASS to be included in the template styling.
*
* @private
*/
_onClickAddCustomCss() {
Router.load('CustomStylesModal', [this.styleConfiguration.getCustomStyles()]);
}
/**
* Event: Activate Button Click
*
* This button must activate the current style.
*
* @param {jQuery.Event} event
*
* @private
*/
_onClickActivate(event) {
const $element = $(event.currentTarget);
StyleApi.activate(this.styleName).done(() => {
const html = `<span class="status">${StyleEdit.Language.translate('label_active', 'style_edit')}</span>`;
$('.edit-style-view .headline .date-status').append(html);
$element
.add($element.siblings('.action.delete'))
.remove();
});
}
/**
* Event: Delete Button Click
*
* Delete the current style. This callback must display a modal prompt to the user before
* removing the style.
*
* @private
*/
_onClickDelete() {
const title = StyleEdit.Language.translate('title_delete_style_modal', 'style_edit');
const message = StyleEdit.Language.translate('message_delete_style_modal', 'style_edit');
Modal.prompt(title, message).done(() => {
StyleApi.delete(this.styleName).done(response => {
EventsEmitter.triggerStyleDeleted($('.edit-style-view'), [response]);
this.destroy().done(() => Router.load('MyStylesView'));
});
});
}
/**
* Event: Option Group Bar Click
*
* @param {jQuery.Event} event
*
* @private
*/
_onClickOptionGroupBar(event) {
$(event.currentTarget).parent().toggleClass('open');
$('.edit-options-container').perfectScrollbar('update');
}
/**
* Event: Window Resize
*
* @private
*/
_onWindowResize() {
this._resizeOptionsContainer();
}
/**
* Event: On Window Before Unload
*
* Check if there are unsaved changes.
*
* @param {jQuery.Event} event
*
* @private
*/
_onWindowBeforeUnload(event) {
const currentStyleJson = JsonParser.encodeStyleConfiguration(this.styleConfiguration);
if (currentStyleJson !== this.originalStyleJson) {
const message = StyleEdit.Language.translate('message_unsaved_changes', 'style_edit');
event.returnValue = message;
return message;
}
}
/**
* Event: Re-order the box settings.
*
* This method will update the position of the box settings.
*
* @param {jQuery.Event} event
*
* @private
*/
_onUpdateBoxPositions(event) {
$(event.currentTarget).find('.form-group').each((index, formGroup) => {
const $element = $(formGroup);
$.each(this.styleConfiguration.getSettings(), (index, collection) => {
if (collection.getType() === 'boxes') {
$.each(collection.getEntries(), (index, boxSetting) => {
if (boxSetting.getName() === $element.find('input:checkbox').attr('id')) {
boxSetting.setPosition($element.index() + 1);
}
});
}
});
});
}
/**
* Event: Custom Styles Changed
*
* @param {jQuery.Event} event
* @param {String} customStyles Contains the new custom CSS.
*
* @private
*/
_onCustomStylesChanged(event, customStyles) {
StyleEdit.Validator.isString(customStyles);
this.styleConfiguration.setCustomStyles(customStyles);
}
/**
* Navigates back to MyStylesView controller.
*
* @private
*/
_goBackToMyStylesView() {
this.destroy().done(() => Router.load('MyStylesView', [this.styleName]));
}
/**
* Reload the template preview.
*
* @param {String} styleName Style name will be provided as a GET parameter to the shop.
*
* @private
*/
_reloadTemplatePreview(styleName) {
StyleEdit.Validator.isString(styleName);
let url = $('.style-edit-preview iframe').get(0).contentWindow.location.href;
const parameter = 'style_edit_style_name=' + encodeURIComponent(styleName);
if (url.indexOf('style_edit_style_name=') > -1) {
url = url.replace(/style_edit_style_name=.*/g, parameter);
} else if (url.indexOf('?') === -1) {
url += '?' + parameter;
} else {
url += '&' + parameter;
}
$('.style-edit-preview iframe').get(0).contentWindow.location.href = url;
EventsEmitter.triggerPreviewReloaded($('.edit-style-view'), [styleName]);
}
/**
* Bind event handlers for the settings view.
*
* @private
*/
_bindEventHandlers() {
$('.edit-style-view')
.off('click')
.on('click', '.btn.save', () => this._onClickSave())
.on('click', '.btn.preview', () => this._onClickPreview())
.on('click', '.btn.back', () => this._onClickBack())
.on('click', '.action.activate', event => this._onClickActivate(event))
.on('click', '.action.delete', () => this._onClickDelete())
.on('click', '.action.add-custom-css', () => this._onClickAddCustomCss())
.on('sortupdate', '.dropdown-menu.ui-sortable', event => this._onUpdateBoxPositions(event));
$('.edit-options-container .option')
.off('click')
.on('click', '.icon, .info, .dropdown-icon', event => this._onClickOptionGroupBar(event));
$(window)
.on('resize', () => this._onWindowResize())
.on('beforeunload', event => this._onWindowBeforeUnload(event))
.on('StyleEdit.CustomStylesChanged', (event, customStyles) => this._onCustomStylesChanged(event, customStyles));
}
/**
* Resize Options Container
*
* @private
*/
_resizeOptionsContainer() {
const editOptionsContainerHeight = window.innerHeight
- $('.style-edit-headline').outerHeight()
- $('.edit-style-view .headline').outerHeight()
- $('.edit-style-view .footer-container').outerHeight();
$('.edit-options-container').height(editOptionsContainerHeight);
}
/**
* Set Local Storage Color Palette
*
* The colorpicker widgets share their palette through the "style_edit_color_palette" item in the
* browser's local storage.
*
* @param {String} colorPalette Contains the colors to be written in local storage.
*
* @private
*/
_setLocalStorageColorPalette(colorPalette) {
StyleEdit.Validator.isObject(colorPalette);
if (window.localStorage === undefined) {
StyleEdit.Debug.warn('Local storage is not supported, no color palette will be set.');
return; // local storage is not supported
}
const storageKey = StyleEdit.Config.get('localStorageColorPalette');
localStorage.removeItem(storageKey);
localStorage.setItem(storageKey, ';' + colorPalette.join(';'));
}
/**
* Validated whether there are unsaved changes.
*
* Use this method before leaving the EditStyleView to validate whether there are unsaved changes.
*
* @return {jQuery.Promise} Returns a promise that will be resolved if the user really wants to leave the page.
*
* @private
*/
_validateUnsavedChanges() {
// Workaround for quickly checking if there are any changes is to encode the "styleConfiguration"
// and the "originalStyleJson".
const currentStyleJson = JsonParser.encodeStyleConfiguration(this.styleConfiguration);
let promise;
if (currentStyleJson !== this.originalStyleJson) {
const title = StyleEdit.Language.translate('title_unsaved_changes', 'style_edit');
const message = StyleEdit.Language.translate('message_unsaved_changes', 'style_edit');
promise = Modal.prompt(title, message);
} else {
promise = $.Deferred().resolve(); // Nothing was changed.
}
return promise;
}
/**
* Load the settings template view.
*
* This method will create the correct HTML for the style settings by using the
* StyleConfiguration object.
*
* @private
*/
_loadViewTemplate() {
if (this.styleConfiguration === null) {
throw new Error('The controller was not initialized properly! There is no style configuration set.');
}
const template = $('#edit-style-view-template').html();
const data = JsonParser.encodeStyleConfiguration(this.styleConfiguration, false);
let newEntriesArray;
const widgetInstances = [];
const colorPalette = [];
const dateFormat = StyleEdit.Config.get('languageCode') === 'de' ? 'dd.MM.yyyy' : 'MM.dd.yyyy';
// Add translations and other labels.
data.label_active = StyleEdit.Language.translate('label_active', 'style_edit');
data.option_add_custom_css = StyleEdit.Language.translate('option_add_custom_css', 'style_edit');
data.option_activate = StyleEdit.Language.translate('option_activate', 'style_edit');
data.option_delete = StyleEdit.Language.translate('option_delete', 'style_edit');
data.modificationDate = Date.parse(data.modificationDate).toString(dateFormat);
data.option_save = StyleEdit.Language.translate('option_save', 'style_edit');
data.option_preview = StyleEdit.Language.translate('option_preview', 'style_edit');
data.option_back = StyleEdit.Language.translate('option_back', 'style_edit');
$.each(data.settings, (index, collection) => {
collection.title = StyleEdit.Language.translate(collection.name, 'template');
newEntriesArray = []; // reset array
if (collection.type === 'boxes') {
collection.entries.sort((a, b) => {
if (a.position < b.position) {
return -1;
} else if (a.position > b.position) {
return 1;
}
return 0;
});
}
$.each(collection.entries, (index, entry) => {
// Check if the setting is a color and if it belongs in the color palette.
if (data.colorPalette) {
$.each(data.colorPalette, (index, variableName) => {
if (variableName === entry.name && entry.type === 'color') {
colorPalette.push(entry.value);
}
});
}
// Create the setting instance.
try {
const widgetInstance = WidgetConverter.convertSettingToWidget(entry, this.styleConfiguration,
this.templateImages);
// Push the instances to their respective arrays.
newEntriesArray.push(widgetInstance);
widgetInstances.push(widgetInstance);
} catch (exception) {
StyleEdit.Debug.error('StyleEdit Error: ', exception);
return true; // continue
}
});
collection.entries = newEntriesArray;
});
// Render the template and bind the event handlers.
$('.style-edit-view').html(Mustache.render(template, data)).fadeIn();
this._bindEventHandlers();
// Initialize the widgets
$.each(widgetInstances, (index, widget) => {
widget.initialize(); // will bind the event handlers
});
// Set the local storage color palette so that wall the colorpickers share the same palette.
this._setLocalStorageColorPalette(colorPalette);
// Add material design effects to new objects.
$.material.init();
// Add sortable functionality to boxes.
$('.style-edit-view .form-group .fa-bars')
.parents('.dropdown-menu')
.sortable({
axis: 'y',
opacity: 0.5,
containment: 'parent'
});
// Add scrollbars.
this._resizeOptionsContainer();
$('.edit-options-container').perfectScrollbar();
// Initialize the filter box widget.
this.filterBox = new FilterBox($('.filter-box-wrapper'), $('.edit-options'), $('.edit-options-container'),
this.styleConfiguration);
this.filterBox.initialize();
}
}