loleaflet/.eslintignore      |    1 
 loleaflet/Makefile.am        |    9 
 loleaflet/js/vex.combined.js | 1628 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1634 insertions(+), 4 deletions(-)

New commits:
commit 05d433b500e76e2a55c044d4c747fc06d8571d9f
Author:     Henry Castro <hcas...@collabora.com>
AuthorDate: Thu Feb 20 08:25:27 2020 -0400
Commit:     Henry Castro <hcas...@collabora.com>
CommitDate: Thu Feb 20 14:51:54 2020 +0100

    loleaflet: import vex.combined.js library
    
    The file was imported from node_modules/vex-js/dist/js/vex.combined.js
    the main reason is to analyze the source code, debug and patch
    if necessary
    
    To get the source code from npm repository
    
        make libs
    
    Change-Id: I59e466e925d43bf4c599305898c656f69ec195d9
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/89099
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Henry Castro <hcas...@collabora.com>

diff --git a/loleaflet/.eslintignore b/loleaflet/.eslintignore
index 04f898987..40ef65124 100644
--- a/loleaflet/.eslintignore
+++ b/loleaflet/.eslintignore
@@ -1,4 +1,5 @@
 # We only directly edit toolbar.js in dist/
+**/js/vex.combined.js
 **/js/sanitize-url.js
 **/js/l10n.js
 **/js/w2ui-1.5.rc1.js
diff --git a/loleaflet/Makefile.am b/loleaflet/Makefile.am
index 8eee500ab..09e0c1e89 100644
--- a/loleaflet/Makefile.am
+++ b/loleaflet/Makefile.am
@@ -72,8 +72,9 @@ define npm_source
 endef
 
 NODE_MODULES_SRC =\
-       @braintree/sanitize-url@3.0.0 \
-       l10n-for-node@0.0.1
+       vex-js@4.1.0 \
+       l10n-for-node@0.0.1 \
+       @braintree/sanitize-url@3.0.0
 
 LOLEAFLET_CSS =\
        $(builddir)/node_modules/select2/dist/css/select2.css \
@@ -122,10 +123,10 @@ NODE_MODULES_JS =\
        node_modules/smartmenus/dist/jquery.smartmenus.js \
        node_modules/autolinker/dist/Autolinker.js \
        node_modules/json-js/json2.js \
-       node_modules/select2/dist/js/select2.js \
-       node_modules/vex-js/dist/js/vex.combined.js
+       node_modules/select2/dist/js/select2.js
 
 LOLEAFLET_LIBS_JS =\
+       vex.combined.js \
        sanitize-url.js
 
 if !ENABLE_MOBILEAPP
diff --git a/loleaflet/js/vex.combined.js b/loleaflet/js/vex.combined.js
new file mode 100644
index 000000000..2e09a5497
--- /dev/null
+++ b/loleaflet/js/vex.combined.js
@@ -0,0 +1,1628 @@
+(function(f){if(typeof exports==="object"&&typeof 
module!=="undefined"){module.exports=f()}else if(typeof 
define==="function"&&define.amd){define([],f)}else{var g;if(typeof 
window!=="undefined"){g=window}else if(typeof 
global!=="undefined"){g=global}else if(typeof 
self!=="undefined"){g=self}else{g=this}g.vex = f()}})(function(){var 
define,module,exports;return (function(){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);var 
f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var 
l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return 
s(n?n:e)},l,l.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}return 
e})()({1:[function(require,module,exports){
+/*
+ * classList.js: Cross-browser full element.classList implementation.
+ * 1.1.20170427
+ *
+ * By Eli Grey, http://eligrey.com
+ * License: Dedicated to the public domain.
+ *   See https://github.com/eligrey/classList.js/blob/master/LICENSE.md
+ */
+
+/*global self, document, DOMException */
+
+/*! @source 
http://purl.eligrey.com/github/classList.js/blob/master/classList.js */
+
+if ("document" in window.self) {
+
+// Full polyfill for browsers with no classList support
+// Including IE < Edge missing SVGElement.classList
+if (!("classList" in document.createElement("_")) 
+       || document.createElementNS && !("classList" in 
document.createElementNS("http://www.w3.org/2000/svg","g";))) {
+
+(function (view) {
+
+"use strict";
+
+if (!('Element' in view)) return;
+
+var
+         classListProp = "classList"
+       , protoProp = "prototype"
+       , elemCtrProto = view.Element[protoProp]
+       , objCtr = Object
+       , strTrim = String[protoProp].trim || function () {
+               return this.replace(/^\s+|\s+$/g, "");
+       }
+       , arrIndexOf = Array[protoProp].indexOf || function (item) {
+               var
+                         i = 0
+                       , len = this.length
+               ;
+               for (; i < len; i++) {
+                       if (i in this && this[i] === item) {
+                               return i;
+                       }
+               }
+               return -1;
+       }
+       // Vendors: please allow content code to instantiate DOMExceptions
+       , DOMEx = function (type, message) {
+               this.name = type;
+               this.code = DOMException[type];
+               this.message = message;
+       }
+       , checkTokenAndGetIndex = function (classList, token) {
+               if (token === "") {
+                       throw new DOMEx(
+                                 "SYNTAX_ERR"
+                               , "An invalid or illegal string was specified"
+                       );
+               }
+               if (/\s/.test(token)) {
+                       throw new DOMEx(
+                                 "INVALID_CHARACTER_ERR"
+                               , "String contains an invalid character"
+                       );
+               }
+               return arrIndexOf.call(classList, token);
+       }
+       , ClassList = function (elem) {
+               var
+                         trimmedClasses = 
strTrim.call(elem.getAttribute("class") || "")
+                       , classes = trimmedClasses ? 
trimmedClasses.split(/\s+/) : []
+                       , i = 0
+                       , len = classes.length
+               ;
+               for (; i < len; i++) {
+                       this.push(classes[i]);
+               }
+               this._updateClassName = function () {
+                       elem.setAttribute("class", this.toString());
+               };
+       }
+       , classListProto = ClassList[protoProp] = []
+       , classListGetter = function () {
+               return new ClassList(this);
+       }
+;
+// Most DOMException implementations don't allow calling DOMException's 
toString()
+// on non-DOMExceptions. Error's toString() is sufficient here.
+DOMEx[protoProp] = Error[protoProp];
+classListProto.item = function (i) {
+       return this[i] || null;
+};
+classListProto.contains = function (token) {
+       token += "";
+       return checkTokenAndGetIndex(this, token) !== -1;
+};
+classListProto.add = function () {
+       var
+                 tokens = arguments
+               , i = 0
+               , l = tokens.length
+               , token
+               , updated = false
+       ;
+       do {
+               token = tokens[i] + "";
+               if (checkTokenAndGetIndex(this, token) === -1) {
+                       this.push(token);
+                       updated = true;
+               }
+       }
+       while (++i < l);
+
+       if (updated) {
+               this._updateClassName();
+       }
+};
+classListProto.remove = function () {
+       var
+                 tokens = arguments
+               , i = 0
+               , l = tokens.length
+               , token
+               , updated = false
+               , index
+       ;
+       do {
+               token = tokens[i] + "";
+               index = checkTokenAndGetIndex(this, token);
+               while (index !== -1) {
+                       this.splice(index, 1);
+                       updated = true;
+                       index = checkTokenAndGetIndex(this, token);
+               }
+       }
+       while (++i < l);
+
+       if (updated) {
+               this._updateClassName();
+       }
+};
+classListProto.toggle = function (token, force) {
+       token += "";
+
+       var
+                 result = this.contains(token)
+               , method = result ?
+                       force !== true && "remove"
+               :
+                       force !== false && "add"
+       ;
+
+       if (method) {
+               this[method](token);
+       }
+
+       if (force === true || force === false) {
+               return force;
+       } else {
+               return !result;
+       }
+};
+classListProto.toString = function () {
+       return this.join(" ");
+};
+
+if (objCtr.defineProperty) {
+       var classListPropDesc = {
+                 get: classListGetter
+               , enumerable: true
+               , configurable: true
+       };
+       try {
+               objCtr.defineProperty(elemCtrProto, classListProp, 
classListPropDesc);
+       } catch (ex) { // IE 8 doesn't support enumerable:true
+               // adding undefined to fight this issue 
https://github.com/eligrey/classList.js/issues/36
+               // modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is 
affected
+               if (ex.number === undefined || ex.number === -0x7FF5EC54) {
+                       classListPropDesc.enumerable = false;
+                       objCtr.defineProperty(elemCtrProto, classListProp, 
classListPropDesc);
+               }
+       }
+} else if (objCtr[protoProp].__defineGetter__) {
+       elemCtrProto.__defineGetter__(classListProp, classListGetter);
+}
+
+}(window.self));
+
+}
+
+// There is full or partial native classList support, so just check if we need
+// to normalize the add/remove and toggle APIs.
+
+(function () {
+       "use strict";
+
+       var testElement = document.createElement("_");
+
+       testElement.classList.add("c1", "c2");
+
+       // Polyfill for IE 10/11 and Firefox <26, where classList.add and
+       // classList.remove exist but support only one argument at a time.
+       if (!testElement.classList.contains("c2")) {
+               var createMethod = function(method) {
+                       var original = DOMTokenList.prototype[method];
+
+                       DOMTokenList.prototype[method] = function(token) {
+                               var i, len = arguments.length;
+
+                               for (i = 0; i < len; i++) {
+                                       token = arguments[i];
+                                       original.call(this, token);
+                               }
+                       };
+               };
+               createMethod('add');
+               createMethod('remove');
+       }
+
+       testElement.classList.toggle("c3", false);
+
+       // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
+       // support the second argument.
+       if (testElement.classList.contains("c3")) {
+               var _toggle = DOMTokenList.prototype.toggle;
+
+               DOMTokenList.prototype.toggle = function(token, force) {
+                       if (1 in arguments && !this.contains(token) === !force) 
{
+                               return force;
+                       } else {
+                               return _toggle.call(this, token);
+                       }
+               };
+
+       }
+
+       testElement = null;
+}());
+
+}
+
+},{}],2:[function(require,module,exports){
+
+/**
+ * Expose `parse`.
+ */
+
+module.exports = parse;
+
+/**
+ * Tests for browser support.
+ */
+
+var innerHTMLBug = false;
+var bugTestDiv;
+if (typeof document !== 'undefined') {
+  bugTestDiv = document.createElement('div');
+  // Setup
+  bugTestDiv.innerHTML = '  <link/><table></table><a href="/a">a</a><input 
type="checkbox"/>';
+  // Make sure that link elements get serialized correctly by innerHTML
+  // This requires a wrapper element in IE
+  innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
+  bugTestDiv = undefined;
+}
+
+/**
+ * Wrap map from jquery.
+ */
+
+var map = {
+  legend: [1, '<fieldset>', '</fieldset>'],
+  tr: [2, '<table><tbody>', '</tbody></table>'],
+  col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
+  // for script/link/style tags to work in IE6-8, you have to wrap
+  // in a div with a non-whitespace character in front, ha!
+  _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
+};
+
+map.td =
+map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
+
+map.option =
+map.optgroup = [1, '<select multiple="multiple">', '</select>'];
+
+map.thead =
+map.tbody =
+map.colgroup =
+map.caption =
+map.tfoot = [1, '<table>', '</table>'];
+
+map.polyline =
+map.ellipse =
+map.polygon =
+map.circle =
+map.text =
+map.line =
+map.path =
+map.rect =
+map.g = [1, '<svg xmlns="http://www.w3.org/2000/svg"; version="1.1">','</svg>'];
+
+/**
+ * Parse `html` and return a DOM Node instance, which could be a TextNode,
+ * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
+ * instance, depending on the contents of the `html` string.
+ *
+ * @param {String} html - HTML string to "domify"
+ * @param {Document} doc - The `document` instance to create the Node for
+ * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
+ * @api private
+ */
+
+function parse(html, doc) {
+  if ('string' != typeof html) throw new TypeError('String expected');
+
+  // default to the global `document` object
+  if (!doc) doc = document;
+
+  // tag name
+  var m = /<([\w:]+)/.exec(html);
+  if (!m) return doc.createTextNode(html);
+
+  html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
+
+  var tag = m[1];
+
+  // body support
+  if (tag == 'body') {
+    var el = doc.createElement('html');
+    el.innerHTML = html;
+    return el.removeChild(el.lastChild);
+  }
+
+  // wrap map
+  var wrap = map[tag] || map._default;
+  var depth = wrap[0];
+  var prefix = wrap[1];
+  var suffix = wrap[2];
+  var el = doc.createElement('div');
+  el.innerHTML = prefix + html + suffix;
+  while (depth--) el = el.lastChild;
+
+  // one element
+  if (el.firstChild == el.lastChild) {
+    return el.removeChild(el.firstChild);
+  }
+
+  // several elements
+  var fragment = doc.createDocumentFragment();
+  while (el.firstChild) {
+    fragment.appendChild(el.removeChild(el.firstChild));
+  }
+
+  return fragment;
+}
+
+},{}],3:[function(require,module,exports){
+/**
+ * Code refactored from Mozilla Developer Network:
+ * 
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
+ */
+
+'use strict';
+
+function assign(target, firstSource) {
+  if (target === undefined || target === null) {
+    throw new TypeError('Cannot convert first argument to object');
+  }
+
+  var to = Object(target);
+  for (var i = 1; i < arguments.length; i++) {
+    var nextSource = arguments[i];
+    if (nextSource === undefined || nextSource === null) {
+      continue;
+    }
+
+    var keysArray = Object.keys(Object(nextSource));
+    for (var nextIndex = 0, len = keysArray.length; nextIndex < len; 
nextIndex++) {
+      var nextKey = keysArray[nextIndex];
+      var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
+      if (desc !== undefined && desc.enumerable) {
+        to[nextKey] = nextSource[nextKey];
+      }
+    }
+  }
+  return to;
+}
+
+function polyfill() {
+  if (!Object.assign) {
+    Object.defineProperty(Object, 'assign', {
+      enumerable: false,
+      configurable: true,
+      writable: true,
+      value: assign
+    });
+  }
+}
+
+module.exports = {
+  assign: assign,
+  polyfill: polyfill
+};
+
+},{}],4:[function(require,module,exports){
+// get successful control from form and assemble into object
+// http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2
+
+// types which indicate a submit action and are not successful controls
+// these will be ignored
+var k_r_submitter = /^(?:submit|button|image|reset|file)$/i;
+
+// node names which could be successful controls
+var k_r_success_contrls = /^(?:input|select|textarea|keygen)/i;
+
+// Matches bracket notation.
+var brackets = /(\[[^\[\]]*\])/g;
+
+// serializes form fields
+// @param form MUST be an HTMLForm element
+// @param options is an optional argument to configure the serialization. 
Default output
+// with no options specified is a url encoded string
+//    - hash: [true | false] Configure the output type. If true, the output 
will
+//    be a js object.
+//    - serializer: [function] Optional serializer function to override the 
default one.
+//    The function takes 3 arguments (result, key, value) and should return 
new result
+//    hash and url encoded str serializers are provided with this module
+//    - disabled: [true | false]. If true serialize disabled fields.
+//    - empty: [true | false]. If true serialize empty fields
+function serialize(form, options) {
+    if (typeof options != 'object') {
+        options = { hash: !!options };
+    }
+    else if (options.hash === undefined) {
+        options.hash = true;
+    }
+
+    var result = (options.hash) ? {} : '';
+    var serializer = options.serializer || ((options.hash) ? hash_serializer : 
str_serialize);
+
+    var elements = form && form.elements ? form.elements : [];
+
+    //Object store each radio and set if it's empty or not
+    var radio_store = Object.create(null);
+
+    for (var i=0 ; i<elements.length ; ++i) {
+        var element = elements[i];
+
+        // ingore disabled fields
+        if ((!options.disabled && element.disabled) || !element.name) {
+            continue;
+        }
+        // ignore anyhting that is not considered a success field
+        if (!k_r_success_contrls.test(element.nodeName) ||
+            k_r_submitter.test(element.type)) {
+            continue;
+        }
+
+        var key = element.name;
+        var val = element.value;
+
+        // we can't just use element.value for checkboxes cause some browsers 
lie to us
+        // they say "on" for value when the box isn't checked
+        if ((element.type === 'checkbox' || element.type === 'radio') && 
!element.checked) {
+            val = undefined;
+        }
+
+        // If we want empty elements
+        if (options.empty) {
+            // for checkbox
+            if (element.type === 'checkbox' && !element.checked) {
+                val = '';
+            }
+
+            // for radio
+            if (element.type === 'radio') {
+                if (!radio_store[element.name] && !element.checked) {
+                    radio_store[element.name] = false;
+                }
+                else if (element.checked) {
+                    radio_store[element.name] = true;
+                }
+            }
+
+            // if options empty is true, continue only if its radio
+            if (!val && element.type == 'radio') {
+                continue;
+            }
+        }
+        else {
+            // value-less fields are ignored unless options.empty is true
+            if (!val) {
+                continue;
+            }
+        }
+
+        // multi select boxes
+        if (element.type === 'select-multiple') {
+            val = [];
+
+            var selectOptions = element.options;
+            var isSelectedOptions = false;
+            for (var j=0 ; j<selectOptions.length ; ++j) {
+                var option = selectOptions[j];
+                var allowedEmpty = options.empty && !option.value;
+                var hasValue = (option.value || allowedEmpty);
+                if (option.selected && hasValue) {
+                    isSelectedOptions = true;
+
+                    // If using a hash serializer be sure to add the
+                    // correct notation for an array in the multi-select
+                    // context. Here the name attribute on the select element
+                    // might be missing the trailing bracket pair. Both names
+                    // "foo" and "foo[]" should be arrays.
+                    if (options.hash && key.slice(key.length - 2) !== '[]') {
+                        result = serializer(result, key + '[]', option.value);
+                    }
+                    else {
+                        result = serializer(result, key, option.value);
+                    }
+                }
+            }
+
+            // Serialize if no selected options and options.empty is true
+            if (!isSelectedOptions && options.empty) {
+                result = serializer(result, key, '');
+            }
+
+            continue;
+        }
+
+        result = serializer(result, key, val);
+    }
+
+    // Check for all empty radio buttons and serialize them with key=""
+    if (options.empty) {
+        for (var key in radio_store) {
+            if (!radio_store[key]) {
+                result = serializer(result, key, '');
+            }
+        }
+    }
+
+    return result;
+}
+
+function parse_keys(string) {
+    var keys = [];
+    var prefix = /^([^\[\]]*)/;
+    var children = new RegExp(brackets);
+    var match = prefix.exec(string);
+
+    if (match[1]) {
+        keys.push(match[1]);
+    }
+
+    while ((match = children.exec(string)) !== null) {
+        keys.push(match[1]);
+    }
+
+    return keys;
+}
+
+function hash_assign(result, keys, value) {
+    if (keys.length === 0) {
+        result = value;
+        return result;
+    }
+
+    var key = keys.shift();
+    var between = key.match(/^\[(.+?)\]$/);
+
+    if (key === '[]') {
+        result = result || [];
+
+        if (Array.isArray(result)) {
+            result.push(hash_assign(null, keys, value));
+        }
+        else {
+            // This might be the result of bad name attributes like "[][foo]",
+            // in this case the original `result` object will already be
+            // assigned to an object literal. Rather than coerce the object to
+            // an array, or cause an exception the attribute "_values" is
+            // assigned as an array.
+            result._values = result._values || [];
+            result._values.push(hash_assign(null, keys, value));
+        }
+
+        return result;
+    }
+
+    // Key is an attribute name and can be assigned directly.
+    if (!between) {
+        result[key] = hash_assign(result[key], keys, value);
+    }
+    else {
+        var string = between[1];
+        // +var converts the variable into a number
+        // better than parseInt because it doesn't truncate away trailing
+        // letters and actually fails if whole thing is not a number
+        var index = +string;
+
+        // If the characters between the brackets is not a number it is an
+        // attribute name and can be assigned directly.
+        if (isNaN(index)) {
+            result = result || {};
+            result[string] = hash_assign(result[string], keys, value);
+        }
+        else {
+            result = result || [];
+            result[index] = hash_assign(result[index], keys, value);
+        }
+    }
+
+    return result;
+}
+
+// Object/hash encoding serializer.
+function hash_serializer(result, key, value) {
+    var matches = key.match(brackets);
+
+    // Has brackets? Use the recursive assignment function to walk the keys,
+    // construct any missing objects in the result tree and make the assignment
+    // at the end of the chain.
+    if (matches) {
+        var keys = parse_keys(key);
+        hash_assign(result, keys, value);
+    }
+    else {
+        // Non bracket notation can make assignments directly.
+        var existing = result[key];
+
+        // If the value has been assigned already (for instance when a radio 
and
+        // a checkbox have the same name attribute) convert the previous value
+        // into an array before pushing into it.
+        //
+        // NOTE: If this requirement were removed all hash creation and
+        // assignment could go through `hash_assign`.
+        if (existing) {
+            if (!Array.isArray(existing)) {
+                result[key] = [ existing ];
+            }
+
+            result[key].push(value);
+        }
+        else {
+            result[key] = value;
+        }
+    }
+
+    return result;
+}
+
+// urlform encoding serializer
+function str_serialize(result, key, value) {
+    // encode newlines as \r\n cause the html spec says so
+    value = value.replace(/(\r)?\n/g, '\r\n');
+    value = encodeURIComponent(value);
+
+    // spaces should be '+' rather than '%20'.
+    value = value.replace(/%20/g, '+');
+    return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + 
value;
+}
+
+module.exports = serialize;
+
+},{}],5:[function(require,module,exports){
+(function (global){
+(function(f){if(typeof exports==="object"&&typeof 
module!=="undefined"){module.exports=f()}else if(typeof 
define==="function"&&define.amd){define([],f)}else{var g;if(typeof 
window!=="undefined"){g=window}else if(typeof 
global!=="undefined"){g=global}else if(typeof 
self!=="undefined"){g=self}else{g=this}g.vexDialog = f()}})(function(){var 
define,module,exports;return (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);var 
f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var 
l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return 
s(n?n:e)},l,l.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){
+
+/**
+ * Expose `parse`.
+ */
+
+module.exports = parse;
+
+/**
+ * Tests for browser support.
+ */
+
+var innerHTMLBug = false;
+var bugTestDiv;
+if (typeof document !== 'undefined') {
+  bugTestDiv = document.createElement('div');
+  // Setup
+  bugTestDiv.innerHTML = '  <link/><table></table><a href="/a">a</a><input 
type="checkbox"/>';
+  // Make sure that link elements get serialized correctly by innerHTML
+  // This requires a wrapper element in IE
+  innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
+  bugTestDiv = undefined;
+}
+
+/**
+ * Wrap map from jquery.
+ */
+
+var map = {
+  legend: [1, '<fieldset>', '</fieldset>'],
+  tr: [2, '<table><tbody>', '</tbody></table>'],
+  col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
+  // for script/link/style tags to work in IE6-8, you have to wrap
+  // in a div with a non-whitespace character in front, ha!
+  _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
+};
+
+map.td =
+map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
+
+map.option =
+map.optgroup = [1, '<select multiple="multiple">', '</select>'];
+
+map.thead =
+map.tbody =
+map.colgroup =
+map.caption =
+map.tfoot = [1, '<table>', '</table>'];
+
+map.polyline =
+map.ellipse =
+map.polygon =
+map.circle =
+map.text =
+map.line =
+map.path =
+map.rect =
+map.g = [1, '<svg xmlns="http://www.w3.org/2000/svg"; version="1.1">','</svg>'];
+
+/**
+ * Parse `html` and return a DOM Node instance, which could be a TextNode,
+ * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
+ * instance, depending on the contents of the `html` string.
+ *
+ * @param {String} html - HTML string to "domify"
+ * @param {Document} doc - The `document` instance to create the Node for
+ * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
+ * @api private
+ */
+
+function parse(html, doc) {
+  if ('string' != typeof html) throw new TypeError('String expected');
+
+  // default to the global `document` object
+  if (!doc) doc = document;
+
+  // tag name
+  var m = /<([\w:]+)/.exec(html);
+  if (!m) return doc.createTextNode(html);
+
+  html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
+
+  var tag = m[1];
+
+  // body support
+  if (tag == 'body') {
+    var el = doc.createElement('html');
+    el.innerHTML = html;
+    return el.removeChild(el.lastChild);
+  }
+
+  // wrap map
+  var wrap = map[tag] || map._default;
+  var depth = wrap[0];
+  var prefix = wrap[1];
+  var suffix = wrap[2];
+  var el = doc.createElement('div');
+  el.innerHTML = prefix + html + suffix;
+  while (depth--) el = el.lastChild;
+
+  // one element
+  if (el.firstChild == el.lastChild) {
+    return el.removeChild(el.firstChild);
+  }
+
+  // several elements
+  var fragment = doc.createDocumentFragment();
+  while (el.firstChild) {
+    fragment.appendChild(el.removeChild(el.firstChild));
+  }
+
+  return fragment;
+}
+
+},{}],2:[function(require,module,exports){
+// get successful control from form and assemble into object
+// http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2
+
+// types which indicate a submit action and are not successful controls
+// these will be ignored
+var k_r_submitter = /^(?:submit|button|image|reset|file)$/i;
+
+// node names which could be successful controls
+var k_r_success_contrls = /^(?:input|select|textarea|keygen)/i;
+
+// Matches bracket notation.
+var brackets = /(\[[^\[\]]*\])/g;
+
+// serializes form fields
+// @param form MUST be an HTMLForm element
+// @param options is an optional argument to configure the serialization. 
Default output
+// with no options specified is a url encoded string
+//    - hash: [true | false] Configure the output type. If true, the output 
will
+//    be a js object.
+//    - serializer: [function] Optional serializer function to override the 
default one.
+//    The function takes 3 arguments (result, key, value) and should return 
new result
+//    hash and url encoded str serializers are provided with this module
+//    - disabled: [true | false]. If true serialize disabled fields.
+//    - empty: [true | false]. If true serialize empty fields
+function serialize(form, options) {
+    if (typeof options != 'object') {
+        options = { hash: !!options };
+    }
+    else if (options.hash === undefined) {
+        options.hash = true;
+    }
+
+    var result = (options.hash) ? {} : '';
+    var serializer = options.serializer || ((options.hash) ? hash_serializer : 
str_serialize);
+
+    var elements = form && form.elements ? form.elements : [];
+
+    //Object store each radio and set if it's empty or not
+    var radio_store = Object.create(null);
+
+    for (var i=0 ; i<elements.length ; ++i) {
+        var element = elements[i];
+
+        // ingore disabled fields
+        if ((!options.disabled && element.disabled) || !element.name) {
+            continue;
+        }
+        // ignore anyhting that is not considered a success field
+        if (!k_r_success_contrls.test(element.nodeName) ||
+            k_r_submitter.test(element.type)) {
+            continue;
+        }
+
+        var key = element.name;
+        var val = element.value;
+
+        // we can't just use element.value for checkboxes cause some browsers 
lie to us
+        // they say "on" for value when the box isn't checked
+        if ((element.type === 'checkbox' || element.type === 'radio') && 
!element.checked) {
+            val = undefined;
+        }
+
+        // If we want empty elements
+        if (options.empty) {
+            // for checkbox
+            if (element.type === 'checkbox' && !element.checked) {
+                val = '';
+            }
+
+            // for radio
+            if (element.type === 'radio') {
+                if (!radio_store[element.name] && !element.checked) {
+                    radio_store[element.name] = false;
+                }
+                else if (element.checked) {
+                    radio_store[element.name] = true;
+                }
+            }
+
+            // if options empty is true, continue only if its radio
+            if (!val && element.type == 'radio') {
+                continue;
+            }
+        }
+        else {
+            // value-less fields are ignored unless options.empty is true
+            if (!val) {
+                continue;
+            }
+        }
+
+        // multi select boxes
+        if (element.type === 'select-multiple') {
+            val = [];
+
+            var selectOptions = element.options;
+            var isSelectedOptions = false;
+            for (var j=0 ; j<selectOptions.length ; ++j) {
+                var option = selectOptions[j];
+                var allowedEmpty = options.empty && !option.value;
+                var hasValue = (option.value || allowedEmpty);
+                if (option.selected && hasValue) {
+                    isSelectedOptions = true;
+
+                    // If using a hash serializer be sure to add the
+                    // correct notation for an array in the multi-select
+                    // context. Here the name attribute on the select element
+                    // might be missing the trailing bracket pair. Both names
+                    // "foo" and "foo[]" should be arrays.
+                    if (options.hash && key.slice(key.length - 2) !== '[]') {
+                        result = serializer(result, key + '[]', option.value);
+                    }
+                    else {
+                        result = serializer(result, key, option.value);
+                    }
+                }
+            }
+
+            // Serialize if no selected options and options.empty is true
+            if (!isSelectedOptions && options.empty) {
+                result = serializer(result, key, '');
+            }
+
+            continue;
+        }
+
+        result = serializer(result, key, val);
+    }
+
+    // Check for all empty radio buttons and serialize them with key=""
+    if (options.empty) {
+        for (var key in radio_store) {
+            if (!radio_store[key]) {
+                result = serializer(result, key, '');
+            }
+        }
+    }
+
+    return result;
+}
+
+function parse_keys(string) {
+    var keys = [];
+    var prefix = /^([^\[\]]*)/;
+    var children = new RegExp(brackets);
+    var match = prefix.exec(string);
+
+    if (match[1]) {
+        keys.push(match[1]);
+    }
+
+    while ((match = children.exec(string)) !== null) {
+        keys.push(match[1]);
+    }
+
+    return keys;
+}
+
+function hash_assign(result, keys, value) {
+    if (keys.length === 0) {
+        result = value;
+        return result;
+    }
+
+    var key = keys.shift();
+    var between = key.match(/^\[(.+?)\]$/);
+
+    if (key === '[]') {
+        result = result || [];
+
+        if (Array.isArray(result)) {
+            result.push(hash_assign(null, keys, value));
+        }
+        else {
+            // This might be the result of bad name attributes like "[][foo]",
+            // in this case the original `result` object will already be
+            // assigned to an object literal. Rather than coerce the object to
+            // an array, or cause an exception the attribute "_values" is
+            // assigned as an array.
+            result._values = result._values || [];
+            result._values.push(hash_assign(null, keys, value));
+        }
+
+        return result;
+    }
+
+    // Key is an attribute name and can be assigned directly.
+    if (!between) {
+        result[key] = hash_assign(result[key], keys, value);
+    }
+    else {
+        var string = between[1];
+        // +var converts the variable into a number
+        // better than parseInt because it doesn't truncate away trailing
+        // letters and actually fails if whole thing is not a number
+        var index = +string;
+
+        // If the characters between the brackets is not a number it is an
+        // attribute name and can be assigned directly.
+        if (isNaN(index)) {
+            result = result || {};
+            result[string] = hash_assign(result[string], keys, value);
+        }
+        else {
+            result = result || [];
+            result[index] = hash_assign(result[index], keys, value);
+        }
+    }
+
+    return result;
+}
+
+// Object/hash encoding serializer.
+function hash_serializer(result, key, value) {
+    var matches = key.match(brackets);
+
+    // Has brackets? Use the recursive assignment function to walk the keys,
+    // construct any missing objects in the result tree and make the assignment
+    // at the end of the chain.
+    if (matches) {
+        var keys = parse_keys(key);
+        hash_assign(result, keys, value);
+    }
+    else {
+        // Non bracket notation can make assignments directly.
+        var existing = result[key];
+
+        // If the value has been assigned already (for instance when a radio 
and
+        // a checkbox have the same name attribute) convert the previous value
+        // into an array before pushing into it.
+        //
+        // NOTE: If this requirement were removed all hash creation and
+        // assignment could go through `hash_assign`.
+        if (existing) {
+            if (!Array.isArray(existing)) {
+                result[key] = [ existing ];
+            }
+
+            result[key].push(value);
+        }
+        else {
+            result[key] = value;
+        }
+    }
+
+    return result;
+}
+
+// urlform encoding serializer
+function str_serialize(result, key, value) {
+    // encode newlines as \r\n cause the html spec says so
+    value = value.replace(/(\r)?\n/g, '\r\n');
+    value = encodeURIComponent(value);
+
+    // spaces should be '+' rather than '%20'.
+    value = value.replace(/%20/g, '+');
+    return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + 
value;
+}
+
+module.exports = serialize;
+
+},{}],3:[function(require,module,exports){
+var domify = require('domify')
+var serialize = require('form-serialize')
+
+// Build DOM elements for the structure of the dialog
+var buildDialogForm = function buildDialogForm (options) {
+  var form = document.createElement('form')
+  form.classList.add('vex-dialog-form')
+
+  var message = document.createElement('div')
+  message.classList.add('vex-dialog-message')
+  message.appendChild(options.message instanceof window.Node ? options.message 
: domify(options.message))
+
+  var input = document.createElement('div')
+  input.classList.add('vex-dialog-input')
+  input.appendChild(options.input instanceof window.Node ? options.input : 
domify(options.input))
+
+  form.appendChild(message)
+  form.appendChild(input)
+
+  return form
+}
+
+// Take an array of buttons (see the default buttons below) and turn them into 
DOM elements
+var buttonsToDOM = function buttonsToDOM (buttons) {
+  var domButtons = document.createElement('div')
+  domButtons.classList.add('vex-dialog-buttons')
+
+  for (var i = 0; i < buttons.length; i++) {
+    var button = buttons[i]
+    var domButton = document.createElement('button')
+    domButton.type = button.type
+    domButton.textContent = button.text
+    domButton.className = button.className
+    domButton.classList.add('vex-dialog-button')
+    if (i === 0) {
+      domButton.classList.add('vex-first')
+    } else if (i === buttons.length - 1) {
+      domButton.classList.add('vex-last')
+    }
+    // Attach click listener to button with closure
+    (function (button) {
+      domButton.addEventListener('click', function (e) {
+        if (button.click) {
+          button.click.call(this, e)
+        }
+      }.bind(this))
+    }.bind(this)(button))
+
+    domButtons.appendChild(domButton)
+  }
+
+  return domButtons
+}
+
+var plugin = function plugin (vex) {
+  // Define the API first
+  var dialog = {
+    // Plugin name
+    name: 'dialog',
+
+    // Open
+    open: function open (opts) {
+      var options = Object.assign({}, this.defaultOptions, opts)
+
+      // `message` is unsafe internally, so translate
+      // safe default: HTML-escape the message before passing it through
+      if (options.unsafeMessage && !options.message) {
+        options.message = options.unsafeMessage
+      } else if (options.message) {
+        options.message = vex._escapeHtml(options.message)
+      }
+
+      // Build the form from the options
+      var form = options.unsafeContent = buildDialogForm(options)
+
+      // Open the dialog
+      var dialogInstance = vex.open(options)
+
+      // Quick comment - these options and appending buttons and everything
+      // would preferably be done _before_ opening the dialog. However, since
+      // they rely on the context of the vex instance, we have to do them
+      // after. A potential future fix would be to differentiate between
+      // a "created" vex instance and an "opened" vex instance, so any actions
+      // that rely on the specific context of the instance can do their stuff
+      // before opening the dialog on the page.
+
+      // Override the before close callback to also pass the value of the form
+      var beforeClose = options.beforeClose && 
options.beforeClose.bind(dialogInstance)
+      dialogInstance.options.beforeClose = function dialogBeforeClose () {
+        // Only call the callback once - when the validation in beforeClose, 
if present, is true
+        var shouldClose = beforeClose ? beforeClose() : true
+        if (shouldClose) {
+          options.callback(this.value || false)
+        }
+        // Return the result of beforeClose() to vex
+        return shouldClose
+      }.bind(dialogInstance)
+
+      // Append buttons to form with correct context
+      form.appendChild(buttonsToDOM.call(dialogInstance, options.buttons))
+
+      // Attach form to instance
+      dialogInstance.form = form
+
+      // Add submit listener to form
+      form.addEventListener('submit', options.onSubmit.bind(dialogInstance))
+
+      // Optionally focus the first input in the form
+      if (options.focusFirstInput) {
+        var el = dialogInstance.contentEl.querySelector('button, input, 
select, textarea')
+        if (el) {
+          el.focus()
+        }
+      }
+
+      // For chaining
+      return dialogInstance
+    },
+
+    // Alert
+    alert: function (options) {
+      // Allow string as message
+      if (typeof options === 'string') {
+        options = {
+          message: options
+        }
+      }
+      options = Object.assign({}, this.defaultOptions, 
this.defaultAlertOptions, options)
+      return this.open(options)
+    },
+
+    // Confirm
+    confirm: function (options) {
+      if (typeof options !== 'object' || typeof options.callback !== 
'function') {
+        throw new Error('dialog.confirm(options) requires options.callback.')
+      }
+      options = Object.assign({}, this.defaultOptions, 
this.defaultConfirmOptions, options)
+      return this.open(options)
+    },
+
+    // Prompt
+    prompt: function (options) {
+      if (typeof options !== 'object' || typeof options.callback !== 
'function') {
+        throw new Error('dialog.prompt(options) requires options.callback.')
+      }
+      var defaults = Object.assign({}, this.defaultOptions, 
this.defaultPromptOptions)
+      var dynamicDefaults = {
+        unsafeMessage: '<label for="vex">' + vex._escapeHtml(options.label || 
defaults.label) + '</label>',
+        input: '<input name="vex" type="text" class="vex-dialog-prompt-input" 
placeholder="' + vex._escapeHtml(options.placeholder || defaults.placeholder) + 
'" value="' + vex._escapeHtml(options.value || defaults.value) + '" />'
+      }
+      options = Object.assign(defaults, dynamicDefaults, options)
+      // Pluck the value of the "vex" input field as the return value for 
prompt's callback
+      // More closely mimics "window.prompt" in that a single string is 
returned
+      var callback = options.callback
+      options.callback = function promptCallback (value) {
+        if (typeof value === 'object') {
+          var keys = Object.keys(value)
+          value = keys.length ? value[keys[0]] : ''
+        }
+        callback(value)
+      }
+      return this.open(options)
+    }
+  }
+
+  // Now define any additional data that's not the direct dialog API
+  dialog.buttons = {
+    YES: {
+      text: 'OK',
+      type: 'submit',
+      className: 'vex-dialog-button-primary',
+      click: function yesClick () {
+        this.value = true
+      }
+    },
+
+    NO: {
+      text: 'Cancel',
+      type: 'button',
+      className: 'vex-dialog-button-secondary',
+      click: function noClick () {
+        this.value = false
+        this.close()
+      }
+    }
+  }
+
+  dialog.defaultOptions = {
+    callback: function () {},
+    afterOpen: function () {},
+    message: '',
+    input: '',
+    buttons: [
+      dialog.buttons.YES,
+      dialog.buttons.NO
+    ],
+    showCloseButton: false,
+    onSubmit: function onDialogSubmit (e) {
+      e.preventDefault()
+      if (this.options.input) {
+        this.value = serialize(this.form, { hash: true })
+      }
+      return this.close()
+    },
+    focusFirstInput: true
+  }
+
+  dialog.defaultAlertOptions = {
+    buttons: [
+      dialog.buttons.YES
+    ]
+  }
+
+  dialog.defaultPromptOptions = {
+    label: 'Prompt:',
+    placeholder: '',
+    value: ''
+  }
+
+  dialog.defaultConfirmOptions = {}
+
+  return dialog
+}
+
+module.exports = plugin
+
+},{"domify":1,"form-serialize":2}]},{},[3])(3)
+});
+}).call(this,typeof global !== "undefined" ? global : typeof self !== 
"undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"domify":2,"form-serialize":4}],6:[function(require,module,exports){
+var vex = require('./vex')
+vex.registerPlugin(require('vex-dialog'))
+module.exports = vex
+
+},{"./vex":7,"vex-dialog":5}],7:[function(require,module,exports){
+// classList polyfill for old browsers
+require('classlist-polyfill')
+// Object.assign polyfill
+require('es6-object-assign').polyfill()
+
+// String to DOM function
+var domify = require('domify')
+
+// Use the DOM's HTML parsing to escape any dangerous strings
+var escapeHtml = function escapeHtml (str) {
+  if (typeof str !== 'undefined') {
+    var div = document.createElement('div')
+    div.appendChild(document.createTextNode(str))
+    return div.innerHTML
+  } else {
+    return ''
+  }
+}
+
+// Utility function to add space-delimited class strings to a DOM element's 
classList
+var addClasses = function addClasses (el, classStr) {
+  if (typeof classStr !== 'string' || classStr.length === 0) {
+    return
+  }
+  var classes = classStr.split(' ')
+  for (var i = 0; i < classes.length; i++) {
+    var className = classes[i]
+    if (className.length) {
+      el.classList.add(className)
+    }
+  }
+}
+
+// Detect CSS Animation End Support
+// 
https://github.com/limonte/sweetalert2/blob/99bd539f85e15ac170f69d35001d12e092ef0054/src/utils/dom.js#L194
+var animationEndEvent = (function detectAnimationEndEvent () {
+  var el = document.createElement('div')
+  var eventNames = {
+    'animation': 'animationend',
+    'WebkitAnimation': 'webkitAnimationEnd',
+    'MozAnimation': 'animationend',
+    'OAnimation': 'oanimationend',
+    'msAnimation': 'MSAnimationEnd'
+  }
+  for (var i in eventNames) {
+    if (el.style[i] !== undefined) {
+      return eventNames[i]
+    }
+  }
+  return false
+})()
+
+// vex base CSS classes
+var baseClassNames = {
+  vex: 'vex',
+  content: 'vex-content',
+  overlay: 'vex-overlay',
+  close: 'vex-close',
+  closing: 'vex-closing',
+  open: 'vex-open'
+}
+
+// Private lookup table of all open vex objects, keyed by id
+var vexes = {}
+var globalId = 1
+
+// Private boolean to assist the escapeButtonCloses option
+var isEscapeActive = false
+
+// vex itself is an object that exposes a simple API to open and close vex 
objects in various ways
+var vex = {
+  open: function open (opts) {
+    // Check for usage of deprecated options, and log a warning
+    var warnDeprecated = function warnDeprecated (prop) {
+      console.warn('The "' + prop + '" property is deprecated in vex 3. Use 
CSS classes and the appropriate "ClassName" options, instead.')
+      console.warn('See http://github.hubspot.com/vex/api/advanced/#options')
+    }
+    if (opts.css) {
+      warnDeprecated('css')
+    }
+    if (opts.overlayCSS) {
+      warnDeprecated('overlayCSS')
+    }
+    if (opts.contentCSS) {
+      warnDeprecated('contentCSS')
+    }
+    if (opts.closeCSS) {
+      warnDeprecated('closeCSS')
+    }
+
+    // The dialog instance
+    var vexInstance = {}
+
+    // Set id
+    vexInstance.id = globalId++
+
+    // Store internally
+    vexes[vexInstance.id] = vexInstance
+
+    // Set state
+    vexInstance.isOpen = true
+
+    // Close function on the vex instance
+    // This is how all API functions should close individual vexes
+    vexInstance.close = function instanceClose () {
+      // Check state
+      if (!this.isOpen) {
+        return true
+      }
+
+      var options = this.options
+
+      // escapeButtonCloses is checked first
+      if (isEscapeActive && !options.escapeButtonCloses) {
+        return false
+      }
+
+      // Allow the user to validate any info or abort the close with the 
beforeClose callback
+      var shouldClose = (function shouldClose () {
+        // Call before close callback
+        if (options.beforeClose) {
+          return options.beforeClose.call(this)
+        }
+        // Otherwise indicate that it's ok to continue with close
+        return true
+      }.bind(this)())
+
+      // If beforeClose() fails, abort the close
+      if (shouldClose === false) {
+        return false
+      }
+
+      // Update state
+      this.isOpen = false
+
+      // Detect if the content el has any CSS animations defined
+      var style = window.getComputedStyle(this.contentEl)
+      function hasAnimationPre (prefix) {
+        return style.getPropertyValue(prefix + 'animation-name') !== 'none' && 
style.getPropertyValue(prefix + 'animation-duration') !== '0s'
+      }
+      var hasAnimation = hasAnimationPre('') || hasAnimationPre('-webkit-') || 
hasAnimationPre('-moz-') || hasAnimationPre('-o-')
+
+      // Define the function that will actually close the instance
+      var close = function close () {
+        if (!this.rootEl.parentNode) {
+          return
+        }
+        // Run once
+        this.rootEl.removeEventListener(animationEndEvent, close)
+        this.overlayEl.removeEventListener(animationEndEvent, close)
+        // Remove from lookup table (prevent memory leaks)
+        delete vexes[this.id]
+        // Remove the dialog from the DOM
+        this.rootEl.parentNode.removeChild(this.rootEl)
+        // Remove the overlay from the DOM
+        this.bodyEl.removeChild(this.overlayEl)
+        // Call after close callback
+        if (options.afterClose) {
+          options.afterClose.call(this)
+        }
+        // Remove styling from the body, if no more vexes are open
+        if (Object.keys(vexes).length === 0) {
+          document.body.classList.remove(baseClassNames.open)
+        }
+      }.bind(this)
+
+      // Close the vex
+      if (animationEndEvent && hasAnimation) {
+        // Setup the end event listener, to remove the el from the DOM
+        this.rootEl.addEventListener(animationEndEvent, close)
+        this.overlayEl.addEventListener(animationEndEvent, close)
+        // Add the closing class to the dialog, showing the close animation
+        this.rootEl.classList.add(baseClassNames.closing)
+        this.overlayEl.classList.add(baseClassNames.closing)
+      } else {
+        close()
+      }
+
+      return true
+    }
+
+    // Allow strings as content
+    if (typeof opts === 'string') {
+      opts = {
+        content: opts
+      }
+    }
+
+    // `content` is unsafe internally, so translate
+    // safe default: HTML-escape the content before passing it through
+    if (opts.unsafeContent && !opts.content) {
+      opts.content = opts.unsafeContent
+    } else if (opts.content) {
+      opts.content = escapeHtml(opts.content)
+    }
+
+    // Store options on instance for future reference
+    var options = vexInstance.options = Object.assign({}, vex.defaultOptions, 
opts)
+
+    // Get Body Element
+    var bodyEl = vexInstance.bodyEl = document.getElementsByTagName('body')[0]
+
+    // vex root
+    var rootEl = vexInstance.rootEl = document.createElement('div')
+    rootEl.classList.add(baseClassNames.vex)
+    addClasses(rootEl, options.className)
+
+    // Overlay
+    var overlayEl = vexInstance.overlayEl = document.createElement('div')
+    overlayEl.classList.add(baseClassNames.overlay)
+    addClasses(overlayEl, options.overlayClassName)
+    if (options.overlayClosesOnClick) {
+      rootEl.addEventListener('click', function overlayClickListener (e) {
+        if (e.target === rootEl) {
+          vexInstance.close()
+        }
+      })
+    }
+    bodyEl.appendChild(overlayEl)
+
+    // Content
+    var contentEl = vexInstance.contentEl = document.createElement('div')
+    contentEl.classList.add(baseClassNames.content)
+    addClasses(contentEl, options.contentClassName)
+    contentEl.appendChild(options.content instanceof window.Node ? 
options.content : domify(options.content))
+    rootEl.appendChild(contentEl)
+
+    // Close button
+    if (options.showCloseButton) {
+      var closeEl = vexInstance.closeEl = document.createElement('div')
+      closeEl.classList.add(baseClassNames.close)
+      addClasses(closeEl, options.closeClassName)
+      closeEl.addEventListener('click', vexInstance.close.bind(vexInstance))
+      contentEl.appendChild(closeEl)
+    }
+
+    // Add to DOM
+    document.querySelector(options.appendLocation).appendChild(rootEl)
+
+    // Call after open callback
+    if (options.afterOpen) {
+      options.afterOpen.call(vexInstance)
+    }
+
+    // Apply styling to the body
+    document.body.classList.add(baseClassNames.open)
+
+    // Return the created vex instance
+    return vexInstance
+  },
+
+  // A top-level vex.close function to close dialogs by reference or id
+  close: function close (vexOrId) {
+    var id
+    if (vexOrId.id) {
+      id = vexOrId.id
+    } else if (typeof vexOrId === 'string') {
+      id = vexOrId
+    } else {
+      throw new TypeError('close requires a vex object or id string')
+    }
+    if (!vexes[id]) {
+      return false
+    }
+    return vexes[id].close()
+  },
+
+  // Close the most recently created/opened vex
+  closeTop: function closeTop () {
+    var ids = Object.keys(vexes)
+    if (!ids.length) {
+      return false
+    }
+    return vexes[ids[ids.length - 1]].close()
+  },
+
+  // Close every vex!
+  closeAll: function closeAll () {
+    for (var id in vexes) {
+      this.close(id)
+    }
+    return true
+  },
+
+  // A getter for the internal lookup table
+  getAll: function getAll () {
+    return vexes
+  },
+
+  // A getter for the internal lookup table
+  getById: function getById (id) {
+    return vexes[id]
+  }
+}
+
+// Close top vex on escape
+window.addEventListener('keyup', function vexKeyupListener (e) {
+  if (e.keyCode === 27) {
+    isEscapeActive = true
+    vex.closeTop()
+    isEscapeActive = false
+  }
+})
+
+// Close all vexes on history pop state (useful in single page apps)
+window.addEventListener('popstate', function () {
+  if (vex.defaultOptions.closeAllOnPopState) {
+    vex.closeAll()
+  }
+})
+
+vex.defaultOptions = {
+  content: '',
+  showCloseButton: true,
+  escapeButtonCloses: true,
+  overlayClosesOnClick: true,
+  appendLocation: 'body',
+  className: '',
+  overlayClassName: '',
+  contentClassName: '',
+  closeClassName: '',
+  closeAllOnPopState: true
+}
+
+// TODO Loading symbols?
+
+// Include escapeHtml function on the library object
+Object.defineProperty(vex, '_escapeHtml', {
+  configurable: false,
+  enumerable: false,
+  writable: false,
+  value: escapeHtml
+})
+
+// Plugin system!
+vex.registerPlugin = function registerPlugin (pluginFn, name) {
+  var plugin = pluginFn(vex)
+  var pluginName = name || plugin.name
+  if (vex[pluginName]) {
+    throw new Error('Plugin ' + name + ' is already registered.')
+  }
+  vex[pluginName] = plugin
+}
+
+module.exports = vex
+
+},{"classlist-polyfill":1,"domify":2,"es6-object-assign":3}]},{},[6])(6)
+});
\ No newline at end of file
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to