File: D:/HostingSpaces/ReturnIndustries/return-industries.nl/wwwroot/js/kms/attributes.js
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
/**
* Knows how to copy component area data to other component areas
*/
var ComponentAreaCopier =
/*#__PURE__*/
function () {
function ComponentAreaCopier() {
_classCallCheck(this, ComponentAreaCopier);
var self = this;
this._componentAreaManagers = []; //An array of componentAreaManagers
this._registerButtonClickListenersDebounced = this.debounce(function () {
self._registerButtonClickListeners();
}, 50);
}
/**
* Copy the contents of one component area to another one
*
* @param {ComponentAreaManager} fromComponentAreaManager
* @param {ComponentAreaManager} toComponentAreaManager
* @private
*/
_createClass(ComponentAreaCopier, [{
key: "_copy",
value: function _copy(fromComponentAreaManager, toComponentAreaManager) {
//Get the component area savestate which contains all source info we need to have to make the copy possible
var saveState = fromComponentAreaManager.getComponentAreaSaveState(); //Copy it by giving the destination component area manager the save state
toComponentAreaManager.addNewComponentsBasedOnComponentAreaSaveState(saveState);
}
/**
* Make the componentAreaCopier aware of a component area manager
* So that other componentAreaManagers can be copied to it.
*
* @param {ComponentAreaManager} componentAreaManager
*/
}, {
key: "registerComponentAreaManager",
value: function registerComponentAreaManager(componentAreaManager) {
if (!(componentAreaManager instanceof ComponentAreaManager)) {
console.error('ComponentAreaCopier: Could not register a component area manager since that was not an instance of ComponentAreaManager. Was:', componentAreaManager);
return;
}
this._componentAreaManagers.push(componentAreaManager);
this._registerButtonClickListenersDebounced();
}
/**
* Registers click event listeners on the component area's copy buttons.
*
* @private
*/
}, {
key: "_registerButtonClickListeners",
value: function _registerButtonClickListeners() {
var self = this;
this._componentAreaManagers.forEach(
/** @param {ComponentAreaManager} componentAreaManager **/
function (componentAreaManager) {
//Find the copy button in the component area
var selector = '.js-component-area-button';
var button = componentAreaManager.getWrapperElement().querySelector(selector);
if (!button) {
console.error('ComponentAreaCopier: Could not find the copy button in the following componentAreaManager using this selector "' + selector + '": ', componentAreaManager);
return;
} //The confirmation controller handles the onClick on the copy button, But only when the user confirms the action. When he confirms the action, we trigger the _onClick method
new ConfirmationController(button).setConfirmCallback(function (componentAreaManager) {
return function () {
self._onClick(componentAreaManager);
};
}(componentAreaManager));
});
}
/**
* Triggered when the user clicked the copy button and confirmed the copy
*
* {ComponentAreaManager} componentAreaManager
* @private
*/
}, {
key: "_onClick",
value: function _onClick(componentAreaManager) {
//Find the select in the component area
var selector = '.js-component-area-select';
var select = componentAreaManager.getWrapperElement().querySelector(selector);
if (!select) {
console.error('ComponentAreaCopier: Could not find the select in the following componentAreaManager using this selector "' + selector + '": ', componentAreaManager);
return;
} //Get the destination component area manager. Or display an error when we don't find it.
var toComponentAreaManager = this._findComponentAreaManagerByWrapperId(select.value);
if (!toComponentAreaManager) {
console.error('componentAreaCopier: could not copy the structure of ' + componentAreaManager.getWrapperElement().id + ' to ' + select.value);
return;
} //Make the copy
this._copy(componentAreaManager, toComponentAreaManager); //Determine if we need to change to another tab. If so, change to that tab
var selectedOption = select.children[select.selectedIndex];
if (selectedOption && 'tab' in selectedOption.dataset) {
var tabToChangeTo = selectedOption.dataset.tab;
window.location.hash = '#' + tabToChangeTo; //Change to that tab.
} //Disable all copy notifications. Event outside the component area managers we managae
document.querySelectorAll('.js-component-area-confirmation').forEach(function (confirmationTextElement) {
confirmationTextElement.classList.remove('active');
}); //Show the copy confirmation in the the destination component area manager wrapper.
var notification = toComponentAreaManager.getWrapperElement().querySelector('.js-component-area-confirmation');
notification.classList.add('active');
}
/**
* @param id
* @private
* @return {ComponentAreaManager|null}
*/
}, {
key: "_findComponentAreaManagerByWrapperId",
value: function _findComponentAreaManagerByWrapperId(id) {
var componentAreaManagersCount = this._componentAreaManagers.length;
for (var index = 0; index < componentAreaManagersCount; index++) {
/** @param {ComponentAreaManager} componentAreaManager **/
var componentAreaManager = this._componentAreaManagers[index];
if (id === componentAreaManager.getWrapperElement().id) return componentAreaManager;
}
return null;
}
/**
* Triggers the function after the wait time (milliseconds) has expired and only
* if the function is not triggered again before the wait time expired.
*
* @param func
* @param wait
* @param immediate
* @returns {Function}
*/
}, {
key: "debounce",
value: function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this,
args = arguments;
var later = function later() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
}]);
return ComponentAreaCopier;
}();
/**
* The main class to manage components
*/
var ComponentAreaManager =
/*#__PURE__*/
function () {
/**
* @param {HTMLDivElement} wrapper
* @param {ComponentManagerApiController} componentManagerApiController
*/
function ComponentAreaManager(wrapper, componentManagerApiController) {
_classCallCheck(this, ComponentAreaManager);
this._componentAreaWrapperElement = wrapper;
this._componentManagerApiController = componentManagerApiController;
if (this._componentAreaWrapperElement === undefined || this._componentAreaWrapperElement.tagName !== "DIV") {
console.error('ComponentAreaManager:constructor Did not get the expected div element that represents the components wrapper.');
return;
}
if (this._componentManagerApiController === undefined) {
console.error('ComponentAreaManager:constructor Did not get the expected _componentManagerApiController.');
return;
}
this._componentAreaAttributeKey = this._componentAreaWrapperElement.id; //Get the input field for the components attribute that will hold all data for the components attribute values.
this._masterInput = this._componentAreaWrapperElement.querySelector('input[name="' + this._componentAreaAttributeKey + '"]');
if (!this._masterInput) {
console.error('ComponentAreaManager:constructor Did not find an hidden input with name "' + this._componentAreaAttributeKey + '" inside of the wrapper.');
return;
}
this._componentAreaContainer = this._componentAreaWrapperElement.querySelector('.js-components');
if (!this._componentAreaContainer) {
console.error('ComponentAreaManager:constructor the wrapper did not contain a div with class components.');
return;
}
if (!'componentAttributeFieldsRegex' in this._componentAreaWrapperElement.dataset) {
console.error('The wrapper element must, but did not have a componentAttributeFieldsRegex dataset value');
return;
}
this._componentAttributeFieldsRegex = this._componentAreaWrapperElement.dataset.componentAttributeFieldsRegex;
this._saveVersion = '0.9.1';
this._addComponentButtonElements = [];
this._eventMap = {};
this._loaded = false;
this._setAddComponentButtonElements();
this._loadComponentsUsingSaveStateData();
}
/**
* Sets up the add component buttons by finding them in the wrapper and adding listeners to them
*/
_createClass(ComponentAreaManager, [{
key: "_setAddComponentButtonElements",
value: function _setAddComponentButtonElements() {
this._addComponentButtonElements = this._componentAreaWrapperElement.querySelectorAll(".js-add-component");
var addComponentButtonsElementsLength = this._addComponentButtonElements.length;
for (var index = 0; index < addComponentButtonsElementsLength; index++) {
var currentAddComponentButtonElement = this._addComponentButtonElements[index];
currentAddComponentButtonElement.addEventListener('click', this._addComponentButtonClicked.bind(this));
}
}
/**
* Click handler for add component buttons
*
* @param {MouseEvent} mouseEvent
*/
}, {
key: "_addComponentButtonClicked",
value: function _addComponentButtonClicked(mouseEvent) {
var self = this;
mouseEvent.preventDefault();
var button = mouseEvent.target;
if (!'component' in button.dataset) {
console.error('ComponentAreaManager: One of the add component buttons was missing the component dataset attribute. Please set it to the name of a valid component');
return;
}
var componentSaveState = new ComponentSaveState();
componentSaveState.id = parseInt(self._componentAreaWrapperElement.dataset.timesAddedComponent) * -1;
componentSaveState.componentTypeId = parseInt(button.dataset.componentType); //The id of the component to resolve
componentSaveState.sortOrder = 0;
this._componentManagerApiController.getComponentHtmlElement(componentSaveState, this._componentAreaWrapperElement.id).then(function (data) {
self.incrementTimesComponentAddedCounter();
var componentHtmlElement = data.element;
self._addComponent(componentHtmlElement);
self._updateMasterInput();
});
}
/**
* Adds new components based on the component area savestate from another component area manager
*
* @param {ComponentAreaSaveState} originalComponentAreaSaveState
*/
}, {
key: "addNewComponentsBasedOnComponentAreaSaveState",
value: function addNewComponentsBasedOnComponentAreaSaveState(originalComponentAreaSaveState) {
if (!(originalComponentAreaSaveState instanceof ComponentAreaSaveState)) {
console.error('ComponentAreaManager: The given "originalComponentAreaSaveState" parameter was not an instance of ComponentAreaSaveState. Not adding its components.');
}
var self = this;
var componentsCount = originalComponentAreaSaveState.componentsCount;
for (var index = 0; index < componentsCount; index++) {
//Get the component save state and its type to make the copy
var originalComponentSaveState = originalComponentAreaSaveState.getComponentSavestateAt(index); //Create a new component save state based on the original
var componentSaveState = new ComponentSaveState();
componentSaveState.id = parseInt(self._componentAreaWrapperElement.dataset.timesAddedComponent) * -1;
componentSaveState.componentTypeId = originalComponentSaveState.componentTypeId; //The id of the component to resolve
componentSaveState.sortOrder = 0; //Add the components after loading it from the api
this._componentManagerApiController.getComponentHtmlElement(componentSaveState, this._componentAreaWrapperElement.id).then(function (data) {
self.incrementTimesComponentAddedCounter();
var componentHtmlElement = data.element;
self._addComponent(componentHtmlElement);
self._updateMasterInput();
});
}
}
/**
* Increments the counter that keeps track of how often a component was added before saving.
*/
}, {
key: "incrementTimesComponentAddedCounter",
value: function incrementTimesComponentAddedCounter() {
return this._componentAreaWrapperElement.dataset.timesAddedComponent = (parseInt(this._componentAreaWrapperElement.dataset.timesAddedComponent) + 1).toString();
}
/**
* Adds a component to the component wrapper and add listeners to it to detect changes
* {HTMLElement} componentHtmlElement
* {Number} position
*/
}, {
key: "_addComponent",
value: function _addComponent(componentHtmlElement) {
var self = this; //Add listeners to the attributes to detect changes and trigger a master input update
var foundComponentInputsModel = this._findAttributeDataInputs(componentHtmlElement);
var inputsCount = foundComponentInputsModel.inputElements.length;
for (var index = 0; index < inputsCount; index++) {
var input = foundComponentInputsModel.inputElements[index];
var debouncedKeyFunction = self._debounce(self._attributeInputChanged.bind(self), 500);
input.addEventListener('change', self._attributeInputChanged.bind(self));
input.addEventListener('blur', self._attributeInputChanged.bind(self));
input.addEventListener('keydown', debouncedKeyFunction.bind(self));
} //Add listeners to componentable attributes to detect changes and trigger a master input update
var componentableComponentInputs = this._findComponentableInputs(componentHtmlElement);
var componentableInputsCount = foundComponentInputsModel.inputElements.length;
for (var _index = 0; _index < componentableInputsCount; _index++) {
var _input = componentableComponentInputs.inputElements[_index];
if (!_input) continue;
var _debouncedKeyFunction = self._debounce(self._attributeInputChanged.bind(self), 500);
_input.addEventListener('change', self._attributeInputChanged.bind(self));
_input.addEventListener('blur', self._attributeInputChanged.bind(self));
_input.addEventListener('keydown', _debouncedKeyFunction.bind(self));
} //Make the delete button work
var deleteButton = componentHtmlElement.querySelector('.js-component-delete');
deleteButton.addEventListener('click', function (event) {
event.preventDefault();
componentHtmlElement.parentElement.removeChild(componentHtmlElement);
self._updateMasterInput();
}); //Make the move down button work
var downButton = componentHtmlElement.querySelector('.js-component-move-up');
downButton.addEventListener('click', function (event) {
event.preventDefault();
if (componentHtmlElement.previousSibling) {
componentHtmlElement.parentElement.insertBefore(componentHtmlElement, componentHtmlElement.previousSibling);
}
self._updateMasterInput();
}); //Make the move up button work
var upButton = componentHtmlElement.querySelector('.js-component-move-down');
upButton.addEventListener('click', function (event) {
event.preventDefault();
if (componentHtmlElement.nextSibling && componentHtmlElement.nextSibling.nextSibling) {
componentHtmlElement.parentElement.insertBefore(componentHtmlElement, componentHtmlElement.nextSibling.nextSibling);
} else {
componentHtmlElement.parentElement.appendChild(componentHtmlElement);
}
self._updateMasterInput();
}); //Put some of the component's attributes in tabs when needed
this._putComponentAttributesInTabs(componentHtmlElement); //Add the component
this._componentAreaContainer.appendChild(componentHtmlElement);
this.triggerEvent('componentAdded', [componentHtmlElement, this._loaded]);
}
/**
* Triggered when an attribute input was changed.
*
* @param event
*/
}, {
key: "_attributeInputChanged",
value: function _attributeInputChanged(event) {
this._updateMasterInput();
}
/**
* updates the master input which holds all attribute values
*/
}, {
key: "_updateMasterInput",
value: function _updateMasterInput() {
var self = this;
var componentAreaSaveState = this.getComponentAreaSaveState();
self._masterInput.value = JSON.stringify(componentAreaSaveState);
}
}, {
key: "_putComponentAttributesInTabs",
value: function _putComponentAttributesInTabs(componentElement) {
//Validate that we did get a component element, or show error and return;
var attributeWrapper = componentElement.querySelector('.attributes');
if (!attributeWrapper) {
console.error('Expected to get a "componentElement" but did not. It did not contain a div with class "attributes" in it.');
return;
} //Retrieve the attributes in the component and store the length
var attributes = attributeWrapper.children;
var attributesCount = attributes.length; //Create tab configuration that we use to build the tabs later on. Each property represents a tab name.
//each property value is an array of attribute elements that belong to the tab name.
var tabsConfiguration = {};
for (var i = 0; i < attributesCount; i++) {
var attributeElement = attributes[i];
if ("tab" in attributeElement.dataset) {
if (!tabsConfiguration.hasOwnProperty(attributeElement.dataset.tab)) tabsConfiguration[attributeElement.dataset.tab] = [];
tabsConfiguration[attributeElement.dataset.tab].push(attributeElement);
}
} //Now build tabs if the tabsConfiguration object has children
var tabsCount = Object.keys(tabsConfiguration).length;
if (tabsCount > 0) {
//First build the tab "framework" html and add it to the attributes container
var domParser = new DOMParser();
var _document = domParser.parseFromString('<div class="component-tab">' + //Note check kms.js. It uses the class name to make the tabs work
' <ul class="component-tab__list">' + ' </ul>' + ' <div class="component-tab__container">' + ' </div>' + '</div>', 'text/html');
var componentTab = _document.body.firstChild;
attributeWrapper.appendChild(componentTab); //Build and add tabs. And put the attributes inside the correct ones
var index = 0;
var _loop = function _loop(tabName) {
if (!tabsConfiguration.hasOwnProperty(tabName)) return "continue"; //Skip "tabName" if it is a property on the objects prototype
//Create the tab switch button to switch to the first tab
_document = domParser.parseFromString('<li class="component-tab__list-item">' + ' <a class="component-tab__button">' + tabName + '</a>' + '</li>', 'text/html');
var tabSwitchButton = _document.body.firstChild; //Add the tabSwitchButton to the tab list
var tabList = componentTab.getElementsByClassName('component-tab__list')[0];
tabList.appendChild(tabSwitchButton); //Create the content holder
_document = domParser.parseFromString('<div class="component-tab__content"></div>', 'text/html');
var tabContent = _document.body.firstChild; //Add the content holder in the componentTab container
var container = componentTab.getElementsByClassName('component-tab__container')[0];
container.appendChild(tabContent); //Put the attributes in the tab content holder
var attributesCount = tabsConfiguration[tabName].length;
for (var _i = 0; _i < attributesCount; _i++) {
tabContent.appendChild(tabsConfiguration[tabName][_i]);
} //Make the first tab active
if (index === 0) {
tabSwitchButton.classList.add('active');
tabContent.classList.add('active');
} //Make the button switch to the correct tab by using the is-active classes
tabSwitchButton.addEventListener('click', function (clickEvent) {
clickEvent.preventDefault();
var activeTabIndex = 0;
for (var tabSwitchButtonIndex = 0; tabSwitchButtonIndex < tabsCount; tabSwitchButtonIndex++) {
var currentTabSwitchButton = tabList.children[tabSwitchButtonIndex];
currentTabSwitchButton.classList.remove('active');
if (currentTabSwitchButton === tabSwitchButton) {
currentTabSwitchButton.classList.add('active');
activeTabIndex = tabSwitchButtonIndex;
}
}
for (var tabContentIndex = 0; tabContentIndex < tabsCount; tabContentIndex++) {
var currentTabContent = container.children[tabContentIndex];
currentTabContent.classList.remove('active');
if (tabContentIndex === activeTabIndex) currentTabContent.classList.add('active');
}
});
index++;
};
for (var tabName in tabsConfiguration) {
var _ret = _loop(tabName);
if (_ret === "continue") continue;
}
}
}
/**
* Does search inputs, textarea's and select's in the given component div element or else inside of
* the componentsWrapper and checks if they match against the regex that identifies them as attribute data fields
*
* @param {HTMLDivElement|null} componentElement
* @param {ComponentSaveState} componentSavestate to also pass when resolved
* @return {FoundComponentInputsModel}
*/
}, {
key: "_findAttributeDataInputs",
value: function _findAttributeDataInputs(componentElement) {
var componentSavestate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
var dataInputs = [];
var attributesContainer = componentElement.getElementsByClassName('attributes')[0];
var possibleDataInputs = attributesContainer.querySelectorAll('input, textarea, select');
var inputsQuantity = possibleDataInputs.length;
for (var index = 0; index < inputsQuantity; index++) {
var input = possibleDataInputs[index];
if (input.name !== undefined && input.name.match(new RegExp(this._componentAttributeFieldsRegex))) {
dataInputs.push(input);
}
}
var model = new FoundComponentInputsModel();
model.inputElements = dataInputs;
model.componentElement = componentElement;
model.componentSaveState = componentSavestate;
return model;
}
/**
* Gets the value of the select / autocomplete input for selecting a model you want to link the component to.
* Notice that the code is pretty much the same as _findAttributeDataInputs.
*
* @param {HTMLDivElement|null} componentElement
* @param {ComponentSaveState} componentSavestate to also pass when resolved
* @return {FoundComponentInputsModel}
*
* @private
*/
}, {
key: "_findComponentableInputs",
value: function _findComponentableInputs(componentElement) {
var componentSavestate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
var dataInputs = [];
var componentableSelectorsContainer = componentElement.querySelector('.componentableSelectors');
if (!componentableSelectorsContainer) return new FoundComponentInputsModel();
var possibleDataInputs = componentableSelectorsContainer.querySelectorAll('input, textarea, select');
var inputsQuantity = possibleDataInputs.length;
for (var index = 0; index < inputsQuantity; index++) {
var input = possibleDataInputs[index];
if (input.name !== undefined && input.name.match(new RegExp(this._componentAttributeFieldsRegex))) {
dataInputs.push(input);
}
}
var model = new FoundComponentInputsModel();
model.inputElements = dataInputs;
model.componentElement = componentElement;
model.componentSaveState = componentSavestate;
return model;
}
/**
* @return {NodeListOf<HTMLElementTagNameMap[HTMLDivElement]>}
*/
}, {
key: "getComponentElements",
value: function getComponentElements() {
return this._componentAreaContainer.querySelectorAll('.c-component');
}
/**
* Returns the component area wrapper div
*
* @return {HTMLElement}
*/
}, {
key: "getWrapperElement",
value: function getWrapperElement() {
return this._componentAreaWrapperElement;
}
/**
* Returns a ComponentAreaSaveState
* And contains a save version to allow non breaking updates in the future.
*
* @return ComponentAreaSaveState
*/
}, {
key: "getComponentAreaSaveState",
value: function getComponentAreaSaveState() {
var saveState = new ComponentAreaSaveState(); //Loop over all components.
var components = this.getComponentElements();
var componentsCount = components.length;
for (var componentNumber = 0; componentNumber < componentsCount; componentNumber++) {
//Loop over all attributes in the components...
var currentComponent = components[componentNumber]; // findAttributeDataInputsPromises.push(this._findAttributeDataInputs(currentComponent));
var foundComponentInputsModel = this._findAttributeDataInputs(currentComponent);
var foundComponentsInputModelForLinkable = this._findComponentableInputs(currentComponent); //Create an array of objects. The objects properties are field names and the objects values are the values of those field names
var attributeInputData = {};
var inputsCounts = foundComponentInputsModel.inputElements.length;
for (var currentInputNumber = 0; currentInputNumber < inputsCounts; currentInputNumber++) {
var currentInput = foundComponentInputsModel.inputElements[currentInputNumber];
if (currentInput.tagName === "INPUT" && currentInput.type === "file") {//Ignore file input
} else {
attributeInputData[currentInput.name] = currentInput.value;
}
} //Create an array containing one object that has a property name that corresponds to an inputs field name and the value of that property is the value of that input.
var linkableInputObject = {};
var linkableInputsCount = foundComponentsInputModelForLinkable.inputElements.length;
for (var _currentInputNumber = 0; _currentInputNumber < linkableInputsCount; _currentInputNumber++) {
var _currentInput = foundComponentsInputModelForLinkable.inputElements[_currentInputNumber];
if (_currentInput.tagName === "INPUT" && _currentInput.type === "file") {//Ignore file input
} else {
linkableInputObject[_currentInput.name] = _currentInput.value;
}
}
var componentSaveState = new ComponentSaveState();
componentSaveState.id = Number(foundComponentInputsModel.componentElement.dataset.id);
componentSaveState.componentTypeId = Number(foundComponentInputsModel.componentElement.dataset.componentTypeId);
componentSaveState.data = attributeInputData;
componentSaveState.version = this._saveVersion;
componentSaveState.sortOrder = Number(componentNumber);
componentSaveState.componentableData = linkableInputObject;
saveState.addComponentSaveState(componentSaveState);
}
return saveState;
}
/**
* Uses the master input to rebuild the saved componentarea with components with their data
*/
}, {
key: "_loadComponentsUsingSaveStateData",
value: function _loadComponentsUsingSaveStateData() {
var self = this; //Retrieve and decode the save state data
var savedData = this._masterInput.value;
if (!savedData) return false;
var saveState = ComponentAreaSaveState.fromJsonString(savedData);
if (!saveState) return false;
var getComponentHtmlElementPromises = [];
var savedComponentsCount = saveState.componentsCount;
for (var currentComponentNumber = 0; currentComponentNumber < savedComponentsCount; currentComponentNumber++) {
var currentComponentSaveState = saveState.getComponentSavestateAt(currentComponentNumber);
getComponentHtmlElementPromises.push(this._componentManagerApiController.getComponentHtmlElement(currentComponentSaveState, this._componentAreaWrapperElement.id));
}
Promise.all(getComponentHtmlElementPromises).then(function (componentDatas) {
var componentDatasCount = componentDatas.length; //Rebuild structure
for (var componentNumber = 0; componentNumber < componentDatasCount; componentNumber++) {
var componentData = componentDatas[componentNumber];
var componentHTMLElement = componentData.element;
self._addComponent(componentHTMLElement);
} //Loop over the same componentHTMLElements and fill their attribute inputs
for (var _currentComponentNumber = 0; _currentComponentNumber < componentDatasCount; _currentComponentNumber++) {
var currentComponentData = componentDatas[_currentComponentNumber];
var currentComponentSavestate = currentComponentData.componentSavestate;
var attributeData = currentComponentSavestate.data;
for (var attributeKeyName in attributeData) {
if (!attributeData.hasOwnProperty(attributeKeyName)) continue;
if (currentComponentSavestate.data.hasOwnProperty(attributeKeyName)) {
var attributeFields = self._componentAreaWrapperElement.querySelectorAll('[name="' + attributeKeyName + '"]');
var nAttributeFields = attributeFields.length;
if (nAttributeFields > 0) {
for (var index = 0; index < nAttributeFields; index++) {
attributeFields[index].value = attributeData[attributeKeyName];
}
} else {
console.error('Could not load data for field: ' + attributeKeyName + ' since it could not be found. Skipping it');
}
}
}
var componentableData = currentComponentSavestate.componentableData;
for (var _attributeKeyName in componentableData) {
if (!componentableData.hasOwnProperty(_attributeKeyName)) continue;
if (currentComponentSavestate.componentableData.hasOwnProperty(_attributeKeyName)) {
var _attributeFields = self._componentAreaWrapperElement.querySelectorAll('[name="' + _attributeKeyName + '"]');
var _nAttributeFields = _attributeFields.length;
if (_nAttributeFields > 0) {
for (var _index2 = 0; _index2 < _nAttributeFields; _index2++) {
_attributeFields[_index2].value = componentableData[_attributeKeyName];
}
} else {
console.error('Could not load data for field: ' + _attributeKeyName + ' since it could not be found. Skipping it');
}
}
}
} //sessionStorage.removeItem("componentScrollPosition");
if (isset(sessionStorage.getItem("componentScrollPosition"))) {
self._componentAreaWrapperElement.parentElement.parentElement.parentElement.scrollTop = sessionStorage.getItem("componentScrollPosition");
}
self.loaded = true;
});
}
/**
* Registers a event to a callback and returns the a reference to the event handler for that specific event
*
* @param event (string)
* @param callback (callable)
*/
}, {
key: "on",
value: function on(event, callback) {
if (!this._eventMap.hasOwnProperty(event)) this._eventMap[event] = [];
return this._eventMap[event].push(callback);
}
/**
* Call event callbacks
*
* @param event (string)
* @param eventArgs (array) an array of arguments to pass to the callback
*/
}, {
key: "triggerEvent",
value: function triggerEvent(event, eventArgs) {
if (!this._eventMap.hasOwnProperty(event)) return;
var nEvents = this._eventMap[event].length;
for (var index = 0; index < nEvents; index++) {
var callback = this._eventMap[event][index];
if (eventArgs && eventArgs.length > 0) {
callback.apply(this, eventArgs);
} else {
callback.call(this);
}
}
}
/**
* Returns a function, that, as long as it continues to be invoked, will not
* be triggered. The function will be called after it stops being called for
* N milliseconds. If `immediate` is passed, trigger the function on the
* leading edge, instead of the trailing.
*
* @param func
* @param wait
* @param immediate
* @return {Function}
*/
}, {
key: "_debounce",
value: function _debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this,
args = arguments;
var later = function later() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
}]);
return ComponentAreaManager;
}();
/**
* Used by the ComponentAreaManager to talk to the backend
*/
var ComponentManagerApiController =
/*#__PURE__*/
function () {
function ComponentManagerApiController() {
_classCallCheck(this, ComponentManagerApiController);
this.domParser = new DOMParser();
}
/**
* @param {ComponentSaveState} componentSavestate
* @param {string} componentAreaAttributeKey
* @return {Promise} that resolves with a HTMLDivElement that represents the newly requested component with it's attributes in it
*/
_createClass(ComponentManagerApiController, [{
key: "getComponentHtmlElement",
value: function getComponentHtmlElement(componentSavestate, componentAreaAttributeKey) {
var self = this;
return new Promise(function (resolve, reject) {
var postData = {
componentAreaAttributeKey: componentAreaAttributeKey,
componentSaveState: JSON.stringify(componentSavestate)
};
axios.post('/api/dynamic/component/resolve', postData).then(function (response) {
var toResolve = {
element: self._stringToHtmlElement(response.data),
componentSavestate: componentSavestate
};
resolve(toResolve);
})["catch"](function (error) {
console.error('ComponentManagerApiController:getComponentHtmlElement Could not get HTML of a component because of the following error:', error);
reject(error);
});
});
}
}, {
key: "getComponentAreaRegexForComponent",
value: function getComponentAreaRegexForComponent(componentKey) {
if (componentKey === undefined) {
console.error('ComponentManagerApiController:getComponentAreaRegexForComponent Could not get the regex for an undefined componentKey. Please specify it.');
return;
}
return new Promise(function (resolve, reject) {
axios.post('/api/dynamic/component/attribute_regex', {
componentKey: componentKey
}).then(function (response) {
resolve(response.data);
})["catch"](function (error) {
console.error('ComponentManagerApiController:getComponentAreaRegexForComponent Could not get the regex to find inputs for a component because of the following error:', error);
reject(error);
});
});
}
/**
* @return {Promise} that resolves with an array of component type names. Or rejects with the already console logged error.
*/
}, {
key: "getAllComponentTypeNames",
value: function getAllComponentTypeNames() {
return new Promise(function (resolve, reject) {
axios.get('/api/dynamic/component').then(function (response) {
return response.data; //Must be an array full of component type names
})["catch"](function (error) {
console.error('ComponentManagerApiController:getAllComponentTypeNames Could not the names of all available componentTypes because of an error:', error);
reject(error);
});
});
}
/**
* Converts a string to an HTMLElement
*
* @param {string} data
* @return {HTMLElement}
*/
}, {
key: "_stringToHtmlElement",
value: function _stringToHtmlElement(data) {
var document = this.domParser.parseFromString(data, "text/html");
return document.body.firstElementChild;
}
}]);
return ComponentManagerApiController;
}();
/**
* Holds information about a component HtmlElement, its input elements
* and the save state for that component.
*/
var FoundComponentInputsModel =
/*#__PURE__*/
function () {
function FoundComponentInputsModel() {
_classCallCheck(this, FoundComponentInputsModel);
this._inputElements = [];
this._componentElement = null;
this._componentSaveState = null;
}
/**
* @return {null|Array}
*/
_createClass(FoundComponentInputsModel, [{
key: "inputElements",
get: function get() {
return this._inputElements;
}
/**
* @param {NodeList} value
*/
,
set: function set(value) {
if (_typeof(value) !== 'object') {
//Pssst...array primitives don't exist. Don't tell anyone :)
console.error('ComponentSaveState: Did not set inputElements since the parameter was not an array. Actual: ', value);
return;
}
this._inputElements = value;
}
/**
* @return {null|HTMLDivElement}
*/
}, {
key: "componentElement",
get: function get() {
return this._componentElement;
}
/**
* @param {HTMLDivElement} value
*/
,
set: function set(value) {
if (!value instanceof HTMLDivElement) {
console.error('ComponentSaveState: Did not set componentElement since the parameter was not an HTMLDivElement.');
return;
}
this._componentElement = value;
}
/**
* @return {null|ComponentSaveState}
*/
}, {
key: "componentSaveState",
get: function get() {
return this._componentSaveState;
}
/**
* @param {null|ComponentSaveState} value
*/
,
set: function set(value) {
if (!value instanceof ComponentSaveState) {
console.error('ComponentSaveState: Did not set componentSaveState since the parameter was not ComponentSaveState.');
return;
}
this._componentSaveState = value;
}
}]);
return FoundComponentInputsModel;
}();
/**
* Represents data that can be saved and loaded for a Component.
* Always used in combination with ComponentAreaSaveState
*/
var ComponentSaveState =
/*#__PURE__*/
function () {
function ComponentSaveState() {
_classCallCheck(this, ComponentSaveState);
this._version = '0.9.1';
this._id = null;
this._componentTypeId = null;
this._data = {};
this._componentableData = {};
this._sortOrder = null;
this.toJSON = this._toJson.bind(this);
}
_createClass(ComponentSaveState, [{
key: "_toJson",
value: function _toJson() {
return {
id: this._id,
version: this._version,
componentTypeId: this._componentTypeId,
data: this._data,
componentableData: this._componentableData,
sortOrder: this._sortOrder
};
}
}, {
key: "version",
get: function get() {
return this._version;
},
set: function set(value) {
if (typeof value !== 'string') {
console.error('ComponentSaveState: Did not set version since the parameter was not a string. Actual: ', value);
return;
}
this._version = value;
}
}, {
key: "id",
get: function get() {
return this._id;
},
set: function set(value) {
if (value === "" || typeof value !== 'number') {
console.error('ComponentSaveState: Did not set the id since the parameter was not a number. Actual: ', _typeof(value), 1);
return;
}
this._id = value;
}
}, {
key: "componentTypeId",
get: function get() {
return this._componentTypeId;
},
set: function set(value) {
if (value === "" || typeof value !== 'number') {
console.error('ComponentSaveState: Did not set componentTypeId since the parameter was not a number. Actual: ', _typeof(value), 1);
return;
}
this._componentTypeId = value;
}
}, {
key: "data",
get: function get() {
return this._data;
},
set: function set(value) {
if (_typeof(value) !== 'object') {
console.error('ComponentSaveState: Did not set data since the parameter was not an object. Actual: ', value);
return;
}
this._data = value;
}
}, {
key: "sortOrder",
get: function get() {
return this._sortOrder;
},
set: function set(value) {
if (value === "" || typeof value !== 'number') {
console.error('ComponentSaveState: Did not set sortOrder since the parameter was not a number. Actual: ', value);
}
this._sortOrder = value;
}
}, {
key: "componentableData",
get: function get() {
return this._componentableData;
},
set: function set(value) {
if (_typeof(value) !== 'object') {
console.error('ComponentSaveState: Did not set componentableData since the parameter was not an object. Actual: ', value);
return;
}
this._componentableData = value;
}
}], [{
key: "fromObject",
value: function fromObject(jsonObject) {
//Validate the object
if (!jsonObject.hasOwnProperty('id') || typeof jsonObject.id !== 'number' || !jsonObject.hasOwnProperty('componentTypeId') || typeof jsonObject.componentTypeId !== 'number' || !jsonObject.hasOwnProperty('version') || typeof jsonObject.version !== 'string' || !jsonObject.hasOwnProperty('sortOrder') || typeof jsonObject.sortOrder !== 'number' || !jsonObject.hasOwnProperty('data') || _typeof(jsonObject.data) !== 'object' || !jsonObject.hasOwnProperty('componentableData') || _typeof(jsonObject.data) !== 'object') {
console.error('Could not create a ComponentSaveState instance from an object since that object did not contain all of the following properties of the correct types: id (number), componentTypeId (number), version (string), sortOrder (number), data (array object). Actual: ', jsonObject);
return;
} //Create a new instance of the current class that we return later on.
var componentSaveState = new this();
componentSaveState.id = jsonObject.id;
componentSaveState.componentTypeId = jsonObject.componentTypeId;
componentSaveState.version = jsonObject.version;
componentSaveState.sortOrder = jsonObject.sortOrder;
componentSaveState.data = jsonObject.data;
componentSaveState.componentableData = jsonObject.componentableData;
return componentSaveState;
}
}]);
return ComponentSaveState;
}();
/**
* Represents data that can be saved and loaded for a ComponentArea.
* This is the actual data container for the backend.
*/
var ComponentAreaSaveState =
/*#__PURE__*/
function () {
function ComponentAreaSaveState() {
_classCallCheck(this, ComponentAreaSaveState);
this.toJSON = this._toJson.bind(this);
this._componentSaveStates = [];
}
/**
* @param {ComponentSaveState} value
*/
_createClass(ComponentAreaSaveState, [{
key: "addComponentSaveState",
value: function addComponentSaveState(value) {
if (!value instanceof ComponentSaveState) {
console.error('ComponentAreaSaveState: The passed "componentSaveState" was not an instance of ComponentSaveState. Actual: ', value);
return;
}
this._componentSaveStates.push(value);
}
/**
*
* @param index
* @return {ComponentSaveState}
*/
}, {
key: "getComponentSavestateAt",
value: function getComponentSavestateAt(index) {
return this._componentSaveStates[index];
}
/**
*
* @return {Array}
* @private
*/
}, {
key: "_toJson",
value: function _toJson() {
return this._componentSaveStates;
}
/**
*
* @param {string} json
* @return {ComponentAreaSaveState}
*/
}, {
key: "componentsCount",
/**
* Returns the amount of components
*
* @return {number}
*/
get: function get() {
return this._componentSaveStates.length;
}
}], [{
key: "fromJsonString",
value: function fromJsonString(json) {
var jsonObject = null;
try {
jsonObject = JSON.parse(json);
} catch (e) {
console.error('ComponentAreaSaveState: The given jsonString does not represent ComponentAreaSaveState since the json string was not a valid json');
return;
} //Create a new instance of the current class that we return later on.
var componentAreaSaveState = new this(); //Create components from the saved data and put it in the new ComponentAreaSaveState instance
var componentsCount = jsonObject.length;
for (var index = 0; index < componentsCount; index++) {
var currentComponentSaveStateObject = jsonObject[index];
var currentComponentSaveState = ComponentSaveState.fromObject(currentComponentSaveStateObject);
componentAreaSaveState.addComponentSaveState(currentComponentSaveState);
}
return componentAreaSaveState;
}
}]);
return ComponentAreaSaveState;
}();
/**
* Give this class an htmlElement with a data-to-copy attribute,
* and it will copy the text in the value of the attribute to your clipboard
* when you click on it.
*/
var CopyText =
/*#__PURE__*/
function () {
function CopyText(element) {
_classCallCheck(this, CopyText);
this.element = element;
if (!'toCopy' in this.element.dataset) {
console.error('CopyText: The given element must have a data-to-copy attribute with the value that you want to copy. But did not have that attribute.', element);
}
this.addEventListeners();
}
_createClass(CopyText, [{
key: "addEventListeners",
value: function addEventListeners() {
this.element.addEventListener('click', this.clickHandler.bind(this));
}
}, {
key: "clickHandler",
value: function clickHandler(mouseEvent) {
//Prevent the event from following a button if element is a button
mouseEvent.preventDefault(); //Get the text to copy
var text = this.element.dataset.toCopy; //Temporary create an input element
var input = document.createElement('input');
document.body.appendChild(input);
input.value = text;
input.select();
document.execCommand("copy");
document.body.removeChild(input);
input = null;
}
}]);
return CopyText;
}();
/**
* Manages file inputs in a wrapper so that files
*
* @param {HTMLElement} wrapper
* @param {HTML5Uploader} HTML5Uploader
*/
var DocumentManager =
/*#__PURE__*/
function () {
function DocumentManager(wrapper, HTML5Uploader, translations) {
_classCallCheck(this, DocumentManager);
//Initialize variables
this.constructedSuccessFully = false;
this.wrapper = wrapper;
this.HTML5Uploader = HTML5Uploader;
this.illegalMoveCount = 0;
this.accept = "documentsAccept" in wrapper.dataset ? wrapper.dataset.documentsAccept : undefined;
if ("documentsKey" in wrapper.dataset) {
this.key = wrapper.dataset.documentsKey;
} else {
console.error('DocumentManager: Make sure that the wrapper contains the attributes key');
return;
}
this.translations = JSON.parse(translations);
this.isSortable = "documentsIsSortable" in wrapper.dataset ? wrapper.dataset.documentsIsSortable === "1" : false;
this.extensionThumbsFolder = "documentsExtensionThumbsFolder" in wrapper.dataset ? wrapper.dataset.documentsExtensionThumbsFolder : '/img/kms/extension_thumbs/';
this.availableExtensionThumbs = "documentsAvailableExtensionThumbs" in wrapper.dataset ? wrapper.dataset.documentsAvailableExtensionThumbs : ['svg', 'pdf', 'zip', 'rar', 'csv', 'xlsx', 'mp3', 'mp4', 'docx', 'doc', 'png', 'jpg', 'jpeg', 'gif'], this.enablePreviewsIfPossible = "documentsEnablePreviewsIfPossible" in wrapper.dataset ? wrapper.dataset.documentsEnablePreviewsIfPossible === "1" : false;
this.maxDocuments = "documentsMaxDocuments" in wrapper.dataset ? wrapper.dataset.documentsMaxDocuments : undefined;
this.imageProperties = "imageProperties" in wrapper.dataset ? wrapper.dataset.imageProperties : null;
this.subFolder = "subFolder" in wrapper.dataset ? wrapper.dataset.subFolder : 'documents';
this.eventMap = {};
var form = document.getElementById('entity-form');
if (form) {
var maxUploadSizeInBytes = form.dataset.maxUploadSize;
if (maxUploadSizeInBytes) this.maxUploadSizeInBytes = maxUploadSizeInBytes;
}
this.uploadSizeExceededMessage = 'You cannot upload more files right now. Please save these first before continuing. The limit is:';
if (wrapper == null) {
console.error('DocumentManager: The wrapper was not a valid html element. Stopping DocumentManager construction');
return;
}
var documentList = wrapper.getElementsByClassName('files')[0];
var dataInput = wrapper.querySelector('input[name="' + this.key + '"]');
if (!documentList) {
console.error('DocumentManager: The document uploader needs an ul element with class "files" in the given wrapper');
return;
}
this.documentList = documentList;
if (!dataInput) {
console.error('DocumentManager: The document uploader needs an input element with name "' + this.key + '" in the given wrapper. It is used to keep track of the states of all documents. Stopping DocumentManager construction');
return;
}
this.dataInput = dataInput;
if (!"uploadedDocuments" in wrapper.dataset) {
console.error('DocumentManager: The wrapper must have a uploadedDocuments dataset attribute containing a json string representing the uploaded documents as an array of documents. Stopping DocumentManager construction');
}
var documents = JSON.parse(this.dataInput.value);
this.constructedSuccessFully = true; //Make sure the "this" inside event callback functions are referencing to the documentManager
this._deleteDocumentButtonClicked = this._deleteDocumentButtonClicked.bind(this);
this._modifiedDocument = this._modifiedDocument.bind(this);
this._drag = this._drag.bind(this);
this._drop = this._drop.bind(this);
this._dragOver = this._dragOver.bind(this);
this._dragLeave = this._dragLeave.bind(this);
this._HTML5UploadStarted = this._HTML5UploadStarted.bind(this);
this._HTML5UploadProgress = this._HTML5UploadProgress.bind(this);
this._HTML5UploadedFile = this._HTML5UploadedFile.bind(this);
this._HTML5UploadFailedOrCanceled = this._HTML5UploadFailedOrCanceled.bind(this);
this._HTML5UploadFailedOrCanceled = this._HTML5UploadFailedOrCanceled.bind(this); //Initialize the document manager with the existing components
this._initialize(documents);
}
/**
* Initializes the setup of the document uploader.
*
* @private
* @param documents string Example structure:
* '[{
* "id": 3,
* "file_url": "uploads/products/Before 2018-01-25 at 14,48,23_1522928384.png",
* "documentable_id": 1,
* "documentable_type": "App\\Komma\\Shop\\Products\\Product\\Product",
* "created_at": "2018-04-05 11:39:44",
* "updated_at": "2018-04-05 11:39:44"
* }]'
*
*/
_createClass(DocumentManager, [{
key: "_initialize",
value: function _initialize(documents) {
if (!this.constructedSuccessFully) return;
if (documents) {
var length = documents.length;
for (var index = 0; index < length; index++) {
var initDocument = documents[index];
var documentModel = DocumentModel.fromJson(initDocument);
if (documentModel) {
this._addDocumentElement(documentModel);
} else {
console.error("DocumentManager stumbled upon a document that is not valid upon initializing: ");
console.error(initDocument);
}
}
this._sortDocuments();
}
this._updateDataInput();
this._setupHtml5Uploader();
}
/**
* Set up the html 5 uploader. Hook to its events
*
* @private
*/
}, {
key: "_setupHtml5Uploader",
value: function _setupHtml5Uploader() {
var self = this; //Uploading event binding
this.HTML5Uploader.on('uploadStart', this._HTML5UploadStarted);
this.HTML5Uploader.on('updateProgress', this._HTML5UploadProgress);
this.HTML5Uploader.on('uploadComplete', this._HTML5UploadedFile);
this.HTML5Uploader.on('uploadFailed', this._HTML5UploadFailedOrCanceled);
this.HTML5Uploader.on('uploadCanceled', this._HTML5UploadFailedOrCanceled);
}
/**
* Triggered when a HTML file upload failed to upload or was canceled.
*
* @constructor
* @private
*/
}, {
key: "_HTML5UploadFailedOrCanceled",
value: function _HTML5UploadFailedOrCanceled(file, responseText, extraData) {
var documentElement = file.documentElement;
if (!documentElement) return;
this.documentList.removeChild(documentElement);
this._updateDataInput();
alert(this.translations.upload_failed);
}
/**
* Triggered when a file was uploaded successfully
*
* @param file
* @param responseText
* @private
*/
}, {
key: "_HTML5UploadedFile",
value: function _HTML5UploadedFile(file, responseText) {
var documentElement = file.documentElement;
if (!documentElement) return;
var backendDocumentModel = JSON.parse(responseText);
var documentModel = DocumentModel.fromJson(backendDocumentModel);
this._attachDocumentModelToDocumentElement(documentElement, documentModel);
this._updateDocumentElementWithDocumentData(documentElement, documentModel);
this._updateSortOrder(); //Does also update the data input
//documentElement.querySelector('.drag-icon').classList.remove('is-hidden');
documentElement.querySelector('.thumb').classList.remove('is-uploading');
documentElement.querySelector('.percentage').remove();
}
/**
* Triggered when HTML5 Uploader made progress in uploading a file
*
* @param file
* @param percentCompleteOrNull
* @private
*/
}, {
key: "_HTML5UploadProgress",
value: function _HTML5UploadProgress(file, percentCompleteOrNull) {
var documentElement = file.documentElement;
if (!documentElement) return;
var progress = documentElement.querySelector('.percentage'); //There is still some backend processing time needed. So we don't show 100%. Only when the backend responds with a complete
if (percentCompleteOrNull && percentCompleteOrNull === 100) percentCompleteOrNull = 99;else if (!percentCompleteOrNull) percentCompleteOrNull = 1; // Update the progress value
progress.setAttribute("aria-valuenow", percentCompleteOrNull);
}
/**
* Triggered when a HTML 5 upload was started.
*
* @param file
* @private
*/
}, {
key: "_HTML5UploadStarted",
value: function _HTML5UploadStarted(file) {
var documentElement = this._createDocumentElement();
this._attachDocumentModelToDocumentElement(documentElement);
var documentModel = DocumentModel.fromJson(JSON.parse(documentElement.dataset.json));
documentModel.state = DOCUMENT_STATE_NEW;
documentModel.name = file.name;
documentModel.file_url = file.name;
documentElement = this._updateDocumentElementWithDocumentData(documentElement, documentModel);
this._attachDocumentModelToDocumentElement(documentElement, documentModel); // Add the progress element to the thumb
var progressPercentageString = '<span class="percentage" role="progressbar" aria-valuemin="0" aria-valuemax="100"></span>'; // let progressPercentage = document.createElement('span');
// progressPercentage.setAttribute('class', 'percentage');
// progressPercentage.setAttribute("role", "progressbar");
// progressPercentage.setAttribute("aria-valuemin", 0);
// progressPercentage.setAttribute("aria-valuemax", 100);
documentElement.querySelector('.thumb').insertAdjacentHTML('afterbegin', progressPercentageString);
this.documentList.appendChild(documentElement);
documentElement.querySelector('.drag-icon').classList.add('is-hidden');
documentElement.querySelector('.thumb').classList.add('is-uploading'); // documentElement.querySelector('.thumb').classList.add('has-image');
file.documentElement = documentElement;
}
/**
* Occurs when the user clicked the delete document button
*
* @param mouseEvent A javascript mouse event
* @private
*/
}, {
key: "_deleteDocumentButtonClicked",
value: function _deleteDocumentButtonClicked(mouseEvent) {
var documentElement = mouseEvent.target.parentElement;
var document = JSON.parse(documentElement.dataset.json);
if (document.state === DOCUMENT_STATE_DELETED) return;
if (document.state !== DOCUMENT_STATE_NEW) {
document.state = DOCUMENT_STATE_DELETED;
documentElement.classList.add(DOCUMENT_STATE_DELETED);
documentElement.dataset.json = JSON.stringify(document);
} else {
this.documentList.removeChild(documentElement); //A housekeeping functionality should delete it in the near future.
}
this._updateDataInput();
this._updateSortOrder();
}
/**
* Occurs when the user modified the document
*
* @param event A javascript event
* @private
*/
}, {
key: "_modifiedDocument",
value: function _modifiedDocument(event) {
var wrapper = event.target.parentElement.parentElement; //Document exists. Updates its json state and hide it.
var document = JSON.parse(wrapper.dataset.json);
if (document.state === DOCUMENT_STATE_DELETED) return;
if (document.state !== DOCUMENT_STATE_NEW) document.state = DOCUMENT_STATE_MODIFIED; //Check what is modified and update the document accordingly
var nameInput = wrapper.getElementsByClassName('name')[0];
document.name = nameInput.value;
wrapper.dataset.json = JSON.stringify(document);
wrapper.classList.add(DOCUMENT_STATE_MODIFIED);
this._updateDataInput();
}
/**
* Adds a new document element. When documentModel isn't specified, the document element wil give the user the
* ability to upload a new document by transforming that document element to a document uploader (fancy fileinput)
*
* @param documentModel DocumentModel. You only need to specify it when it is an existing document.
* @private
*/
}, {
key: "_addDocumentElement",
value: function _addDocumentElement() {
var documentModel = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;
//Create an fileInput wrapper in which we put the fileInput and delete / remove button
var documentElement = this._createDocumentElement();
if (documentModel !== undefined) this._updateDocumentElementWithDocumentData(documentElement, documentModel);
this._attachDocumentModelToDocumentElement(documentElement, documentModel); // if(documentModel === undefined) this.transformDocumentElementIntoADocumentUpload(documentElement);
//Make it dragable if needed. With this it can be sorted
if (documentModel) {
this._makeElementRespondToDragging(documentElement, this.isSortable);
this._makeElementRespondToDragOverAndLeave(documentElement, this.isSortable);
this._makeElementRespondToDrop(documentElement, this.isSortable);
} //Add the newly created HTMLElement to the document list
this.documentList.appendChild(documentElement);
}
/**
* @param documentElement {HTMLElement}
* @param documentModel {DocumentModel|undefined}
* @returns {HTMLElement} The document element
* @private
*/
}, {
key: "_attachDocumentModelToDocumentElement",
value: function _attachDocumentModelToDocumentElement(documentElement) {
var documentModel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
if (documentModel !== undefined) {
documentElement.dataset.json = JSON.stringify(documentModel);
} else {
documentModel = new DocumentModel();
documentModel.sort_order = this.getCurrentDocumentsCount() + 1;
documentElement.dataset.json = JSON.stringify(documentModel);
}
return documentElement;
}
/**
*
* @param documentElement {HTMLElement}
* @param documentModel {DocumentModel}
* @return {HTMLElement}
* @private
*/
}, {
key: "_updateDocumentElementWithDocumentData",
value: function _updateDocumentElementWithDocumentData(documentElement, documentModel) {
var nameInput = documentElement.querySelector('.name');
var fileUrl = documentElement.querySelector('.path');
var thumbImageElement = documentElement.querySelector('.thumb'); //Set the path of the document
if (fileUrl) {
fileUrl.innerText = documentModel.file_url;
} //Set the name of the document
if (nameInput) {
nameInput.setAttribute('value', documentModel.name);
} //Set the thumb image
if (thumbImageElement && documentModel.file_url) {
var thumbUrl = this._getThumbUrlUsingDocumentModel(documentModel);
var documentExtension = this._getExtensionFromFileName(documentModel.file_url);
thumbImageElement.setAttribute('data-filetype', documentExtension);
var thumbImage = thumbImageElement.querySelector('.thumb__image');
if (thumbImageElement) {
if (thumbUrl && documentModel.state !== 'new') {
thumbImage.style.backgroundImage = "url('" + thumbUrl + "')";
thumbImageElement.classList.add('has-image');
} else if (this.availableExtensionThumbs.indexOf(documentExtension) !== -1) {
thumbImage.style.backgroundImage = "url('" + this.extensionThumbsFolder + documentExtension + ".svg')";
thumbImageElement.classList.add('has-icon');
}
}
}
return documentElement;
}
/**
* @private
*/
}, {
key: "_incrementIllegalMoveCount",
value: function _incrementIllegalMoveCount() {
this.illegalMoveCount++;
if (this.illegalMoveCount >= 3) {
this.illegalMoveCount = 0;
this._say('Je kunt niet tussen 2 lijsten slepen.'); //Tell the user that he....well could not do what he was doing
}
}
/**
* Says something
*
* @param message
* @private
*/
}, {
key: "_say",
value: function _say(message) {
if (SpeechSynthesisUtterance !== undefined) {
var msg = new SpeechSynthesisUtterance();
var voices = window.speechSynthesis.getVoices();
msg.voice = voices[10];
msg.voiceURI = "native";
msg.volume = 1;
msg.rate = 1;
msg.pitch = 0.8;
msg.text = message;
msg.lang = 'nl-NL';
speechSynthesis.speak(msg);
}
}
/**
* Creates a li item with a name input, file_url text paragraph, delete button and a thumb image.
*
* @returns {HTMLElement}
* @private
*/
}, {
key: "_createDocumentElement",
value: function _createDocumentElement() {
var documentElement = document.createElement('li');
documentElement.className = 'document';
var nameInput = document.createElement('input');
nameInput.setAttribute('class', 'name');
nameInput.setAttribute('type', 'text');
nameInput.addEventListener('change', this._modifiedDocument);
var fileUrl = document.createElement('p');
fileUrl.setAttribute('class', 'path');
var contentWrapper = document.createElement('div');
contentWrapper.setAttribute('class', 'content-wrapper');
contentWrapper.appendChild(nameInput);
contentWrapper.appendChild(fileUrl);
var deleteButton = document.createElement('span');
deleteButton.className = 'delete'; // deleteButton.innerText = 'x';
deleteButton.addEventListener('click', this._deleteDocumentButtonClicked);
var dragIcon = document.createElement('span');
dragIcon.className = 'drag-icon';
var thumbContainer = document.createElement('div');
thumbContainer.className = 'thumb';
thumbContainer.setAttribute('draggable', 'false'); //Prevent image from being dragged and interfering with what the makeElementDraggableIfNeeded method does
var thumbImage = document.createElement('div');
thumbImage.className = 'thumb__image';
thumbContainer.appendChild(thumbImage);
var fileInput = document.createElement('input');
fileInput.setAttribute('type', 'file');
fileInput.setAttribute('name', this.key + '-' + (this.getCurrentDocumentsCount() + 1));
if (this.accept) fileInput.setAttribute('accept', this.accept);
documentElement.appendChild(fileInput);
fileInput.style.display = "none";
documentElement.appendChild(dragIcon);
documentElement.appendChild(thumbContainer);
documentElement.appendChild(contentWrapper);
documentElement.appendChild(deleteButton);
return documentElement;
}
/**
* Retrieves a javascript file instance and creates a documentElement for it.
* Usually used by outside classes to inject a document from a file to upload.
*
* @param fileInstance {File}
*/
}, {
key: "receiveFile",
value: function receiveFile(fileInstance) {
if (!fileInstance) {
console.warn('DocumentManager:receiveFile: Expected to get a file but did not get one');
return;
} // console.log('this.getCurrentDocumentsCount() < this.maxDocuments: ', this.getCurrentDocumentsCount(), this.maxDocuments, 'File', fileInstance);
if (this.getCurrentDocumentsCount() < this.maxDocuments) {
var documentElement = this._createDocumentElement();
this._attachDocumentModelToDocumentElement(documentElement);
if (this.HTML5Uploader.isSupported() === false) {
documentElement = this._giveDocumentElementAFile(documentElement, fileInstance); //Add the newly created HTMLElement to the document list
this.documentList.appendChild(documentElement);
if (this._formSizeExceeded()) {
documentElement.parentElement.removeChild(documentElement); //Remove the documentElement
}
this._updateSortOrder();
} else {
// console.log('Uploading via HTML5');
var extraData = {
'imageProperties': this.imageProperties,
'subFolder': this.subFolder
};
this.HTML5Uploader.upload(fileInstance, JSON.stringify(extraData));
}
}
}
/**
* Returns the amount of documents that are not deleted.
* If you set the boolean parameter to true it will include the deleted ones.
*/
}, {
key: "getCurrentDocumentsCount",
value: function getCurrentDocumentsCount() {
var includingDeleted = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var documents = this.documentList.getElementsByClassName('document');
var realDocumentCount = documents.length;
var documentCount = realDocumentCount; //Subtract the ones that are about to be deleted from the real document count
if (!includingDeleted) {
for (var documentsIndex = 0; documentsIndex < realDocumentCount; documentsIndex++) {
var documentElement = documents[documentsIndex];
if ("json" in documentElement.dataset === false) continue; //used to skip the add new document button
/** @var {DocumentModel} document **/
var _document2 = JSON.parse(documentElement.dataset.json);
if (_document2.state === DOCUMENT_STATE_DELETED) documentCount--;
}
}
return documentCount;
}
/**
* Sets the file of an document element to the given one.
* Makes the drag icon invisible since it was not uploaded yet
* and cannot be positioned. Sets the file input to the files name and
* loads the thumb with the appropiate extension
*
* @param {HTMLElement} documentElement
* @param {File} file
* @return {HTMLElement} the documentElement
* @private
*/
}, {
key: "_giveDocumentElementAFile",
value: function _giveDocumentElementAFile(documentElement, file) {
var filename = file.name;
var extension = this._getExtensionFromFileName(filename);
var thumbUrl = this._previewThumbUrlIsImage(filename); //Get the document element and some parts in it
var nameInputElement = documentElement.querySelector('.name');
var thumbImageElement = documentElement.querySelector('.thumb');
var contentWrapper = documentElement.querySelector('.content-wrapper');
var deleteButton = documentElement.querySelector('.delete');
var dragIcon = documentElement.querySelector('.drag-icon');
var fileInputElement = documentElement.querySelector('input[type="file"]'); //Hide the drag icon. Dragging is only supported after file upload
dragIcon.style.display = 'none'; //Update file input with a file if the input does not have a file.
if (fileInputElement && !fileInputElement.files[0]) {
fileInputElement.files = new FileList(file);
} //Make thumb visible and load extension image
thumbImageElement.setAttribute('data-filetype', extension);
if (this.availableExtensionThumbs.indexOf(extension) !== -1) {
var thumbImage = thumbImageElement.querySelector('thumb__image');
thumbImage.style.backgroundImage = "url('" + this.extensionThumbsFolder + extension + ".svg')";
thumbImage.classList.add('has-icon');
}
nameInputElement.value = filename;
return documentElement;
}
/**
* Returns the thumbnail for the document or false if it isn't available.
* @private
*/
}, {
key: "_getThumbUrlUsingDocumentModel",
value: function _getThumbUrlUsingDocumentModel(documentModel) {
if (documentModel) {
var filename = documentModel.file_url;
if (documentModel.thumb_image_url !== '') filename = documentModel.thumb_image_url;
if (this._previewThumbUrlIsImage(filename)) return filename;
}
return false;
}
/**
* Returns the given preview thumb url for an extension if that extension is an image or false if it is not an image
* @private
*/
}, {
key: "_previewThumbUrlIsImage",
value: function _previewThumbUrlIsImage(url) {
if (!this.enablePreviewsIfPossible) return false;
var extension = this._getExtensionFromFileName(url);
switch (extension) {
case 'png':
case 'jpg':
case 'jpeg':
case 'gif':
return url;
case 'pdf':
default:
return false;
}
}
/**
* Returns the extension without leading dot from a file name or '' when it did not have an extension.
*
* @private
*/
}, {
key: "_getExtensionFromFileName",
value: function _getExtensionFromFileName(filename) {
var extension = filename.split(/[.]+/).pop();
if (extension === filename) return '';
return extension.toLowerCase();
}
/**
* Check if the total form size isn't bigger then the maximum allowed upload size.
* Warning: when maxUploadSizeInBytes isn't set this function wil always return false.
*
* @private
*/
}, {
key: "_formSizeExceeded",
value: function _formSizeExceeded() {
if (this.maxUploadSizeInBytes) {
var exceeded = false;
var currentTotalInBytes = 0; //validate total
this.documentList.querySelectorAll('input[type="file"]').forEach(function (fileInput) {
if (fileInput.files.length !== 1) return;
var document = fileInput.files[0];
currentTotalInBytes += document.size;
});
console.log('max upload size in bytes: ' + this.maxUploadSizeInBytes + ' current upload size in bytes: ' + currentTotalInBytes);
if (currentTotalInBytes > this.maxUploadSizeInBytes) {
var maxUploadSizeInMegaBytes = this.maxUploadSizeInBytes / 1048576;
exceeded = true;
alert(this.uploadSizeExceededMessage + ' ' + maxUploadSizeInMegaBytes + ' MegaBytes');
}
return exceeded;
} else {
return false;
}
}
/**
* Update the data input with an array of json objects that are the data-json attributes of each "document" li.
* This is used for the backend to determine what has changed and what did not.
*
* @private
*/
}, {
key: "_updateDataInput",
value: function _updateDataInput() {
var documentsDataArray = []; //Please notice that the first document isnt a document but is the document add button. That's why we check for the json dataset
var documents = this.documentList.children;
var nDocuments = documents.length;
for (var documentsIndex = 0; documentsIndex < nDocuments; documentsIndex++) {
var documentElement = documents[documentsIndex];
if ("json" in documentElement.dataset) {
documentsDataArray.push(JSON.parse(documentElement.dataset.json));
}
}
if (this.getCurrentDocumentsCount() >= this.maxDocuments) {
this.wrapper.querySelector('.drag-and-drop-area').classList.add('is-hidden');
} else {
this.wrapper.querySelector('.drag-and-drop-area').classList.remove('is-hidden');
}
this.dataInput.value = JSON.stringify(documentsDataArray);
var changeEvent = createNewEvent('change');
dispatchEventForElement(this.dataInput, changeEvent);
}
/**
* Updates the sort order of each document when needed and then updates the data input field
*
* @private
*/
}, {
key: "_updateSortOrder",
value: function _updateSortOrder() {
//Please notice that the first document isnt a document but is the document add button. That's why we check for the json dataset
var documents = this.documentList.children;
var nDocuments = documents.length;
var currentSortNumber = 1;
for (var documentsIndex = 0; documentsIndex < nDocuments; documentsIndex++) {
var documentElement = documents[documentsIndex];
if ("json" in documentElement.dataset === false) continue; //used to skip the add new document button
var _document3 = JSON.parse(documentElement.dataset.json);
if (_document3.state === DOCUMENT_STATE_DELETED) continue;
_document3.sort_order = currentSortNumber;
if (_document3.state !== DOCUMENT_STATE_NEW) _document3.state = DOCUMENT_STATE_MODIFIED;
documentElement.dataset.json = JSON.stringify(_document3);
documentElement.classList.add(DOCUMENT_STATE_MODIFIED);
currentSortNumber++;
}
this._updateDataInput();
}
/**
* Does have a look at the documentElements and sorts them by using their sort order values
*
* @private
*/
}, {
key: "_sortDocuments",
value: function _sortDocuments() {
var documentElements = this.documentList.children;
documentElements = Array.prototype.slice.call(documentElements); //Converts the htmlCollection of HTMLElement documentElements to an Array of documentElements
documentElements.sort(function (itemA, itemB) {
var itemADocument = JSON.parse(itemA.dataset.json);
var itemBDocument = JSON.parse(itemB.dataset.json); // console.log(itemADocument.sort_order, itemBDocument.sort_order);
if (itemADocument.sort_order < itemBDocument.sort_order) return -1;
return 1;
});
var sortedDocumentsLength = documentElements.length;
for (var index = 1; index < sortedDocumentsLength; index++) {
this.documentList.removeChild(documentElements[index]);
if (this.documentList.length > 1) this.documentList.insertBefore(documentElements[index], this.documentList.firstChild);else this.documentList.appendChild(documentElements[index]);
}
}
/**
* @param element HTMLElement that needs to be draggable or not
* @param respondOrNotBoolean
* @return {DocumentManager}
* @private
*/
}, {
key: "_makeElementRespondToDragging",
value: function _makeElementRespondToDragging(element) {
var respondOrNotBoolean = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
element.setAttribute('draggable', respondOrNotBoolean ? 'true' : 'false');
element.id = this.key + '_' + this.getCurrentDocumentsCount();
if (respondOrNotBoolean) {
element.removeEventListener('dragstart', this._drag);
element.addEventListener('dragstart', this._drag);
} else {
element.removeEventListener('dragstart', this._drag);
}
return this;
}
/**
* @param element HTMLElement that needs to be draggable or not
* @param respondOrNotBoolean
* @return {DocumentManager}
* @private
*/
}, {
key: "_makeElementRespondToDrop",
value: function _makeElementRespondToDrop(element) {
var respondOrNotBoolean = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
if (respondOrNotBoolean) {
element.removeEventListener('drop', this._drop);
element.addEventListener('drop', this._drop);
} else {
element.removeEventListener('drop', this._drop);
}
return this;
}
/**
* Prepares the element so that it can receive items that are dropped onto it
*
* @param element HTMLElement that needs can be a drop target or not
* @param respondOrNotBoolean wheter or not it should be a drop target
* @private
*/
}, {
key: "_makeElementRespondToDragOverAndLeave",
value: function _makeElementRespondToDragOverAndLeave(element) {
var respondOrNotBoolean = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
if (respondOrNotBoolean) {
element.removeEventListener('dragover', this._dragOver);
element.removeEventListener('dragleave', this._dragLeave);
element.addEventListener('dragover', this._dragOver);
element.addEventListener('dragleave', this._dragLeave);
} else {
element.removeEventListener('dragover', this._dragOver);
element.removeEventListener('dragleave', this._dragLeave);
}
}
/**
* Occurs when a document (li) HTMLElement is being dragged
*
* @param dragEvent
* @private
*/
}, {
key: "_drag",
value: function _drag(dragEvent) {
if (!dragEvent.target.id) return;
dragEvent.stopPropagation();
dragEvent.dataTransfer.setData("text", dragEvent.target.id); //Set the id of the thing that is being dragged in the event.
var draggedElement = document.getElementById(dragEvent.target.id);
this._triggerEvent('drag', draggedElement);
}
/**
* Occurs when a document (li) HTMLElement is being dragged over the target element.
* So the dragEvent target is not the element that you drag, but the place / HTMLElement where it may be dropped.
*
* @param dragEvent
* @private
*/
}, {
key: "_dragOver",
value: function _dragOver(dragEvent) {
dragEvent.preventDefault(); //Sets target HTMLElement to allow a drop
dragEvent.stopPropagation();
if (!dragEvent.target.id) return;
var draggedElementId = dragEvent.dataTransfer.getData("text");
var draggedElement = document.getElementById(draggedElementId);
this._enableOrDisablePointerEventsOnChildrenOfElement(dragEvent.target, false);
dragEvent.target.classList.add('isDropTarget');
this._triggerEvent('dragLeave', [draggedElement, dragEvent.target]);
}
/**
* Occurs when a document (li) HTMLElement is NOT being dragged anymore over the target element.
*
* @param dragEvent
* @private
*/
}, {
key: "_dragLeave",
value: function _dragLeave(dragEvent) {
if (!dragEvent.target.id) return;
dragEvent.stopPropagation();
var draggedElementId = dragEvent.dataTransfer.getData("text");
var draggedElement = document.getElementById(draggedElementId);
this._enableOrDisablePointerEventsOnChildrenOfElement(dragEvent.target, true);
dragEvent.target.classList.remove('isDropTarget');
this._triggerEvent('dragLeave', [draggedElement, dragEvent.target]);
}
/**
* Occurs when a document is being dropped
*
* @param dragEvent
*/
}, {
key: "_drop",
value: function _drop(dragEvent) {
dragEvent.preventDefault(); //Prevent browser from activating links and buttons
if (!dragEvent.target.id) return;
var draggedElementId = dragEvent.dataTransfer.getData("text");
var draggedElement = document.getElementById(draggedElementId);
var targetElement = dragEvent.target;
targetElement.classList.remove('isDropTarget'); //Only "move" the dragged element to the new location when it has the same parent. E.g. when they both are in the same list
//If they don't have the same parent. We are going to ignore the action
if (targetElement.parentElement !== draggedElement.parentElement) {
this._incrementIllegalMoveCount();
return;
} //Create a shim element that keeps track of where the dragged element was and where the target element must be inserted
var shimElement = document.createElement('div');
draggedElement.parentElement.insertBefore(shimElement, draggedElement); //Move the dragged element in just before the target element
draggedElement.parentElement.insertBefore(draggedElement, targetElement); //Move the target element before the shim and then remove the shim since we only needed that to mark the dragged elements original position
draggedElement.parentElement.insertBefore(targetElement, shimElement);
shimElement.parentElement.removeChild(shimElement);
this._triggerEvent('drop', [draggedElement, targetElement]);
this._enableOrDisablePointerEventsOnChildrenOfElement(targetElement, true);
this._updateSortOrder();
}
/**
* Enables / disables the listening to pointer (example: mouse) events on an element
* and all of it's children. This prevents for example the dragover event from beeing canceled
* when dragging over an input that resides in an element which listens to the dragover event
* because the input captures the mouse.
*/
}, {
key: "_enableOrDisablePointerEventsOnChildrenOfElement",
value: function _enableOrDisablePointerEventsOnChildrenOfElement(element, enable) {
var length = element.children.length;
for (var index = 1; index < length; index++) {
if (enable === false) {
element.children[index].style.pointerEvents = 'none';
} else {
element.children[index].style.pointerEvents = null;
}
var childrenLength = element.children.children;
for (var childrenIndex = 1; childrenIndex < childrenLength; childrenIndex++) {
this._enableOrDisablePointerEventsOnChildrenOfElement(element.children.children[index], enable);
}
}
}
/**
* Registers a event to a callback and returns the a reference to the event handler for that specific event
*
* @param event (string)
* @param callback (callable)
*/
}, {
key: "on",
value: function on(event, callback) {
if (!this.eventMap.hasOwnProperty(event)) this.eventMap[event] = [];
return this.eventMap[event].push(callback);
}
/**
* Call event callbacks
*
* @param event (string)
* @param eventArgs (array) an array of arguments to pass to the callback
* @private
*/
}, {
key: "_triggerEvent",
value: function _triggerEvent(event, eventArgs) {
if (!this.eventMap.hasOwnProperty(event)) return;
var nEvents = this.eventMap[event].length;
for (var index = 0; index < nEvents; index++) {
var callback = this.eventMap[event][index];
if (eventArgs && eventArgs.length > 0) {
callback.apply(this, eventArgs);
} else {
callback.call(this);
}
}
}
}]);
return DocumentManager;
}();
/**
* Represents a Document. It the equivalent of the laravel php version
*/
var DocumentModel =
/*#__PURE__*/
function () {
function DocumentModel() {
_classCallCheck(this, DocumentModel);
this.id = -1;
this.file_url = '';
this.state = DOCUMENT_STATE_NEW;
this.name = '';
this.sort_order = 1;
this.thumb_image_url = '';
this.small_image_url = '';
this.medium_image_url = '';
this.large_image_url = '';
this.documentable_id = -1;
this.documentable_type = '';
this.created_at = '';
this.updated_at = '';
}
_createClass(DocumentModel, null, [{
key: "isValidDocumentJson",
value: function isValidDocumentJson(jsonData) {
return jsonData.hasOwnProperty('id') && jsonData.hasOwnProperty('file_url') && jsonData.hasOwnProperty('state') && jsonData.hasOwnProperty('name') && jsonData.hasOwnProperty('sort_order') && jsonData.hasOwnProperty('thumb_image_url') && jsonData.hasOwnProperty('small_image_url') && jsonData.hasOwnProperty('medium_image_url') && jsonData.hasOwnProperty('large_image_url') && jsonData.hasOwnProperty('documentable_id') && jsonData.hasOwnProperty('documentable_type') && jsonData.hasOwnProperty('created_at') && jsonData.hasOwnProperty('updated_at');
}
}, {
key: "fromJson",
value: function fromJson(jsonData) {
if (!DocumentModel.isValidDocumentJson(jsonData)) {
console.error('DocumentModel: Tried to create an instance of invalid json data: ');
console.error(jsonData);
return false;
}
var documentModel = new DocumentModel();
documentModel.id = jsonData.id;
documentModel.file_url = jsonData.file_url;
documentModel.state = jsonData.state;
documentModel.name = jsonData.name;
documentModel.sort_order = jsonData.sort_order;
documentModel.thumb_image_url = jsonData.thumb_image_url;
documentModel.small_image_url = jsonData.small_image_url;
documentModel.medium_image_url = jsonData.medium_image_url;
documentModel.large_image_url = jsonData.large_image_url;
documentModel.documentable_id = jsonData.id;
documentModel.documentable_type = jsonData.documentable_type;
documentModel.created_at = jsonData.created_at;
documentModel.updated_at = jsonData.updated_at;
return documentModel;
}
}]);
return DocumentModel;
}();
var DOCUMENT_STATE_NEW = 'new';
var DOCUMENT_STATE_PRISTINE = 'pristine';
var DOCUMENT_STATE_MODIFIED = 'modified';
var DOCUMENT_STATE_DELETED = 'deleted';
/**
* Used for setting files
*/
var FileList = function FileList() {
var _ref;
for (var _len = arguments.length, items = new Array(_len), _key = 0; _key < _len; _key++) {
items[_key] = arguments[_key];
}
_classCallCheck(this, FileList);
// flatten rest parameter
items = (_ref = []).concat.apply(_ref, _toConsumableArray(items)); // check if every element of array is an instance of `File`
if (items.length && !items.every(function (file) {
return file instanceof File;
})) {
throw new TypeError("expected argument to FileList is File or array of File objects");
} // use `ClipboardEvent("").clipboardData` for Firefox, which returns `null` at Chromium
// we just need the `DataTransfer` instance referenced by `.clipboardData`
var dt = new ClipboardEvent("").clipboardData || new DataTransfer(); // add `File` objects to `DataTransfer` `.items`
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = items[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var file = _step.value;
dt.items.add(file);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator["return"] != null) {
_iterator["return"]();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return dt.files;
};
var FileDragAndDropHandler =
/*#__PURE__*/
function () {
/**
*
*
* @param areaElement {HTMLElement}
*/
function FileDragAndDropHandler(areaElement) {
_classCallCheck(this, FileDragAndDropHandler);
this.hooks = [];
this.selectButton = areaElement.querySelector('button.select');
if (!this.selectButton) {
console.log('FileDragAndDropHandler:constructor The document area must have a button in it with class select. But did not have one. Not responding to drag and drop');
return;
}
this.fileCatcherInput = areaElement.querySelector('input[type="file"]');
if (!this.fileCatcherInput) {
console.log('FileDragAndDropHandler:constructor The document area must have file input. But did not have one. Not responding to drag and drop');
return;
}
this.makeElementRespondToDragOverAndLeave(areaElement);
this.makeElementRespondToDrop(areaElement);
this.makeElementRespondToClick(areaElement);
this.makeFileInputPassFilesToHooks();
}
/**
* Adds an event listener to the file input and makes it pass its files to the document manager
*/
_createClass(FileDragAndDropHandler, [{
key: "makeFileInputPassFilesToHooks",
value: function makeFileInputPassFilesToHooks() {
var self = this;
this.fileCatcherInput.addEventListener('change', function (event) {
var nFiles = event.target.files.length;
for (var index = 0; index < nFiles; index++) {
var file = event.target.files[index]; // console.log(file);
self.createFileListForFileAndPassToHooks(file);
}
event.target.value = '';
});
}
/**
* Catches click on the element and passes them trough to the file input
*/
}, {
key: "makeElementRespondToClick",
value: function makeElementRespondToClick(element) {
var self = this;
element.addEventListener('click', function (event) {
self.fileCatcherInput.click();
});
}
/**
* Hooks a hookable (an object that has a addFile method / function) to the drag and drop handler so that the drag and drop handler passes inputs to the
* hookable
* @param hookable {Class}
*/
}, {
key: "hookTo",
value: function hookTo(hookable) {
if (typeof hookable.receiveFile !== 'function') {
console.error('The given hookable does not have a required receiveFile method / function. Not hooking the given "hookable".');
return;
}
this.hooks.push(hookable);
}
/**
* @param element HTMLElement that needs to be draggable or not
* @param respondOrNotBoolean
* @return {FileDragAndDropHandler}
*/
}, {
key: "makeElementRespondToDrop",
value: function makeElementRespondToDrop(element) {
var respondOrNotBoolean = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
if (respondOrNotBoolean) {
element.removeEventListener('drop', this.drop.bind(this));
element.addEventListener('drop', this.drop.bind(this));
} else {
element.removeEventListener('drop', this.drop.bind(this));
}
return this;
}
/**
* Prepares the element so that it can receive items that are dropped onto it
*
* @param element HTMLElement that needs can be a drop target or not
* @param respondOrNotBoolean wheter or not it should be a drop target
*/
}, {
key: "makeElementRespondToDragOverAndLeave",
value: function makeElementRespondToDragOverAndLeave(element) {
var respondOrNotBoolean = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
if (respondOrNotBoolean) {
element.removeEventListener('dragover', this.dragOver.bind(this));
element.removeEventListener('dragleave', this.dragLeave.bind(this));
element.addEventListener('dragover', this.dragOver.bind(this));
element.addEventListener('dragleave', this.dragLeave.bind(this));
} else {
element.removeEventListener('dragover', this.dragOver.bind(this));
element.removeEventListener('dragleave', this.dragLeave.bind(this));
}
}
/**
* Occurs when a document (li) HTMLElement is being dragged over the target element.
* So the dragEvent target is not the element that you drag, but the place / HTMLElement where it may be dropped.
*
* @param dragEvent
*/
}, {
key: "dragOver",
value: function dragOver(dragEvent) {
dragEvent.preventDefault(); //Sets target HTMLElement to allow a drop
dragEvent.stopPropagation();
if (!dragEvent.target.id) return;
this.enableOrDisablePointerEventsOnChildrenOfElement(dragEvent.target, false);
dragEvent.target.classList.add('isDropTarget');
}
/**
* Occurs when a document (li) HTMLElement is NOT being dragged anymore over the target element.
*
* @param dragEvent
*/
}, {
key: "dragLeave",
value: function dragLeave(dragEvent) {
if (!dragEvent.target.id) return;
dragEvent.stopPropagation();
this.enableOrDisablePointerEventsOnChildrenOfElement(dragEvent.target, true);
dragEvent.target.classList.remove('isDropTarget');
}
/**
* Occurs when a document is being dropped
*
* @param dragEvent
*/
}, {
key: "drop",
value: function drop(dragEvent) {
dragEvent.preventDefault(); //Prevent browser from activating links and buttons
var targetElement = dragEvent.target;
targetElement.classList.remove('isDropTarget');
this.enableOrDisablePointerEventsOnChildrenOfElement(targetElement, true); // Prevent default behavior (Prevent file from being opened)
dragEvent.preventDefault();
if (dragEvent.dataTransfer.items) {
// Use DataTransferItemList interface to access the file(s)
for (var i = 0; i < dragEvent.dataTransfer.items.length; i++) {
// If dropped items aren't files, reject them
if (dragEvent.dataTransfer.items[i].kind === 'file') {
var file = dragEvent.dataTransfer.items[i].getAsFile();
this.createFileListForFileAndPassToHooks(file);
}
}
} else {
// Use DataTransfer interface to access the file(s)
for (var _i2 = 0; _i2 < dragEvent.dataTransfer.files.length; _i2++) {
var _file = dragEvent.dataTransfer.files[_i2];
this.createFileListForFileAndPassToHooks(_file);
}
}
}
}, {
key: "createFileListForFileAndPassToHooks",
value: function createFileListForFileAndPassToHooks(file) {
var length = this.hooks.length;
for (var index = 0; index < length; index++) {
this.hooks[index].receiveFile(file);
}
}
/**
* Enables / disables the listening to pointer (example: mouse) events on an element
* and all of it's children. This prevents for example the dragover event from beeing canceled
* when dragging over an input that resides in an element which listens to the dragover event
* because the input captures the mouse.
*/
}, {
key: "enableOrDisablePointerEventsOnChildrenOfElement",
value: function enableOrDisablePointerEventsOnChildrenOfElement(element, enable) {
var length = element.children.length;
for (var index = 1; index < length; index++) {
if (enable === false) {
element.children[index].style.pointerEvents = 'none';
} else {
element.children[index].style.pointerEvents = null;
}
var childrenLength = element.children.children;
for (var childrenIndex = 1; childrenIndex < childrenLength; childrenIndex++) {
this.enableOrDisablePointerEventsOnChildrenOfElement(element.children.children[index], enable);
}
}
}
}]);
return FileDragAndDropHandler;
}();
/**
* HTML 5 file uploads that report progress while uploading
*/
var HTML5Uploader =
/*#__PURE__*/
function () {
function HTML5Uploader(uploadUrl, maxPostSize, maxUploadSize, translations) {
_classCallCheck(this, HTML5Uploader);
this._constructedSuccessfully = false;
if (!uploadUrl && !(typeof uploadUrl === 'string')) {
console.error('Did not get a valid upload url. Not initializing Html5Uploader');
return;
}
this._uploadUrl = uploadUrl;
if (!maxPostSize) {
console.error('Did not get the maximum post size. Not initializing Html5Uploader');
return;
}
this._maxPostSize = maxPostSize;
if (!maxUploadSize) {
console.error('Did not get the maximum upload size. Not initializing Html5Uploader');
return;
}
this._maxUploadSize = maxUploadSize;
if (!translations) {
console.error('Did not get the translations. Not initializing Html5Uploader');
return;
}
this._translations = JSON.parse(translations);
this._eventMap = {};
if (!this.isSupported()) {
console.warn('HTML 5 file upload is not supported. Not initializing Html5Uploader');
return;
}
this.csrfTokenContainer = document.querySelector('meta[name="csrf-token"]');
if (!this.csrfTokenContainer) {
console.error('No csrf-token could be found in a meta tag with name "csrf-token". Not initializing Html5Uploader');
return;
}
this._constructedSuccessfully = true;
}
/**
* Returns true if the browser supports HTML 5 uploading. false if not
* @return {boolean}
*/
_createClass(HTML5Uploader, [{
key: "isSupported",
value: function isSupported() {
return window.FormData !== undefined;
}
/**
* @param {File} file
*/
}, {
key: "receiveFile",
value: function receiveFile(file) {
if (!this.isSupported()) {
console.error('HTML 5 file upload is not supported. Not uploading file.');
return;
}
}
/**
* @param {File} file
* @param {string} extraData
*/
}, {
key: "upload",
value: function upload(file, extraData) {
if (!this._verifyFileSizeOrShowError(file)) return;
if (this._constructedSuccessfully === false) return;
var self = this;
var formData = new FormData();
formData.append(file.name, file);
formData.append('extraData', extraData);
var request = new XMLHttpRequest();
var uploadRequest = request.upload;
uploadRequest.addEventListener("progress", function (file, extraData) {
return function (event) {
self._updateProgress(file, event, extraData);
};
}(file, extraData));
request.addEventListener("loadstart", function (file, extraData) {
return function (event) {
self._uploadStart(file, extraData);
};
}(file, extraData));
request.addEventListener("error", function (file, extraData) {
return function (event) {
self._uploadFailed(file, 'general error', extraData);
};
}(file, extraData));
request.addEventListener("abort", function (file, extraData) {
return function (event) {
self._uploadCanceled(file, extraData);
};
}(file, extraData));
request.onreadystatechange = function (file, extraData) {
return function () {
if (request.readyState === 4) {
if (request.status === 200) {
self._uploadComplete(file, request.responseText, extraData);
} else {
self._uploadFailed(file, request.responseText, extraData);
}
}
};
}(file, extraData);
request.open('POST', this._uploadUrl);
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
request.setRequestHeader('X-CSRF-TOKEN', this.csrfTokenContainer.getAttribute('content'));
request.send(formData);
}
/**
* Returns true if the file size is lower then the maximum allowed server upload size.
* Or shows an alert and returns false if it is bigger then the allowed server upload size.
*
* @param {File} file
* @return {boolean}
* @private
*/
}, {
key: "_verifyFileSizeOrShowError",
value: function _verifyFileSizeOrShowError(file) {
if (file.size > this._maxPostSize || file.size > this._maxUploadSize) {
//Calculate file size and max file size to megabytes
var fileSizeInMegaBytes = file.size / (1024 * 1024);
var maxSizeInMegaBytes = (this._maxUploadSize > this._maxPostSize ? this._maxPostSize : this._maxUploadSize) / (1024 * 1024); //Round this sizes to 2 decimals
fileSizeInMegaBytes = Math.round(fileSizeInMegaBytes * 100) / 100;
maxSizeInMegaBytes = Math.round(maxSizeInMegaBytes * 100) / 100; //Gather translation texts
var introText = this._translations.file_to_big;
var maxFileSizeUploadTranslation = this._translations.max_file_size_upload;
var fileSizeUploadTranslation = this._translations.file_size_upload; //Assemble alert message
var alertText = introText + '\n\n' + maxFileSizeUploadTranslation + maxSizeInMegaBytes + ' MB\n' + fileSizeUploadTranslation + fileSizeInMegaBytes + ' MB\n'; //Show alert message and return false
alert(alertText);
return false;
} //File size is fine. Return true
return true;
}
/**
* @param {File} file
* @param {ProgressEvent} event
* @param extraData
* @private
*/
}, {
key: "_updateProgress",
value: function _updateProgress(file, event, extraData) {
if (event.lengthComputable) {
var percentComplete = Math.ceil(event.loaded / event.total * 100);
this._triggerEvent('updateProgress', [file, percentComplete, extraData]);
} else {
// Unable to compute progress information since the total size is unknown
this._triggerEvent('updateProgress', [file, null, extraData]);
}
}
/**
* @param {File} file
* @param extraData
* @private
*/
}, {
key: "_uploadStart",
value: function _uploadStart(file, extraData) {
this._triggerEvent('uploadStart', [file, extraData]);
}
/**
* @param {File} file
* @param {string} responseText
* @param extraData
* @private
*/
}, {
key: "_uploadComplete",
value: function _uploadComplete(file, responseText, extraData) {
this._triggerEvent('uploadComplete', [file, responseText, extraData]);
}
/**
* @param {File} file
* @param extraData
* @private
*/
}, {
key: "_uploadFailed",
value: function _uploadFailed(file, extraData) {
this._triggerEvent('uploadFailed', [file, extraData]);
}
/**
* @param {File} file
* @param extraData
* @private
*/
}, {
key: "_uploadCanceled",
value: function _uploadCanceled(file, extraData) {
this._triggerEvent('uploadCanceled', [file, extraData]);
}
/**
* @param {int} fileId
* @private
*/
}, {
key: "_deleteStart",
value: function _deleteStart(fileId) {}
/**
* @param {int} fileId
* @private
*/
}, {
key: "_deleteComplete",
value: function _deleteComplete(fileId) {
// console.log('HTML5Uploader: deleted file with id: '+fileId);
this._triggerEvent('deleteComplete', fileId);
}
/**
* @param {int} fileId
*/
}, {
key: "_deleteFail",
value: function _deleteFail(fileId) {
// console.error('HTML5Uploader: could not delete file with id: '+fileId);
this._triggerEvent('deleteFail', fileId);
}
/**
* Registers a event to a callback and returns the a reference to the event handler for that specific event
*
* @param event (string)
* @param callback (callable)
*/
}, {
key: "on",
value: function on(event, callback) {
if (this._constructedSuccessfully === false) return;
if (!this._eventMap.hasOwnProperty(event)) this._eventMap[event] = [];
return this._eventMap[event].push(callback);
}
/**
* Call event callbacks
*
* @param event (string)
* @param eventArgs (array) an array of arguments to pass to the callback
* @private
*/
}, {
key: "_triggerEvent",
value: function _triggerEvent(event, eventArgs) {
if (!this._eventMap.hasOwnProperty(event)) return;
var nEvents = this._eventMap[event].length;
for (var index = 0; index < nEvents; index++) {
var callback = this._eventMap[event][index];
if (eventArgs && eventArgs.length > 0) {
callback.apply(this, eventArgs);
} else {
callback.call(this);
}
}
}
}]);
return HTML5Uploader;
}();
var ImageController =
/*#__PURE__*/
function () {
function ImageController(key, images, maxImages) {
_classCallCheck(this, ImageController);
//console.log('Image controller got images: ');
//console.log(images);
//console.log('ImageController: key: '+key);
//console.log('ImageController: maxImages: '+maxImages);
//
this.key = key;
this.currentImageListId = "#image-list-" + key;
this.fileCounter = 0;
this.maxImages = maxImages;
this.images = images; //
this.initialize();
this.checkNewButtonState();
}
_createClass(ImageController, [{
key: "initialize",
value: function initialize() {
var self = this; // Click on an existing image to remove it
$(self.currentImageListId + ' .image-thumb-li').click(function () {
$(this).remove();
self.removeFromImages($('img', this).attr('data-image-id'));
}); // When a file is selected for uploading
$(document).on('click', self.currentImageListId + ' .new-image input', function (e) {
//console.log(self.countActiveImages());
if (self.maxImages != '' && self.countActiveImages() >= self.maxImages) {
e.preventDefault();
return;
}
});
$(document).on('change', self.currentImageListId + ' .new-image input', function () {
//console.log("images.blade.php: Change event triggered");
if (self.maxImages != '' && self.countActiveImages() >= self.maxImages) return; //console.log('Checking old input element: #'+self.key+'-'+self.fileCounter);
var $oldInput = $('#' + self.key + '-' + self.fileCounter); //console.log("old input: ");
//console.log($oldInput);
//console.log("current image list element: "+self.currentImageListId + ' .uploads :');
//console.log($(self.currentImageListId + ' .uploads'));
$(self.currentImageListId + ' .uploads').append($oldInput);
self.images.push({
id: null,
name: $oldInput.attr('id'),
"delete": false
});
self.updateImages();
$oldInput.unbind('change'); //console.log("unbinded change event from the old input element");
var files = $oldInput.prop('files'); //console.log("files from property from the old input: ");
//console.log(files);
// Removing multiple files doesn't work yet, so it is disabled
for (var i = 0; i < files.length; i++) {
self.insertImage(files[i], self.fileCounter, i);
}
self.fileCounter++;
$(self.currentImageListId + ' .new-image').append('<input type="file" id="' + self.key + '-' + self.fileCounter + '" name="' + self.key + '-' + self.fileCounter + '" accept="image/*" />');
});
this.checkNewButtonState();
}
}, {
key: "insertImage",
value: function insertImage(file, fileCounter, imageCounter) {
var self = this; //console.log('insertImage');
var reader = new FileReader();
reader.onload = function (e) {
var dataURL = e.target.result;
$(self.currentImageListId + ' .thumbs').append('' + '<li id="image-thumb-' + this.key + '-' + fileCounter + '-' + imageCounter + '">' + '<img src="' + dataURL + '" />' + '<div class="deleteImage">тип</div>' + '</li>');
var thumb = $('#image-thumb-' + self.key + '-' + fileCounter + '-' + imageCounter); // Remove image for uploading when clicked
thumb.click(function () {
self.removeFromImages('' + self.key + '-' + fileCounter);
thumb.remove();
var element = $('#' + self.key + '-' + fileCounter);
element.val('');
element.remove();
});
};
this.checkNewButtonState();
reader.readAsDataURL(file);
}
}, {
key: "checkNewButtonState",
value: function checkNewButtonState() {
var button = $(self.currentImageListId + ' .new-image');
if (this.maxImages !== undefined && this.countActiveImages() >= this.maxImages) {
//hide the button
button.hide(); // //console.log("hide add new image button");
} else {
//show the button
button.show(); // //console.log("show add new image button");
}
}
}, {
key: "updateImages",
value: function updateImages() {
var images = JSON.stringify(this.images, null, 2); //console.log('Update images: '+images);
$('#' + this.key).val(images); //console.log("Updated images: id:"+'#'+this.key+" with json data:"+JSON.stringify(this.images, null, 2));
//console.log($('#'+this.key));
this.checkNewButtonState();
}
}, {
key: "countActiveImages",
value: function countActiveImages() {
//console.log("countActiveImages: ");
//console.log(this.images);
var count = 0;
for (var i = 0; i < this.images.length; i++) {
if (!this.images[i]["delete"]) count++;
} //console.log("countActiveImages thats: "+count+" length: "+this.images.length);
return count;
}
}, {
key: "removeFromImages",
value: function removeFromImages(idOrFileInputName) {
//console.log('Removing image: '+idOrFileInputName);
//console.log('this.images: ');
//console.log(this.images);
for (var i = 0; i < this.images.length; i++) {
if (this.images[i].name == idOrFileInputName) {
this.images.splice(i, 1);
this.updateImages();
return;
}
if (this.images[i].id == idOrFileInputName) {
this.images[i]["delete"] = true;
this.updateImages();
return;
}
}
}
}]);
return ImageController;
}();
var MultiSelect =
/*#__PURE__*/
function () {
function MultiSelect(attributeWrapper) {
_classCallCheck(this, MultiSelect);
this.attributeKey = attributeWrapper.dataset.key;
this.value = attributeWrapper.querySelector('[name="' + this.attributeKey + '"]').value;
/**Select all elements for easy access later on**/
this.uiWidget = attributeWrapper.querySelector('.ui-widget');
this.input = document.getElementById(this.attributeKey);
this.openbutton = document.getElementById(this.attributeKey + "-open");
this.autoCompleteSelectField = document.getElementById(this.attributeKey + "-fake");
this.itemsWrapper = document.getElementById(this.attributeKey + "_items");
this.autoSaveUrl = attributeWrapper.dataset.autosaveUrl;
this.maxItemsToSelect = attributeWrapper.dataset.maxItemsToSelect;
this.selectOptions = MultiSelect._buildSelectOptionsFromObject(JSON.parse(attributeWrapper.dataset.items));
this.dataSet = MultiSelect._buildDataSetFromSelectOptions(this.selectOptions);
this.sortable = attributeWrapper.dataset.sortable === "true" ? true : null;
if (this.sortable) {
var _self = this;
this.dragElement = null; // Sorting starts
this.itemsWrapper.addEventListener('dragstart', function (evt) {
_self.dragElement = evt.target; // Remembering an element that will be moved
// Limiting the movement type
evt.dataTransfer.effectAllowed = 'move';
evt.dataTransfer.setData('Text', _self.dragElement.textContent); // Subscribing to the events at dnd
_self.itemsWrapper.addEventListener('dragover', _self._onDragOver.bind(_self), false);
_self.itemsWrapper.addEventListener('dragend', _self._onDragEnd.bind(_self), false);
setTimeout(function () {
// If this action is performed without setTimeout, then
// the moved object will be of this class.
_self.dragElement.classList.add('ghost');
}, 0);
}, false);
}
this._makeMultiSelect();
this._addItems();
this._updateRealInput();
this._enableListeners(true);
this._enableOpenButton();
}
_createClass(MultiSelect, [{
key: "_enableListeners",
value: function _enableListeners(enable) {
this.listenersEnabled = enable;
var length = this.itemsWrapper.children.length; //Add / remove listeners to items
for (var i = 0; i < length; i++) {
var item = this.itemsWrapper.children[i];
var id = item.dataset.id;
item.classList.remove('readonly');
this.autoCompleteSelectField.classList.remove('hidden');
if (!enable) {
item.classList.add('readonly');
this.autoCompleteSelectField.classList.add('hidden');
this.openbutton.classList.add('hidden');
}
}
}
}, {
key: "_addItems",
value: function _addItems() {
var valuesFromAttribute = this.value.split(',');
var datasetLength = this.dataSet.length;
for (var valuesIndex = 0; valuesIndex < valuesFromAttribute.length; valuesIndex++) {
var idFromAttribute = parseInt(valuesFromAttribute[valuesIndex]);
for (var itemIndex = 0; itemIndex < datasetLength; itemIndex++) {
var item = this.dataSet[itemIndex];
if (item.id === idFromAttribute) {
this._addItem(item.id, item.value);
break;
}
}
}
}
}, {
key: "_makeMultiSelect",
/**
* Makes the fake input field and autocomplete input field.
* Focus method is triggered when you hover over items in the menu
* select method is triggered when you click an item in the list.
*/
value: function _makeMultiSelect() {
var self = this;
var element = document.getElementById(this.attributeKey + "-fake");
$(element).autocomplete({
source: this.dataSet,
minLength: 0,
focus: function focus(event, ui) {
return false;
},
select: function select(event, ui) {
$(this.autoCompleteSelectField).val("");
self._addItem(ui.item.id, ui.item.value);
self._updateRealInput();
self._autosaveIfNeeded();
self._enableListeners(true);
return false;
}
});
}
}, {
key: "_addItem",
/**
* Adds a span tag containing the value given and the data-id property set to id given to
* the p tag with class items.
*/
value: function _addItem(id, value) {
var self = this;
if (this._itemsCount() >= self.maxItemsToSelect) return;
var itemElement = document.createElement('p');
itemElement.classList.add('item');
if (this.sortable) {
itemElement.draggable = true;
value = '<span class="drag-icon"></span><span class="text">' + value + '</span>';
}
itemElement.innerHTML = value;
var removeButton = document.createElement('span');
removeButton.classList.add('remove');
itemElement.dataset.id = id;
itemElement.dataset.sort_order = this._itemsCount() + 1;
removeButton.addEventListener('click', function (itemToRemove) {
return function () {
if (!self.listenersEnabled) return;
self._removeItem(itemToRemove);
};
}(id));
this.itemsWrapper.appendChild(itemElement);
itemElement.appendChild(removeButton);
if (this._itemsCount() >= self.maxItemsToSelect) {
this.uiWidget.style.display = "none";
}
}
}, {
key: "_enableOpenButton",
/**
* Make sure we can open the autocomplete field dropdown with the open button
*/
value: function _enableOpenButton() {
var self = this;
this.openbutton.addEventListener('click', function (event) {
$(self.autoCompleteSelectField).autocomplete("search", "");
});
}
}, {
key: "_itemsCount",
value: function _itemsCount() {
return this.itemsWrapper.childNodes.length - 1;
}
}, {
key: "_removeItem",
/**
* Iterates over the child elements of the p element with class items and removes the element that has
* data-id set to the specified id. Then calls _updateRealInput to update the hidden input
*/
value: function _removeItem(id) {
var items = this.itemsWrapper.children;
for (var index = 0; index < items.length; index++) {
var item = items[index];
if (parseInt(item.dataset.id) === id) {
this.itemsWrapper.removeChild(item);
if (this._itemsCount() <= this.maxItemsToSelect) {
this.uiWidget.style.display = "block";
}
break;
}
}
this._updateRealInput();
this._autosaveIfNeeded();
}
}, {
key: "_updateRealInput",
/**
* Iterates over the child elements of the p element with class items and concatenates their data-id
* values into a string. After that it sets the hidden input with the id string
*/
value: function _updateRealInput() {
var ids = [];
var items = this.itemsWrapper.children;
var length = this.itemsWrapper.children.length;
for (var i = 0; i < length; i++) {
var item = items[i];
ids[ids.length] = item.dataset.id;
}
var idString = ids.join(',');
this.input.setAttribute('value', idString);
var changeEvent = document.createEvent("Event");
changeEvent.initEvent("change", false, true); // args: string type, boolean bubbles, boolean cancelable
this.input.dispatchEvent(changeEvent);
}
}, {
key: "_autosaveIfNeeded",
value: function _autosaveIfNeeded() {
if (!this.autoSaveUrl) return;
var itemIds = this.input.getAttribute('value');
var self = this;
$.ajax({
type: "POST",
url: this.autoSaveUrl,
data: {
'itemIds': itemIds
},
success: function success(response, textStatus, xhr) {
if (xhr.status === 200) {
console.info('autosave successfull to url: ' + self.autoSaveUrl);
} else {
console.error('autosave failure to url (no code 200): ' + self.autoSaveUrl + '');
console.error(response);
}
},
error: function error(message) {
console.error('autosave failure to url: ' + self.autoSaveUrl + '');
console.error(message);
},
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
dataType: 'json'
});
}
}, {
key: "_onDragOver",
value: function _onDragOver(evt) {
evt.preventDefault();
evt.dataTransfer.dropEffect = 'move';
var target = evt.target;
if (target && target !== this.dragElement && target.nodeName === 'P') {
// Sorting
this.itemsWrapper.insertBefore(this.dragElement, target.nextSibling || target);
}
}
}, {
key: "_onDragEnd",
value: function _onDragEnd(evt) {
evt.preventDefault();
this.dragElement.classList.remove('ghost');
this.itemsWrapper.removeEventListener('dragover', this.onDragOver, false);
this.itemsWrapper.removeEventListener('dragend', this.onDragEnd, false);
this._updateRealInput();
}
}], [{
key: "_buildSelectOptionsFromObject",
value: function _buildSelectOptionsFromObject(data) {
var selectOptions = [];
var itemsCount = data.length;
for (var index = 0; index < itemsCount; index++) {
var selectOption = SelectOption.fromObject(data[index]);
if (selectOption) selectOptions.push(selectOption);
}
return selectOptions;
}
/**
* @param {SelectOption[]}selectOptions
* @private
*/
}, {
key: "_buildDataSetFromSelectOptions",
value: function _buildDataSetFromSelectOptions(selectOptions) {
var dataset = [];
var selectoptionsCount = selectOptions.length;
for (var index = 0; index < selectoptionsCount; index++) {
/** @var {SelectOption} selectOption **/
dataset.push({
id: selectOptions[index].value,
value: selectOptions[index].htmlContent.replace(/ /gi, '.')
});
}
return dataset;
}
}]);
return MultiSelect;
}();
/**
* Matches it's php twin functionality
*/
var SelectOption =
/*#__PURE__*/
function () {
function SelectOption() {
_classCallCheck(this, SelectOption);
this._value = '';
this._content = '';
this._htmlContent = '';
this.toJSON = this._toJson.bind(this);
}
_createClass(SelectOption, [{
key: "_toJson",
value: function _toJson() {
return {
value: this._value,
content: this._content,
htmlContent: this._htmlContent
};
}
}, {
key: "value",
get: function get() {
return this._value;
},
set: function set(value) {
if (typeof value !== 'string') {
console.error('SelectOption::Value must be a string');
return;
}
this._value = value;
}
}, {
key: "content",
get: function get() {
return this._content;
},
set: function set(value) {
if (typeof value !== 'string') {
console.error('SelectOption::Content must be a string');
return;
}
this._content = value;
}
}, {
key: "htmlContent",
get: function get() {
return this._htmlContent;
},
set: function set(value) {
if (typeof value !== 'string') {
console.error('SelectOption::htmlContent must be a string');
return;
}
this._htmlContent = value;
}
}], [{
key: "fromObject",
value: function fromObject(data) {
if (!this._objectRepresentsSelectOption(data)) return;
var instance = new this();
instance._value = data.value;
instance._content = data.content;
instance._htmlContent = data.htmlContent;
return instance;
}
}, {
key: "_objectRepresentsSelectOption",
value: function _objectRepresentsSelectOption(data) {
if (_typeof(data) !== 'object' || !data.hasOwnProperty('value') || !data.hasOwnProperty('content') || !data.hasOwnProperty('htmlContent')) {
console.error('SelectOption::_objectRepresentsSelectOption: This does not represent an select option. It must be an object containing properties: value, content and htmlContent', data);
return false;
}
return true;
}
}]);
return SelectOption;
}(); //also @See onOff.blade.php
var OnOff =
/*#__PURE__*/
function () {
function OnOff(onOffElementWrapper) {
_classCallCheck(this, OnOff);
if (onOffElementWrapper === undefined || onOffElementWrapper.tagName !== "DIV") {
console.error('OnOff:constructor Missing the expected div element that represents the OnOff attribute wrapper.');
return;
}
this._onOffElementWrapper = onOffElementWrapper;
if (!('key' in onOffElementWrapper.dataset)) {
console.error('OnOff:constructor Missing the key dataset property on the onOffElementWrapper');
return;
}
var realCheckbox = onOffElementWrapper.querySelector('input[type="checkbox"]');
if (!realCheckbox) {
console.error('OnOff:constructor Did not find a required input of type checkbox in the OnOff attribute wrapper.');
return;
}
this._realCheckbox = realCheckbox;
var visibleCheckbox = onOffElementWrapper.querySelector('.on-off-switch');
if (!visibleCheckbox) {
console.error('OnOff:constructor Did not find a required div with class on-off-switch in the OnOff attribute wrapper.');
return;
}
this._visibleCheckbox = visibleCheckbox;
this._visibleCheckbox.addEventListener('click', this.toggleOnOffSwitch.bind(this));
this.initialize();
}
_createClass(OnOff, [{
key: "initialize",
value: function initialize() {
this.updateOnOffState();
}
}, {
key: "updateOnOffState",
value: function updateOnOffState() {
if (this._realCheckbox.value === '1') {
this._realCheckbox.value = '1';
this._visibleCheckbox.classList.add('on');
this._realCheckbox.setAttribute('checked', '');
} else {
this._realCheckbox.value = '0';
this._visibleCheckbox.classList.remove('on');
this._realCheckbox.removeAttribute('checked');
}
}
}, {
key: "toggleOnOffSwitch",
value: function toggleOnOffSwitch() {
this._realCheckbox.value = this._realCheckbox.value === "0" ? "1" : "0";
this.updateOnOffState();
var changeEvent = document.createEvent("Event");
changeEvent.initEvent("change", false, true); // args: string type, boolean bubbles, boolean cancelable
this._realCheckbox.dispatchEvent(changeEvent);
}
}]);
return OnOff;
}();
var PasswordController =
/*#__PURE__*/
function () {
/**
* Validates password fields.
* The password fields values wil be imploded with a pipe symbol
*
* @param passwordInputSelector The css selector for selecting the password input fields
* @param wrapperSelector The css selector for the wrapper div / element that wraps the first and second input fields along the validation helper
* @param passwordDontMatchErrorText string
* @param saveButtonId The id of a save button that needs to be disabled when the passwords are not valid
* @param minPasswordLength int
* @param wrapperHasTitleAttributeAndErrorClass Must be set to true if the wrapper (selected with the wrapper selector) has the ability to have an error class and title attribute for displaying an error
*/
function PasswordController(passwordInputSelector, wrapperSelector, passwordDontMatchErrorText, saveButtonId) {
var minPasswordLength = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 6;
var wrapperHasTitleAttributeAndErrorClass = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
_classCallCheck(this, PasswordController);
this.wrapperHasTitleAttributeAndErrorClass = wrapperHasTitleAttributeAndErrorClass;
this.wrapper = document.querySelector(wrapperSelector);
this.saveButton = document.querySelector("#" + saveButtonId);
this.firstPasswordInput = this.wrapper.querySelector('input[name=' + passwordInputSelector + '-1]');
this.secondPasswordInput = this.wrapper.querySelector('input[name=' + passwordInputSelector + '-2]');
this.realPasswordInput = this.wrapper.querySelector('input[name=' + passwordInputSelector + ']');
this.validationMessageWrapperSelector = '.validationHelper';
this.validationMessageWrapper = this.wrapper.querySelector(this.validationMessageWrapperSelector);
this.minPasswordLength = minPasswordLength; //Used for validation
this.letter = this.validationMessageWrapper.querySelector(".letter");
this.capital = this.validationMessageWrapper.querySelector(".capital");
this.number = this.validationMessageWrapper.querySelector(".number");
this.length = this.validationMessageWrapper.querySelector(".length");
this.match = this.validationMessageWrapper.querySelector(".match"); // this.noPipe = document.querySelector(this.validationMessageWrapperSelector + " .noPipe");
this.activateListeners(true);
}
/**
* Activates listening for keyup events on the password fields to that the passwordChanged method is triggered
*
* @param state
*/
_createClass(PasswordController, [{
key: "activateListeners",
value: function activateListeners(state) {
var self = this;
var validationHelper = this.validationMessageWrapper;
if (state) {
this.firstPasswordInput.addEventListener('keyup', self.debounce(function () {
self.passwordChanged();
}, 100));
this.secondPasswordInput.addEventListener('keyup', self.debounce(function () {
self.passwordChanged();
}, 100));
this.firstPasswordInput.addEventListener('focus', function () {
if (!validationHelper.classList.contains('active')) validationHelper.classList.add('active');
});
this.secondPasswordInput.addEventListener('focus', function () {
if (!validationHelper.classList.contains('active')) validationHelper.classList.add('active');
});
this.firstPasswordInput.addEventListener('blur', function () {
if (validationHelper.classList.contains('active')) validationHelper.classList.remove('active');
});
this.secondPasswordInput.addEventListener('blur', function () {
if (validationHelper.classList.contains('active')) validationHelper.classList.remove('active');
});
} else {
this.firstPasswordInput.removeEventListener('keyup', self.debounce);
this.secondPasswordInput.removeEventListener('keyup', self.debounce); //TODO, these remove listeners won't work. since they need a reference to the original function. the original functions also need to be bound properly when adding them
this.firstPasswordInput.removeEventListener('focus');
this.secondPasswordInput.removeEventListener('focus');
this.firstPasswordInput.removeEventListener('blur');
this.secondPasswordInput.removeEventListener('blur');
}
}
/**
* Triggered when one of the password fields are changed and if the listeners for those fields are active
*/
}, {
key: "passwordChanged",
value: function passwordChanged() {
console.log('password changed');
var value1 = this.firstPasswordInput.value;
var value2 = this.secondPasswordInput.value;
var valid = this.validate(value1, value2);
console.log(valid);
if (valid) this.realPasswordInput.value = value2;else this.realPasswordInput.value = '';
this.enableValidMessage(valid);
this.enableSaveButton(valid);
if (value1 === '' && value2 === '') {
this.enableSaveButton(true);
}
this.removeWrapperError();
}
}, {
key: "enableValidMessage",
value: function enableValidMessage(enable) {
var validationHelper = this.validationMessageWrapper;
if (enable) {
if (!validationHelper.classList.contains('valid')) validationHelper.classList.add('valid');
} else {
if (validationHelper.classList.contains('valid')) validationHelper.classList.remove('valid');
}
}
}, {
key: "enableSaveButton",
value: function enableSaveButton(enable) {
console.log(enable);
if (enable) {
if (this.saveButton.classList.contains('disabled')) this.saveButton.classList.remove('disabled');
} else {
if (!this.saveButton.classList.contains('disabled')) this.saveButton.classList.add('disabled');
}
}
/**
* Removes the error that may be set on the wrapper
*/
}, {
key: "removeWrapperError",
value: function removeWrapperError() {
if (!this.wrapperHasTitleAttributeAndErrorClass) return;
if (this.wrapper.hasAttribute('title')) this.wrapper.setAttribute('title', '');
if (this.wrapper.classList.contains('error')) this.wrapper.classList.remove('error');
}
/**
* Validate two values and return true or false if respectively valid or not
*
* @param value1
* @param value2
* @returns {boolean}
*/
}, {
key: "validate",
value: function validate(value1, value2) {
var valid = true; // Validate lowercase letters
var lowerCaseLetters = /[a-z]/g;
if (value1.match(lowerCaseLetters)) {
this.letter.classList.remove("invalid");
this.letter.classList.add("valid");
} else {
this.letter.classList.remove("valid");
this.letter.classList.add("invalid");
valid = false;
} // Validate capital letters
var upperCaseLetters = /[A-Z]/g;
if (value1.match(upperCaseLetters)) {
this.capital.classList.remove("invalid");
this.capital.classList.add("valid");
} else {
this.capital.classList.remove("valid");
this.capital.classList.add("invalid");
valid = false;
} // Validate numbers
var numbers = /[0-9]/g;
if (value1.match(numbers)) {
this.number.classList.remove("invalid");
this.number.classList.add("valid");
} else {
this.number.classList.remove("valid");
this.number.classList.add("invalid");
valid = false;
} // Validate numbers
// let pipe = /\|/g;
// if(value1.match(pipe)) {
// this.noPipe.classList.remove("valid");
// this.noPipe.classList.add("invalid");
// valid = false;
// } else {
// this.noPipe.classList.remove("invalid");
// this.noPipe.classList.add("valid");
// }
// Validate length
if (value1.length >= this.minPasswordLength) {
this.length.classList.remove("invalid");
this.length.classList.add("valid");
} else {
this.length.classList.remove("valid");
this.length.classList.add("invalid");
valid = false;
} // Validate password match
if (value1 === value2 && (value1 !== '' || value2 !== '')) {
this.match.classList.remove("invalid");
this.match.classList.add("valid");
} else {
this.match.classList.remove("valid");
this.match.classList.add("invalid");
valid = false;
}
return valid;
}
/**
* Triggers the function after the wait time (milliseconds) has expired and only
* if the function is not triggered again before the wait time expired.
*
* @param func
* @param wait
* @param immediate
* @returns {Function}
*/
}, {
key: "debounce",
value: function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this,
args = arguments;
var later = function later() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
}]);
return PasswordController;
}();
var Select =
/*#__PURE__*/
function () {
function Select(selectElementWrapper) {
_classCallCheck(this, Select);
if (selectElementWrapper === undefined || selectElementWrapper.tagName !== "DIV") {
console.error('SelectElement:constructor Missing the expected div element that represents the selectElementWrapper.');
return;
}
this._selectElementWrapper = selectElementWrapper;
if (!('key' in selectElementWrapper.dataset)) {
console.error('SelectElement:constructor Missing the key dataset property on the selectElementWrapper');
return;
}
var key = selectElementWrapper.dataset.key;
var realInput = selectElementWrapper.querySelector('select[name="' + key + '"]');
if (!realInput) {
console.error('SelectElement:constructor Did not find a required hidden select with name "' + key + '" in the VideoElementWrapper.');
return;
}
this._realInput = realInput;
this.initialize(key);
}
_createClass(Select, [{
key: "initialize",
value: function initialize(key) {
var selectHandler = this;
var selectMenu = this._selectElementWrapper.querySelector('.select-menu');
var options = {
width: '100%',
create: function create(event, ui) {
var buttonId = this.id + '-button'; //Open button
var menuId = this.id + '-menu';
document.getElementById(buttonId).setAttribute('dusk', this.id);
},
open: function open(event, ui) {
var button = document.getElementById(this.id + '-button');
var menu = document.getElementById(this.id + '-menu');
menu.style.width = button.offsetWidth + 'px';
menu.parentNode.style.width = button.offsetWidth + 'px';
button.classList.add('dropdown-open');
},
change: function change(event, ui) {
var button = document.getElementById(this.id + '-button');
var buttonText = button.querySelector('.ui-selectmenu-text').innerHTML;
button.querySelector('.ui-selectmenu-text').innerHTML = buttonText.replace(/ /gi, '');
var changeEvent = document.createEvent("Event");
changeEvent.initEvent("change", false, true); // args: string type, boolean bubbles, boolean cancelable
selectHandler._realInput.dispatchEvent(changeEvent);
},
close: function close(event, ui) {
var button = document.getElementById(this.id + '-button');
button.classList.remove('dropdown-open');
}
};
$(selectMenu).selectmenu(options).data("ui-selectmenu")._renderItem = function (ul, item) {
var li = $("<li>"),
wrapper = $("<div>", {
title: item.element.attr("title")
});
if (item.disabled) {
this._addClass(li, null, "ui-state-disabled");
}
this._setText(wrapper, item.label);
$(li).attr('dusk', selectMenu.id + "-" + item.value);
return li.append(wrapper).appendTo(ul);
};
}
}]);
return Select;
}();
var SendPasswordMailButton =
/*#__PURE__*/
function () {
/**
* Validates password fields.
* The password fields values wil be imploded with a pipe symbol
*
* @param {HTMLDivElement} wrapper The wrapper div / element that wraps the button.
*/
function SendPasswordMailButton(wrapper) {
_classCallCheck(this, SendPasswordMailButton);
this.wrapper = wrapper;
this.csrfTokenContainer = document.querySelector('meta[name="csrf-token"]');
if (!this.csrfTokenContainer) {
console.error('PasswordController: could not find the csrf token container. Password controller does not work');
return;
}
this.mailButtonWrapper = this.wrapper.querySelector('.js_password_mail');
if (!this.mailButtonWrapper) {
console.error('PasswordController: could not find the wrapper that holds a button to mail the user instructions on how to set his password. Password controller does not work');
return;
}
this.mailButton = this.mailButtonWrapper.querySelector('button');
if (!this.mailButton || !("url" in this.mailButton.dataset) || !("userId" in this.mailButton.dataset)) {
console.error('PasswordController: Could not find a button within the mail button wrapper, that has the data attributes url and user-id. Password controller does not work.');
return;
}
this.mailButtonUrl = this.mailButton.dataset.url;
this.mailButtonUserId = this.mailButton.dataset.userId;
this.mailConfirmation = this.mailButtonWrapper.querySelector('p.js_confirmation');
if (!this.mailConfirmation) {
console.error('PasswordController: Could not find a paragraph with class js_confirmation. Password controller does not work.');
return;
}
this.mailFailMessage = this.mailButtonWrapper.querySelector('p.js_fail');
if (!this.mailFailMessage) {
console.error('PasswordController: Could not find a paragraph with class js_fail. Password controller does not work.');
return;
}
this.mailButtonClicked = this.mailButtonClicked.bind(this); //Needed to make sure that "this" inside the method always refers to the password controller.
this.activateListeners(true);
}
/**
* Activates listening for keyup events on the password fields to that the passwordChanged method is triggered
*
* @param state
*/
_createClass(SendPasswordMailButton, [{
key: "activateListeners",
value: function activateListeners(state) {
if (state) {
this.mailButton.addEventListener('click', this.mailButtonClicked);
} else {
this.mailButton.removeEventListener('click', this.mailButtonClicked);
}
}
/**
* Triggered when the mail set password button was clicked.
*
* @var {MouseEvent} mouseEvent
*/
}, {
key: "mailButtonClicked",
value: function mailButtonClicked(mouseEvent) {
var self = this;
mouseEvent.preventDefault();
var request = new XMLHttpRequest();
request.open("POST", this.mailButtonUrl, true); //Send the proper header information along with the request
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.setRequestHeader("X-CSRF-TOKEN", this.csrfTokenContainer.getAttribute('content'));
request.setRequestHeader("X-Requested-With", 'XMLHttpRequest');
request.onreadystatechange = function (passwordController, originalRequest) {
return function () {
if (this.readyState === XMLHttpRequest.DONE) {
if (this.status === 200 || this.status === 204) {
passwordController.mailSend();
} else {
passwordController.mailError();
}
}
};
}(self, request);
this.mailButton.classList.add('hidden');
request.send("user_id=" + this.mailButtonUserId);
}
/**
* Triggered when the user could not be mailed the set password mail for some reason.
*/
}, {
key: "mailError",
value: function mailError() {
this.mailFailMessage.classList.remove('hidden');
}
/**
* Triggered when the user did get a set password mail.
*/
}, {
key: "mailSend",
value: function mailSend() {
this.mailConfirmation.classList.remove('hidden');
}
}]);
return SendPasswordMailButton;
}();
/**
* Helps managing classes on a button.
* You can request to add a class and for each time you request to add the class, it will increment a counter.
* You can also request to remove a class and for each time you do that, it will decrement a counter.
* When that counter hits 0 it will remove the class.
* It will keep counter for each unique class you request to add.
*/
var styleClassController =
/*#__PURE__*/
function () {
/**
* Constructor
*
* @param {HTMLElement} htmlElement
*/
function styleClassController(htmlElement) {
_classCallCheck(this, styleClassController);
this.constructedSuccessFully = false;
if (!htmlElement instanceof HTMLElement) {
console.error('styleClassController: The given htmlElement must be, but was not a HTMLElement');
return;
}
this.htmlElement = htmlElement;
this.classCounts = {};
this.constructedSuccessFully = true;
}
/**
* @param {string} styleClass
*/
_createClass(styleClassController, [{
key: "requestAddClass",
value: function requestAddClass(styleClass) {
if (!this.htmlElement.classList.contains(styleClass)) this.htmlElement.classList.add(styleClass);
if (!this.classCounts.hasOwnProperty(styleClass)) this.classCounts[styleClass] = 0;
this.classCounts[styleClass]++;
return true;
}
}, {
key: "requestRemoveClass",
value: function requestRemoveClass(styleClass) {
if (!this.htmlElement.classList.contains(styleClass) || !this.classCounts.hasOwnProperty(styleClass)) return false;
this.classCounts[styleClass]--;
if (this.classCounts[styleClass] === 0) {
delete this.classCounts[styleClass];
this.htmlElement.classList.remove(styleClass);
}
}
}]);
return styleClassController;
}(); //also @See video.blade.php
var Video =
/*#__PURE__*/
function () {
function Video(videoElementWrapper) {
_classCallCheck(this, Video);
if (videoElementWrapper === undefined || videoElementWrapper.tagName !== "DIV") {
console.error('VideoElement:constructor Missing the expected div element that represents the VideoElementWrapper.');
return;
}
this._videoElementWrapper = videoElementWrapper;
if (!('key' in videoElementWrapper.dataset)) {
console.error('VideoElement:constructor Missing the key dataset property on the videoElementWrapper');
return;
}
var key = videoElementWrapper.dataset.key;
var realInput = videoElementWrapper.querySelector('input[name="' + key + '"]');
if (!realInput) {
console.error('VideoElement:constructor Did not find a required hidden input with name "' + key + '" in the VideoElementWrapper.');
return;
}
this._realInput = realInput;
var realCheckbox = videoElementWrapper.querySelector('input[name="' + key + '_autoplay"]');
if (!realCheckbox) {
console.error('VideoElement:constructor Did not find a required checkbox input of type checkbox with name "' + key + '_autoplay" in the VideoElementWrapper.');
return;
}
this._realCheckbox = realCheckbox;
var videoIdInput = videoElementWrapper.querySelector('input[name="' + key + '_video_id"]');
if (!videoIdInput) {
console.error('VideoElement:constructor Did not find a required input of type text with name "' + key + '_video_id" in the VideoElementWrapper.');
return;
}
this._videoIdInput = videoIdInput;
this._videoWatchPath = 'https://www.youtube.com/watch?v={videoInputValue}';
this._videoImgPath = 'https://img.youtube.com/vi/{videoInputValue}/0.jpg';
this.initialize();
this.enableEventListeners();
}
_createClass(Video, [{
key: "enableEventListeners",
value: function enableEventListeners() {
this._videoIdInput.addEventListener('keyup', this.updateRealInput.bind(this));
this._realCheckbox.addEventListener('change', this.updateRealInput.bind(this));
}
}, {
key: "updateRealInput",
value: function updateRealInput(event) {
var autoPlayCheckboxValue = this._realCheckbox.checked === true ? '1' : '0';
var videoInputValue = this._videoIdInput.value;
this._realInput.value = autoPlayCheckboxValue + ',' + videoInputValue;
this.updateThumbnail(videoInputValue);
}
/**
* Generate a thumbnail with link to the video
*
* @param videoInputValue
*/
}, {
key: "updateThumbnail",
value: function updateThumbnail(videoInputValue) {
// Get the attribute that will change
var videoLink = this._videoElementWrapper.querySelector('.js-video-link');
var videoThumb = this._videoElementWrapper.querySelector('.js-video-thumb'); // Remove the attribute if the input is empty
if (!isset(videoInputValue) || videoInputValue === '') {
videoThumb.removeAttribute('src');
videoLink.removeAttribute('href');
return;
} // Get the videoThumbPath
var videoThumbPath = this._getYoutubePath(videoInputValue); // TODO: Create something like this to preven the ugly video not found image of youtube
// this._ifVideoThumbnailExists(videoThumbPath)
// Set the attribute to preview the thumbnail with a link to the video
videoThumb.setAttribute('src', videoThumbPath);
videoLink.setAttribute('href', this._getYoutubePath(videoInputValue, 'watch'));
}
/**
* Grab the desired path for a youtube link or thumbnail
*
* @param {string} videoInputValue
* @param {string} type
* @returns {string}
* @private
*/
}, {
key: "_getYoutubePath",
value: function _getYoutubePath(videoInputValue) {
var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'thumbnail';
var path = ''; // Grab the desired path and replace the placeholder with the input
switch (type) {
case 'thumbnail':
path = this._videoImgPath;
return path.replace("{videoInputValue}", videoInputValue);
case 'watch':
path = this._videoWatchPath;
return path.replace("{videoInputValue}", videoInputValue);
default:
console.alert('VideoElement:_getPath Type rule not defined');
return '';
}
} // _ifVideoThumbnailExists(videoThumbPath){
//
// Ajax.get(videoThumbPath, function (response) {
// console.log(response);
// });
//
// }
}, {
key: "initialize",
value: function initialize() {
//Get autoplay value and video id from the hidden input
if (this._realInput.value === "") return;
var splittedValue = this._realInput.value.split(',');
if (splittedValue.length < 2) console.error('VideoElement:initialize Could not initialize a video element because it received an invalid value: ', this._realInput.value);
var autoplayCheckboxValue = splittedValue[0];
var videoIdInputValue = splittedValue[1]; //Set the video id input with the videoIdInputValue
this._videoIdInput.value = videoIdInputValue;
this.updateThumbnail(videoIdInputValue); //Set the checkbox using the autoplayCheckbox value
this._realCheckbox.checked = autoplayCheckboxValue === '1';
}
}]);
return Video;
}();