unforassets 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3 -0
  3. data/LICENSE.md +21 -0
  4. data/README.md +41 -0
  5. data/lib/unforassets.rb +8 -0
  6. data/lib/unforassets/engine.rb +4 -0
  7. data/lib/unforassets/version.rb +3 -0
  8. data/vendor/assets/javascripts/big.js +1 -0
  9. data/vendor/assets/javascripts/fancybox.js +12 -0
  10. data/vendor/assets/javascripts/jquery.blockui.js +620 -0
  11. data/vendor/assets/javascripts/tooltipster-plugin-scrollable-tip.js +187 -0
  12. data/vendor/assets/javascripts/tooltipster-plugin-svg.js +171 -0
  13. data/vendor/assets/javascripts/tooltipster.bundle.js +4260 -0
  14. data/vendor/assets/javascripts/vex.combined.js +1621 -0
  15. data/vendor/assets/stylesheets/fancybox.css +1 -0
  16. data/vendor/assets/stylesheets/tooltipster-sidetip-borderless.min.css +1 -0
  17. data/vendor/assets/stylesheets/tooltipster-sidetip-light.min.css +1 -0
  18. data/vendor/assets/stylesheets/tooltipster-sidetip-noir.min.css +1 -0
  19. data/vendor/assets/stylesheets/tooltipster-sidetip-punk.min.css +1 -0
  20. data/vendor/assets/stylesheets/tooltipster-sidetip-shadow.min.css +1 -0
  21. data/vendor/assets/stylesheets/tooltipster.bundle.css +388 -0
  22. data/vendor/assets/stylesheets/vex-theme-bottom-right-corner.css +437 -0
  23. data/vendor/assets/stylesheets/vex-theme-default.css +368 -0
  24. data/vendor/assets/stylesheets/vex-theme-flat-attack.css +325 -0
  25. data/vendor/assets/stylesheets/vex-theme-os.css +373 -0
  26. data/vendor/assets/stylesheets/vex-theme-plain.css +173 -0
  27. data/vendor/assets/stylesheets/vex-theme-top.css +432 -0
  28. data/vendor/assets/stylesheets/vex-theme-wireframe.css +174 -0
  29. data/vendor/assets/stylesheets/vex.css +231 -0
  30. metadata +100 -0
@@ -0,0 +1,1621 @@
1
+ (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 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){
2
+ /*
3
+ * classList.js: Cross-browser full element.classList implementation.
4
+ * 2014-07-23
5
+ *
6
+ * By Eli Grey, http://eligrey.com
7
+ * Public Domain.
8
+ * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
9
+ */
10
+
11
+ /*global self, document, DOMException */
12
+
13
+ /*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
14
+
15
+ /* Copied from MDN:
16
+ * https://developer.mozilla.org/en-US/docs/Web/API/Element/classList
17
+ */
18
+
19
+ if ("document" in window.self) {
20
+
21
+ // Full polyfill for browsers with no classList support
22
+ // Including IE < Edge missing SVGElement.classList
23
+ if (!("classList" in document.createElement("_"))
24
+ || document.createElementNS && !("classList" in document.createElementNS("http://www.w3.org/2000/svg","g"))) {
25
+
26
+ (function (view) {
27
+
28
+ "use strict";
29
+
30
+ if (!('Element' in view)) return;
31
+
32
+ var
33
+ classListProp = "classList"
34
+ , protoProp = "prototype"
35
+ , elemCtrProto = view.Element[protoProp]
36
+ , objCtr = Object
37
+ , strTrim = String[protoProp].trim || function () {
38
+ return this.replace(/^\s+|\s+$/g, "");
39
+ }
40
+ , arrIndexOf = Array[protoProp].indexOf || function (item) {
41
+ var
42
+ i = 0
43
+ , len = this.length
44
+ ;
45
+ for (; i < len; i++) {
46
+ if (i in this && this[i] === item) {
47
+ return i;
48
+ }
49
+ }
50
+ return -1;
51
+ }
52
+ // Vendors: please allow content code to instantiate DOMExceptions
53
+ , DOMEx = function (type, message) {
54
+ this.name = type;
55
+ this.code = DOMException[type];
56
+ this.message = message;
57
+ }
58
+ , checkTokenAndGetIndex = function (classList, token) {
59
+ if (token === "") {
60
+ throw new DOMEx(
61
+ "SYNTAX_ERR"
62
+ , "An invalid or illegal string was specified"
63
+ );
64
+ }
65
+ if (/\s/.test(token)) {
66
+ throw new DOMEx(
67
+ "INVALID_CHARACTER_ERR"
68
+ , "String contains an invalid character"
69
+ );
70
+ }
71
+ return arrIndexOf.call(classList, token);
72
+ }
73
+ , ClassList = function (elem) {
74
+ var
75
+ trimmedClasses = strTrim.call(elem.getAttribute("class") || "")
76
+ , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
77
+ , i = 0
78
+ , len = classes.length
79
+ ;
80
+ for (; i < len; i++) {
81
+ this.push(classes[i]);
82
+ }
83
+ this._updateClassName = function () {
84
+ elem.setAttribute("class", this.toString());
85
+ };
86
+ }
87
+ , classListProto = ClassList[protoProp] = []
88
+ , classListGetter = function () {
89
+ return new ClassList(this);
90
+ }
91
+ ;
92
+ // Most DOMException implementations don't allow calling DOMException's toString()
93
+ // on non-DOMExceptions. Error's toString() is sufficient here.
94
+ DOMEx[protoProp] = Error[protoProp];
95
+ classListProto.item = function (i) {
96
+ return this[i] || null;
97
+ };
98
+ classListProto.contains = function (token) {
99
+ token += "";
100
+ return checkTokenAndGetIndex(this, token) !== -1;
101
+ };
102
+ classListProto.add = function () {
103
+ var
104
+ tokens = arguments
105
+ , i = 0
106
+ , l = tokens.length
107
+ , token
108
+ , updated = false
109
+ ;
110
+ do {
111
+ token = tokens[i] + "";
112
+ if (checkTokenAndGetIndex(this, token) === -1) {
113
+ this.push(token);
114
+ updated = true;
115
+ }
116
+ }
117
+ while (++i < l);
118
+
119
+ if (updated) {
120
+ this._updateClassName();
121
+ }
122
+ };
123
+ classListProto.remove = function () {
124
+ var
125
+ tokens = arguments
126
+ , i = 0
127
+ , l = tokens.length
128
+ , token
129
+ , updated = false
130
+ , index
131
+ ;
132
+ do {
133
+ token = tokens[i] + "";
134
+ index = checkTokenAndGetIndex(this, token);
135
+ while (index !== -1) {
136
+ this.splice(index, 1);
137
+ updated = true;
138
+ index = checkTokenAndGetIndex(this, token);
139
+ }
140
+ }
141
+ while (++i < l);
142
+
143
+ if (updated) {
144
+ this._updateClassName();
145
+ }
146
+ };
147
+ classListProto.toggle = function (token, force) {
148
+ token += "";
149
+
150
+ var
151
+ result = this.contains(token)
152
+ , method = result ?
153
+ force !== true && "remove"
154
+ :
155
+ force !== false && "add"
156
+ ;
157
+
158
+ if (method) {
159
+ this[method](token);
160
+ }
161
+
162
+ if (force === true || force === false) {
163
+ return force;
164
+ } else {
165
+ return !result;
166
+ }
167
+ };
168
+ classListProto.toString = function () {
169
+ return this.join(" ");
170
+ };
171
+
172
+ if (objCtr.defineProperty) {
173
+ var classListPropDesc = {
174
+ get: classListGetter
175
+ , enumerable: true
176
+ , configurable: true
177
+ };
178
+ try {
179
+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
180
+ } catch (ex) { // IE 8 doesn't support enumerable:true
181
+ if (ex.number === -0x7FF5EC54) {
182
+ classListPropDesc.enumerable = false;
183
+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
184
+ }
185
+ }
186
+ } else if (objCtr[protoProp].__defineGetter__) {
187
+ elemCtrProto.__defineGetter__(classListProp, classListGetter);
188
+ }
189
+
190
+ }(window.self));
191
+
192
+ } else {
193
+ // There is full or partial native classList support, so just check if we need
194
+ // to normalize the add/remove and toggle APIs.
195
+
196
+ (function () {
197
+ "use strict";
198
+
199
+ var testElement = document.createElement("_");
200
+
201
+ testElement.classList.add("c1", "c2");
202
+
203
+ // Polyfill for IE 10/11 and Firefox <26, where classList.add and
204
+ // classList.remove exist but support only one argument at a time.
205
+ if (!testElement.classList.contains("c2")) {
206
+ var createMethod = function(method) {
207
+ var original = DOMTokenList.prototype[method];
208
+
209
+ DOMTokenList.prototype[method] = function(token) {
210
+ var i, len = arguments.length;
211
+
212
+ for (i = 0; i < len; i++) {
213
+ token = arguments[i];
214
+ original.call(this, token);
215
+ }
216
+ };
217
+ };
218
+ createMethod('add');
219
+ createMethod('remove');
220
+ }
221
+
222
+ testElement.classList.toggle("c3", false);
223
+
224
+ // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
225
+ // support the second argument.
226
+ if (testElement.classList.contains("c3")) {
227
+ var _toggle = DOMTokenList.prototype.toggle;
228
+
229
+ DOMTokenList.prototype.toggle = function(token, force) {
230
+ if (1 in arguments && !this.contains(token) === !force) {
231
+ return force;
232
+ } else {
233
+ return _toggle.call(this, token);
234
+ }
235
+ };
236
+
237
+ }
238
+
239
+ testElement = null;
240
+ }());
241
+ }
242
+ }
243
+
244
+ },{}],2:[function(require,module,exports){
245
+
246
+ /**
247
+ * Expose `parse`.
248
+ */
249
+
250
+ module.exports = parse;
251
+
252
+ /**
253
+ * Tests for browser support.
254
+ */
255
+
256
+ var innerHTMLBug = false;
257
+ var bugTestDiv;
258
+ if (typeof document !== 'undefined') {
259
+ bugTestDiv = document.createElement('div');
260
+ // Setup
261
+ bugTestDiv.innerHTML = ' <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
262
+ // Make sure that link elements get serialized correctly by innerHTML
263
+ // This requires a wrapper element in IE
264
+ innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
265
+ bugTestDiv = undefined;
266
+ }
267
+
268
+ /**
269
+ * Wrap map from jquery.
270
+ */
271
+
272
+ var map = {
273
+ legend: [1, '<fieldset>', '</fieldset>'],
274
+ tr: [2, '<table><tbody>', '</tbody></table>'],
275
+ col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
276
+ // for script/link/style tags to work in IE6-8, you have to wrap
277
+ // in a div with a non-whitespace character in front, ha!
278
+ _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
279
+ };
280
+
281
+ map.td =
282
+ map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
283
+
284
+ map.option =
285
+ map.optgroup = [1, '<select multiple="multiple">', '</select>'];
286
+
287
+ map.thead =
288
+ map.tbody =
289
+ map.colgroup =
290
+ map.caption =
291
+ map.tfoot = [1, '<table>', '</table>'];
292
+
293
+ map.polyline =
294
+ map.ellipse =
295
+ map.polygon =
296
+ map.circle =
297
+ map.text =
298
+ map.line =
299
+ map.path =
300
+ map.rect =
301
+ map.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
302
+
303
+ /**
304
+ * Parse `html` and return a DOM Node instance, which could be a TextNode,
305
+ * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
306
+ * instance, depending on the contents of the `html` string.
307
+ *
308
+ * @param {String} html - HTML string to "domify"
309
+ * @param {Document} doc - The `document` instance to create the Node for
310
+ * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
311
+ * @api private
312
+ */
313
+
314
+ function parse(html, doc) {
315
+ if ('string' != typeof html) throw new TypeError('String expected');
316
+
317
+ // default to the global `document` object
318
+ if (!doc) doc = document;
319
+
320
+ // tag name
321
+ var m = /<([\w:]+)/.exec(html);
322
+ if (!m) return doc.createTextNode(html);
323
+
324
+ html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
325
+
326
+ var tag = m[1];
327
+
328
+ // body support
329
+ if (tag == 'body') {
330
+ var el = doc.createElement('html');
331
+ el.innerHTML = html;
332
+ return el.removeChild(el.lastChild);
333
+ }
334
+
335
+ // wrap map
336
+ var wrap = map[tag] || map._default;
337
+ var depth = wrap[0];
338
+ var prefix = wrap[1];
339
+ var suffix = wrap[2];
340
+ var el = doc.createElement('div');
341
+ el.innerHTML = prefix + html + suffix;
342
+ while (depth--) el = el.lastChild;
343
+
344
+ // one element
345
+ if (el.firstChild == el.lastChild) {
346
+ return el.removeChild(el.firstChild);
347
+ }
348
+
349
+ // several elements
350
+ var fragment = doc.createDocumentFragment();
351
+ while (el.firstChild) {
352
+ fragment.appendChild(el.removeChild(el.firstChild));
353
+ }
354
+
355
+ return fragment;
356
+ }
357
+
358
+ },{}],3:[function(require,module,exports){
359
+ /**
360
+ * Code refactored from Mozilla Developer Network:
361
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
362
+ */
363
+
364
+ 'use strict';
365
+
366
+ function assign(target, firstSource) {
367
+ if (target === undefined || target === null) {
368
+ throw new TypeError('Cannot convert first argument to object');
369
+ }
370
+
371
+ var to = Object(target);
372
+ for (var i = 1; i < arguments.length; i++) {
373
+ var nextSource = arguments[i];
374
+ if (nextSource === undefined || nextSource === null) {
375
+ continue;
376
+ }
377
+
378
+ var keysArray = Object.keys(Object(nextSource));
379
+ for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
380
+ var nextKey = keysArray[nextIndex];
381
+ var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
382
+ if (desc !== undefined && desc.enumerable) {
383
+ to[nextKey] = nextSource[nextKey];
384
+ }
385
+ }
386
+ }
387
+ return to;
388
+ }
389
+
390
+ function polyfill() {
391
+ if (!Object.assign) {
392
+ Object.defineProperty(Object, 'assign', {
393
+ enumerable: false,
394
+ configurable: true,
395
+ writable: true,
396
+ value: assign
397
+ });
398
+ }
399
+ }
400
+
401
+ module.exports = {
402
+ assign: assign,
403
+ polyfill: polyfill
404
+ };
405
+
406
+ },{}],4:[function(require,module,exports){
407
+ // get successful control from form and assemble into object
408
+ // http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2
409
+
410
+ // types which indicate a submit action and are not successful controls
411
+ // these will be ignored
412
+ var k_r_submitter = /^(?:submit|button|image|reset|file)$/i;
413
+
414
+ // node names which could be successful controls
415
+ var k_r_success_contrls = /^(?:input|select|textarea|keygen)/i;
416
+
417
+ // Matches bracket notation.
418
+ var brackets = /(\[[^\[\]]*\])/g;
419
+
420
+ // serializes form fields
421
+ // @param form MUST be an HTMLForm element
422
+ // @param options is an optional argument to configure the serialization. Default output
423
+ // with no options specified is a url encoded string
424
+ // - hash: [true | false] Configure the output type. If true, the output will
425
+ // be a js object.
426
+ // - serializer: [function] Optional serializer function to override the default one.
427
+ // The function takes 3 arguments (result, key, value) and should return new result
428
+ // hash and url encoded str serializers are provided with this module
429
+ // - disabled: [true | false]. If true serialize disabled fields.
430
+ // - empty: [true | false]. If true serialize empty fields
431
+ function serialize(form, options) {
432
+ if (typeof options != 'object') {
433
+ options = { hash: !!options };
434
+ }
435
+ else if (options.hash === undefined) {
436
+ options.hash = true;
437
+ }
438
+
439
+ var result = (options.hash) ? {} : '';
440
+ var serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize);
441
+
442
+ var elements = form && form.elements ? form.elements : [];
443
+
444
+ //Object store each radio and set if it's empty or not
445
+ var radio_store = Object.create(null);
446
+
447
+ for (var i=0 ; i<elements.length ; ++i) {
448
+ var element = elements[i];
449
+
450
+ // ingore disabled fields
451
+ if ((!options.disabled && element.disabled) || !element.name) {
452
+ continue;
453
+ }
454
+ // ignore anyhting that is not considered a success field
455
+ if (!k_r_success_contrls.test(element.nodeName) ||
456
+ k_r_submitter.test(element.type)) {
457
+ continue;
458
+ }
459
+
460
+ var key = element.name;
461
+ var val = element.value;
462
+
463
+ // we can't just use element.value for checkboxes cause some browsers lie to us
464
+ // they say "on" for value when the box isn't checked
465
+ if ((element.type === 'checkbox' || element.type === 'radio') && !element.checked) {
466
+ val = undefined;
467
+ }
468
+
469
+ // If we want empty elements
470
+ if (options.empty) {
471
+ // for checkbox
472
+ if (element.type === 'checkbox' && !element.checked) {
473
+ val = '';
474
+ }
475
+
476
+ // for radio
477
+ if (element.type === 'radio') {
478
+ if (!radio_store[element.name] && !element.checked) {
479
+ radio_store[element.name] = false;
480
+ }
481
+ else if (element.checked) {
482
+ radio_store[element.name] = true;
483
+ }
484
+ }
485
+
486
+ // if options empty is true, continue only if its radio
487
+ if (!val && element.type == 'radio') {
488
+ continue;
489
+ }
490
+ }
491
+ else {
492
+ // value-less fields are ignored unless options.empty is true
493
+ if (!val) {
494
+ continue;
495
+ }
496
+ }
497
+
498
+ // multi select boxes
499
+ if (element.type === 'select-multiple') {
500
+ val = [];
501
+
502
+ var selectOptions = element.options;
503
+ var isSelectedOptions = false;
504
+ for (var j=0 ; j<selectOptions.length ; ++j) {
505
+ var option = selectOptions[j];
506
+ var allowedEmpty = options.empty && !option.value;
507
+ var hasValue = (option.value || allowedEmpty);
508
+ if (option.selected && hasValue) {
509
+ isSelectedOptions = true;
510
+
511
+ // If using a hash serializer be sure to add the
512
+ // correct notation for an array in the multi-select
513
+ // context. Here the name attribute on the select element
514
+ // might be missing the trailing bracket pair. Both names
515
+ // "foo" and "foo[]" should be arrays.
516
+ if (options.hash && key.slice(key.length - 2) !== '[]') {
517
+ result = serializer(result, key + '[]', option.value);
518
+ }
519
+ else {
520
+ result = serializer(result, key, option.value);
521
+ }
522
+ }
523
+ }
524
+
525
+ // Serialize if no selected options and options.empty is true
526
+ if (!isSelectedOptions && options.empty) {
527
+ result = serializer(result, key, '');
528
+ }
529
+
530
+ continue;
531
+ }
532
+
533
+ result = serializer(result, key, val);
534
+ }
535
+
536
+ // Check for all empty radio buttons and serialize them with key=""
537
+ if (options.empty) {
538
+ for (var key in radio_store) {
539
+ if (!radio_store[key]) {
540
+ result = serializer(result, key, '');
541
+ }
542
+ }
543
+ }
544
+
545
+ return result;
546
+ }
547
+
548
+ function parse_keys(string) {
549
+ var keys = [];
550
+ var prefix = /^([^\[\]]*)/;
551
+ var children = new RegExp(brackets);
552
+ var match = prefix.exec(string);
553
+
554
+ if (match[1]) {
555
+ keys.push(match[1]);
556
+ }
557
+
558
+ while ((match = children.exec(string)) !== null) {
559
+ keys.push(match[1]);
560
+ }
561
+
562
+ return keys;
563
+ }
564
+
565
+ function hash_assign(result, keys, value) {
566
+ if (keys.length === 0) {
567
+ result = value;
568
+ return result;
569
+ }
570
+
571
+ var key = keys.shift();
572
+ var between = key.match(/^\[(.+?)\]$/);
573
+
574
+ if (key === '[]') {
575
+ result = result || [];
576
+
577
+ if (Array.isArray(result)) {
578
+ result.push(hash_assign(null, keys, value));
579
+ }
580
+ else {
581
+ // This might be the result of bad name attributes like "[][foo]",
582
+ // in this case the original `result` object will already be
583
+ // assigned to an object literal. Rather than coerce the object to
584
+ // an array, or cause an exception the attribute "_values" is
585
+ // assigned as an array.
586
+ result._values = result._values || [];
587
+ result._values.push(hash_assign(null, keys, value));
588
+ }
589
+
590
+ return result;
591
+ }
592
+
593
+ // Key is an attribute name and can be assigned directly.
594
+ if (!between) {
595
+ result[key] = hash_assign(result[key], keys, value);
596
+ }
597
+ else {
598
+ var string = between[1];
599
+ // +var converts the variable into a number
600
+ // better than parseInt because it doesn't truncate away trailing
601
+ // letters and actually fails if whole thing is not a number
602
+ var index = +string;
603
+
604
+ // If the characters between the brackets is not a number it is an
605
+ // attribute name and can be assigned directly.
606
+ if (isNaN(index)) {
607
+ result = result || {};
608
+ result[string] = hash_assign(result[string], keys, value);
609
+ }
610
+ else {
611
+ result = result || [];
612
+ result[index] = hash_assign(result[index], keys, value);
613
+ }
614
+ }
615
+
616
+ return result;
617
+ }
618
+
619
+ // Object/hash encoding serializer.
620
+ function hash_serializer(result, key, value) {
621
+ var matches = key.match(brackets);
622
+
623
+ // Has brackets? Use the recursive assignment function to walk the keys,
624
+ // construct any missing objects in the result tree and make the assignment
625
+ // at the end of the chain.
626
+ if (matches) {
627
+ var keys = parse_keys(key);
628
+ hash_assign(result, keys, value);
629
+ }
630
+ else {
631
+ // Non bracket notation can make assignments directly.
632
+ var existing = result[key];
633
+
634
+ // If the value has been assigned already (for instance when a radio and
635
+ // a checkbox have the same name attribute) convert the previous value
636
+ // into an array before pushing into it.
637
+ //
638
+ // NOTE: If this requirement were removed all hash creation and
639
+ // assignment could go through `hash_assign`.
640
+ if (existing) {
641
+ if (!Array.isArray(existing)) {
642
+ result[key] = [ existing ];
643
+ }
644
+
645
+ result[key].push(value);
646
+ }
647
+ else {
648
+ result[key] = value;
649
+ }
650
+ }
651
+
652
+ return result;
653
+ }
654
+
655
+ // urlform encoding serializer
656
+ function str_serialize(result, key, value) {
657
+ // encode newlines as \r\n cause the html spec says so
658
+ value = value.replace(/(\r)?\n/g, '\r\n');
659
+ value = encodeURIComponent(value);
660
+
661
+ // spaces should be '+' rather than '%20'.
662
+ value = value.replace(/%20/g, '+');
663
+ return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + value;
664
+ }
665
+
666
+ module.exports = serialize;
667
+
668
+ },{}],5:[function(require,module,exports){
669
+ (function (global){
670
+ (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){
671
+
672
+ /**
673
+ * Expose `parse`.
674
+ */
675
+
676
+ module.exports = parse;
677
+
678
+ /**
679
+ * Tests for browser support.
680
+ */
681
+
682
+ var innerHTMLBug = false;
683
+ var bugTestDiv;
684
+ if (typeof document !== 'undefined') {
685
+ bugTestDiv = document.createElement('div');
686
+ // Setup
687
+ bugTestDiv.innerHTML = ' <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
688
+ // Make sure that link elements get serialized correctly by innerHTML
689
+ // This requires a wrapper element in IE
690
+ innerHTMLBug = !bugTestDiv.getElementsByTagName('link').length;
691
+ bugTestDiv = undefined;
692
+ }
693
+
694
+ /**
695
+ * Wrap map from jquery.
696
+ */
697
+
698
+ var map = {
699
+ legend: [1, '<fieldset>', '</fieldset>'],
700
+ tr: [2, '<table><tbody>', '</tbody></table>'],
701
+ col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
702
+ // for script/link/style tags to work in IE6-8, you have to wrap
703
+ // in a div with a non-whitespace character in front, ha!
704
+ _default: innerHTMLBug ? [1, 'X<div>', '</div>'] : [0, '', '']
705
+ };
706
+
707
+ map.td =
708
+ map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
709
+
710
+ map.option =
711
+ map.optgroup = [1, '<select multiple="multiple">', '</select>'];
712
+
713
+ map.thead =
714
+ map.tbody =
715
+ map.colgroup =
716
+ map.caption =
717
+ map.tfoot = [1, '<table>', '</table>'];
718
+
719
+ map.polyline =
720
+ map.ellipse =
721
+ map.polygon =
722
+ map.circle =
723
+ map.text =
724
+ map.line =
725
+ map.path =
726
+ map.rect =
727
+ map.g = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
728
+
729
+ /**
730
+ * Parse `html` and return a DOM Node instance, which could be a TextNode,
731
+ * HTML DOM Node of some kind (<div> for example), or a DocumentFragment
732
+ * instance, depending on the contents of the `html` string.
733
+ *
734
+ * @param {String} html - HTML string to "domify"
735
+ * @param {Document} doc - The `document` instance to create the Node for
736
+ * @return {DOMNode} the TextNode, DOM Node, or DocumentFragment instance
737
+ * @api private
738
+ */
739
+
740
+ function parse(html, doc) {
741
+ if ('string' != typeof html) throw new TypeError('String expected');
742
+
743
+ // default to the global `document` object
744
+ if (!doc) doc = document;
745
+
746
+ // tag name
747
+ var m = /<([\w:]+)/.exec(html);
748
+ if (!m) return doc.createTextNode(html);
749
+
750
+ html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace
751
+
752
+ var tag = m[1];
753
+
754
+ // body support
755
+ if (tag == 'body') {
756
+ var el = doc.createElement('html');
757
+ el.innerHTML = html;
758
+ return el.removeChild(el.lastChild);
759
+ }
760
+
761
+ // wrap map
762
+ var wrap = map[tag] || map._default;
763
+ var depth = wrap[0];
764
+ var prefix = wrap[1];
765
+ var suffix = wrap[2];
766
+ var el = doc.createElement('div');
767
+ el.innerHTML = prefix + html + suffix;
768
+ while (depth--) el = el.lastChild;
769
+
770
+ // one element
771
+ if (el.firstChild == el.lastChild) {
772
+ return el.removeChild(el.firstChild);
773
+ }
774
+
775
+ // several elements
776
+ var fragment = doc.createDocumentFragment();
777
+ while (el.firstChild) {
778
+ fragment.appendChild(el.removeChild(el.firstChild));
779
+ }
780
+
781
+ return fragment;
782
+ }
783
+
784
+ },{}],2:[function(require,module,exports){
785
+ // get successful control from form and assemble into object
786
+ // http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2
787
+
788
+ // types which indicate a submit action and are not successful controls
789
+ // these will be ignored
790
+ var k_r_submitter = /^(?:submit|button|image|reset|file)$/i;
791
+
792
+ // node names which could be successful controls
793
+ var k_r_success_contrls = /^(?:input|select|textarea|keygen)/i;
794
+
795
+ // Matches bracket notation.
796
+ var brackets = /(\[[^\[\]]*\])/g;
797
+
798
+ // serializes form fields
799
+ // @param form MUST be an HTMLForm element
800
+ // @param options is an optional argument to configure the serialization. Default output
801
+ // with no options specified is a url encoded string
802
+ // - hash: [true | false] Configure the output type. If true, the output will
803
+ // be a js object.
804
+ // - serializer: [function] Optional serializer function to override the default one.
805
+ // The function takes 3 arguments (result, key, value) and should return new result
806
+ // hash and url encoded str serializers are provided with this module
807
+ // - disabled: [true | false]. If true serialize disabled fields.
808
+ // - empty: [true | false]. If true serialize empty fields
809
+ function serialize(form, options) {
810
+ if (typeof options != 'object') {
811
+ options = { hash: !!options };
812
+ }
813
+ else if (options.hash === undefined) {
814
+ options.hash = true;
815
+ }
816
+
817
+ var result = (options.hash) ? {} : '';
818
+ var serializer = options.serializer || ((options.hash) ? hash_serializer : str_serialize);
819
+
820
+ var elements = form && form.elements ? form.elements : [];
821
+
822
+ //Object store each radio and set if it's empty or not
823
+ var radio_store = Object.create(null);
824
+
825
+ for (var i=0 ; i<elements.length ; ++i) {
826
+ var element = elements[i];
827
+
828
+ // ingore disabled fields
829
+ if ((!options.disabled && element.disabled) || !element.name) {
830
+ continue;
831
+ }
832
+ // ignore anyhting that is not considered a success field
833
+ if (!k_r_success_contrls.test(element.nodeName) ||
834
+ k_r_submitter.test(element.type)) {
835
+ continue;
836
+ }
837
+
838
+ var key = element.name;
839
+ var val = element.value;
840
+
841
+ // we can't just use element.value for checkboxes cause some browsers lie to us
842
+ // they say "on" for value when the box isn't checked
843
+ if ((element.type === 'checkbox' || element.type === 'radio') && !element.checked) {
844
+ val = undefined;
845
+ }
846
+
847
+ // If we want empty elements
848
+ if (options.empty) {
849
+ // for checkbox
850
+ if (element.type === 'checkbox' && !element.checked) {
851
+ val = '';
852
+ }
853
+
854
+ // for radio
855
+ if (element.type === 'radio') {
856
+ if (!radio_store[element.name] && !element.checked) {
857
+ radio_store[element.name] = false;
858
+ }
859
+ else if (element.checked) {
860
+ radio_store[element.name] = true;
861
+ }
862
+ }
863
+
864
+ // if options empty is true, continue only if its radio
865
+ if (!val && element.type == 'radio') {
866
+ continue;
867
+ }
868
+ }
869
+ else {
870
+ // value-less fields are ignored unless options.empty is true
871
+ if (!val) {
872
+ continue;
873
+ }
874
+ }
875
+
876
+ // multi select boxes
877
+ if (element.type === 'select-multiple') {
878
+ val = [];
879
+
880
+ var selectOptions = element.options;
881
+ var isSelectedOptions = false;
882
+ for (var j=0 ; j<selectOptions.length ; ++j) {
883
+ var option = selectOptions[j];
884
+ var allowedEmpty = options.empty && !option.value;
885
+ var hasValue = (option.value || allowedEmpty);
886
+ if (option.selected && hasValue) {
887
+ isSelectedOptions = true;
888
+
889
+ // If using a hash serializer be sure to add the
890
+ // correct notation for an array in the multi-select
891
+ // context. Here the name attribute on the select element
892
+ // might be missing the trailing bracket pair. Both names
893
+ // "foo" and "foo[]" should be arrays.
894
+ if (options.hash && key.slice(key.length - 2) !== '[]') {
895
+ result = serializer(result, key + '[]', option.value);
896
+ }
897
+ else {
898
+ result = serializer(result, key, option.value);
899
+ }
900
+ }
901
+ }
902
+
903
+ // Serialize if no selected options and options.empty is true
904
+ if (!isSelectedOptions && options.empty) {
905
+ result = serializer(result, key, '');
906
+ }
907
+
908
+ continue;
909
+ }
910
+
911
+ result = serializer(result, key, val);
912
+ }
913
+
914
+ // Check for all empty radio buttons and serialize them with key=""
915
+ if (options.empty) {
916
+ for (var key in radio_store) {
917
+ if (!radio_store[key]) {
918
+ result = serializer(result, key, '');
919
+ }
920
+ }
921
+ }
922
+
923
+ return result;
924
+ }
925
+
926
+ function parse_keys(string) {
927
+ var keys = [];
928
+ var prefix = /^([^\[\]]*)/;
929
+ var children = new RegExp(brackets);
930
+ var match = prefix.exec(string);
931
+
932
+ if (match[1]) {
933
+ keys.push(match[1]);
934
+ }
935
+
936
+ while ((match = children.exec(string)) !== null) {
937
+ keys.push(match[1]);
938
+ }
939
+
940
+ return keys;
941
+ }
942
+
943
+ function hash_assign(result, keys, value) {
944
+ if (keys.length === 0) {
945
+ result = value;
946
+ return result;
947
+ }
948
+
949
+ var key = keys.shift();
950
+ var between = key.match(/^\[(.+?)\]$/);
951
+
952
+ if (key === '[]') {
953
+ result = result || [];
954
+
955
+ if (Array.isArray(result)) {
956
+ result.push(hash_assign(null, keys, value));
957
+ }
958
+ else {
959
+ // This might be the result of bad name attributes like "[][foo]",
960
+ // in this case the original `result` object will already be
961
+ // assigned to an object literal. Rather than coerce the object to
962
+ // an array, or cause an exception the attribute "_values" is
963
+ // assigned as an array.
964
+ result._values = result._values || [];
965
+ result._values.push(hash_assign(null, keys, value));
966
+ }
967
+
968
+ return result;
969
+ }
970
+
971
+ // Key is an attribute name and can be assigned directly.
972
+ if (!between) {
973
+ result[key] = hash_assign(result[key], keys, value);
974
+ }
975
+ else {
976
+ var string = between[1];
977
+ // +var converts the variable into a number
978
+ // better than parseInt because it doesn't truncate away trailing
979
+ // letters and actually fails if whole thing is not a number
980
+ var index = +string;
981
+
982
+ // If the characters between the brackets is not a number it is an
983
+ // attribute name and can be assigned directly.
984
+ if (isNaN(index)) {
985
+ result = result || {};
986
+ result[string] = hash_assign(result[string], keys, value);
987
+ }
988
+ else {
989
+ result = result || [];
990
+ result[index] = hash_assign(result[index], keys, value);
991
+ }
992
+ }
993
+
994
+ return result;
995
+ }
996
+
997
+ // Object/hash encoding serializer.
998
+ function hash_serializer(result, key, value) {
999
+ var matches = key.match(brackets);
1000
+
1001
+ // Has brackets? Use the recursive assignment function to walk the keys,
1002
+ // construct any missing objects in the result tree and make the assignment
1003
+ // at the end of the chain.
1004
+ if (matches) {
1005
+ var keys = parse_keys(key);
1006
+ hash_assign(result, keys, value);
1007
+ }
1008
+ else {
1009
+ // Non bracket notation can make assignments directly.
1010
+ var existing = result[key];
1011
+
1012
+ // If the value has been assigned already (for instance when a radio and
1013
+ // a checkbox have the same name attribute) convert the previous value
1014
+ // into an array before pushing into it.
1015
+ //
1016
+ // NOTE: If this requirement were removed all hash creation and
1017
+ // assignment could go through `hash_assign`.
1018
+ if (existing) {
1019
+ if (!Array.isArray(existing)) {
1020
+ result[key] = [ existing ];
1021
+ }
1022
+
1023
+ result[key].push(value);
1024
+ }
1025
+ else {
1026
+ result[key] = value;
1027
+ }
1028
+ }
1029
+
1030
+ return result;
1031
+ }
1032
+
1033
+ // urlform encoding serializer
1034
+ function str_serialize(result, key, value) {
1035
+ // encode newlines as \r\n cause the html spec says so
1036
+ value = value.replace(/(\r)?\n/g, '\r\n');
1037
+ value = encodeURIComponent(value);
1038
+
1039
+ // spaces should be '+' rather than '%20'.
1040
+ value = value.replace(/%20/g, '+');
1041
+ return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + value;
1042
+ }
1043
+
1044
+ module.exports = serialize;
1045
+
1046
+ },{}],3:[function(require,module,exports){
1047
+ var domify = require('domify')
1048
+ var serialize = require('form-serialize')
1049
+
1050
+ // Build DOM elements for the structure of the dialog
1051
+ var buildDialogForm = function buildDialogForm (options) {
1052
+ var form = document.createElement('form')
1053
+ form.classList.add('vex-dialog-form')
1054
+
1055
+ var message = document.createElement('div')
1056
+ message.classList.add('vex-dialog-message')
1057
+ message.appendChild(options.message instanceof window.Node ? options.message : domify(options.message))
1058
+
1059
+ var input = document.createElement('div')
1060
+ input.classList.add('vex-dialog-input')
1061
+ input.appendChild(options.input instanceof window.Node ? options.input : domify(options.input))
1062
+
1063
+ form.appendChild(message)
1064
+ form.appendChild(input)
1065
+
1066
+ return form
1067
+ }
1068
+
1069
+ // Take an array of buttons (see the default buttons below) and turn them into DOM elements
1070
+ var buttonsToDOM = function buttonsToDOM (buttons) {
1071
+ var domButtons = document.createElement('div')
1072
+ domButtons.classList.add('vex-dialog-buttons')
1073
+
1074
+ for (var i = 0; i < buttons.length; i++) {
1075
+ var button = buttons[i]
1076
+ var domButton = document.createElement('button')
1077
+ domButton.type = button.type
1078
+ domButton.textContent = button.text
1079
+ domButton.className = button.className
1080
+ domButton.classList.add('vex-dialog-button')
1081
+ if (i === 0) {
1082
+ domButton.classList.add('vex-first')
1083
+ } else if (i === buttons.length - 1) {
1084
+ domButton.classList.add('vex-last')
1085
+ }
1086
+ // Attach click listener to button with closure
1087
+ (function (button) {
1088
+ domButton.addEventListener('click', function (e) {
1089
+ if (button.click) {
1090
+ button.click.call(this, e)
1091
+ }
1092
+ }.bind(this))
1093
+ }.bind(this)(button))
1094
+
1095
+ domButtons.appendChild(domButton)
1096
+ }
1097
+
1098
+ return domButtons
1099
+ }
1100
+
1101
+ var plugin = function plugin (vex) {
1102
+ // Define the API first
1103
+ var dialog = {
1104
+ // Plugin name
1105
+ name: 'dialog',
1106
+
1107
+ // Open
1108
+ open: function open (opts) {
1109
+ var options = Object.assign({}, this.defaultOptions, opts)
1110
+
1111
+ // `message` is unsafe internally, so translate
1112
+ // safe default: HTML-escape the message before passing it through
1113
+ if (options.unsafeMessage && !options.message) {
1114
+ options.message = options.unsafeMessage
1115
+ } else if (options.message) {
1116
+ options.message = vex._escapeHtml(options.message)
1117
+ }
1118
+
1119
+ // Build the form from the options
1120
+ var form = options.unsafeContent = buildDialogForm(options)
1121
+
1122
+ // Open the dialog
1123
+ var dialogInstance = vex.open(options)
1124
+
1125
+ // Quick comment - these options and appending buttons and everything
1126
+ // would preferably be done _before_ opening the dialog. However, since
1127
+ // they rely on the context of the vex instance, we have to do them
1128
+ // after. A potential future fix would be to differentiate between
1129
+ // a "created" vex instance and an "opened" vex instance, so any actions
1130
+ // that rely on the specific context of the instance can do their stuff
1131
+ // before opening the dialog on the page.
1132
+
1133
+ // Override the before close callback to also pass the value of the form
1134
+ var beforeClose = options.beforeClose && options.beforeClose.bind(dialogInstance)
1135
+ dialogInstance.options.beforeClose = function dialogBeforeClose () {
1136
+ // Only call the callback once - when the validation in beforeClose, if present, is true
1137
+ var shouldClose = beforeClose ? beforeClose() : true
1138
+ if (shouldClose) {
1139
+ options.callback(this.value || false)
1140
+ }
1141
+ // Return the result of beforeClose() to vex
1142
+ return shouldClose
1143
+ }.bind(dialogInstance)
1144
+
1145
+ // Append buttons to form with correct context
1146
+ form.appendChild(buttonsToDOM.call(dialogInstance, options.buttons))
1147
+
1148
+ // Attach form to instance
1149
+ dialogInstance.form = form
1150
+
1151
+ // Add submit listener to form
1152
+ form.addEventListener('submit', options.onSubmit.bind(dialogInstance))
1153
+
1154
+ // Optionally focus the first input in the form
1155
+ if (options.focusFirstInput) {
1156
+ var el = dialogInstance.contentEl.querySelector('button, input, select, textarea')
1157
+ if (el) {
1158
+ el.focus()
1159
+ }
1160
+ }
1161
+
1162
+ // For chaining
1163
+ return dialogInstance
1164
+ },
1165
+
1166
+ // Alert
1167
+ alert: function (options) {
1168
+ // Allow string as message
1169
+ if (typeof options === 'string') {
1170
+ options = {
1171
+ message: options
1172
+ }
1173
+ }
1174
+ options = Object.assign({}, this.defaultOptions, this.defaultAlertOptions, options)
1175
+ return this.open(options)
1176
+ },
1177
+
1178
+ // Confirm
1179
+ confirm: function (options) {
1180
+ if (typeof options !== 'object' || typeof options.callback !== 'function') {
1181
+ throw new Error('dialog.confirm(options) requires options.callback.')
1182
+ }
1183
+ options = Object.assign({}, this.defaultOptions, this.defaultConfirmOptions, options)
1184
+ return this.open(options)
1185
+ },
1186
+
1187
+ // Prompt
1188
+ prompt: function (options) {
1189
+ if (typeof options !== 'object' || typeof options.callback !== 'function') {
1190
+ throw new Error('dialog.prompt(options) requires options.callback.')
1191
+ }
1192
+ var defaults = Object.assign({}, this.defaultOptions, this.defaultPromptOptions)
1193
+ var dynamicDefaults = {
1194
+ unsafeMessage: '<label for="vex">' + vex._escapeHtml(options.label || defaults.label) + '</label>',
1195
+ 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) + '" />'
1196
+ }
1197
+ options = Object.assign(defaults, dynamicDefaults, options)
1198
+ // Pluck the value of the "vex" input field as the return value for prompt's callback
1199
+ // More closely mimics "window.prompt" in that a single string is returned
1200
+ var callback = options.callback
1201
+ options.callback = function promptCallback (value) {
1202
+ if (typeof value === 'object') {
1203
+ var keys = Object.keys(value)
1204
+ value = keys.length ? value[keys[0]] : ''
1205
+ }
1206
+ callback(value)
1207
+ }
1208
+ return this.open(options)
1209
+ }
1210
+ }
1211
+
1212
+ // Now define any additional data that's not the direct dialog API
1213
+ dialog.buttons = {
1214
+ YES: {
1215
+ text: 'OK',
1216
+ type: 'submit',
1217
+ className: 'vex-dialog-button-primary',
1218
+ click: function yesClick () {
1219
+ this.value = true
1220
+ }
1221
+ },
1222
+
1223
+ NO: {
1224
+ text: 'Cancel',
1225
+ type: 'button',
1226
+ className: 'vex-dialog-button-secondary',
1227
+ click: function noClick () {
1228
+ this.value = false
1229
+ this.close()
1230
+ }
1231
+ }
1232
+ }
1233
+
1234
+ dialog.defaultOptions = {
1235
+ callback: function () {},
1236
+ afterOpen: function () {},
1237
+ message: '',
1238
+ input: '',
1239
+ buttons: [
1240
+ dialog.buttons.YES,
1241
+ dialog.buttons.NO
1242
+ ],
1243
+ showCloseButton: false,
1244
+ onSubmit: function onDialogSubmit (e) {
1245
+ e.preventDefault()
1246
+ if (this.options.input) {
1247
+ this.value = serialize(this.form, { hash: true })
1248
+ }
1249
+ return this.close()
1250
+ },
1251
+ focusFirstInput: true
1252
+ }
1253
+
1254
+ dialog.defaultAlertOptions = {
1255
+ buttons: [
1256
+ dialog.buttons.YES
1257
+ ]
1258
+ }
1259
+
1260
+ dialog.defaultPromptOptions = {
1261
+ label: 'Prompt:',
1262
+ placeholder: '',
1263
+ value: ''
1264
+ }
1265
+
1266
+ dialog.defaultConfirmOptions = {}
1267
+
1268
+ return dialog
1269
+ }
1270
+
1271
+ module.exports = plugin
1272
+
1273
+ },{"domify":1,"form-serialize":2}]},{},[3])(3)
1274
+ });
1275
+ }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
1276
+ },{"domify":2,"form-serialize":4}],6:[function(require,module,exports){
1277
+ var vex = require('./vex')
1278
+ vex.registerPlugin(require('vex-dialog'))
1279
+ module.exports = vex
1280
+
1281
+ },{"./vex":7,"vex-dialog":5}],7:[function(require,module,exports){
1282
+ // classList polyfill for old browsers
1283
+ require('classlist-polyfill')
1284
+ // Object.assign polyfill
1285
+ require('es6-object-assign').polyfill()
1286
+
1287
+ // String to DOM function
1288
+ var domify = require('domify')
1289
+
1290
+ // Use the DOM's HTML parsing to escape any dangerous strings
1291
+ var escapeHtml = function escapeHtml (str) {
1292
+ if (typeof str !== 'undefined') {
1293
+ var div = document.createElement('div')
1294
+ div.appendChild(document.createTextNode(str))
1295
+ return div.innerHTML
1296
+ } else {
1297
+ return ''
1298
+ }
1299
+ }
1300
+
1301
+ // Utility function to add space-delimited class strings to a DOM element's classList
1302
+ var addClasses = function addClasses (el, classStr) {
1303
+ if (typeof classStr !== 'string' || classStr.length === 0) {
1304
+ return
1305
+ }
1306
+ var classes = classStr.split(' ')
1307
+ for (var i = 0; i < classes.length; i++) {
1308
+ var className = classes[i]
1309
+ if (className.length) {
1310
+ el.classList.add(className)
1311
+ }
1312
+ }
1313
+ }
1314
+
1315
+ // Detect CSS Animation End Support
1316
+ // https://github.com/limonte/sweetalert2/blob/99bd539f85e15ac170f69d35001d12e092ef0054/src/utils/dom.js#L194
1317
+ var animationEndEvent = (function detectAnimationEndEvent () {
1318
+ var el = document.createElement('div')
1319
+ var eventNames = {
1320
+ 'WebkitAnimation': 'webkitAnimationEnd',
1321
+ 'MozAnimation': 'animationend',
1322
+ 'OAnimation': 'oanimationend',
1323
+ 'msAnimation': 'MSAnimationEnd',
1324
+ 'animation': 'animationend'
1325
+ }
1326
+ for (var i in eventNames) {
1327
+ if (el.style[i] !== undefined) {
1328
+ return eventNames[i]
1329
+ }
1330
+ }
1331
+ return false
1332
+ })()
1333
+
1334
+ // vex base CSS classes
1335
+ var baseClassNames = {
1336
+ vex: 'vex',
1337
+ content: 'vex-content',
1338
+ overlay: 'vex-overlay',
1339
+ close: 'vex-close',
1340
+ closing: 'vex-closing',
1341
+ open: 'vex-open'
1342
+ }
1343
+
1344
+ // Private lookup table of all open vex objects, keyed by id
1345
+ var vexes = {}
1346
+ var globalId = 1
1347
+
1348
+ // Private boolean to assist the escapeButtonCloses option
1349
+ var isEscapeActive = false
1350
+
1351
+ // vex itself is an object that exposes a simple API to open and close vex objects in various ways
1352
+ var vex = {
1353
+ open: function open (opts) {
1354
+ // Check for usage of deprecated options, and log a warning
1355
+ var warnDeprecated = function warnDeprecated (prop) {
1356
+ console.warn('The "' + prop + '" property is deprecated in vex 3. Use CSS classes and the appropriate "ClassName" options, instead.')
1357
+ console.warn('See http://github.hubspot.com/vex/api/advanced/#options')
1358
+ }
1359
+ if (opts.css) {
1360
+ warnDeprecated('css')
1361
+ }
1362
+ if (opts.overlayCSS) {
1363
+ warnDeprecated('overlayCSS')
1364
+ }
1365
+ if (opts.contentCSS) {
1366
+ warnDeprecated('contentCSS')
1367
+ }
1368
+ if (opts.closeCSS) {
1369
+ warnDeprecated('closeCSS')
1370
+ }
1371
+
1372
+ // The dialog instance
1373
+ var vexInstance = {}
1374
+
1375
+ // Set id
1376
+ vexInstance.id = globalId++
1377
+
1378
+ // Store internally
1379
+ vexes[vexInstance.id] = vexInstance
1380
+
1381
+ // Set state
1382
+ vexInstance.isOpen = true
1383
+
1384
+ // Close function on the vex instance
1385
+ // This is how all API functions should close individual vexes
1386
+ vexInstance.close = function instanceClose () {
1387
+ // Check state
1388
+ if (!this.isOpen) {
1389
+ return true
1390
+ }
1391
+
1392
+ var options = this.options
1393
+
1394
+ // escapeButtonCloses is checked first
1395
+ if (isEscapeActive && !options.escapeButtonCloses) {
1396
+ return false
1397
+ }
1398
+
1399
+ // Allow the user to validate any info or abort the close with the beforeClose callback
1400
+ var shouldClose = (function shouldClose () {
1401
+ // Call before close callback
1402
+ if (options.beforeClose) {
1403
+ return options.beforeClose.call(this)
1404
+ }
1405
+ // Otherwise indicate that it's ok to continue with close
1406
+ return true
1407
+ }.bind(this)())
1408
+
1409
+ // If beforeClose() fails, abort the close
1410
+ if (shouldClose === false) {
1411
+ return false
1412
+ }
1413
+
1414
+ // Update state
1415
+ this.isOpen = false
1416
+
1417
+ // Detect if the content el has any CSS animations defined
1418
+ var style = window.getComputedStyle(this.contentEl)
1419
+ function hasAnimationPre (prefix) {
1420
+ return style.getPropertyValue(prefix + 'animation-name') !== 'none' && style.getPropertyValue(prefix + 'animation-duration') !== '0s'
1421
+ }
1422
+ var hasAnimation = hasAnimationPre('') || hasAnimationPre('-webkit-') || hasAnimationPre('-moz-') || hasAnimationPre('-o-')
1423
+
1424
+ // Define the function that will actually close the instance
1425
+ var close = function close () {
1426
+ if (!this.rootEl.parentNode) {
1427
+ return
1428
+ }
1429
+ // Run once
1430
+ this.rootEl.removeEventListener(animationEndEvent, close)
1431
+ // Remove from lookup table (prevent memory leaks)
1432
+ delete vexes[this.id]
1433
+ // Remove the dialog from the DOM
1434
+ this.rootEl.parentNode.removeChild(this.rootEl)
1435
+ // Call after close callback
1436
+ if (options.afterClose) {
1437
+ options.afterClose.call(this)
1438
+ }
1439
+ // Remove styling from the body, if no more vexes are open
1440
+ if (Object.keys(vexes).length === 0) {
1441
+ document.body.classList.remove(baseClassNames.open)
1442
+ }
1443
+ }.bind(this)
1444
+
1445
+ // Close the vex
1446
+ if (animationEndEvent && hasAnimation) {
1447
+ // Setup the end event listener, to remove the el from the DOM
1448
+ this.rootEl.addEventListener(animationEndEvent, close)
1449
+ // Add the closing class to the dialog, showing the close animation
1450
+ this.rootEl.classList.add(baseClassNames.closing)
1451
+ } else {
1452
+ close()
1453
+ }
1454
+
1455
+ return true
1456
+ }
1457
+
1458
+ // Allow strings as content
1459
+ if (typeof opts === 'string') {
1460
+ opts = {
1461
+ content: opts
1462
+ }
1463
+ }
1464
+
1465
+ // `content` is unsafe internally, so translate
1466
+ // safe default: HTML-escape the content before passing it through
1467
+ if (opts.unsafeContent && !opts.content) {
1468
+ opts.content = opts.unsafeContent
1469
+ } else if (opts.content) {
1470
+ opts.content = escapeHtml(opts.content)
1471
+ }
1472
+
1473
+ // Store options on instance for future reference
1474
+ var options = vexInstance.options = Object.assign({}, vex.defaultOptions, opts)
1475
+
1476
+ // vex root
1477
+ var rootEl = vexInstance.rootEl = document.createElement('div')
1478
+ rootEl.classList.add(baseClassNames.vex)
1479
+ addClasses(rootEl, options.className)
1480
+
1481
+ // Overlay
1482
+ var overlayEl = vexInstance.overlayEl = document.createElement('div')
1483
+ overlayEl.classList.add(baseClassNames.overlay)
1484
+ addClasses(overlayEl, options.overlayClassName)
1485
+ if (options.overlayClosesOnClick) {
1486
+ overlayEl.addEventListener('click', function overlayClickListener (e) {
1487
+ if (e.target === overlayEl) {
1488
+ vexInstance.close()
1489
+ }
1490
+ })
1491
+ }
1492
+ rootEl.appendChild(overlayEl)
1493
+
1494
+ // Content
1495
+ var contentEl = vexInstance.contentEl = document.createElement('div')
1496
+ contentEl.classList.add(baseClassNames.content)
1497
+ addClasses(contentEl, options.contentClassName)
1498
+ contentEl.appendChild(options.content instanceof window.Node ? options.content : domify(options.content))
1499
+ rootEl.appendChild(contentEl)
1500
+
1501
+ // Close button
1502
+ if (options.showCloseButton) {
1503
+ var closeEl = vexInstance.closeEl = document.createElement('div')
1504
+ closeEl.classList.add(baseClassNames.close)
1505
+ addClasses(closeEl, options.closeClassName)
1506
+ closeEl.addEventListener('click', vexInstance.close.bind(vexInstance))
1507
+ contentEl.appendChild(closeEl)
1508
+ }
1509
+
1510
+ // Add to DOM
1511
+ document.querySelector(options.appendLocation).appendChild(rootEl)
1512
+
1513
+ // Call after open callback
1514
+ if (options.afterOpen) {
1515
+ options.afterOpen.call(vexInstance)
1516
+ }
1517
+
1518
+ // Apply styling to the body
1519
+ document.body.classList.add(baseClassNames.open)
1520
+
1521
+ // Return the created vex instance
1522
+ return vexInstance
1523
+ },
1524
+
1525
+ // A top-level vex.close function to close dialogs by reference or id
1526
+ close: function close (vexOrId) {
1527
+ var id
1528
+ if (vexOrId.id) {
1529
+ id = vexOrId.id
1530
+ } else if (typeof vexOrId === 'string') {
1531
+ id = vexOrId
1532
+ } else {
1533
+ throw new TypeError('close requires a vex object or id string')
1534
+ }
1535
+ if (!vexes[id]) {
1536
+ return false
1537
+ }
1538
+ return vexes[id].close()
1539
+ },
1540
+
1541
+ // Close the most recently created/opened vex
1542
+ closeTop: function closeTop () {
1543
+ var ids = Object.keys(vexes)
1544
+ if (!ids.length) {
1545
+ return false
1546
+ }
1547
+ return vexes[ids[ids.length - 1]].close()
1548
+ },
1549
+
1550
+ // Close every vex!
1551
+ closeAll: function closeAll () {
1552
+ for (var id in vexes) {
1553
+ this.close(id)
1554
+ }
1555
+ return true
1556
+ },
1557
+
1558
+ // A getter for the internal lookup table
1559
+ getAll: function getAll () {
1560
+ return vexes
1561
+ },
1562
+
1563
+ // A getter for the internal lookup table
1564
+ getById: function getById (id) {
1565
+ return vexes[id]
1566
+ }
1567
+ }
1568
+
1569
+ // Close top vex on escape
1570
+ window.addEventListener('keyup', function vexKeyupListener (e) {
1571
+ if (e.keyCode === 27) {
1572
+ isEscapeActive = true
1573
+ vex.closeTop()
1574
+ isEscapeActive = false
1575
+ }
1576
+ })
1577
+
1578
+ // Close all vexes on history pop state (useful in single page apps)
1579
+ window.addEventListener('popstate', function () {
1580
+ if (vex.defaultOptions.closeAllOnPopState) {
1581
+ vex.closeAll()
1582
+ }
1583
+ })
1584
+
1585
+ vex.defaultOptions = {
1586
+ content: '',
1587
+ showCloseButton: true,
1588
+ escapeButtonCloses: true,
1589
+ overlayClosesOnClick: true,
1590
+ appendLocation: 'body',
1591
+ className: '',
1592
+ overlayClassName: '',
1593
+ contentClassName: '',
1594
+ closeClassName: '',
1595
+ closeAllOnPopState: true
1596
+ }
1597
+
1598
+ // TODO Loading symbols?
1599
+
1600
+ // Include escapeHtml function on the library object
1601
+ Object.defineProperty(vex, '_escapeHtml', {
1602
+ configurable: false,
1603
+ enumerable: false,
1604
+ writable: false,
1605
+ value: escapeHtml
1606
+ })
1607
+
1608
+ // Plugin system!
1609
+ vex.registerPlugin = function registerPlugin (pluginFn, name) {
1610
+ var plugin = pluginFn(vex)
1611
+ var pluginName = name || plugin.name
1612
+ if (vex[pluginName]) {
1613
+ throw new Error('Plugin ' + name + ' is already registered.')
1614
+ }
1615
+ vex[pluginName] = plugin
1616
+ }
1617
+
1618
+ module.exports = vex
1619
+
1620
+ },{"classlist-polyfill":1,"domify":2,"es6-object-assign":3}]},{},[6])(6)
1621
+ });