flounder
Version:
a native friendly dropdown menu
1,618 lines (1,402 loc) • 167 kB
JavaScript
/*!
* Flounder JavaScript Stylable Selectbox v1.3.13
* https://github.com/sociomantic-tsunami/flounder
*
* Copyright 2015-2018 Sociomantic Labs and other contributors
* Released under the MIT license
* https://github.com/sociomantic-tsunami/flounder/license
*
* Date: Thu Oct 11 2018
*
* "This, so far, is the best Flounder ever"
*/(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";
// rawAsap provides everything we need except exception management.
var rawAsap = require("./raw");
// RawTasks are recycled to reduce GC churn.
var freeTasks = [];
// We queue errors to ensure they are thrown in right order (FIFO).
// Array-as-queue is good enough here, since we are just dealing with exceptions.
var pendingErrors = [];
var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
function throwFirstError() {
if (pendingErrors.length) {
throw pendingErrors.shift();
}
}
/**
* Calls a task as soon as possible after returning, in its own event, with priority
* over other events like animation, reflow, and repaint. An error thrown from an
* event will not interrupt, nor even substantially slow down the processing of
* other events, but will be rather postponed to a lower priority event.
* @param {{call}} task A callable object, typically a function that takes no
* arguments.
*/
module.exports = asap;
function asap(task) {
var rawTask;
if (freeTasks.length) {
rawTask = freeTasks.pop();
} else {
rawTask = new RawTask();
}
rawTask.task = task;
rawAsap(rawTask);
}
// We wrap tasks with recyclable task objects. A task object implements
// `call`, just like a function.
function RawTask() {
this.task = null;
}
// The sole purpose of wrapping the task is to catch the exception and recycle
// the task object after its single use.
RawTask.prototype.call = function () {
try {
this.task.call();
} catch (error) {
if (asap.onerror) {
// This hook exists purely for testing purposes.
// Its name will be periodically randomized to break any code that
// depends on its existence.
asap.onerror(error);
} else {
// In a web browser, exceptions are not fatal. However, to avoid
// slowing down the queue of pending tasks, we rethrow the error in a
// lower priority turn.
pendingErrors.push(error);
requestErrorThrow();
}
} finally {
this.task = null;
freeTasks[freeTasks.length] = this;
}
};
},{"./raw":2}],2:[function(require,module,exports){
(function (global){
"use strict";
// Use the fastest means possible to execute a task in its own turn, with
// priority over other events including IO, animation, reflow, and redraw
// events in browsers.
//
// An exception thrown by a task will permanently interrupt the processing of
// subsequent tasks. The higher level `asap` function ensures that if an
// exception is thrown by a task, that the task queue will continue flushing as
// soon as possible, but if you use `rawAsap` directly, you are responsible to
// either ensure that no exceptions are thrown from your task, or to manually
// call `rawAsap.requestFlush` if an exception is thrown.
module.exports = rawAsap;
function rawAsap(task) {
if (!queue.length) {
requestFlush();
flushing = true;
}
// Equivalent to push, but avoids a function call.
queue[queue.length] = task;
}
var queue = [];
// Once a flush has been requested, no further calls to `requestFlush` are
// necessary until the next `flush` completes.
var flushing = false;
// `requestFlush` is an implementation-specific method that attempts to kick
// off a `flush` event as quickly as possible. `flush` will attempt to exhaust
// the event queue before yielding to the browser's own event loop.
var requestFlush;
// The position of the next task to execute in the task queue. This is
// preserved between calls to `flush` so that it can be resumed if
// a task throws an exception.
var index = 0;
// If a task schedules additional tasks recursively, the task queue can grow
// unbounded. To prevent memory exhaustion, the task queue will periodically
// truncate already-completed tasks.
var capacity = 1024;
// The flush function processes all tasks that have been scheduled with
// `rawAsap` unless and until one of those tasks throws an exception.
// If a task throws an exception, `flush` ensures that its state will remain
// consistent and will resume where it left off when called again.
// However, `flush` does not make any arrangements to be called again if an
// exception is thrown.
function flush() {
while (index < queue.length) {
var currentIndex = index;
// Advance the index before calling the task. This ensures that we will
// begin flushing on the next task the task throws an error.
index = index + 1;
queue[currentIndex].call();
// Prevent leaking memory for long chains of recursive calls to `asap`.
// If we call `asap` within tasks scheduled by `asap`, the queue will
// grow, but to avoid an O(n) walk for every task we execute, we don't
// shift tasks off the queue after they have been executed.
// Instead, we periodically shift 1024 tasks off the queue.
if (index > capacity) {
// Manually shift all values starting at the index back to the
// beginning of the queue.
for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
queue[scan] = queue[scan + index];
}
queue.length -= index;
index = 0;
}
}
queue.length = 0;
index = 0;
flushing = false;
}
// `requestFlush` is implemented using a strategy based on data collected from
// every available SauceLabs Selenium web driver worker at time of writing.
// https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593
// Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that
// have WebKitMutationObserver but not un-prefixed MutationObserver.
// Must use `global` or `self` instead of `window` to work in both frames and web
// workers. `global` is a provision of Browserify, Mr, Mrs, or Mop.
/* globals self */
var scope = typeof global !== "undefined" ? global : self;
var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver;
// MutationObservers are desirable because they have high priority and work
// reliably everywhere they are implemented.
// They are implemented in all modern browsers.
//
// - Android 4-4.3
// - Chrome 26-34
// - Firefox 14-29
// - Internet Explorer 11
// - iPad Safari 6-7.1
// - iPhone Safari 7-7.1
// - Safari 6-7
if (typeof BrowserMutationObserver === "function") {
requestFlush = makeRequestCallFromMutationObserver(flush);
// MessageChannels are desirable because they give direct access to the HTML
// task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera
// 11-12, and in web workers in many engines.
// Although message channels yield to any queued rendering and IO tasks, they
// would be better than imposing the 4ms delay of timers.
// However, they do not work reliably in Internet Explorer or Safari.
// Internet Explorer 10 is the only browser that has setImmediate but does
// not have MutationObservers.
// Although setImmediate yields to the browser's renderer, it would be
// preferrable to falling back to setTimeout since it does not have
// the minimum 4ms penalty.
// Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and
// Desktop to a lesser extent) that renders both setImmediate and
// MessageChannel useless for the purposes of ASAP.
// https://github.com/kriskowal/q/issues/396
// Timers are implemented universally.
// We fall back to timers in workers in most engines, and in foreground
// contexts in the following browsers.
// However, note that even this simple case requires nuances to operate in a
// broad spectrum of browsers.
//
// - Firefox 3-13
// - Internet Explorer 6-9
// - iPad Safari 4.3
// - Lynx 2.8.7
} else {
requestFlush = makeRequestCallFromTimer(flush);
}
// `requestFlush` requests that the high priority event queue be flushed as
// soon as possible.
// This is useful to prevent an error thrown in a task from stalling the event
// queue if the exception handled by Node.js’s
// `process.on("uncaughtException")` or by a domain.
rawAsap.requestFlush = requestFlush;
// To request a high priority event, we induce a mutation observer by toggling
// the text of a text node between "1" and "-1".
function makeRequestCallFromMutationObserver(callback) {
var toggle = 1;
var observer = new BrowserMutationObserver(callback);
var node = document.createTextNode("");
observer.observe(node, {characterData: true});
return function requestCall() {
toggle = -toggle;
node.data = toggle;
};
}
// The message channel technique was discovered by Malte Ubl and was the
// original foundation for this library.
// http://www.nonblocking.io/2011/06/windownexttick.html
// Safari 6.0.5 (at least) intermittently fails to create message ports on a
// page's first load. Thankfully, this version of Safari supports
// MutationObservers, so we don't need to fall back in that case.
// function makeRequestCallFromMessageChannel(callback) {
// var channel = new MessageChannel();
// channel.port1.onmessage = callback;
// return function requestCall() {
// channel.port2.postMessage(0);
// };
// }
// For reasons explained above, we are also unable to use `setImmediate`
// under any circumstances.
// Even if we were, there is another bug in Internet Explorer 10.
// It is not sufficient to assign `setImmediate` to `requestFlush` because
// `setImmediate` must be called *by name* and therefore must be wrapped in a
// closure.
// Never forget.
// function makeRequestCallFromSetImmediate(callback) {
// return function requestCall() {
// setImmediate(callback);
// };
// }
// Safari 6.0 has a problem where timers will get lost while the user is
// scrolling. This problem does not impact ASAP because Safari 6.0 supports
// mutation observers, so that implementation is used instead.
// However, if we ever elect to use timers in Safari, the prevalent work-around
// is to add a scroll event listener that calls for a flush.
// `setTimeout` does not call the passed callback if the delay is less than
// approximately 7 in web workers in Firefox 8 through 18, and sometimes not
// even then.
function makeRequestCallFromTimer(callback) {
return function requestCall() {
// We dispatch a timeout with a specified delay of 0 for engines that
// can reliably accommodate that request. This will usually be snapped
// to a 4 milisecond delay, but once we're flushing, there's no delay
// between events.
var timeoutHandle = setTimeout(handleTimer, 0);
// However, since this timer gets frequently dropped in Firefox
// workers, we enlist an interval handle that will try to fire
// an event 20 times per second until it succeeds.
var intervalHandle = setInterval(handleTimer, 50);
function handleTimer() {
// Whichever timer succeeds will cancel both timers and
// execute the callback.
clearTimeout(timeoutHandle);
clearInterval(intervalHandle);
callback();
}
};
}
// This is for `asap.js` only.
// Its name will be periodically randomized to break any code that depends on
// its existence.
rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer;
// ASAP was originally a nextTick shim included in Q. This was factored out
// into this ASAP package. It was later adapted to RSVP which made further
// amendments. These decisions, particularly to marginalize MessageChannel and
// to capture the MutationObserver implementation in a closure, were integrated
// back into ASAP proper.
// https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],3:[function(require,module,exports){
/**
* http.js
*
* @author Mouse Braun <mouse@knoblau.ch>
* @author Nicolas Brugneaux <nicolas.brugneaux@gmail.com>
*
* @package Microbe
*/
module.exports = function( Microbe )
{
'use strict';
var Promise = require( 'promise' );
/**
* ## http
*
* Method takes as many as necessary parameters, with url being the only required.
* The return then has the methods `.then( _cb )` and `.error( _cb )`
*
* @param {Object} _parameters http parameters. possible properties
* method, url, data, user, password, headers, async
*
* @example µ.http( {url: './test.html', method: 'POST', data: { number: 67867} } ).then( function(){} ).catch( function(){} );
*/
Microbe.http = function( _parameters )
{
var req, method, url, data, user, password, headers, async;
if ( !_parameters )
{
return new Error( 'No parameters given' );
}
else
{
if ( typeof _parameters === 'string' )
{
_parameters = { url: _parameters };
}
req = new XMLHttpRequest();
method = _parameters.method || 'GET';
url = _parameters.url;
data = JSON.stringify( _parameters.data ) || null;
user = _parameters.user || '';
password = _parameters.password || '';
headers = _parameters.headers || null;
async = typeof _parameters.async === "boolean" ?
_parameters.async : true;
req.onreadystatechange = function()
{
if ( req.readyState === 4 )
{
return req;
}
};
}
req.open( method, url, async, user, password );
// weird Safari voodoo fix
if ( method === 'POST' )
{
req.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
}
if ( headers )
{
for ( var header in headers )
{
req.setRequestHeader( header, headers[header] );
}
}
if ( async )
{
return new Promise( function( resolve, reject )
{
req.onerror = function()
{
reject( new Error( 'Network error!' ) );
};
req.send( data );
req.onload = function()
{
if ( req.status === 200 )
{
resolve( req.response );
}
else
{
reject( new Error( req.status ) );
}
};
});
}
else
{
var _response = function( _val )
{
var _responses = {
/**
* ## .then
*
* Called after `http`, `http.get`, or `http.post`, this is
* called passing the result as the first parameter to the callback
*
* @param {Function} _cb function to call after http request
*
* @return _Object_ contains the `.catch` method
*/
then: function( _cb )
{
if ( _val.status === 200 )
{
_cb( _val.responseText );
}
return _responses;
},
/**
* ## .catch
*
* Called after `http`, `http.get`, or `http.post`, this is
* called passing the error as the first parameter to the callback
*
* @param {Function} _cb function to call after http request
*
* @return _Object_ contains the `.then` method
*/
catch: function( _cb )
{
if ( _val.status !== 200 )
{
_cb( {
status : _val.status,
statusText : _val.statusText
} );
}
return _responses;
}
};
return _responses;
};
req.send( data );
req.onloadend = function()
{
req.onreadystatechange();
return _response( req );
};
return req.onloadend();
}
};
/**
* ## http.get
*
* Syntactic shortcut for simple GET requests
*
* @param {String} _url file url
*
* @example µ.http.get( './test.html' ).then( function(){} ).catch( function(){} );
*
* @return _Object_ contains `.then` and `.catch`
*/
Microbe.http.get = function( _url )
{
return this( {
url : _url,
method : 'GET'
} );
};
/**
* ## http.post
*
* Syntactic shortcut for simple POST requests
*
* @param {String} _url file url
* @param {Mixed} _data data to post to location {Object or String}
*
* @example µ.http.post( './test.html', { number: 67867} ).then( function(){} ).catch( function(){} );
*
* @return _Object_ contains `.then` and `.catch`
*/
Microbe.http.post = function( _url, _data )
{
return this( {
url : _url,
data : _data,
method : 'POST'
} );
};
};
},{"promise":4}],4:[function(require,module,exports){
'use strict';
module.exports = require('./lib')
},{"./lib":9}],5:[function(require,module,exports){
'use strict';
var asap = require('asap/raw');
function noop() {}
// States:
//
// 0 - pending
// 1 - fulfilled with _value
// 2 - rejected with _value
// 3 - adopted the state of another promise, _value
//
// once the state is no longer pending (0) it is immutable
// All `_` prefixed properties will be reduced to `_{random number}`
// at build time to obfuscate them and discourage their use.
// We don't use symbols or Object.defineProperty to fully hide them
// because the performance isn't good enough.
// to avoid using try/catch inside critical functions, we
// extract them to here.
var LAST_ERROR = null;
var IS_ERROR = {};
function getThen(obj) {
try {
return obj.then;
} catch (ex) {
LAST_ERROR = ex;
return IS_ERROR;
}
}
function tryCallOne(fn, a) {
try {
return fn(a);
} catch (ex) {
LAST_ERROR = ex;
return IS_ERROR;
}
}
function tryCallTwo(fn, a, b) {
try {
fn(a, b);
} catch (ex) {
LAST_ERROR = ex;
return IS_ERROR;
}
}
module.exports = Promise;
function Promise(fn) {
if (typeof this !== 'object') {
throw new TypeError('Promises must be constructed via new');
}
if (typeof fn !== 'function') {
throw new TypeError('Promise constructor\'s argument is not a function');
}
this._40 = 0;
this._65 = 0;
this._55 = null;
this._72 = null;
if (fn === noop) return;
doResolve(fn, this);
}
Promise._37 = null;
Promise._87 = null;
Promise._61 = noop;
Promise.prototype.then = function(onFulfilled, onRejected) {
if (this.constructor !== Promise) {
return safeThen(this, onFulfilled, onRejected);
}
var res = new Promise(noop);
handle(this, new Handler(onFulfilled, onRejected, res));
return res;
};
function safeThen(self, onFulfilled, onRejected) {
return new self.constructor(function (resolve, reject) {
var res = new Promise(noop);
res.then(resolve, reject);
handle(self, new Handler(onFulfilled, onRejected, res));
});
}
function handle(self, deferred) {
while (self._65 === 3) {
self = self._55;
}
if (Promise._37) {
Promise._37(self);
}
if (self._65 === 0) {
if (self._40 === 0) {
self._40 = 1;
self._72 = deferred;
return;
}
if (self._40 === 1) {
self._40 = 2;
self._72 = [self._72, deferred];
return;
}
self._72.push(deferred);
return;
}
handleResolved(self, deferred);
}
function handleResolved(self, deferred) {
asap(function() {
var cb = self._65 === 1 ? deferred.onFulfilled : deferred.onRejected;
if (cb === null) {
if (self._65 === 1) {
resolve(deferred.promise, self._55);
} else {
reject(deferred.promise, self._55);
}
return;
}
var ret = tryCallOne(cb, self._55);
if (ret === IS_ERROR) {
reject(deferred.promise, LAST_ERROR);
} else {
resolve(deferred.promise, ret);
}
});
}
function resolve(self, newValue) {
// Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
if (newValue === self) {
return reject(
self,
new TypeError('A promise cannot be resolved with itself.')
);
}
if (
newValue &&
(typeof newValue === 'object' || typeof newValue === 'function')
) {
var then = getThen(newValue);
if (then === IS_ERROR) {
return reject(self, LAST_ERROR);
}
if (
then === self.then &&
newValue instanceof Promise
) {
self._65 = 3;
self._55 = newValue;
finale(self);
return;
} else if (typeof then === 'function') {
doResolve(then.bind(newValue), self);
return;
}
}
self._65 = 1;
self._55 = newValue;
finale(self);
}
function reject(self, newValue) {
self._65 = 2;
self._55 = newValue;
if (Promise._87) {
Promise._87(self, newValue);
}
finale(self);
}
function finale(self) {
if (self._40 === 1) {
handle(self, self._72);
self._72 = null;
}
if (self._40 === 2) {
for (var i = 0; i < self._72.length; i++) {
handle(self, self._72[i]);
}
self._72 = null;
}
}
function Handler(onFulfilled, onRejected, promise){
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.promise = promise;
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*/
function doResolve(fn, promise) {
var done = false;
var res = tryCallTwo(fn, function (value) {
if (done) return;
done = true;
resolve(promise, value);
}, function (reason) {
if (done) return;
done = true;
reject(promise, reason);
});
if (!done && res === IS_ERROR) {
done = true;
reject(promise, LAST_ERROR);
}
}
},{"asap/raw":2}],6:[function(require,module,exports){
'use strict';
var Promise = require('./core.js');
module.exports = Promise;
Promise.prototype.done = function (onFulfilled, onRejected) {
var self = arguments.length ? this.then.apply(this, arguments) : this;
self.then(null, function (err) {
setTimeout(function () {
throw err;
}, 0);
});
};
},{"./core.js":5}],7:[function(require,module,exports){
'use strict';
//This file contains the ES6 extensions to the core Promises/A+ API
var Promise = require('./core.js');
module.exports = Promise;
/* Static Functions */
var TRUE = valuePromise(true);
var FALSE = valuePromise(false);
var NULL = valuePromise(null);
var UNDEFINED = valuePromise(undefined);
var ZERO = valuePromise(0);
var EMPTYSTRING = valuePromise('');
function valuePromise(value) {
var p = new Promise(Promise._61);
p._65 = 1;
p._55 = value;
return p;
}
Promise.resolve = function (value) {
if (value instanceof Promise) return value;
if (value === null) return NULL;
if (value === undefined) return UNDEFINED;
if (value === true) return TRUE;
if (value === false) return FALSE;
if (value === 0) return ZERO;
if (value === '') return EMPTYSTRING;
if (typeof value === 'object' || typeof value === 'function') {
try {
var then = value.then;
if (typeof then === 'function') {
return new Promise(then.bind(value));
}
} catch (ex) {
return new Promise(function (resolve, reject) {
reject(ex);
});
}
}
return valuePromise(value);
};
Promise.all = function (arr) {
var args = Array.prototype.slice.call(arr);
return new Promise(function (resolve, reject) {
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
if (val && (typeof val === 'object' || typeof val === 'function')) {
if (val instanceof Promise && val.then === Promise.prototype.then) {
while (val._65 === 3) {
val = val._55;
}
if (val._65 === 1) return res(i, val._55);
if (val._65 === 2) reject(val._55);
val.then(function (val) {
res(i, val);
}, reject);
return;
} else {
var then = val.then;
if (typeof then === 'function') {
var p = new Promise(then.bind(val));
p.then(function (val) {
res(i, val);
}, reject);
return;
}
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
};
Promise.reject = function (value) {
return new Promise(function (resolve, reject) {
reject(value);
});
};
Promise.race = function (values) {
return new Promise(function (resolve, reject) {
values.forEach(function(value){
Promise.resolve(value).then(resolve, reject);
});
});
};
/* Prototype Methods */
Promise.prototype['catch'] = function (onRejected) {
return this.then(null, onRejected);
};
},{"./core.js":5}],8:[function(require,module,exports){
'use strict';
var Promise = require('./core.js');
module.exports = Promise;
Promise.prototype['finally'] = function (f) {
return this.then(function (value) {
return Promise.resolve(f()).then(function () {
return value;
});
}, function (err) {
return Promise.resolve(f()).then(function () {
throw err;
});
});
};
},{"./core.js":5}],9:[function(require,module,exports){
'use strict';
module.exports = require('./core.js');
require('./done.js');
require('./finally.js');
require('./es6-extensions.js');
require('./node-extensions.js');
require('./synchronous.js');
},{"./core.js":5,"./done.js":6,"./es6-extensions.js":7,"./finally.js":8,"./node-extensions.js":10,"./synchronous.js":11}],10:[function(require,module,exports){
'use strict';
// This file contains then/promise specific extensions that are only useful
// for node.js interop
var Promise = require('./core.js');
var asap = require('asap');
module.exports = Promise;
/* Static Functions */
Promise.denodeify = function (fn, argumentCount) {
if (
typeof argumentCount === 'number' && argumentCount !== Infinity
) {
return denodeifyWithCount(fn, argumentCount);
} else {
return denodeifyWithoutCount(fn);
}
};
var callbackFn = (
'function (err, res) {' +
'if (err) { rj(err); } else { rs(res); }' +
'}'
);
function denodeifyWithCount(fn, argumentCount) {
var args = [];
for (var i = 0; i < argumentCount; i++) {
args.push('a' + i);
}
var body = [
'return function (' + args.join(',') + ') {',
'var self = this;',
'return new Promise(function (rs, rj) {',
'var res = fn.call(',
['self'].concat(args).concat([callbackFn]).join(','),
');',
'if (res &&',
'(typeof res === "object" || typeof res === "function") &&',
'typeof res.then === "function"',
') {rs(res);}',
'});',
'};'
].join('');
return Function(['Promise', 'fn'], body)(Promise, fn);
}
function denodeifyWithoutCount(fn) {
var fnLength = Math.max(fn.length - 1, 3);
var args = [];
for (var i = 0; i < fnLength; i++) {
args.push('a' + i);
}
var body = [
'return function (' + args.join(',') + ') {',
'var self = this;',
'var args;',
'var argLength = arguments.length;',
'if (arguments.length > ' + fnLength + ') {',
'args = new Array(arguments.length + 1);',
'for (var i = 0; i < arguments.length; i++) {',
'args[i] = arguments[i];',
'}',
'}',
'return new Promise(function (rs, rj) {',
'var cb = ' + callbackFn + ';',
'var res;',
'switch (argLength) {',
args.concat(['extra']).map(function (_, index) {
return (
'case ' + (index) + ':' +
'res = fn.call(' + ['self'].concat(args.slice(0, index)).concat('cb').join(',') + ');' +
'break;'
);
}).join(''),
'default:',
'args[argLength] = cb;',
'res = fn.apply(self, args);',
'}',
'if (res &&',
'(typeof res === "object" || typeof res === "function") &&',
'typeof res.then === "function"',
') {rs(res);}',
'});',
'};'
].join('');
return Function(
['Promise', 'fn'],
body
)(Promise, fn);
}
Promise.nodeify = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
var callback =
typeof args[args.length - 1] === 'function' ? args.pop() : null;
var ctx = this;
try {
return fn.apply(this, arguments).nodeify(callback, ctx);
} catch (ex) {
if (callback === null || typeof callback == 'undefined') {
return new Promise(function (resolve, reject) {
reject(ex);
});
} else {
asap(function () {
callback.call(ctx, ex);
})
}
}
}
};
Promise.prototype.nodeify = function (callback, ctx) {
if (typeof callback != 'function') return this;
this.then(function (value) {
asap(function () {
callback.call(ctx, null, value);
});
}, function (err) {
asap(function () {
callback.call(ctx, err);
});
});
};
},{"./core.js":5,"asap":1}],11:[function(require,module,exports){
'use strict';
var Promise = require('./core.js');
module.exports = Promise;
Promise.enableSynchronous = function () {
Promise.prototype.isPending = function() {
return this.getState() == 0;
};
Promise.prototype.isFulfilled = function() {
return this.getState() == 1;
};
Promise.prototype.isRejected = function() {
return this.getState() == 2;
};
Promise.prototype.getValue = function () {
if (this._65 === 3) {
return this._55.getValue();
}
if (!this.isFulfilled()) {
throw new Error('Cannot get a value of an unfulfilled promise.');
}
return this._55;
};
Promise.prototype.getReason = function () {
if (this._65 === 3) {
return this._55.getReason();
}
if (!this.isRejected()) {
throw new Error('Cannot get a rejection reason of a non-rejected promise.');
}
return this._55;
};
Promise.prototype.getState = function () {
if (this._65 === 3) {
return this._55.getState();
}
if (this._65 === -1 || this._65 === -2) {
return 0;
}
return this._65;
};
};
Promise.disableSynchronous = function() {
Promise.prototype.isPending = undefined;
Promise.prototype.isFulfilled = undefined;
Promise.prototype.isRejected = undefined;
Promise.prototype.getValue = undefined;
Promise.prototype.getReason = undefined;
Promise.prototype.getState = undefined;
};
},{"./core.js":5}],12:[function(require,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /*
* Copyright (c) 2015-2018 dunnhumby Germany GmbH.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the LICENSE file
* in the root directory of this source tree.
*
*/
/* globals console */
var _utils = require('./utils');
var _utils2 = _interopRequireDefault(_utils);
var _defaults = require('./defaults');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var api = {
/**
* ## buildFromUrl
*
* uses loadDataFromUrl and completes the entire build with the new data
*
* @param {String} url address to get the data from
* @param {Function} callback function to run after getting the data
*
* @return {Void} void
*/
buildFromUrl: function buildFromUrl(url, callback) {
var _this = this;
this.loadDataFromUrl(url, function (data) {
_this.data = data;
if (callback) {
callback(_this.data);
}
_this.rebuild(_this.data);
});
return [];
},
/**
* ## clickByIndex
*
* programatically sets selected by index. If there are not enough elements
* to match the index, then nothing is selected. Fires the onClick event
*
* @param {Mixed} index index to set flounder to.
* _Number, or Array of numbers_
* @param {Boolean} multiple multiSelect or not
*
* @return {Void} void
*/
clickByIndex: function clickByIndex(index, multiple) {
return this.setByIndex(index, multiple, false);
},
/**
* ## clickByText
*
* programatically sets selected by text string. If the text string
* is not matched to an element, nothing will be selected. Fires the
* onClick event
*
* @param {Mixed} text text to set flounder to.
* _String, or Array of strings_
* @param {Boolean} multiple multiSelect or not
*
* @return {Void} void
*/
clickByText: function clickByText(text, multiple) {
return this.setByText(text, multiple, false);
},
/**
* ## clickByValue
*
* programatically sets selected by value string. If the value string
* is not matched to an element, nothing will be selected. Fires the
* onClick event
*
* @param {Mixed} value value to set flounder to.
* _String, or Array of strings_
* @param {Boolean} multiple multiSelect or not
*
* @return {Void} void
*/
clickByValue: function clickByValue(value, multiple) {
return this.setByValue(value, multiple, false);
},
/**
* ## destroy
*
* removes flounder and all it`s events from the dom
*
* @return {Void} void
*/
destroy: function destroy() {
this.componentWillUnmount();
var refs = this.refs;
var classes = this.classes;
var originalTarget = this.originalTarget;
var tagName = originalTarget.tagName;
if (tagName === 'INPUT' || tagName === 'SELECT') {
var target = originalTarget.nextElementSibling;
if (tagName === 'SELECT') {
var firstOption = originalTarget[0];
if (firstOption && _utils2.default.hasClass(firstOption, classes.PLACEHOLDER)) {
originalTarget.removeChild(firstOption);
}
} else {
target = refs.flounder.parentNode;
}
try {
var _classes = this.classes;
target.parentNode.removeChild(target);
originalTarget.tabIndex = 0;
_utils2.default.removeClass(originalTarget, _classes.HIDDEN);
} catch (e) {
throw ' : this flounder may have already been removed';
}
} else {
try {
var wrapper = refs.wrapper;
var parent = wrapper.parentNode;
parent.removeChild(wrapper);
} catch (e) {
throw ' : this flounder may have already been removed';
}
}
refs.flounder.flounder = originalTarget.flounder = this.target.flounder = null;
},
/**
* ## deselectAll
*
* deslects all data
*
* @param {Boolean} silent stifle the onChange event
*
* @return {Void} void
*/
deselectAll: function deselectAll(silent) {
this.removeSelectedClass();
this.removeSelectedValue();
if (this.multiple) {
var multiTagWrapper = this.refs.multiTagWrapper;
if (multiTagWrapper) {
var children = multiTagWrapper.children;
for (var i = 0; i < children.length - 1; i++) {
var el = children[i];
var lastEl = i === children.length - 1;
if (!silent && lastEl) {
el = el.children;
el = el[0];
el.click();
} else {
el.removeEventListener('click', this.removeMultiTag);
el.remove();
}
}
this.addPlaceholder();
}
}
},
/**
* ## disable
*
* disables flounder by adjusting listeners and classes
*
* @param {Boolean} bool disable or enable
*
* @return {Void} void
*/
disable: function disable(bool) {
var refs = this.refs;
var classes = this.classes;
var flounder = refs.flounder;
var selected = refs.selected;
if (bool) {
flounder.removeEventListener('keydown', this.checkFlounderKeypress);
selected.removeEventListener('click', this.toggleList);
_utils2.default.addClass(flounder, classes.DISABLED);
} else {
flounder.addEventListener('keydown', this.checkFlounderKeypress);
selected.addEventListener('click', this.toggleList);
_utils2.default.removeClass(flounder, classes.DISABLED);
}
},
/**
* ## disableByIndex
*
* disables the options with the given index
*
* @param {Mixed} index index of the option
* @param {Boolean} reenable enables the option instead
*
* @return {Void} void
*/
disableByIndex: function disableByIndex(index, reenable) {
var refs = this.refs;
if (typeof index !== 'string' && index.length) {
var disableByIndex = this.disableByIndex.bind(this);
return index.map(function (_i) {
return disableByIndex(_i, reenable);
});
}
var data = refs.data;
var length = data.length;
if (index < 0) {
length = data.length;
index = length + index;
}
var el = data[index];
if (el) {
var opt = refs.selectOptions[index];
var classes = this.classes;
if (reenable) {
opt.disabled = false;
_utils2.default.removeClass(el, classes.DISABLED);
} else {
opt.disabled = true;
_utils2.default.addClass(el, classes.DISABLED);
}
return [el, opt];
}
console.warn('Flounder - No element to disable.');
},
/**
* ## disableByText
*
* disables THE FIRST option that has the given value
*
* @param {Mixed} text value of the option
* @param {Boolean} reenable enables the option instead
*
* @return {Void} void
*/
disableByText: function disableByText(text, reenable) {
if (typeof text !== 'string' && text.length) {
var disableByText = this.disableByText.bind(this);
var _res = text.map(function (_v) {
return disableByText(_v, reenable);
});
return _res.length === 1 ? _res[0] : _res;
}
var res = [];
this.refs.data.forEach(function (el, i) {
var elText = el.innerHTML;
if (elText === text) {
res.push(i);
}
});
res = res.length === 1 ? res[0] : res;
return this.disableByIndex(res, reenable);
},
/**
* ## disableByValue
*
* disables THE FIRST option that has the given value
*
* @param {Mixed} value value of the option
* @param {Boolean} reenable enables the option instead
*
* @return {Void} void
*/
disableByValue: function disableByValue(value, reenable) {
if (typeof value !== 'string' && value.length) {
var disableByValue = this.disableByValue.bind(this);
var _res2 = value.map(function (_v) {
return disableByValue(_v, reenable);
});
return _res2.length === 1 ? _res2[0] : _res2;
}
var res = this.refs.selectOptions.map(function (el, i) {
return '' + el.value === '' + value ? i : null;
}).filter(function (a) {
return !!a || a === 0;
});
res = res.length === 1 ? res[0] : res;
return this.disableByIndex(res, reenable);
},
/**
* ## enableByIndex
*
* shortcut syntax to enable an index
*
* @param {Mixed} index index of the option to enable
*
* @return {Object} flounder(s)
*/
enableByIndex: function enableByIndex(index) {
return this.disableByIndex(index, true);
},
/**
* ## enableByText
*
* shortcut syntax to enable by text
*
* @param {Mixed} text text of the option to enable
*
* @return {Object} flounder(s)
*/
enableByText: function enableByText(text) {
return this.disableByText(text, true);
},
/**
* ## enableByValue
*
* shortcut syntax to enable a value
*
* @param {Mixed} value value of the option to enable
*
* @return {Object} flounder(s)
*/
enableByValue: function enableByValue(value) {
this.disableByValue(value, true);
},
/**
* ## getData
*
* returns the option and div tags related to an option
*
* @param {Number} index index to return
*
* @return {Object} option and div tage
*/
getData: function getData(index) {
var _this2 = this;
var refs = this.refs;
if (typeof index === 'number') {
return {
option: refs.selectOptions[index],
div: refs.data[index]
};
} else if (index && index.length && typeof index !== 'string') {
return index.map(function (i) {
return _this2.getData(i);
});
} else if (!index) {
return refs.selectOptions.map(function (el, i) {
return _this2.getData(i);
});
}
console.warn('Flounder - Illegal parameter type.');
},
/**
* ## getSelected
*
* returns the currently selected data of a SELECT box
*
* @return {Void} void
*/
getSelected: function getSelected() {
var el = this.refs.select;
var opts = [];
var data = el.options;
var classes = this.classes;
for (var i = 0; i < data.length; i++) {
var _el = data[i];
if (_el.selected && !_utils2.default.hasClass(_el, classes.PLACEHOLDER)) {
opts.push(_el);
}
}
return opts;
},
/**
* ## getSelectedValues
*
* returns the values of the currently selected data
*
* @return {Void} void
*/
getSelectedValues: function getSelectedValues() {
return this.getSelected().map(function (_v) {
return _v.value;
});
},
/**
* ## loadDataFromUrl
*
* loads data from a passed url
*
* @param {String} url address to get the data from
* @param {Function} callback function to run after getting the data
*
* @return {Void} void
*/
loadDataFromUrl: function loadDataFromUrl(url, callback) {
var _this3 = this;
var classes = this.classes;
_utils2.default.http.get(url).then(function (data) {
if (data) {
_this3.data = JSON.parse(data);
if (callback) {
callback(_this3.data);
}
} else {
console.warn('no data recieved');
}
}).catch(function (e) {
console.warn('something happened: ', e);
_this3.rebuild([{
text: '',
value: '',
index: 0,
extraClass: classes.LOADING_FAILED
}]);
});
return [{
text: '',
value: '',
index: 0,
extraClass: classes.LOADING
}];
},
/**
* ## rebuild
*
* after editing the data, this can be used to rebuild them
*
* @param {Array} data array with option information
* @param {Object} props options object
*
* @return {Object} rebuilt flounder object
*/
rebuild: function rebuild(data, props) {
if (props || !props && (typeof data === 'string' || data && typeof data.length !== 'number')) {
return this.reconfigure(data, props);
}
data = this.data = data || this.data;
props = this.props;
var refs = this.refs;
var select = refs.select;
this.deselectAll();
this.removeOptionsListeners();
refs.select.innerHTML = '';
refs.select = false;
this.defaultObj = (0, _defaults.setDefaultOption)(this, props, data, true);
refs.optionsList.innerHTML = '';
if (refs.noMoreOptionsEl || _typeof(refs.noMoreOptionsEl) === undefined) {
delete refs.noMoreOptionsEl;
}
if (refs.noResultsEl || _typeof(refs.noResultsEl) === undefine