platypusui
Version:
A front-end set of UI controls for PlatypusTS written in TypeScript
1,148 lines (1,147 loc) • 337 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
/* tslint:disable */
/**
* PlatypusUI v0.16.9 (https://platypi.io)
* Copyright 2015 Platypi, LLC. All rights reserved.
*
* PlatypusUI is licensed under the MIT license found at
* https://github.com/Platypi/platypusui/blob/master/LICENSE
*
*/
/**
* The entry point into the platypus UI controls library.
*/
var platui;
(function (platui) {
'use strict';
/* tslint:disable:no-unused-variable */
/*
*/
var __prefix = '$', __Promise = __prefix + "Promise", __Compat = __prefix + "Compat", __Regex = __prefix + "Regex", __Window = __prefix + "Window", __Document = __prefix + "Document", __Utils = __prefix + "Utils", __Animator = __prefix + "Animator", __DomEventInstance = __prefix + "DomEventInstance", __TemplateControlFactory = __prefix + "TemplateControlFactory", __NodeManagerStatic = __prefix + "NodeManagerStatic",
/**
*/
__CONTEXT = 'context',
/**
*/
__PlatPrefix = 'plat', __Plat = __PlatPrefix + "-", __Button = __Plat + "button", __Checkbox = __Plat + "checkbox", __Drawer = __Plat + "drawer", __DrawerController = __Drawer + "-controller", __Modal = __Plat + "modal", __ProgressBar = __Plat + "progress", __ProgressRing = __Plat + "ring", __Radio = __Plat + "radio", __Toggle = __Plat + "toggle", __Slider = __Plat + "slider", __Range = __Plat + "range", __Select = __Plat + "select", __Input = __Plat + "input", __File = __Plat + "file", __Carousel = __Plat + "carousel", __Listview = __Plat + "listview", __Navbar = __Plat + "navbar", __Image = __Plat + "image",
/**
*/
__Hide = __Plat + "hide", __Hidden = __Plat + "hidden", __Context = __Plat + __CONTEXT, __ForEach = __Plat + "foreach", __Html = __Plat + "html", __Disabled = __Plat + "disabled", __Readonly = __Plat + "readonly", __CamelContext = __PlatPrefix + "Context", __CamelChecked = __PlatPrefix + "Checked", __CamelBind = __PlatPrefix + "Bind", __CamelSrc = __PlatPrefix + "Src",
/**
*/
__listviewAliasOptions = {
index: 'index',
even: 'even',
odd: 'odd',
first: 'first',
last: 'last',
group: 'group'
},
/**
*/
__Transition = __Plat + "transition", __Enter = __Plat + "enter", __Leave = __Plat + "leave",
/**
*/
__$tap = '$tap', __$touchstart = '$touchstart', __$touchend = '$touchend', __$touchcancel = '$touchcancel', __$swipe = '$swipe', __$track = '$track', __$trackend = '$trackend', __ButtonPrefix = '__plat-button-', __RadioPrefix = '__plat-radio-', __DrawerControllerInitEvent = '__platDrawerControllerInit', __DrawerControllerFetchEvent = '__platDrawerControllerFetch', __DrawerFoundEvent = '__platDrawerFound',
/**
*/
__Reversed = '-reversed', __NAME_ATTRIBUTE = 'name', __LITERAL_RESOURCE = 'literal', __transitionNegate = {
right: 'left',
left: 'right',
up: 'down',
down: 'up'
}, __src = 'src', __preventDefault = function (ev) {
ev.preventDefault();
return false;
}, noop = function () { };
/* tslint:enable:no-unused-variable */
if (typeof window !== 'undefined') {
if (typeof window.platui === 'undefined') {
window.platui = platui;
}
if (typeof window.module === 'undefined') {
window.module = {};
}
}
/**
* An BindControl that standardizes an HTML5 button.
*/
var Button = /** @class */ (function (_super) {
__extends(Button, _super);
function Button() {
var _this = _super !== null && _super.apply(this, arguments) || this;
/**
* Replaces the <plat-button> node with
* a <button> node.
*/
_this.replaceWith = 'button';
/**
* A boolean value showing the selected state of this Button.
*/
_this._isSelected = false;
return _this;
}
/**
* Sets the classes on the proper elements.
* @param {string} className? An optional, additional class name or class names to set on the control
* in addition to its standard set.
* @param {Element} element? The element to set the class name on. Should default to
* the control's element if not specified.
*/
Button.prototype.setClasses = function (className, element) {
this.dom.addClass(element || this.element, __Button + " " + (className || ''));
};
/**
* Sets default classes.
*/
Button.prototype.initialize = function () {
this.setClasses();
};
/**
* Determine the button style and apply the proper classes.
*/
Button.prototype.loaded = function () {
var element = this.element, optionObj = this.options || {}, options = optionObj.value || {}, group = options.group, isString = this.utils.isString;
if (!isString(group)) {
group = this.attributes[__CamelBind];
if (isString(group)) {
this._group = group;
if (this.dom.hasClass(element, __Plat + "selected")) {
this._onTap();
}
this._addEventListeners();
}
return;
}
this._group = group;
if (this.dom.hasClass(element, __Plat + "selected")) {
this._onTap();
}
this._addEventListeners();
};
/**
* A function that allows this control to observe both the bound property itself as well as
* potential child properties if being bound to an object.
* @param {plat.observable.IImplementTwoWayBinding} binder The control that facilitates the
* databinding.
*/
Button.prototype.observeProperties = function (binder) {
binder.observeProperty(this._setBoundProperty);
};
/**
* The function called when the bindable property is set externally.
* @param {string} newValue The new value of the bindable property.
* @param {string} oldValue The old value of the bindable property.
* @param {string} identifier The identifier of the property being observed.
* @param {boolean} firstTime? A boolean value indicating whether this is the first time its being set.
*/
Button.prototype._setBoundProperty = function (newValue, oldValue, identifier, firstTime) {
if (!this.utils.isString(newValue) || newValue !== this.element.textContent) {
return;
}
this._onTap();
};
/**
* Add event listeners for selection.
*/
Button.prototype._addEventListeners = function () {
var _this = this;
this.addEventListener(this.element, __$tap, this._onTap, false);
this.on(__ButtonPrefix + this._group, function () {
if (_this._isSelected) {
_this.dom.removeClass(_this.element, __Plat + "selected");
_this._isSelected = false;
}
});
};
/**
* Place the pushed button in a selected state.
*/
Button.prototype._onTap = function () {
if (this._isSelected) {
return;
}
var element = this.element;
this.dom.addClass(element, __Plat + "selected");
this.dispatchEvent(__ButtonPrefix + this._group, plat.events.EventManager.DIRECT);
this._isSelected = true;
this.inputChanged(element.hasAttribute('value') ? element.getAttribute('value').trim() : element.textContent.trim());
};
Button._inject = {
_document: __Document
};
return Button;
}(plat.ui.BindControl));
platui.Button = Button;
plat.register.control(__Button, Button);
/**
* An BindControl that simulates a toggle switch.
*/
var Toggle = /** @class */ (function (_super) {
__extends(Toggle, _super);
function Toggle() {
var _this = _super !== null && _super.apply(this, arguments) || this;
/**
* The HTML template represented as a string.
*/
_this.templateString = '<div class="plat-toggle-container">\n' +
' <div class="plat-knob"></div>\n' +
'</div>\n';
/**
* A boolean value indicating whether the control is actively selected.
*/
_this.isActive = false;
/**
* The type of the control's activated element.
*/
_this._targetType = 'slide';
return _this;
}
/**
* Sets the classes on the proper elements.
* @param {string} className? An optional, additional class name or class names to set on the control
* in addition to its standard set.
* @param {Element} element? The element to set the class name on. Should default to
* the control's element if not specified.
*/
Toggle.prototype.setClasses = function (className, element) {
this.dom.addClass(element || this.element, __Toggle + " " + (className || ''));
};
/**
* Set the class name.
*/
Toggle.prototype.initialize = function () {
this.setClasses();
};
/**
* Adds the inner template to the DOM making sure to wrap text nodes in spans.
*/
Toggle.prototype.setTemplate = function () {
var isNull = this.utils.isNull, innerTemplate = this.innerTemplate;
if (isNull(innerTemplate)) {
return;
}
var span = this._document.createElement('span');
this.dom.appendChildren(innerTemplate.childNodes, span);
this.element.insertBefore(span, null);
};
/**
* Adds a listener for the tap event.
*/
Toggle.prototype.loaded = function () {
var element = this.element;
this._targetElement = element.firstElementChild;
this.addEventListener(element, __$tap, this._onTap);
this._convertChecked();
};
/**
* Toggles the active state of the control.
*/
Toggle.prototype.toggle = function () {
this._toggle(true);
};
/**
* A function that allows this control to observe both the bound property itself as well as
* potential child properties if being bound to an object.
* @param {plat.observable.IImplementTwoWayBinding} binder The control that facilitates the
* databinding.
*/
Toggle.prototype.observeProperties = function (binder) {
binder.observeProperty(this._setBoundProperty);
};
/**
* The function called when the bindable property is set externally.
* @param {any} newValue The new value of the bindable property.
* @param {any} oldValue The old value of the bindable property.
* @param {string} identifier The identifier of the property being observed.
* @param {boolean} setProperty? A boolean value indicating whether we should set
* the property if we need to toggle the state.
*/
Toggle.prototype._setBoundProperty = function (newValue, oldValue, identifier, setProperty) {
if (newValue === oldValue) {
return;
}
else if (setProperty === true && this.utils.isNull(newValue)) {
this.inputChanged(this.isActive);
return;
}
var isActive = !!newValue;
if (isActive === this.isActive) {
return;
}
this._toggle(setProperty);
};
/**
* A function for checking "checked" attributes and handling them accordingly.
* @param {any} newValue The newValue of the attribute to convert.
* @param {any} oldValue? The oldValue of the attribute to convert.
*/
Toggle.prototype._convertChecked = function () {
var element = this.element;
if (!this.utils.isNull(this.attributes[__CamelChecked])) {
this._convertAttribute(this.attributes[__CamelChecked]);
this.attributes.observe(this._convertAttribute, __CamelChecked);
}
else if (element.hasAttribute('checked')) {
this._convertAttribute(true);
}
};
/**
* A function for handling the attribute value conversion for updating the
* bound property.
* @param {any} newValue The newValue of the attribute to convert.
* @param {any} oldValue? The oldValue of the attribute to convert.
*/
Toggle.prototype._convertAttribute = function (newValue, oldValue) {
var utils = this.utils;
if (utils.isBoolean(newValue)) {
return this._setBoundProperty(newValue, oldValue, null, true);
}
else if (!utils.isString(newValue)) {
return;
}
this._setBoundProperty(newValue === 'true', oldValue === 'true', null, true);
};
/**
* The callback for a tap event.
* @param {plat.ui.IGestureEvent} ev The tap event object.
*/
Toggle.prototype._onTap = function (ev) {
if (this.element.hasAttribute('disabled')) {
return;
}
this._toggle(true);
this._trigger('change');
};
/**
* Triggers an event starting from this control's element.
* @param {string} event The event name to trigger.
*/
Toggle.prototype._trigger = function (event) {
var domEvent = plat.acquire(__DomEventInstance);
domEvent.initialize(this.element, event);
domEvent.trigger();
};
/**
* Toggles the mark and updates the bindable property if needed.
* @param {boolean} setProperty? A boolean value stating whether the bindable
* property should be updated.
*/
Toggle.prototype._toggle = function (setProperty) {
var wasActive = this.isActive, isActive = !wasActive, element = this.element;
this._activate(this._targetElement || (this._targetElement = element.firstElementChild));
this.isActive = element.checked = isActive;
if (isActive) {
element.setAttribute('checked', 'checked');
}
else {
element.removeAttribute('checked');
}
if (setProperty === true) {
this.inputChanged(isActive, wasActive);
}
};
/**
* A function to activate the given element by toggling the
* class specified as the target type.
* @param {Element} element The element to activate.
*/
Toggle.prototype._activate = function (element) {
this.dom.toggleClass(element, __Plat + this._targetType);
};
Toggle._inject = {
_document: __Document
};
return Toggle;
}(plat.ui.BindControl));
platui.Toggle = Toggle;
plat.register.control(__Toggle, Toggle);
/**
* An IBindablePropertyControl that standardizes the HTML5 checkbox.
*/
var Checkbox = /** @class */ (function (_super) {
__extends(Checkbox, _super);
function Checkbox() {
var _this = _super !== null && _super.apply(this, arguments) || this;
/**
* The HTML template represented as a string.
*/
_this.templateString = '<div class="plat-checkbox-container">\n' +
' <span class="plat-mark"></span>\n' +
'</div>\n';
/**
* Whether the target type has been set already or not.
*/
_this._targetTypeSet = false;
return _this;
}
/**
* Sets the classes on the proper elements.
* @param {string} className? An optional, additional class name or class names to set on the control
* in addition to its standard set.
* @param {Element} element? The element to set the class name on. Should default to
* the control's element if not specified.
*/
Checkbox.prototype.setClasses = function (className, element) {
this.dom.addClass(element || this.element, __Checkbox + " " + (className || ''));
};
/**
* Checks for checked attributes and handles them accordingly. Also,
* initializes the mark and adds a listener for the tap event.
*/
Checkbox.prototype.loaded = function () {
_super.prototype.loaded.call(this);
var optionObj = this.options || {}, options = optionObj.value || {}, previousType = this._targetType, mark = this._targetType = options.mark || 'check';
switch (mark.toLowerCase()) {
case 'check':
case 'x':
break;
default:
this._log.debug("Invalid mark option specified for " + this.type + ". Defaulting to checkmark.");
this._targetType = 'check';
break;
}
if (this._targetTypeSet) {
var target = this._targetElement;
this.dom.removeClass(target, previousType);
this._activate(target);
}
this._targetTypeSet = true;
};
/**
* A function to activate the given element by toggling the
* class specified as the target type.
* @param {Element} element The element to activate.
*/
Checkbox.prototype._activate = function (element) {
if (this._targetTypeSet) {
this.dom.toggleClass(element, __Plat + this._targetType);
return;
}
this._targetTypeSet = true;
};
return Checkbox;
}(Toggle));
platui.Checkbox = Checkbox;
plat.register.control(__Checkbox, Checkbox);
/**
* An IBindablePropertyControl that standardizes the HTML5 radio button.
*/
var Radio = /** @class */ (function (_super) {
__extends(Radio, _super);
function Radio() {
var _this = _super !== null && _super.apply(this, arguments) || this;
/**
* The HTML template represented as a string.
*/
_this.templateString = '<div class="plat-radio-container">\n' +
' <div class="plat-mark"></div>\n' +
'</div>\n';
/**
* The radio groups name if a radio group is present.
*/
_this.groupName = '';
/**
* The check type to be placed in the element.
*/
_this._targetType = 'bullet';
/**
* Whether the target type has been set already or not.
*/
_this._targetTypeSet = true;
return _this;
}
/**
* Sets the classes on the proper elements.
* @param {string} className? An optional, additional class name or class names to set on the control
* in addition to its standard set.
* @param {Element} element? The element to set the class name on. Should default to
* the control's element if not specified.
*/
Radio.prototype.setClasses = function (className, element) {
this.dom.addClass(element || this.element, __Radio + " " + (className || ''));
};
/**
* Checks for a radio group and converts "checked" attributes.
*/
Radio.prototype.loaded = function () {
var element = this.element;
this._targetElement = element.firstElementChild;
this.addEventListener(element, __$tap, this._onTap);
if (element.hasAttribute(__NAME_ATTRIBUTE)) {
this.groupName = element.getAttribute(__NAME_ATTRIBUTE);
}
else if (!this.utils.isNull(this.attributes[__CamelBind])) {
this.groupName = this.attributes[__CamelBind];
}
this._convertChecked();
};
/**
* Checks if the radio has been selected and only notifies of a bindable
* property changed if it has.
* @param {any} newValue? The new value of the property after the change.
* @param {any} oldValue? The old value of the property prior to the change.
*/
Radio.prototype.inputChanged = function (newValue, oldValue) {
if (this.isActive) {
_super.prototype.inputChanged.call(this, this._getValue());
}
};
/**
* The function called when the bindable property is set externally.
* @param {any} newValue The new value of the bindable property.
* @param {any} oldValue The old value of the bindable property.
* @param {string} identifier The identifier of the property being observed.
* @param {boolean} setProperty? A boolean value indicating whether we should set
* the property if we need to toggle the mark.
*/
Radio.prototype._setBoundProperty = function (newValue, oldValue, identifier, setProperty) {
var utils = this.utils;
if (newValue === oldValue) {
return;
}
else if (setProperty === true && utils.isNull(newValue)) {
this.inputChanged();
return;
}
var value = this._getValue(), isChecked = newValue === value, wasChecked = this.isActive;
if (isChecked) {
if (wasChecked) {
return;
}
}
else if (utils.isNull(newValue)) {
if (!wasChecked) {
return;
}
}
else {
var newValueStr = utils.isFunction(newValue.toString) ? newValue.toString() : Object.prototype.toString.call(newValue);
if (wasChecked) {
if (newValueStr === value) {
return;
}
}
else {
if (newValueStr !== value) {
return;
}
}
}
this._toggle(setProperty);
};
/**
* The callback for a tap event. Only fires the event if the Radio
* has been selected.
* @param {plat.ui.IGestureEvent} ev The tap event object.
*/
Radio.prototype._onTap = function (ev) {
if (this.isActive) {
return;
}
_super.prototype._onTap.call(this, ev);
};
/**
* Toggles the mark and updates the bindable property if needed.
* @param {boolean} setProperty? A boolean value stating whether the bindable
* property should be updated.
*/
Radio.prototype._toggle = function (setProperty) {
var _this = this;
_super.prototype._toggle.call(this, setProperty);
if (this.utils.isFunction(this._removeListener)) {
this._removeListener();
this._removeListener = null;
}
if (this.isActive) {
var name_1 = this.groupName;
this.dispatchEvent(__RadioPrefix + name_1, plat.events.EventManager.DIRECT);
var remover_1 = this._removeListener = this.on(__RadioPrefix + name_1, function () {
_this._toggle();
remover_1();
});
}
};
/**
* A function for handling the attribute value conversion for updating the
* bound property.
* @param {any} newValue The newValue of the attribute to convert.
* @param {any} oldValue? The oldValue of the attribute to convert.
*/
Radio.prototype._convertAttribute = function (newValue, oldValue) {
var utils = this.utils;
if (utils.isBoolean(newValue)) {
if (newValue) {
this._setBoundProperty(this._getValue(), null, null, true);
}
return;
}
else if (!utils.isString(newValue)) {
return;
}
if (newValue === 'true') {
this._setBoundProperty(this._getValue(), null, null, true);
}
};
/**
* Grabs the value of this Radio's bindable property. It first checks for
* the "value" attribute, and defaults to the elements textContent if it's unavailable.
*/
Radio.prototype._getValue = function () {
var element = this.element;
return element.hasAttribute('value') ? element.getAttribute('value').trim() : element.textContent.trim();
};
return Radio;
}(Checkbox));
platui.Radio = Radio;
plat.register.control(__Radio, Radio);
/**
* An ITemplateControl for showing indeterminate progress.
*/
var ProgressRing = /** @class */ (function (_super) {
__extends(ProgressRing, _super);
function ProgressRing() {
var _this = _super !== null && _super.apply(this, arguments) || this;
/**
* The HTML template represented as a string.
*/
_this.templateString = '<div class="plat-animated-ring"></div>';
return _this;
}
/**
* Sets the classes on the proper elements.
* @param {string} className? An optional, additional class name or class names to set on the control
* in addition to its standard set.
* @param {Element} element? The element to set the class name on. Should default to
* the control's element if not specified.
*/
ProgressRing.prototype.setClasses = function (className, element) {
this.dom.addClass(element || this.element, __ProgressRing + " " + (className || ''));
};
/**
* Set the class name.
*/
ProgressRing.prototype.initialize = function () {
this.setClasses();
};
/**
* Set the animation.
*/
ProgressRing.prototype.loaded = function () {
var options = this.options, utils = this.utils, isObject = utils.isObject, style = 0;
if (isObject(options) && isObject(options.value)) {
style = options.value.style;
if (!utils.isNumber(style)) {
style = 0;
}
}
this.dom.addClass(this.element, __ProgressRing + "-" + style);
if (style === 0) {
return;
}
this._addAnimatedElements(style);
};
/**
* Adds any needed DOM for the animation.
*/
ProgressRing.prototype._addAnimatedElements = function (style) {
var _document = plat.acquire(__Document), fragment = _document.createDocumentFragment(), count = style === 2 ? 12 : 4, div = 'div', classPrefix = __Plat + "animated-child " + __Plat + "animated-child-", child;
for (var i = 0; i < count; ++i) {
child = _document.createElement(div);
child.className = classPrefix + i;
fragment.insertBefore(child, null);
}
this.element.firstElementChild.insertBefore(fragment, null);
};
return ProgressRing;
}(plat.ui.TemplateControl));
platui.ProgressRing = ProgressRing;
plat.register.control(__ProgressRing, ProgressRing);
/**
* An ITemplateControl for showing incremental progress.
*/
var ProgressBar = /** @class */ (function (_super) {
__extends(ProgressBar, _super);
function ProgressBar() {
var _this = _super !== null && _super.apply(this, arguments) || this;
/**
* The HTML template represented as a string.
*/
_this.templateString = '<div class="plat-progress-container">\n' +
' <div class="plat-animated-bar"></div>\n' +
'</div>\n';
/**
* A function that will stop listening for visibility if applicable.
*/
_this._removeVisibilityListener = noop;
return _this;
}
/**
* Sets the classes on the proper elements.
* @param {string} className? An optional, additional class name or class names to set on the control
* in addition to its standard set.
* @param {Element} element? The element to set the class name on. Should default to
* the control's element if not specified.
*/
ProgressBar.prototype.setClasses = function (className, element) {
this.dom.addClass(element || this.element, __ProgressBar + " " + (className || ''));
};
/**
* Set the class name.
*/
ProgressBar.prototype.initialize = function () {
this.setClasses();
};
/**
* Grabs the bar element then sets any initial progress.
*/
ProgressBar.prototype.loaded = function () {
var _this = this;
this._barElement = this.element.firstElementChild.firstElementChild;
this.addEventListener(this._window, 'resize', function () {
_this.setProgress(_this.context);
});
this.setProgress(this.context);
};
/**
* Removes the visibility listener if applicable.
*/
ProgressBar.prototype.dispose = function () {
this._removeVisibilityListener();
};
/**
* Animates the bar on a context changed.
*/
ProgressBar.prototype.contextChanged = function () {
this.setProgress(this.context);
};
/**
* Sets the progress bar value.
* @param {number} value The decimal number between 0 and 1 to set as the
* bar percentage (e.g. - 0.5 would be 50% complete).
*/
ProgressBar.prototype.setProgress = function (value) {
var _this = this;
return new this._Promise(function (resolve, reject) {
if (!_this.utils.isNumber(value) || value > 1 || value < 0) {
var msg = "The value of a \"" + _this.type + "\" control must be a number between 0 and 1.";
_this._log.debug(msg);
reject(msg);
return;
}
var barElement = _this._barElement, barMax = barElement.parentElement.clientWidth;
if (!barMax) {
_this._removeVisibilityListener();
_this._removeVisibilityListener = _this.dom.whenVisible(function () {
_this.setProgress(value).then(resolve);
}, _this.element);
return;
}
_this._animator.animate(barElement, __Transition, {
properties: {
width: Math.ceil(barMax * value) + "px"
}
}).then(function () {
resolve();
});
});
};
ProgressBar._inject = {
_window: __Window,
_Promise: __Promise,
_animator: __Animator
};
return ProgressBar;
}(plat.ui.TemplateControl));
platui.ProgressBar = ProgressBar;
plat.register.control(__ProgressBar, ProgressBar);
/**
* An BindControl that acts as a global drawer.
*/
var Drawer = /** @class */ (function (_super) {
__extends(Drawer, _super);
/**
* The constructor for a Drawer. Creates the ready Promise.
*/
function Drawer() {
var _this = _super.call(this) || this;
/**
* References to all the DrawerControllers used to control this Drawer.
*/
_this._controllers = [];
/**
* Whether or not the this control has been paired with a corresponding Drawer.
*/
_this._isInitialized = false;
/**
* A bound value that may have come through prior to initialization.
*/
_this._preInitializedValue = false;
/**
* A private variable that tells the Drawer its last open or closed state.
*/
_this.__state = false;
/**
* A private variable that tells the Drawer its next open or closed state.
*/
_this.__nextState = false;
_this.ready = _this._Promise.resolve();
return _this;
}
/**
* Sets the classes on the proper elements.
* @param {string} className? An optional, additional class name or class names to set on the control
* in addition to its standard set.
* @param {Element} element? The element to set the class name on. Should default to
* the control's element if not specified.
*/
Drawer.prototype.setClasses = function (className, element) {
this.dom.addClass(element || this.element, __Drawer + " " + (className || ''));
};
/**
* Set the class name and hides the element and
* removes the innerHTML from the DOM and saves it.
*/
Drawer.prototype.initialize = function () {
this.setClasses();
};
/**
* Removes the innerHTML from the DOM and saves it.
*/
Drawer.prototype.setTemplate = function () {
this.innerTemplate = this.dom.appendChildren(this.element.childNodes);
};
/**
* Check for a position and initialize event handling.
*/
Drawer.prototype.loaded = function () {
var _this = this;
var element = this.element, utils = this.utils, optionObj = this.options || {}, options = optionObj.value || {}, position = this._currentPosition = options.position || 'left', id = options.id || '', templateUrl = options.templateUrl, isElastic = options.elastic === true;
element.setAttribute(__Hide, '');
this.dom.addClass(element, __Plat + position);
if (utils.isString(templateUrl)) {
plat.ui.TemplateControl.determineTemplate(this, templateUrl).then(function (template) {
_this.innerTemplate = template;
_this._initializeEvents(id, position, isElastic);
});
return;
}
this._initializeEvents(id, position, isElastic);
};
/**
* Opens the Drawer.
*/
Drawer.prototype.open = function () {
var controller = this._controllers[0];
if (this.utils.isNull(controller)) {
this._log.debug("No controller, such as a " + __DrawerController + ", found for the " + this.type + " attempting to open.");
return this._Promise.resolve();
}
return controller.open();
};
/**
* Closes the Drawer.
*/
Drawer.prototype.close = function () {
var controller = this._controllers[0];
if (this.utils.isNull(controller)) {
this._log.debug("No controller, such as a " + __DrawerController + ", found for the " + this.type + " attempting to close.");
return this._Promise.resolve();
}
return controller.close();
};
/**
* Toggles the Drawer's open/closed state.
*/
Drawer.prototype.toggle = function () {
var controller = this._controllers[0];
if (this.utils.isNull(controller)) {
this._log.debug("No controller, such as a " + __DrawerController + ", found for the " + this.type + " attempting to toggle.");
return this._Promise.resolve();
}
return controller.toggle();
};
/**
* Indicates whether the Drawer is currently open.
*/
Drawer.prototype.isOpen = function () {
var controller = this._controllers[0];
if (this.utils.isNull(controller)) {
this._log.debug("No controller, such as a " + __DrawerController + ", found for the " + this.type + " attempting to check if open.");
return false;
}
return controller.isOpen();
};
/**
* Adds and binds the added HTML template to this control's inherited context.
* @param {string} name The template name to both add and bind.
* @param {Node} node The node to add as a bindable template.
*/
Drawer.prototype.bindTemplate = function (name, node) {
var _this = this;
var bindableTemplates = this.bindableTemplates;
bindableTemplates.add(name, node);
return bindableTemplates.bind(name).then(function (template) {
var element = _this.element;
_this.dom.clearNode(element);
element.appendChild(template);
}).catch(function (error) {
_this._log.debug("Error binding template for " + _this.type + ": " + error);
});
};
/**
* Returns the number of DrawerControllers linked to this
* Drawer.
*/
Drawer.prototype.controllerCount = function () {
return this._controllers.length;
};
/**
* Removes a specified DrawerController from this control's Array of
* linked DrawerControllers.
* @param {platui.DrawerController} controller The DrawerController
* to splice.
*/
Drawer.prototype.spliceController = function (controller) {
var controllers = this._controllers, index = controllers.indexOf(controller);
if (index === -1) {
return;
}
this.__state = this.__nextState = controllers[index].isOpen();
controllers.splice(index, 1);
};
/**
* A function that allows this control to observe both the bound property itself as well as
* potential child properties if being bound to an object.
* @param {plat.observable.IImplementTwoWayBinding} binder The control that facilitates the
* databinding.
*/
Drawer.prototype.observeProperties = function (binder) {
binder.observeProperty(this._setBoundProperty);
};
/**
* The function called when the bindable property is set externally.
* @param {boolean} newValue The new value of the control state.
* @param {boolean} oldValue The old value of the bindable control state.
* @param {void} identifier The child identifier of the property being observed.
* @param {boolean} firstTime? Whether or not this is the first call to bind the property.
*/
Drawer.prototype._setBoundProperty = function (newValue, oldValue, identifier, firstTime) {
var utils = this.utils, controller = this._controllers[0];
if (firstTime === true && utils.isNull(newValue)) {
this.inputChanged(utils.isNull(controller) ? false : controller.isOpen());
return;
}
var drawerState = !!newValue;
if (drawerState !== newValue) {
this.inputChanged(drawerState);
}
if (!this._isInitialized) {
this._preInitializedValue = drawerState;
}
else if (utils.isNull(controller)) {
this.__nextState = drawerState;
}
else if (drawerState) {
if (controller.isOpen()) {
return;
}
controller.open();
}
else if (controller.isOpen()) {
controller.close();
}
};
/**
* Changes the placement and implied position of the Drawer.
* @param {string} position The new position to change to.
*/
Drawer.prototype._changeDirection = function (position) {
if (this.utils.isNull(position) || position === this._currentPosition) {
return;
}
var dom = this.dom, element = this.element;
dom.removeClass(element, __Plat + this._currentPosition);
dom.addClass(element, __Plat + position);
this._currentPosition = position;
};
/**
* Initializes and dispatches pub sub events.
* @param {string} id The ID of this Drawer if used.
* @param {string} position The position.
* @param {boolean} isElastic Whether or not the Drawer has an
* elastic transition effect.
*/
Drawer.prototype._initializeEvents = function (id, position, isElastic) {
var _this = this;
var utils = this.utils, innerTemplate = this.innerTemplate;
this.on(__DrawerControllerFetchEvent + "_" + id, function (event, controllerArg) {
var control = controllerArg.control;
if (utils.isNull(control)) {
return;
}
if (utils.isString(controllerArg.position)) {
position = controllerArg.position;
_this._changeDirection(position);
}
_this._controllers.unshift(control);
if (!controllerArg.received) {
_this.ready.then(function () {
_this.dispatchEvent(__DrawerFoundEvent + "_" + id, plat.events.EventManager.DIRECT, {
control: _this,
received: true,
position: position,
template: utils.isNode(innerTemplate) ? innerTemplate.cloneNode(true) : null,
elastic: isElastic,
state: _this.__state,
nextState: _this.__nextState
});
});
}
_this._isInitialized = true;
if (!controllerArg.useContext) {
_this.bindTemplate('drawer', innerTemplate.cloneNode(true)).then(function () {
_this._checkPreInit();
});
return;
}
_this._checkPreInit();
});
this.dispatchEvent(__DrawerFoundEvent + "_" + id, plat.events.EventManager.DIRECT, {
control: this,
received: false,
position: position,
template: utils.isNode(innerTemplate) ? innerTemplate.cloneNode(true) : null,
elastic: isElastic,
state: this.__state,
nextState: this.__nextState
});
};
/**
* Checks the pre-initialized value and handles accordingly.
*/
Drawer.prototype._checkPreInit = function () {
var _this = this;
if (this._preInitializedValue) {
var utils_1 = this.utils;
utils_1.postpone(function () {
var controller = _this._controllers[0];
if (!utils_1.isNull(controller)) {
controller.open();
}
});
}
};
Drawer._inject = {
_Promise: __Promise
};
return Drawer;
}(plat.ui.BindControl));
platui.Drawer = Drawer;
plat.register.control(__Drawer, Drawer);
/**
* An BindControl that manipulates and controls a global drawer.
*/
var DrawerController = /** @class */ (function (_super) {
__extends(DrawerController, _super);
function DrawerController() {
var _this = _super !== null && _super.apply(this, arguments) || this;
/**
* Whether or not the user has swiped.
*/
_this._hasSwiped = false;
/**
* Whether or not the user has tapped.
*/
_this._hasTapped = false;
/**
* Whether or not the Drawer is open.
*/
_this._isOpen = false;
/**
* An enum denoting the current touch state of the user.
*/
_this._touchState = 0;
/**
* Whether the corresponding Drawer is vertical or horizontal.
*/
_this._isVertical = false;
/**
* A function for removing the click eater scroll listening event.
*/
_this._removeClickEaterListener = noop;
/**
* A function to remove the toggle delay if present.
*/
_this._toggleDelay = noop;
/**
* Whether or not the this control has been paired with a corresponding Drawer.
*/
_this._isInitialized = false;
return _this;
}
/**
* Sets the classes on the proper elements.
* @param {string} className? An optional, additional class name or class names to set on the control
* in addition to its standard set.
* @param {Element} element? The element to set the class name on. Should default to
* the control's element if not specified.
*/
DrawerController.prototype.setClasses = function (className, element) {
this.dom.addClass(element || this.element, __DrawerController + " " + (className || ''));
};
/**
* Sets the class name on the element.
*/
DrawerController.prototype.initialize = function () {
this.dom.addClass(this.element, __DrawerController);
};
/**
* Initialize the track events on the element.
*/
DrawerController.prototype.loaded = function () {
var optionObj = this.options || {}, options = optionObj.value || {}, position = options.position, id = options.id || '';
this._type = options.type || 'tap track';
this._isElastic = options.elastic;
this._useContext = options.useContext === true;
this._templateUrl = options.templateUrl;
this._initializeEvents(id, position);
};
/**
* Remove the transition classes off the root element and reset the position and
* zIndex properties if modified and only if this is the last DrawerController
* referencing this Drawer.
*/
DrawerController.prototype.dispose = function () {
var _this = this;
_super.prototype.dispose.call(this);
var drawer = this._drawer;
if (this.utils.isNull(drawer)) {
return;
}
if (drawer.controllerCount() > 1) {
drawer.spliceController(this);
return;
}
else if (this._isOpen) {
drawer.ready = this.close().then(function () {
drawer.spliceController(_this);
if (drawer.controllerCount() > 0) {
return;
}
_this._cleanRootElement();
});
return;