mirror of
https://gitlab.silvrtree.co.uk/martind2000/mdot_server.git
synced 2025-01-30 23:10:15 +00:00
1809 lines
43 KiB
JavaScript
1809 lines
43 KiB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
|
/**
|
|
* MUI CSS/JS main module
|
|
* @module main
|
|
*/
|
|
|
|
(function(win) {
|
|
'use strict';
|
|
|
|
// return if library has been loaded already
|
|
if (win._muiLoadedJS) return;
|
|
else win._muiLoadedJS = true;
|
|
|
|
// load dependencies
|
|
var jqLite = require('src/js/lib/jqLite'),
|
|
dropdown = require('src/js/dropdown'),
|
|
overlay = require('src/js/overlay'),
|
|
ripple = require('src/js/ripple'),
|
|
select = require('src/js/select'),
|
|
tabs = require('src/js/tabs'),
|
|
textfield = require('src/js/textfield');
|
|
|
|
// expose api
|
|
win.mui = {
|
|
overlay: overlay,
|
|
tabs: tabs.api
|
|
};
|
|
|
|
// init libraries
|
|
jqLite.ready(function() {
|
|
textfield.initListeners();
|
|
select.initListeners();
|
|
ripple.initListeners();
|
|
dropdown.initListeners();
|
|
tabs.initListeners();
|
|
});
|
|
})(window);
|
|
|
|
},{"src/js/dropdown":6,"src/js/lib/jqLite":7,"src/js/overlay":8,"src/js/ripple":9,"src/js/select":10,"src/js/tabs":11,"src/js/textfield":12}],2:[function(require,module,exports){
|
|
/**
|
|
* MUI config module
|
|
* @module config
|
|
*/
|
|
|
|
/** Define module API */
|
|
module.exports = {
|
|
/** Use debug mode */
|
|
debug: true
|
|
};
|
|
|
|
},{}],3:[function(require,module,exports){
|
|
/**
|
|
* MUI CSS/JS form helpers module
|
|
* @module lib/forms.py
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var wrapperPadding = 15, // from CSS
|
|
inputHeight = 32, // from CSS
|
|
optionHeight = 42, // from CSS
|
|
menuPadding = 8; // from CSS
|
|
|
|
|
|
/**
|
|
* Menu position/size/scroll helper
|
|
* @returns {Object} Object with keys 'height', 'top', 'scrollTop'
|
|
*/
|
|
function getMenuPositionalCSSFn(wrapperEl, numOptions, currentIndex) {
|
|
var viewHeight = document.documentElement.clientHeight;
|
|
|
|
// determine 'height'
|
|
var h = numOptions * optionHeight + 2 * menuPadding,
|
|
height = Math.min(h, viewHeight);
|
|
|
|
// determine 'top'
|
|
var top, initTop, minTop, maxTop;
|
|
|
|
initTop = (menuPadding + optionHeight) - (wrapperPadding + inputHeight);
|
|
initTop -= currentIndex * optionHeight;
|
|
|
|
minTop = -1 * wrapperEl.getBoundingClientRect().top;
|
|
maxTop = (viewHeight - height) + minTop;
|
|
|
|
top = Math.min(Math.max(initTop, minTop), maxTop);
|
|
|
|
// determine 'scrollTop'
|
|
var scrollTop = 0,
|
|
scrollIdeal,
|
|
scrollMax;
|
|
|
|
if (h > viewHeight) {
|
|
scrollIdeal = (menuPadding + (currentIndex + 1) * optionHeight) -
|
|
(-1 * top + wrapperPadding + inputHeight);
|
|
scrollMax = numOptions * optionHeight + 2 * menuPadding - height;
|
|
scrollTop = Math.min(scrollIdeal, scrollMax);
|
|
}
|
|
|
|
return {
|
|
'height': height + 'px',
|
|
'top': top + 'px',
|
|
'scrollTop': scrollTop
|
|
};
|
|
}
|
|
|
|
|
|
/** Define module API */
|
|
module.exports = {
|
|
getMenuPositionalCSS: getMenuPositionalCSSFn
|
|
};
|
|
|
|
},{}],4:[function(require,module,exports){
|
|
/**
|
|
* MUI CSS/JS jqLite module
|
|
* @module lib/jqLite
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
|
|
/**
|
|
* Add a class to an element.
|
|
* @param {Element} element - The DOM element.
|
|
* @param {string} cssClasses - Space separated list of class names.
|
|
*/
|
|
function jqLiteAddClass(element, cssClasses) {
|
|
if (!cssClasses || !element.setAttribute) return;
|
|
|
|
var existingClasses = _getExistingClasses(element),
|
|
splitClasses = cssClasses.split(' '),
|
|
cssClass;
|
|
|
|
for (var i=0; i < splitClasses.length; i++) {
|
|
cssClass = splitClasses[i].trim();
|
|
if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
|
|
existingClasses += cssClass + ' ';
|
|
}
|
|
}
|
|
|
|
element.setAttribute('class', existingClasses.trim());
|
|
}
|
|
|
|
|
|
/**
|
|
* Get or set CSS properties.
|
|
* @param {Element} element - The DOM element.
|
|
* @param {string} [name] - The property name.
|
|
* @param {string} [value] - The property value.
|
|
*/
|
|
function jqLiteCss(element, name, value) {
|
|
// Return full style object
|
|
if (name === undefined) {
|
|
return getComputedStyle(element);
|
|
}
|
|
|
|
var nameType = jqLiteType(name);
|
|
|
|
// Set multiple values
|
|
if (nameType === 'object') {
|
|
for (var key in name) element.style[_camelCase(key)] = name[key];
|
|
return;
|
|
}
|
|
|
|
// Set a single value
|
|
if (nameType === 'string' && value !== undefined) {
|
|
element.style[_camelCase(name)] = value;
|
|
}
|
|
|
|
var styleObj = getComputedStyle(element),
|
|
isArray = (jqLiteType(name) === 'array');
|
|
|
|
// Read single value
|
|
if (!isArray) return _getCurrCssProp(element, name, styleObj);
|
|
|
|
// Read multiple values
|
|
var outObj = {},
|
|
key;
|
|
|
|
for (var i=0; i < name.length; i++) {
|
|
key = name[i];
|
|
outObj[key] = _getCurrCssProp(element, key, styleObj);
|
|
}
|
|
|
|
return outObj;
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if element has class.
|
|
* @param {Element} element - The DOM element.
|
|
* @param {string} cls - The class name string.
|
|
*/
|
|
function jqLiteHasClass(element, cls) {
|
|
if (!cls || !element.getAttribute) return false;
|
|
return (_getExistingClasses(element).indexOf(' ' + cls + ' ') > -1);
|
|
}
|
|
|
|
|
|
/**
|
|
* Return the type of a variable.
|
|
* @param {} somevar - The JavaScript variable.
|
|
*/
|
|
function jqLiteType(somevar) {
|
|
// handle undefined
|
|
if (somevar === undefined) return 'undefined';
|
|
|
|
// handle others (of type [object <Type>])
|
|
var typeStr = Object.prototype.toString.call(somevar);
|
|
if (typeStr.indexOf('[object ') === 0) {
|
|
return typeStr.slice(8, -1).toLowerCase();
|
|
} else {
|
|
throw new Error("MUI: Could not understand type: " + typeStr);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Attach an event handler to a DOM element
|
|
* @param {Element} element - The DOM element.
|
|
* @param {string} type - The event type name.
|
|
* @param {Function} callback - The callback function.
|
|
* @param {Boolean} useCapture - Use capture flag.
|
|
*/
|
|
function jqLiteOn(element, type, callback, useCapture) {
|
|
useCapture = (useCapture === undefined) ? false : useCapture;
|
|
|
|
// add to DOM
|
|
element.addEventListener(type, callback, useCapture);
|
|
|
|
// add to cache
|
|
var cache = element._muiEventCache = element._muiEventCache || {};
|
|
cache[type] = cache[type] || [];
|
|
cache[type].push([callback, useCapture]);
|
|
}
|
|
|
|
|
|
/**
|
|
* Remove an event handler from a DOM element
|
|
* @param {Element} element - The DOM element.
|
|
* @param {string} type - The event type name.
|
|
* @param {Function} callback - The callback function.
|
|
* @param {Boolean} useCapture - Use capture flag.
|
|
*/
|
|
function jqLiteOff(element, type, callback, useCapture) {
|
|
useCapture = (useCapture === undefined) ? false : useCapture;
|
|
|
|
// remove from cache
|
|
var cache = element._muiEventCache = element._muiEventCache || {},
|
|
argsList = cache[type] || [],
|
|
args,
|
|
i;
|
|
|
|
i = argsList.length;
|
|
while (i--) {
|
|
args = argsList[i];
|
|
|
|
// remove all events if callback is undefined
|
|
if (callback === undefined ||
|
|
(args[0] === callback && args[1] === useCapture)) {
|
|
|
|
// remove from cache
|
|
argsList.splice(i, 1);
|
|
|
|
// remove from DOM
|
|
element.removeEventListener(type, args[0], args[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Attach an event hander which will only execute once
|
|
* @param {Element} element - The DOM element.
|
|
* @param {string} type - The event type name.
|
|
* @param {Function} callback - The callback function.
|
|
* @param {Boolean} useCapture - Use capture flag.
|
|
*/
|
|
function jqLiteOne(element, type, callback, useCapture) {
|
|
jqLiteOn(element, type, function onFn(ev) {
|
|
// execute callback
|
|
if (callback) callback.apply(this, arguments);
|
|
|
|
// remove wrapper
|
|
jqLiteOff(element, type, onFn);
|
|
}, useCapture);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get or set horizontal scroll position
|
|
* @param {Element} element - The DOM element
|
|
* @param {number} [value] - The scroll position
|
|
*/
|
|
function jqLiteScrollLeft(element, value) {
|
|
var win = window;
|
|
|
|
// get
|
|
if (value === undefined) {
|
|
if (element === win) {
|
|
var docEl = document.documentElement;
|
|
return (win.pageXOffset || docEl.scrollLeft) - (docEl.clientLeft || 0);
|
|
} else {
|
|
return element.scrollLeft;
|
|
}
|
|
}
|
|
|
|
// set
|
|
if (element === win) win.scrollTo(value, jqLiteScrollTop(win));
|
|
else element.scrollLeft = value;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get or set vertical scroll position
|
|
* @param {Element} element - The DOM element
|
|
* @param {number} value - The scroll position
|
|
*/
|
|
function jqLiteScrollTop(element, value) {
|
|
var win = window;
|
|
|
|
// get
|
|
if (value === undefined) {
|
|
if (element === win) {
|
|
var docEl = document.documentElement;
|
|
return (win.pageYOffset || docEl.scrollTop) - (docEl.clientTop || 0);
|
|
} else {
|
|
return element.scrollTop;
|
|
}
|
|
}
|
|
|
|
// set
|
|
if (element === win) win.scrollTo(jqLiteScrollLeft(win), value);
|
|
else element.scrollTop = value;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return object representing top/left offset and element height/width.
|
|
* @param {Element} element - The DOM element.
|
|
*/
|
|
function jqLiteOffset(element) {
|
|
var win = window,
|
|
rect = element.getBoundingClientRect(),
|
|
scrollTop = jqLiteScrollTop(win),
|
|
scrollLeft = jqLiteScrollLeft(win);
|
|
|
|
return {
|
|
top: rect.top + scrollTop,
|
|
left: rect.left + scrollLeft,
|
|
height: rect.height,
|
|
width: rect.width
|
|
};
|
|
}
|
|
|
|
|
|
/**
|
|
* Attach a callback to the DOM ready event listener
|
|
* @param {Function} fn - The callback function.
|
|
*/
|
|
function jqLiteReady(fn) {
|
|
var done = false,
|
|
top = true,
|
|
doc = document,
|
|
win = doc.defaultView,
|
|
root = doc.documentElement,
|
|
add = doc.addEventListener ? 'addEventListener' : 'attachEvent',
|
|
rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent',
|
|
pre = doc.addEventListener ? '' : 'on';
|
|
|
|
var init = function(e) {
|
|
if (e.type == 'readystatechange' && doc.readyState != 'complete') {
|
|
return;
|
|
}
|
|
|
|
(e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
|
|
if (!done && (done = true)) fn.call(win, e.type || e);
|
|
};
|
|
|
|
var poll = function() {
|
|
try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
|
|
init('poll');
|
|
};
|
|
|
|
if (doc.readyState == 'complete') {
|
|
fn.call(win, 'lazy');
|
|
} else {
|
|
if (doc.createEventObject && root.doScroll) {
|
|
try { top = !win.frameElement; } catch(e) { }
|
|
if (top) poll();
|
|
}
|
|
doc[add](pre + 'DOMContentLoaded', init, false);
|
|
doc[add](pre + 'readystatechange', init, false);
|
|
win[add](pre + 'load', init, false);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Remove classes from a DOM element
|
|
* @param {Element} element - The DOM element.
|
|
* @param {string} cssClasses - Space separated list of class names.
|
|
*/
|
|
function jqLiteRemoveClass(element, cssClasses) {
|
|
if (!cssClasses || !element.setAttribute) return;
|
|
|
|
var existingClasses = _getExistingClasses(element),
|
|
splitClasses = cssClasses.split(' '),
|
|
cssClass;
|
|
|
|
for (var i=0; i < splitClasses.length; i++) {
|
|
cssClass = splitClasses[i].trim();
|
|
while (existingClasses.indexOf(' ' + cssClass + ' ') >= 0) {
|
|
existingClasses = existingClasses.replace(' ' + cssClass + ' ', ' ');
|
|
}
|
|
}
|
|
|
|
element.setAttribute('class', existingClasses.trim());
|
|
}
|
|
|
|
|
|
// ------------------------------
|
|
// Utilities
|
|
// ------------------------------
|
|
var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g,
|
|
MOZ_HACK_REGEXP = /^moz([A-Z])/,
|
|
ESCAPE_REGEXP = /([.*+?^=!:${}()|\[\]\/\\])/g,
|
|
BOOLEAN_ATTRS;
|
|
|
|
|
|
BOOLEAN_ATTRS = {
|
|
multiple: true,
|
|
selected: true,
|
|
checked: true,
|
|
disabled: true,
|
|
readonly: true,
|
|
required: true,
|
|
open: true
|
|
}
|
|
|
|
|
|
function _getExistingClasses(element) {
|
|
var classes = (element.getAttribute('class') || '').replace(/[\n\t]/g, '');
|
|
return ' ' + classes + ' ';
|
|
}
|
|
|
|
|
|
function _camelCase(name) {
|
|
return name.
|
|
replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
|
|
return offset ? letter.toUpperCase() : letter;
|
|
}).
|
|
replace(MOZ_HACK_REGEXP, 'Moz$1');
|
|
}
|
|
|
|
|
|
function _escapeRegExp(string) {
|
|
return string.replace(ESCAPE_REGEXP, "\\$1");
|
|
}
|
|
|
|
|
|
function _getCurrCssProp(elem, name, computed) {
|
|
var ret;
|
|
|
|
// try computed style
|
|
ret = computed.getPropertyValue(name);
|
|
|
|
// try style attribute (if element is not attached to document)
|
|
if (ret === '' && !elem.ownerDocument) ret = elem.style[_camelCase(name)];
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* Module API
|
|
*/
|
|
module.exports = {
|
|
/** Add classes */
|
|
addClass: jqLiteAddClass,
|
|
|
|
/** Get or set CSS properties */
|
|
css: jqLiteCss,
|
|
|
|
/** Check for class */
|
|
hasClass: jqLiteHasClass,
|
|
|
|
/** Remove event handlers */
|
|
off: jqLiteOff,
|
|
|
|
/** Return offset values */
|
|
offset: jqLiteOffset,
|
|
|
|
/** Add event handlers */
|
|
on: jqLiteOn,
|
|
|
|
/** Add an execute-once event handler */
|
|
one: jqLiteOne,
|
|
|
|
/** DOM ready event handler */
|
|
ready: jqLiteReady,
|
|
|
|
/** Remove classes */
|
|
removeClass: jqLiteRemoveClass,
|
|
|
|
/** Check JavaScript variable instance type */
|
|
type: jqLiteType,
|
|
|
|
/** Get or set horizontal scroll position */
|
|
scrollLeft: jqLiteScrollLeft,
|
|
|
|
/** Get or set vertical scroll position */
|
|
scrollTop: jqLiteScrollTop
|
|
};
|
|
|
|
},{}],5:[function(require,module,exports){
|
|
/**
|
|
* MUI CSS/JS utilities module
|
|
* @module lib/util
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
|
|
var config = require('../config'),
|
|
jqLite = require('./jqLite'),
|
|
nodeInsertedCallbacks = [],
|
|
scrollLock = 0,
|
|
scrollLockCls = 'mui-body--scroll-lock',
|
|
scrollLockPos,
|
|
_supportsPointerEvents;
|
|
|
|
|
|
/**
|
|
* Logging function
|
|
*/
|
|
function logFn() {
|
|
var win = window;
|
|
|
|
if (config.debug && typeof win.console !== "undefined") {
|
|
try {
|
|
win.console.log.apply(win.console, arguments);
|
|
} catch (a) {
|
|
var e = Array.prototype.slice.call(arguments);
|
|
win.console.log(e.join("\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Load CSS text in new stylesheet
|
|
* @param {string} cssText - The css text.
|
|
*/
|
|
function loadStyleFn(cssText) {
|
|
var doc = document,
|
|
head;
|
|
|
|
// copied from jQuery
|
|
head = doc.head ||
|
|
doc.getElementsByTagName('head')[0] ||
|
|
doc.documentElement;
|
|
|
|
var e = doc.createElement('style');
|
|
e.type = 'text/css';
|
|
|
|
if (e.styleSheet) e.styleSheet.cssText = cssText;
|
|
else e.appendChild(doc.createTextNode(cssText));
|
|
|
|
// add to document
|
|
head.insertBefore(e, head.firstChild);
|
|
|
|
return e;
|
|
}
|
|
|
|
|
|
/**
|
|
* Raise an error
|
|
* @param {string} msg - The error message.
|
|
*/
|
|
function raiseErrorFn(msg, useConsole) {
|
|
if (useConsole) {
|
|
if (typeof console !== 'undefined') console.error('MUI Warning: ' + msg);
|
|
} else {
|
|
throw new Error('MUI: ' + msg);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Register callbacks on muiNodeInserted event
|
|
* @param {function} callbackFn - The callback function.
|
|
*/
|
|
function onNodeInsertedFn(callbackFn) {
|
|
nodeInsertedCallbacks.push(callbackFn);
|
|
|
|
// initalize listeners
|
|
if (nodeInsertedCallbacks._initialized === undefined) {
|
|
var doc = document;
|
|
|
|
jqLite.on(doc, 'animationstart', animationHandlerFn);
|
|
jqLite.on(doc, 'mozAnimationStart', animationHandlerFn);
|
|
jqLite.on(doc, 'webkitAnimationStart', animationHandlerFn);
|
|
|
|
nodeInsertedCallbacks._initialized = true;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Execute muiNodeInserted callbacks
|
|
* @param {Event} ev - The DOM event.
|
|
*/
|
|
function animationHandlerFn(ev) {
|
|
// check animation name
|
|
if (ev.animationName !== 'mui-node-inserted') return;
|
|
|
|
var el = ev.target;
|
|
|
|
// iterate through callbacks
|
|
for (var i=nodeInsertedCallbacks.length - 1; i >= 0; i--) {
|
|
nodeInsertedCallbacks[i](el);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Convert Classname object, with class as key and true/false as value, to an
|
|
* class string.
|
|
* @param {Object} classes The classes
|
|
* @return {String} class string
|
|
*/
|
|
function classNamesFn(classes) {
|
|
var cs = '';
|
|
for (var i in classes) {
|
|
cs += (classes[i]) ? i + ' ' : '';
|
|
}
|
|
return cs.trim();
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if client supports pointer events.
|
|
*/
|
|
function supportsPointerEventsFn() {
|
|
// check cache
|
|
if (_supportsPointerEvents !== undefined) return _supportsPointerEvents;
|
|
|
|
var element = document.createElement('x');
|
|
element.style.cssText = 'pointer-events:auto';
|
|
_supportsPointerEvents = (element.style.pointerEvents === 'auto');
|
|
return _supportsPointerEvents;
|
|
}
|
|
|
|
|
|
/**
|
|
* Create callback closure.
|
|
* @param {Object} instance - The object instance.
|
|
* @param {String} funcName - The name of the callback function.
|
|
*/
|
|
function callbackFn(instance, funcName) {
|
|
return function() {instance[funcName].apply(instance, arguments);};
|
|
}
|
|
|
|
|
|
/**
|
|
* Dispatch event.
|
|
* @param {Element} element - The DOM element.
|
|
* @param {String} eventType - The event type.
|
|
* @param {Boolean} bubbles=true - If true, event bubbles.
|
|
* @param {Boolean} cancelable=true = If true, event is cancelable
|
|
* @param {Object} [data] - Data to add to event object
|
|
*/
|
|
function dispatchEventFn(element, eventType, bubbles, cancelable, data) {
|
|
var ev = document.createEvent('HTMLEvents'),
|
|
bubbles = (bubbles !== undefined) ? bubbles : true,
|
|
cancelable = (cancelable !== undefined) ? cancelable : true,
|
|
k;
|
|
|
|
ev.initEvent(eventType, bubbles, cancelable);
|
|
|
|
// add data to event object
|
|
if (data) for (k in data) ev[k] = data[k];
|
|
|
|
// dispatch
|
|
if (element) element.dispatchEvent(ev);
|
|
|
|
return ev;
|
|
}
|
|
|
|
|
|
/**
|
|
* Turn on window scroll lock.
|
|
*/
|
|
function enableScrollLockFn() {
|
|
// increment counter
|
|
scrollLock += 1
|
|
|
|
// add lock
|
|
if (scrollLock === 1) {
|
|
var win = window,
|
|
doc = document;
|
|
|
|
scrollLockPos = {left: jqLite.scrollLeft(win), top: jqLite.scrollTop(win)};
|
|
jqLite.addClass(doc.body, scrollLockCls);
|
|
win.scrollTo(scrollLockPos.left, scrollLockPos.top);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Turn off window scroll lock.
|
|
*/
|
|
function disableScrollLockFn() {
|
|
// ignore
|
|
if (scrollLock === 0) return;
|
|
|
|
// decrement counter
|
|
scrollLock -= 1
|
|
|
|
// remove lock
|
|
if (scrollLock === 0) {
|
|
var win = window,
|
|
doc = document;
|
|
|
|
jqLite.removeClass(doc.body, scrollLockCls);
|
|
win.scrollTo(scrollLockPos.left, scrollLockPos.top);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Define the module API
|
|
*/
|
|
module.exports = {
|
|
/** Create callback closures */
|
|
callback: callbackFn,
|
|
|
|
/** Classnames object to string */
|
|
classNames: classNamesFn,
|
|
|
|
/** Disable scroll lock */
|
|
disableScrollLock: disableScrollLockFn,
|
|
|
|
/** Dispatch event */
|
|
dispatchEvent: dispatchEventFn,
|
|
|
|
/** Enable scroll lock */
|
|
enableScrollLock: enableScrollLockFn,
|
|
|
|
/** Log messages to the console when debug is turned on */
|
|
log: logFn,
|
|
|
|
/** Load CSS text as new stylesheet */
|
|
loadStyle: loadStyleFn,
|
|
|
|
/** Register muiNodeInserted handler */
|
|
onNodeInserted: onNodeInsertedFn,
|
|
|
|
/** Raise MUI error */
|
|
raiseError: raiseErrorFn,
|
|
|
|
/** Support Pointer Events check */
|
|
supportsPointerEvents: supportsPointerEventsFn
|
|
};
|
|
|
|
},{"../config":2,"./jqLite":4}],6:[function(require,module,exports){
|
|
/**
|
|
* MUI CSS/JS dropdown module
|
|
* @module dropdowns
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
|
|
var jqLite = require('./lib/jqLite'),
|
|
util = require('./lib/util'),
|
|
attrKey = 'data-mui-toggle',
|
|
attrSelector = '[data-mui-toggle="dropdown"]',
|
|
openClass = 'mui--is-open',
|
|
menuClass = 'mui-dropdown__menu';
|
|
|
|
|
|
/**
|
|
* Initialize toggle element.
|
|
* @param {Element} toggleEl - The toggle element.
|
|
*/
|
|
function initialize(toggleEl) {
|
|
// check flag
|
|
if (toggleEl._muiDropdown === true) return;
|
|
else toggleEl._muiDropdown = true;
|
|
|
|
// use type "button" to prevent form submission by default
|
|
if (!toggleEl.hasAttribute('type')) toggleEl.type = 'button';
|
|
|
|
// attach click handler
|
|
jqLite.on(toggleEl, 'click', clickHandler);
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle click events on dropdown toggle element.
|
|
* @param {Event} ev - The DOM event
|
|
*/
|
|
function clickHandler(ev) {
|
|
// only left clicks
|
|
if (ev.button !== 0) return;
|
|
|
|
var toggleEl = this;
|
|
|
|
// exit if toggle button is disabled
|
|
if (toggleEl.getAttribute('disabled') !== null) return;
|
|
|
|
// toggle dropdown
|
|
toggleDropdown(toggleEl);
|
|
}
|
|
|
|
|
|
/**
|
|
* Toggle the dropdown.
|
|
* @param {Element} toggleEl - The dropdown toggle element.
|
|
*/
|
|
function toggleDropdown(toggleEl) {
|
|
var wrapperEl = toggleEl.parentNode,
|
|
menuEl = toggleEl.nextElementSibling,
|
|
doc = wrapperEl.ownerDocument;
|
|
|
|
// exit if no menu element
|
|
if (!menuEl || !jqLite.hasClass(menuEl, menuClass)) {
|
|
return util.raiseError('Dropdown menu element not found');
|
|
}
|
|
|
|
// method to close dropdown
|
|
function closeDropdownFn() {
|
|
jqLite.removeClass(menuEl, openClass);
|
|
|
|
// remove event handlers
|
|
jqLite.off(doc, 'click', closeDropdownFn);
|
|
}
|
|
|
|
// method to open dropdown
|
|
function openDropdownFn() {
|
|
// position menu element below toggle button
|
|
var wrapperRect = wrapperEl.getBoundingClientRect(),
|
|
toggleRect = toggleEl.getBoundingClientRect();
|
|
|
|
var top = toggleRect.top - wrapperRect.top + toggleRect.height;
|
|
jqLite.css(menuEl, 'top', top + 'px');
|
|
|
|
// add open class to wrapper
|
|
jqLite.addClass(menuEl, openClass);
|
|
|
|
// close dropdown when user clicks outside of menu
|
|
setTimeout(function() {jqLite.on(doc, 'click', closeDropdownFn);}, 0);
|
|
}
|
|
|
|
// toggle dropdown
|
|
if (jqLite.hasClass(menuEl, openClass)) closeDropdownFn();
|
|
else openDropdownFn();
|
|
}
|
|
|
|
|
|
/** Define module API */
|
|
module.exports = {
|
|
/** Initialize module listeners */
|
|
initListeners: function() {
|
|
var doc = document;
|
|
|
|
// markup elements available when method is called
|
|
var elList = doc.querySelectorAll(attrSelector);
|
|
for (var i=elList.length - 1; i >= 0; i--) initialize(elList[i]);
|
|
|
|
// listen for new elements
|
|
util.onNodeInserted(function(el) {
|
|
if (el.getAttribute(attrKey) === 'dropdown') initialize(el);
|
|
});
|
|
}
|
|
};
|
|
|
|
},{"./lib/jqLite":4,"./lib/util":5}],7:[function(require,module,exports){
|
|
module.exports=require(4)
|
|
},{}],8:[function(require,module,exports){
|
|
/**
|
|
* MUI CSS/JS overlay module
|
|
* @module overlay
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
|
|
var util = require('./lib/util'),
|
|
jqLite = require('./lib/jqLite'),
|
|
overlayId = 'mui-overlay',
|
|
bodyClass = 'mui--overflow-hidden',
|
|
iosRegex = /(iPad|iPhone|iPod)/g;
|
|
|
|
|
|
/**
|
|
* Turn overlay on/off.
|
|
* @param {string} action - Turn overlay "on"/"off".
|
|
* @param {object} [options]
|
|
* @config {boolean} [keyboard] - If true, close when escape key is pressed.
|
|
* @config {boolean} [static] - If false, close when backdrop is clicked.
|
|
* @config {Function} [onclose] - Callback function to execute on close
|
|
* @param {Element} [childElement] - Child element to add to overlay.
|
|
*/
|
|
function overlayFn(action) {
|
|
var overlayEl;
|
|
|
|
if (action === 'on') {
|
|
// extract arguments
|
|
var arg, options, childElement;
|
|
|
|
// pull options and childElement from arguments
|
|
for (var i=arguments.length - 1; i > 0; i--) {
|
|
arg = arguments[i];
|
|
|
|
if (jqLite.type(arg) === 'object') options = arg;
|
|
if (arg instanceof Element && arg.nodeType === 1) childElement = arg;
|
|
}
|
|
|
|
// option defaults
|
|
options = options || {};
|
|
if (options.keyboard === undefined) options.keyboard = true;
|
|
if (options.static === undefined) options.static = false;
|
|
|
|
// execute method
|
|
overlayEl = overlayOn(options, childElement);
|
|
|
|
} else if (action === 'off') {
|
|
overlayEl = overlayOff();
|
|
|
|
} else {
|
|
// raise error
|
|
util.raiseError("Expecting 'on' or 'off'");
|
|
}
|
|
|
|
return overlayEl;
|
|
}
|
|
|
|
|
|
/**
|
|
* Turn on overlay.
|
|
* @param {object} options - Overlay options.
|
|
* @param {Element} childElement - The child element.
|
|
*/
|
|
function overlayOn(options, childElement) {
|
|
var bodyEl = document.body,
|
|
overlayEl = document.getElementById(overlayId);
|
|
|
|
// add overlay
|
|
util.enableScrollLock();
|
|
//jqLite.addClass(bodyEl, bodyClass);
|
|
|
|
if (!overlayEl) {
|
|
// create overlayEl
|
|
overlayEl = document.createElement('div');
|
|
overlayEl.setAttribute('id', overlayId);
|
|
|
|
// add child element
|
|
if (childElement) overlayEl.appendChild(childElement);
|
|
|
|
bodyEl.appendChild(overlayEl);
|
|
|
|
} else {
|
|
// remove existing children
|
|
while (overlayEl.firstChild) overlayEl.removeChild(overlayEl.firstChild);
|
|
|
|
// add child element
|
|
if (childElement) overlayEl.appendChild(childElement);
|
|
}
|
|
|
|
// iOS bugfix
|
|
if (iosRegex.test(navigator.userAgent)) {
|
|
jqLite.css(overlayEl, 'cursor', 'pointer');
|
|
}
|
|
|
|
// handle options
|
|
if (options.keyboard) addKeyupHandler();
|
|
else removeKeyupHandler();
|
|
|
|
if (options.static) removeClickHandler(overlayEl);
|
|
else addClickHandler(overlayEl);
|
|
|
|
// attach options
|
|
overlayEl.muiOptions = options;
|
|
|
|
return overlayEl;
|
|
}
|
|
|
|
|
|
/**
|
|
* Turn off overlay.
|
|
*/
|
|
function overlayOff() {
|
|
var overlayEl = document.getElementById(overlayId),
|
|
callbackFn;
|
|
|
|
if (overlayEl) {
|
|
// remove children
|
|
while (overlayEl.firstChild) overlayEl.removeChild(overlayEl.firstChild);
|
|
|
|
// remove overlay element
|
|
overlayEl.parentNode.removeChild(overlayEl);
|
|
|
|
// callback reference
|
|
callbackFn = overlayEl.muiOptions.onclose;
|
|
|
|
// remove click handler
|
|
removeClickHandler(overlayEl);
|
|
}
|
|
|
|
util.disableScrollLock();
|
|
|
|
// remove keyup handler
|
|
removeKeyupHandler();
|
|
|
|
// execute callback
|
|
if (callbackFn) callbackFn();
|
|
|
|
return overlayEl;
|
|
}
|
|
|
|
|
|
/**
|
|
* Add keyup handler.
|
|
*/
|
|
function addKeyupHandler() {
|
|
jqLite.on(document, 'keyup', onKeyup);
|
|
}
|
|
|
|
|
|
/**
|
|
* Remove keyup handler.
|
|
*/
|
|
function removeKeyupHandler() {
|
|
jqLite.off(document, 'keyup', onKeyup);
|
|
}
|
|
|
|
|
|
/**
|
|
* Teardown overlay when escape key is pressed.
|
|
*/
|
|
function onKeyup(ev) {
|
|
if (ev.keyCode === 27) overlayOff();
|
|
}
|
|
|
|
|
|
/**
|
|
* Add click handler.
|
|
*/
|
|
function addClickHandler(overlayEl) {
|
|
jqLite.on(overlayEl, 'click', onClick);
|
|
}
|
|
|
|
|
|
/**
|
|
* Remove click handler.
|
|
*/
|
|
function removeClickHandler(overlayEl) {
|
|
jqLite.off(overlayEl, 'click', onClick);
|
|
}
|
|
|
|
|
|
/**
|
|
* Teardown overlay when backdrop is clicked.
|
|
*/
|
|
function onClick(ev) {
|
|
if (ev.target.id === overlayId) overlayOff();
|
|
}
|
|
|
|
|
|
/** Define module API */
|
|
module.exports = overlayFn;
|
|
|
|
},{"./lib/jqLite":4,"./lib/util":5}],9:[function(require,module,exports){
|
|
/**
|
|
* MUI CSS/JS ripple module
|
|
* @module ripple
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
|
|
var jqLite = require('./lib/jqLite'),
|
|
util = require('./lib/util'),
|
|
btnClass = 'mui-btn',
|
|
btnFABClass = 'mui-btn--fab',
|
|
rippleClass = 'mui-ripple-effect',
|
|
animationName = 'mui-btn-inserted';
|
|
|
|
|
|
/**
|
|
* Add ripple effects to button element.
|
|
* @param {Element} buttonEl - The button element.
|
|
*/
|
|
function initialize(buttonEl) {
|
|
// check flag
|
|
if (buttonEl._muiRipple === true) return;
|
|
else buttonEl._muiRipple = true;
|
|
|
|
// exit if element is INPUT (doesn't support absolute positioned children)
|
|
if (buttonEl.tagName === 'INPUT') return;
|
|
|
|
// attach event handler
|
|
jqLite.on(buttonEl, 'touchstart', eventHandler);
|
|
jqLite.on(buttonEl, 'mousedown', eventHandler);
|
|
}
|
|
|
|
|
|
/**
|
|
* Event handler
|
|
* @param {Event} ev - The DOM event
|
|
*/
|
|
function eventHandler(ev) {
|
|
// only left clicks
|
|
if (ev.button !== 0) return;
|
|
|
|
var buttonEl = this;
|
|
|
|
// exit if button is disabled
|
|
if (buttonEl.disabled === true) return;
|
|
|
|
// de-dupe touchstart and mousedown with 100msec flag
|
|
if (buttonEl.touchFlag === true) {
|
|
return;
|
|
} else {
|
|
buttonEl.touchFlag = true;
|
|
setTimeout(function() {
|
|
buttonEl.touchFlag = false;
|
|
}, 100);
|
|
}
|
|
|
|
var rippleEl = document.createElement('div');
|
|
rippleEl.className = rippleClass;
|
|
|
|
var offset = jqLite.offset(buttonEl),
|
|
xPos = ev.pageX - offset.left,
|
|
yPos = ev.pageY - offset.top,
|
|
diameter,
|
|
radius;
|
|
|
|
// get height
|
|
if (jqLite.hasClass(buttonEl, btnFABClass)) diameter = offset.height / 2;
|
|
else diameter = offset.height;
|
|
|
|
radius = diameter / 2;
|
|
|
|
jqLite.css(rippleEl, {
|
|
height: diameter + 'px',
|
|
width: diameter + 'px',
|
|
top: yPos - radius + 'px',
|
|
left: xPos - radius + 'px'
|
|
});
|
|
|
|
buttonEl.appendChild(rippleEl);
|
|
|
|
window.setTimeout(function() {
|
|
var parentNode = rippleEl.parentNode;
|
|
if (parentNode) parentNode.removeChild(rippleEl);
|
|
}, 2000);
|
|
}
|
|
|
|
|
|
/** Define module API */
|
|
module.exports = {
|
|
/** Initialize module listeners */
|
|
initListeners: function() {
|
|
var doc = document;
|
|
|
|
// markup elements available when method is called
|
|
var elList = doc.getElementsByClassName(btnClass);
|
|
for (var i=elList.length - 1; i >= 0; i--) initialize(elList[i]);
|
|
|
|
// listen for new elements
|
|
util.onNodeInserted(function(el) {
|
|
if (jqLite.hasClass(el, btnClass)) initialize(el);
|
|
});
|
|
}
|
|
};
|
|
|
|
},{"./lib/jqLite":4,"./lib/util":5}],10:[function(require,module,exports){
|
|
/**
|
|
* MUI CSS/JS select module
|
|
* @module forms/select
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
|
|
var jqLite = require('./lib/jqLite'),
|
|
util = require('./lib/util'),
|
|
formlib = require('./lib/forms'),
|
|
wrapperClass = 'mui-select',
|
|
cssSelector = '.mui-select > select',
|
|
menuClass = 'mui-select__menu',
|
|
selectedClass = 'mui--is-selected',
|
|
doc = document,
|
|
win = window;
|
|
|
|
|
|
/**
|
|
* Initialize select element.
|
|
* @param {Element} selectEl - The select element.
|
|
*/
|
|
function initialize(selectEl) {
|
|
// check flag
|
|
if (selectEl._muiSelect === true) return;
|
|
else selectEl._muiSelect = true;
|
|
|
|
// use default behavior on touch devices
|
|
if ('ontouchstart' in doc.documentElement) return;
|
|
|
|
// initialize element
|
|
new Select(selectEl);
|
|
}
|
|
|
|
|
|
/**
|
|
* Creates a new Select object
|
|
* @class
|
|
*/
|
|
function Select(selectEl) {
|
|
// instance variables
|
|
this.selectEl = selectEl;
|
|
this.wrapperEl = selectEl.parentNode;
|
|
this.useDefault = false; // currently unused but let's keep just in case
|
|
|
|
// attach event handlers
|
|
jqLite.on(selectEl, 'mousedown', util.callback(this, 'mousedownHandler'));
|
|
jqLite.on(selectEl, 'focus', util.callback(this, 'focusHandler'));
|
|
jqLite.on(selectEl, 'click', util.callback(this, 'clickHandler'));
|
|
|
|
// make wrapper focusable and fix firefox bug
|
|
this.wrapperEl.tabIndex = -1;
|
|
var callbackFn = util.callback(this, 'wrapperFocusHandler');
|
|
jqLite.on(this.wrapperEl, 'focus', callbackFn);
|
|
}
|
|
|
|
|
|
/**
|
|
* Disable default dropdown on mousedown.
|
|
* @param {Event} ev - The DOM event
|
|
*/
|
|
Select.prototype.mousedownHandler = function(ev) {
|
|
if (ev.button !== 0 || this.useDefault === true) return;
|
|
ev.preventDefault();
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle focus event on select element.
|
|
* @param {Event} ev - The DOM event
|
|
*/
|
|
Select.prototype.focusHandler = function(ev) {
|
|
// check flag
|
|
if (this.useDefault === true) return;
|
|
|
|
var selectEl = this.selectEl,
|
|
wrapperEl = this.wrapperEl,
|
|
origIndex = selectEl.tabIndex,
|
|
keydownFn = util.callback(this, 'keydownHandler');
|
|
|
|
// attach keydown handler
|
|
jqLite.on(doc, 'keydown', keydownFn);
|
|
|
|
// disable tabfocus once
|
|
selectEl.tabIndex = -1;
|
|
jqLite.one(wrapperEl, 'blur', function() {
|
|
selectEl.tabIndex = origIndex;
|
|
jqLite.off(doc, 'keydown', keydownFn);
|
|
});
|
|
|
|
// defer focus to parent
|
|
wrapperEl.focus();
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle keydown events on doc
|
|
**/
|
|
Select.prototype.keydownHandler = function(ev) {
|
|
var keyCode = ev.keyCode;
|
|
|
|
// spacebar, down, up
|
|
if (keyCode === 32 || keyCode === 38 || keyCode === 40) {
|
|
// prevent win scroll
|
|
ev.preventDefault();
|
|
|
|
if (this.selectEl.disabled !== true) this.renderMenu();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle focus event on wrapper element.
|
|
*/
|
|
Select.prototype.wrapperFocusHandler = function() {
|
|
// firefox bugfix
|
|
if (this.selectEl.disabled) return this.wrapperEl.blur();
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle click events on select element.
|
|
* @param {Event} ev - The DOM event
|
|
*/
|
|
Select.prototype.clickHandler = function(ev) {
|
|
// only left clicks
|
|
if (ev.button !== 0) return;
|
|
this.renderMenu();
|
|
}
|
|
|
|
|
|
/**
|
|
* Render options dropdown.
|
|
*/
|
|
Select.prototype.renderMenu = function() {
|
|
// check and reset flag
|
|
if (this.useDefault === true) return this.useDefault = false;
|
|
|
|
new Menu(this.wrapperEl, this.selectEl);
|
|
}
|
|
|
|
|
|
/**
|
|
* Creates a new Menu
|
|
* @class
|
|
*/
|
|
function Menu(wrapperEl, selectEl) {
|
|
// add scroll lock
|
|
util.enableScrollLock();
|
|
|
|
// instance variables
|
|
this.origIndex = null;
|
|
this.currentIndex = null;
|
|
this.selectEl = selectEl;
|
|
this.menuEl = this._createMenuEl(wrapperEl, selectEl);
|
|
this.clickCallbackFn = util.callback(this, 'clickHandler');
|
|
this.keydownCallbackFn = util.callback(this, 'keydownHandler');
|
|
this.destroyCallbackFn = util.callback(this, 'destroy');
|
|
|
|
// add to DOM
|
|
wrapperEl.appendChild(this.menuEl);
|
|
jqLite.scrollTop(this.menuEl, this.menuEl._muiScrollTop);
|
|
|
|
// blur active element
|
|
setTimeout(function() {
|
|
// ie10 bugfix
|
|
if (doc.activeElement.nodeName.toLowerCase() !== "body") {
|
|
doc.activeElement.blur();
|
|
}
|
|
}, 0);
|
|
|
|
// attach event handlers
|
|
jqLite.on(this.menuEl, 'click', this.clickCallbackFn);
|
|
jqLite.on(doc, 'keydown', this.keydownCallbackFn);
|
|
jqLite.on(win, 'resize', this.destroyCallbackFn);
|
|
|
|
// attach event handler after current event loop exits
|
|
var fn = this.destroyCallbackFn;
|
|
setTimeout(function() {jqLite.on(doc, 'click', fn);}, 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Create menu element
|
|
* @param {Element} selectEl - The select element
|
|
*/
|
|
Menu.prototype._createMenuEl = function(wrapperEl, selectEl) {
|
|
var menuEl = doc.createElement('div'),
|
|
optionEls = selectEl.children,
|
|
numOptions = optionEls.length,
|
|
selectedPos = 0,
|
|
optionEl,
|
|
itemEl,
|
|
i;
|
|
|
|
menuEl.className = menuClass;
|
|
|
|
// add options
|
|
for (i=0; i < numOptions; i++) {
|
|
optionEl = optionEls[i];
|
|
|
|
itemEl = doc.createElement('div');
|
|
itemEl.textContent = optionEl.textContent;
|
|
itemEl._muiPos = i;
|
|
|
|
if (optionEl.selected) {
|
|
itemEl.setAttribute('class', selectedClass);
|
|
selectedPos = i;
|
|
}
|
|
|
|
menuEl.appendChild(itemEl);
|
|
}
|
|
|
|
// save indices
|
|
this.origIndex = selectedPos;
|
|
this.currentIndex = selectedPos;
|
|
|
|
// set position
|
|
var props = formlib.getMenuPositionalCSS(
|
|
wrapperEl,
|
|
numOptions,
|
|
selectedPos
|
|
);
|
|
|
|
jqLite.css(menuEl, props);
|
|
menuEl._muiScrollTop = props.scrollTop;
|
|
|
|
return menuEl;
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle keydown events on doc element.
|
|
* @param {Event} ev - The DOM event
|
|
*/
|
|
Menu.prototype.keydownHandler = function(ev) {
|
|
var keyCode = ev.keyCode;
|
|
|
|
// tab
|
|
if (keyCode === 9) return this.destroy();
|
|
|
|
// escape | up | down | enter
|
|
if (keyCode === 27 || keyCode === 40 || keyCode === 38 || keyCode === 13) {
|
|
ev.preventDefault();
|
|
}
|
|
|
|
if (keyCode === 27) {
|
|
this.destroy();
|
|
} else if (keyCode === 40) {
|
|
this.increment();
|
|
} else if (keyCode === 38) {
|
|
this.decrement();
|
|
} else if (keyCode === 13) {
|
|
this.selectCurrent();
|
|
this.destroy();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle click events on menu element.
|
|
* @param {Event} ev - The DOM event
|
|
*/
|
|
Menu.prototype.clickHandler = function(ev) {
|
|
// don't allow events to bubble
|
|
ev.stopPropagation();
|
|
|
|
var pos = ev.target._muiPos;
|
|
|
|
// ignore clicks on non-items
|
|
if (pos === undefined) return;
|
|
|
|
// select option
|
|
this.currentIndex = pos;
|
|
this.selectCurrent();
|
|
|
|
// destroy menu
|
|
this.destroy();
|
|
}
|
|
|
|
|
|
/**
|
|
* Increment selected item
|
|
*/
|
|
Menu.prototype.increment = function() {
|
|
if (this.currentIndex === this.menuEl.children.length - 1) return;
|
|
|
|
var optionEls = this.menuEl.children;
|
|
|
|
jqLite.removeClass(optionEls[this.currentIndex], selectedClass);
|
|
this.currentIndex += 1;
|
|
jqLite.addClass(optionEls[this.currentIndex], selectedClass);
|
|
}
|
|
|
|
|
|
/**
|
|
* Decrement selected item
|
|
*/
|
|
Menu.prototype.decrement = function() {
|
|
if (this.currentIndex === 0) return;
|
|
|
|
var optionEls = this.menuEl.children;
|
|
|
|
jqLite.removeClass(optionEls[this.currentIndex], selectedClass);
|
|
this.currentIndex -= 1;
|
|
jqLite.addClass(optionEls[this.currentIndex], selectedClass);
|
|
}
|
|
|
|
|
|
/**
|
|
* Select current item
|
|
*/
|
|
Menu.prototype.selectCurrent = function() {
|
|
if (this.currentIndex !== this.origIndex) {
|
|
var optionEls = this.selectEl.children;
|
|
optionEls[this.origIndex].selected = false;
|
|
optionEls[this.currentIndex].selected = true;
|
|
|
|
// trigger change event
|
|
util.dispatchEvent(this.selectEl, 'change');
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Destroy menu and detach event handlers
|
|
*/
|
|
Menu.prototype.destroy = function() {
|
|
// remove element and focus element
|
|
var parentNode = this.menuEl.parentNode;
|
|
if (parentNode) parentNode.removeChild(this.menuEl);
|
|
|
|
this.selectEl.focus();
|
|
|
|
// remove scroll lock
|
|
util.disableScrollLock();
|
|
|
|
// remove event handlers
|
|
jqLite.off(this.menuEl, 'click', this.clickCallbackFn);
|
|
jqLite.off(doc, 'keydown', this.keydownCallbackFn);
|
|
jqLite.off(doc, 'click', this.destroyCallbackFn);
|
|
jqLite.off(win, 'resize', this.destroyCallbackFn);
|
|
}
|
|
|
|
|
|
/** Define module API */
|
|
module.exports = {
|
|
/** Initialize module listeners */
|
|
initListeners: function() {
|
|
// markup elements available when method is called
|
|
var elList = doc.querySelectorAll(cssSelector);
|
|
for (var i=elList.length - 1; i >= 0; i--) initialize(elList[i]);
|
|
|
|
// listen for new elements
|
|
util.onNodeInserted(function(el) {
|
|
if (el.tagName === 'SELECT' &&
|
|
jqLite.hasClass(el.parentNode, wrapperClass)) {
|
|
initialize(el);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
},{"./lib/forms":3,"./lib/jqLite":4,"./lib/util":5}],11:[function(require,module,exports){
|
|
/**
|
|
* MUI CSS/JS tabs module
|
|
* @module tabs
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
|
|
var jqLite = require('./lib/jqLite'),
|
|
util = require('./lib/util'),
|
|
attrKey = 'data-mui-toggle',
|
|
attrSelector = '[' + attrKey + '="tab"]',
|
|
controlsAttrKey = 'data-mui-controls',
|
|
activeClass = 'mui--is-active',
|
|
showstartKey = 'mui.tabs.showstart',
|
|
showendKey = 'mui.tabs.showend',
|
|
hidestartKey = 'mui.tabs.hidestart',
|
|
hideendKey = 'mui.tabs.hideend';
|
|
|
|
|
|
/**
|
|
* Initialize the toggle element
|
|
* @param {Element} toggleEl - The toggle element.
|
|
*/
|
|
function initialize(toggleEl) {
|
|
// check flag
|
|
if (toggleEl._muiTabs === true) return;
|
|
else toggleEl._muiTabs = true;
|
|
|
|
// attach click handler
|
|
jqLite.on(toggleEl, 'click', clickHandler);
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle clicks on the toggle element.
|
|
* @param {Event} ev - The DOM event.
|
|
*/
|
|
function clickHandler(ev) {
|
|
// only left clicks
|
|
if (ev.button !== 0) return;
|
|
|
|
var toggleEl = this;
|
|
|
|
// exit if toggle element is disabled
|
|
if (toggleEl.getAttribute('disabled') !== null) return;
|
|
|
|
activateTab(toggleEl);
|
|
}
|
|
|
|
|
|
/**
|
|
* Activate the tab controlled by the toggle element.
|
|
* @param {Element} toggleEl - The toggle element.
|
|
*/
|
|
function activateTab(currToggleEl) {
|
|
var currTabEl = currToggleEl.parentNode,
|
|
currPaneId = currToggleEl.getAttribute(controlsAttrKey),
|
|
currPaneEl = document.getElementById(currPaneId),
|
|
prevTabEl,
|
|
prevPaneEl,
|
|
prevPaneId,
|
|
prevToggleEl,
|
|
currData,
|
|
prevData,
|
|
ev1,
|
|
ev2,
|
|
cssSelector;
|
|
|
|
// exit if already active
|
|
if (jqLite.hasClass(currTabEl, activeClass)) return;
|
|
|
|
// raise error if pane doesn't exist
|
|
if (!currPaneEl) util.raiseError('Tab pane "' + currPaneId + '" not found');
|
|
|
|
// get previous pane
|
|
prevPaneEl = getActiveSibling(currPaneEl);
|
|
prevPaneId = prevPaneEl.id;
|
|
|
|
// get previous toggle and tab elements
|
|
cssSelector = '[' + controlsAttrKey + '="' + prevPaneId + '"]';
|
|
prevToggleEl = document.querySelectorAll(cssSelector)[0];
|
|
prevTabEl = prevToggleEl.parentNode;
|
|
|
|
// define event data
|
|
currData = {paneId: currPaneId, relatedPaneId: prevPaneId};
|
|
prevData = {paneId: prevPaneId, relatedPaneId: currPaneId};
|
|
|
|
// dispatch 'hidestart', 'showstart' events
|
|
ev1 = util.dispatchEvent(prevToggleEl, hidestartKey, true, true, prevData);
|
|
ev2 = util.dispatchEvent(currToggleEl, showstartKey, true, true, currData);
|
|
|
|
// let events bubble
|
|
setTimeout(function() {
|
|
// exit if either event was canceled
|
|
if (ev1.defaultPrevented || ev2.defaultPrevented) return;
|
|
|
|
// de-activate previous
|
|
if (prevTabEl) jqLite.removeClass(prevTabEl, activeClass);
|
|
if (prevPaneEl) jqLite.removeClass(prevPaneEl, activeClass);
|
|
|
|
// activate current
|
|
jqLite.addClass(currTabEl, activeClass);
|
|
jqLite.addClass(currPaneEl, activeClass);
|
|
|
|
// dispatch 'hideend', 'showend' events
|
|
util.dispatchEvent(prevToggleEl, hideendKey, true, false, prevData);
|
|
util.dispatchEvent(currToggleEl, showendKey, true, false, currData);
|
|
}, 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get previous active sibling.
|
|
* @param {Element} el - The anchor element.
|
|
*/
|
|
function getActiveSibling(el) {
|
|
var elList = el.parentNode.children,
|
|
q = elList.length,
|
|
activeEl = null,
|
|
tmpEl;
|
|
|
|
while (q-- && !activeEl) {
|
|
tmpEl = elList[q];
|
|
if (tmpEl !== el && jqLite.hasClass(tmpEl, activeClass)) activeEl = tmpEl
|
|
}
|
|
|
|
return activeEl;
|
|
}
|
|
|
|
|
|
/** Define module API */
|
|
module.exports = {
|
|
/** Initialize module listeners */
|
|
initListeners: function() {
|
|
// markup elements available when method is called
|
|
var elList = document.querySelectorAll(attrSelector);
|
|
for (var i=elList.length - 1; i >= 0; i--) initialize(elList[i]);
|
|
|
|
// TODO: listen for new elements
|
|
util.onNodeInserted(function(el) {
|
|
if (el.getAttribute(attrKey) === 'tab') initialize(el);
|
|
});
|
|
},
|
|
|
|
/** External API */
|
|
api: {
|
|
activate: function(paneId) {
|
|
var cssSelector = '[' + controlsAttrKey + '=' + paneId + ']',
|
|
toggleEl = document.querySelectorAll(cssSelector);
|
|
|
|
if (!toggleEl.length) {
|
|
util.raiseError('Tab control for pane "' + paneId + '" not found');
|
|
}
|
|
|
|
activateTab(toggleEl[0]);
|
|
}
|
|
}
|
|
};
|
|
|
|
},{"./lib/jqLite":4,"./lib/util":5}],12:[function(require,module,exports){
|
|
/**
|
|
* MUI CSS/JS form-control module
|
|
* @module forms/form-control
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
|
|
var jqLite = require('./lib/jqLite'),
|
|
util = require('./lib/util'),
|
|
cssSelector = '.mui-textfield > input, .mui-textfield > textarea',
|
|
emptyClass = 'mui--is-empty',
|
|
notEmptyClass = 'mui--is-not-empty',
|
|
dirtyClass = 'mui--is-dirty',
|
|
floatingLabelClass = 'mui-textfield--float-label';
|
|
|
|
|
|
/**
|
|
* Initialize input element.
|
|
* @param {Element} inputEl - The input element.
|
|
*/
|
|
function initialize(inputEl) {
|
|
// check flag
|
|
if (inputEl._muiTextfield === true) return;
|
|
else inputEl._muiTextfield = true;
|
|
|
|
if (inputEl.value.length) jqLite.addClass(inputEl, notEmptyClass);
|
|
else jqLite.addClass(inputEl, emptyClass);
|
|
|
|
jqLite.on(inputEl, 'input', inputHandler);
|
|
jqLite.on(inputEl, 'change', inputHandler);
|
|
|
|
// add dirty class on focus
|
|
jqLite.on(inputEl, 'focus', function(){jqLite.addClass(this, dirtyClass);});
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle input events.
|
|
*/
|
|
function inputHandler() {
|
|
var inputEl = this;
|
|
|
|
if (inputEl.value.length) {
|
|
jqLite.removeClass(inputEl, emptyClass);
|
|
jqLite.addClass(inputEl, notEmptyClass);
|
|
} else {
|
|
jqLite.removeClass(inputEl, notEmptyClass);
|
|
jqLite.addClass(inputEl, emptyClass)
|
|
}
|
|
|
|
jqLite.addClass(inputEl, dirtyClass);
|
|
}
|
|
|
|
|
|
/** Define module API */
|
|
module.exports = {
|
|
/** Initialize input elements */
|
|
initialize: initialize,
|
|
|
|
/** Initialize module listeners */
|
|
initListeners: function() {
|
|
var doc = document;
|
|
|
|
// markup elements available when method is called
|
|
var elList = doc.querySelectorAll(cssSelector);
|
|
for (var i=elList.length - 1; i >= 0; i--) initialize(elList[i]);
|
|
|
|
// listen for new elements
|
|
util.onNodeInserted(function(el) {
|
|
if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') initialize(el);
|
|
});
|
|
|
|
// add transition css for floating labels
|
|
setTimeout(function() {
|
|
var css = '.mui-textfield.mui-textfield--float-label > label {' + [
|
|
'-webkit-transition',
|
|
'-moz-transition',
|
|
'-o-transition',
|
|
'transition',
|
|
''
|
|
].join(':all .15s ease-out;') + '}';
|
|
|
|
util.loadStyle(css);
|
|
}, 150);
|
|
|
|
// pointer-events shim for floating labels
|
|
if (util.supportsPointerEvents() === false) {
|
|
jqLite.on(document, 'click', function(ev) {
|
|
var targetEl = ev.target;
|
|
|
|
if (targetEl.tagName === 'LABEL' &&
|
|
jqLite.hasClass(targetEl.parentNode, floatingLabelClass)) {
|
|
var inputEl = targetEl.previousElementSibling;
|
|
if (inputEl) inputEl.focus();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
},{"./lib/jqLite":4,"./lib/util":5}]},{},[1]) |