PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.3.13
HTML Forms – Simple WordPress Forms Plugin v1.3.13
1.7.0 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0 1.3.0 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 All 67 releases
html-forms / assets / js / public.js

public.js in HTML Forms – Simple WordPress Forms Plugin 1.3.13, at assets/js/public.js

1,023 lines 33.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () { var require = undefined; var module = undefined; var exports = undefined; var define = undefined;(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2 'use strict';
3
4 Object.defineProperty(exports, "__esModule", {
5 value: true
6 });
7 exports["default"] = void 0;
8
9 function getFieldValues(form, fieldName, evt) {
10 var values = [];
11 var inputs = form.querySelectorAll('input[name="' + fieldName + '"], select[name="' + fieldName + '"], textarea[name="' + fieldName + '"], button[name="' + fieldName + '"]');
12
13 for (var i = 0; i < inputs.length; i++) {
14 var input = inputs[i];
15 var type = input.getAttribute("type").toLowerCase();
16
17 if ((type === "radio" || type === "checkbox") && !input.checked) {
18 continue;
19 } // ignore buttons which are not clicked (in case there's more than one button with same name)
20
21
22 if (type === 'button' || type === 'submit' || input.tagName === 'BUTTON') {
23 if ((!evt || evt.target !== input) && form.dataset[fieldName] !== input.value) {
24 continue;
25 }
26
27 form.dataset[fieldName] = input.value;
28 }
29
30 values.push(input.value);
31 } // default to an empty string
32 // can be used to show or hide an element when a field is empty or has not been set
33 // Usage: data-show-if="FIELDNAME:"
34
35
36 if (values.length === 0) {
37 values.push("");
38 }
39
40 return values;
41 }
42
43 function findForm(element) {
44 var bubbleElement = element;
45
46 while (bubbleElement.parentElement) {
47 bubbleElement = bubbleElement.parentElement;
48
49 if (bubbleElement.tagName === 'FORM') {
50 return bubbleElement;
51 }
52 }
53
54 return null;
55 }
56
57 function toggleElement(el, evt) {
58 var show = !!el.getAttribute('data-show-if');
59 var conditions = show ? el.getAttribute('data-show-if').split(':') : el.getAttribute('data-hide-if').split(':');
60 var fieldName = conditions[0];
61 var expectedValues = (conditions.length > 1 ? conditions[1] : "*").split('|');
62 var form = findForm(el);
63 var values = getFieldValues(form, fieldName, evt); // determine whether condition is met
64
65 var conditionMet = false;
66
67 for (var i = 0; i < values.length; i++) {
68 var value = values[i]; // condition is met when value is in array of expected values OR expected values contains a wildcard and value is not empty
69
70 conditionMet = expectedValues.indexOf(value) > -1 || expectedValues.indexOf('*') > -1 && value.length > 0;
71
72 if (conditionMet) {
73 break;
74 }
75 } // toggle element display
76
77
78 if (show) {
79 el.style.display = conditionMet ? '' : 'none';
80 } else {
81 el.style.display = conditionMet ? 'none' : '';
82 } // find all inputs inside this element and toggle [required] attr (to prevent HTML5 validation on hidden elements)
83
84
85 var inputs = el.querySelectorAll('input, select, textarea');
86 [].forEach.call(inputs, function (el) {
87 if ((conditionMet || show) && el.getAttribute('data-was-required')) {
88 el.required = true;
89 el.removeAttribute('data-was-required');
90 }
91
92 if ((!conditionMet || !show) && el.required) {
93 el.setAttribute('data-was-required', "true");
94 el.required = false;
95 }
96 });
97 } // evaluate conditional elements globally
98
99
100 function evaluate() {
101 var elements = document.querySelectorAll('.hf-form [data-show-if], .hf-form [data-hide-if]');
102 [].forEach.call(elements, toggleElement);
103 } // re-evaluate conditional elements for change events on forms
104
105
106 function handleInputEvent(evt) {
107 if (!evt.target || !evt.target.form || evt.target.form.className.indexOf('hf-form') < 0) {
108 return;
109 }
110
111 var form = evt.target.form;
112 var elements = form.querySelectorAll('[data-show-if], [data-hide-if]');
113 [].forEach.call(elements, function (el) {
114 return toggleElement(el, evt);
115 });
116 }
117
118 var _default = {
119 'init': function init() {
120 document.addEventListener('click', handleInputEvent, true);
121 document.addEventListener('keyup', handleInputEvent, true);
122 document.addEventListener('change', handleInputEvent, true);
123 document.addEventListener('hf-refresh', evaluate, true);
124 window.addEventListener('load', evaluate);
125 evaluate();
126 }
127 };
128 exports["default"] = _default;
129
130 },{}],2:[function(require,module,exports){
131 'use strict';
132
133 function getButtonText(button) {
134 return button.innerHTML ? button.innerHTML : button.value;
135 }
136
137 function setButtonText(button, text) {
138 button.innerHTML ? button.innerHTML = text : button.value = text;
139 }
140
141 function Loader(formElement) {
142 this.form = formElement;
143 this.button = formElement.querySelector('input[type="submit"], button[type="submit"]');
144 this.loadingInterval = 0;
145 this.character = "\xB7";
146
147 if (this.button) {
148 this.originalButton = this.button.cloneNode(true);
149 }
150 }
151
152 Loader.prototype.setCharacter = function (c) {
153 this.character = c;
154 };
155
156 Loader.prototype.start = function () {
157 if (this.button) {
158 // loading text
159 var loadingText = this.button.getAttribute('data-loading-text');
160
161 if (loadingText) {
162 setButtonText(this.button, loadingText);
163 return;
164 } // Show AJAX loader
165
166
167 var styles = window.getComputedStyle(this.button);
168 this.button.style.width = styles.width;
169 setButtonText(this.button, this.character);
170 this.loadingInterval = window.setInterval(this.tick.bind(this), 500);
171 } else {
172 this.form.style.opacity = '0.5';
173 }
174 };
175
176 Loader.prototype.tick = function () {
177 // count chars, start over at 5
178 var text = getButtonText(this.button);
179 var loadingChar = this.character;
180 setButtonText(this.button, text.length >= 5 ? loadingChar : text + " " + loadingChar);
181 };
182
183 Loader.prototype.stop = function () {
184 if (this.button) {
185 this.button.style.width = this.originalButton.style.width;
186 var text = getButtonText(this.originalButton);
187 setButtonText(this.button, text);
188 window.clearInterval(this.loadingInterval);
189 } else {
190 this.form.style.opacity = '';
191 }
192 };
193
194 module.exports = Loader;
195
196 },{}],3:[function(require,module,exports){
197 'use strict';
198
199 Object.defineProperty(exports, "__esModule", {
200 value: true
201 });
202 exports["default"] = void 0;
203
204 function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
205
206 function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
207
208 function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
209
210 function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
211
212 var populate = require('populate.js'); // parse ?query=string with array support. no nesting.
213
214
215 function parseUrlParams(q) {
216 var params = new URLSearchParams(q);
217 var obj = {};
218 var _iteratorNormalCompletion = true;
219 var _didIteratorError = false;
220 var _iteratorError = undefined;
221
222 try {
223 for (var _iterator = params.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
224 var _step$value = _slicedToArray(_step.value, 2),
225 name = _step$value[0],
226 value = _step$value[1];
227
228 if (name.substr(name.length - 2) === "[]") {
229 var arrName = name.substr(0, name.length - 2);
230 obj[arrName] = obj[arrName] || [];
231 obj[arrName].push(value);
232 } else {
233 obj[name] = value;
234 }
235 }
236 } catch (err) {
237 _didIteratorError = true;
238 _iteratorError = err;
239 } finally {
240 try {
241 if (!_iteratorNormalCompletion && _iterator["return"] != null) {
242 _iterator["return"]();
243 }
244 } finally {
245 if (_didIteratorError) {
246 throw _iteratorError;
247 }
248 }
249 }
250
251 return obj;
252 }
253
254 function init() {
255 if (!window.URLSearchParams) {
256 return;
257 } // only act on form elements outputted by HTML Forms
258
259
260 var forms = [].filter.call(document.forms, function (f) {
261 return f.className.indexOf('hf-form') > -1;
262 });
263
264 if (!forms) {
265 return;
266 } // fill each form with data from URL params
267
268
269 var data = parseUrlParams(window.location.search);
270 forms.forEach(function (f) {
271 populate(f, data);
272 });
273 }
274
275 var _default = {
276 init: init
277 };
278 exports["default"] = _default;
279
280 },{"populate.js":6}],4:[function(require,module,exports){
281 "use strict";
282
283 /* window.CustomEvent polyfill for IE */
284 (function () {
285 if (typeof window.CustomEvent === "function") return false;
286
287 function CustomEvent(event, params) {
288 params = params || {
289 bubbles: false,
290 cancelable: false,
291 detail: undefined
292 };
293 var evt = document.createEvent('CustomEvent');
294 evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
295 return evt;
296 }
297
298 CustomEvent.prototype = window.Event.prototype;
299 window.CustomEvent = CustomEvent;
300 })();
301
302 },{}],5:[function(require,module,exports){
303 "use strict";
304
305 var _formPrefiller = _interopRequireDefault(require("./form-prefiller.js"));
306
307 var _conditionality = _interopRequireDefault(require("./conditionality.js"));
308
309 require("./polyfills/custom-event.js");
310
311 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
312
313 var Loader = require('./form-loading-indicator.js');
314
315 var vars = window.hf_js_vars || {
316 ajax_url: window.location.href
317 };
318
319 var EventEmitter = require('wolfy87-eventemitter');
320
321 var events = new EventEmitter();
322
323 function cleanFormMessages(formEl) {
324 var messageElements = formEl.querySelectorAll('.hf-message');
325 [].forEach.call(messageElements, function (el) {
326 el.parentNode.removeChild(el);
327 });
328 }
329
330 function addFormMessage(formEl, message) {
331 var txtElement = document.createElement('p');
332 txtElement.className = 'hf-message hf-message-' + message.type;
333 txtElement.innerHTML = message.text; // uses innerHTML because we allow some HTML strings in the message settings
334
335 txtElement.setAttribute('role', 'alert');
336 var wrapperElement = formEl.querySelector('.hf-messages') || formEl;
337 wrapperElement.appendChild(txtElement);
338 }
339
340 function handleSubmitEvents(e) {
341 var formEl = e.target;
342
343 if (formEl.className.indexOf('hf-form') < 0) {
344 return;
345 } // always prevent default (because regular submit doesn't work for HTML Forms)
346
347
348 e.preventDefault();
349 submitForm(formEl);
350 }
351
352 function submitForm(formEl) {
353 cleanFormMessages(formEl);
354 emitEvent('submit', formEl);
355 var formData = new FormData(formEl);
356 [].forEach.call(formEl.querySelectorAll('[data-was-required=true]'), function (el) {
357 formData.append('_was_required[]', el.getAttribute('name'));
358 });
359 var request = new XMLHttpRequest();
360 request.onreadystatechange = createRequestHandler(formEl);
361 request.open('POST', vars.ajax_url, true);
362 request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
363 request.send(formData);
364 request = null;
365 }
366
367 function emitEvent(eventName, element) {
368 // browser event API: formElement.on('hf-success', ..)
369 element.dispatchEvent(new CustomEvent("hf-" + eventName)); // custom events API: html_forms.on('success', ..)
370
371 events.emit(eventName, [element]);
372 }
373
374 function createRequestHandler(formEl) {
375 var loader = new Loader(formEl);
376 loader.start();
377 return function () {
378 // are we done?
379 if (this.readyState === 4) {
380 var response;
381 loader.stop();
382
383 if (this.status >= 200 && this.status < 400) {
384 try {
385 response = JSON.parse(this.responseText);
386 } catch (error) {
387 console.log('HTML Forms: failed to parse AJAX response.\n\nError: "' + error + '"');
388 return;
389 }
390
391 emitEvent('submitted', formEl);
392
393 if (response.error) {
394 emitEvent('error', formEl);
395 } else {
396 emitEvent('success', formEl);
397 } // Show form message
398
399
400 if (response.message) {
401 addFormMessage(formEl, response.message);
402 emitEvent('message', formEl);
403 } // Should we hide form?
404
405
406 if (response.hide_form) {
407 formEl.querySelector('.hf-fields-wrap').style.display = 'none';
408 } // Should we redirect?
409
410
411 if (response.redirect_url) {
412 window.location = response.redirect_url;
413 } // clear form
414
415
416 if (!response.error) {
417 formEl.reset();
418 }
419 } else {
420 // Server error :(
421 console.log(this.responseText);
422 }
423 }
424 };
425 }
426
427 document.addEventListener('submit', handleSubmitEvents, false); // useCapture=false to ensure we bubble upwards (and thus can cancel propagation)
428
429 _conditionality["default"].init();
430
431 _formPrefiller["default"].init();
432
433 window.html_forms = {
434 'on': events.on.bind(events),
435 'submit': submitForm
436 };
437
438 },{"./conditionality.js":1,"./form-loading-indicator.js":2,"./form-prefiller.js":3,"./polyfills/custom-event.js":4,"wolfy87-eventemitter":7}],6:[function(require,module,exports){
439 /*! populate.js v1.0.2 by @dannyvankooten | MIT license */
440 ;(function(root) {
441
442 /**
443 * Populate form fields from a JSON object.
444 *
445 * @param form object The form element containing your input fields.
446 * @param data array JSON data to populate the fields with.
447 * @param basename string Optional basename which is added to `name` attributes
448 */
449 var populate = function( form, data, basename) {
450
451 for(var key in data) {
452
453 if( ! data.hasOwnProperty( key ) ) {
454 continue;
455 }
456
457 var name = key;
458 var value = data[key];
459
460 if ('undefined' === typeof value) {
461 value = '';
462 }
463
464 if (null === value) {
465 value = '';
466 }
467
468 // handle array name attributes
469 if(typeof(basename) !== "undefined") {
470 name = basename + "[" + key + "]";
471 }
472
473 if(value.constructor === Array) {
474 name += '[]';
475 } else if(typeof value == "object") {
476 populate( form, value, name);
477 continue;
478 }
479
480 // only proceed if element is set
481 var element = form.elements.namedItem( name );
482 if( ! element ) {
483 continue;
484 }
485
486 var type = element.type || element[0].type;
487
488 switch(type ) {
489 default:
490 element.value = value;
491 break;
492
493 case 'radio':
494 case 'checkbox':
495 for( var j=0; j < element.length; j++ ) {
496 element[j].checked = ( value.indexOf(element[j].value) > -1 );
497 }
498 break;
499
500 case 'select-multiple':
501 var values = value.constructor == Array ? value : [value];
502
503 for(var k = 0; k < element.options.length; k++) {
504 element.options[k].selected |= (values.indexOf(element.options[k].value) > -1 );
505 }
506 break;
507
508 case 'select':
509 case 'select-one':
510 element.value = value.toString() || value;
511 break;
512 case 'date':
513 element.value = new Date(value).toISOString().split('T')[0];
514 break;
515 }
516
517 }
518
519 };
520
521 // Play nice with AMD, CommonJS or a plain global object.
522 if ( typeof define == 'function' && typeof define.amd == 'object' && define.amd ) {
523 define(function() {
524 return populate;
525 });
526 } else if ( typeof module !== 'undefined' && module.exports ) {
527 module.exports = populate;
528 } else {
529 root.populate = populate;
530 }
531
532 }(this));
533
534 },{}],7:[function(require,module,exports){
535 /*!
536 * EventEmitter v5.2.6 - git.io/ee
537 * Unlicense - http://unlicense.org/
538 * Oliver Caldwell - https://oli.me.uk/
539 * @preserve
540 */
541
542 ;(function (exports) {
543 'use strict';
544
545 /**
546 * Class for managing events.
547 * Can be extended to provide event functionality in other classes.
548 *
549 * @class EventEmitter Manages event registering and emitting.
550 */
551 function EventEmitter() {}
552
553 // Shortcuts to improve speed and size
554 var proto = EventEmitter.prototype;
555 var originalGlobalValue = exports.EventEmitter;
556
557 /**
558 * Finds the index of the listener for the event in its storage array.
559 *
560 * @param {Function[]} listeners Array of listeners to search through.
561 * @param {Function} listener Method to look for.
562 * @return {Number} Index of the specified listener, -1 if not found
563 * @api private
564 */
565 function indexOfListener(listeners, listener) {
566 var i = listeners.length;
567 while (i--) {
568 if (listeners[i].listener === listener) {
569 return i;
570 }
571 }
572
573 return -1;
574 }
575
576 /**
577 * Alias a method while keeping the context correct, to allow for overwriting of target method.
578 *
579 * @param {String} name The name of the target method.
580 * @return {Function} The aliased method
581 * @api private
582 */
583 function alias(name) {
584 return function aliasClosure() {
585 return this[name].apply(this, arguments);
586 };
587 }
588
589 /**
590 * Returns the listener array for the specified event.
591 * Will initialise the event object and listener arrays if required.
592 * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
593 * Each property in the object response is an array of listener functions.
594 *
595 * @param {String|RegExp} evt Name of the event to return the listeners from.
596 * @return {Function[]|Object} All listener functions for the event.
597 */
598 proto.getListeners = function getListeners(evt) {
599 var events = this._getEvents();
600 var response;
601 var key;
602
603 // Return a concatenated array of all matching events if
604 // the selector is a regular expression.
605 if (evt instanceof RegExp) {
606 response = {};
607 for (key in events) {
608 if (events.hasOwnProperty(key) && evt.test(key)) {
609 response[key] = events[key];
610 }
611 }
612 }
613 else {
614 response = events[evt] || (events[evt] = []);
615 }
616
617 return response;
618 };
619
620 /**
621 * Takes a list of listener objects and flattens it into a list of listener functions.
622 *
623 * @param {Object[]} listeners Raw listener objects.
624 * @return {Function[]} Just the listener functions.
625 */
626 proto.flattenListeners = function flattenListeners(listeners) {
627 var flatListeners = [];
628 var i;
629
630 for (i = 0; i < listeners.length; i += 1) {
631 flatListeners.push(listeners[i].listener);
632 }
633
634 return flatListeners;
635 };
636
637 /**
638 * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
639 *
640 * @param {String|RegExp} evt Name of the event to return the listeners from.
641 * @return {Object} All listener functions for an event in an object.
642 */
643 proto.getListenersAsObject = function getListenersAsObject(evt) {
644 var listeners = this.getListeners(evt);
645 var response;
646
647 if (listeners instanceof Array) {
648 response = {};
649 response[evt] = listeners;
650 }
651
652 return response || listeners;
653 };
654
655 function isValidListener (listener) {
656 if (typeof listener === 'function' || listener instanceof RegExp) {
657 return true
658 } else if (listener && typeof listener === 'object') {
659 return isValidListener(listener.listener)
660 } else {
661 return false
662 }
663 }
664
665 /**
666 * Adds a listener function to the specified event.
667 * The listener will not be added if it is a duplicate.
668 * If the listener returns true then it will be removed after it is called.
669 * If you pass a regular expression as the event name then the listener will be added to all events that match it.
670 *
671 * @param {String|RegExp} evt Name of the event to attach the listener to.
672 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
673 * @return {Object} Current instance of EventEmitter for chaining.
674 */
675 proto.addListener = function addListener(evt, listener) {
676 if (!isValidListener(listener)) {
677 throw new TypeError('listener must be a function');
678 }
679
680 var listeners = this.getListenersAsObject(evt);
681 var listenerIsWrapped = typeof listener === 'object';
682 var key;
683
684 for (key in listeners) {
685 if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
686 listeners[key].push(listenerIsWrapped ? listener : {
687 listener: listener,
688 once: false
689 });
690 }
691 }
692
693 return this;
694 };
695
696 /**
697 * Alias of addListener
698 */
699 proto.on = alias('addListener');
700
701 /**
702 * Semi-alias of addListener. It will add a listener that will be
703 * automatically removed after its first execution.
704 *
705 * @param {String|RegExp} evt Name of the event to attach the listener to.
706 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
707 * @return {Object} Current instance of EventEmitter for chaining.
708 */
709 proto.addOnceListener = function addOnceListener(evt, listener) {
710 return this.addListener(evt, {
711 listener: listener,
712 once: true
713 });
714 };
715
716 /**
717 * Alias of addOnceListener.
718 */
719 proto.once = alias('addOnceListener');
720
721 /**
722 * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
723 * You need to tell it what event names should be matched by a regex.
724 *
725 * @param {String} evt Name of the event to create.
726 * @return {Object} Current instance of EventEmitter for chaining.
727 */
728 proto.defineEvent = function defineEvent(evt) {
729 this.getListeners(evt);
730 return this;
731 };
732
733 /**
734 * Uses defineEvent to define multiple events.
735 *
736 * @param {String[]} evts An array of event names to define.
737 * @return {Object} Current instance of EventEmitter for chaining.
738 */
739 proto.defineEvents = function defineEvents(evts) {
740 for (var i = 0; i < evts.length; i += 1) {
741 this.defineEvent(evts[i]);
742 }
743 return this;
744 };
745
746 /**
747 * Removes a listener function from the specified event.
748 * When passed a regular expression as the event name, it will remove the listener from all events that match it.
749 *
750 * @param {String|RegExp} evt Name of the event to remove the listener from.
751 * @param {Function} listener Method to remove from the event.
752 * @return {Object} Current instance of EventEmitter for chaining.
753 */
754 proto.removeListener = function removeListener(evt, listener) {
755 var listeners = this.getListenersAsObject(evt);
756 var index;
757 var key;
758
759 for (key in listeners) {
760 if (listeners.hasOwnProperty(key)) {
761 index = indexOfListener(listeners[key], listener);
762
763 if (index !== -1) {
764 listeners[key].splice(index, 1);
765 }
766 }
767 }
768
769 return this;
770 };
771
772 /**
773 * Alias of removeListener
774 */
775 proto.off = alias('removeListener');
776
777 /**
778 * Adds listeners in bulk using the manipulateListeners method.
779 * If you pass an object as the first argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
780 * You can also pass it a regular expression to add the array of listeners to all events that match it.
781 * Yeah, this function does quite a bit. That's probably a bad thing.
782 *
783 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
784 * @param {Function[]} [listeners] An optional array of listener functions to add.
785 * @return {Object} Current instance of EventEmitter for chaining.
786 */
787 proto.addListeners = function addListeners(evt, listeners) {
788 // Pass through to manipulateListeners
789 return this.manipulateListeners(false, evt, listeners);
790 };
791
792 /**
793 * Removes listeners in bulk using the manipulateListeners method.
794 * If you pass an object as the first argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
795 * You can also pass it an event name and an array of listeners to be removed.
796 * You can also pass it a regular expression to remove the listeners from all events that match it.
797 *
798 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
799 * @param {Function[]} [listeners] An optional array of listener functions to remove.
800 * @return {Object} Current instance of EventEmitter for chaining.
801 */
802 proto.removeListeners = function removeListeners(evt, listeners) {
803 // Pass through to manipulateListeners
804 return this.manipulateListeners(true, evt, listeners);
805 };
806
807 /**
808 * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
809 * The first argument will determine if the listeners are removed (true) or added (false).
810 * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
811 * You can also pass it an event name and an array of listeners to be added/removed.
812 * You can also pass it a regular expression to manipulate the listeners of all events that match it.
813 *
814 * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
815 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
816 * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
817 * @return {Object} Current instance of EventEmitter for chaining.
818 */
819 proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
820 var i;
821 var value;
822 var single = remove ? this.removeListener : this.addListener;
823 var multiple = remove ? this.removeListeners : this.addListeners;
824
825 // If evt is an object then pass each of its properties to this method
826 if (typeof evt === 'object' && !(evt instanceof RegExp)) {
827 for (i in evt) {
828 if (evt.hasOwnProperty(i) && (value = evt[i])) {
829 // Pass the single listener straight through to the singular method
830 if (typeof value === 'function') {
831 single.call(this, i, value);
832 }
833 else {
834 // Otherwise pass back to the multiple function
835 multiple.call(this, i, value);
836 }
837 }
838 }
839 }
840 else {
841 // So evt must be a string
842 // And listeners must be an array of listeners
843 // Loop over it and pass each one to the multiple method
844 i = listeners.length;
845 while (i--) {
846 single.call(this, evt, listeners[i]);
847 }
848 }
849
850 return this;
851 };
852
853 /**
854 * Removes all listeners from a specified event.
855 * If you do not specify an event then all listeners will be removed.
856 * That means every event will be emptied.
857 * You can also pass a regex to remove all events that match it.
858 *
859 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
860 * @return {Object} Current instance of EventEmitter for chaining.
861 */
862 proto.removeEvent = function removeEvent(evt) {
863 var type = typeof evt;
864 var events = this._getEvents();
865 var key;
866
867 // Remove different things depending on the state of evt
868 if (type === 'string') {
869 // Remove all listeners for the specified event
870 delete events[evt];
871 }
872 else if (evt instanceof RegExp) {
873 // Remove all events matching the regex.
874 for (key in events) {
875 if (events.hasOwnProperty(key) && evt.test(key)) {
876 delete events[key];
877 }
878 }
879 }
880 else {
881 // Remove all listeners in all events
882 delete this._events;
883 }
884
885 return this;
886 };
887
888 /**
889 * Alias of removeEvent.
890 *
891 * Added to mirror the node API.
892 */
893 proto.removeAllListeners = alias('removeEvent');
894
895 /**
896 * Emits an event of your choice.
897 * When emitted, every listener attached to that event will be executed.
898 * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
899 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
900 * So they will not arrive within the array on the other side, they will be separate.
901 * You can also pass a regular expression to emit to all events that match it.
902 *
903 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
904 * @param {Array} [args] Optional array of arguments to be passed to each listener.
905 * @return {Object} Current instance of EventEmitter for chaining.
906 */
907 proto.emitEvent = function emitEvent(evt, args) {
908 var listenersMap = this.getListenersAsObject(evt);
909 var listeners;
910 var listener;
911 var i;
912 var key;
913 var response;
914
915 for (key in listenersMap) {
916 if (listenersMap.hasOwnProperty(key)) {
917 listeners = listenersMap[key].slice(0);
918
919 for (i = 0; i < listeners.length; i++) {
920 // If the listener returns true then it shall be removed from the event
921 // The function is executed either with a basic call or an apply if there is an args array
922 listener = listeners[i];
923
924 if (listener.once === true) {
925 this.removeListener(evt, listener.listener);
926 }
927
928 response = listener.listener.apply(this, args || []);
929
930 if (response === this._getOnceReturnValue()) {
931 this.removeListener(evt, listener.listener);
932 }
933 }
934 }
935 }
936
937 return this;
938 };
939
940 /**
941 * Alias of emitEvent
942 */
943 proto.trigger = alias('emitEvent');
944
945 /**
946 * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
947 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
948 *
949 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
950 * @param {...*} Optional additional arguments to be passed to each listener.
951 * @return {Object} Current instance of EventEmitter for chaining.
952 */
953 proto.emit = function emit(evt) {
954 var args = Array.prototype.slice.call(arguments, 1);
955 return this.emitEvent(evt, args);
956 };
957
958 /**
959 * Sets the current value to check against when executing listeners. If a
960 * listeners return value matches the one set here then it will be removed
961 * after execution. This value defaults to true.
962 *
963 * @param {*} value The new value to check for when executing listeners.
964 * @return {Object} Current instance of EventEmitter for chaining.
965 */
966 proto.setOnceReturnValue = function setOnceReturnValue(value) {
967 this._onceReturnValue = value;
968 return this;
969 };
970
971 /**
972 * Fetches the current value to check against when executing listeners. If
973 * the listeners return value matches this one then it should be removed
974 * automatically. It will return true by default.
975 *
976 * @return {*|Boolean} The current value to check for or the default, true.
977 * @api private
978 */
979 proto._getOnceReturnValue = function _getOnceReturnValue() {
980 if (this.hasOwnProperty('_onceReturnValue')) {
981 return this._onceReturnValue;
982 }
983 else {
984 return true;
985 }
986 };
987
988 /**
989 * Fetches the events object and creates one if required.
990 *
991 * @return {Object} The events storage object.
992 * @api private
993 */
994 proto._getEvents = function _getEvents() {
995 return this._events || (this._events = {});
996 };
997
998 /**
999 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
1000 *
1001 * @return {Function} Non conflicting EventEmitter class.
1002 */
1003 EventEmitter.noConflict = function noConflict() {
1004 exports.EventEmitter = originalGlobalValue;
1005 return EventEmitter;
1006 };
1007
1008 // Expose the class either via AMD, CommonJS or the global object
1009 if (typeof define === 'function' && define.amd) {
1010 define(function () {
1011 return EventEmitter;
1012 });
1013 }
1014 else if (typeof module === 'object' && module.exports){
1015 module.exports = EventEmitter;
1016 }
1017 else {
1018 exports.EventEmitter = EventEmitter;
1019 }
1020 }(typeof window !== 'undefined' ? window : this || {}));
1021
1022 },{}]},{},[5]);
1023 ; })();