· 7 years ago · Jan 23, 2019, 08:16 PM
1var POS =
2/******/ (function(modules) { // webpackBootstrap
3/******/ // The module cache
4/******/ var installedModules = {};
5/******/
6/******/ // The require function
7/******/ function __webpack_require__(moduleId) {
8/******/
9/******/ // Check if module is in cache
10/******/ if(installedModules[moduleId]) {
11/******/ return installedModules[moduleId].exports;
12/******/ }
13/******/ // Create a new module (and put it into the cache)
14/******/ var module = installedModules[moduleId] = {
15/******/ i: moduleId,
16/******/ l: false,
17/******/ exports: {}
18/******/ };
19/******/
20/******/ // Execute the module function
21/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
22/******/
23/******/ // Flag the module as loaded
24/******/ module.l = true;
25/******/
26/******/ // Return the exports of the module
27/******/ return module.exports;
28/******/ }
29/******/
30/******/
31/******/ // expose the modules object (__webpack_modules__)
32/******/ __webpack_require__.m = modules;
33/******/
34/******/ // expose the module cache
35/******/ __webpack_require__.c = installedModules;
36/******/
37/******/ // define getter function for harmony exports
38/******/ __webpack_require__.d = function(exports, name, getter) {
39/******/ if(!__webpack_require__.o(exports, name)) {
40/******/ Object.defineProperty(exports, name, {
41/******/ configurable: false,
42/******/ enumerable: true,
43/******/ get: getter
44/******/ });
45/******/ }
46/******/ };
47/******/
48/******/ // getDefaultExport function for compatibility with non-harmony modules
49/******/ __webpack_require__.n = function(module) {
50/******/ var getter = module && module.__esModule ?
51/******/ function getDefault() { return module['default']; } :
52/******/ function getModuleExports() { return module; };
53/******/ __webpack_require__.d(getter, 'a', getter);
54/******/ return getter;
55/******/ };
56/******/
57/******/ // Object.prototype.hasOwnProperty.call
58/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
59/******/
60/******/ // __webpack_public_path__
61/******/ __webpack_require__.p = "";
62/******/
63/******/ // Load entry module and return exports
64/******/ return __webpack_require__(__webpack_require__.s = 224);
65/******/ })
66/************************************************************************/
67/******/ ([
68/* 0 */
69/***/ (function(module, exports) {
70
71module.exports = _;
72
73/***/ }),
74/* 1 */
75/***/ (function(module, exports, __webpack_require__) {
76
77var Mn = __webpack_require__(9);
78var Radio = __webpack_require__(2);
79var _ = __webpack_require__(0);
80var $ = __webpack_require__(3);
81var hbs = __webpack_require__(7);
82var Utils = __webpack_require__(13);
83var polyglot = __webpack_require__(6);
84var debugFunction = __webpack_require__(8);
85var bb = __webpack_require__(4);
86var accounting = __webpack_require__(18);
87
88module.exports = Mn.Application.extend({
89
90 _initChannel: function () {
91 this.channelName = _.result(this, 'channelName') || 'global';
92 this.channel = _.result(this, 'channel') ||
93 Radio.channel(this.channelName);
94 },
95
96 _initDebug: function( debug ){
97 if( debug ){
98 debugFunction.enable('*');
99 }
100 Radio.DEBUG = debug;
101 console.info(
102 'Debugging is ' +
103 ( debug ? 'on' : 'off' ) +
104 ', visit http://woopos.com.au/docs/debugging'
105 );
106 },
107
108 _initOptions: function( payload ){
109 payload = payload || {};
110
111 // templates
112 hbs.Templates = payload.templates || {};
113
114 // polyglot
115 polyglot.extend( payload.i18n );
116
117 // options
118 this.options = payload.params || {};
119
120 // debug
121 this._initDebug( this.options.debug );
122
123 // emulateHTTP
124 bb.emulateHTTP = this.options.emulateHTTP === true;
125
126 // bootstrap accounting settings
127 accounting.settings = this.options.accounting;
128 },
129
130 /**
131 * todo: handle errors
132 * @param options
133 */
134 start: function( options ){
135 var self = this;
136 $.getJSON(
137 options.ajaxurl, {
138 action: options.action || 'wc_pos_payload',
139 security: options.nonce
140 }, function( payload ){
141 if(payload === 0) {
142 window.location.replace('/wp-login.php?pos=1');
143 }
144 self._initOptions( payload );
145 Mn.Application.prototype.start.call(self, payload);
146 }
147 );
148 },
149
150 set: function( path, value ){
151 _.set( this, path, value );
152 },
153
154 // namespace prefix for WP Admin
155 namespace: function( str ){
156 var prefix = window.adminpage ? 'wc_pos-' : '' ;
157 return prefix + str;
158 },
159
160 // extend app for third party plugins
161 debug: debugFunction,
162 polyglot: polyglot,
163 Utils: Utils
164
165});
166
167/**
168 * Custom Template Access
169 **/
170Mn.TemplateCache.prototype.loadTemplate = function(templateId){
171 return _.get( hbs.Templates, templateId.split('.'), $(templateId).html() );
172};
173
174Mn.TemplateCache.prototype.compileTemplate = function(rawTemplate) {
175 return hbs.compile(rawTemplate);
176};
177
178/***/ }),
179/* 2 */
180/***/ (function(module, exports) {
181
182module.exports = Backbone.Radio;
183
184/***/ }),
185/* 3 */
186/***/ (function(module, exports) {
187
188module.exports = jQuery;
189
190/***/ }),
191/* 4 */
192/***/ (function(module, exports) {
193
194module.exports = Backbone;
195
196/***/ }),
197/* 5 */
198/***/ (function(module, exports, __webpack_require__) {
199
200var Mn = __webpack_require__(9);
201var app = __webpack_require__(1);
202
203module.exports = app.prototype.ItemView = Mn.ItemView;
204
205/***/ }),
206/* 6 */
207/***/ (function(module, exports, __webpack_require__) {
208
209var Polyglot = __webpack_require__(41);
210module.exports = new Polyglot();
211
212/***/ }),
213/* 7 */
214/***/ (function(module, exports) {
215
216module.exports = Handlebars;
217
218/***/ }),
219/* 8 */
220/***/ (function(module, exports, __webpack_require__) {
221
222/* WEBPACK VAR INJECTION */(function(process) {/**
223 * This is the web browser implementation of `debug()`.
224 *
225 * Expose `debug()` as the module.
226 */
227
228exports = module.exports = __webpack_require__(58);
229exports.log = log;
230exports.formatArgs = formatArgs;
231exports.save = save;
232exports.load = load;
233exports.useColors = useColors;
234exports.storage = 'undefined' != typeof chrome
235 && 'undefined' != typeof chrome.storage
236 ? chrome.storage.local
237 : localstorage();
238
239/**
240 * Colors.
241 */
242
243exports.colors = [
244 '#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC',
245 '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF',
246 '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC',
247 '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF',
248 '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC',
249 '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033',
250 '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366',
251 '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933',
252 '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC',
253 '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF',
254 '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33'
255];
256
257/**
258 * Currently only WebKit-based Web Inspectors, Firefox >= v31,
259 * and the Firebug extension (any Firefox version) are known
260 * to support "%c" CSS customizations.
261 *
262 * TODO: add a `localStorage` variable to explicitly enable/disable colors
263 */
264
265function useColors() {
266 // NB: In an Electron preload script, document will be defined but not fully
267 // initialized. Since we know we're in Chrome, we'll just detect this case
268 // explicitly
269 if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') {
270 return true;
271 }
272
273 // Internet Explorer and Edge do not support colors.
274 if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
275 return false;
276 }
277
278 // is webkit? http://stackoverflow.com/a/16459606/376773
279 // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
280 return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
281 // is firebug? http://stackoverflow.com/a/398120/376773
282 (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
283 // is firefox >= v31?
284 // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
285 (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
286 // double check webkit in userAgent just in case we are in a worker
287 (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
288}
289
290/**
291 * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
292 */
293
294exports.formatters.j = function(v) {
295 try {
296 return JSON.stringify(v);
297 } catch (err) {
298 return '[UnexpectedJSONParseError]: ' + err.message;
299 }
300};
301
302
303/**
304 * Colorize log arguments if enabled.
305 *
306 * @api public
307 */
308
309function formatArgs(args) {
310 var useColors = this.useColors;
311
312 args[0] = (useColors ? '%c' : '')
313 + this.namespace
314 + (useColors ? ' %c' : ' ')
315 + args[0]
316 + (useColors ? '%c ' : ' ')
317 + '+' + exports.humanize(this.diff);
318
319 if (!useColors) return;
320
321 var c = 'color: ' + this.color;
322 args.splice(1, 0, c, 'color: inherit')
323
324 // the final "%c" is somewhat tricky, because there could be other
325 // arguments passed either before or after the %c, so we need to
326 // figure out the correct index to insert the CSS into
327 var index = 0;
328 var lastC = 0;
329 args[0].replace(/%[a-zA-Z%]/g, function(match) {
330 if ('%%' === match) return;
331 index++;
332 if ('%c' === match) {
333 // we only are interested in the *last* %c
334 // (the user may have provided their own)
335 lastC = index;
336 }
337 });
338
339 args.splice(lastC, 0, c);
340}
341
342/**
343 * Invokes `console.log()` when available.
344 * No-op when `console.log` is not a "function".
345 *
346 * @api public
347 */
348
349function log() {
350 // this hackery is required for IE8/9, where
351 // the `console.log` function doesn't have 'apply'
352 return 'object' === typeof console
353 && console.log
354 && Function.prototype.apply.call(console.log, console, arguments);
355}
356
357/**
358 * Save `namespaces`.
359 *
360 * @param {String} namespaces
361 * @api private
362 */
363
364function save(namespaces) {
365 try {
366 if (null == namespaces) {
367 exports.storage.removeItem('debug');
368 } else {
369 exports.storage.debug = namespaces;
370 }
371 } catch(e) {}
372}
373
374/**
375 * Load `namespaces`.
376 *
377 * @return {String} returns the previously persisted debug modes
378 * @api private
379 */
380
381function load() {
382 var r;
383 try {
384 r = exports.storage.debug;
385 } catch(e) {}
386
387 // If debug isn't set in LS, and we're in Electron, try to load $DEBUG
388 if (!r && typeof process !== 'undefined' && 'env' in process) {
389 r = process.env.DEBUG;
390 }
391
392 return r;
393}
394
395/**
396 * Enable namespaces listed in `localStorage.debug` initially.
397 */
398
399exports.enable(load());
400
401/**
402 * Localstorage attempts to return the localstorage.
403 *
404 * This is necessary because safari throws
405 * when a user disables cookies/localstorage
406 * and you attempt to access it.
407 *
408 * @return {LocalStorage}
409 * @api private
410 */
411
412function localstorage() {
413 try {
414 return window.localStorage;
415 } catch (e) {}
416}
417
418/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(27)))
419
420/***/ }),
421/* 9 */
422/***/ (function(module, exports) {
423
424module.exports = Marionette;
425
426/***/ }),
427/* 10 */
428/***/ (function(module, exports, __webpack_require__) {
429
430var Mn = __webpack_require__(9);
431var app = __webpack_require__(1);
432
433module.exports = app.prototype.LayoutView = Mn.LayoutView.extend({
434
435 working: function( action ) {
436 if (action === 'start') {
437 this.$el.addClass('working');
438 } else {
439 this.$el.removeClass('working');
440 }
441 }
442
443});
444
445/***/ }),
446/* 11 */
447/***/ (function(module, exports, __webpack_require__) {
448
449var bb = __webpack_require__(4);
450var Mn = __webpack_require__(9);
451var $ = __webpack_require__(3);
452var _ = __webpack_require__(0);
453var app = __webpack_require__(1);
454var LoadingService = __webpack_require__(113);
455var Radio = __webpack_require__(2);
456var globalChannel = Radio.channel('global');
457
458module.exports = app.prototype.Route = Mn.Object.extend({
459 constructor: function() {
460 this.initialize.apply(this, arguments);
461 },
462
463 _triggerMethod: function(name, args) {
464 if (this.router) {
465 this.router.triggerMethod.apply(
466 this.router,
467 [name + ':route'].concat(args)
468 );
469 }
470 this.triggerMethod.apply(this, [name].concat(args));
471 },
472
473 enter: function(args) {
474 var self = this;
475 this.transitioning = true;
476 this._triggerMethod('before:enter', args);
477 this._triggerMethod('before:fetch', args);
478
479 _.defer(function() {
480 if (self.transitioning) {
481 self.loading = new LoadingService({
482 container: self.container
483 });
484 }
485 });
486
487 return $.when(this.fetch.call(this, args)).then(function() {
488 self._triggerMethod('fetch', args);
489 self._triggerMethod('before:render', args);
490 }).then(function() {
491 self.transitioning = false;
492 return self.render.apply(self, args);
493 }).then(function() {
494 self._triggerMethod('render', args);
495 self._triggerMethod('enter', args);
496 }).fail(function() {
497 self._triggerMethod('error', args);
498 });
499 },
500
501 navigate: function() {
502 bb.history.navigate.apply(bb.history, arguments);
503 },
504
505 fetch : function() {},
506 render : function() {},
507
508 setTabLabel: function(options){
509 globalChannel.trigger('tab:label', options);
510 }
511
512});
513
514/***/ }),
515/* 12 */
516/***/ (function(module, exports, __webpack_require__) {
517
518var Mn = __webpack_require__(9);
519var Radio = __webpack_require__(2);
520var app = __webpack_require__(1);
521var _ = __webpack_require__(0);
522
523module.exports = app.prototype.Service = Mn.Object.extend({
524 constructor: function(options) {
525 options = options || {};
526
527 if (this.channelName) {
528 this.channel = Radio.channel(_.result(this, 'channelName'));
529 }
530
531 // add reference to the app, like old Marionette.Module
532 if(options.app){
533 this.app = options.app;
534 }
535
536 Mn.Object.apply(this, arguments);
537 },
538
539 start: function(){
540 this.triggerMethod('before:start');
541 this._isStarted = true;
542 this.triggerMethod('start');
543 },
544
545 stop: function(){
546 this.triggerMethod('before:stop');
547 this._isStarted = false;
548 this.triggerMethod('stop');
549 },
550
551 isStarted: function(){
552 return this._isStarted === true;
553 }
554
555});
556
557/***/ }),
558/* 13 */
559/***/ (function(module, exports, __webpack_require__) {
560
561var accounting = __webpack_require__(18);
562var _ = __webpack_require__(0);
563var Utils = {};
564
565/**
566 * Using the same function as Woo: /assets/js/admin/round.js
567 * PHP_ROUND_HALF_EVEN should be the default?!
568 * @param value
569 * @param precision
570 * @param mode
571 * @returns {number}
572 */
573/* jshint -W018, -W071, -W074 */
574Utils.round = function(value, precision, mode) {
575 // http://kevin.vanzonneveld.net
576 // + original by: Philip Peterson
577 // + revised by: Onno Marsman
578 // + input by: Greenseed
579 // + revised by: T.Wild
580 // + input by: meo
581 // + input by: William
582 // + bugfixed by: Brett Zamir (http://brett-zamir.me)
583 // + input by: Josep Sanz (http://www.ws3.es/)
584 // + revised by: Rafał Kukawski (http://blog.kukawski.pl/)
585 // % note 1: Great work. Ideas for improvement:
586 // % note 1: - code more compliant with developer guidelines
587 // % note 1: - for implementing PHP constant arguments look at
588 // % note 1: the pathinfo() function, it offers the greatest
589 // % note 1: flexibility & compatibility possible
590 // * example 1: round(1241757, -3);
591 // * returns 1: 1242000
592 // * example 2: round(3.6);
593 // * returns 2: 4
594 // * example 3: round(2.835, 2);
595 // * returns 3: 2.84
596 // * example 4: round(1.1749999999999, 2);
597 // * returns 4: 1.17
598 // * example 5: round(58551.799999999996, 2);
599 // * returns 5: 58551.8
600
601 //
602 //mode = mode || 'PHP_ROUND_HALF_EVEN';
603
604 if( !_.isFinite( parseInt(precision, 10) ) ) {
605 precision = accounting.settings.currency.precision;
606 }
607
608 var m, f, isHalf, sgn; // helper variables
609 //precision |= 0; // making sure precision is integer
610 m = Math.pow(10, precision);
611 value *= m;
612 sgn = (value > 0) | -(value < 0); // sign of the number
613 isHalf = value % 1 === 0.5 * sgn;
614 f = Math.floor(value);
615
616 if (isHalf) {
617 switch (mode) {
618 case '2':
619 case 'PHP_ROUND_HALF_DOWN':
620 value = f + (sgn < 0); // rounds .5 toward zero
621 break;
622 case '3':
623 case 'PHP_ROUND_HALF_EVEN':
624 value = f + (f % 2 * sgn); // rouds .5 towards the next even integer
625 break;
626 case '4':
627 case 'PHP_ROUND_HALF_ODD':
628 value = f + !(f % 2); // rounds .5 towards the next odd integer
629 break;
630 default:
631 value = f + (sgn > 0); // rounds .5 away from zero
632 }
633 }
634
635 return (isHalf ? value : Math.round(value)) / m;
636};
637/* jshint +W018, +W071, +W074 */
638
639/**
640 * Number of significant decimal places
641 */
642Utils.decimalPlaces = function(num){
643 return ((+num).toFixed(4)).replace(/^-?\d*\.?|0+$/g, '').length;
644};
645
646/**
647 *
648 */
649Utils.unformat = function( num ) {
650 return accounting.unformat( num, accounting.settings.number.decimal );
651};
652
653/**
654 *
655 */
656Utils.formatNumber = function( num, precision ) {
657 if( precision === 'auto' ) {
658 precision = Utils.decimalPlaces(num);
659 }
660 if( !_.isFinite( parseInt(precision, 10) ) ) {
661 precision = accounting.settings.currency.precision;
662 }
663 return accounting.formatNumber(num, precision);
664};
665
666/**
667 *
668 */
669Utils.formatMoney = function( num, precision ) {
670 if( precision === 'auto' ) {
671 precision = Utils.decimalPlaces(num);
672 }
673 if( !_.isFinite( parseInt(precision, 10) ) ) {
674 precision = accounting.settings.currency.precision;
675 }
676 // round the number to even
677 num = Utils.round(num, precision);
678 return accounting.formatMoney(num);
679};
680
681/**
682 *
683 */
684Utils.isPositiveInteger = function( num, allowZero ){
685 var n = ~~Number(num);
686 if(allowZero) {
687 return String(n) === num && n >= 0;
688 } else {
689 return String(n) === num && n > 0;
690 }
691};
692
693/**
694 * Parse error messages from the server
695 */
696Utils.parseErrorResponse = function( jqXHR ){
697 var resp = jqXHR.responseJSON;
698 if( resp.errors ){
699 return resp.errors[0].message;
700 }
701
702 return jqXHR.responseText;
703};
704
705/**
706 * returns the variable type
707 * http://wp.me/pQpop-JM
708 *
709 *
710toType({a: 4}); //"object"
711toType([1, 2, 3]); //"array"
712(function() {console.log(toType(arguments))})(); //arguments
713toType(new ReferenceError); //"error"
714toType(new Date); //"date"
715toType(/a-z/); //"regexp"
716toType(Math); //"math"
717toType(JSON); //"json"
718toType(new Number(4)); //"number"
719toType(new String("abc")); //"string"
720toType(new Boolean(true)); //"boolean"
721
722 */
723Utils.toType = function(obj) {
724 return ({}).toString.call(obj).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
725};
726
727module.exports = Utils;
728
729/***/ }),
730/* 14 */
731/***/ (function(module, exports, __webpack_require__) {
732
733var bb = __webpack_require__(4);
734var app = __webpack_require__(1);
735
736module.exports = app.prototype.Collection = bb.Collection.extend({
737 constructor: function() {
738 bb.Collection.apply(this, arguments);
739 this._isNew = true;
740 this.once('sync', function() {
741 this._isNew = false;
742 });
743 },
744
745 isNew: function() {
746 return this._isNew;
747 },
748
749 parse: function (resp){
750 return resp && resp[this.name] ? resp[this.name] : resp ;
751 },
752
753 sync: function(){
754 return bb.sync.apply(this, arguments);
755 }
756
757});
758
759/***/ }),
760/* 15 */
761/***/ (function(module, exports, __webpack_require__) {
762
763var Mn = __webpack_require__(9);
764var app = __webpack_require__(1);
765
766module.exports = app.prototype.Behavior = Mn.Behavior;
767
768/***/ }),
769/* 16 */
770/***/ (function(module, exports, __webpack_require__) {
771
772var bb = __webpack_require__(4);
773var app = __webpack_require__(1);
774var _ = __webpack_require__(0);
775//var Radio = require('backbone.radio');
776
777// parsing functions
778var parse = {
779 'float': parseFloat,
780 'int': parseInt,
781 'number': function(num){
782 num = Number(num);
783 return _.isNaN(num) ? 0 : num;
784 }
785};
786
787module.exports = app.prototype.Model = bb.Model.extend({
788
789 parse: function (resp){
790 var data = resp && resp[this.name] ? resp[this.name] : resp;
791 if( ! data ){
792 return;
793 }
794
795 // check data type
796 _.each( this.schema, function( val, attr ) {
797
798 // if attribute exists
799 if( ! _.has( data, attr ) ){
800 return;
801 }
802
803 // string, eg: 'float'
804 if( _.isString(val) && parse[val] ){
805 data[attr] = parse[val]( data[attr] );
806 }
807
808 }, this);
809
810 return data;
811 }
812
813});
814
815/***/ }),
816/* 17 */
817/***/ (function(module, exports, __webpack_require__) {
818
819var ItemView = __webpack_require__(5);
820var bb = __webpack_require__(4);
821var app = __webpack_require__(1);
822__webpack_require__(109);
823__webpack_require__(110);
824__webpack_require__(111);
825
826module.exports = app.prototype.FormView = ItemView.extend({
827
828 constructor: function() {
829 return ItemView.prototype.constructor.apply(this, arguments);
830 },
831
832 bindings: {},
833
834 render: function(){
835 // Invoke original render function
836 var args = Array.prototype.slice.apply(arguments);
837 var result = ItemView.prototype.render.apply(this, args);
838
839 // Apply validation
840 bb.Validation.bind(this, {
841 model: this.model,
842 valid: function(view, attr) {
843 view
844 .$('input[name="' + attr + '"]')
845 .removeClass('form-control-error')
846 .parent()
847 .removeClass('has-error');
848 },
849 invalid: function(view, attr) {
850 view
851 .$('input[name="' + attr + '"]')
852 .addClass('form-control-error')
853 .parent()
854 .addClass('has-error');
855 }
856 });
857
858 // Apply stickit
859 this.stickit();
860
861 // Return render result
862 return result;
863 },
864
865 remove: function() {
866 // Remove the validation binding
867 bb.Validation.unbind(this);
868 return ItemView.prototype.remove.apply(this, arguments);
869 }
870
871});
872
873/***/ }),
874/* 18 */
875/***/ (function(module, exports) {
876
877module.exports = accounting;
878
879/***/ }),
880/* 19 */
881/***/ (function(module, exports, __webpack_require__) {
882
883
884var _ = __webpack_require__(0);
885var Backbone = __webpack_require__(4);
886
887// Methods in the collection prototype that we won't expose
888var blacklistedMethods = [
889 "_onModelEvent", "_prepareModel", "_removeReference", "_reset", "add",
890 "initialize", "sync", "remove", "reset", "set", "push", "pop", "unshift",
891 "shift", "sort", "parse", "fetch", "create", "model", "off", "on",
892 "listenTo", "listenToOnce", "bind", "trigger", "once", "stopListening"
893];
894
895var eventWhiteList = [
896 'add', 'remove', 'reset', 'sort', 'destroy', 'sync', 'request', 'error'
897];
898
899function proxyCollection(from, target) {
900
901 function updateLength() {
902 target.length = from.length;
903 }
904
905 function pipeEvents(eventName) {
906 var args = _.toArray(arguments);
907 var isChangeEvent = eventName === 'change' ||
908 eventName.slice(0, 7) === 'change:';
909
910 // In the case of a `reset` event, the Collection.models reference
911 // is updated to a new array, so we need to update our reference.
912 if (eventName === 'reset') {
913 target.models = from.models;
914 }
915
916 if (_.contains(eventWhiteList, eventName)) {
917 if (_.contains(['add', 'remove', 'destroy'], eventName)) {
918 args[2] = target;
919 } else if (_.contains(['reset', 'sort'], eventName)) {
920 args[1] = target;
921 }
922 target.trigger.apply(this, args);
923 } else if (isChangeEvent) {
924 // In some cases I was seeing change events fired after the model
925 // had already been removed from the collection.
926 if (target.contains(args[1])) {
927 target.trigger.apply(this, args);
928 }
929 }
930 }
931
932 var methods = {};
933
934 _.each(_.functions(Backbone.Collection.prototype), function(method) {
935 if (!_.contains(blacklistedMethods, method)) {
936 methods[method] = function() {
937 return from[method].apply(from, arguments);
938 };
939 }
940 });
941
942 _.extend(target, Backbone.Events, methods);
943
944 target.listenTo(from, 'all', updateLength);
945 target.listenTo(from, 'all', pipeEvents);
946 target.models = from.models;
947
948 updateLength();
949 return target;
950}
951
952module.exports = proxyCollection;
953
954
955
956/***/ }),
957/* 20 */
958/***/ (function(module, exports, __webpack_require__) {
959
960"use strict";
961
962
963var implementation = __webpack_require__(45);
964
965module.exports = Function.prototype.bind || implementation;
966
967
968/***/ }),
969/* 21 */
970/***/ (function(module, exports, __webpack_require__) {
971
972/**
973 * Dual Collection makes sure the data locally and the data on the server
974 * stay in sync.
975 */
976
977var Backbone = __webpack_require__(4);
978var Radio = Backbone.Radio;
979var debug = __webpack_require__(8)('dualCollection');
980var IDBCollection = __webpack_require__(34);
981var app = __webpack_require__(1);
982var _ = __webpack_require__(0);
983var $ = __webpack_require__(3);
984var moment = __webpack_require__(35);
985
986module.exports = app.prototype.DualCollection = IDBCollection.extend({
987 keyPath: 'local_id',
988 mergeKeyPath: 'id',
989 _syncDelayed: true,
990
991 /**
992 * Items for download will be placed in queue
993 * Delay is the pause between the next items in queue
994 */
995 queue: [],
996 delay: 500, // server breathing spacing, can also be set via radio
997
998 url: function(){
999 var wc_api = Radio.request('entities', 'get', {
1000 type: 'option',
1001 name: 'wc_api'
1002 });
1003 return wc_api + this.name;
1004 },
1005
1006 state: {
1007 pageSize: 10
1008 },
1009
1010 /**
1011 *
1012 */
1013 fetch: function(options){
1014 options = options || {};
1015 if(options.remote){
1016 return this.remoteFetch(options);
1017 }
1018 return IDBCollection.prototype.fetch.call(this, options);
1019 },
1020
1021 /**
1022 *
1023 */
1024 remoteFetch: function(options){
1025 var self = this;
1026 return this.sync('read', this, options)
1027 .then(function(resp){
1028 var models = self.parse(resp);
1029 return IDBCollection.prototype.merge.call(self, models);
1030 })
1031 .then(function(models){
1032 var ids = _.map(models, function(model){
1033 return model.get('id');
1034 });
1035 self.dequeue(ids);
1036 });
1037 },
1038
1039 /**
1040 * Full sync
1041 * - Get any updated records
1042 * - Audit using full list of remote ids vs local
1043 * - Upload any local changes
1044 */
1045 fullSync: function(){
1046 var self = this;
1047
1048 if(this._syncing){
1049 debug('sync already in progress');
1050 return;
1051 }
1052
1053 this._syncing = true;
1054 debug('fullSync started');
1055 this.trigger('start:fullSync');
1056
1057 return this.fetchUpdated()
1058 .then(function(){
1059 return self.auditRecords();
1060 })
1061 .then(function(){
1062 if(self._syncDelayed){
1063 return self.syncDelayed();
1064 }
1065 })
1066 .done(function(){ debug('fullSync complete'); })
1067 .fail(function(err){ debug('fullSync failed', err); })
1068 .always(function(){
1069 self._syncing = false;
1070 self.trigger('end:fullSync');
1071 });
1072
1073 },
1074
1075 /**
1076 * Fetch updated
1077 * - if collection is empty, fetch the first page
1078 * - else, get the latest updated_at from local collection
1079 * - check server for any new updates
1080 */
1081 fetchUpdated: function(){
1082 var self = this;
1083
1084 // no local records, possibly first fetch
1085 if(this.length === 0){
1086 return this.fetch({ remote: true });
1087 }
1088
1089 //var last_update = this.formatDate( this.getState('last_update') );
1090 var last_update = _.compact( this.pluck('updated_at') ).sort().pop();
1091
1092 //
1093 return this.getRemoteIds(last_update)
1094 .then(function(ids){
1095 self.enqueue(ids);
1096 return self.processQueue({
1097 queue: ids,
1098 all : true
1099 });
1100 });
1101
1102 },
1103
1104 /**
1105 * get delayed models and remote create/update
1106 */
1107 syncDelayed: function(){
1108 var models = this.getDelayedModels();
1109 var sync = _.map(models, function(model){
1110 return model.remoteSync(null, model);
1111 });
1112 return $.when.apply(this, sync);
1113 },
1114
1115 /**
1116 * returns array of all delayed records
1117 */
1118 getDelayedModels: function() {
1119 return this.filter(function(model){
1120 return model.isDelayed();
1121 });
1122 },
1123
1124 /**
1125 * Audit records
1126 * - get full list of remote ids
1127 * - compare to local ids
1128 * - queue records for remote fetch
1129 * - remove any garbage records
1130 */
1131 auditRecords: function(){
1132 var local = this.pluck('id'),
1133 self = this;
1134
1135 return this.getRemoteIds()
1136 .then(function(remote){
1137 var add = _.chain(remote).difference(local).compact().value(),
1138 remove = _.chain(local).difference(remote).compact().value();
1139 self.enqueue(add);
1140 self.dequeue(remove);
1141 return self.removeGarbage(remove);
1142 })
1143 .done(function(){ debug('audit complete'); })
1144 .fail(function(err){ debug('audit failed', err); });
1145
1146 },
1147
1148 /**
1149 * Get array of all entity ids from the server
1150 * - optionally get ids modified since last_update
1151 * - uses ajax for performance
1152 */
1153 getRemoteIds: function(last_update){
1154 var ajaxurl = Radio.request('entities', 'get', {
1155 type: 'option',
1156 name: 'ajaxurl'
1157 });
1158
1159 if(last_update){
1160 debug('getting updated ids from server since ' + last_update);
1161 } else {
1162 debug('getting all ids from server');
1163 }
1164
1165 return $.getJSON( ajaxurl, {
1166 action : 'wc_pos_get_all_ids',
1167 type : this.name,
1168 updated_at_min: last_update
1169 });
1170 },
1171
1172 /**
1173 * Remove garbage records, ie: records deleted on server
1174 */
1175 removeGarbage: function(ids){
1176 var models = this.getModelsByRemoteIds(ids);
1177
1178 if(models.length === 0){
1179 return;
1180 }
1181
1182 this.remove(models);
1183 return this.db.removeBatch(_.pluck(models, 'id'));
1184 },
1185
1186 /**
1187 * Turn array of remoteIds into array of models
1188 * idAttribute = 'local_id'
1189 * remoteIdAttribute = 'id
1190 */
1191 getModelsByRemoteIds: function(ids){
1192 return this.filter(function(model){
1193 return _(ids).contains(model.get('id'));
1194 });
1195 },
1196
1197 /**
1198 * Add ids to queue for potential download
1199 */
1200 enqueue: function(ids){
1201 if(!_.isArray(ids)){
1202 return this.queue.push(ids);
1203 }
1204 this.queue = _.union(this.queue, ids);
1205 },
1206
1207 /**
1208 * Remove ids from queue
1209 */
1210 dequeue: function(ids){
1211 if(!_.isArray(ids)){
1212 this.queue = _.without(this.queue, ids);
1213 } else {
1214 this.queue = _.difference(this.queue, ids);
1215 }
1216 },
1217
1218 /**
1219 *
1220 */
1221 hasAllRecords: function(){
1222 return (this.queue.length === 0);
1223 },
1224
1225 /**
1226 * Process queue
1227 * - take slice of ids from queue and remote fetch
1228 * - optionally keep processing queue until empty
1229 */
1230 /* jshint -W071, -W074 */
1231 processQueue: function(options){
1232 options = options || {};
1233 var queue = options.queue || _.clone(this.queue);
1234 if(queue.length === 0 || this._processingQueue){
1235 return;
1236 }
1237 this._processingQueue = true;
1238 this.trigger('start:processQueue');
1239
1240 var self = this,
1241 deferred = new $.Deferred(),
1242 ids = queue.splice(0, this.state.pageSize).join(',');
1243
1244 this.fetch({
1245 remote: true,
1246 data: {
1247 filter: options.filter || {
1248 limit: -1,
1249 'in': ids
1250 }
1251 }
1252 })
1253 .done(function(){
1254 if(!options.all || queue.length === 0){
1255 deferred.resolve();
1256 } else {
1257 deferred.progress(ids);
1258 _.delay(self.processQueue.bind(self), self.getDelay(), options);
1259 }
1260 })
1261 .fail(deferred.reject)
1262 .always(function(){
1263 self._processingQueue = false;
1264 self.trigger('end:processQueue');
1265 });
1266
1267 return deferred.promise();
1268 },
1269 /* jshint +W071, +W074 */
1270
1271 /**
1272 * Allows delay to be added between process queue
1273 * - may be necessary to ease server load
1274 */
1275 getDelay: function(){
1276 return Radio.request('entities', 'get', {
1277 type: 'option',
1278 name: 'delay'
1279 }) || this.delay;
1280 },
1281
1282 /**
1283 * Clears the IDB storage and resets the collection
1284 */
1285 clear: function(){
1286 if(!this.db){
1287 return;
1288 }
1289
1290 var self = this;
1291 return IDBCollection.prototype.clear.call(this)
1292 .then(function(){
1293 self.queue = [];
1294 });
1295 },
1296
1297 /*
1298 * Helper function to format Date.now() to RFC3339
1299 * - returns 2015-03-11T02:30:43.925Z (with milliseconds)
1300 * - undefined if no timestamp
1301 */
1302 formatDate: function(timestamp) {
1303 if(timestamp){
1304 //return moment(timestamp).utc().format('YYYY-MM-DDTHH:mm:ss') + 'Z';
1305 return moment(timestamp).toISOString();
1306 }
1307 }
1308
1309});
1310
1311/***/ }),
1312/* 22 */
1313/***/ (function(module, exports, __webpack_require__) {
1314
1315var DeepModel = __webpack_require__(23);
1316var app = __webpack_require__(1);
1317var _ = __webpack_require__(0);
1318var debug = __webpack_require__(8)('dualModel');
1319
1320module.exports = app.prototype.DualModel = DeepModel.extend({
1321 idAttribute: 'local_id',
1322 remoteIdAttribute: 'id',
1323 fields: ['title'],
1324
1325 validate: function(attrs){
1326 var obj = {};
1327 if(attrs[this.idAttribute]) {
1328 obj[this.idAttribute] = parseInt(attrs[this.idAttribute], 10);
1329 }
1330 if(attrs[this.remoteIdAttribute]){
1331 obj[this.remoteIdAttribute] = parseInt(attrs[this.remoteIdAttribute], 10);
1332 }
1333 this.set(obj, {silent: true});
1334 },
1335
1336 url: function(){
1337 var remoteId = this.get(this.remoteIdAttribute),
1338 urlRoot = _.result(this.collection, 'url');
1339
1340 if(remoteId){
1341 return '' + urlRoot + '/' + remoteId + '/';
1342 }
1343 return urlRoot;
1344 },
1345
1346 // delayed states
1347 states: {
1348 //'patch' : 'UPDATE_FAILED',
1349 'update' : 'UPDATE_FAILED',
1350 'create' : 'CREATE_FAILED',
1351 'delete' : 'DELETE_FAILED'
1352 },
1353
1354 hasRemoteId: function() {
1355 return !!this.get(this.remoteIdAttribute);
1356 },
1357
1358 isDelayed: function() {
1359 var status = this.get('status');
1360 return status === this.states['update'] ||
1361 status === this.states['create'] ||
1362 status === this.states['delete'];
1363 },
1364
1365 /**
1366 * - sync to idb with correct status
1367 * - if remote, sync to remote
1368 */
1369 sync: function(method, model, options){
1370 options = options || {};
1371 var opts = _.clone(options);
1372 opts.remote = undefined;
1373 var m = method === 'patch' ? 'update' : method;
1374
1375 this.setStatus(m);
1376
1377 return DeepModel.prototype.sync.call(this, m, model, opts)
1378 .then(function(){
1379 if(options.remote){
1380 return model.remoteSync(method, model, options);
1381 }
1382 });
1383 },
1384
1385 remoteSync: function(method, model, options){
1386 model = model || this;
1387 options = options || {};
1388 options.remote = true;
1389 method = method || model.getMethod();
1390
1391 return DeepModel.prototype.sync.call(this, method, model, options)
1392 .then(function(resp){
1393 if(resp){
1394 var data = model.parse(resp);
1395 return model.merge(data);
1396 }
1397 });
1398 },
1399
1400 setStatus: function(method){
1401 if(this.states[method]){
1402 if(method === 'update' && !this.hasRemoteId()){
1403 method = 'create';
1404 }
1405 this.set({ status: this.states[method] });
1406 }
1407 },
1408
1409 getMethod: function(){
1410 var status = this.get('status');
1411 var remoteMethod = _.findKey(this.states, function(state) {
1412 return state === status;
1413 });
1414 if(remoteMethod){
1415 return remoteMethod;
1416 } else {
1417 debug('No method given for remote sync');
1418 }
1419 },
1420
1421 merge: function(resp){
1422 // todo: merge
1423 // - merge should take bb & json?
1424 this.set(resp);
1425 if(this.isDelayed()){
1426 this.unset('status');
1427 }
1428 if(this.collection && this.collection.db){
1429 return this.collection.merge( this.toJSON() );
1430 }
1431 }
1432
1433});
1434
1435/***/ }),
1436/* 23 */
1437/***/ (function(module, exports, __webpack_require__) {
1438
1439var app = __webpack_require__(1);
1440var Model = __webpack_require__(16);
1441var DeepModel = __webpack_require__(65);
1442
1443module.exports = app.prototype.DeepModel = Model.extend(DeepModel);
1444
1445/***/ }),
1446/* 24 */
1447/***/ (function(module, exports, __webpack_require__) {
1448
1449var Behavior = __webpack_require__(15);
1450var App = __webpack_require__(1);
1451var _ = __webpack_require__(0);
1452var $ = __webpack_require__(3);
1453var Drop = __webpack_require__(38);
1454var App = __webpack_require__(1);
1455var namespace = App.prototype.namespace('tooltip');
1456
1457var Drop_ = Drop.createContext({
1458 classPrefix: namespace
1459});
1460
1461var defaults = {
1462 position: 'top center',
1463 openOn: 'hover',
1464 classes: namespace + '-theme-arrows',
1465 constrainToWindow: true,
1466 constrainToScrollParent: false,
1467 remove: true
1468};
1469
1470var TooltipBehavior = Behavior.extend({
1471
1472 _initialized: [],
1473
1474 initialize: function(options){
1475 this.options = _.extend({}, defaults, options);
1476
1477 // define ui
1478 this.ui = {
1479 tooltip: '*[data-toggle="' + namespace + '"]'
1480 };
1481 },
1482
1483 events: {
1484 'mouseenter @ui.tooltip': 'onHover'
1485 },
1486
1487 onHover: function(e){
1488 if(this._initialized.indexOf(e.target) !== -1) {
1489 return;
1490 }
1491
1492 // drop instance
1493 var options = _.extend({}, this.options, {
1494 target : e.target,
1495 content : $(e.target).attr('title')
1496 });
1497 var drop = new Drop_(options);
1498 this._initialized.push(e.target);
1499
1500 // remove the title attribute to prevent browser hover
1501 $(e.target).removeAttr('title');
1502
1503 drop.open();
1504 }
1505
1506});
1507
1508module.exports = TooltipBehavior;
1509App.prototype.set('Behaviors.Tooltip', TooltipBehavior);
1510
1511/***/ }),
1512/* 25 */
1513/***/ (function(module, exports, __webpack_require__) {
1514
1515var Mn = __webpack_require__(9);
1516var app = __webpack_require__(1);
1517
1518module.exports = app.prototype.CollectionView = Mn.CollectionView.extend({
1519 //// Marionette's default implementation ignores the index, always
1520 //// appending the new view to the end. Let's be a little more clever.
1521 //appendHtml: function(collectionView, itemView, index){
1522 // if (!index) {
1523 // collectionView.$el.prepend(itemView.el);
1524 // } else {
1525 // $(collectionView.$('li')[index - 1]).after(itemView.el);
1526 // }
1527 //}
1528});
1529
1530/***/ }),
1531/* 26 */
1532/***/ (function(module, exports, __webpack_require__) {
1533
1534var ItemView = __webpack_require__(5);
1535var hbs = __webpack_require__(7);
1536var _ = __webpack_require__(0);
1537var tmpl = __webpack_require__(107);
1538var polyglot = __webpack_require__(6);
1539var ButtonsBehavior = __webpack_require__(108);
1540
1541module.exports = ItemView.extend({
1542
1543 viewOptions: ['buttons'],
1544
1545 buttons: [{
1546 action: 'save',
1547 className: 'btn-primary'
1548 }],
1549
1550 template: hbs.compile(tmpl),
1551
1552 initialize: function(options){
1553 this.mergeOptions(options, this.viewOptions);
1554 },
1555
1556 templateHelpers: function(){
1557 _.each(this.buttons, function(button){
1558 var type = button.type || 'button';
1559 button[type] = true;
1560 button.label = button.label || polyglot.t('buttons.' + button.action);
1561 });
1562 return {
1563 buttons: this.buttons
1564 };
1565 },
1566
1567 behaviors: {
1568 Buttons: {
1569 behaviorClass: ButtonsBehavior
1570 }
1571 }
1572
1573});
1574
1575/***/ }),
1576/* 27 */
1577/***/ (function(module, exports) {
1578
1579// shim for using process in browser
1580var process = module.exports = {};
1581
1582// cached from whatever global is present so that test runners that stub it
1583// don't break things. But we need to wrap it in a try catch in case it is
1584// wrapped in strict mode code which doesn't define any globals. It's inside a
1585// function because try/catches deoptimize in certain engines.
1586
1587var cachedSetTimeout;
1588var cachedClearTimeout;
1589
1590function defaultSetTimout() {
1591 throw new Error('setTimeout has not been defined');
1592}
1593function defaultClearTimeout () {
1594 throw new Error('clearTimeout has not been defined');
1595}
1596(function () {
1597 try {
1598 if (typeof setTimeout === 'function') {
1599 cachedSetTimeout = setTimeout;
1600 } else {
1601 cachedSetTimeout = defaultSetTimout;
1602 }
1603 } catch (e) {
1604 cachedSetTimeout = defaultSetTimout;
1605 }
1606 try {
1607 if (typeof clearTimeout === 'function') {
1608 cachedClearTimeout = clearTimeout;
1609 } else {
1610 cachedClearTimeout = defaultClearTimeout;
1611 }
1612 } catch (e) {
1613 cachedClearTimeout = defaultClearTimeout;
1614 }
1615} ())
1616function runTimeout(fun) {
1617 if (cachedSetTimeout === setTimeout) {
1618 //normal enviroments in sane situations
1619 return setTimeout(fun, 0);
1620 }
1621 // if setTimeout wasn't available but was latter defined
1622 if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
1623 cachedSetTimeout = setTimeout;
1624 return setTimeout(fun, 0);
1625 }
1626 try {
1627 // when when somebody has screwed with setTimeout but no I.E. maddness
1628 return cachedSetTimeout(fun, 0);
1629 } catch(e){
1630 try {
1631 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
1632 return cachedSetTimeout.call(null, fun, 0);
1633 } catch(e){
1634 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
1635 return cachedSetTimeout.call(this, fun, 0);
1636 }
1637 }
1638
1639
1640}
1641function runClearTimeout(marker) {
1642 if (cachedClearTimeout === clearTimeout) {
1643 //normal enviroments in sane situations
1644 return clearTimeout(marker);
1645 }
1646 // if clearTimeout wasn't available but was latter defined
1647 if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
1648 cachedClearTimeout = clearTimeout;
1649 return clearTimeout(marker);
1650 }
1651 try {
1652 // when when somebody has screwed with setTimeout but no I.E. maddness
1653 return cachedClearTimeout(marker);
1654 } catch (e){
1655 try {
1656 // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
1657 return cachedClearTimeout.call(null, marker);
1658 } catch (e){
1659 // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
1660 // Some versions of I.E. have different rules for clearTimeout vs setTimeout
1661 return cachedClearTimeout.call(this, marker);
1662 }
1663 }
1664
1665
1666
1667}
1668var queue = [];
1669var draining = false;
1670var currentQueue;
1671var queueIndex = -1;
1672
1673function cleanUpNextTick() {
1674 if (!draining || !currentQueue) {
1675 return;
1676 }
1677 draining = false;
1678 if (currentQueue.length) {
1679 queue = currentQueue.concat(queue);
1680 } else {
1681 queueIndex = -1;
1682 }
1683 if (queue.length) {
1684 drainQueue();
1685 }
1686}
1687
1688function drainQueue() {
1689 if (draining) {
1690 return;
1691 }
1692 var timeout = runTimeout(cleanUpNextTick);
1693 draining = true;
1694
1695 var len = queue.length;
1696 while(len) {
1697 currentQueue = queue;
1698 queue = [];
1699 while (++queueIndex < len) {
1700 if (currentQueue) {
1701 currentQueue[queueIndex].run();
1702 }
1703 }
1704 queueIndex = -1;
1705 len = queue.length;
1706 }
1707 currentQueue = null;
1708 draining = false;
1709 runClearTimeout(timeout);
1710}
1711
1712process.nextTick = function (fun) {
1713 var args = new Array(arguments.length - 1);
1714 if (arguments.length > 1) {
1715 for (var i = 1; i < arguments.length; i++) {
1716 args[i - 1] = arguments[i];
1717 }
1718 }
1719 queue.push(new Item(fun, args));
1720 if (queue.length === 1 && !draining) {
1721 runTimeout(drainQueue);
1722 }
1723};
1724
1725// v8 likes predictible objects
1726function Item(fun, array) {
1727 this.fun = fun;
1728 this.array = array;
1729}
1730Item.prototype.run = function () {
1731 this.fun.apply(null, this.array);
1732};
1733process.title = 'browser';
1734process.browser = true;
1735process.env = {};
1736process.argv = [];
1737process.version = ''; // empty string to avoid regexp issues
1738process.versions = {};
1739
1740function noop() {}
1741
1742process.on = noop;
1743process.addListener = noop;
1744process.once = noop;
1745process.off = noop;
1746process.removeListener = noop;
1747process.removeAllListeners = noop;
1748process.emit = noop;
1749process.prependListener = noop;
1750process.prependOnceListener = noop;
1751
1752process.listeners = function (name) { return [] }
1753
1754process.binding = function (name) {
1755 throw new Error('process.binding is not supported');
1756};
1757
1758process.cwd = function () { return '/' };
1759process.chdir = function (dir) {
1760 throw new Error('process.chdir is not supported');
1761};
1762process.umask = function() { return 0; };
1763
1764
1765/***/ }),
1766/* 28 */
1767/***/ (function(module, exports, __webpack_require__) {
1768
1769var bind = __webpack_require__(20);
1770
1771module.exports = bind.call(Function.call, Object.prototype.hasOwnProperty);
1772
1773
1774/***/ }),
1775/* 29 */
1776/***/ (function(module, exports, __webpack_require__) {
1777
1778"use strict";
1779
1780
1781var keys = __webpack_require__(47);
1782var foreach = __webpack_require__(49);
1783var hasSymbols = typeof Symbol === 'function' && typeof Symbol() === 'symbol';
1784
1785var toStr = Object.prototype.toString;
1786
1787var isFunction = function (fn) {
1788 return typeof fn === 'function' && toStr.call(fn) === '[object Function]';
1789};
1790
1791var arePropertyDescriptorsSupported = function () {
1792 var obj = {};
1793 try {
1794 Object.defineProperty(obj, 'x', { enumerable: false, value: obj });
1795 /* eslint-disable no-unused-vars, no-restricted-syntax */
1796 for (var _ in obj) { return false; }
1797 /* eslint-enable no-unused-vars, no-restricted-syntax */
1798 return obj.x === obj;
1799 } catch (e) { /* this is IE 8. */
1800 return false;
1801 }
1802};
1803var supportsDescriptors = Object.defineProperty && arePropertyDescriptorsSupported();
1804
1805var defineProperty = function (object, name, value, predicate) {
1806 if (name in object && (!isFunction(predicate) || !predicate())) {
1807 return;
1808 }
1809 if (supportsDescriptors) {
1810 Object.defineProperty(object, name, {
1811 configurable: true,
1812 enumerable: false,
1813 value: value,
1814 writable: true
1815 });
1816 } else {
1817 object[name] = value;
1818 }
1819};
1820
1821var defineProperties = function (object, map) {
1822 var predicates = arguments.length > 2 ? arguments[2] : {};
1823 var props = keys(map);
1824 if (hasSymbols) {
1825 props = props.concat(Object.getOwnPropertySymbols(map));
1826 }
1827 foreach(props, function (name) {
1828 defineProperty(object, name, map[name], predicates[name]);
1829 });
1830};
1831
1832defineProperties.supportsDescriptors = !!supportsDescriptors;
1833
1834module.exports = defineProperties;
1835
1836
1837/***/ }),
1838/* 30 */
1839/***/ (function(module, exports, __webpack_require__) {
1840
1841"use strict";
1842
1843
1844var bind = __webpack_require__(20);
1845var ES = __webpack_require__(50);
1846var replace = bind.call(Function.call, String.prototype.replace);
1847
1848var leftWhitespace = /^[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+/;
1849var rightWhitespace = /[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]+$/;
1850
1851module.exports = function trim() {
1852 var S = ES.ToString(ES.CheckObjectCoercible(this));
1853 return replace(replace(S, leftWhitespace, ''), rightWhitespace, '');
1854};
1855
1856
1857/***/ }),
1858/* 31 */
1859/***/ (function(module, exports, __webpack_require__) {
1860
1861"use strict";
1862
1863
1864var fnToStr = Function.prototype.toString;
1865
1866var constructorRegex = /^\s*class /;
1867var isES6ClassFn = function isES6ClassFn(value) {
1868 try {
1869 var fnStr = fnToStr.call(value);
1870 var singleStripped = fnStr.replace(/\/\/.*\n/g, '');
1871 var multiStripped = singleStripped.replace(/\/\*[.\s\S]*\*\//g, '');
1872 var spaceStripped = multiStripped.replace(/\n/mg, ' ').replace(/ {2}/g, ' ');
1873 return constructorRegex.test(spaceStripped);
1874 } catch (e) {
1875 return false; // not a function
1876 }
1877};
1878
1879var tryFunctionObject = function tryFunctionObject(value) {
1880 try {
1881 if (isES6ClassFn(value)) { return false; }
1882 fnToStr.call(value);
1883 return true;
1884 } catch (e) {
1885 return false;
1886 }
1887};
1888var toStr = Object.prototype.toString;
1889var fnClass = '[object Function]';
1890var genClass = '[object GeneratorFunction]';
1891var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
1892
1893module.exports = function isCallable(value) {
1894 if (!value) { return false; }
1895 if (typeof value !== 'function' && typeof value !== 'object') { return false; }
1896 if (hasToStringTag) { return tryFunctionObject(value); }
1897 if (isES6ClassFn(value)) { return false; }
1898 var strClass = toStr.call(value);
1899 return strClass === fnClass || strClass === genClass;
1900};
1901
1902
1903/***/ }),
1904/* 32 */
1905/***/ (function(module, exports, __webpack_require__) {
1906
1907"use strict";
1908
1909
1910var implementation = __webpack_require__(30);
1911
1912var zeroWidthSpace = '\u200b';
1913
1914module.exports = function getPolyfill() {
1915 if (String.prototype.trim && zeroWidthSpace.trim() === zeroWidthSpace) {
1916 return String.prototype.trim;
1917 }
1918 return implementation;
1919};
1920
1921
1922/***/ }),
1923/* 33 */
1924/***/ (function(module, exports) {
1925
1926var g;
1927
1928// This works in non-strict mode
1929g = (function() {
1930 return this;
1931})();
1932
1933try {
1934 // This works if eval is allowed (see CSP)
1935 g = g || Function("return this")() || (1,eval)("this");
1936} catch(e) {
1937 // This works if the window reference is available
1938 if(typeof window === "object")
1939 g = window;
1940}
1941
1942// g can still be undefined, but nothing to do about it...
1943// We return undefined, instead of nothing here, so it's
1944// easier to handle this case. if(!global) { ...}
1945
1946module.exports = g;
1947
1948
1949/***/ }),
1950/* 34 */
1951/***/ (function(module, exports, __webpack_require__) {
1952
1953/**
1954 * TODO: merge sync/idb.js & sync/idbsync.js?
1955 */
1956
1957var Collection = __webpack_require__(14);
1958//var debug = require('debug')('idbCollection');
1959var app = __webpack_require__(1);
1960var IndexedDB = __webpack_require__(62);
1961var Radio = __webpack_require__(2);
1962
1963module.exports = app.prototype.IndexedDBCollection = Collection.extend({
1964 name : 'store',
1965 storePrefix : 'wc_pos_',
1966 dbVersion : 4005,
1967 keyPath : 'local_id',
1968 autoIncrement : true,
1969 indexes : [
1970 {name: 'local_id', keyPath: 'local_id', unique: true},
1971 {name: 'id', keyPath: 'id', unique: true},
1972 {name: 'status', keyPath: 'status', unique: false}
1973 ],
1974
1975 constructor: function() {
1976 Collection.apply(this, arguments);
1977
1978 var options = {
1979 storeName : this.name,
1980 storePrefix : this.storePrefix,
1981 dbVersion : this.dbVersion,
1982 keyPath : this.keyPath,
1983 autoIncrement : this.autoIncrement,
1984 indexes : this.indexes,
1985 defaultErrorHandler : function(error){
1986 Radio.trigger('global', 'error', {
1987 status: error.target.error.name,
1988 message: error.target.error.message
1989 });
1990 }
1991 };
1992
1993 this.db = new IndexedDB(options, this);
1994 this.versionCheck();
1995 this.db.open()
1996 // error opening db
1997 .fail(function(error){
1998 Radio.trigger('global', 'error', {
1999 status : 'indexedDB error',
2000 message : error
2001 });
2002 });
2003 },
2004
2005 merge: function(models){
2006 var self = this;
2007 return this.db.merge(models)
2008 .then(function(){
2009 var models = Array.prototype.slice.apply(arguments);
2010 return self.add(models, {merge: true});
2011 });
2012 },
2013
2014 /**
2015 * Clears the IDB storage and resets the collection
2016 */
2017 clear: function(){
2018 if(!this.db){
2019 return;
2020 }
2021
2022 var self = this;
2023 return this.db.open()
2024 .then(function(){
2025 self.reset();
2026 return self.db.clear();
2027 });
2028 },
2029
2030 /**
2031 * Each website will have a unique idbVersion number
2032 * the version number is incremented on plugin update and some user actions
2033 * this version check will compare the version numbers
2034 * idb is flushed on version change
2035 */
2036 versionCheck: function(){
2037 var name = this.name;
2038
2039 var newVersion = parseInt( Radio.request('entities', 'get', {
2040 type: 'option',
2041 name: 'idbVersion'
2042 }), 10 ) || 0;
2043 var oldVersion = parseInt( Radio.request('entities', 'get', {
2044 type: 'localStorage',
2045 name: name + '_idbVersion'
2046 }), 10 ) || 0;
2047
2048 if( newVersion !== oldVersion ){
2049 this.clear().then(function(){
2050 Radio.request('entities', 'set', {
2051 type : 'localStorage',
2052 name : name + '_idbVersion',
2053 data : newVersion
2054 });
2055 });
2056 }
2057 }
2058
2059});
2060
2061/***/ }),
2062/* 35 */
2063/***/ (function(module, exports) {
2064
2065module.exports = moment;
2066
2067/***/ }),
2068/* 36 */
2069/***/ (function(module, exports, __webpack_require__) {
2070
2071/* jshint -W071, -W003, -W021 */
2072var _ = __webpack_require__(0);
2073var Backbone = __webpack_require__(4);
2074var FilteredCollection = __webpack_require__(68);
2075var SortedCollection = __webpack_require__(70);
2076var PaginatedCollection = __webpack_require__(72);
2077var proxyCollection = __webpack_require__(19);
2078var proxyEvents = __webpack_require__(73);
2079var query = __webpack_require__(74);
2080
2081// extend FilteredCollection with query methods
2082_.extend(FilteredCollection.prototype, query);
2083
2084function Obscura(superset, options) {
2085 this._superset = superset;
2086 this._filtered = new FilteredCollection(superset, options);
2087 this._sorted = new SortedCollection(this._filtered, options);
2088 this._paginated = new PaginatedCollection(this._sorted, options);
2089 proxyCollection(this._paginated, this);
2090 proxyEvents.call(this, this._filtered, filteredEvents);
2091 proxyEvents.call(this, this._sorted, sortedEvents);
2092 proxyEvents.call(this, this._paginated, paginatedEvents);
2093 this.initialize(options);
2094}
2095
2096var methods = {
2097 superset: function () {
2098 return this._superset;
2099 },
2100 getFilteredLength: function () {
2101 return this._filtered.length;
2102 },
2103 removeTransforms: function () {
2104 this._filtered.resetFilters();
2105 this._sorted.removeSort();
2106 this._paginated.removePagination();
2107 return this;
2108 },
2109 destroy: function () {
2110 this.stopListening();
2111 this._filtered.destroy();
2112 this._sorted.destroy();
2113 this._paginated.destroy();
2114 this.length = 0;
2115 this.trigger('obscura:destroy');
2116 }
2117};
2118
2119var filteredMethods = [
2120 'filterBy',
2121 'removeFilter',
2122 'resetFilters',
2123 'refilter',
2124 'hasFilter',
2125 'getFilters',
2126 'query',
2127 'getQuery',
2128 'getTokens',
2129 'getRemoteFilter'
2130];
2131var filteredEvents = [
2132 'filtered:add',
2133 'filtered:remove',
2134 'filtered:reset'
2135];
2136var sortedMethods = [
2137 'setSort',
2138 'reverseSort',
2139 'removeSort'
2140];
2141var sortedEvents = [
2142 'sorted:add',
2143 'sorted:remove'
2144];
2145var paginatedMethods = [
2146 'setPerPage',
2147 'setPage',
2148 'getPerPage',
2149 'getNumPages',
2150 'getPage',
2151 'hasNextPage',
2152 'hasPrevPage',
2153 'nextPage',
2154 'prevPage',
2155 'movePage',
2156 'removePagination',
2157 'firstPage',
2158 'lastPage',
2159 'appendNextPage'
2160];
2161var paginatedEvents = [
2162 'paginated:change:perPage',
2163 'paginated:change:page',
2164 'paginated:change:numPages'
2165];
2166var unsupportedMethods = [
2167 'add',
2168 'create',
2169 'remove',
2170 'set',
2171 'reset',
2172 'sort',
2173 'parse',
2174 'sync',
2175 'fetch',
2176 'push',
2177 'pop',
2178 'shift',
2179 'unshift'
2180];
2181
2182_.each(filteredMethods, function (method) {
2183 methods[method] = function () {
2184 var result = FilteredCollection.prototype[method]
2185 .apply(this._filtered, arguments);
2186 return result === this._filtered ? this : result;
2187 };
2188});
2189_.each(paginatedMethods, function (method) {
2190 methods[method] = function () {
2191 var result = PaginatedCollection.prototype[method]
2192 .apply(this._paginated, arguments);
2193 return result === this._paginated ? this : result;
2194 };
2195});
2196_.each(sortedMethods, function (method) {
2197 methods[method] = function () {
2198 var result = SortedCollection.prototype[method]
2199 .apply(this._sorted, arguments);
2200 return result === this._sorted ? this : result;
2201 };
2202});
2203_.each(unsupportedMethods, function (method) {
2204 methods[method] = function () {
2205 throw new Error(
2206 'Backbone.Obscura: Unsupported method: ' +
2207 method + 'called on read-only proxy'
2208 );
2209 };
2210});
2211
2212_.extend(Obscura.prototype, methods, Backbone.Events);
2213Obscura = Backbone.Collection.extend(Obscura.prototype);
2214Obscura.FilteredCollection = FilteredCollection;
2215Obscura.SortedCollection = SortedCollection;
2216Obscura.PaginatedCollection = PaginatedCollection;
2217module.exports = Obscura;
2218/* jshint +W071, +W003, +W021 */
2219
2220/***/ }),
2221/* 37 */
2222/***/ (function(module, exports, __webpack_require__) {
2223
2224var DeepModel = __webpack_require__(23);
2225var Radio = __webpack_require__(2);
2226var polyglot = __webpack_require__(6);
2227
2228module.exports = DeepModel.extend({
2229
2230 initialize: function() {
2231 this.url = Radio.request('entities', 'get', {
2232 type: 'option',
2233 name: 'ajaxurl'
2234 });
2235 },
2236
2237 sync: function (method, model, options) {
2238 var nonce = Radio.request('entities', 'get', {
2239 type: 'option',
2240 name: 'nonce'
2241 });
2242
2243 var id = 'id=' + model.get('id'),
2244 action = 'action=wc_pos_admin_settings',
2245 security = 'security=' + nonce;
2246
2247 //options.emulateHTTP = true;
2248 options.url = this.url + '?' + action + '&' + id + '&' + security;
2249
2250 // button state
2251 if(options.buttons){
2252 this.updateButtonState(options);
2253 }
2254
2255 return DeepModel.prototype.sync(method, model, options);
2256 },
2257
2258 parse: function (resp) {
2259 // ajax will return false if no option exists
2260 if(!resp){ resp = null; }
2261 return resp;
2262 },
2263
2264 updateButtonState: function(options){
2265 var success = options.success,
2266 error = options.error,
2267 btn = options.buttons;
2268
2269 btn.trigger('state', [ 'loading', '' ]);
2270
2271 options.success = function(model, resp, options){
2272 if( success ) { success(model, resp, options); }
2273 btn.trigger('state', [ 'success', null ]);
2274 };
2275
2276 options.error = function(jqxhr, textStatus, errorThrown){
2277 if( error ) { error(jqxhr, textStatus, errorThrown); }
2278 var message = null;
2279
2280 // code 405 = not allowed HTTP methods
2281 if( jqxhr.status && jqxhr.status === 405 ){
2282 message = polyglot.t('messages.legacy') +
2283 '. <a href="#tools">' + polyglot.t('buttons.legacy') + '</a>.';
2284 }
2285
2286 // other errors
2287 if( !message && jqxhr.responseJSON && jqxhr.responseJSON.errors ){
2288 message = jqxhr.responseJSON.errors[0].message;
2289 }
2290 btn.trigger('state', ['error', message]);
2291 };
2292 },
2293
2294 /**
2295 * Override destroy to restore data
2296 * @param options
2297 * @returns {*}
2298 */
2299 destroy: function(options){
2300 var self = this;
2301 return this.sync('delete', this, options)
2302 .then(function(data){
2303 data.id = self.id;
2304 self.clear({ silent: true }).set(data);
2305 });
2306 }
2307
2308});
2309
2310/***/ }),
2311/* 38 */
2312/***/ (function(module, exports, __webpack_require__) {
2313
2314var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! tether-drop 1.4.1 */
2315
2316(function(root, factory) {
2317 if (true) {
2318 !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(90)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
2319 __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
2320 (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
2321 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
2322 } else if (typeof exports === 'object') {
2323 module.exports = factory(require('tether'));
2324 } else {
2325 root.Drop = factory(root.Tether);
2326 }
2327}(this, function(Tether) {
2328
2329/* global Tether */
2330'use strict';
2331
2332var _bind = Function.prototype.bind;
2333
2334var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
2335
2336var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
2337
2338var _get = function get(_x2, _x3, _x4) { var _again = true; _function: while (_again) { var object = _x2, property = _x3, receiver = _x4; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x2 = parent; _x3 = property; _x4 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
2339
2340function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
2341
2342function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
2343
2344var _Tether$Utils = Tether.Utils;
2345var extend = _Tether$Utils.extend;
2346var addClass = _Tether$Utils.addClass;
2347var removeClass = _Tether$Utils.removeClass;
2348var hasClass = _Tether$Utils.hasClass;
2349var Evented = _Tether$Utils.Evented;
2350
2351function sortAttach(str) {
2352 var _str$split = str.split(' ');
2353
2354 var _str$split2 = _slicedToArray(_str$split, 2);
2355
2356 var first = _str$split2[0];
2357 var second = _str$split2[1];
2358
2359 if (['left', 'right'].indexOf(first) >= 0) {
2360 var _ref = [second, first];
2361 first = _ref[0];
2362 second = _ref[1];
2363 }
2364 return [first, second].join(' ');
2365}
2366
2367function removeFromArray(arr, item) {
2368 var index = undefined;
2369 var results = [];
2370 while ((index = arr.indexOf(item)) !== -1) {
2371 results.push(arr.splice(index, 1));
2372 }
2373 return results;
2374}
2375
2376var clickEvents = ['click'];
2377if ('ontouchstart' in document.documentElement) {
2378 clickEvents.push('touchstart');
2379}
2380
2381var transitionEndEvents = {
2382 'WebkitTransition': 'webkitTransitionEnd',
2383 'MozTransition': 'transitionend',
2384 'OTransition': 'otransitionend',
2385 'transition': 'transitionend'
2386};
2387
2388var transitionEndEvent = '';
2389for (var _name in transitionEndEvents) {
2390 if (({}).hasOwnProperty.call(transitionEndEvents, _name)) {
2391 var tempEl = document.createElement('p');
2392 if (typeof tempEl.style[_name] !== 'undefined') {
2393 transitionEndEvent = transitionEndEvents[_name];
2394 }
2395 }
2396}
2397
2398var MIRROR_ATTACH = {
2399 left: 'right',
2400 right: 'left',
2401 top: 'bottom',
2402 bottom: 'top',
2403 middle: 'middle',
2404 center: 'center'
2405};
2406
2407var allDrops = {};
2408
2409// Drop can be included in external libraries. Calling createContext gives you a fresh
2410// copy of drop which won't interact with other copies on the page (beyond calling the document events).
2411
2412function createContext() {
2413 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
2414
2415 var drop = function drop() {
2416 for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
2417 args[_key] = arguments[_key];
2418 }
2419
2420 return new (_bind.apply(DropInstance, [null].concat(args)))();
2421 };
2422
2423 extend(drop, {
2424 createContext: createContext,
2425 drops: [],
2426 defaults: {}
2427 });
2428
2429 var defaultOptions = {
2430 classPrefix: 'drop',
2431 defaults: {
2432 position: 'bottom left',
2433 openOn: 'click',
2434 beforeClose: null,
2435 constrainToScrollParent: true,
2436 constrainToWindow: true,
2437 classes: '',
2438 remove: false,
2439 openDelay: 0,
2440 closeDelay: 50,
2441 // inherited from openDelay and closeDelay if not explicitly defined
2442 focusDelay: null,
2443 blurDelay: null,
2444 hoverOpenDelay: null,
2445 hoverCloseDelay: null,
2446 tetherOptions: {}
2447 }
2448 };
2449
2450 extend(drop, defaultOptions, options);
2451 extend(drop.defaults, defaultOptions.defaults, options.defaults);
2452
2453 if (typeof allDrops[drop.classPrefix] === 'undefined') {
2454 allDrops[drop.classPrefix] = [];
2455 }
2456
2457 drop.updateBodyClasses = function () {
2458 // There is only one body, so despite the context concept, we still iterate through all
2459 // drops which share our classPrefix.
2460
2461 var anyOpen = false;
2462 var drops = allDrops[drop.classPrefix];
2463 var len = drops.length;
2464 for (var i = 0; i < len; ++i) {
2465 if (drops[i].isOpened()) {
2466 anyOpen = true;
2467 break;
2468 }
2469 }
2470
2471 if (anyOpen) {
2472 addClass(document.body, drop.classPrefix + '-open');
2473 } else {
2474 removeClass(document.body, drop.classPrefix + '-open');
2475 }
2476 };
2477
2478 var DropInstance = (function (_Evented) {
2479 _inherits(DropInstance, _Evented);
2480
2481 function DropInstance(opts) {
2482 _classCallCheck(this, DropInstance);
2483
2484 _get(Object.getPrototypeOf(DropInstance.prototype), 'constructor', this).call(this);
2485 this.options = extend({}, drop.defaults, opts);
2486 this.target = this.options.target;
2487
2488 if (typeof this.target === 'undefined') {
2489 throw new Error('Drop Error: You must provide a target.');
2490 }
2491
2492 var dataPrefix = 'data-' + drop.classPrefix;
2493
2494 var contentAttr = this.target.getAttribute(dataPrefix);
2495 if (contentAttr && this.options.content == null) {
2496 this.options.content = contentAttr;
2497 }
2498
2499 var attrsOverride = ['position', 'openOn'];
2500 for (var i = 0; i < attrsOverride.length; ++i) {
2501
2502 var override = this.target.getAttribute(dataPrefix + '-' + attrsOverride[i]);
2503 if (override && this.options[attrsOverride[i]] == null) {
2504 this.options[attrsOverride[i]] = override;
2505 }
2506 }
2507
2508 if (this.options.classes && this.options.addTargetClasses !== false) {
2509 addClass(this.target, this.options.classes);
2510 }
2511
2512 drop.drops.push(this);
2513 allDrops[drop.classPrefix].push(this);
2514
2515 this._boundEvents = [];
2516 this.bindMethods();
2517 this.setupElements();
2518 this.setupEvents();
2519 this.setupTether();
2520 }
2521
2522 _createClass(DropInstance, [{
2523 key: '_on',
2524 value: function _on(element, event, handler) {
2525 this._boundEvents.push({ element: element, event: event, handler: handler });
2526 element.addEventListener(event, handler);
2527 }
2528 }, {
2529 key: 'bindMethods',
2530 value: function bindMethods() {
2531 this.transitionEndHandler = this._transitionEndHandler.bind(this);
2532 }
2533 }, {
2534 key: 'setupElements',
2535 value: function setupElements() {
2536 var _this = this;
2537
2538 this.drop = document.createElement('div');
2539 addClass(this.drop, drop.classPrefix);
2540
2541 if (this.options.classes) {
2542 addClass(this.drop, this.options.classes);
2543 }
2544
2545 this.content = document.createElement('div');
2546 addClass(this.content, drop.classPrefix + '-content');
2547
2548 if (typeof this.options.content === 'function') {
2549 var generateAndSetContent = function generateAndSetContent() {
2550 // content function might return a string or an element
2551 var contentElementOrHTML = _this.options.content.call(_this, _this);
2552
2553 if (typeof contentElementOrHTML === 'string') {
2554 _this.content.innerHTML = contentElementOrHTML;
2555 } else if (typeof contentElementOrHTML === 'object') {
2556 _this.content.innerHTML = '';
2557 _this.content.appendChild(contentElementOrHTML);
2558 } else {
2559 throw new Error('Drop Error: Content function should return a string or HTMLElement.');
2560 }
2561 };
2562
2563 generateAndSetContent();
2564 this.on('open', generateAndSetContent.bind(this));
2565 } else if (typeof this.options.content === 'object') {
2566 this.content.appendChild(this.options.content);
2567 } else {
2568 this.content.innerHTML = this.options.content;
2569 }
2570
2571 this.drop.appendChild(this.content);
2572 }
2573 }, {
2574 key: 'setupTether',
2575 value: function setupTether() {
2576 // Tether expects two attachment points, one in the target element, one in the
2577 // drop. We use a single one, and use the order as well, to allow us to put
2578 // the drop on either side of any of the four corners. This magic converts between
2579 // the two:
2580 var dropAttach = this.options.position.split(' ');
2581 dropAttach[0] = MIRROR_ATTACH[dropAttach[0]];
2582 dropAttach = dropAttach.join(' ');
2583
2584 var constraints = [];
2585 if (this.options.constrainToScrollParent) {
2586 constraints.push({
2587 to: 'scrollParent',
2588 pin: 'top, bottom',
2589 attachment: 'together none'
2590 });
2591 } else {
2592 // To get 'out of bounds' classes
2593 constraints.push({
2594 to: 'scrollParent'
2595 });
2596 }
2597
2598 if (this.options.constrainToWindow !== false) {
2599 constraints.push({
2600 to: 'window',
2601 attachment: 'together'
2602 });
2603 } else {
2604 // To get 'out of bounds' classes
2605 constraints.push({
2606 to: 'window'
2607 });
2608 }
2609
2610 var opts = {
2611 element: this.drop,
2612 target: this.target,
2613 attachment: sortAttach(dropAttach),
2614 targetAttachment: sortAttach(this.options.position),
2615 classPrefix: drop.classPrefix,
2616 offset: '0 0',
2617 targetOffset: '0 0',
2618 enabled: false,
2619 constraints: constraints,
2620 addTargetClasses: this.options.addTargetClasses
2621 };
2622
2623 if (this.options.tetherOptions !== false) {
2624 this.tether = new Tether(extend({}, opts, this.options.tetherOptions));
2625 }
2626 }
2627 }, {
2628 key: 'setupEvents',
2629 value: function setupEvents() {
2630 var _this2 = this;
2631
2632 if (!this.options.openOn) {
2633 return;
2634 }
2635
2636 if (this.options.openOn === 'always') {
2637 setTimeout(this.open.bind(this));
2638 return;
2639 }
2640
2641 var events = this.options.openOn.split(' ');
2642
2643 if (events.indexOf('click') >= 0) {
2644 var openHandler = function openHandler(event) {
2645 _this2.toggle(event);
2646 event.preventDefault();
2647 };
2648
2649 var closeHandler = function closeHandler(event) {
2650 if (!_this2.isOpened()) {
2651 return;
2652 }
2653
2654 // Clicking inside dropdown
2655 if (event.target === _this2.drop || _this2.drop.contains(event.target)) {
2656 return;
2657 }
2658
2659 // Clicking target
2660 if (event.target === _this2.target || _this2.target.contains(event.target)) {
2661 return;
2662 }
2663
2664 _this2.close(event);
2665 };
2666
2667 for (var i = 0; i < clickEvents.length; ++i) {
2668 var clickEvent = clickEvents[i];
2669 this._on(this.target, clickEvent, openHandler);
2670 this._on(document, clickEvent, closeHandler);
2671 }
2672 }
2673
2674 var inTimeout = null;
2675 var outTimeout = null;
2676
2677 var inHandler = function inHandler(event) {
2678 if (outTimeout !== null) {
2679 clearTimeout(outTimeout);
2680 } else {
2681 inTimeout = setTimeout(function () {
2682 _this2.open(event);
2683 inTimeout = null;
2684 }, (event.type === 'focus' ? _this2.options.focusDelay : _this2.options.hoverOpenDelay) || _this2.options.openDelay);
2685 }
2686 };
2687
2688 var outHandler = function outHandler(event) {
2689 if (inTimeout !== null) {
2690 clearTimeout(inTimeout);
2691 } else {
2692 outTimeout = setTimeout(function () {
2693 _this2.close(event);
2694 outTimeout = null;
2695 }, (event.type === 'blur' ? _this2.options.blurDelay : _this2.options.hoverCloseDelay) || _this2.options.closeDelay);
2696 }
2697 };
2698
2699 if (events.indexOf('hover') >= 0) {
2700 this._on(this.target, 'mouseover', inHandler);
2701 this._on(this.drop, 'mouseover', inHandler);
2702 this._on(this.target, 'mouseout', outHandler);
2703 this._on(this.drop, 'mouseout', outHandler);
2704 }
2705
2706 if (events.indexOf('focus') >= 0) {
2707 this._on(this.target, 'focus', inHandler);
2708 this._on(this.drop, 'focus', inHandler);
2709 this._on(this.target, 'blur', outHandler);
2710 this._on(this.drop, 'blur', outHandler);
2711 }
2712 }
2713 }, {
2714 key: 'isOpened',
2715 value: function isOpened() {
2716 if (this.drop) {
2717 return hasClass(this.drop, drop.classPrefix + '-open');
2718 }
2719 }
2720 }, {
2721 key: 'toggle',
2722 value: function toggle(event) {
2723 if (this.isOpened()) {
2724 this.close(event);
2725 } else {
2726 this.open(event);
2727 }
2728 }
2729 }, {
2730 key: 'open',
2731 value: function open(event) {
2732 var _this3 = this;
2733
2734 /* eslint no-unused-vars: 0 */
2735 if (this.isOpened()) {
2736 return;
2737 }
2738
2739 if (!this.drop.parentNode) {
2740 document.body.appendChild(this.drop);
2741 }
2742
2743 if (typeof this.tether !== 'undefined') {
2744 this.tether.enable();
2745 }
2746
2747 addClass(this.drop, drop.classPrefix + '-open');
2748 addClass(this.drop, drop.classPrefix + '-open-transitionend');
2749
2750 setTimeout(function () {
2751 if (_this3.drop) {
2752 addClass(_this3.drop, drop.classPrefix + '-after-open');
2753 }
2754 });
2755
2756 if (typeof this.tether !== 'undefined') {
2757 this.tether.position();
2758 }
2759
2760 this.trigger('open');
2761
2762 drop.updateBodyClasses();
2763 }
2764 }, {
2765 key: '_transitionEndHandler',
2766 value: function _transitionEndHandler(e) {
2767 if (e.target !== e.currentTarget) {
2768 return;
2769 }
2770
2771 if (!hasClass(this.drop, drop.classPrefix + '-open')) {
2772 removeClass(this.drop, drop.classPrefix + '-open-transitionend');
2773 }
2774 this.drop.removeEventListener(transitionEndEvent, this.transitionEndHandler);
2775 }
2776 }, {
2777 key: 'beforeCloseHandler',
2778 value: function beforeCloseHandler(event) {
2779 var shouldClose = true;
2780
2781 if (!this.isClosing && typeof this.options.beforeClose === 'function') {
2782 this.isClosing = true;
2783 shouldClose = this.options.beforeClose(event, this) !== false;
2784 }
2785
2786 this.isClosing = false;
2787
2788 return shouldClose;
2789 }
2790 }, {
2791 key: 'close',
2792 value: function close(event) {
2793 if (!this.isOpened()) {
2794 return;
2795 }
2796
2797 if (!this.beforeCloseHandler(event)) {
2798 return;
2799 }
2800
2801 removeClass(this.drop, drop.classPrefix + '-open');
2802 removeClass(this.drop, drop.classPrefix + '-after-open');
2803
2804 this.drop.addEventListener(transitionEndEvent, this.transitionEndHandler);
2805
2806 this.trigger('close');
2807
2808 if (typeof this.tether !== 'undefined') {
2809 this.tether.disable();
2810 }
2811
2812 drop.updateBodyClasses();
2813
2814 if (this.options.remove) {
2815 this.remove(event);
2816 }
2817 }
2818 }, {
2819 key: 'remove',
2820 value: function remove(event) {
2821 this.close(event);
2822 if (this.drop.parentNode) {
2823 this.drop.parentNode.removeChild(this.drop);
2824 }
2825 }
2826 }, {
2827 key: 'position',
2828 value: function position() {
2829 if (this.isOpened() && typeof this.tether !== 'undefined') {
2830 this.tether.position();
2831 }
2832 }
2833 }, {
2834 key: 'destroy',
2835 value: function destroy() {
2836 this.remove();
2837
2838 if (typeof this.tether !== 'undefined') {
2839 this.tether.destroy();
2840 }
2841
2842 for (var i = 0; i < this._boundEvents.length; ++i) {
2843 var _boundEvents$i = this._boundEvents[i];
2844 var element = _boundEvents$i.element;
2845 var _event = _boundEvents$i.event;
2846 var handler = _boundEvents$i.handler;
2847
2848 element.removeEventListener(_event, handler);
2849 }
2850
2851 this._boundEvents = [];
2852
2853 this.tether = null;
2854 this.drop = null;
2855 this.content = null;
2856 this.target = null;
2857
2858 removeFromArray(allDrops[drop.classPrefix], this);
2859 removeFromArray(drop.drops, this);
2860 }
2861 }]);
2862
2863 return DropInstance;
2864 })(Evented);
2865
2866 return drop;
2867}
2868
2869var Drop = createContext();
2870
2871document.addEventListener('DOMContentLoaded', function () {
2872 Drop.updateBodyClasses();
2873});
2874return Drop;
2875
2876}));
2877
2878
2879/***/ }),
2880/* 39 */
2881/***/ (function(module, exports, __webpack_require__) {
2882
2883var bb = __webpack_require__(4);
2884var Mn = __webpack_require__(9);
2885var $ = __webpack_require__(3);
2886var _ = __webpack_require__(0);
2887var Route = __webpack_require__(11);
2888var app = __webpack_require__(1);
2889
2890module.exports = app.prototype.Router = Mn.AppRouter.extend({
2891 constructor: function() {
2892 this.channel = bb.Radio.channel('router');
2893 this.on('all', this._onRouterEvent);
2894 this.listenTo(bb.history, 'route', this._onHistoryRoute);
2895 Mn.AppRouter.apply(this, arguments);
2896 },
2897
2898 _onRouterEvent: function(name) {
2899 var args = _.toArray(arguments).slice(1);
2900 this.channel.trigger.apply(this.channel, [name, this].concat(args));
2901 },
2902
2903 _onHistoryRoute: function(router) {
2904 if (this === router) {
2905 this.active = true;
2906 } else {
2907 this.active = false;
2908 this._currentRoute = undefined;
2909 }
2910 },
2911
2912 execute: function(callback, args) {
2913 var self = this;
2914
2915 if (!this.active) {
2916 this.triggerMethod.apply(this, ['before:enter'].concat(args));
2917 }
2918
2919 this.triggerMethod.apply(this, ['before:route'].concat(args));
2920
2921 $.when(this._execute(callback, args)).then(function() {
2922 if (!self.active) {
2923 self.triggerMethod.apply(self, ['enter'].concat(args));
2924 }
2925
2926 self.triggerMethod.apply(self, ['route'].concat(args));
2927 });
2928 },
2929
2930 _execute: function(callback, args) {
2931 var route = callback.apply(this, args);
2932 this._currentRoute = route;
2933
2934 if (route instanceof Route) {
2935 route.router = this;
2936 return route.enter(args);
2937 }
2938 },
2939
2940 triggerMethod: Mn.triggerMethod
2941});
2942
2943/***/ }),
2944/* 40 */
2945/***/ (function(module, exports, __webpack_require__) {
2946
2947var Behavior = __webpack_require__(15);
2948var App = __webpack_require__(1);
2949var $ = __webpack_require__(3);
2950var Radio = __webpack_require__(2);
2951
2952/**
2953 * Toggles legacy server support
2954 */
2955var EmulateHTTP = Behavior.extend({
2956
2957 ui: {
2958 toggle : '*[data-action^="legacy-"]'
2959 },
2960
2961 events: {
2962 'click @ui.toggle' : 'toggle'
2963 },
2964
2965 toggle: function(e) {
2966 e.preventDefault();
2967
2968 var ajaxurl = Radio.request('entities', 'get', {
2969 type: 'option',
2970 name: 'ajaxurl'
2971 });
2972
2973 var nonce = Radio.request('entities', 'get', {
2974 type: 'option',
2975 name: 'nonce'
2976 });
2977
2978 $.getJSON( ajaxurl, {
2979 action: 'wc_pos_toggle_legacy_server',
2980 enable: $(e.target).data('action').split('-').pop() === 'enable',
2981 security: nonce
2982 }, function(){
2983 window.location.reload();
2984 });
2985 }
2986
2987});
2988
2989module.exports = EmulateHTTP;
2990App.prototype.set('Behaviors.EmulateHTTP', EmulateHTTP);
2991
2992/***/ }),
2993/* 41 */
2994/***/ (function(module, exports, __webpack_require__) {
2995
2996"use strict";
2997// (c) 2012-2016 Airbnb, Inc.
2998//
2999// polyglot.js may be freely distributed under the terms of the BSD
3000// license. For all licensing information, details, and documention:
3001// http://airbnb.github.com/polyglot.js
3002//
3003//
3004// Polyglot.js is an I18n helper library written in JavaScript, made to
3005// work both in the browser and in Node. It provides a simple solution for
3006// interpolation and pluralization, based off of Airbnb's
3007// experience adding I18n functionality to its Backbone.js and Node apps.
3008//
3009// Polylglot is agnostic to your translation backend. It doesn't perform any
3010// translation; it simply gives you a way to manage translated phrases from
3011// your client- or server-side JavaScript application.
3012//
3013
3014
3015
3016var forEach = __webpack_require__(42);
3017var warning = __webpack_require__(44);
3018var has = __webpack_require__(28);
3019var trim = __webpack_require__(46);
3020
3021var warn = function warn(message) {
3022 warning(false, message);
3023};
3024
3025var replace = String.prototype.replace;
3026var split = String.prototype.split;
3027
3028// #### Pluralization methods
3029// The string that separates the different phrase possibilities.
3030var delimeter = '||||';
3031
3032// Mapping from pluralization group plural logic.
3033var pluralTypes = {
3034 arabic: function (n) {
3035 // http://www.arabeyes.org/Plural_Forms
3036 if (n < 3) { return n; }
3037 if (n % 100 >= 3 && n % 100 <= 10) return 3;
3038 return n % 100 >= 11 ? 4 : 5;
3039 },
3040 chinese: function () { return 0; },
3041 german: function (n) { return n !== 1 ? 1 : 0; },
3042 french: function (n) { return n > 1 ? 1 : 0; },
3043 russian: function (n) {
3044 if (n % 10 === 1 && n % 100 !== 11) { return 0; }
3045 return n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
3046 },
3047 czech: function (n) {
3048 if (n === 1) { return 0; }
3049 return (n >= 2 && n <= 4) ? 1 : 2;
3050 },
3051 polish: function (n) {
3052 if (n === 1) { return 0; }
3053 return n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
3054 },
3055 icelandic: function (n) { return (n % 10 !== 1 || n % 100 === 11) ? 1 : 0; }
3056};
3057
3058// Mapping from pluralization group to individual locales.
3059var pluralTypeToLanguages = {
3060 arabic: ['ar'],
3061 chinese: ['fa', 'id', 'ja', 'ko', 'lo', 'ms', 'th', 'tr', 'zh'],
3062 german: ['da', 'de', 'en', 'es', 'fi', 'el', 'he', 'hu', 'it', 'nl', 'no', 'pt', 'sv'],
3063 french: ['fr', 'tl', 'pt-br'],
3064 russian: ['hr', 'ru', 'lt'],
3065 czech: ['cs', 'sk'],
3066 polish: ['pl'],
3067 icelandic: ['is']
3068};
3069
3070function langToTypeMap(mapping) {
3071 var ret = {};
3072 forEach(mapping, function (langs, type) {
3073 forEach(langs, function (lang) {
3074 ret[lang] = type;
3075 });
3076 });
3077 return ret;
3078}
3079
3080function pluralTypeName(locale) {
3081 var langToPluralType = langToTypeMap(pluralTypeToLanguages);
3082 return langToPluralType[locale]
3083 || langToPluralType[split.call(locale, /-/, 1)[0]]
3084 || langToPluralType.en;
3085}
3086
3087function pluralTypeIndex(locale, count) {
3088 return pluralTypes[pluralTypeName(locale)](count);
3089}
3090
3091var dollarRegex = /\$/g;
3092var dollarBillsYall = '$$';
3093var tokenRegex = /%\{(.*?)\}/g;
3094
3095// ### transformPhrase(phrase, substitutions, locale)
3096//
3097// Takes a phrase string and transforms it by choosing the correct
3098// plural form and interpolating it.
3099//
3100// transformPhrase('Hello, %{name}!', {name: 'Spike'});
3101// // "Hello, Spike!"
3102//
3103// The correct plural form is selected if substitutions.smart_count
3104// is set. You can pass in a number instead of an Object as `substitutions`
3105// as a shortcut for `smart_count`.
3106//
3107// transformPhrase('%{smart_count} new messages |||| 1 new message', {smart_count: 1}, 'en');
3108// // "1 new message"
3109//
3110// transformPhrase('%{smart_count} new messages |||| 1 new message', {smart_count: 2}, 'en');
3111// // "2 new messages"
3112//
3113// transformPhrase('%{smart_count} new messages |||| 1 new message', 5, 'en');
3114// // "5 new messages"
3115//
3116// You should pass in a third argument, the locale, to specify the correct plural type.
3117// It defaults to `'en'` with 2 plural forms.
3118function transformPhrase(phrase, substitutions, locale) {
3119 if (typeof phrase !== 'string') {
3120 throw new TypeError('Polyglot.transformPhrase expects argument #1 to be string');
3121 }
3122
3123 if (substitutions == null) {
3124 return phrase;
3125 }
3126
3127 var result = phrase;
3128
3129 // allow number as a pluralization shortcut
3130 var options = typeof substitutions === 'number' ? { smart_count: substitutions } : substitutions;
3131
3132 // Select plural form: based on a phrase text that contains `n`
3133 // plural forms separated by `delimeter`, a `locale`, and a `substitutions.smart_count`,
3134 // choose the correct plural form. This is only done if `count` is set.
3135 if (options.smart_count != null && result) {
3136 var texts = split.call(result, delimeter);
3137 result = trim(texts[pluralTypeIndex(locale || 'en', options.smart_count)] || texts[0]);
3138 }
3139
3140 // Interpolate: Creates a `RegExp` object for each interpolation placeholder.
3141 result = replace.call(result, tokenRegex, function (expression, argument) {
3142 if (!has(options, argument) || options[argument] == null) { return expression; }
3143 // Ensure replacement value is escaped to prevent special $-prefixed regex replace tokens.
3144 return replace.call(options[argument], dollarRegex, dollarBillsYall);
3145 });
3146
3147 return result;
3148}
3149
3150// ### Polyglot class constructor
3151function Polyglot(options) {
3152 var opts = options || {};
3153 this.phrases = {};
3154 this.extend(opts.phrases || {});
3155 this.currentLocale = opts.locale || 'en';
3156 var allowMissing = opts.allowMissing ? transformPhrase : null;
3157 this.onMissingKey = typeof opts.onMissingKey === 'function' ? opts.onMissingKey : allowMissing;
3158 this.warn = opts.warn || warn;
3159}
3160
3161// ### polyglot.locale([locale])
3162//
3163// Get or set locale. Internally, Polyglot only uses locale for pluralization.
3164Polyglot.prototype.locale = function (newLocale) {
3165 if (newLocale) this.currentLocale = newLocale;
3166 return this.currentLocale;
3167};
3168
3169// ### polyglot.extend(phrases)
3170//
3171// Use `extend` to tell Polyglot how to translate a given key.
3172//
3173// polyglot.extend({
3174// "hello": "Hello",
3175// "hello_name": "Hello, %{name}"
3176// });
3177//
3178// The key can be any string. Feel free to call `extend` multiple times;
3179// it will override any phrases with the same key, but leave existing phrases
3180// untouched.
3181//
3182// It is also possible to pass nested phrase objects, which get flattened
3183// into an object with the nested keys concatenated using dot notation.
3184//
3185// polyglot.extend({
3186// "nav": {
3187// "hello": "Hello",
3188// "hello_name": "Hello, %{name}",
3189// "sidebar": {
3190// "welcome": "Welcome"
3191// }
3192// }
3193// });
3194//
3195// console.log(polyglot.phrases);
3196// // {
3197// // 'nav.hello': 'Hello',
3198// // 'nav.hello_name': 'Hello, %{name}',
3199// // 'nav.sidebar.welcome': 'Welcome'
3200// // }
3201//
3202// `extend` accepts an optional second argument, `prefix`, which can be used
3203// to prefix every key in the phrases object with some string, using dot
3204// notation.
3205//
3206// polyglot.extend({
3207// "hello": "Hello",
3208// "hello_name": "Hello, %{name}"
3209// }, "nav");
3210//
3211// console.log(polyglot.phrases);
3212// // {
3213// // 'nav.hello': 'Hello',
3214// // 'nav.hello_name': 'Hello, %{name}'
3215// // }
3216//
3217// This feature is used internally to support nested phrase objects.
3218Polyglot.prototype.extend = function (morePhrases, prefix) {
3219 forEach(morePhrases, function (phrase, key) {
3220 var prefixedKey = prefix ? prefix + '.' + key : key;
3221 if (typeof phrase === 'object') {
3222 this.extend(phrase, prefixedKey);
3223 } else {
3224 this.phrases[prefixedKey] = phrase;
3225 }
3226 }, this);
3227};
3228
3229// ### polyglot.unset(phrases)
3230// Use `unset` to selectively remove keys from a polyglot instance.
3231//
3232// polyglot.unset("some_key");
3233// polyglot.unset({
3234// "hello": "Hello",
3235// "hello_name": "Hello, %{name}"
3236// });
3237//
3238// The unset method can take either a string (for the key), or an object hash with
3239// the keys that you would like to unset.
3240Polyglot.prototype.unset = function (morePhrases, prefix) {
3241 if (typeof morePhrases === 'string') {
3242 delete this.phrases[morePhrases];
3243 } else {
3244 forEach(morePhrases, function (phrase, key) {
3245 var prefixedKey = prefix ? prefix + '.' + key : key;
3246 if (typeof phrase === 'object') {
3247 this.unset(phrase, prefixedKey);
3248 } else {
3249 delete this.phrases[prefixedKey];
3250 }
3251 }, this);
3252 }
3253};
3254
3255// ### polyglot.clear()
3256//
3257// Clears all phrases. Useful for special cases, such as freeing
3258// up memory if you have lots of phrases but no longer need to
3259// perform any translation. Also used internally by `replace`.
3260Polyglot.prototype.clear = function () {
3261 this.phrases = {};
3262};
3263
3264// ### polyglot.replace(phrases)
3265//
3266// Completely replace the existing phrases with a new set of phrases.
3267// Normally, just use `extend` to add more phrases, but under certain
3268// circumstances, you may want to make sure no old phrases are lying around.
3269Polyglot.prototype.replace = function (newPhrases) {
3270 this.clear();
3271 this.extend(newPhrases);
3272};
3273
3274
3275// ### polyglot.t(key, options)
3276//
3277// The most-used method. Provide a key, and `t` will return the
3278// phrase.
3279//
3280// polyglot.t("hello");
3281// => "Hello"
3282//
3283// The phrase value is provided first by a call to `polyglot.extend()` or
3284// `polyglot.replace()`.
3285//
3286// Pass in an object as the second argument to perform interpolation.
3287//
3288// polyglot.t("hello_name", {name: "Spike"});
3289// => "Hello, Spike"
3290//
3291// If you like, you can provide a default value in case the phrase is missing.
3292// Use the special option key "_" to specify a default.
3293//
3294// polyglot.t("i_like_to_write_in_language", {
3295// _: "I like to write in %{language}.",
3296// language: "JavaScript"
3297// });
3298// => "I like to write in JavaScript."
3299//
3300Polyglot.prototype.t = function (key, options) {
3301 var phrase, result;
3302 var opts = options == null ? {} : options;
3303 if (typeof this.phrases[key] === 'string') {
3304 phrase = this.phrases[key];
3305 } else if (typeof opts._ === 'string') {
3306 phrase = opts._;
3307 } else if (this.onMissingKey) {
3308 var onMissingKey = this.onMissingKey;
3309 result = onMissingKey(key, opts, this.currentLocale);
3310 } else {
3311 this.warn('Missing translation for key: "' + key + '"');
3312 result = key;
3313 }
3314 if (typeof phrase === 'string') {
3315 result = transformPhrase(phrase, opts, this.currentLocale);
3316 }
3317 return result;
3318};
3319
3320
3321// ### polyglot.has(key)
3322//
3323// Check if polyglot has a translation for given key
3324Polyglot.prototype.has = function (key) {
3325 return has(this.phrases, key);
3326};
3327
3328// export transformPhrase
3329Polyglot.transformPhrase = transformPhrase;
3330
3331module.exports = Polyglot;
3332
3333
3334/***/ }),
3335/* 42 */
3336/***/ (function(module, exports, __webpack_require__) {
3337
3338var isFunction = __webpack_require__(43)
3339
3340module.exports = forEach
3341
3342var toString = Object.prototype.toString
3343var hasOwnProperty = Object.prototype.hasOwnProperty
3344
3345function forEach(list, iterator, context) {
3346 if (!isFunction(iterator)) {
3347 throw new TypeError('iterator must be a function')
3348 }
3349
3350 if (arguments.length < 3) {
3351 context = this
3352 }
3353
3354 if (toString.call(list) === '[object Array]')
3355 forEachArray(list, iterator, context)
3356 else if (typeof list === 'string')
3357 forEachString(list, iterator, context)
3358 else
3359 forEachObject(list, iterator, context)
3360}
3361
3362function forEachArray(array, iterator, context) {
3363 for (var i = 0, len = array.length; i < len; i++) {
3364 if (hasOwnProperty.call(array, i)) {
3365 iterator.call(context, array[i], i, array)
3366 }
3367 }
3368}
3369
3370function forEachString(string, iterator, context) {
3371 for (var i = 0, len = string.length; i < len; i++) {
3372 // no such thing as a sparse string.
3373 iterator.call(context, string.charAt(i), i, string)
3374 }
3375}
3376
3377function forEachObject(object, iterator, context) {
3378 for (var k in object) {
3379 if (hasOwnProperty.call(object, k)) {
3380 iterator.call(context, object[k], k, object)
3381 }
3382 }
3383}
3384
3385
3386/***/ }),
3387/* 43 */
3388/***/ (function(module, exports) {
3389
3390module.exports = isFunction
3391
3392var toString = Object.prototype.toString
3393
3394function isFunction (fn) {
3395 var string = toString.call(fn)
3396 return string === '[object Function]' ||
3397 (typeof fn === 'function' && string !== '[object RegExp]') ||
3398 (typeof window !== 'undefined' &&
3399 // IE8 and below
3400 (fn === window.setTimeout ||
3401 fn === window.alert ||
3402 fn === window.confirm ||
3403 fn === window.prompt))
3404};
3405
3406
3407/***/ }),
3408/* 44 */
3409/***/ (function(module, exports, __webpack_require__) {
3410
3411"use strict";
3412/* WEBPACK VAR INJECTION */(function(process) {/**
3413 * Copyright 2014-2015, Facebook, Inc.
3414 * All rights reserved.
3415 *
3416 * This source code is licensed under the BSD-style license found in the
3417 * LICENSE file in the root directory of this source tree. An additional grant
3418 * of patent rights can be found in the PATENTS file in the same directory.
3419 */
3420
3421
3422
3423/**
3424 * Similar to invariant but only logs a warning if the condition is not met.
3425 * This can be used to log issues in development environments in critical
3426 * paths. Removing the logging code for production environments will keep the
3427 * same logic and follow the same code paths.
3428 */
3429
3430var warning = function() {};
3431
3432if (process.env.NODE_ENV !== 'production') {
3433 warning = function(condition, format, args) {
3434 var len = arguments.length;
3435 args = new Array(len > 2 ? len - 2 : 0);
3436 for (var key = 2; key < len; key++) {
3437 args[key - 2] = arguments[key];
3438 }
3439 if (format === undefined) {
3440 throw new Error(
3441 '`warning(condition, format, ...args)` requires a warning ' +
3442 'message argument'
3443 );
3444 }
3445
3446 if (format.length < 10 || (/^[s\W]*$/).test(format)) {
3447 throw new Error(
3448 'The warning format should be able to uniquely identify this ' +
3449 'warning. Please, use a more descriptive format than: ' + format
3450 );
3451 }
3452
3453 if (!condition) {
3454 var argIndex = 0;
3455 var message = 'Warning: ' +
3456 format.replace(/%s/g, function() {
3457 return args[argIndex++];
3458 });
3459 if (typeof console !== 'undefined') {
3460 console.error(message);
3461 }
3462 try {
3463 // This error was thrown as a convenience so that you can use this stack
3464 // to find the callsite that caused this warning to fire.
3465 throw new Error(message);
3466 } catch(x) {}
3467 }
3468 };
3469}
3470
3471module.exports = warning;
3472
3473/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(27)))
3474
3475/***/ }),
3476/* 45 */
3477/***/ (function(module, exports, __webpack_require__) {
3478
3479"use strict";
3480
3481
3482/* eslint no-invalid-this: 1 */
3483
3484var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible ';
3485var slice = Array.prototype.slice;
3486var toStr = Object.prototype.toString;
3487var funcType = '[object Function]';
3488
3489module.exports = function bind(that) {
3490 var target = this;
3491 if (typeof target !== 'function' || toStr.call(target) !== funcType) {
3492 throw new TypeError(ERROR_MESSAGE + target);
3493 }
3494 var args = slice.call(arguments, 1);
3495
3496 var bound;
3497 var binder = function () {
3498 if (this instanceof bound) {
3499 var result = target.apply(
3500 this,
3501 args.concat(slice.call(arguments))
3502 );
3503 if (Object(result) === result) {
3504 return result;
3505 }
3506 return this;
3507 } else {
3508 return target.apply(
3509 that,
3510 args.concat(slice.call(arguments))
3511 );
3512 }
3513 };
3514
3515 var boundLength = Math.max(0, target.length - args.length);
3516 var boundArgs = [];
3517 for (var i = 0; i < boundLength; i++) {
3518 boundArgs.push('$' + i);
3519 }
3520
3521 bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder);
3522
3523 if (target.prototype) {
3524 var Empty = function Empty() {};
3525 Empty.prototype = target.prototype;
3526 bound.prototype = new Empty();
3527 Empty.prototype = null;
3528 }
3529
3530 return bound;
3531};
3532
3533
3534/***/ }),
3535/* 46 */
3536/***/ (function(module, exports, __webpack_require__) {
3537
3538"use strict";
3539
3540
3541var bind = __webpack_require__(20);
3542var define = __webpack_require__(29);
3543
3544var implementation = __webpack_require__(30);
3545var getPolyfill = __webpack_require__(32);
3546var shim = __webpack_require__(57);
3547
3548var boundTrim = bind.call(Function.call, getPolyfill());
3549
3550define(boundTrim, {
3551 getPolyfill: getPolyfill,
3552 implementation: implementation,
3553 shim: shim
3554});
3555
3556module.exports = boundTrim;
3557
3558
3559/***/ }),
3560/* 47 */
3561/***/ (function(module, exports, __webpack_require__) {
3562
3563"use strict";
3564
3565
3566// modified from https://github.com/es-shims/es5-shim
3567var has = Object.prototype.hasOwnProperty;
3568var toStr = Object.prototype.toString;
3569var slice = Array.prototype.slice;
3570var isArgs = __webpack_require__(48);
3571var isEnumerable = Object.prototype.propertyIsEnumerable;
3572var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString');
3573var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype');
3574var dontEnums = [
3575 'toString',
3576 'toLocaleString',
3577 'valueOf',
3578 'hasOwnProperty',
3579 'isPrototypeOf',
3580 'propertyIsEnumerable',
3581 'constructor'
3582];
3583var equalsConstructorPrototype = function (o) {
3584 var ctor = o.constructor;
3585 return ctor && ctor.prototype === o;
3586};
3587var excludedKeys = {
3588 $console: true,
3589 $external: true,
3590 $frame: true,
3591 $frameElement: true,
3592 $frames: true,
3593 $innerHeight: true,
3594 $innerWidth: true,
3595 $outerHeight: true,
3596 $outerWidth: true,
3597 $pageXOffset: true,
3598 $pageYOffset: true,
3599 $parent: true,
3600 $scrollLeft: true,
3601 $scrollTop: true,
3602 $scrollX: true,
3603 $scrollY: true,
3604 $self: true,
3605 $webkitIndexedDB: true,
3606 $webkitStorageInfo: true,
3607 $window: true
3608};
3609var hasAutomationEqualityBug = (function () {
3610 /* global window */
3611 if (typeof window === 'undefined') { return false; }
3612 for (var k in window) {
3613 try {
3614 if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') {
3615 try {
3616 equalsConstructorPrototype(window[k]);
3617 } catch (e) {
3618 return true;
3619 }
3620 }
3621 } catch (e) {
3622 return true;
3623 }
3624 }
3625 return false;
3626}());
3627var equalsConstructorPrototypeIfNotBuggy = function (o) {
3628 /* global window */
3629 if (typeof window === 'undefined' || !hasAutomationEqualityBug) {
3630 return equalsConstructorPrototype(o);
3631 }
3632 try {
3633 return equalsConstructorPrototype(o);
3634 } catch (e) {
3635 return false;
3636 }
3637};
3638
3639var keysShim = function keys(object) {
3640 var isObject = object !== null && typeof object === 'object';
3641 var isFunction = toStr.call(object) === '[object Function]';
3642 var isArguments = isArgs(object);
3643 var isString = isObject && toStr.call(object) === '[object String]';
3644 var theKeys = [];
3645
3646 if (!isObject && !isFunction && !isArguments) {
3647 throw new TypeError('Object.keys called on a non-object');
3648 }
3649
3650 var skipProto = hasProtoEnumBug && isFunction;
3651 if (isString && object.length > 0 && !has.call(object, 0)) {
3652 for (var i = 0; i < object.length; ++i) {
3653 theKeys.push(String(i));
3654 }
3655 }
3656
3657 if (isArguments && object.length > 0) {
3658 for (var j = 0; j < object.length; ++j) {
3659 theKeys.push(String(j));
3660 }
3661 } else {
3662 for (var name in object) {
3663 if (!(skipProto && name === 'prototype') && has.call(object, name)) {
3664 theKeys.push(String(name));
3665 }
3666 }
3667 }
3668
3669 if (hasDontEnumBug) {
3670 var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);
3671
3672 for (var k = 0; k < dontEnums.length; ++k) {
3673 if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) {
3674 theKeys.push(dontEnums[k]);
3675 }
3676 }
3677 }
3678 return theKeys;
3679};
3680
3681keysShim.shim = function shimObjectKeys() {
3682 if (Object.keys) {
3683 var keysWorksWithArguments = (function () {
3684 // Safari 5.0 bug
3685 return (Object.keys(arguments) || '').length === 2;
3686 }(1, 2));
3687 if (!keysWorksWithArguments) {
3688 var originalKeys = Object.keys;
3689 Object.keys = function keys(object) {
3690 if (isArgs(object)) {
3691 return originalKeys(slice.call(object));
3692 } else {
3693 return originalKeys(object);
3694 }
3695 };
3696 }
3697 } else {
3698 Object.keys = keysShim;
3699 }
3700 return Object.keys || keysShim;
3701};
3702
3703module.exports = keysShim;
3704
3705
3706/***/ }),
3707/* 48 */
3708/***/ (function(module, exports, __webpack_require__) {
3709
3710"use strict";
3711
3712
3713var toStr = Object.prototype.toString;
3714
3715module.exports = function isArguments(value) {
3716 var str = toStr.call(value);
3717 var isArgs = str === '[object Arguments]';
3718 if (!isArgs) {
3719 isArgs = str !== '[object Array]' &&
3720 value !== null &&
3721 typeof value === 'object' &&
3722 typeof value.length === 'number' &&
3723 value.length >= 0 &&
3724 toStr.call(value.callee) === '[object Function]';
3725 }
3726 return isArgs;
3727};
3728
3729
3730/***/ }),
3731/* 49 */
3732/***/ (function(module, exports) {
3733
3734
3735var hasOwn = Object.prototype.hasOwnProperty;
3736var toString = Object.prototype.toString;
3737
3738module.exports = function forEach (obj, fn, ctx) {
3739 if (toString.call(fn) !== '[object Function]') {
3740 throw new TypeError('iterator must be a function');
3741 }
3742 var l = obj.length;
3743 if (l === +l) {
3744 for (var i = 0; i < l; i++) {
3745 fn.call(ctx, obj[i], i, obj);
3746 }
3747 } else {
3748 for (var k in obj) {
3749 if (hasOwn.call(obj, k)) {
3750 fn.call(ctx, obj[k], k, obj);
3751 }
3752 }
3753 }
3754};
3755
3756
3757
3758/***/ }),
3759/* 50 */
3760/***/ (function(module, exports, __webpack_require__) {
3761
3762"use strict";
3763
3764
3765var $isNaN = __webpack_require__(51);
3766var $isFinite = __webpack_require__(52);
3767
3768var sign = __webpack_require__(53);
3769var mod = __webpack_require__(54);
3770
3771var IsCallable = __webpack_require__(31);
3772var toPrimitive = __webpack_require__(55);
3773
3774var has = __webpack_require__(28);
3775
3776// https://es5.github.io/#x9
3777var ES5 = {
3778 ToPrimitive: toPrimitive,
3779
3780 ToBoolean: function ToBoolean(value) {
3781 return !!value;
3782 },
3783 ToNumber: function ToNumber(value) {
3784 return Number(value);
3785 },
3786 ToInteger: function ToInteger(value) {
3787 var number = this.ToNumber(value);
3788 if ($isNaN(number)) { return 0; }
3789 if (number === 0 || !$isFinite(number)) { return number; }
3790 return sign(number) * Math.floor(Math.abs(number));
3791 },
3792 ToInt32: function ToInt32(x) {
3793 return this.ToNumber(x) >> 0;
3794 },
3795 ToUint32: function ToUint32(x) {
3796 return this.ToNumber(x) >>> 0;
3797 },
3798 ToUint16: function ToUint16(value) {
3799 var number = this.ToNumber(value);
3800 if ($isNaN(number) || number === 0 || !$isFinite(number)) { return 0; }
3801 var posInt = sign(number) * Math.floor(Math.abs(number));
3802 return mod(posInt, 0x10000);
3803 },
3804 ToString: function ToString(value) {
3805 return String(value);
3806 },
3807 ToObject: function ToObject(value) {
3808 this.CheckObjectCoercible(value);
3809 return Object(value);
3810 },
3811 CheckObjectCoercible: function CheckObjectCoercible(value, optMessage) {
3812 /* jshint eqnull:true */
3813 if (value == null) {
3814 throw new TypeError(optMessage || 'Cannot call method on ' + value);
3815 }
3816 return value;
3817 },
3818 IsCallable: IsCallable,
3819 SameValue: function SameValue(x, y) {
3820 if (x === y) { // 0 === -0, but they are not identical.
3821 if (x === 0) { return 1 / x === 1 / y; }
3822 return true;
3823 }
3824 return $isNaN(x) && $isNaN(y);
3825 },
3826
3827 // http://www.ecma-international.org/ecma-262/5.1/#sec-8
3828 Type: function Type(x) {
3829 if (x === null) {
3830 return 'Null';
3831 }
3832 if (typeof x === 'undefined') {
3833 return 'Undefined';
3834 }
3835 if (typeof x === 'function' || typeof x === 'object') {
3836 return 'Object';
3837 }
3838 if (typeof x === 'number') {
3839 return 'Number';
3840 }
3841 if (typeof x === 'boolean') {
3842 return 'Boolean';
3843 }
3844 if (typeof x === 'string') {
3845 return 'String';
3846 }
3847 },
3848
3849 // http://ecma-international.org/ecma-262/6.0/#sec-property-descriptor-specification-type
3850 IsPropertyDescriptor: function IsPropertyDescriptor(Desc) {
3851 if (this.Type(Desc) !== 'Object') {
3852 return false;
3853 }
3854 var allowed = {
3855 '[[Configurable]]': true,
3856 '[[Enumerable]]': true,
3857 '[[Get]]': true,
3858 '[[Set]]': true,
3859 '[[Value]]': true,
3860 '[[Writable]]': true
3861 };
3862 // jscs:disable
3863 for (var key in Desc) { // eslint-disable-line
3864 if (has(Desc, key) && !allowed[key]) {
3865 return false;
3866 }
3867 }
3868 // jscs:enable
3869 var isData = has(Desc, '[[Value]]');
3870 var IsAccessor = has(Desc, '[[Get]]') || has(Desc, '[[Set]]');
3871 if (isData && IsAccessor) {
3872 throw new TypeError('Property Descriptors may not be both accessor and data descriptors');
3873 }
3874 return true;
3875 },
3876
3877 // http://ecma-international.org/ecma-262/5.1/#sec-8.10.1
3878 IsAccessorDescriptor: function IsAccessorDescriptor(Desc) {
3879 if (typeof Desc === 'undefined') {
3880 return false;
3881 }
3882
3883 if (!this.IsPropertyDescriptor(Desc)) {
3884 throw new TypeError('Desc must be a Property Descriptor');
3885 }
3886
3887 if (!has(Desc, '[[Get]]') && !has(Desc, '[[Set]]')) {
3888 return false;
3889 }
3890
3891 return true;
3892 },
3893
3894 // http://ecma-international.org/ecma-262/5.1/#sec-8.10.2
3895 IsDataDescriptor: function IsDataDescriptor(Desc) {
3896 if (typeof Desc === 'undefined') {
3897 return false;
3898 }
3899
3900 if (!this.IsPropertyDescriptor(Desc)) {
3901 throw new TypeError('Desc must be a Property Descriptor');
3902 }
3903
3904 if (!has(Desc, '[[Value]]') && !has(Desc, '[[Writable]]')) {
3905 return false;
3906 }
3907
3908 return true;
3909 },
3910
3911 // http://ecma-international.org/ecma-262/5.1/#sec-8.10.3
3912 IsGenericDescriptor: function IsGenericDescriptor(Desc) {
3913 if (typeof Desc === 'undefined') {
3914 return false;
3915 }
3916
3917 if (!this.IsPropertyDescriptor(Desc)) {
3918 throw new TypeError('Desc must be a Property Descriptor');
3919 }
3920
3921 if (!this.IsAccessorDescriptor(Desc) && !this.IsDataDescriptor(Desc)) {
3922 return true;
3923 }
3924
3925 return false;
3926 },
3927
3928 // http://ecma-international.org/ecma-262/5.1/#sec-8.10.4
3929 FromPropertyDescriptor: function FromPropertyDescriptor(Desc) {
3930 if (typeof Desc === 'undefined') {
3931 return Desc;
3932 }
3933
3934 if (!this.IsPropertyDescriptor(Desc)) {
3935 throw new TypeError('Desc must be a Property Descriptor');
3936 }
3937
3938 if (this.IsDataDescriptor(Desc)) {
3939 return {
3940 value: Desc['[[Value]]'],
3941 writable: !!Desc['[[Writable]]'],
3942 enumerable: !!Desc['[[Enumerable]]'],
3943 configurable: !!Desc['[[Configurable]]']
3944 };
3945 } else if (this.IsAccessorDescriptor(Desc)) {
3946 return {
3947 get: Desc['[[Get]]'],
3948 set: Desc['[[Set]]'],
3949 enumerable: !!Desc['[[Enumerable]]'],
3950 configurable: !!Desc['[[Configurable]]']
3951 };
3952 } else {
3953 throw new TypeError('FromPropertyDescriptor must be called with a fully populated Property Descriptor');
3954 }
3955 },
3956
3957 // http://ecma-international.org/ecma-262/5.1/#sec-8.10.5
3958 ToPropertyDescriptor: function ToPropertyDescriptor(Obj) {
3959 if (this.Type(Obj) !== 'Object') {
3960 throw new TypeError('ToPropertyDescriptor requires an object');
3961 }
3962
3963 var desc = {};
3964 if (has(Obj, 'enumerable')) {
3965 desc['[[Enumerable]]'] = this.ToBoolean(Obj.enumerable);
3966 }
3967 if (has(Obj, 'configurable')) {
3968 desc['[[Configurable]]'] = this.ToBoolean(Obj.configurable);
3969 }
3970 if (has(Obj, 'value')) {
3971 desc['[[Value]]'] = Obj.value;
3972 }
3973 if (has(Obj, 'writable')) {
3974 desc['[[Writable]]'] = this.ToBoolean(Obj.writable);
3975 }
3976 if (has(Obj, 'get')) {
3977 var getter = Obj.get;
3978 if (typeof getter !== 'undefined' && !this.IsCallable(getter)) {
3979 throw new TypeError('getter must be a function');
3980 }
3981 desc['[[Get]]'] = getter;
3982 }
3983 if (has(Obj, 'set')) {
3984 var setter = Obj.set;
3985 if (typeof setter !== 'undefined' && !this.IsCallable(setter)) {
3986 throw new TypeError('setter must be a function');
3987 }
3988 desc['[[Set]]'] = setter;
3989 }
3990
3991 if ((has(desc, '[[Get]]') || has(desc, '[[Set]]')) && (has(desc, '[[Value]]') || has(desc, '[[Writable]]'))) {
3992 throw new TypeError('Invalid property descriptor. Cannot both specify accessors and a value or writable attribute');
3993 }
3994 return desc;
3995 }
3996};
3997
3998module.exports = ES5;
3999
4000
4001/***/ }),
4002/* 51 */
4003/***/ (function(module, exports) {
4004
4005module.exports = Number.isNaN || function isNaN(a) {
4006 return a !== a;
4007};
4008
4009
4010/***/ }),
4011/* 52 */
4012/***/ (function(module, exports) {
4013
4014var $isNaN = Number.isNaN || function (a) { return a !== a; };
4015
4016module.exports = Number.isFinite || function (x) { return typeof x === 'number' && !$isNaN(x) && x !== Infinity && x !== -Infinity; };
4017
4018
4019/***/ }),
4020/* 53 */
4021/***/ (function(module, exports) {
4022
4023module.exports = function sign(number) {
4024 return number >= 0 ? 1 : -1;
4025};
4026
4027
4028/***/ }),
4029/* 54 */
4030/***/ (function(module, exports) {
4031
4032module.exports = function mod(number, modulo) {
4033 var remain = number % modulo;
4034 return Math.floor(remain >= 0 ? remain : remain + modulo);
4035};
4036
4037
4038/***/ }),
4039/* 55 */
4040/***/ (function(module, exports, __webpack_require__) {
4041
4042"use strict";
4043
4044
4045var toStr = Object.prototype.toString;
4046
4047var isPrimitive = __webpack_require__(56);
4048
4049var isCallable = __webpack_require__(31);
4050
4051// https://es5.github.io/#x8.12
4052var ES5internalSlots = {
4053 '[[DefaultValue]]': function (O, hint) {
4054 var actualHint = hint || (toStr.call(O) === '[object Date]' ? String : Number);
4055
4056 if (actualHint === String || actualHint === Number) {
4057 var methods = actualHint === String ? ['toString', 'valueOf'] : ['valueOf', 'toString'];
4058 var value, i;
4059 for (i = 0; i < methods.length; ++i) {
4060 if (isCallable(O[methods[i]])) {
4061 value = O[methods[i]]();
4062 if (isPrimitive(value)) {
4063 return value;
4064 }
4065 }
4066 }
4067 throw new TypeError('No default value');
4068 }
4069 throw new TypeError('invalid [[DefaultValue]] hint supplied');
4070 }
4071};
4072
4073// https://es5.github.io/#x9
4074module.exports = function ToPrimitive(input, PreferredType) {
4075 if (isPrimitive(input)) {
4076 return input;
4077 }
4078 return ES5internalSlots['[[DefaultValue]]'](input, PreferredType);
4079};
4080
4081
4082/***/ }),
4083/* 56 */
4084/***/ (function(module, exports) {
4085
4086module.exports = function isPrimitive(value) {
4087 return value === null || (typeof value !== 'function' && typeof value !== 'object');
4088};
4089
4090
4091/***/ }),
4092/* 57 */
4093/***/ (function(module, exports, __webpack_require__) {
4094
4095"use strict";
4096
4097
4098var define = __webpack_require__(29);
4099var getPolyfill = __webpack_require__(32);
4100
4101module.exports = function shimStringTrim() {
4102 var polyfill = getPolyfill();
4103 define(String.prototype, { trim: polyfill }, { trim: function () { return String.prototype.trim !== polyfill; } });
4104 return polyfill;
4105};
4106
4107
4108/***/ }),
4109/* 58 */
4110/***/ (function(module, exports, __webpack_require__) {
4111
4112
4113/**
4114 * This is the common logic for both the Node.js and web browser
4115 * implementations of `debug()`.
4116 *
4117 * Expose `debug()` as the module.
4118 */
4119
4120exports = module.exports = createDebug.debug = createDebug['default'] = createDebug;
4121exports.coerce = coerce;
4122exports.disable = disable;
4123exports.enable = enable;
4124exports.enabled = enabled;
4125exports.humanize = __webpack_require__(59);
4126
4127/**
4128 * Active `debug` instances.
4129 */
4130exports.instances = [];
4131
4132/**
4133 * The currently active debug mode names, and names to skip.
4134 */
4135
4136exports.names = [];
4137exports.skips = [];
4138
4139/**
4140 * Map of special "%n" handling functions, for the debug "format" argument.
4141 *
4142 * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
4143 */
4144
4145exports.formatters = {};
4146
4147/**
4148 * Select a color.
4149 * @param {String} namespace
4150 * @return {Number}
4151 * @api private
4152 */
4153
4154function selectColor(namespace) {
4155 var hash = 0, i;
4156
4157 for (i in namespace) {
4158 hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
4159 hash |= 0; // Convert to 32bit integer
4160 }
4161
4162 return exports.colors[Math.abs(hash) % exports.colors.length];
4163}
4164
4165/**
4166 * Create a debugger with the given `namespace`.
4167 *
4168 * @param {String} namespace
4169 * @return {Function}
4170 * @api public
4171 */
4172
4173function createDebug(namespace) {
4174
4175 var prevTime;
4176
4177 function debug() {
4178 // disabled?
4179 if (!debug.enabled) return;
4180
4181 var self = debug;
4182
4183 // set `diff` timestamp
4184 var curr = +new Date();
4185 var ms = curr - (prevTime || curr);
4186 self.diff = ms;
4187 self.prev = prevTime;
4188 self.curr = curr;
4189 prevTime = curr;
4190
4191 // turn the `arguments` into a proper Array
4192 var args = new Array(arguments.length);
4193 for (var i = 0; i < args.length; i++) {
4194 args[i] = arguments[i];
4195 }
4196
4197 args[0] = exports.coerce(args[0]);
4198
4199 if ('string' !== typeof args[0]) {
4200 // anything else let's inspect with %O
4201 args.unshift('%O');
4202 }
4203
4204 // apply any `formatters` transformations
4205 var index = 0;
4206 args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
4207 // if we encounter an escaped % then don't increase the array index
4208 if (match === '%%') return match;
4209 index++;
4210 var formatter = exports.formatters[format];
4211 if ('function' === typeof formatter) {
4212 var val = args[index];
4213 match = formatter.call(self, val);
4214
4215 // now we need to remove `args[index]` since it's inlined in the `format`
4216 args.splice(index, 1);
4217 index--;
4218 }
4219 return match;
4220 });
4221
4222 // apply env-specific formatting (colors, etc.)
4223 exports.formatArgs.call(self, args);
4224
4225 var logFn = debug.log || exports.log || console.log.bind(console);
4226 logFn.apply(self, args);
4227 }
4228
4229 debug.namespace = namespace;
4230 debug.enabled = exports.enabled(namespace);
4231 debug.useColors = exports.useColors();
4232 debug.color = selectColor(namespace);
4233 debug.destroy = destroy;
4234
4235 // env-specific initialization logic for debug instances
4236 if ('function' === typeof exports.init) {
4237 exports.init(debug);
4238 }
4239
4240 exports.instances.push(debug);
4241
4242 return debug;
4243}
4244
4245function destroy () {
4246 var index = exports.instances.indexOf(this);
4247 if (index !== -1) {
4248 exports.instances.splice(index, 1);
4249 return true;
4250 } else {
4251 return false;
4252 }
4253}
4254
4255/**
4256 * Enables a debug mode by namespaces. This can include modes
4257 * separated by a colon and wildcards.
4258 *
4259 * @param {String} namespaces
4260 * @api public
4261 */
4262
4263function enable(namespaces) {
4264 exports.save(namespaces);
4265
4266 exports.names = [];
4267 exports.skips = [];
4268
4269 var i;
4270 var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
4271 var len = split.length;
4272
4273 for (i = 0; i < len; i++) {
4274 if (!split[i]) continue; // ignore empty strings
4275 namespaces = split[i].replace(/\*/g, '.*?');
4276 if (namespaces[0] === '-') {
4277 exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
4278 } else {
4279 exports.names.push(new RegExp('^' + namespaces + '$'));
4280 }
4281 }
4282
4283 for (i = 0; i < exports.instances.length; i++) {
4284 var instance = exports.instances[i];
4285 instance.enabled = exports.enabled(instance.namespace);
4286 }
4287}
4288
4289/**
4290 * Disable debug output.
4291 *
4292 * @api public
4293 */
4294
4295function disable() {
4296 exports.enable('');
4297}
4298
4299/**
4300 * Returns true if the given mode name is enabled, false otherwise.
4301 *
4302 * @param {String} name
4303 * @return {Boolean}
4304 * @api public
4305 */
4306
4307function enabled(name) {
4308 if (name[name.length - 1] === '*') {
4309 return true;
4310 }
4311 var i, len;
4312 for (i = 0, len = exports.skips.length; i < len; i++) {
4313 if (exports.skips[i].test(name)) {
4314 return false;
4315 }
4316 }
4317 for (i = 0, len = exports.names.length; i < len; i++) {
4318 if (exports.names[i].test(name)) {
4319 return true;
4320 }
4321 }
4322 return false;
4323}
4324
4325/**
4326 * Coerce `val`.
4327 *
4328 * @param {Mixed} val
4329 * @return {Mixed}
4330 * @api private
4331 */
4332
4333function coerce(val) {
4334 if (val instanceof Error) return val.stack || val.message;
4335 return val;
4336}
4337
4338
4339/***/ }),
4340/* 59 */
4341/***/ (function(module, exports) {
4342
4343/**
4344 * Helpers.
4345 */
4346
4347var s = 1000;
4348var m = s * 60;
4349var h = m * 60;
4350var d = h * 24;
4351var y = d * 365.25;
4352
4353/**
4354 * Parse or format the given `val`.
4355 *
4356 * Options:
4357 *
4358 * - `long` verbose formatting [false]
4359 *
4360 * @param {String|Number} val
4361 * @param {Object} [options]
4362 * @throws {Error} throw an error if val is not a non-empty string or a number
4363 * @return {String|Number}
4364 * @api public
4365 */
4366
4367module.exports = function(val, options) {
4368 options = options || {};
4369 var type = typeof val;
4370 if (type === 'string' && val.length > 0) {
4371 return parse(val);
4372 } else if (type === 'number' && isNaN(val) === false) {
4373 return options.long ? fmtLong(val) : fmtShort(val);
4374 }
4375 throw new Error(
4376 'val is not a non-empty string or a valid number. val=' +
4377 JSON.stringify(val)
4378 );
4379};
4380
4381/**
4382 * Parse the given `str` and return milliseconds.
4383 *
4384 * @param {String} str
4385 * @return {Number}
4386 * @api private
4387 */
4388
4389function parse(str) {
4390 str = String(str);
4391 if (str.length > 100) {
4392 return;
4393 }
4394 var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(
4395 str
4396 );
4397 if (!match) {
4398 return;
4399 }
4400 var n = parseFloat(match[1]);
4401 var type = (match[2] || 'ms').toLowerCase();
4402 switch (type) {
4403 case 'years':
4404 case 'year':
4405 case 'yrs':
4406 case 'yr':
4407 case 'y':
4408 return n * y;
4409 case 'days':
4410 case 'day':
4411 case 'd':
4412 return n * d;
4413 case 'hours':
4414 case 'hour':
4415 case 'hrs':
4416 case 'hr':
4417 case 'h':
4418 return n * h;
4419 case 'minutes':
4420 case 'minute':
4421 case 'mins':
4422 case 'min':
4423 case 'm':
4424 return n * m;
4425 case 'seconds':
4426 case 'second':
4427 case 'secs':
4428 case 'sec':
4429 case 's':
4430 return n * s;
4431 case 'milliseconds':
4432 case 'millisecond':
4433 case 'msecs':
4434 case 'msec':
4435 case 'ms':
4436 return n;
4437 default:
4438 return undefined;
4439 }
4440}
4441
4442/**
4443 * Short format for `ms`.
4444 *
4445 * @param {Number} ms
4446 * @return {String}
4447 * @api private
4448 */
4449
4450function fmtShort(ms) {
4451 if (ms >= d) {
4452 return Math.round(ms / d) + 'd';
4453 }
4454 if (ms >= h) {
4455 return Math.round(ms / h) + 'h';
4456 }
4457 if (ms >= m) {
4458 return Math.round(ms / m) + 'm';
4459 }
4460 if (ms >= s) {
4461 return Math.round(ms / s) + 's';
4462 }
4463 return ms + 'ms';
4464}
4465
4466/**
4467 * Long format for `ms`.
4468 *
4469 * @param {Number} ms
4470 * @return {String}
4471 * @api private
4472 */
4473
4474function fmtLong(ms) {
4475 return plural(ms, d, 'day') ||
4476 plural(ms, h, 'hour') ||
4477 plural(ms, m, 'minute') ||
4478 plural(ms, s, 'second') ||
4479 ms + ' ms';
4480}
4481
4482/**
4483 * Pluralization helper.
4484 */
4485
4486function plural(ms, n, name) {
4487 if (ms < n) {
4488 return;
4489 }
4490 if (ms < n * 1.5) {
4491 return Math.floor(ms / n) + ' ' + name;
4492 }
4493 return Math.ceil(ms / n) + ' ' + name + 's';
4494}
4495
4496
4497/***/ }),
4498/* 60 */
4499/***/ (function(module, exports, __webpack_require__) {
4500
4501/* WEBPACK VAR INJECTION */(function(global) {var Service = __webpack_require__(12);
4502var Products = __webpack_require__(61);
4503var Orders = __webpack_require__(77);
4504var Cart = __webpack_require__(79);
4505var Customers = __webpack_require__(81);
4506var Coupons = __webpack_require__(83);
4507var Settings = __webpack_require__(37);
4508var SettingsCollection = __webpack_require__(85);
4509var Gateways = __webpack_require__(86);
4510var FilteredCollection = __webpack_require__(36);
4511var debug = __webpack_require__(8)('entities');
4512var App = __webpack_require__(1);
4513var _ = __webpack_require__(0);
4514var storage = global.localStorage || window.localStorage;
4515var JSON = global.JSON || window.JSON;
4516
4517var EntitiesService = Service.extend({
4518 channelName: 'entities',
4519
4520 initialize: function() {
4521 this.channel.reply('get', this.get, this);
4522 this.channel.reply('set', this.set, this);
4523 this.channel.reply('remove', this.remove, this);
4524 this.channel.reply('set:filter', this.setFilter, this);
4525 },
4526
4527 collections: {
4528 products : Products,
4529 orders : Orders,
4530 cart : Cart,
4531 customers : Customers,
4532 coupons : Coupons,
4533 gateways : Gateways,
4534 settings : SettingsCollection
4535 },
4536
4537 getMethods: {
4538 collection : 'getCollection',
4539 model : 'getModel',
4540 filtered : 'getFiltered',
4541 option : 'getOption',
4542 settings : 'getSettings',
4543 localStorage: 'getLocalStorage'
4544 },
4545
4546 setMethods: {
4547 localStorage: 'setLocalStorage'
4548 },
4549
4550 get: function(options){
4551 options = options || {};
4552 var method = this.getMethods[options.type];
4553 if( this[method] ){
4554 return this[method](options);
4555 }
4556 debug('request needs a type, eg: "collection" or "option"');
4557 },
4558
4559 set: function(options){
4560 options = options || {};
4561 var method = this.setMethods[options.type];
4562 if( this[method] ){
4563 return this[method](options);
4564 }
4565 debug('set needs a type, eg: "localStorage"');
4566 },
4567
4568 /**
4569 * init a new collection, attach to this and return a reference
4570 */
4571 attach: function(options){
4572 var type = options.type === 'model' ? 'models' : 'collections',
4573 prop = '_' + options.name;
4574 if( this[type].hasOwnProperty(options.name) ){
4575 this[prop] = new this[type][options.name]([], options);
4576 }
4577 return this[prop];
4578 },
4579
4580 /**
4581 * return a reference to the collection
4582 */
4583 getCollection: function(options){
4584 var prop = '_' + options.name;
4585 if( options.init ) {
4586 return new this.collections[options.name]([], options);
4587 }
4588 return ( this[prop] || this.attach(options) );
4589 },
4590
4591 getAllCollections: function(){
4592 return _.reduce( this.collections, function(result, col, key){
4593 result[key] = this.getCollection({ name: key });
4594 return result;
4595 }, {}, this);
4596 },
4597
4598 getModel: function(options){
4599 var prop = '_' + options.name;
4600 if( options.init ) {
4601 return new this.models[options.name]([], options);
4602 }
4603 return ( this[prop] || this.attach(options) );
4604 },
4605
4606 /**
4607 * return a filtered collection and attach to this
4608 */
4609 getFiltered: function(options){
4610 var prop = '_' + options.name;
4611 var filteredProp = '_filtered' + options.name;
4612 if( this[filteredProp] ){ return this[filteredProp]; }
4613 if( !this[prop] ){ this.attach(options); }
4614
4615 this[filteredProp] = new FilteredCollection(this[prop], options);
4616 return this[filteredProp];
4617 },
4618
4619 /**
4620 * return an option set during app.start(options)
4621 */
4622 getOption: function(options){
4623 return this.app.getOption(options.name);
4624 },
4625
4626 /**
4627 * settings are App options that can be changed by the user
4628 * eg: HotKeys are bootstrapped as start options, but also
4629 * can be updated through the POS
4630 */
4631 getSettings: function(options){
4632 var option = this.app.getOption(options.name);
4633 return new Settings(option);
4634 },
4635
4636 setFilter: function(options){
4637 options = options || {};
4638 var filteredProp = '_filtered' + options.name;
4639 if( this[filteredProp] ){
4640 this[filteredProp].filterBy('search', options.filter);
4641 }
4642 },
4643
4644 serialize: function(value){
4645 return JSON.stringify(value);
4646 },
4647
4648 deserialize: function(value){
4649 try { value = JSON.parse(value); }
4650 catch(e) { debug(e); }
4651 return value || undefined;
4652 },
4653
4654 getLocalStorage: function(options){
4655 options = options || {};
4656 var data = storage.getItem('wc_pos_' + options.name);
4657 var obj = this.deserialize(data);
4658 if(options.key && obj && obj[options.key]){
4659 return obj[options.key];
4660 }
4661 return obj;
4662 },
4663
4664 setLocalStorage: function(options){
4665 options = options || {};
4666 var data = options.data;
4667 var old = this.getLocalStorage({name: options.name});
4668 if( _.isObject(old) && _.isObject(data) ){
4669 data = _.extend(old, data);
4670 }
4671 storage.setItem('wc_pos_' + options.name, this.serialize(data));
4672 },
4673
4674 remove: function(options){
4675 options = options || {};
4676 if(options.type === 'localStorage' && options.name && options.key){
4677 var data = this.getLocalStorage({name: options.name});
4678 delete data[options.key];
4679 storage.setItem('wc_pos_' + options.name, JSON.stringify(data));
4680 } else {
4681 storage.removeItem('wc_pos_' + options.name);
4682 }
4683 },
4684
4685 idbCollections: function(){
4686 return _.reduce( this.getAllCollections(), function(result, col, key){
4687 if( col instanceof App.IndexedDBCollection ){
4688 result[key] = col;
4689 }
4690 return result;
4691 }, {}, this);
4692 }
4693
4694});
4695
4696module.exports = EntitiesService;
4697App.prototype.set('Entities.Service', EntitiesService);
4698/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(33)))
4699
4700/***/ }),
4701/* 61 */
4702/***/ (function(module, exports, __webpack_require__) {
4703
4704var DualCollection = __webpack_require__(21);
4705var Model = __webpack_require__(64);
4706
4707module.exports = DualCollection.extend({
4708 model: Model,
4709 name: 'products'
4710});
4711
4712/***/ }),
4713/* 62 */
4714/***/ (function(module, exports, __webpack_require__) {
4715
4716/**
4717 * Backbone adapter for idb-wrapper api
4718 */
4719var IDBStore = __webpack_require__(63);
4720var $ = __webpack_require__(3);
4721var _ = __webpack_require__(0);
4722var bb = __webpack_require__(4);
4723var noop = function (){};
4724var defaultErrorHandler = function (error) {
4725 throw error;
4726};
4727
4728function IndexedDB(options, parent) {
4729 this.parent = parent;
4730 this.options = options;
4731 if(options.defaultErrorHandler){
4732 defaultErrorHandler = options.defaultErrorHandler;
4733 }
4734}
4735
4736var methods = {
4737
4738 /**
4739 *
4740 */
4741 open: function () {
4742 if(this._open){
4743 return this._open;
4744 }
4745 var deferred = new $.Deferred(),
4746 options = this.options || {};
4747
4748 options.onStoreReady = deferred.resolve;
4749 options.onError = deferred.reject;
4750
4751 this.store = new IDBStore(options);
4752
4753 this._open = deferred.promise();
4754 return this._open;
4755 },
4756
4757 /**
4758 * Add a new model to the store
4759 */
4760 create: function(model, options) {
4761 options = options || {};
4762 var onSuccess = options.success || noop,
4763 onError = options.error || defaultErrorHandler,
4764 data = this._returnAttributes(model),
4765 keyPath = this.store.keyPath;
4766
4767 return this.put(data)
4768 .then(function(insertedId){
4769 data[keyPath] = insertedId;
4770 onSuccess(data);
4771 return data;
4772 })
4773 .fail(onError);
4774 },
4775
4776 /**
4777 * Update a model in the store
4778 */
4779 update: function(model, options) {
4780 options = options || {};
4781 var onSuccess = options.success || noop,
4782 onError = options.error || defaultErrorHandler,
4783 data = this._returnAttributes(model),
4784 self = this;
4785
4786 return this.put(data)
4787 .then(function(insertedId){
4788 return self.get(insertedId)
4789 .done(onSuccess)
4790 .fail(onError);
4791 })
4792 .fail(onError);
4793 },
4794
4795 /**
4796 * Retrieve a model from the store
4797 */
4798 read: function(model, options) {
4799 options = options || {};
4800 var onSuccess = options.success || noop,
4801 onError = options.error || defaultErrorHandler;
4802 return this.get(model.id)
4803 .done(onSuccess)
4804 .fail(onError);
4805 },
4806
4807 /**
4808 * Delete a model from the store
4809 */
4810 destroy: function(model, options) {
4811 if (model.isNew()) {
4812 return false;
4813 }
4814 options = options || {};
4815 var onSuccess = options.success || noop,
4816 onError = options.error || defaultErrorHandler;
4817
4818 return this.remove(model.id)
4819 .done(onSuccess)
4820 .fail(onError);
4821 },
4822
4823 /**
4824 *
4825 */
4826 put: function (key, value) {
4827 var deferred = new $.Deferred();
4828
4829 if (this.store.keyPath !== null) {
4830 // in-line keys: one arg only (key == value)
4831 this.store.put(key, deferred.resolve, deferred.reject);
4832 } else {
4833 // out-of-line keys: two args
4834 this.store.put(key, value, deferred.resolve, deferred.reject);
4835 }
4836
4837 return deferred.promise();
4838 },
4839
4840 /**
4841 *
4842 */
4843 get: function (key) {
4844 var deferred = new $.Deferred();
4845 this.store.get(key, deferred.resolve, deferred.reject);
4846 return deferred.promise();
4847 },
4848
4849 /**
4850 *
4851 */
4852 remove: function(key){
4853 if( _.isObject(key) && key.hasOwnProperty(this.store.keyPath) ) {
4854 key = key[this.store.keyPath];
4855 }
4856 return this._remove(key);
4857 },
4858
4859 _remove: function (key) {
4860 var deferred = new $.Deferred();
4861 this.store.remove(key, deferred.resolve, deferred.reject);
4862 return deferred.promise();
4863 },
4864
4865 /**
4866 * Retrieve a collection from the store
4867 */
4868 getAll: function(options) {
4869 var deferred = new $.Deferred();
4870
4871 var onSuccess = function (result) {
4872 options.success.apply(this, arguments);
4873 deferred.resolve(result);
4874 };
4875
4876 var onError = function (result) {
4877 options.error.apply(this, arguments);
4878 deferred.reject(result);
4879 };
4880
4881 this.store.getAll(onSuccess, onError);
4882
4883 return deferred.promise();
4884 },
4885
4886 /**
4887 * Iterates over the store using the given options and calling onItem
4888 * for each entry matching the options.
4889 */
4890 iterate: function(options) {
4891 options = options || {};
4892 var deferred = new $.Deferred();
4893 options.onEnd = deferred.resolve;
4894 options.onError = deferred.reject;
4895 var onItem = deferred.notify;
4896 this.store.iterate(onItem, options);
4897 return deferred.promise();
4898 },
4899
4900 /**
4901 * Creates a key range using specified options. This key range can be
4902 * handed over to the count() and iterate() methods.
4903 *
4904 * Note: You must provide at least one or both of "lower" or "upper" value.
4905 */
4906 makeKeyRange: function(options) {
4907 return this.store.makeKeyRange(options);
4908 },
4909
4910 /**
4911 * Perform a batch operation to save all models in the current collection to
4912 * indexedDB.
4913 */
4914 saveAll: function() {
4915 return this.putBatch(this.parent.toJSON());
4916 },
4917
4918 /**
4919 * Perform a batch operation to save and/or remove models in the current
4920 * collection to indexedDB. This is a proxy to the idbstore `batch` method
4921 */
4922 batch: function(dataArray) {
4923 var deferred = new $.Deferred();
4924 this.store.batch(dataArray, deferred.resolve, deferred.reject);
4925 return deferred.promise();
4926 },
4927
4928 /**
4929 * Perform a batch put operation to save models to indexedDB. This is a
4930 * proxy to the idbstore `putBatch` method
4931 */
4932 putBatch: function(dataArray) {
4933 if( !_.isArray(dataArray) ){
4934 return this.put(dataArray);
4935 }
4936 return this._putBatch(dataArray);
4937 },
4938
4939 _putBatch: function(dataArray) {
4940 var deferred = new $.Deferred();
4941 this.store.putBatch(dataArray, deferred.resolve, deferred.reject);
4942 return deferred.promise();
4943 },
4944
4945 /**
4946 * Perform a batch operation to remove models from indexedDB. This is a
4947 * proxy to the idbstore `removeBatch` method
4948 */
4949 removeBatch: function(keyArray) {
4950 if( !_.isArray(keyArray) ){
4951 return this.remove(keyArray);
4952 }
4953 return this._removeBatch(keyArray);
4954 },
4955
4956 _removeBatch: function(keyArray){
4957 var deferred = new $.Deferred();
4958 this.store.removeBatch(keyArray, deferred.resolve, deferred.reject);
4959 return deferred.promise();
4960 },
4961
4962 /**
4963 * Clears all content from the current indexedDB for this collection/model
4964 */
4965 clear: function() {
4966 var deferred = new $.Deferred();
4967 this.store.clear(deferred.resolve, deferred.reject);
4968 return deferred.promise();
4969 },
4970
4971 /**
4972 *
4973 */
4974 query: function(index, keyRange){
4975 var deferred = new $.Deferred();
4976
4977 this.store.query(deferred.resolve, {
4978 index: index,
4979 keyRange: keyRange,
4980 onError: deferred.reject
4981 });
4982
4983 return deferred.promise();
4984 },
4985
4986 /**
4987 * select records by {key: value}
4988 */
4989 getByAttribute: function(attribute){
4990 var index = _.chain(attribute).keys().first().value();
4991 var keyRange = this.store.makeKeyRange({
4992 only: _.chain(attribute).values().first().value()
4993 });
4994 return this.query(index, keyRange);
4995 },
4996
4997 merge: function(models){
4998 models = !_.isArray(models) ? [models] : models;
4999 if(!this.parent.mergeKeyPath){
5000 return this.putBatch(models);
5001 }
5002 var merge = _.map(models, this._merge, this);
5003 return $.when.apply(this, merge);
5004 },
5005
5006 _merge: function(model){
5007 var mergeKeyPath = this.parent.mergeKeyPath,
5008 keyPath = this.store.keyPath,
5009 self = this,
5010 opts = {};
5011
5012 if(model[keyPath]){
5013 return this.update(model);
5014 }
5015
5016 opts[mergeKeyPath] = model[mergeKeyPath];
5017
5018 return this.getByAttribute(opts)
5019 .then(function(array){
5020 var local = _.first(array);
5021 if(local){
5022 model[keyPath] = local[keyPath];
5023 return self.update(model);
5024 }
5025 return self.create(model);
5026 });
5027 },
5028
5029 _returnAttributes: function(model){
5030 if(model instanceof bb.Model){
5031 return model.toJSON();
5032 }
5033 return model;
5034 }
5035};
5036
5037_.extend(IndexedDB.prototype, methods);
5038module.exports = IndexedDB;
5039
5040/***/ }),
5041/* 63 */
5042/***/ (function(module, exports) {
5043
5044module.exports = IDBStore;
5045
5046/***/ }),
5047/* 64 */
5048/***/ (function(module, exports, __webpack_require__) {
5049
5050var DualModel = __webpack_require__(22);
5051var _ = __webpack_require__(0);
5052var Variations = __webpack_require__(66);
5053var FilteredCollection = __webpack_require__(36);
5054
5055module.exports = DualModel.extend({
5056 name: 'product',
5057
5058 // this is an array of fields used by FilterCollection.matchmaker()
5059 fields: ['name'],
5060
5061 // data types
5062 schema: {
5063 price : 'number',
5064 regular_price : 'number',
5065 sale_price : 'number',
5066 stock_quantity: 'number'
5067 },
5068
5069 initialize: function(){
5070 this.on({
5071 'change:updated_at': this.onUpdate
5072 });
5073 },
5074
5075 onUpdate: function(){
5076 // update stock
5077 if( this.get('type') === 'variable' ){
5078 var variations = this.getVariations().superset();
5079 variations.set( this.get('variations') );
5080 }
5081 },
5082
5083 /**
5084 * Helper functions to display attributes vs variations
5085 */
5086 productAttributes: function(){
5087 return _.chain(this.get('attributes'))
5088 .where({variation: false})
5089 .where({visible: true})
5090 .value();
5091 },
5092
5093 productVariations: function(){
5094 return _.where(this.get('attributes'), {variation: true});
5095 },
5096
5097 /**
5098 * Special cases for product model filter
5099 * @param {Array} tokens An array of query tokens, see QParser
5100 * @param {Object} methods Helper match methods
5101 * @param {Function} callback
5102 */
5103 matchMaker: function(tokens, methods, callback){
5104
5105 var match = _.all(tokens, function(token){
5106
5107 // barcode
5108 if( token.type === 'prefix' && token.prefix === 'barcode' ){
5109 if(token.query){ return this.barcodeMatch(token.query); }
5110 }
5111
5112 // cat
5113 if( token.type === 'prefix' && token.prefix === 'cat' ){
5114 token.prefix = 'categories';
5115 return methods.prefix(token, this);
5116 }
5117
5118 }, this);
5119
5120 //if(match){
5121 // return match;
5122 //}
5123
5124 // the original matchMaker
5125 return match ? match : callback(tokens, this);
5126
5127 },
5128
5129 barcodeMatch: function(barcode){
5130 var type = this.get('type'),
5131 test = this.get('barcode').toLowerCase(),
5132 value = barcode.toString().toLowerCase();
5133
5134 if(test === value) {
5135 if(type !== 'variable'){
5136 this.trigger('match:barcode', this);
5137 }
5138 return true;
5139 }
5140
5141 if(type !== 'variable'){
5142 return this.partialBarcodeMatch(test, value);
5143 }
5144
5145 return this.variableBarcodeMatch(test, value);
5146 },
5147
5148 partialBarcodeMatch: function(test, value){
5149 if(test.indexOf( value ) !== -1) {
5150 return true;
5151 }
5152 return false;
5153 },
5154
5155 variableBarcodeMatch: function(test, value){
5156 var match;
5157
5158 this.getVariations().superset().each(function(variation){
5159 var vtest = variation.get('barcode').toLowerCase();
5160 if(vtest === value){
5161 match = variation;
5162 return;
5163 }
5164 if(vtest.indexOf( value ) !== -1) {
5165 match = 'partial';
5166 return;
5167 }
5168 });
5169
5170 if(match){
5171 if(match !== 'partial'){
5172 this.trigger('match:barcode', match, this);
5173 }
5174 return true;
5175 }
5176
5177 return this.partialBarcodeMatch(test, value);
5178 },
5179
5180 /**
5181 * Construct variable options from variation array
5182 * - variable.attributes includes all options, including those not used
5183 */
5184 getVariationOptions: function(){
5185 if( this._variationOptions ) {
5186 return this._variationOptions;
5187 }
5188
5189 var variations = this.get('variations');
5190
5191 // pluck all options, eg:
5192 // { Color: ['Black', 'Blue'], Size: ['Small', 'Large'] }
5193 var result = _.pluck(variations, 'attributes')
5194 .reduce(function(result, attrs){
5195 _.each(attrs, function(attr){
5196 if(result[attr.name]){
5197 return result[attr.name].push(attr.option);
5198 }
5199 result[attr.name] = [attr.option];
5200 });
5201 return result;
5202 }, {});
5203
5204 // map options with consistent keys
5205 this._variationOptions = _.map(result, function(options, name){
5206 return {
5207 'name': name,
5208 'options': _.uniq( options )
5209 };
5210 });
5211
5212 return this._variationOptions;
5213 },
5214
5215 /**
5216 *
5217 */
5218 getVariations: function(){
5219 if( this.get('type') !== 'variable' ){ return false; }
5220 if( ! this._variations ){
5221 var variations = new Variations(this.get('variations'), {
5222 parent: this,
5223 parentAttrs: this.attributes
5224 });
5225 this._variations = new FilteredCollection(variations);
5226 }
5227 return this._variations;
5228 }
5229
5230});
5231
5232/***/ }),
5233/* 65 */
5234/***/ (function(module, exports, __webpack_require__) {
5235
5236var _ = __webpack_require__(0);
5237
5238/**
5239 * Takes a nested object and returns a shallow object keyed with the path names
5240 * e.g. { "level1.level2": "value" }
5241 *
5242 * @param {Object} Nested object e.g. { level1: { level2: 'value' } }
5243 * @return {Object} Shallow object with path names e.g. { 'level1.level2': 'value' }
5244 */
5245function objToPaths(obj) {
5246 var ret = {},
5247 separator = DeepModel.keyPathSeparator;
5248
5249 for (var key in obj) {
5250 var val = obj[key];
5251
5252 if (val && (val.constructor === Object || val.constructor === Array) && !_.isEmpty(val)) {
5253 //Recursion for embedded objects
5254 var obj2 = objToPaths(val);
5255
5256 for (var key2 in obj2) {
5257 var val2 = obj2[key2];
5258
5259 ret[key + separator + key2] = val2;
5260 }
5261 } else {
5262 ret[key] = val;
5263 }
5264 }
5265
5266 return ret;
5267}
5268
5269/**
5270 * [getNested description]
5271 * @param {object} obj to fetch attribute from
5272 * @param {string} path path e.g. 'user.name'
5273 * @param {[type]} return_exists [description]
5274 * @return {mixed} [description]
5275 */
5276function getNested(obj, path, return_exists) {
5277 var separator = DeepModel.keyPathSeparator;
5278
5279 var fields = path ? path.split(separator) : [];
5280 var result = obj;
5281 return_exists || (return_exists === false);
5282 for (var i = 0, n = fields.length; i < n; i++) {
5283 if (return_exists && !_.has(result, fields[i])) {
5284 return false;
5285 }
5286 result = result[fields[i]];
5287
5288 if (result == null && i < n - 1) {
5289 result = {};
5290 }
5291
5292 if (typeof result === 'undefined') {
5293 if (return_exists) {
5294 return true;
5295 }
5296 return result;
5297 }
5298 }
5299 if (return_exists) {
5300 return true;
5301 }
5302 return result;
5303}
5304
5305
5306
5307/**
5308 * @param {Object} obj Object to fetch attribute from
5309 * @param {String} path Object path e.g. 'user.name'
5310 * @param {Object} [options] Options
5311 * @param {Boolean} [options.unset] Whether to delete the value
5312 * @param {Mixed} Value to set
5313 */
5314function setNested(obj, path, val, options) {
5315 options = options || {};
5316
5317 var separator = DeepModel.keyPathSeparator;
5318
5319 var fields = path ? path.split(separator) : [];
5320 var result = obj;
5321 for (var i = 0, n = fields.length; i < n && result !== undefined; i++) {
5322 var field = fields[i];
5323
5324 //If the last in the path, set the value
5325 if (i === n - 1) {
5326 options.unset ? delete result[field] : result[field] = val;
5327 } else {
5328 //Create the child object if it doesn't exist, or isn't an object
5329 if (typeof result[field] === 'undefined' || !_.isObject(result[field])) {
5330 // If trying to remove a field that doesn't exist, then there's no need
5331 // to create its missing parent (doing so causes a problem with
5332 // hasChanged()).
5333 if (options.unset) {
5334 delete result[field]; // in case parent exists but is not an object
5335 return;
5336 }
5337 var nextField = fields[i + 1];
5338
5339 // create array if next field is integer, else create object
5340 result[field] = /^\d+$/.test(nextField) ? [] : {};
5341 }
5342
5343 //Move onto the next part of the path
5344 result = result[field];
5345 }
5346 }
5347}
5348
5349function deleteNested(obj, path) {
5350 setNested(obj, path, null, {
5351 unset: true
5352 });
5353}
5354
5355var DeepModel = {
5356
5357 // Override constructor
5358 // Support having nested defaults by using _.deepExtend instead of _.extend
5359 constructor: function(attributes, options) {
5360 var attrs = attributes || {};
5361 this.cid = _.uniqueId('c');
5362 this.attributes = {};
5363 if (options && options.collection) this.collection = options.collection;
5364 if (options && options.parse) attrs = this.parse(attrs, options) || {};
5365 attrs = _.merge({}, _.result(this, 'defaults'), attrs);
5366 this.set(attrs, options);
5367 this.changed = {};
5368 this.initialize.apply(this, arguments);
5369 },
5370
5371 // Return a copy of the model's `attributes` object.
5372 toJSON: function(options) {
5373 return _.merge({}, this.attributes);
5374 },
5375
5376 // Override get
5377 // Supports nested attributes via the syntax 'obj.attr' e.g. 'author.user.name'
5378 get: function(attr) {
5379 return getNested(this.attributes, attr);
5380 },
5381
5382 // Override set
5383 // Supports nested attributes via the syntax 'obj.attr' e.g. 'author.user.name'
5384 set: function(key, val, options) {
5385 var attr, attrs, unset, changes, silent, changing, prev, current;
5386 if (key == null) return this;
5387
5388 // Handle both `"key", value` and `{key: value}` -style arguments.
5389 if (typeof key === 'object') {
5390 attrs = key;
5391 options = val || {};
5392 } else {
5393 (attrs = {})[key] = val;
5394 }
5395
5396 options || (options = {});
5397
5398 // Run validation.
5399 if (!this._validate(attrs, options)) return false;
5400
5401 // Extract attributes and options.
5402 unset = options.unset;
5403 silent = options.silent;
5404 changes = [];
5405 changing = this._changing;
5406 this._changing = true;
5407
5408 if (!changing) {
5409 this._previousAttributes = _.merge({}, this.attributes); //<custom>: Replaced _.clone with _.deepClone
5410 this.changed = {};
5411 }
5412 current = this.attributes, prev = this._previousAttributes;
5413
5414 // Check for changes of `id`.
5415 if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
5416
5417 //<custom code>
5418 attrs = objToPaths(attrs);
5419 //</custom code>
5420
5421 // For each `set` attribute, update or delete the current value.
5422 for (attr in attrs) {
5423 val = attrs[attr];
5424
5425 //<custom code>: Using getNested, setNested and deleteNested
5426 if (!_.isEqual(getNested(current, attr), val)) changes.push(attr);
5427 if (!_.isEqual(getNested(prev, attr), val)) {
5428 setNested(this.changed, attr, val);
5429 } else {
5430 deleteNested(this.changed, attr);
5431 }
5432 unset ? deleteNested(current, attr) : setNested(current, attr, val);
5433 //</custom code>
5434 }
5435
5436 // Trigger all relevant attribute changes.
5437 if (!silent) {
5438 if (changes.length) this._pending = true;
5439
5440 //<custom code>
5441 var separator = DeepModel.keyPathSeparator;
5442 var alreadyTriggered = {}; // * @restorer
5443
5444 for (var i = 0, l = changes.length; i < l; i++) {
5445 var key = changes[i];
5446
5447 if (!alreadyTriggered.hasOwnProperty(key) || !alreadyTriggered[key]) { // * @restorer
5448 alreadyTriggered[key] = true; // * @restorer
5449 this.trigger('change:' + key, this, getNested(current, key), options);
5450 } // * @restorer
5451
5452 var fields = key.split(separator);
5453
5454 //Trigger change events for parent keys with wildcard (*) notation
5455 for (var n = fields.length - 1; n > 0; n--) {
5456 var parentKey = fields.slice(0, n).join(separator),
5457 wildcardKey = parentKey + separator + '*';
5458
5459 if (!alreadyTriggered.hasOwnProperty(wildcardKey) || !alreadyTriggered[wildcardKey]) { // * @restorer
5460 alreadyTriggered[wildcardKey] = true; // * @restorer
5461 this.trigger('change:' + wildcardKey, this, getNested(current, parentKey), options);
5462 } // * @restorer
5463
5464 // + @restorer
5465 if (!alreadyTriggered.hasOwnProperty(parentKey) || !alreadyTriggered[parentKey]) {
5466 alreadyTriggered[parentKey] = true;
5467 this.trigger('change:' + parentKey, this, getNested(current, parentKey), options);
5468 }
5469 // - @restorer
5470 }
5471 //</custom code>
5472 }
5473 }
5474
5475 if (changing) return this;
5476 if (!silent) {
5477 while (this._pending) {
5478 this._pending = false;
5479 this.trigger('change', this, options);
5480 }
5481 }
5482 this._pending = false;
5483 this._changing = false;
5484 return this;
5485 },
5486
5487 // Clear all attributes on the model, firing `"change"` unless you choose
5488 // to silence it.
5489 clear: function(options) {
5490 var attrs = {};
5491 var shallowAttributes = objToPaths(this.attributes);
5492 for (var key in shallowAttributes) attrs[key] = void 0;
5493 return this.set(attrs, _.extend({}, options, {
5494 unset: true
5495 }));
5496 },
5497
5498 // Determine if the model has changed since the last `"change"` event.
5499 // If you specify an attribute name, determine if that attribute has changed.
5500 hasChanged: function(attr) {
5501 if (attr == null) {
5502 return !_.isEmpty(this.changed);
5503 }
5504 return getNested(this.changed, attr) !== undefined;
5505 },
5506
5507 // Return an object containing all the attributes that have changed, or
5508 // false if there are no changed attributes. Useful for determining what
5509 // parts of a view need to be updated and/or what attributes need to be
5510 // persisted to the server. Unset attributes will be set to undefined.
5511 // You can also pass an attributes object to diff against the model,
5512 // determining if there *would be* a change.
5513 changedAttributes: function(diff) {
5514 //<custom code>: objToPaths
5515 if (!diff) return this.hasChanged() ? objToPaths(this.changed) : false;
5516 //</custom code>
5517
5518 var old = this._changing ? this._previousAttributes : this.attributes;
5519
5520 //<custom code>
5521 diff = objToPaths(diff);
5522 old = objToPaths(old);
5523 //</custom code>
5524
5525 var val, changed = false;
5526 for (var attr in diff) {
5527 if (_.isEqual(old[attr], (val = diff[attr]))) continue;
5528 (changed || (changed = {}))[attr] = val;
5529 }
5530 return changed;
5531 },
5532
5533 // Get the previous value of an attribute, recorded at the time the last
5534 // `"change"` event was fired.
5535 previous: function(attr) {
5536 if (attr == null || !this._previousAttributes) {
5537 return null;
5538 }
5539 //<custom code>
5540 return getNested(this._previousAttributes, attr);
5541 //</custom code>
5542 },
5543
5544 // Get all of the attributes of the model at the time of the previous
5545 // `"change"` event.
5546 previousAttributes: function() {
5547 return _.merge({}, this._previousAttributes);
5548 }
5549};
5550
5551//Config; override in your app to customise
5552DeepModel.keyPathSeparator = '.';
5553
5554
5555module.exports = DeepModel;
5556
5557/***/ }),
5558/* 66 */
5559/***/ (function(module, exports, __webpack_require__) {
5560
5561var Collection = __webpack_require__(14);
5562var Model = __webpack_require__(67);
5563var Radio = __webpack_require__(2);
5564var _ = __webpack_require__(0);
5565
5566module.exports = Collection.extend({
5567 model: Model,
5568
5569 url: function(){
5570 var wc_api = Radio.request('entities', 'get', {
5571 type: 'option',
5572 name: 'wc_api'
5573 });
5574 return wc_api + 'products';
5575 },
5576
5577 initialize: function() {
5578 this._isNew = false;
5579 },
5580
5581 /**
5582 * same as _.compact
5583 * except allows 0
5584 */
5585 /* jshint -W074 */
5586 compact: function(array) {
5587 var index = -1,
5588 length = array ? array.length : 0,
5589 resIndex = -1,
5590 result = [];
5591
5592 while (++index < length) {
5593 var value = array[index];
5594 if (value === 0 || value) {
5595 result[++resIndex] = value;
5596 }
5597 }
5598 return result;
5599 },
5600 /* jshint +W074 */
5601
5602 range: function(attr){
5603 var attrs = this.compact( this.pluck(attr)), min = 0, max = 0;
5604 if( !_.isEmpty(attrs) ) {
5605 min = _(attrs).min();
5606 max = _(attrs).max();
5607 }
5608 return _.uniq([min, max]);
5609 }
5610
5611});
5612
5613/***/ }),
5614/* 67 */
5615/***/ (function(module, exports, __webpack_require__) {
5616
5617//var Model = require('lib/config/model');
5618var Model = __webpack_require__(23);
5619var _ = __webpack_require__(0);
5620var Radio = __webpack_require__(2);
5621
5622module.exports = Model.extend({
5623 name: 'product',
5624 defaults: {
5625 type: 'variation'
5626 },
5627
5628 // data types
5629 schema: {
5630 price : 'number',
5631 regular_price : 'number',
5632 sale_price : 'number',
5633 stock_quantity: 'number'
5634 },
5635
5636 url: function(){
5637 var wc_api = Radio.request('entities', 'get', {
5638 type: 'option',
5639 name: 'wc_api'
5640 });
5641 if(wc_api.indexOf('wp-json') !== -1) {
5642 var id = this.get('id');
5643 var parent_id = this.parent.get('id');
5644 if(id && parent_id) {
5645 return wc_api + 'products/' + parent_id + '/variations/' + id;
5646 }
5647 }
5648 return wc_api + 'products/' + this.id;
5649 },
5650
5651 constructor: function(attributes, options){
5652 options = _.extend({parse: true}, options); // parse by default
5653 Model.call(this, attributes, options);
5654 },
5655
5656 initialize: function(attributes, options){
5657 options = options || {};
5658 this.parent = options.parent;
5659 this.set({ name: options.parent.get('name') });
5660 },
5661
5662 // copy variation to parent
5663 save: function(attributes, options){
5664 var self = this;
5665 return Model.prototype.save.call(this, attributes, options)
5666 .then(function(){
5667 self.parent.set({ variations: self.collection.toJSON() });
5668 self.parent.merge();
5669 });
5670 },
5671
5672 /**
5673 *
5674 */
5675 getVariationAttributes: function(){
5676 var result = [];
5677 var attributes = this.get('attributes');
5678
5679 _.each(this.parent.productVariations(), function(attribute){
5680 // pluck attribute on id and merge
5681 var attr = _.findWhere(attributes, { id: attribute.id });
5682
5683 // piped attributes have id = 0 ffs
5684 if(!attr || attr.id === 0){
5685 attr = _.findWhere(attributes, { name: attribute.name });
5686 }
5687
5688 if( attr ) {
5689 result.push( _.merge(attr, attribute) );
5690 } else {
5691 result.push( attribute );
5692 }
5693 });
5694
5695 // sort
5696 return _.sortBy( result, 'position' );
5697 }
5698
5699});
5700
5701/***/ }),
5702/* 68 */
5703/***/ (function(module, exports, __webpack_require__) {
5704
5705var _ = __webpack_require__(0);
5706var Backbone = __webpack_require__(4);
5707var proxyCollection = __webpack_require__(19);
5708var createFilter = __webpack_require__(69);
5709
5710// Beware of `this`
5711// All of the following functions are meant to be called in the context
5712// of the FilteredCollection object, but are not public functions.
5713
5714function invalidateCache() {
5715 this._filterResultCache = {};
5716}
5717
5718function invalidateCacheForFilter(filterName) {
5719 for (var cid in this._filterResultCache) {
5720 if (this._filterResultCache.hasOwnProperty(cid)) {
5721 delete this._filterResultCache[cid][filterName];
5722 }
5723 }
5724}
5725
5726function addFilter(filterName, filterObj) {
5727 // If we've already had a filter of this name, we need to invalidate
5728 // any and all of the cached results
5729 if (this._filters[filterName]) {
5730 invalidateCacheForFilter.call(this, filterName);
5731 }
5732
5733 this._filters[filterName] = filterObj;
5734 this.trigger('filtered:add', filterName);
5735}
5736
5737function removeFilter(filterName) {
5738 delete this._filters[filterName];
5739
5740 /* todo: integrate query methods */
5741 delete this._query;
5742 delete this._tokens;
5743
5744 invalidateCacheForFilter.call(this, filterName);
5745 this.trigger('filtered:remove', filterName);
5746}
5747
5748function execFilterOnModel(model) {
5749 if (!this._filterResultCache[model.cid]) {
5750 this._filterResultCache[model.cid] = {};
5751 }
5752
5753 var cache = this._filterResultCache[model.cid];
5754
5755 for (var filterName in this._filters) {
5756 if (this._filters.hasOwnProperty(filterName)) {
5757 // if we haven't already calculated this, calculate it and cache
5758 if (!cache.hasOwnProperty(filterName)) {
5759 cache[filterName] = this._filters[filterName].fn(model);
5760 }
5761 if (!cache[filterName]) {
5762 return false;
5763 }
5764 }
5765 }
5766 return true;
5767}
5768
5769function execFilter() {
5770 var filtered = [];
5771
5772 // Filter the collection
5773 if (this._superset) {
5774 filtered = this._superset.filter(_.bind(execFilterOnModel, this));
5775 }
5776
5777 this._collection.reset(filtered);
5778 this.length = this._collection.length;
5779}
5780
5781function onAddChange(model) {
5782 // reset the cached results
5783 this._filterResultCache[model.cid] = {};
5784
5785 if (execFilterOnModel.call(this, model)) {
5786 if (!this._collection.get(model.cid)) {
5787 var index = this.superset().indexOf(model);
5788
5789 // Find the index at which to insert the model in the
5790 // filtered collection by finding the index of the
5791 // previous non-filtered model in the filtered collection
5792 var filteredIndex = null;
5793 for (var i = index - 1; i >= 0; i -= 1) {
5794 if (this.contains(this.superset().at(i))) {
5795 filteredIndex = this.indexOf(this.superset().at(i)) + 1;
5796 break;
5797 }
5798 }
5799 filteredIndex = filteredIndex || 0;
5800
5801 this._collection.add(model, { at: filteredIndex });
5802 }
5803 } else {
5804 if (this._collection.get(model.cid)) {
5805 this._collection.remove(model);
5806 }
5807 }
5808 this.length = this._collection.length;
5809}
5810
5811// This fires on 'change:[attribute]' events. We only want to
5812// remove this model if it fails the test, but not add it if
5813// it does. If we remove it, it will prevent the 'change'
5814// events from being forwarded, and if we add it, it will cause
5815// an unneccesary 'change' event to be forwarded without the
5816// 'change:[attribute]' that goes along with it.
5817function onModelAttributeChange(model) {
5818 // reset the cached results
5819 this._filterResultCache[model.cid] = {};
5820
5821 if (!execFilterOnModel.call(this, model)) {
5822 if (this._collection.get(model.cid)) {
5823 this._collection.remove(model);
5824 }
5825 }
5826}
5827
5828function onAll(eventName, model, value) {
5829 if (eventName.slice(0, 7) === "change:") {
5830 onModelAttributeChange.call(this, arguments[1]);
5831 }
5832}
5833
5834function onModelRemove(model) {
5835 if (this.contains(model)) {
5836 this._collection.remove(model);
5837 }
5838 this.length = this._collection.length;
5839}
5840
5841function Filtered(superset) {
5842 // Save a reference to the original collection
5843 this._superset = superset;
5844
5845 // The idea is to keep an internal backbone collection with the filtered
5846 // set, and expose limited functionality.
5847 this._collection = new Backbone.Collection(superset.toArray());
5848 proxyCollection(this._collection, this);
5849
5850 // Set up the filter data structures
5851 this.resetFilters();
5852
5853 this.listenTo(this._superset, 'reset sort', execFilter);
5854 this.listenTo(this._superset, 'add change', onAddChange);
5855 this.listenTo(this._superset, 'remove', onModelRemove);
5856 this.listenTo(this._superset, 'all', onAll);
5857}
5858
5859var methods = {
5860
5861 defaultFilterName: '__default',
5862
5863 filterBy: function(filterName, filter) {
5864 // Allow the user to skip the filter name if they're only using one filter
5865 if (!filter) {
5866 filter = filterName;
5867 filterName = this.defaultFilterName;
5868 }
5869
5870 addFilter.call(this, filterName, createFilter(filter));
5871
5872 execFilter.call(this);
5873 return this;
5874 },
5875
5876 removeFilter: function(filterName) {
5877 if (!filterName) {
5878 filterName = this.defaultFilterName;
5879 }
5880
5881 removeFilter.call(this, filterName);
5882
5883 execFilter.call(this);
5884 return this;
5885 },
5886
5887 resetFilters: function() {
5888 this._filters = {};
5889 invalidateCache.call(this);
5890
5891 this.trigger('filtered:reset');
5892
5893 execFilter.call(this);
5894 return this;
5895 },
5896
5897 superset: function() {
5898 return this._superset;
5899 },
5900
5901 refilter: function(arg) {
5902 if (typeof arg === "object" && arg.cid) {
5903 // is backbone model, refilter that one
5904 onAddChange.call(this, arg);
5905 } else {
5906 // refilter everything
5907 invalidateCache.call(this);
5908 execFilter.call(this);
5909 }
5910
5911 return this;
5912 },
5913
5914 getFilters: function() {
5915 return _.keys(this._filters);
5916 },
5917
5918 hasFilter: function(name) {
5919 return _.contains(this.getFilters(), name);
5920 },
5921
5922 destroy: function() {
5923 this.stopListening();
5924 this._collection.reset([]);
5925 this._superset = this._collection;
5926 this.length = 0;
5927
5928 this.trigger('filtered:destroy');
5929 }
5930
5931};
5932
5933// Build up the prototype
5934_.extend(Filtered.prototype, methods, Backbone.Events);
5935
5936module.exports = Filtered;
5937
5938/***/ }),
5939/* 69 */
5940/***/ (function(module, exports, __webpack_require__) {
5941
5942var _ = __webpack_require__(0);
5943
5944// Converts a key and value into a function that accepts a model
5945// and returns a boolean.
5946function convertKeyValueToFunction(key, value) {
5947 return function(model) {
5948 return model.get(key) === value;
5949 };
5950}
5951
5952// Converts a key and an associated filter function into a function
5953// that accepts a model and returns a boolean.
5954function convertKeyFunctionToFunction(key, fn) {
5955 return function(model) {
5956 return fn(model.get(key));
5957 };
5958}
5959
5960function createFilterObject(filterFunction, keys) {
5961 // Make sure the keys value is either an array or null
5962 if (!_.isArray(keys)) {
5963 keys = null;
5964 }
5965 return { fn: filterFunction, keys: keys };
5966}
5967
5968// Accepts an object in the form of:
5969//
5970// {
5971// key: value,
5972// key: function(val) { ... }
5973// }
5974//
5975// and turns it into a function that accepts a model an returns a
5976// boolean + a list of the keys that the function depends on.
5977function createFilterFromObject(filterObj) {
5978 var keys = _.keys(filterObj);
5979
5980 var filterFunctions = _.map(keys, function(key) {
5981 var val = filterObj[key];
5982 if (_.isFunction(val)) {
5983 return convertKeyFunctionToFunction(key, val);
5984 }
5985 return convertKeyValueToFunction(key, val);
5986 });
5987
5988 // Iterate through each of the generated filter functions. If any
5989 // are false, kill the computation and return false. The function
5990 // is only true if all of the subfunctions are true.
5991 var filterFunction = function(model) {
5992 for (var i = 0; i < filterFunctions.length; i++) {
5993 if (!filterFunctions[i](model)) {
5994 return false;
5995 }
5996 }
5997 return true;
5998 };
5999
6000 return createFilterObject(filterFunction, keys);
6001}
6002
6003// Expects one of the following:
6004//
6005// - A filter function that accepts a model + (optional) array of
6006// keys to listen to changes for or null)
6007// - An object describing a filter
6008function createFilter(filter, keys) {
6009 // This must go first because _.isObject(fn) === true
6010 if (_.isFunction(filter)) {
6011 return createFilterObject(filter, keys);
6012 }
6013
6014 // If the filter is an object describing a filter, generate the
6015 // appropriate function.
6016 if (_.isObject(filter)) {
6017 return createFilterFromObject(filter);
6018 }
6019}
6020
6021module.exports = createFilter;
6022
6023
6024
6025/***/ }),
6026/* 70 */
6027/***/ (function(module, exports, __webpack_require__) {
6028
6029
6030var _ = __webpack_require__(0);
6031var Backbone =__webpack_require__(4);
6032var proxyCollection = __webpack_require__(19);
6033var sortedIndex = __webpack_require__(71);
6034
6035function lookupIterator(value) {
6036 return _.isFunction(value) ? value : function(obj){ return obj.get(value); };
6037}
6038
6039function modelInsertIndex(model) {
6040 if (!this._comparator) {
6041 return this._superset.indexOf(model);
6042 } else {
6043 return sortedIndex(this._collection.models, model, lookupIterator(this._comparator), this._reverse);
6044 }
6045}
6046
6047function onAdd(model) {
6048 var index = modelInsertIndex.call(this, model);
6049 this._collection.add(model, { at: index });
6050}
6051
6052function onRemove(model) {
6053 if (this.contains(model)) {
6054 this._collection.remove(model);
6055 }
6056}
6057
6058function onChange(model) {
6059 if (this.contains(model) && this._collection.indexOf(model) !== modelInsertIndex.call(this, model)) {
6060 this._collection.remove(model);
6061 onAdd.call(this, model);
6062 }
6063}
6064
6065function sort() {
6066 if (!this._comparator) {
6067 this._collection.reset(this._superset.toArray());
6068 return;
6069 }
6070
6071 // Evaluate the type of comparator based on http://backbonejs.org/#Collection-comparator
6072 var newOrder;
6073 if (_.isString(this._comparator) || this._comparator.length === 1) {
6074 newOrder = this._superset.sortBy(this._comparator);
6075 } else {
6076 newOrder = this._superset.models.sort(this._comparator);
6077 }
6078 this._collection.reset(this._reverse ? newOrder.reverse() : newOrder);
6079}
6080
6081function Sorted(superset) {
6082 // Save a reference to the original collection
6083 this._superset = superset;
6084 this._reverse = false;
6085 this._comparator = null;
6086
6087 // The idea is to keep an internal backbone collection with the paginated
6088 // set, and expose limited functionality.
6089 this._collection = new Backbone.Collection(superset.toArray());
6090 proxyCollection(this._collection, this);
6091
6092 this.listenTo(this._superset, 'add', onAdd);
6093 this.listenTo(this._superset, 'remove', onRemove);
6094 this.listenTo(this._superset, 'change', onChange);
6095 this.listenTo(this._superset, 'reset', sort);
6096}
6097
6098var methods = {
6099
6100 setSort: function(comparator, direction) {
6101 this._reverse = direction === 'desc' ? true : false;
6102 this._comparator = comparator;
6103
6104 sort.call(this);
6105
6106 if (!comparator) {
6107 this.trigger('sorted:remove');
6108 } else {
6109 this.trigger('sorted:add');
6110 }
6111
6112 return this;
6113 },
6114
6115 reverseSort: function() {
6116 this._reverse = !this._reverse;
6117 sort.call(this);
6118
6119 return this;
6120 },
6121
6122 removeSort: function() {
6123 this.setSort();
6124 return this;
6125 },
6126
6127 superset: function() {
6128 return this._superset;
6129 },
6130
6131 destroy: function() {
6132 this.stopListening();
6133 this._collection.reset([]);
6134 this._superset = this._collection;
6135 this.length = 0;
6136
6137 this.trigger('sorted:destroy');
6138 }
6139
6140};
6141
6142// Build up the prototype
6143_.extend(Sorted.prototype, methods, Backbone.Events);
6144
6145module.exports = Sorted;
6146
6147
6148
6149/***/ }),
6150/* 71 */
6151/***/ (function(module, exports, __webpack_require__) {
6152
6153
6154var _ = __webpack_require__(0);
6155
6156// Underscore provides a .sortedIndex function that works
6157// when sorting ascending based on a function or a key, but there's no
6158// way to do the same thing when sorting descending. This is a slight
6159// modification of the underscore / backbone code to do the same thing
6160// but descending.
6161
6162function comparatorAdapter(fieldExtractor, reverse) {
6163 return function(left, right) {
6164 var l = fieldExtractor(left);
6165 var r = fieldExtractor(right);
6166
6167 if(l === r) return 0;
6168
6169 return reverse ? (l < r ? 1 : -1) : (l < r ? -1 : 1);
6170 };
6171}
6172
6173function lookupIterator(value, reverse) {
6174 return value.length === 2 ? value : comparatorAdapter(value, reverse);
6175}
6176
6177function sortedIndex(array, obj, iterator, reverse) {
6178 iterator = iterator === null ? _.identity : lookupIterator(iterator, reverse);
6179
6180 var low = 0, high = array.length;
6181 while (low < high) {
6182 var mid = (low + high) >>> 1;
6183 if(iterator(array[mid], obj) < 0) {
6184 low = mid + 1;
6185 } else {
6186 high = mid;
6187 }
6188 }
6189
6190 return low;
6191}
6192
6193module.exports = sortedIndex;
6194
6195
6196/***/ }),
6197/* 72 */
6198/***/ (function(module, exports, __webpack_require__) {
6199
6200var _ = __webpack_require__(0);
6201var Backbone = __webpack_require__(4);
6202var proxyCollection = __webpack_require__(19);
6203
6204function getPageLimits() {
6205 if(this._infinite){
6206 var start = 0;
6207 var end = this._collection.length;
6208 } else {
6209 var start = this.getPage() * this.getPerPage();
6210 var end = start + this.getPerPage();
6211 }
6212 return [start, end];
6213}
6214
6215function updatePagination() {
6216 var pages = getPageLimits.call(this);
6217 return this._collection.reset(this.superset().slice(pages[0], pages[1]));
6218}
6219
6220function infintePagination() {
6221 var start = 0;
6222 var end = this._collection.length + this.getPerPage();
6223 return this._collection.add(this.superset().slice(start, end));
6224}
6225
6226function calcPages() {
6227 var perPage = this.getPerPage();
6228 var length = this.superset().length - this._collection.length;
6229
6230 var totalPages = length % perPage === 0 ?
6231 (length / perPage) : Math.floor(length / perPage) + 1;
6232
6233 return totalPages + 1;
6234}
6235
6236function updateNumPages() {
6237 var length = this.superset().length;
6238 var perPage = this.getPerPage();
6239
6240 // If the # of objects can be exactly divided by the number
6241 // of pages, it would leave an empty last page if we took
6242 // the floor.
6243 var totalPages = length % perPage === 0 ?
6244 (length / perPage) : Math.floor(length / perPage) + 1;
6245
6246 var numPagesChanged = this._totalPages !== totalPages;
6247 this._totalPages = totalPages;
6248
6249 if (numPagesChanged) {
6250 this.trigger('paginated:change:numPages', { numPages: totalPages });
6251 }
6252
6253 // Test to see if we are past the last page, and if so,
6254 // move back. Return true so that we can test to see if
6255 // this happened.
6256 if (this.getPage() >= totalPages) {
6257 this.setPage(totalPages - 1);
6258 return true;
6259 }
6260}
6261
6262function recalculatePagination() {
6263 // reset infinite page
6264 this._infinite = false;
6265
6266 if (updateNumPages.call(this)) { return; }
6267 updatePagination.call(this);
6268}
6269
6270// Given two arrays of backbone models, with at most one model added
6271// and one model removed from each, return the model in arrayA that
6272// is not in arrayB or undefined.
6273function difference(arrayA, arrayB) {
6274 var maxLength = _.max([ arrayA.length, arrayB.length ]);
6275
6276 for (var i = 0, j = 0; i < maxLength; i += 1, j += 1) {
6277 if (arrayA[i] !== arrayB[j]) {
6278 if (arrayB[i-1] === arrayA[i]) {
6279 j -= 1;
6280 } else if (arrayB[i+1] === arrayA[i]) {
6281 j += 1;
6282 } else {
6283 return arrayA[i];
6284 }
6285 }
6286 }
6287}
6288
6289function onAddRemove(model, collection, options) {
6290 if (updateNumPages.call(this)) { return; }
6291
6292 var pages = getPageLimits.call(this);
6293 var start = pages[0], end = pages[1];
6294
6295 // We are only adding and removing at most one model at a time,
6296 // so we can find just those two models. We could probably rewrite
6297 // `collectionDifference` to only make on pass instead of two. This
6298 // is a bottleneck on the total size of collections. I was getting
6299 // slow unit tests around 30,000 models / page in Firefox.
6300 var toAdd = difference(this.superset().slice(start, end), this._collection.toArray());
6301
6302 var infinite = this._infinite && options.add;
6303 var toRemove;
6304
6305 if(!infinite){
6306 toRemove = difference(this._collection.toArray(), this.superset().slice(start, end));
6307 }
6308
6309 if (toRemove) {
6310 this._collection.remove(toRemove);
6311 }
6312
6313 if (toAdd) {
6314 this._collection.add(toAdd, {
6315 at: this.superset().indexOf(toAdd) - start
6316 });
6317 }
6318};
6319
6320function Paginated(superset, options) {
6321 // Save a reference to the original collection
6322 this._superset = superset;
6323
6324 // The idea is to keep an internal backbone collection with the paginated
6325 // set, and expose limited functionality.
6326 this._collection = new Backbone.Collection(superset.toArray());
6327 this._page = 0;
6328 this.setPerPage((options && options.perPage) ? options.perPage : null);
6329
6330 proxyCollection(this._collection, this);
6331
6332 this.listenTo(this._superset, 'add remove', onAddRemove);
6333 this.listenTo(this._superset, 'reset sort', recalculatePagination);
6334}
6335
6336var methods = {
6337
6338 removePagination: function() {
6339 this._infinite = false;
6340 this.setPerPage(null);
6341 return this;
6342 },
6343
6344 setPerPage: function(perPage) {
6345 this._perPage = perPage;
6346 recalculatePagination.call(this);
6347 this.setPage(0);
6348
6349 this.trigger('paginated:change:perPage', {
6350 perPage: perPage,
6351 numPages: this.getNumPages()
6352 });
6353
6354 return this;
6355 },
6356
6357 setPage: function(page) {
6358
6359 // reset infinite page
6360 this._infinite = false;
6361
6362 // The lowest page we could set
6363 var lowerLimit = 0;
6364 // The highest page we could set
6365 var upperLimit = this.getNumPages() - 1;
6366
6367 // If the page is higher or lower than these limits,
6368 // set it to the limit.
6369 page = page > lowerLimit ? page : lowerLimit;
6370 page = page < upperLimit ? page : upperLimit;
6371 page = page < 0 ? 0 : page;
6372
6373 this._page = page;
6374 updatePagination.call(this);
6375
6376 this.trigger('paginated:change:page', { page: page });
6377 return this;
6378 },
6379
6380 getPerPage: function() {
6381 return this._perPage || this.superset().length || 1;
6382 },
6383
6384 getNumPages: function() {
6385 if(this._infinite){
6386 return calcPages.call(this);
6387 } else {
6388 return this._totalPages;
6389 }
6390 },
6391
6392 getPage: function() {
6393 return this._page;
6394 },
6395
6396 hasNextPage: function() {
6397 return this.getPage() < this.getNumPages() - 1;
6398 },
6399
6400 hasPrevPage: function() {
6401 return this.getPage() > 0;
6402 },
6403
6404 nextPage: function() {
6405 this.movePage(1);
6406 return this;
6407 },
6408
6409 prevPage: function() {
6410 this.movePage(-1);
6411 return this;
6412 },
6413
6414 firstPage: function() {
6415 this.setPage(0);
6416 },
6417
6418 lastPage: function() {
6419 this.setPage(this.getNumPages() - 1);
6420 },
6421
6422 movePage: function(delta) {
6423 this.setPage(this.getPage() + delta);
6424 return this;
6425 },
6426
6427 superset: function() {
6428 return this._superset;
6429 },
6430
6431 destroy: function() {
6432 this.stopListening();
6433 this._collection.reset([]);
6434 this._superset = this._collection;
6435 this._page = 0;
6436 this._totalPages = 0;
6437 this.length = 0;
6438 this._infinite = false;
6439
6440 this.trigger('paginated:destroy');
6441 },
6442
6443 // infinite scroll
6444 appendNextPage: function(){
6445 this._infinite = true;
6446 infintePagination.call(this);
6447 this.trigger('paginated:change:page', { page: 0 });
6448 return this;
6449 }
6450
6451};
6452
6453// Build up the prototype
6454_.extend(Paginated.prototype, methods, Backbone.Events);
6455
6456module.exports = Paginated;
6457
6458/***/ }),
6459/* 73 */
6460/***/ (function(module, exports, __webpack_require__) {
6461
6462var _ = __webpack_require__(0);
6463
6464function proxyEvents(from, eventNames) {
6465 _.each(eventNames, function (eventName) {
6466 this.listenTo(from, eventName, function () {
6467 var args = _.toArray(arguments);
6468 args.unshift(eventName);
6469 this.trigger.apply(this, args);
6470 });
6471 }, this);
6472}
6473
6474module.exports = proxyEvents;
6475
6476/***/ }),
6477/* 74 */
6478/***/ (function(module, exports, __webpack_require__) {
6479
6480/**
6481 * query methods to extend Filtered Collection
6482 */
6483
6484var _ = __webpack_require__(0);
6485var query = __webpack_require__(75);
6486
6487module.exports = {
6488
6489 query: function (filterName, filter) {
6490 if( _.isUndefined(filter) ) {
6491 filter = filterName;
6492 filterName = 'search';
6493 }
6494 this._query = filter;
6495 if( filter === '' ){
6496 return this.removeFilter(filterName);
6497 }
6498 return this.filterBy(filterName,
6499 _.bind( query, this, filter )
6500 );
6501 },
6502
6503 getQuery: function(){
6504 return this._query;
6505 },
6506
6507 getTokens: function(){
6508 return this._tokens;
6509 },
6510
6511 getRemoteFilter: function(){
6512 if(!this._tokens){
6513 return;
6514 }
6515
6516 var filter = {
6517 'not_in': this.pluck('id').join(',')
6518 };
6519
6520 _.each(this._tokens, function(token){
6521
6522 // simple search
6523 if(token.type === 'string'){
6524 filter.q = token.query;
6525 }
6526
6527 // simple prefix search
6528 if(token.type === 'prefix'){
6529 filter[token.prefix] = token.query;
6530 }
6531
6532 });
6533
6534 return filter;
6535 }
6536
6537};
6538
6539/***/ }),
6540/* 75 */
6541/***/ (function(module, exports, __webpack_require__) {
6542
6543var _ = __webpack_require__(0);
6544var Parser = __webpack_require__(76);
6545var parser = new Parser();
6546
6547function toType(obj) {
6548 return ({}).toString.call(obj).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
6549}
6550
6551/**
6552 * Helper methods for matching tokens
6553 */
6554var methods = {
6555
6556 /**
6557 * Token type `string`
6558 * @return {Boolean}
6559 */
6560 string: function(token, model){
6561 token = token || {};
6562 if(!_.isString(token.query)){ return false; }
6563
6564 var attributes = _.chain(model.fields || ['title'])
6565 .map(function(key){
6566 return model.get(key); // allows nested get
6567 })
6568 .compact()
6569 .value();
6570
6571 return _.any( attributes, function( attribute ) {
6572 return this._partialString(attribute, token.query.toLowerCase());
6573 }, this);
6574 },
6575
6576 /**
6577 * Token type `prefix`
6578 * @return {Boolean}
6579 */
6580 prefix: function(token, model){
6581 token = token || {};
6582 if(!_.isString(token.query)){ return false; }
6583
6584 var attr = model.get(token.prefix),
6585 type = toType(attr);
6586
6587 // _boolean, _array etc
6588 if(this.hasOwnProperty('_' + type)){
6589 return this['_' + type](attr, token.query.toLowerCase());
6590 }
6591 },
6592
6593 /**
6594 * Token type `or`
6595 * @return {Boolean}
6596 */
6597 or: function(token, model){
6598 return _.any(token.queries, function(t){
6599 return this[t.type](t, model);
6600 }, this);
6601 },
6602
6603 _string: function(str, value){
6604 return str.toLowerCase() === value;
6605 },
6606
6607 _partialString: function(str, value){
6608 return str.toLowerCase().indexOf( value ) !== -1;
6609 },
6610
6611 _number: function(number, value){
6612 return number.toString() === value;
6613 },
6614
6615 _partialNumber: function(number, value){
6616 return number.toString().indexOf( value ) !== -1;
6617 },
6618
6619 _boolean: function(bool, value){
6620 if(value === 'true'){
6621 return bool === true;
6622 } else if (value === 'false'){
6623 return bool === false;
6624 }
6625 return false;
6626 },
6627
6628 _array: function(arr, value){
6629 return _.any(arr, function(elem){
6630 if( _.isString(elem) ) {
6631 return elem.toLowerCase() === value;
6632 }
6633 if( _.isObject(elem) && elem.hasOwnProperty('slug') ) {
6634 return elem.slug.toLowerCase() === value;
6635 }
6636 });
6637 }
6638
6639};
6640
6641function matchMaker(tokens, model){
6642 // match tokens
6643 // todo: all = AND, any = OR
6644 return _.all(tokens, function(token){
6645 return methods[token.type](token, model);
6646 });
6647}
6648
6649/**
6650 * Match Maker
6651 * return true or false for model based on Qparser tokens
6652 * @param {String|Array} filter
6653 * @param {Object} model
6654 * @returns {Boolean}
6655 */
6656module.exports = function(filter, model){
6657 var tokens = _.isArray(filter) ? filter : parser.parse(filter);
6658 this._tokens = tokens;
6659
6660 // allow model specific match maker
6661 if(model.matchMaker){
6662 return model.matchMaker(tokens, methods, matchMaker);
6663 } else {
6664 return matchMaker(tokens, model);
6665 }
6666};
6667
6668/***/ }),
6669/* 76 */
6670/***/ (function(module, exports, __webpack_require__) {
6671
6672/* jshint -W071, -W074 */
6673var _ = __webpack_require__(0);
6674
6675/**
6676 *
6677 * @param options
6678 * @constructor
6679 */
6680function Parser(options){
6681 this.options = options || {};
6682}
6683
6684/**
6685 * Regex for special characters
6686 */
6687var regex = {
6688 QUOTES : /['"`]/, // quotes
6689 SPACES : /[ \t\r\n]/, // spaces
6690 FLAGS : /[~\+#!\*\/]/, // flags
6691 SCREEN : /[\\]/, // screen
6692 GROUP_OPEN : /\(/, // group openers
6693 GROUP_CLOSE : /\)/, // group endings
6694 OR : /\|/, // logical OR
6695 PREFIX : /:/, // divider between prefix and value
6696 RANGE : /-/, // divider between values in range
6697 OR_OPEN : /\[/, // OR group openers
6698 OR_CLOSE : /]/ // OR group endings
6699};
6700
6701/**
6702 * Returns first regex match for given character
6703 * note: order is important!
6704 * @param character
6705 */
6706function matchRegex(character){
6707 var match;
6708
6709 _.any([
6710 'SCREEN',
6711 'OR_OPEN',
6712 'OR_CLOSE',
6713 'GROUP_OPEN',
6714 'GROUP_CLOSE',
6715 'OR',
6716 'PREFIX',
6717 //'RANGE',
6718 'SPACES',
6719 'QUOTES',
6720 'FLAGS'
6721 ], function(key){
6722 if(regex[key].test(character)){
6723 match = key; return true;
6724 } else {
6725 match = undefined; return false;
6726 }
6727 });
6728
6729 return match;
6730}
6731
6732/**
6733 *
6734 */
6735function logicalOr(parts){
6736 var p2 = parts.pop(),
6737 p1 = parts.pop();
6738
6739 parts.push({
6740 type: 'or',
6741 queries: [ p1, p2 ]
6742 });
6743}
6744
6745/**
6746 *
6747 * @param options
6748 */
6749function appendPart(opts){
6750 var part = opts.part || {};
6751
6752 if(!opts.hasarg){ return; }
6753
6754 if (['range', 'prange'].indexOf(part.type) >= 0) {
6755 part.to = opts.buffer;
6756 } else if (opts.buffer && opts.buffer.length) {
6757 part.query = opts.buffer;
6758 }
6759
6760 if (!part.type) {
6761 part.type = part.prefix ? 'prefix' : 'string';
6762 }
6763
6764 opts.parts.push(part);
6765
6766 if (opts.or_at_next_arg && (opts.or_at_next_arg + 1 === opts.parts.length)){
6767 logicalOr(opts.parts);
6768 opts.or_at_next_arg = 0;
6769 }
6770
6771 opts.part = {};
6772 opts.buffer = '';
6773 opts.hasarg = false;
6774
6775}
6776
6777/**
6778 *
6779 * @param options
6780 * @param quote
6781 */
6782function inQuote(opts, quote){
6783 if(this._input.length === 0){
6784 return;
6785 }
6786
6787 opts.character = this._input.shift();
6788
6789 if (opts.character === quote) {
6790 appendPart.call(this, opts);
6791 } else {
6792 opts.buffer += opts.character;
6793 opts.hasarg = true;
6794 inQuote.call(this, opts, quote);
6795 }
6796}
6797
6798/**
6799 *
6800 */
6801var matches = {
6802
6803 screen: function(opts){
6804 opts.screen = true;
6805 },
6806
6807 or_open: function(opts){
6808 if (opts.hasarg) {
6809 opts.buffer += opts.character;
6810 } else {
6811 opts.part.type = 'or';
6812 opts.part.queries = this.parse(this._input.join(''), true);
6813 if (opts.part.queries && opts.part.queries.length) {
6814 opts.hasarg = true;
6815 appendPart.call(this, opts);
6816 }
6817 }
6818 },
6819
6820 or_close: function(opts){
6821 opts.close = true;
6822 },
6823
6824 group_open: function(opts){
6825 if (opts.hasarg) {
6826 opts.buffer += opts.character;
6827 } else {
6828 opts.part.type = 'and';
6829 opts.part.queries = this.parse(this._input.join(''), true);
6830 if (opts.part.queries && opts.part.queries.length) {
6831 opts.hasarg = true;
6832 appendPart.call(this, opts);
6833 }
6834 }
6835 },
6836
6837 group_close: function(opts){
6838 if(opts.open){
6839 opts.close = true;
6840 opts.open = undefined;
6841 } else {
6842 opts.buffer += opts.character;
6843 }
6844 },
6845
6846 or: function(opts){
6847 opts.or_at_next_arg = opts.parts.length;
6848 if (opts.hasarg) {
6849 opts.or_at_next_arg += 1;
6850 appendPart.call(this, opts);
6851 }
6852 },
6853
6854 prefix: function(opts){
6855 opts.part.prefix = opts.buffer;
6856 opts.part.type = 'prefix';
6857 opts.buffer = '';
6858 opts.hasarg = true;
6859 },
6860
6861 range: function(opts){
6862 if (opts.part.type && (opts.part.type === 'prefix')) {
6863 opts.part.type = 'prange';
6864 } else {
6865 opts.part.type = 'range';
6866 }
6867 opts.part.from = opts.buffer;
6868 opts.buffer = '';
6869 opts.hasarg = true;
6870 },
6871
6872 spaces: function(opts){
6873 appendPart.call(this, opts);
6874 },
6875
6876 quotes: function(opts){
6877 if (opts.buffer.length) {
6878 opts.buffer += opts.character;
6879 opts.hasarg = true;
6880 } else {
6881 inQuote.call(this, opts, opts.character);
6882 }
6883 },
6884
6885 flags: function(opts){
6886 if (!opts.buffer.length) {
6887 if (!opts.part.flags) { opts.part.flags = []; }
6888 opts.part.flags.push(opts.character);
6889 } else {
6890 opts.buffer += opts.character;
6891 }
6892 }
6893};
6894
6895/**
6896 *
6897 * @param options
6898 */
6899function next(opts){
6900 opts.character = this._input.shift();
6901 var match = matchRegex.call(this, opts.character);
6902 if(match && !opts.screen){
6903 matches[match.toLowerCase()].call(this, opts);
6904 } else {
6905 opts.buffer += opts.character;
6906 opts.hasarg = true;
6907 opts.screen = false;
6908 }
6909 if(this._input.length > 0 && !opts.close){
6910 next.call(this, opts);
6911 } else {
6912 opts.close = undefined;
6913 return;
6914 }
6915}
6916
6917/**
6918 *
6919 */
6920var methods = {
6921
6922 parse: function(input, open) {
6923 var opts = {
6924 parts : [],
6925 part : {},
6926 open : open,
6927 buffer : '',
6928 hasarg : false
6929 };
6930
6931 if (!input || !input.length || (typeof input !== 'string')) {
6932 return opts.parts;
6933 }
6934
6935 this._input = input.split('');
6936 next.call(this, opts);
6937 appendPart.call(this, opts);
6938 return opts.parts;
6939 }
6940
6941};
6942
6943_.extend(Parser.prototype, methods);
6944
6945module.exports = Parser;
6946/* jshint +W071, +W074 */
6947
6948/***/ }),
6949/* 77 */
6950/***/ (function(module, exports, __webpack_require__) {
6951
6952var DualCollection = __webpack_require__(21);
6953var Model = __webpack_require__(78);
6954var $ = __webpack_require__(3);
6955var _ = __webpack_require__(0);
6956var bb = __webpack_require__(4);
6957
6958module.exports = DualCollection.extend({
6959 model: Model,
6960 name: 'orders',
6961 _syncDelayed: false,
6962
6963 /**
6964 * Open orders first
6965 */
6966 //comparator: function( model ){
6967 // if( model.get('id') === undefined ) { return 0; }
6968 // return 1;
6969 //},
6970
6971 /**
6972 *
6973 */
6974 setActiveOrder: function(id){
6975 var order = this.get(id);
6976
6977 if( !order && id !== 'new' ){
6978 order = _.first( this.openOrders() );
6979 }
6980
6981 this.active = order;
6982 return order;
6983 },
6984
6985 /**
6986 * Promise of an active order
6987 */
6988 getActiveOrder: function(){
6989 var self = this;
6990 var deferred = new $.Deferred();
6991
6992 if(!this.active){
6993 this.create().then(function(order){
6994 order.cart.order_id = order.id;
6995 self.active = order;
6996 if(bb.history.getHash() === 'cart/new') {
6997 bb.history.navigate('cart/' + order.id);
6998 }
6999 deferred.resolve(order);
7000 });
7001 } else {
7002 deferred.resolve(this.active);
7003 }
7004
7005 return deferred.promise();
7006 },
7007
7008 addToCart: function(options){
7009 this.getActiveOrder()
7010 .then(function(order){
7011 order.cart.addToCart(options);
7012 });
7013 },
7014
7015 create: function(){
7016 var deferred = new $.Deferred();
7017
7018 // Safari has a problem with create, perhaps an autoincrement problem?
7019 // Set local_id as timestamp milliseconds
7020 DualCollection.prototype.create.call(this, { local_id: Date.now() }, {
7021 wait: true,
7022 success: deferred.resolve,
7023 error: deferred.reject
7024 });
7025
7026 return deferred.promise();
7027 },
7028
7029 /**
7030 *
7031 */
7032 openOrders: function(){
7033 return this.filter(function(model){
7034 return model.isEditable();
7035 });
7036 }
7037
7038});
7039
7040/***/ }),
7041/* 78 */
7042/***/ (function(module, exports, __webpack_require__) {
7043
7044//var DualModel = require('lib/config/dual-model');
7045var DualModel = __webpack_require__(22);
7046var Radio = __webpack_require__(2);
7047var Utils = __webpack_require__(13);
7048var debug = __webpack_require__(8)('order');
7049var App = __webpack_require__(1);
7050var $ = __webpack_require__(3);
7051
7052var Model = DualModel.extend({
7053 name: 'order',
7054 fields: [
7055 'customer.first_name',
7056 'customer.last_name',
7057 'customer.email'
7058 ],
7059
7060 /**
7061 * Orders with the following status are closed for editing
7062 */
7063 //closedStatus: [
7064 // 'completed',
7065 // 'on-hold',
7066 // 'cancelled',
7067 // 'refunded',
7068 // 'processing',
7069 // 'failed'
7070 //],
7071
7072 /**
7073 *
7074 */
7075 defaults: {
7076 note : '',
7077 order_discount : 0
7078 },
7079
7080 /**
7081 * - attach tax settings
7082 * - attach cart & gateways if order is open
7083 */
7084 /* jshint -W071, -W074 */
7085 initialize: function(attributes){
7086 attributes = attributes || {};
7087
7088 if(!attributes.customer && !attributes.billing){
7089 var customers = this.getEntities('customers');
7090 var customer = customers['default'] || customers.guest || {};
7091 this.set({
7092 customer_id : customer.id,
7093 customer : customer
7094 });
7095 }
7096
7097 this.tax = this.getEntities('tax');
7098 this.tax_rates = this.getEntities('tax_rates');
7099
7100 if( this.isEditable() ){
7101 this.attachCart();
7102 this.attachGateways();
7103 }
7104
7105 // order_discount input
7106 this.on({
7107 'change:order_discount': this.calcTotals,
7108 'change:status': this.isEditable
7109 });
7110
7111 },
7112 /* jshint +W071, +W074 */
7113
7114 getEntities: function(name){
7115 return Radio.request('entities', 'get', {
7116 type: 'option',
7117 name: name
7118 }) || {};
7119 },
7120
7121 /**
7122 * is order editable method, sets _open true or false
7123 */
7124 isEditable: function(){
7125 //return !_.contains(this.closedStatus, this.get('status'));
7126 return this.get('status') === undefined || this.isDelayed();
7127 //return this.isDelayed();
7128 },
7129
7130 /**
7131 * Remove items from cart before destroy
7132 */
7133 destroy: function(options){
7134 var self = this;
7135 return this.cart.db.removeBatch( this.cart.pluck('local_id') )
7136 .always(function(){
7137 return DualModel.prototype.destroy.call(self, options);
7138 });
7139 },
7140
7141 /**
7142 * Attach cart
7143 */
7144 attachCart: function(){
7145 var cart = Radio.request('entities', 'get', {
7146 init : true,
7147 type : 'collection',
7148 name : 'cart'
7149 });
7150
7151 cart.order_id = this.id;
7152
7153 this.listenTo(cart, {
7154 'add change' : this.calcTotals,
7155 'remove' : this.itemRemoved
7156 });
7157
7158 if(cart.db){
7159 cart.db.open().then(function(){
7160 cart.fetchCartItems();
7161 });
7162 }
7163
7164 this.cart = cart;
7165 },
7166
7167 /**
7168 * remove cart items from idb after successful order
7169 */
7170 clearCart: function(){
7171 if(this.cart){
7172 this.cart.db.removeBatch( this.cart.pluck('local_id') );
7173 }
7174 },
7175
7176 /**
7177 * Attach gateways
7178 */
7179 attachGateways: function(){
7180 this.gateways = Radio.request('entities', 'get', {
7181 init : true,
7182 type : 'collection',
7183 name : 'gateways'
7184 });
7185
7186 var gateways = Radio.request('entities', 'get', {
7187 type: 'option',
7188 name: 'gateways'
7189 });
7190 this.gateways.add(gateways);
7191 },
7192
7193 /**
7194 *
7195 */
7196 itemRemoved: function(){
7197 if(this.cart.length > 0){
7198 return this.calcTotals();
7199 }
7200 return this.destroy();
7201 },
7202
7203 /**
7204 * Sum cart totals
7205 * todo: too many statements
7206 */
7207 /* jshint -W071 */
7208 calcTotals: function(){
7209 var total_tax = 0,
7210 subtotal_tax = 0,
7211 shipping_tax = 0,
7212 cart_discount_tax = 0,
7213 subtotal = this.cart.sum('subtotal'),
7214 total = this.cart.sum('total'),
7215 cart_discount = subtotal - total,
7216 order_discount = this.get('order_discount');
7217
7218 if( this.tax.calc_taxes === 'yes' ) {
7219 total_tax = this.cart.sum('total_tax');
7220 subtotal_tax = this.cart.sum('subtotal_tax');
7221 shipping_tax = this.cart.sum('total_tax', 'shipping');
7222 cart_discount_tax = subtotal_tax - total_tax;
7223 }
7224
7225 total += total_tax;
7226 total -= order_discount;
7227
7228 // tax_lines will merge the data - possibly due to deep model
7229 // clear tax_lines before save to ensure clean data
7230 this.unset('tax_lines', { silent: true });
7231
7232 // create totals object
7233 var totals = {
7234 'total' : Utils.round( total, 4 ),
7235 'subtotal' : Utils.round( subtotal, 4 ),
7236 'total_tax' : Utils.round( total_tax, 4 ),
7237 'subtotal_tax' : Utils.round( subtotal_tax, 4 ),
7238 'shipping_tax' : Utils.round( shipping_tax, 4 ),
7239 'cart_discount' : Utils.round( cart_discount, 4 ),
7240 'cart_discount_tax' : Utils.round( cart_discount_tax, 4 ),
7241 'tax_lines' : this.cart.itemizedTax()
7242 };
7243
7244 this.save(totals);
7245 debug('update totals', totals);
7246 },
7247 /* jshint +W071 */
7248
7249 /**
7250 * Convenience method to sum attributes
7251 */
7252 sum: function(array){
7253 var sum = 0;
7254 for (var i = 0; i < array.length; i++) {
7255 sum += parseFloat( this.get(array[i]) );
7256 }
7257 return sum;
7258 },
7259
7260 /**
7261 * process order
7262 * todo: remoteSync resolves w/ an array of models, should match sync?
7263 */
7264 process: function(){
7265 var self = this;
7266
7267 return $.when( this.processCart() )
7268 .then(function(){
7269 return self.processGateway();
7270 })
7271 .then(function(){
7272 var method = self.get('id') ? 'update' : 'create';
7273 return self.remoteSync(method);
7274 })
7275 .then(function(array){
7276 var model = array[0];
7277 if(model.get('status') === 'failed'){
7278 model.save({ status: 'UPDATE_FAILED' });
7279 }
7280 });
7281 },
7282
7283 /**
7284 *
7285 */
7286 processCart: function(){
7287 var obj = {
7288 product : [],
7289 shipping: [],
7290 fee : []
7291 };
7292
7293 this.cart.each(function(model){
7294 var type = model.get('type');
7295 if(type !== 'shipping' && type !== 'fee'){
7296 type = 'product';
7297 }
7298 obj[type].push( model.toJSON() );
7299 });
7300
7301 // set
7302 this.set({
7303 line_items : obj.product,
7304 shipping_lines: obj.shipping,
7305 fee_lines : obj.fee,
7306 tax_lines : this.cart.itemizedTax() // reset for retry
7307 });
7308 },
7309
7310 /**
7311 *
7312 */
7313 processGateway: function(){
7314 var data = this.gateways.findWhere({ active: true }).toJSON();
7315 this.set({
7316 payment_details: data
7317 });
7318 }
7319
7320});
7321
7322module.exports = Model;
7323App.prototype.set('Entities.Order.Model', Model);
7324
7325/***/ }),
7326/* 79 */
7327/***/ (function(module, exports, __webpack_require__) {
7328
7329var IndexedDBCollection = __webpack_require__(34);
7330var Model = __webpack_require__(80);
7331var _ = __webpack_require__(0);
7332var bb = __webpack_require__(4);
7333
7334module.exports = IndexedDBCollection.extend({
7335 model: Model,
7336 name: 'cart',
7337 indexes: [
7338 {name: 'local_id', keyPath: 'local_id', unique: true},
7339 {name: 'order', keyPath: 'order', unique: false},
7340 {name: 'type', keyPath: 'type', unique: false}
7341 ],
7342
7343 /**
7344 * Whitelist of attributes taken from product model
7345 */
7346 productAttributes: [
7347 'order',
7348 'name',
7349 'local_id',
7350 'product_id',
7351 'type',
7352 'price',
7353 'regular_price',
7354 'sale_price',
7355 'taxable',
7356 'tax_status',
7357 'tax_class',
7358 'attributes',
7359 'meta', // variation meta
7360 'method_title', // shipping
7361 'method_id' // shipping
7362 ],
7363
7364 comparator: function( model ){
7365 var type = model.get( 'type' );
7366 if( type === 'fee' ) { return 2; }
7367 if( type === 'shipping' ) { return 1; }
7368 return 0;
7369 },
7370
7371 /**
7372 * If collection has order_id, query idb for index: 'order' = order_id
7373 * onSuccess add items to collection
7374 */
7375 fetchCartItems: function () {
7376 if(!this.order_id){
7377 return;
7378 }
7379
7380 var onSuccess = this.add.bind(this);
7381 var keyRange = this.db.store.makeKeyRange({
7382 only: this.order_id
7383 });
7384
7385 this.db.store.query(onSuccess, {
7386 index: 'order',
7387 keyRange: keyRange
7388 });
7389 },
7390
7391 // convenience method to sum attributes in collection
7392 sum: function(attribute, type){
7393 var col = this.toJSON();
7394 if(type){ col = _.where(col, {type: type}); }
7395 return _.pluck(col, attribute).reduce(function(a, b){return a + b;}, 0);
7396 },
7397
7398 /**
7399 * add/increase item
7400 * also prune attributes
7401 */
7402 /* jshint -W071, -W074 */
7403 addToCart: function(options){
7404 options = options || {};
7405 var model, attributes = options.model || options;
7406 if(attributes instanceof bb.Model){
7407 attributes = attributes.toJSON();
7408 }
7409
7410 if(attributes.id){
7411 model = this.findWhere({ product_id: attributes.id });
7412 attributes.product_id = attributes.id;
7413 delete attributes.id;
7414 }
7415
7416 if(model){
7417 model.quantity('increase');
7418 } else {
7419 model = this._addToCart(attributes);
7420 }
7421
7422 model.trigger('pulse');
7423 },
7424 /* jshint +W071, +W074 */
7425
7426 _addToCart: function(attributes){
7427 attributes.order = this.order_id;
7428
7429 // turn variation attributes into line item meta
7430 if(attributes.type === 'variation'){
7431 attributes.meta = _.map(attributes.attributes, function(variant, idx){
7432 return {
7433 key: ++idx,
7434 label: variant.name,
7435 value: variant.option
7436 };
7437 });
7438 }
7439
7440 return this.add(_.pick(attributes, this.productAttributes));
7441 },
7442
7443 itemizedTax: function(){
7444 var items = _.clone(this.toJSON(), true);
7445 var taxes = _.map(items, function(item){
7446 if(!item.tax) { return; }
7447 _.each(item.tax, function(tax){
7448 tax.shipping = item.type === 'shipping' ? tax.total : 0 ;
7449 });
7450 return item.tax;
7451 });
7452 var obj = this.sumTaxes(taxes);
7453
7454 // convert obj to array to be consistent with WC REST API output
7455 var arr = [];
7456 _.each(obj, function(value, key){
7457 //value.rate_id = parseInt(key, 10);
7458 value.rate_id = key.toString(); // make sure it's a string
7459 arr.push(value);
7460 });
7461
7462 return arr;
7463 },
7464
7465 sumTaxes: function(taxes){
7466 return _.reduce(taxes, function(result, tax){
7467 return _.merge(result, tax, function(a, b){
7468 if(a){
7469 b.total += a.total;
7470 b.subtotal += a.subtotal;
7471 b.shipping += a.shipping;
7472 }
7473 return b;
7474 });
7475 }, {});
7476 }
7477
7478});
7479
7480/***/ }),
7481/* 80 */
7482/***/ (function(module, exports, __webpack_require__) {
7483
7484var Model = __webpack_require__(16);
7485var debug = __webpack_require__(8)('cartItem');
7486var Utils = __webpack_require__(13);
7487var _ = __webpack_require__(0);
7488var Radio = __webpack_require__(2);
7489
7490module.exports = Model.extend({
7491 idAttribute: 'local_id',
7492
7493 defaults : {
7494 'subtotal' : 0,
7495 'subtotal_tax' : 0,
7496 'total_tax' : 0,
7497 'total' : 0,
7498 'item_tax' : 0,
7499 'quantity' : 1,
7500 'taxable' : true,
7501 'tax_class' : ''
7502 },
7503
7504 /* jshint -W074 */
7505 initialize: function() {
7506
7507 // attach tax settings
7508 this.tax = Radio.request('entities', 'get', {
7509 type: 'option',
7510 name: 'tax'
7511 }) || {};
7512 this.tax_rates = Radio.request('entities', 'get', {
7513 type: 'option',
7514 name: 'tax_rates'
7515 }) || {};
7516
7517 // update on change to quantity, item_price ...
7518 this.on(
7519 'change:quantity ' +
7520 'change:item_price ' +
7521 'change:regular_price ' +
7522 'change:taxable ' +
7523 'change:tax_class',
7524 this.updateLineTotals );
7525
7526 // set item price on init, this wil kick off updateLineTotals
7527 if( this.get('item_price') === undefined ) {
7528 var price = parseFloat( this.get('price') );
7529 this.set({ 'item_price': _.isNaN(price) ? 0 : price });
7530 }
7531 },
7532 /* jshint +W074 */
7533
7534 /* jshint -W071, -W074 */
7535 /* todo: too many statements, too complex */
7536 updateLineTotals: function() {
7537 var quantity = this.get('quantity'),
7538 item_price = this.get('item_price'),
7539 type = this.get('type'),
7540 regular_price = parseFloat( this.get('regular_price')),
7541 tax_class = this.get('tax_class'),
7542 item_tax,
7543 item_subtotal_tax,
7544 rates;
7545
7546 // make a copy of the tax rates for this product
7547 if(this.tax_rates[tax_class]){
7548 rates = _.cloneDeep(this.tax_rates[tax_class]);
7549 }
7550
7551 // if shipping or fee
7552 if( type === 'shipping' || type === 'fee' ) {
7553 regular_price = item_price;
7554 }
7555
7556 // calc taxes
7557 item_tax = this.calcTax({
7558 price : item_price,
7559 quantity : quantity,
7560 rates : rates
7561 });
7562
7563 item_subtotal_tax = this.calcTax({
7564 price : regular_price,
7565 quantity : quantity,
7566 rates : rates,
7567 subtotal : true
7568 });
7569
7570 // if price does not include tax
7571 if( this.tax.prices_include_tax === 'yes' ) {
7572 regular_price -= item_subtotal_tax;
7573 item_price -= item_tax;
7574 }
7575
7576 // create totals object
7577 var totals = {
7578 'item_subtotal' : Utils.round( regular_price, 4 ),
7579 'item_subtotal_tax' : Utils.round( item_subtotal_tax, 4 ),
7580 'item_tax' : Utils.round( item_tax, 4 ),
7581 'subtotal' : Utils.round( regular_price * quantity, 4 ),
7582 'subtotal_tax' : Utils.round( item_subtotal_tax * quantity, 4 ),
7583 'total_tax' : Utils.round( item_tax * quantity, 4 ),
7584 'total' : Utils.round( item_price * quantity, 4 )
7585 };
7586
7587 this.save(totals);
7588 debug('update totals', totals);
7589 },
7590 /* jshint +W071, +W074 */
7591
7592 /**
7593 * Calculate the line item tax total
7594 * based on the calc_tax function in woocommerce/includes/class-wc-tax.php
7595 */
7596 calcTax: function(options) {
7597 var item_tax = 0;
7598
7599 if(this.tax.calc_taxes === 'yes' && this.get('taxable') && options.rates) {
7600 if( this.tax.prices_include_tax === 'yes' ) {
7601 item_tax = this.calcInclusiveTax(options);
7602 } else {
7603 item_tax = this.calcExclusiveTax(options);
7604 }
7605 } else {
7606 this.set('tax', undefined);
7607 }
7608
7609 return item_tax;
7610 },
7611
7612 /**
7613 * Calculate the line item tax total
7614 * based on the calc_inclusive_tax function in
7615 * woocommerce/includes/class-wc-tax.php
7616 */
7617 /* todo: too many statements */
7618 /* jshint -W071 */
7619 calcInclusiveTax: function(options) {
7620 var regular_tax_rates = 0,
7621 compound_tax_rates = 0,
7622 non_compound_price = 0,
7623 tax_amount = 0,
7624 item_tax = 0,
7625 price = options.price,
7626 rates = options.rates,
7627 qty = options.quantity;
7628
7629 _.each(rates, function(rate, key) {
7630 if( this.get('type') === 'shipping' && rate.shipping === 'no' ){
7631 delete rates[key];
7632 return;
7633 }
7634 if ( rate.compound === 'yes' ) {
7635 compound_tax_rates = compound_tax_rates + parseFloat(rate.rate);
7636 } else {
7637 regular_tax_rates = regular_tax_rates + parseFloat(rate.rate);
7638 }
7639 }, this);
7640
7641 var regular_tax_rate = 1 + ( regular_tax_rates / 100 );
7642 var compound_tax_rate = 1 + ( compound_tax_rates / 100 );
7643 non_compound_price = price / compound_tax_rate;
7644
7645 _.each(rates, function(rate) {
7646 var the_rate = parseFloat(rate.rate) / 100;
7647 var the_price = 0;
7648
7649 if ( rate.compound === 'yes' ) {
7650 the_price = price;
7651 the_rate = the_rate / compound_tax_rate;
7652 } else {
7653 the_price = non_compound_price;
7654 the_rate = the_rate / regular_tax_rate;
7655 }
7656
7657 var net_price = price - ( the_rate * the_price );
7658 tax_amount = price - net_price;
7659
7660 // set the itemized taxes
7661 var prop = options.subtotal ? 'subtotal' : 'total';
7662 rate[prop] = Utils.round( tax_amount * qty, 4 );
7663
7664 // sum item taxes
7665 item_tax += tax_amount;
7666
7667 }, this);
7668
7669 // itemized tax
7670 if( !_.isEmpty(rates) ){
7671 this.set('tax', rates);
7672 }
7673
7674 // return the item tax
7675 return item_tax;
7676 },
7677 /* jshint +W071 */
7678
7679 /**
7680 * Calculate the line item tax total
7681 * based on the calc_exclusive_tax function in
7682 * woocommerce/includes/class-wc-tax.php
7683 */
7684 calcExclusiveTax: function(options) {
7685 var taxes = [],
7686 pre_compound_total = 0,
7687 tax_amount = 0,
7688 item_tax = 0,
7689 price = options.price,
7690 rates = options.rates,
7691 qty = options.quantity;
7692
7693 // multiple taxes
7694 _.each(rates, function(rate, key) {
7695 tax_amount = 0;
7696 if( this.get('type') === 'shipping' && rate.shipping === 'no' ){
7697 delete rates[key];
7698 return;
7699 }
7700 if ( rate.compound !== 'yes' ) {
7701 tax_amount = price * ( parseFloat(rate.rate) / 100 );
7702 }
7703 taxes[ key ] = tax_amount;
7704 }, this);
7705
7706 if( taxes.length > 0 ) {
7707 pre_compound_total = taxes.reduce(function(sum, num) {return sum + num;});
7708 }
7709
7710 // compound taxes
7711 _.each(rates, function(rate, key) {
7712 if ( rate.compound === 'yes' ) {
7713 var the_price_inc_tax = price + pre_compound_total;
7714 taxes[ key ] = the_price_inc_tax * ( parseFloat(rate.rate) / 100 );
7715 }
7716
7717 // set the itemized taxes
7718 var prop = options.subtotal ? 'subtotal' : 'total';
7719 rate[prop] = Utils.round( taxes[ key ] * qty, 4 );
7720
7721 // sum item taxes
7722 item_tax += taxes[ key ];
7723
7724 }, this);
7725
7726 // itemized tax
7727 if( !_.isEmpty(rates) ){
7728 this.set('tax', rates);
7729 }
7730
7731 // return the item tax
7732 return item_tax;
7733 },
7734
7735 // Convenience method to increase or decrease quantity
7736 quantity: function( type ) {
7737 var quantity = this.get('quantity');
7738 this.set('quantity', (type === 'increase' ? ++quantity : --quantity) );
7739 return this;
7740 },
7741
7742 // Convenience method to sum attributes
7743 sum: function(array){
7744 var sum = 0;
7745 for (var i = 0; i < array.length; i++) {
7746 sum += this.get(array[i]);
7747 }
7748 return Utils.round(sum, 4);
7749 },
7750
7751 // hack to copy meta to meta_data
7752 toJSON: function(args){
7753 var data = Model.prototype.toJSON.apply(this, args);
7754 if(data.meta) {
7755 var array = [];
7756 _.each(data.meta, function(meta){
7757 array.push({
7758 key : meta.label,
7759 value : meta.value
7760 });
7761 });
7762 data.meta_data = array;
7763 }
7764 return data;
7765 }
7766
7767});
7768
7769/***/ }),
7770/* 81 */
7771/***/ (function(module, exports, __webpack_require__) {
7772
7773var DualCollection = __webpack_require__(21);
7774var Model = __webpack_require__(82);
7775var Radio = __webpack_require__(2);
7776
7777module.exports = DualCollection.extend({
7778 model: Model,
7779 name: 'customers',
7780 indexes: [
7781 {name: 'local_id', keyPath: 'local_id', unique: true},
7782 {name: 'id', keyPath: 'id', unique: true},
7783 {name: 'status', keyPath: 'status', unique: false},
7784 {name: 'email', keyPath: 'email', unique: true},
7785 {name: 'username', keyPath: 'username', unique: true}
7786 ],
7787
7788 initialize: function(){
7789 var settings = Radio.request('entities', 'get', {
7790 type: 'option',
7791 name: 'customers'
7792 });
7793 if(settings){
7794 this._guest = settings.guest;
7795 this._default = settings['default'] || settings.guest;
7796 }
7797 },
7798
7799 getGuestCustomer: function(){
7800 return this._guest;
7801 },
7802
7803 getDefaultCustomer: function(){
7804 return this._default;
7805 }
7806
7807});
7808
7809/***/ }),
7810/* 82 */
7811/***/ (function(module, exports, __webpack_require__) {
7812
7813var DualModel = __webpack_require__(22);
7814var App = __webpack_require__(1);
7815
7816var CustomersModel = DualModel.extend({
7817 name: 'customer',
7818 // this is an array of fields used by FilterCollection.matchmaker()
7819 fields: ['email', 'username', 'first_name', 'last_name']
7820});
7821
7822module.exports = CustomersModel;
7823App.prototype.set('Entities.Customers.Model', CustomersModel);
7824
7825/***/ }),
7826/* 83 */
7827/***/ (function(module, exports, __webpack_require__) {
7828
7829var Collection = __webpack_require__(14);
7830var Model = __webpack_require__(84);
7831
7832module.exports = Collection.extend({
7833 model: Model
7834});
7835
7836/***/ }),
7837/* 84 */
7838/***/ (function(module, exports, __webpack_require__) {
7839
7840var Model = __webpack_require__(16);
7841
7842module.exports = Model.extend({});
7843
7844/***/ }),
7845/* 85 */
7846/***/ (function(module, exports, __webpack_require__) {
7847
7848var Collection = __webpack_require__(14);
7849var Model = __webpack_require__(37);
7850
7851module.exports = Collection.extend({
7852 model: Model
7853});
7854
7855/***/ }),
7856/* 86 */
7857/***/ (function(module, exports, __webpack_require__) {
7858
7859var Collection = __webpack_require__(14);
7860var Model = __webpack_require__(87);
7861
7862module.exports = Collection.extend({
7863 model: Model,
7864
7865 initialize: function() {
7866 this._isNew = false;
7867 this.on( 'change:active', this.onChangeActive );
7868 },
7869
7870 onChangeActive: function(model, active) {
7871 if(!active){ return; }
7872 this.each( function(tab) {
7873 if( model.id !== tab.id ) {
7874 tab.set({ active: false });
7875 }
7876 });
7877 }
7878});
7879
7880/***/ }),
7881/* 87 */
7882/***/ (function(module, exports, __webpack_require__) {
7883
7884var Model = __webpack_require__(16);
7885
7886module.exports = Model.extend({
7887 idAttribute: 'method_id',
7888
7889 defaults: {
7890 active: false
7891 }
7892});
7893
7894/***/ }),
7895/* 88 */,
7896/* 89 */,
7897/* 90 */
7898/***/ (function(module, exports, __webpack_require__) {
7899
7900var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! tether 1.4.2 */
7901
7902(function(root, factory) {
7903 if (true) {
7904 !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
7905 __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
7906 (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) :
7907 __WEBPACK_AMD_DEFINE_FACTORY__),
7908 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
7909 } else if (typeof exports === 'object') {
7910 module.exports = factory(require, exports, module);
7911 } else {
7912 root.Tether = factory();
7913 }
7914}(this, function(require, exports, module) {
7915
7916'use strict';
7917
7918var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
7919
7920function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
7921
7922var TetherBase = undefined;
7923if (typeof TetherBase === 'undefined') {
7924 TetherBase = { modules: [] };
7925}
7926
7927var zeroElement = null;
7928
7929// Same as native getBoundingClientRect, except it takes into account parent <frame> offsets
7930// if the element lies within a nested document (<frame> or <iframe>-like).
7931function getActualBoundingClientRect(node) {
7932 var boundingRect = node.getBoundingClientRect();
7933
7934 // The original object returned by getBoundingClientRect is immutable, so we clone it
7935 // We can't use extend because the properties are not considered part of the object by hasOwnProperty in IE9
7936 var rect = {};
7937 for (var k in boundingRect) {
7938 rect[k] = boundingRect[k];
7939 }
7940
7941 if (node.ownerDocument !== document) {
7942 var _frameElement = node.ownerDocument.defaultView.frameElement;
7943 if (_frameElement) {
7944 var frameRect = getActualBoundingClientRect(_frameElement);
7945 rect.top += frameRect.top;
7946 rect.bottom += frameRect.top;
7947 rect.left += frameRect.left;
7948 rect.right += frameRect.left;
7949 }
7950 }
7951
7952 return rect;
7953}
7954
7955function getScrollParents(el) {
7956 // In firefox if the el is inside an iframe with display: none; window.getComputedStyle() will return null;
7957 // https://bugzilla.mozilla.org/show_bug.cgi?id=548397
7958 var computedStyle = getComputedStyle(el) || {};
7959 var position = computedStyle.position;
7960 var parents = [];
7961
7962 if (position === 'fixed') {
7963 return [el];
7964 }
7965
7966 var parent = el;
7967 while ((parent = parent.parentNode) && parent && parent.nodeType === 1) {
7968 var style = undefined;
7969 try {
7970 style = getComputedStyle(parent);
7971 } catch (err) {}
7972
7973 if (typeof style === 'undefined' || style === null) {
7974 parents.push(parent);
7975 return parents;
7976 }
7977
7978 var _style = style;
7979 var overflow = _style.overflow;
7980 var overflowX = _style.overflowX;
7981 var overflowY = _style.overflowY;
7982
7983 if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {
7984 if (position !== 'absolute' || ['relative', 'absolute', 'fixed'].indexOf(style.position) >= 0) {
7985 parents.push(parent);
7986 }
7987 }
7988 }
7989
7990 parents.push(el.ownerDocument.body);
7991
7992 // If the node is within a frame, account for the parent window scroll
7993 if (el.ownerDocument !== document) {
7994 parents.push(el.ownerDocument.defaultView);
7995 }
7996
7997 return parents;
7998}
7999
8000var uniqueId = (function () {
8001 var id = 0;
8002 return function () {
8003 return ++id;
8004 };
8005})();
8006
8007var zeroPosCache = {};
8008var getOrigin = function getOrigin() {
8009 // getBoundingClientRect is unfortunately too accurate. It introduces a pixel or two of
8010 // jitter as the user scrolls that messes with our ability to detect if two positions
8011 // are equivilant or not. We place an element at the top left of the page that will
8012 // get the same jitter, so we can cancel the two out.
8013 var node = zeroElement;
8014 if (!node || !document.body.contains(node)) {
8015 node = document.createElement('div');
8016 node.setAttribute('data-tether-id', uniqueId());
8017 extend(node.style, {
8018 top: 0,
8019 left: 0,
8020 position: 'absolute'
8021 });
8022
8023 document.body.appendChild(node);
8024
8025 zeroElement = node;
8026 }
8027
8028 var id = node.getAttribute('data-tether-id');
8029 if (typeof zeroPosCache[id] === 'undefined') {
8030 zeroPosCache[id] = getActualBoundingClientRect(node);
8031
8032 // Clear the cache when this position call is done
8033 defer(function () {
8034 delete zeroPosCache[id];
8035 });
8036 }
8037
8038 return zeroPosCache[id];
8039};
8040
8041function removeUtilElements() {
8042 if (zeroElement) {
8043 document.body.removeChild(zeroElement);
8044 }
8045 zeroElement = null;
8046};
8047
8048function getBounds(el) {
8049 var doc = undefined;
8050 if (el === document) {
8051 doc = document;
8052 el = document.documentElement;
8053 } else {
8054 doc = el.ownerDocument;
8055 }
8056
8057 var docEl = doc.documentElement;
8058
8059 var box = getActualBoundingClientRect(el);
8060
8061 var origin = getOrigin();
8062
8063 box.top -= origin.top;
8064 box.left -= origin.left;
8065
8066 if (typeof box.width === 'undefined') {
8067 box.width = document.body.scrollWidth - box.left - box.right;
8068 }
8069 if (typeof box.height === 'undefined') {
8070 box.height = document.body.scrollHeight - box.top - box.bottom;
8071 }
8072
8073 box.top = box.top - docEl.clientTop;
8074 box.left = box.left - docEl.clientLeft;
8075 box.right = doc.body.clientWidth - box.width - box.left;
8076 box.bottom = doc.body.clientHeight - box.height - box.top;
8077
8078 return box;
8079}
8080
8081function getOffsetParent(el) {
8082 return el.offsetParent || document.documentElement;
8083}
8084
8085var _scrollBarSize = null;
8086function getScrollBarSize() {
8087 if (_scrollBarSize) {
8088 return _scrollBarSize;
8089 }
8090 var inner = document.createElement('div');
8091 inner.style.width = '100%';
8092 inner.style.height = '200px';
8093
8094 var outer = document.createElement('div');
8095 extend(outer.style, {
8096 position: 'absolute',
8097 top: 0,
8098 left: 0,
8099 pointerEvents: 'none',
8100 visibility: 'hidden',
8101 width: '200px',
8102 height: '150px',
8103 overflow: 'hidden'
8104 });
8105
8106 outer.appendChild(inner);
8107
8108 document.body.appendChild(outer);
8109
8110 var widthContained = inner.offsetWidth;
8111 outer.style.overflow = 'scroll';
8112 var widthScroll = inner.offsetWidth;
8113
8114 if (widthContained === widthScroll) {
8115 widthScroll = outer.clientWidth;
8116 }
8117
8118 document.body.removeChild(outer);
8119
8120 var width = widthContained - widthScroll;
8121
8122 _scrollBarSize = { width: width, height: width };
8123 return _scrollBarSize;
8124}
8125
8126function extend() {
8127 var out = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
8128
8129 var args = [];
8130
8131 Array.prototype.push.apply(args, arguments);
8132
8133 args.slice(1).forEach(function (obj) {
8134 if (obj) {
8135 for (var key in obj) {
8136 if (({}).hasOwnProperty.call(obj, key)) {
8137 out[key] = obj[key];
8138 }
8139 }
8140 }
8141 });
8142
8143 return out;
8144}
8145
8146function removeClass(el, name) {
8147 if (typeof el.classList !== 'undefined') {
8148 name.split(' ').forEach(function (cls) {
8149 if (cls.trim()) {
8150 el.classList.remove(cls);
8151 }
8152 });
8153 } else {
8154 var regex = new RegExp('(^| )' + name.split(' ').join('|') + '( |$)', 'gi');
8155 var className = getClassName(el).replace(regex, ' ');
8156 setClassName(el, className);
8157 }
8158}
8159
8160function addClass(el, name) {
8161 if (typeof el.classList !== 'undefined') {
8162 name.split(' ').forEach(function (cls) {
8163 if (cls.trim()) {
8164 el.classList.add(cls);
8165 }
8166 });
8167 } else {
8168 removeClass(el, name);
8169 var cls = getClassName(el) + (' ' + name);
8170 setClassName(el, cls);
8171 }
8172}
8173
8174function hasClass(el, name) {
8175 if (typeof el.classList !== 'undefined') {
8176 return el.classList.contains(name);
8177 }
8178 var className = getClassName(el);
8179 return new RegExp('(^| )' + name + '( |$)', 'gi').test(className);
8180}
8181
8182function getClassName(el) {
8183 // Can't use just SVGAnimatedString here since nodes within a Frame in IE have
8184 // completely separately SVGAnimatedString base classes
8185 if (el.className instanceof el.ownerDocument.defaultView.SVGAnimatedString) {
8186 return el.className.baseVal;
8187 }
8188 return el.className;
8189}
8190
8191function setClassName(el, className) {
8192 el.setAttribute('class', className);
8193}
8194
8195function updateClasses(el, add, all) {
8196 // Of the set of 'all' classes, we need the 'add' classes, and only the
8197 // 'add' classes to be set.
8198 all.forEach(function (cls) {
8199 if (add.indexOf(cls) === -1 && hasClass(el, cls)) {
8200 removeClass(el, cls);
8201 }
8202 });
8203
8204 add.forEach(function (cls) {
8205 if (!hasClass(el, cls)) {
8206 addClass(el, cls);
8207 }
8208 });
8209}
8210
8211var deferred = [];
8212
8213var defer = function defer(fn) {
8214 deferred.push(fn);
8215};
8216
8217var flush = function flush() {
8218 var fn = undefined;
8219 while (fn = deferred.pop()) {
8220 fn();
8221 }
8222};
8223
8224var Evented = (function () {
8225 function Evented() {
8226 _classCallCheck(this, Evented);
8227 }
8228
8229 _createClass(Evented, [{
8230 key: 'on',
8231 value: function on(event, handler, ctx) {
8232 var once = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
8233
8234 if (typeof this.bindings === 'undefined') {
8235 this.bindings = {};
8236 }
8237 if (typeof this.bindings[event] === 'undefined') {
8238 this.bindings[event] = [];
8239 }
8240 this.bindings[event].push({ handler: handler, ctx: ctx, once: once });
8241 }
8242 }, {
8243 key: 'once',
8244 value: function once(event, handler, ctx) {
8245 this.on(event, handler, ctx, true);
8246 }
8247 }, {
8248 key: 'off',
8249 value: function off(event, handler) {
8250 if (typeof this.bindings === 'undefined' || typeof this.bindings[event] === 'undefined') {
8251 return;
8252 }
8253
8254 if (typeof handler === 'undefined') {
8255 delete this.bindings[event];
8256 } else {
8257 var i = 0;
8258 while (i < this.bindings[event].length) {
8259 if (this.bindings[event][i].handler === handler) {
8260 this.bindings[event].splice(i, 1);
8261 } else {
8262 ++i;
8263 }
8264 }
8265 }
8266 }
8267 }, {
8268 key: 'trigger',
8269 value: function trigger(event) {
8270 if (typeof this.bindings !== 'undefined' && this.bindings[event]) {
8271 var i = 0;
8272
8273 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
8274 args[_key - 1] = arguments[_key];
8275 }
8276
8277 while (i < this.bindings[event].length) {
8278 var _bindings$event$i = this.bindings[event][i];
8279 var handler = _bindings$event$i.handler;
8280 var ctx = _bindings$event$i.ctx;
8281 var once = _bindings$event$i.once;
8282
8283 var context = ctx;
8284 if (typeof context === 'undefined') {
8285 context = this;
8286 }
8287
8288 handler.apply(context, args);
8289
8290 if (once) {
8291 this.bindings[event].splice(i, 1);
8292 } else {
8293 ++i;
8294 }
8295 }
8296 }
8297 }
8298 }]);
8299
8300 return Evented;
8301})();
8302
8303TetherBase.Utils = {
8304 getActualBoundingClientRect: getActualBoundingClientRect,
8305 getScrollParents: getScrollParents,
8306 getBounds: getBounds,
8307 getOffsetParent: getOffsetParent,
8308 extend: extend,
8309 addClass: addClass,
8310 removeClass: removeClass,
8311 hasClass: hasClass,
8312 updateClasses: updateClasses,
8313 defer: defer,
8314 flush: flush,
8315 uniqueId: uniqueId,
8316 Evented: Evented,
8317 getScrollBarSize: getScrollBarSize,
8318 removeUtilElements: removeUtilElements
8319};
8320/* globals TetherBase, performance */
8321
8322'use strict';
8323
8324var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
8325
8326var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
8327
8328var _get = function get(_x6, _x7, _x8) { var _again = true; _function: while (_again) { var object = _x6, property = _x7, receiver = _x8; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x6 = parent; _x7 = property; _x8 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
8329
8330function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
8331
8332function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
8333
8334if (typeof TetherBase === 'undefined') {
8335 throw new Error('You must include the utils.js file before tether.js');
8336}
8337
8338var _TetherBase$Utils = TetherBase.Utils;
8339var getScrollParents = _TetherBase$Utils.getScrollParents;
8340var getBounds = _TetherBase$Utils.getBounds;
8341var getOffsetParent = _TetherBase$Utils.getOffsetParent;
8342var extend = _TetherBase$Utils.extend;
8343var addClass = _TetherBase$Utils.addClass;
8344var removeClass = _TetherBase$Utils.removeClass;
8345var updateClasses = _TetherBase$Utils.updateClasses;
8346var defer = _TetherBase$Utils.defer;
8347var flush = _TetherBase$Utils.flush;
8348var getScrollBarSize = _TetherBase$Utils.getScrollBarSize;
8349var removeUtilElements = _TetherBase$Utils.removeUtilElements;
8350
8351function within(a, b) {
8352 var diff = arguments.length <= 2 || arguments[2] === undefined ? 1 : arguments[2];
8353
8354 return a + diff >= b && b >= a - diff;
8355}
8356
8357var transformKey = (function () {
8358 if (typeof document === 'undefined') {
8359 return '';
8360 }
8361 var el = document.createElement('div');
8362
8363 var transforms = ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform'];
8364 for (var i = 0; i < transforms.length; ++i) {
8365 var key = transforms[i];
8366 if (el.style[key] !== undefined) {
8367 return key;
8368 }
8369 }
8370})();
8371
8372var tethers = [];
8373
8374var position = function position() {
8375 tethers.forEach(function (tether) {
8376 tether.position(false);
8377 });
8378 flush();
8379};
8380
8381function now() {
8382 if (performance && performance.now) {
8383 return performance.now();
8384 }
8385 return +new Date();
8386}
8387
8388(function () {
8389 var lastCall = null;
8390 var lastDuration = null;
8391 var pendingTimeout = null;
8392
8393 var tick = function tick() {
8394 if (typeof lastDuration !== 'undefined' && lastDuration > 16) {
8395 // We voluntarily throttle ourselves if we can't manage 60fps
8396 lastDuration = Math.min(lastDuration - 16, 250);
8397
8398 // Just in case this is the last event, remember to position just once more
8399 pendingTimeout = setTimeout(tick, 250);
8400 return;
8401 }
8402
8403 if (typeof lastCall !== 'undefined' && now() - lastCall < 10) {
8404 // Some browsers call events a little too frequently, refuse to run more than is reasonable
8405 return;
8406 }
8407
8408 if (pendingTimeout != null) {
8409 clearTimeout(pendingTimeout);
8410 pendingTimeout = null;
8411 }
8412
8413 lastCall = now();
8414 position();
8415 lastDuration = now() - lastCall;
8416 };
8417
8418 if (typeof window !== 'undefined' && typeof window.addEventListener !== 'undefined') {
8419 ['resize', 'scroll', 'touchmove'].forEach(function (event) {
8420 window.addEventListener(event, tick);
8421 });
8422 }
8423})();
8424
8425var MIRROR_LR = {
8426 center: 'center',
8427 left: 'right',
8428 right: 'left'
8429};
8430
8431var MIRROR_TB = {
8432 middle: 'middle',
8433 top: 'bottom',
8434 bottom: 'top'
8435};
8436
8437var OFFSET_MAP = {
8438 top: 0,
8439 left: 0,
8440 middle: '50%',
8441 center: '50%',
8442 bottom: '100%',
8443 right: '100%'
8444};
8445
8446var autoToFixedAttachment = function autoToFixedAttachment(attachment, relativeToAttachment) {
8447 var left = attachment.left;
8448 var top = attachment.top;
8449
8450 if (left === 'auto') {
8451 left = MIRROR_LR[relativeToAttachment.left];
8452 }
8453
8454 if (top === 'auto') {
8455 top = MIRROR_TB[relativeToAttachment.top];
8456 }
8457
8458 return { left: left, top: top };
8459};
8460
8461var attachmentToOffset = function attachmentToOffset(attachment) {
8462 var left = attachment.left;
8463 var top = attachment.top;
8464
8465 if (typeof OFFSET_MAP[attachment.left] !== 'undefined') {
8466 left = OFFSET_MAP[attachment.left];
8467 }
8468
8469 if (typeof OFFSET_MAP[attachment.top] !== 'undefined') {
8470 top = OFFSET_MAP[attachment.top];
8471 }
8472
8473 return { left: left, top: top };
8474};
8475
8476function addOffset() {
8477 var out = { top: 0, left: 0 };
8478
8479 for (var _len = arguments.length, offsets = Array(_len), _key = 0; _key < _len; _key++) {
8480 offsets[_key] = arguments[_key];
8481 }
8482
8483 offsets.forEach(function (_ref) {
8484 var top = _ref.top;
8485 var left = _ref.left;
8486
8487 if (typeof top === 'string') {
8488 top = parseFloat(top, 10);
8489 }
8490 if (typeof left === 'string') {
8491 left = parseFloat(left, 10);
8492 }
8493
8494 out.top += top;
8495 out.left += left;
8496 });
8497
8498 return out;
8499}
8500
8501function offsetToPx(offset, size) {
8502 if (typeof offset.left === 'string' && offset.left.indexOf('%') !== -1) {
8503 offset.left = parseFloat(offset.left, 10) / 100 * size.width;
8504 }
8505 if (typeof offset.top === 'string' && offset.top.indexOf('%') !== -1) {
8506 offset.top = parseFloat(offset.top, 10) / 100 * size.height;
8507 }
8508
8509 return offset;
8510}
8511
8512var parseOffset = function parseOffset(value) {
8513 var _value$split = value.split(' ');
8514
8515 var _value$split2 = _slicedToArray(_value$split, 2);
8516
8517 var top = _value$split2[0];
8518 var left = _value$split2[1];
8519
8520 return { top: top, left: left };
8521};
8522var parseAttachment = parseOffset;
8523
8524var TetherClass = (function (_Evented) {
8525 _inherits(TetherClass, _Evented);
8526
8527 function TetherClass(options) {
8528 var _this = this;
8529
8530 _classCallCheck(this, TetherClass);
8531
8532 _get(Object.getPrototypeOf(TetherClass.prototype), 'constructor', this).call(this);
8533 this.position = this.position.bind(this);
8534
8535 tethers.push(this);
8536
8537 this.history = [];
8538
8539 this.setOptions(options, false);
8540
8541 TetherBase.modules.forEach(function (module) {
8542 if (typeof module.initialize !== 'undefined') {
8543 module.initialize.call(_this);
8544 }
8545 });
8546
8547 this.position();
8548 }
8549
8550 _createClass(TetherClass, [{
8551 key: 'getClass',
8552 value: function getClass() {
8553 var key = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
8554 var classes = this.options.classes;
8555
8556 if (typeof classes !== 'undefined' && classes[key]) {
8557 return this.options.classes[key];
8558 } else if (this.options.classPrefix) {
8559 return this.options.classPrefix + '-' + key;
8560 } else {
8561 return key;
8562 }
8563 }
8564 }, {
8565 key: 'setOptions',
8566 value: function setOptions(options) {
8567 var _this2 = this;
8568
8569 var pos = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1];
8570
8571 var defaults = {
8572 offset: '0 0',
8573 targetOffset: '0 0',
8574 targetAttachment: 'auto auto',
8575 classPrefix: 'tether'
8576 };
8577
8578 this.options = extend(defaults, options);
8579
8580 var _options = this.options;
8581 var element = _options.element;
8582 var target = _options.target;
8583 var targetModifier = _options.targetModifier;
8584
8585 this.element = element;
8586 this.target = target;
8587 this.targetModifier = targetModifier;
8588
8589 if (this.target === 'viewport') {
8590 this.target = document.body;
8591 this.targetModifier = 'visible';
8592 } else if (this.target === 'scroll-handle') {
8593 this.target = document.body;
8594 this.targetModifier = 'scroll-handle';
8595 }
8596
8597 ['element', 'target'].forEach(function (key) {
8598 if (typeof _this2[key] === 'undefined') {
8599 throw new Error('Tether Error: Both element and target must be defined');
8600 }
8601
8602 if (typeof _this2[key].jquery !== 'undefined') {
8603 _this2[key] = _this2[key][0];
8604 } else if (typeof _this2[key] === 'string') {
8605 _this2[key] = document.querySelector(_this2[key]);
8606 }
8607 });
8608
8609 addClass(this.element, this.getClass('element'));
8610 if (!(this.options.addTargetClasses === false)) {
8611 addClass(this.target, this.getClass('target'));
8612 }
8613
8614 if (!this.options.attachment) {
8615 throw new Error('Tether Error: You must provide an attachment');
8616 }
8617
8618 this.targetAttachment = parseAttachment(this.options.targetAttachment);
8619 this.attachment = parseAttachment(this.options.attachment);
8620 this.offset = parseOffset(this.options.offset);
8621 this.targetOffset = parseOffset(this.options.targetOffset);
8622
8623 if (typeof this.scrollParents !== 'undefined') {
8624 this.disable();
8625 }
8626
8627 if (this.targetModifier === 'scroll-handle') {
8628 this.scrollParents = [this.target];
8629 } else {
8630 this.scrollParents = getScrollParents(this.target);
8631 }
8632
8633 if (!(this.options.enabled === false)) {
8634 this.enable(pos);
8635 }
8636 }
8637 }, {
8638 key: 'getTargetBounds',
8639 value: function getTargetBounds() {
8640 if (typeof this.targetModifier !== 'undefined') {
8641 if (this.targetModifier === 'visible') {
8642 if (this.target === document.body) {
8643 return { top: pageYOffset, left: pageXOffset, height: innerHeight, width: innerWidth };
8644 } else {
8645 var bounds = getBounds(this.target);
8646
8647 var out = {
8648 height: bounds.height,
8649 width: bounds.width,
8650 top: bounds.top,
8651 left: bounds.left
8652 };
8653
8654 out.height = Math.min(out.height, bounds.height - (pageYOffset - bounds.top));
8655 out.height = Math.min(out.height, bounds.height - (bounds.top + bounds.height - (pageYOffset + innerHeight)));
8656 out.height = Math.min(innerHeight, out.height);
8657 out.height -= 2;
8658
8659 out.width = Math.min(out.width, bounds.width - (pageXOffset - bounds.left));
8660 out.width = Math.min(out.width, bounds.width - (bounds.left + bounds.width - (pageXOffset + innerWidth)));
8661 out.width = Math.min(innerWidth, out.width);
8662 out.width -= 2;
8663
8664 if (out.top < pageYOffset) {
8665 out.top = pageYOffset;
8666 }
8667 if (out.left < pageXOffset) {
8668 out.left = pageXOffset;
8669 }
8670
8671 return out;
8672 }
8673 } else if (this.targetModifier === 'scroll-handle') {
8674 var bounds = undefined;
8675 var target = this.target;
8676 if (target === document.body) {
8677 target = document.documentElement;
8678
8679 bounds = {
8680 left: pageXOffset,
8681 top: pageYOffset,
8682 height: innerHeight,
8683 width: innerWidth
8684 };
8685 } else {
8686 bounds = getBounds(target);
8687 }
8688
8689 var style = getComputedStyle(target);
8690
8691 var hasBottomScroll = target.scrollWidth > target.clientWidth || [style.overflow, style.overflowX].indexOf('scroll') >= 0 || this.target !== document.body;
8692
8693 var scrollBottom = 0;
8694 if (hasBottomScroll) {
8695 scrollBottom = 15;
8696 }
8697
8698 var height = bounds.height - parseFloat(style.borderTopWidth) - parseFloat(style.borderBottomWidth) - scrollBottom;
8699
8700 var out = {
8701 width: 15,
8702 height: height * 0.975 * (height / target.scrollHeight),
8703 left: bounds.left + bounds.width - parseFloat(style.borderLeftWidth) - 15
8704 };
8705
8706 var fitAdj = 0;
8707 if (height < 408 && this.target === document.body) {
8708 fitAdj = -0.00011 * Math.pow(height, 2) - 0.00727 * height + 22.58;
8709 }
8710
8711 if (this.target !== document.body) {
8712 out.height = Math.max(out.height, 24);
8713 }
8714
8715 var scrollPercentage = this.target.scrollTop / (target.scrollHeight - height);
8716 out.top = scrollPercentage * (height - out.height - fitAdj) + bounds.top + parseFloat(style.borderTopWidth);
8717
8718 if (this.target === document.body) {
8719 out.height = Math.max(out.height, 24);
8720 }
8721
8722 return out;
8723 }
8724 } else {
8725 return getBounds(this.target);
8726 }
8727 }
8728 }, {
8729 key: 'clearCache',
8730 value: function clearCache() {
8731 this._cache = {};
8732 }
8733 }, {
8734 key: 'cache',
8735 value: function cache(k, getter) {
8736 // More than one module will often need the same DOM info, so
8737 // we keep a cache which is cleared on each position call
8738 if (typeof this._cache === 'undefined') {
8739 this._cache = {};
8740 }
8741
8742 if (typeof this._cache[k] === 'undefined') {
8743 this._cache[k] = getter.call(this);
8744 }
8745
8746 return this._cache[k];
8747 }
8748 }, {
8749 key: 'enable',
8750 value: function enable() {
8751 var _this3 = this;
8752
8753 var pos = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];
8754
8755 if (!(this.options.addTargetClasses === false)) {
8756 addClass(this.target, this.getClass('enabled'));
8757 }
8758 addClass(this.element, this.getClass('enabled'));
8759 this.enabled = true;
8760
8761 this.scrollParents.forEach(function (parent) {
8762 if (parent !== _this3.target.ownerDocument) {
8763 parent.addEventListener('scroll', _this3.position);
8764 }
8765 });
8766
8767 if (pos) {
8768 this.position();
8769 }
8770 }
8771 }, {
8772 key: 'disable',
8773 value: function disable() {
8774 var _this4 = this;
8775
8776 removeClass(this.target, this.getClass('enabled'));
8777 removeClass(this.element, this.getClass('enabled'));
8778 this.enabled = false;
8779
8780 if (typeof this.scrollParents !== 'undefined') {
8781 this.scrollParents.forEach(function (parent) {
8782 parent.removeEventListener('scroll', _this4.position);
8783 });
8784 }
8785 }
8786 }, {
8787 key: 'destroy',
8788 value: function destroy() {
8789 var _this5 = this;
8790
8791 this.disable();
8792
8793 tethers.forEach(function (tether, i) {
8794 if (tether === _this5) {
8795 tethers.splice(i, 1);
8796 }
8797 });
8798
8799 // Remove any elements we were using for convenience from the DOM
8800 if (tethers.length === 0) {
8801 removeUtilElements();
8802 }
8803 }
8804 }, {
8805 key: 'updateAttachClasses',
8806 value: function updateAttachClasses(elementAttach, targetAttach) {
8807 var _this6 = this;
8808
8809 elementAttach = elementAttach || this.attachment;
8810 targetAttach = targetAttach || this.targetAttachment;
8811 var sides = ['left', 'top', 'bottom', 'right', 'middle', 'center'];
8812
8813 if (typeof this._addAttachClasses !== 'undefined' && this._addAttachClasses.length) {
8814 // updateAttachClasses can be called more than once in a position call, so
8815 // we need to clean up after ourselves such that when the last defer gets
8816 // ran it doesn't add any extra classes from previous calls.
8817 this._addAttachClasses.splice(0, this._addAttachClasses.length);
8818 }
8819
8820 if (typeof this._addAttachClasses === 'undefined') {
8821 this._addAttachClasses = [];
8822 }
8823 var add = this._addAttachClasses;
8824
8825 if (elementAttach.top) {
8826 add.push(this.getClass('element-attached') + '-' + elementAttach.top);
8827 }
8828 if (elementAttach.left) {
8829 add.push(this.getClass('element-attached') + '-' + elementAttach.left);
8830 }
8831 if (targetAttach.top) {
8832 add.push(this.getClass('target-attached') + '-' + targetAttach.top);
8833 }
8834 if (targetAttach.left) {
8835 add.push(this.getClass('target-attached') + '-' + targetAttach.left);
8836 }
8837
8838 var all = [];
8839 sides.forEach(function (side) {
8840 all.push(_this6.getClass('element-attached') + '-' + side);
8841 all.push(_this6.getClass('target-attached') + '-' + side);
8842 });
8843
8844 defer(function () {
8845 if (!(typeof _this6._addAttachClasses !== 'undefined')) {
8846 return;
8847 }
8848
8849 updateClasses(_this6.element, _this6._addAttachClasses, all);
8850 if (!(_this6.options.addTargetClasses === false)) {
8851 updateClasses(_this6.target, _this6._addAttachClasses, all);
8852 }
8853
8854 delete _this6._addAttachClasses;
8855 });
8856 }
8857 }, {
8858 key: 'position',
8859 value: function position() {
8860 var _this7 = this;
8861
8862 var flushChanges = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];
8863
8864 // flushChanges commits the changes immediately, leave true unless you are positioning multiple
8865 // tethers (in which case call Tether.Utils.flush yourself when you're done)
8866
8867 if (!this.enabled) {
8868 return;
8869 }
8870
8871 this.clearCache();
8872
8873 // Turn 'auto' attachments into the appropriate corner or edge
8874 var targetAttachment = autoToFixedAttachment(this.targetAttachment, this.attachment);
8875
8876 this.updateAttachClasses(this.attachment, targetAttachment);
8877
8878 var elementPos = this.cache('element-bounds', function () {
8879 return getBounds(_this7.element);
8880 });
8881
8882 var width = elementPos.width;
8883 var height = elementPos.height;
8884
8885 if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') {
8886 var _lastSize = this.lastSize;
8887
8888 // We cache the height and width to make it possible to position elements that are
8889 // getting hidden.
8890 width = _lastSize.width;
8891 height = _lastSize.height;
8892 } else {
8893 this.lastSize = { width: width, height: height };
8894 }
8895
8896 var targetPos = this.cache('target-bounds', function () {
8897 return _this7.getTargetBounds();
8898 });
8899 var targetSize = targetPos;
8900
8901 // Get an actual px offset from the attachment
8902 var offset = offsetToPx(attachmentToOffset(this.attachment), { width: width, height: height });
8903 var targetOffset = offsetToPx(attachmentToOffset(targetAttachment), targetSize);
8904
8905 var manualOffset = offsetToPx(this.offset, { width: width, height: height });
8906 var manualTargetOffset = offsetToPx(this.targetOffset, targetSize);
8907
8908 // Add the manually provided offset
8909 offset = addOffset(offset, manualOffset);
8910 targetOffset = addOffset(targetOffset, manualTargetOffset);
8911
8912 // It's now our goal to make (element position + offset) == (target position + target offset)
8913 var left = targetPos.left + targetOffset.left - offset.left;
8914 var top = targetPos.top + targetOffset.top - offset.top;
8915
8916 for (var i = 0; i < TetherBase.modules.length; ++i) {
8917 var _module2 = TetherBase.modules[i];
8918 var ret = _module2.position.call(this, {
8919 left: left,
8920 top: top,
8921 targetAttachment: targetAttachment,
8922 targetPos: targetPos,
8923 elementPos: elementPos,
8924 offset: offset,
8925 targetOffset: targetOffset,
8926 manualOffset: manualOffset,
8927 manualTargetOffset: manualTargetOffset,
8928 scrollbarSize: scrollbarSize,
8929 attachment: this.attachment
8930 });
8931
8932 if (ret === false) {
8933 return false;
8934 } else if (typeof ret === 'undefined' || typeof ret !== 'object') {
8935 continue;
8936 } else {
8937 top = ret.top;
8938 left = ret.left;
8939 }
8940 }
8941
8942 // We describe the position three different ways to give the optimizer
8943 // a chance to decide the best possible way to position the element
8944 // with the fewest repaints.
8945 var next = {
8946 // It's position relative to the page (absolute positioning when
8947 // the element is a child of the body)
8948 page: {
8949 top: top,
8950 left: left
8951 },
8952
8953 // It's position relative to the viewport (fixed positioning)
8954 viewport: {
8955 top: top - pageYOffset,
8956 bottom: pageYOffset - top - height + innerHeight,
8957 left: left - pageXOffset,
8958 right: pageXOffset - left - width + innerWidth
8959 }
8960 };
8961
8962 var doc = this.target.ownerDocument;
8963 var win = doc.defaultView;
8964
8965 var scrollbarSize = undefined;
8966 if (win.innerHeight > doc.documentElement.clientHeight) {
8967 scrollbarSize = this.cache('scrollbar-size', getScrollBarSize);
8968 next.viewport.bottom -= scrollbarSize.height;
8969 }
8970
8971 if (win.innerWidth > doc.documentElement.clientWidth) {
8972 scrollbarSize = this.cache('scrollbar-size', getScrollBarSize);
8973 next.viewport.right -= scrollbarSize.width;
8974 }
8975
8976 if (['', 'static'].indexOf(doc.body.style.position) === -1 || ['', 'static'].indexOf(doc.body.parentElement.style.position) === -1) {
8977 // Absolute positioning in the body will be relative to the page, not the 'initial containing block'
8978 next.page.bottom = doc.body.scrollHeight - top - height;
8979 next.page.right = doc.body.scrollWidth - left - width;
8980 }
8981
8982 if (typeof this.options.optimizations !== 'undefined' && this.options.optimizations.moveElement !== false && !(typeof this.targetModifier !== 'undefined')) {
8983 (function () {
8984 var offsetParent = _this7.cache('target-offsetparent', function () {
8985 return getOffsetParent(_this7.target);
8986 });
8987 var offsetPosition = _this7.cache('target-offsetparent-bounds', function () {
8988 return getBounds(offsetParent);
8989 });
8990 var offsetParentStyle = getComputedStyle(offsetParent);
8991 var offsetParentSize = offsetPosition;
8992
8993 var offsetBorder = {};
8994 ['Top', 'Left', 'Bottom', 'Right'].forEach(function (side) {
8995 offsetBorder[side.toLowerCase()] = parseFloat(offsetParentStyle['border' + side + 'Width']);
8996 });
8997
8998 offsetPosition.right = doc.body.scrollWidth - offsetPosition.left - offsetParentSize.width + offsetBorder.right;
8999 offsetPosition.bottom = doc.body.scrollHeight - offsetPosition.top - offsetParentSize.height + offsetBorder.bottom;
9000
9001 if (next.page.top >= offsetPosition.top + offsetBorder.top && next.page.bottom >= offsetPosition.bottom) {
9002 if (next.page.left >= offsetPosition.left + offsetBorder.left && next.page.right >= offsetPosition.right) {
9003 // We're within the visible part of the target's scroll parent
9004 var scrollTop = offsetParent.scrollTop;
9005 var scrollLeft = offsetParent.scrollLeft;
9006
9007 // It's position relative to the target's offset parent (absolute positioning when
9008 // the element is moved to be a child of the target's offset parent).
9009 next.offset = {
9010 top: next.page.top - offsetPosition.top + scrollTop - offsetBorder.top,
9011 left: next.page.left - offsetPosition.left + scrollLeft - offsetBorder.left
9012 };
9013 }
9014 }
9015 })();
9016 }
9017
9018 // We could also travel up the DOM and try each containing context, rather than only
9019 // looking at the body, but we're gonna get diminishing returns.
9020
9021 this.move(next);
9022
9023 this.history.unshift(next);
9024
9025 if (this.history.length > 3) {
9026 this.history.pop();
9027 }
9028
9029 if (flushChanges) {
9030 flush();
9031 }
9032
9033 return true;
9034 }
9035
9036 // THE ISSUE
9037 }, {
9038 key: 'move',
9039 value: function move(pos) {
9040 var _this8 = this;
9041
9042 if (!(typeof this.element.parentNode !== 'undefined')) {
9043 return;
9044 }
9045
9046 var same = {};
9047
9048 for (var type in pos) {
9049 same[type] = {};
9050
9051 for (var key in pos[type]) {
9052 var found = false;
9053
9054 for (var i = 0; i < this.history.length; ++i) {
9055 var point = this.history[i];
9056 if (typeof point[type] !== 'undefined' && !within(point[type][key], pos[type][key])) {
9057 found = true;
9058 break;
9059 }
9060 }
9061
9062 if (!found) {
9063 same[type][key] = true;
9064 }
9065 }
9066 }
9067
9068 var css = { top: '', left: '', right: '', bottom: '' };
9069
9070 var transcribe = function transcribe(_same, _pos) {
9071 var hasOptimizations = typeof _this8.options.optimizations !== 'undefined';
9072 var gpu = hasOptimizations ? _this8.options.optimizations.gpu : null;
9073 if (gpu !== false) {
9074 var yPos = undefined,
9075 xPos = undefined;
9076 if (_same.top) {
9077 css.top = 0;
9078 yPos = _pos.top;
9079 } else {
9080 css.bottom = 0;
9081 yPos = -_pos.bottom;
9082 }
9083
9084 if (_same.left) {
9085 css.left = 0;
9086 xPos = _pos.left;
9087 } else {
9088 css.right = 0;
9089 xPos = -_pos.right;
9090 }
9091
9092 if (window.matchMedia) {
9093 // HubSpot/tether#207
9094 var retina = window.matchMedia('only screen and (min-resolution: 1.3dppx)').matches || window.matchMedia('only screen and (-webkit-min-device-pixel-ratio: 1.3)').matches;
9095 if (!retina) {
9096 xPos = Math.round(xPos);
9097 yPos = Math.round(yPos);
9098 }
9099 }
9100
9101 css[transformKey] = 'translateX(' + xPos + 'px) translateY(' + yPos + 'px)';
9102
9103 if (transformKey !== 'msTransform') {
9104 // The Z transform will keep this in the GPU (faster, and prevents artifacts),
9105 // but IE9 doesn't support 3d transforms and will choke.
9106 css[transformKey] += " translateZ(0)";
9107 }
9108 } else {
9109 if (_same.top) {
9110 css.top = _pos.top + 'px';
9111 } else {
9112 css.bottom = _pos.bottom + 'px';
9113 }
9114
9115 if (_same.left) {
9116 css.left = _pos.left + 'px';
9117 } else {
9118 css.right = _pos.right + 'px';
9119 }
9120 }
9121 };
9122
9123 var moved = false;
9124 if ((same.page.top || same.page.bottom) && (same.page.left || same.page.right)) {
9125 css.position = 'absolute';
9126 transcribe(same.page, pos.page);
9127 } else if ((same.viewport.top || same.viewport.bottom) && (same.viewport.left || same.viewport.right)) {
9128 css.position = 'fixed';
9129 transcribe(same.viewport, pos.viewport);
9130 } else if (typeof same.offset !== 'undefined' && same.offset.top && same.offset.left) {
9131 (function () {
9132 css.position = 'absolute';
9133 var offsetParent = _this8.cache('target-offsetparent', function () {
9134 return getOffsetParent(_this8.target);
9135 });
9136
9137 if (getOffsetParent(_this8.element) !== offsetParent) {
9138 defer(function () {
9139 _this8.element.parentNode.removeChild(_this8.element);
9140 offsetParent.appendChild(_this8.element);
9141 });
9142 }
9143
9144 transcribe(same.offset, pos.offset);
9145 moved = true;
9146 })();
9147 } else {
9148 css.position = 'absolute';
9149 transcribe({ top: true, left: true }, pos.page);
9150 }
9151
9152 if (!moved) {
9153 if (this.options.bodyElement) {
9154 if (this.element.parentNode !== this.options.bodyElement) {
9155 this.options.bodyElement.appendChild(this.element);
9156 }
9157 } else {
9158 var offsetParentIsBody = true;
9159 var currentNode = this.element.parentNode;
9160 while (currentNode && currentNode.nodeType === 1 && currentNode.tagName !== 'BODY') {
9161 if (getComputedStyle(currentNode).position !== 'static') {
9162 offsetParentIsBody = false;
9163 break;
9164 }
9165
9166 currentNode = currentNode.parentNode;
9167 }
9168
9169 if (!offsetParentIsBody) {
9170 this.element.parentNode.removeChild(this.element);
9171 this.element.ownerDocument.body.appendChild(this.element);
9172 }
9173 }
9174 }
9175
9176 // Any css change will trigger a repaint, so let's avoid one if nothing changed
9177 var writeCSS = {};
9178 var write = false;
9179 for (var key in css) {
9180 var val = css[key];
9181 var elVal = this.element.style[key];
9182
9183 if (elVal !== val) {
9184 write = true;
9185 writeCSS[key] = val;
9186 }
9187 }
9188
9189 if (write) {
9190 defer(function () {
9191 extend(_this8.element.style, writeCSS);
9192 _this8.trigger('repositioned');
9193 });
9194 }
9195 }
9196 }]);
9197
9198 return TetherClass;
9199})(Evented);
9200
9201TetherClass.modules = [];
9202
9203TetherBase.position = position;
9204
9205var Tether = extend(TetherClass, TetherBase);
9206/* globals TetherBase */
9207
9208'use strict';
9209
9210var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
9211
9212var _TetherBase$Utils = TetherBase.Utils;
9213var getBounds = _TetherBase$Utils.getBounds;
9214var extend = _TetherBase$Utils.extend;
9215var updateClasses = _TetherBase$Utils.updateClasses;
9216var defer = _TetherBase$Utils.defer;
9217
9218var BOUNDS_FORMAT = ['left', 'top', 'right', 'bottom'];
9219
9220function getBoundingRect(tether, to) {
9221 if (to === 'scrollParent') {
9222 to = tether.scrollParents[0];
9223 } else if (to === 'window') {
9224 to = [pageXOffset, pageYOffset, innerWidth + pageXOffset, innerHeight + pageYOffset];
9225 }
9226
9227 if (to === document) {
9228 to = to.documentElement;
9229 }
9230
9231 if (typeof to.nodeType !== 'undefined') {
9232 (function () {
9233 var node = to;
9234 var size = getBounds(to);
9235 var pos = size;
9236 var style = getComputedStyle(to);
9237
9238 to = [pos.left, pos.top, size.width + pos.left, size.height + pos.top];
9239
9240 // Account any parent Frames scroll offset
9241 if (node.ownerDocument !== document) {
9242 var win = node.ownerDocument.defaultView;
9243 to[0] += win.pageXOffset;
9244 to[1] += win.pageYOffset;
9245 to[2] += win.pageXOffset;
9246 to[3] += win.pageYOffset;
9247 }
9248
9249 BOUNDS_FORMAT.forEach(function (side, i) {
9250 side = side[0].toUpperCase() + side.substr(1);
9251 if (side === 'Top' || side === 'Left') {
9252 to[i] += parseFloat(style['border' + side + 'Width']);
9253 } else {
9254 to[i] -= parseFloat(style['border' + side + 'Width']);
9255 }
9256 });
9257 })();
9258 }
9259
9260 return to;
9261}
9262
9263TetherBase.modules.push({
9264 position: function position(_ref) {
9265 var _this = this;
9266
9267 var top = _ref.top;
9268 var left = _ref.left;
9269 var targetAttachment = _ref.targetAttachment;
9270
9271 if (!this.options.constraints) {
9272 return true;
9273 }
9274
9275 var _cache = this.cache('element-bounds', function () {
9276 return getBounds(_this.element);
9277 });
9278
9279 var height = _cache.height;
9280 var width = _cache.width;
9281
9282 if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') {
9283 var _lastSize = this.lastSize;
9284
9285 // Handle the item getting hidden as a result of our positioning without glitching
9286 // the classes in and out
9287 width = _lastSize.width;
9288 height = _lastSize.height;
9289 }
9290
9291 var targetSize = this.cache('target-bounds', function () {
9292 return _this.getTargetBounds();
9293 });
9294
9295 var targetHeight = targetSize.height;
9296 var targetWidth = targetSize.width;
9297
9298 var allClasses = [this.getClass('pinned'), this.getClass('out-of-bounds')];
9299
9300 this.options.constraints.forEach(function (constraint) {
9301 var outOfBoundsClass = constraint.outOfBoundsClass;
9302 var pinnedClass = constraint.pinnedClass;
9303
9304 if (outOfBoundsClass) {
9305 allClasses.push(outOfBoundsClass);
9306 }
9307 if (pinnedClass) {
9308 allClasses.push(pinnedClass);
9309 }
9310 });
9311
9312 allClasses.forEach(function (cls) {
9313 ['left', 'top', 'right', 'bottom'].forEach(function (side) {
9314 allClasses.push(cls + '-' + side);
9315 });
9316 });
9317
9318 var addClasses = [];
9319
9320 var tAttachment = extend({}, targetAttachment);
9321 var eAttachment = extend({}, this.attachment);
9322
9323 this.options.constraints.forEach(function (constraint) {
9324 var to = constraint.to;
9325 var attachment = constraint.attachment;
9326 var pin = constraint.pin;
9327
9328 if (typeof attachment === 'undefined') {
9329 attachment = '';
9330 }
9331
9332 var changeAttachX = undefined,
9333 changeAttachY = undefined;
9334 if (attachment.indexOf(' ') >= 0) {
9335 var _attachment$split = attachment.split(' ');
9336
9337 var _attachment$split2 = _slicedToArray(_attachment$split, 2);
9338
9339 changeAttachY = _attachment$split2[0];
9340 changeAttachX = _attachment$split2[1];
9341 } else {
9342 changeAttachX = changeAttachY = attachment;
9343 }
9344
9345 var bounds = getBoundingRect(_this, to);
9346
9347 if (changeAttachY === 'target' || changeAttachY === 'both') {
9348 if (top < bounds[1] && tAttachment.top === 'top') {
9349 top += targetHeight;
9350 tAttachment.top = 'bottom';
9351 }
9352
9353 if (top + height > bounds[3] && tAttachment.top === 'bottom') {
9354 top -= targetHeight;
9355 tAttachment.top = 'top';
9356 }
9357 }
9358
9359 if (changeAttachY === 'together') {
9360 if (tAttachment.top === 'top') {
9361 if (eAttachment.top === 'bottom' && top < bounds[1]) {
9362 top += targetHeight;
9363 tAttachment.top = 'bottom';
9364
9365 top += height;
9366 eAttachment.top = 'top';
9367 } else if (eAttachment.top === 'top' && top + height > bounds[3] && top - (height - targetHeight) >= bounds[1]) {
9368 top -= height - targetHeight;
9369 tAttachment.top = 'bottom';
9370
9371 eAttachment.top = 'bottom';
9372 }
9373 }
9374
9375 if (tAttachment.top === 'bottom') {
9376 if (eAttachment.top === 'top' && top + height > bounds[3]) {
9377 top -= targetHeight;
9378 tAttachment.top = 'top';
9379
9380 top -= height;
9381 eAttachment.top = 'bottom';
9382 } else if (eAttachment.top === 'bottom' && top < bounds[1] && top + (height * 2 - targetHeight) <= bounds[3]) {
9383 top += height - targetHeight;
9384 tAttachment.top = 'top';
9385
9386 eAttachment.top = 'top';
9387 }
9388 }
9389
9390 if (tAttachment.top === 'middle') {
9391 if (top + height > bounds[3] && eAttachment.top === 'top') {
9392 top -= height;
9393 eAttachment.top = 'bottom';
9394 } else if (top < bounds[1] && eAttachment.top === 'bottom') {
9395 top += height;
9396 eAttachment.top = 'top';
9397 }
9398 }
9399 }
9400
9401 if (changeAttachX === 'target' || changeAttachX === 'both') {
9402 if (left < bounds[0] && tAttachment.left === 'left') {
9403 left += targetWidth;
9404 tAttachment.left = 'right';
9405 }
9406
9407 if (left + width > bounds[2] && tAttachment.left === 'right') {
9408 left -= targetWidth;
9409 tAttachment.left = 'left';
9410 }
9411 }
9412
9413 if (changeAttachX === 'together') {
9414 if (left < bounds[0] && tAttachment.left === 'left') {
9415 if (eAttachment.left === 'right') {
9416 left += targetWidth;
9417 tAttachment.left = 'right';
9418
9419 left += width;
9420 eAttachment.left = 'left';
9421 } else if (eAttachment.left === 'left') {
9422 left += targetWidth;
9423 tAttachment.left = 'right';
9424
9425 left -= width;
9426 eAttachment.left = 'right';
9427 }
9428 } else if (left + width > bounds[2] && tAttachment.left === 'right') {
9429 if (eAttachment.left === 'left') {
9430 left -= targetWidth;
9431 tAttachment.left = 'left';
9432
9433 left -= width;
9434 eAttachment.left = 'right';
9435 } else if (eAttachment.left === 'right') {
9436 left -= targetWidth;
9437 tAttachment.left = 'left';
9438
9439 left += width;
9440 eAttachment.left = 'left';
9441 }
9442 } else if (tAttachment.left === 'center') {
9443 if (left + width > bounds[2] && eAttachment.left === 'left') {
9444 left -= width;
9445 eAttachment.left = 'right';
9446 } else if (left < bounds[0] && eAttachment.left === 'right') {
9447 left += width;
9448 eAttachment.left = 'left';
9449 }
9450 }
9451 }
9452
9453 if (changeAttachY === 'element' || changeAttachY === 'both') {
9454 if (top < bounds[1] && eAttachment.top === 'bottom') {
9455 top += height;
9456 eAttachment.top = 'top';
9457 }
9458
9459 if (top + height > bounds[3] && eAttachment.top === 'top') {
9460 top -= height;
9461 eAttachment.top = 'bottom';
9462 }
9463 }
9464
9465 if (changeAttachX === 'element' || changeAttachX === 'both') {
9466 if (left < bounds[0]) {
9467 if (eAttachment.left === 'right') {
9468 left += width;
9469 eAttachment.left = 'left';
9470 } else if (eAttachment.left === 'center') {
9471 left += width / 2;
9472 eAttachment.left = 'left';
9473 }
9474 }
9475
9476 if (left + width > bounds[2]) {
9477 if (eAttachment.left === 'left') {
9478 left -= width;
9479 eAttachment.left = 'right';
9480 } else if (eAttachment.left === 'center') {
9481 left -= width / 2;
9482 eAttachment.left = 'right';
9483 }
9484 }
9485 }
9486
9487 if (typeof pin === 'string') {
9488 pin = pin.split(',').map(function (p) {
9489 return p.trim();
9490 });
9491 } else if (pin === true) {
9492 pin = ['top', 'left', 'right', 'bottom'];
9493 }
9494
9495 pin = pin || [];
9496
9497 var pinned = [];
9498 var oob = [];
9499
9500 if (top < bounds[1]) {
9501 if (pin.indexOf('top') >= 0) {
9502 top = bounds[1];
9503 pinned.push('top');
9504 } else {
9505 oob.push('top');
9506 }
9507 }
9508
9509 if (top + height > bounds[3]) {
9510 if (pin.indexOf('bottom') >= 0) {
9511 top = bounds[3] - height;
9512 pinned.push('bottom');
9513 } else {
9514 oob.push('bottom');
9515 }
9516 }
9517
9518 if (left < bounds[0]) {
9519 if (pin.indexOf('left') >= 0) {
9520 left = bounds[0];
9521 pinned.push('left');
9522 } else {
9523 oob.push('left');
9524 }
9525 }
9526
9527 if (left + width > bounds[2]) {
9528 if (pin.indexOf('right') >= 0) {
9529 left = bounds[2] - width;
9530 pinned.push('right');
9531 } else {
9532 oob.push('right');
9533 }
9534 }
9535
9536 if (pinned.length) {
9537 (function () {
9538 var pinnedClass = undefined;
9539 if (typeof _this.options.pinnedClass !== 'undefined') {
9540 pinnedClass = _this.options.pinnedClass;
9541 } else {
9542 pinnedClass = _this.getClass('pinned');
9543 }
9544
9545 addClasses.push(pinnedClass);
9546 pinned.forEach(function (side) {
9547 addClasses.push(pinnedClass + '-' + side);
9548 });
9549 })();
9550 }
9551
9552 if (oob.length) {
9553 (function () {
9554 var oobClass = undefined;
9555 if (typeof _this.options.outOfBoundsClass !== 'undefined') {
9556 oobClass = _this.options.outOfBoundsClass;
9557 } else {
9558 oobClass = _this.getClass('out-of-bounds');
9559 }
9560
9561 addClasses.push(oobClass);
9562 oob.forEach(function (side) {
9563 addClasses.push(oobClass + '-' + side);
9564 });
9565 })();
9566 }
9567
9568 if (pinned.indexOf('left') >= 0 || pinned.indexOf('right') >= 0) {
9569 eAttachment.left = tAttachment.left = false;
9570 }
9571 if (pinned.indexOf('top') >= 0 || pinned.indexOf('bottom') >= 0) {
9572 eAttachment.top = tAttachment.top = false;
9573 }
9574
9575 if (tAttachment.top !== targetAttachment.top || tAttachment.left !== targetAttachment.left || eAttachment.top !== _this.attachment.top || eAttachment.left !== _this.attachment.left) {
9576 _this.updateAttachClasses(eAttachment, tAttachment);
9577 _this.trigger('update', {
9578 attachment: eAttachment,
9579 targetAttachment: tAttachment
9580 });
9581 }
9582 });
9583
9584 defer(function () {
9585 if (!(_this.options.addTargetClasses === false)) {
9586 updateClasses(_this.target, addClasses, allClasses);
9587 }
9588 updateClasses(_this.element, addClasses, allClasses);
9589 });
9590
9591 return { top: top, left: left };
9592 }
9593});
9594/* globals TetherBase */
9595
9596'use strict';
9597
9598var _TetherBase$Utils = TetherBase.Utils;
9599var getBounds = _TetherBase$Utils.getBounds;
9600var updateClasses = _TetherBase$Utils.updateClasses;
9601var defer = _TetherBase$Utils.defer;
9602
9603TetherBase.modules.push({
9604 position: function position(_ref) {
9605 var _this = this;
9606
9607 var top = _ref.top;
9608 var left = _ref.left;
9609
9610 var _cache = this.cache('element-bounds', function () {
9611 return getBounds(_this.element);
9612 });
9613
9614 var height = _cache.height;
9615 var width = _cache.width;
9616
9617 var targetPos = this.getTargetBounds();
9618
9619 var bottom = top + height;
9620 var right = left + width;
9621
9622 var abutted = [];
9623 if (top <= targetPos.bottom && bottom >= targetPos.top) {
9624 ['left', 'right'].forEach(function (side) {
9625 var targetPosSide = targetPos[side];
9626 if (targetPosSide === left || targetPosSide === right) {
9627 abutted.push(side);
9628 }
9629 });
9630 }
9631
9632 if (left <= targetPos.right && right >= targetPos.left) {
9633 ['top', 'bottom'].forEach(function (side) {
9634 var targetPosSide = targetPos[side];
9635 if (targetPosSide === top || targetPosSide === bottom) {
9636 abutted.push(side);
9637 }
9638 });
9639 }
9640
9641 var allClasses = [];
9642 var addClasses = [];
9643
9644 var sides = ['left', 'top', 'right', 'bottom'];
9645 allClasses.push(this.getClass('abutted'));
9646 sides.forEach(function (side) {
9647 allClasses.push(_this.getClass('abutted') + '-' + side);
9648 });
9649
9650 if (abutted.length) {
9651 addClasses.push(this.getClass('abutted'));
9652 }
9653
9654 abutted.forEach(function (side) {
9655 addClasses.push(_this.getClass('abutted') + '-' + side);
9656 });
9657
9658 defer(function () {
9659 if (!(_this.options.addTargetClasses === false)) {
9660 updateClasses(_this.target, addClasses, allClasses);
9661 }
9662 updateClasses(_this.element, addClasses, allClasses);
9663 });
9664
9665 return true;
9666 }
9667});
9668/* globals TetherBase */
9669
9670'use strict';
9671
9672var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
9673
9674TetherBase.modules.push({
9675 position: function position(_ref) {
9676 var top = _ref.top;
9677 var left = _ref.left;
9678
9679 if (!this.options.shift) {
9680 return;
9681 }
9682
9683 var shift = this.options.shift;
9684 if (typeof this.options.shift === 'function') {
9685 shift = this.options.shift.call(this, { top: top, left: left });
9686 }
9687
9688 var shiftTop = undefined,
9689 shiftLeft = undefined;
9690 if (typeof shift === 'string') {
9691 shift = shift.split(' ');
9692 shift[1] = shift[1] || shift[0];
9693
9694 var _shift = shift;
9695
9696 var _shift2 = _slicedToArray(_shift, 2);
9697
9698 shiftTop = _shift2[0];
9699 shiftLeft = _shift2[1];
9700
9701 shiftTop = parseFloat(shiftTop, 10);
9702 shiftLeft = parseFloat(shiftLeft, 10);
9703 } else {
9704 shiftTop = shift.top;
9705 shiftLeft = shift.left;
9706 }
9707
9708 top += shiftTop;
9709 left += shiftLeft;
9710
9711 return { top: top, left: left };
9712 }
9713});
9714return Tether;
9715
9716}));
9717
9718
9719/***/ }),
9720/* 91 */
9721/***/ (function(module, exports, __webpack_require__) {
9722
9723var Service = __webpack_require__(12);
9724var Backbone = __webpack_require__(4);
9725var LayoutView = __webpack_require__(92);
9726var AlertView = __webpack_require__(98);
9727var $ = __webpack_require__(3);
9728var _ = __webpack_require__(0);
9729var globalChannel = __webpack_require__(2).channel('global');
9730
9731module.exports = Service.extend({
9732 channelName: 'modal',
9733
9734 initialize: function(options){
9735 this.container = options.container;
9736 this.start();
9737 },
9738
9739 onStart: function(){
9740 this.channel.reply({
9741 'open' : this.open,
9742 'close' : this.close,
9743 'alert' : this.alert,
9744 'confirm' : this.confirm,
9745 'prompt' : this.prompt
9746 }, this);
9747
9748 this.layout = new LayoutView();
9749 this.container.show(this.layout);
9750
9751 this.channel.reply({
9752 'update': this.layout.update
9753 }, this.layout);
9754
9755 globalChannel.on({
9756 'error' : this.error
9757 }, this);
9758
9759 this.listenTo(Backbone.history, {
9760 'route' : this.onRoute
9761 });
9762 },
9763
9764 onStop: function(){
9765 delete this.layout;
9766 this.container.reset();
9767 this.channel.reset();
9768 },
9769
9770 onRoute: function(){
9771 if (this.fragment !== Backbone.history.fragment) {
9772 this.close();
9773 }
9774 },
9775
9776 //alert: function(options){
9777 // var deferred = $.Deferred();
9778 // var view = new AlertView(options);
9779 //
9780 // view.on({
9781 // 'confirm' : deferred.resolve,
9782 // 'cancel' : deferred.resolve
9783 // });
9784 //
9785 // return deferred;
9786 //},
9787 //
9788 //confirm: function(options){
9789 // var deferred = $.Deferred();
9790 // var view = new ConfirmView(options);
9791 //
9792 // view.on({
9793 // 'confirm' : deferred.resolve,
9794 // 'cancel' : deferred.reject
9795 // });
9796 //
9797 // return deferred;
9798 //},
9799 //
9800 //prompt: function(options){
9801 // var deferred = $.Deferred();
9802 // var view = new PromptView(options);
9803 //
9804 // view.on({
9805 // 'submit' : deferred.resolve,
9806 // 'cancel' : deferred.reject
9807 // });
9808 //
9809 // return deferred;
9810 //},
9811
9812 open: function(view){
9813 var self = this;
9814 this.fragment = Backbone.history.fragment;
9815 return this.close().then(function() {
9816 self.isOpen = true;
9817 return self.layout.open(view);
9818 });
9819 },
9820
9821 close: function(){
9822 if (this.isOpen) {
9823 this.isOpen = false;
9824 return this.layout.close();
9825 } else {
9826 return $.Deferred().resolve();
9827 }
9828 },
9829
9830 error: function(options){
9831 options = options || {};
9832
9833 if(options.jqXHR){
9834 this.parseXHR(options);
9835 }
9836
9837 var view = new AlertView({
9838 className : 'error',
9839 title : options.status,
9840 message : options.message,
9841 raw : options.raw
9842 });
9843
9844 this.open(view);
9845 },
9846
9847 parseXHR: function(options){
9848 if( _.isObject(options.thrownError) ){
9849 options.status = options.thrownError.name;
9850 options.message = options.thrownError.message;
9851 } else {
9852 options.status = options.jqXHR.statusText;
9853 if(options.jqXHR.responseJSON && options.jqXHR.responseJSON.message) {
9854 options.message = options.jqXHR.responseJSON.message;
9855 }
9856 else if( options.jqXHR.responseJSON &&
9857 options.jqXHR.responseJSON.errors &&
9858 options.jqXHR.responseJSON.errors[0] ){
9859 options.message = options.jqXHR.responseJSON.errors[0].message;
9860 }
9861 }
9862 options.raw = options.jqXHR.responseText;
9863 }
9864
9865});
9866
9867/***/ }),
9868/* 92 */
9869/***/ (function(module, exports, __webpack_require__) {
9870
9871var LayoutView = __webpack_require__(10);
9872var Header = __webpack_require__(93);
9873var _ = __webpack_require__(0);
9874var $ = __webpack_require__(3);
9875var hbs = __webpack_require__(7);
9876var Tmpl = __webpack_require__(95);
9877var Radio = __webpack_require__(2);
9878var debug = __webpack_require__(8)('modalLayout');
9879var App = __webpack_require__(1);
9880__webpack_require__(96);
9881
9882module.exports = LayoutView.extend({
9883 template: hbs.compile(Tmpl),
9884
9885 // if wp-admin, add css prefix
9886 className: function(){
9887 return App.prototype.namespace('modal');
9888 },
9889
9890 attributes: {
9891 'tabindex' : -1,
9892 'role' : 'dialog'
9893 },
9894
9895 buttons: [
9896 {
9897 type: 'message'
9898 },{
9899 action: 'save',
9900 icon: 'prepend',
9901 className: 'btn-primary'
9902 }
9903 ],
9904
9905 regions: {
9906 header : '.modal-header',
9907 content : '.modal-body',
9908 footer : '.modal-footer'
9909 },
9910
9911 initialize: function () {
9912 this.$el.modal({ show: false, backdrop: 'static' });
9913 },
9914
9915 events: {
9916 'click [data-action="close"]' : function(e){
9917 e.preventDefault();
9918 Radio.request('modal', 'close');
9919 }
9920 },
9921
9922 triggers: {
9923 'show.bs.modal' : { preventDefault: false, event: 'before:open' },
9924 'shown.bs.modal' : { preventDefault: false, event: 'open' },
9925 'hide.bs.modal' : { preventDefault: false, event: 'before:close' },
9926 'hidden.bs.modal' : { preventDefault: false, event: 'close' }
9927 },
9928
9929 open: function(view){
9930 var deferred = $.Deferred();
9931 this.once('open', deferred.resolve);
9932 this.setup(view);
9933 this.content.show(view);
9934 this.$el.modal('show');
9935 return deferred;
9936 },
9937
9938 close: function() {
9939 var deferred = $.Deferred();
9940 this.once('close', function() {
9941 this.tearDown();
9942 deferred.resolve();
9943 });
9944 this.$el.modal('hide');
9945 return deferred;
9946 },
9947
9948 setup: function(view){
9949 var attributes = view.modal || {};
9950
9951 _.defaults(attributes, {
9952 header: {},
9953 footer: {}
9954 });
9955
9956 _.each(attributes, function(attr, key){
9957 var method = $.camelCase('modal-' + key);
9958 if(this[method]){
9959 this[method](attr);
9960 } else {
9961 debug('no method matching ' + method);
9962 }
9963 }, this);
9964 },
9965
9966 tearDown: function(){
9967 this.header.empty();
9968 this.content.empty();
9969 this.footer.empty();
9970 this.$('.modal-dialog').removeClass().addClass('modal-dialog');
9971 },
9972
9973 update: function(options){
9974 options = options || {};
9975 _.each(options, function(attr, key){
9976 this[key].currentView.triggerMethod('Update', attr);
9977 }, this);
9978 },
9979
9980 modalHeader: function(options){
9981 var view = new Header(options);
9982 this.header.show(view);
9983 },
9984
9985 modalFooter: function(options){
9986 options.buttons = options.buttons || this.buttons;
9987 var view = Radio.request('buttons', 'view', options);
9988 this.footer.show(view);
9989 },
9990
9991 modalTitle: function(title){
9992 //title = title || this.$('.modal-header h1').data('title');
9993 this.$('.modal-header h1').html(title);
9994 },
9995
9996 modalClassName: function(className){
9997 if(className){
9998 this.$('.modal-dialog').addClass(className);
9999 }
10000 },
10001
10002 getButtons: function(){
10003 return this.getRegion('footer').currentView;
10004 }
10005
10006});
10007
10008/***/ }),
10009/* 93 */
10010/***/ (function(module, exports, __webpack_require__) {
10011
10012var ItemView = __webpack_require__(5);
10013var hbs = __webpack_require__(7);
10014var Tmpl = __webpack_require__(94);
10015var _ = __webpack_require__(0);
10016var polyglot = __webpack_require__(6);
10017
10018module.exports = ItemView.extend({
10019 template: hbs.compile(Tmpl),
10020
10021 initialize: function(options){
10022 options = options || {};
10023 var defaults = {
10024 title: polyglot.t('messages.loading'),
10025 close: polyglot.t('buttons.close')
10026 };
10027 this.data = _.defaults(options, defaults);
10028 },
10029
10030 templateHelpers: function(){
10031 this.data.iconPrefix = window.adminpage ? 'wc_pos-icon' : 'icon';
10032 return this.data;
10033 },
10034
10035 onUpdate: function(options){
10036 _.extend(this.data, options);
10037 this.render();
10038 }
10039});
10040
10041/***/ }),
10042/* 94 */
10043/***/ (function(module, exports) {
10044
10045module.exports = "<h4 class=\"{{namespace 'modal-title'}} modal-title\">\r\n {{{title}}}\r\n</h4>\r\n<a class=\"{{namespace 'btn'}} close\" data-action=\"close\">\r\n <i class=\"{{namespace 'icon-times'}}\" title=\"{{close}}\"></i>\r\n</a>"
10046
10047/***/ }),
10048/* 95 */
10049/***/ (function(module, exports) {
10050
10051module.exports = "<div class=\"{{namespace 'modal-dialog'}} modal-dialog\">\r\n <div class=\"{{namespace 'modal-content'}} modal-content\">\r\n <div class=\"{{namespace 'modal-header'}} modal-header\"></div>\r\n <div class=\"{{namespace 'modal-body'}} modal-body\"></div>\r\n <div class=\"{{namespace 'modal-footer'}} modal-footer\"></div>\r\n </div>\r\n</div>"
10052
10053/***/ }),
10054/* 96 */
10055/***/ (function(module, exports, __webpack_require__) {
10056
10057var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* jshint ignore:start */
10058(function (global, factory) {
10059 if (true) {
10060 !(__WEBPACK_AMD_DEFINE_ARRAY__ = [exports, module, __webpack_require__(97)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
10061 __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
10062 (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
10063 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
10064 } else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
10065 factory(exports, module, require('./util'));
10066 } else {
10067 var mod = {
10068 exports: {}
10069 };
10070 factory(mod.exports, mod, global.Util);
10071 global.modal = mod.exports;
10072 }
10073})(this, function (exports, module, _util) {
10074 'use strict';
10075
10076 var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
10077
10078 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
10079
10080 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
10081
10082 var _Util = _interopRequireDefault(_util);
10083
10084 /**
10085 * --------------------------------------------------------------------------
10086 * Bootstrap (v4.0.0-alpha.2): modal.js
10087 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
10088 * --------------------------------------------------------------------------
10089 */
10090
10091 var Modal = (function ($) {
10092
10093 /**
10094 * ------------------------------------------------------------------------
10095 * Constants
10096 * ------------------------------------------------------------------------
10097 */
10098
10099 var NAME = 'modal';
10100 var VERSION = '4.0.0-alpha.2';
10101 var DATA_KEY = 'bs.modal';
10102 var EVENT_KEY = '.' + DATA_KEY;
10103 var DATA_API_KEY = '.data-api';
10104 var JQUERY_NO_CONFLICT = $.fn[NAME];
10105 var TRANSITION_DURATION = 300;
10106 var BACKDROP_TRANSITION_DURATION = 150;
10107 var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
10108
10109 var Default = {
10110 backdrop: true,
10111 keyboard: true,
10112 focus: true,
10113 show: true
10114 };
10115
10116 var DefaultType = {
10117 backdrop: '(boolean|string)',
10118 keyboard: 'boolean',
10119 focus: 'boolean',
10120 show: 'boolean'
10121 };
10122
10123 var Event = {
10124 HIDE: 'hide' + EVENT_KEY,
10125 HIDDEN: 'hidden' + EVENT_KEY,
10126 SHOW: 'show' + EVENT_KEY,
10127 SHOWN: 'shown' + EVENT_KEY,
10128 FOCUSIN: 'focusin' + EVENT_KEY,
10129 RESIZE: 'resize' + EVENT_KEY,
10130 CLICK_DISMISS: 'click.dismiss' + EVENT_KEY,
10131 KEYDOWN_DISMISS: 'keydown.dismiss' + EVENT_KEY,
10132 MOUSEUP_DISMISS: 'mouseup.dismiss' + EVENT_KEY,
10133 MOUSEDOWN_DISMISS: 'mousedown.dismiss' + EVENT_KEY,
10134 CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY
10135 };
10136
10137 var ClassName = {
10138 SCROLLBAR_MEASURER: 'modal-scrollbar-measure',
10139 BACKDROP: 'modal-backdrop',
10140 OPEN: 'modal-open',
10141 FADE: 'fade',
10142 IN: 'in'
10143 };
10144
10145 var Selector = {
10146 DIALOG: '.modal-dialog',
10147 DATA_TOGGLE: '[data-toggle="modal"]',
10148 DATA_DISMISS: '[data-dismiss="modal"]',
10149 FIXED_CONTENT: '.navbar-fixed-top, .navbar-fixed-bottom, .is-fixed'
10150 };
10151
10152 /**
10153 * ------------------------------------------------------------------------
10154 * Class Definition
10155 * ------------------------------------------------------------------------
10156 */
10157
10158 var Modal = (function () {
10159 function Modal(element, config) {
10160 _classCallCheck(this, Modal);
10161
10162 this._config = this._getConfig(config);
10163 this._element = element;
10164 this._dialog = $(element).find(Selector.DIALOG)[0];
10165 this._backdrop = null;
10166 this._isShown = false;
10167 this._isBodyOverflowing = false;
10168 this._ignoreBackdropClick = false;
10169 this._originalBodyPadding = 0;
10170 this._scrollbarWidth = 0;
10171 }
10172
10173 /**
10174 * ------------------------------------------------------------------------
10175 * Data Api implementation
10176 * ------------------------------------------------------------------------
10177 */
10178
10179 // getters
10180
10181 _createClass(Modal, [{
10182 key: 'toggle',
10183
10184 // public
10185
10186 value: function toggle(relatedTarget) {
10187 return this._isShown ? this.hide() : this.show(relatedTarget);
10188 }
10189 }, {
10190 key: 'show',
10191 value: function show(relatedTarget) {
10192 var _this = this;
10193
10194 var showEvent = $.Event(Event.SHOW, {
10195 relatedTarget: relatedTarget
10196 });
10197
10198 $(this._element).trigger(showEvent);
10199
10200 if (this._isShown || showEvent.isDefaultPrevented()) {
10201 return;
10202 }
10203
10204 this._isShown = true;
10205
10206 this._checkScrollbar();
10207 this._setScrollbar();
10208
10209 $(document.body).addClass(ClassName.OPEN);
10210
10211 this._setEscapeEvent();
10212 this._setResizeEvent();
10213
10214 $(this._element).on(Event.CLICK_DISMISS, Selector.DATA_DISMISS, $.proxy(this.hide, this));
10215
10216 $(this._dialog).on(Event.MOUSEDOWN_DISMISS, function () {
10217 $(_this._element).one(Event.MOUSEUP_DISMISS, function (event) {
10218 if ($(event.target).is(_this._element)) {
10219 _this._ignoreBackdropClick = true;
10220 }
10221 });
10222 });
10223
10224 this._showBackdrop($.proxy(this._showElement, this, relatedTarget));
10225 }
10226 }, {
10227 key: 'hide',
10228 value: function hide(event) {
10229 if (event) {
10230 event.preventDefault();
10231 }
10232
10233 var hideEvent = $.Event(Event.HIDE);
10234
10235 $(this._element).trigger(hideEvent);
10236
10237 if (!this._isShown || hideEvent.isDefaultPrevented()) {
10238 return;
10239 }
10240
10241 this._isShown = false;
10242
10243 this._setEscapeEvent();
10244 this._setResizeEvent();
10245
10246 $(document).off(Event.FOCUSIN);
10247
10248 $(this._element).removeClass(ClassName.IN);
10249
10250 $(this._element).off(Event.CLICK_DISMISS);
10251 $(this._dialog).off(Event.MOUSEDOWN_DISMISS);
10252
10253 if (_Util['default'].supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE)) {
10254
10255 $(this._element).one(_Util['default'].TRANSITION_END, $.proxy(this._hideModal, this)).emulateTransitionEnd(TRANSITION_DURATION);
10256 } else {
10257 this._hideModal();
10258 }
10259 }
10260 }, {
10261 key: 'dispose',
10262 value: function dispose() {
10263 $.removeData(this._element, DATA_KEY);
10264
10265 $(window).off(EVENT_KEY);
10266 $(document).off(EVENT_KEY);
10267 $(this._element).off(EVENT_KEY);
10268 $(this._backdrop).off(EVENT_KEY);
10269
10270 this._config = null;
10271 this._element = null;
10272 this._dialog = null;
10273 this._backdrop = null;
10274 this._isShown = null;
10275 this._isBodyOverflowing = null;
10276 this._ignoreBackdropClick = null;
10277 this._originalBodyPadding = null;
10278 this._scrollbarWidth = null;
10279 }
10280
10281 // private
10282
10283 }, {
10284 key: '_getConfig',
10285 value: function _getConfig(config) {
10286 config = $.extend({}, Default, config);
10287 _Util['default'].typeCheckConfig(NAME, config, DefaultType);
10288 return config;
10289 }
10290 }, {
10291 key: '_showElement',
10292 value: function _showElement(relatedTarget) {
10293 var _this2 = this;
10294
10295 var transition = _Util['default'].supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE);
10296
10297 if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
10298 // don't move modals dom position
10299 document.body.appendChild(this._element);
10300 }
10301
10302 this._element.style.display = 'block';
10303 this._element.removeAttribute('aria-hidden');
10304 this._element.scrollTop = 0;
10305
10306 if (transition) {
10307 _Util['default'].reflow(this._element);
10308 }
10309
10310 $(this._element).addClass(ClassName.IN);
10311
10312 if (this._config.focus) {
10313 this._enforceFocus();
10314 }
10315
10316 var shownEvent = $.Event(Event.SHOWN, {
10317 relatedTarget: relatedTarget
10318 });
10319
10320 var transitionComplete = function transitionComplete() {
10321 if (_this2._config.focus) {
10322 _this2._element.focus();
10323 }
10324 $(_this2._element).trigger(shownEvent);
10325 };
10326
10327 if (transition) {
10328 $(this._dialog).one(_Util['default'].TRANSITION_END, transitionComplete).emulateTransitionEnd(TRANSITION_DURATION);
10329 } else {
10330 transitionComplete();
10331 }
10332 }
10333 }, {
10334 key: '_enforceFocus',
10335 value: function _enforceFocus() {
10336 var _this3 = this;
10337
10338 $(document).off(Event.FOCUSIN) // guard against infinite focus loop
10339 .on(Event.FOCUSIN, function (event) {
10340 if (document !== event.target && _this3._element !== event.target && !$(_this3._element).has(event.target).length) {
10341 _this3._element.focus();
10342 }
10343 });
10344 }
10345 }, {
10346 key: '_setEscapeEvent',
10347 value: function _setEscapeEvent() {
10348 var _this4 = this;
10349
10350 if (this._isShown && this._config.keyboard) {
10351 $(this._element).on(Event.KEYDOWN_DISMISS, function (event) {
10352 if (event.which === ESCAPE_KEYCODE) {
10353 _this4.hide();
10354 }
10355 });
10356 } else if (!this._isShown) {
10357 $(this._element).off(Event.KEYDOWN_DISMISS);
10358 }
10359 }
10360 }, {
10361 key: '_setResizeEvent',
10362 value: function _setResizeEvent() {
10363 if (this._isShown) {
10364 $(window).on(Event.RESIZE, $.proxy(this._handleUpdate, this));
10365 } else {
10366 $(window).off(Event.RESIZE);
10367 }
10368 }
10369 }, {
10370 key: '_hideModal',
10371 value: function _hideModal() {
10372 var _this5 = this;
10373
10374 this._element.style.display = 'none';
10375 this._element.setAttribute('aria-hidden', 'true');
10376 this._showBackdrop(function () {
10377 $(document.body).removeClass(ClassName.OPEN);
10378 _this5._resetAdjustments();
10379 _this5._resetScrollbar();
10380 $(_this5._element).trigger(Event.HIDDEN);
10381 });
10382 }
10383 }, {
10384 key: '_removeBackdrop',
10385 value: function _removeBackdrop() {
10386 if (this._backdrop) {
10387 $(this._backdrop).remove();
10388 this._backdrop = null;
10389 }
10390 }
10391 }, {
10392 key: '_showBackdrop',
10393 value: function _showBackdrop(callback) {
10394 var _this6 = this;
10395
10396 var animate = $(this._element).hasClass(ClassName.FADE) ? ClassName.FADE : '';
10397
10398 if (this._isShown && this._config.backdrop) {
10399 var doAnimate = _Util['default'].supportsTransitionEnd() && animate;
10400
10401 this._backdrop = document.createElement('div');
10402 this._backdrop.className = ClassName.BACKDROP;
10403
10404 if (animate) {
10405 $(this._backdrop).addClass(animate);
10406 }
10407
10408 $(this._backdrop).appendTo(document.body);
10409
10410 $(this._element).on(Event.CLICK_DISMISS, function (event) {
10411 if (_this6._ignoreBackdropClick) {
10412 _this6._ignoreBackdropClick = false;
10413 return;
10414 }
10415 if (event.target !== event.currentTarget) {
10416 return;
10417 }
10418 if (_this6._config.backdrop === 'static') {
10419 _this6._element.focus();
10420 } else {
10421 _this6.hide();
10422 }
10423 });
10424
10425 if (doAnimate) {
10426 _Util['default'].reflow(this._backdrop);
10427 }
10428
10429 $(this._backdrop).addClass(ClassName.IN);
10430
10431 if (!callback) {
10432 return;
10433 }
10434
10435 if (!doAnimate) {
10436 callback();
10437 return;
10438 }
10439
10440 $(this._backdrop).one(_Util['default'].TRANSITION_END, callback).emulateTransitionEnd(BACKDROP_TRANSITION_DURATION);
10441 } else if (!this._isShown && this._backdrop) {
10442 $(this._backdrop).removeClass(ClassName.IN);
10443
10444 var callbackRemove = function callbackRemove() {
10445 _this6._removeBackdrop();
10446 if (callback) {
10447 callback();
10448 }
10449 };
10450
10451 if (_Util['default'].supportsTransitionEnd() && $(this._element).hasClass(ClassName.FADE)) {
10452 $(this._backdrop).one(_Util['default'].TRANSITION_END, callbackRemove).emulateTransitionEnd(BACKDROP_TRANSITION_DURATION);
10453 } else {
10454 callbackRemove();
10455 }
10456 } else if (callback) {
10457 callback();
10458 }
10459 }
10460
10461 // ----------------------------------------------------------------------
10462 // the following methods are used to handle overflowing modals
10463 // todo (fat): these should probably be refactored out of modal.js
10464 // ----------------------------------------------------------------------
10465
10466 }, {
10467 key: '_handleUpdate',
10468 value: function _handleUpdate() {
10469 this._adjustDialog();
10470 }
10471 }, {
10472 key: '_adjustDialog',
10473 value: function _adjustDialog() {
10474 var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
10475
10476 if (!this._isBodyOverflowing && isModalOverflowing) {
10477 this._element.style.paddingLeft = this._scrollbarWidth + 'px';
10478 }
10479
10480 if (this._isBodyOverflowing && !isModalOverflowing) {
10481 this._element.style.paddingRight = this._scrollbarWidth + 'px';
10482 }
10483 }
10484 }, {
10485 key: '_resetAdjustments',
10486 value: function _resetAdjustments() {
10487 this._element.style.paddingLeft = '';
10488 this._element.style.paddingRight = '';
10489 }
10490 }, {
10491 key: '_checkScrollbar',
10492 value: function _checkScrollbar() {
10493 this._isBodyOverflowing = document.body.clientWidth < window.innerWidth;
10494 this._scrollbarWidth = this._getScrollbarWidth();
10495 }
10496 }, {
10497 key: '_setScrollbar',
10498 value: function _setScrollbar() {
10499 var bodyPadding = parseInt($(Selector.FIXED_CONTENT).css('padding-right') || 0, 10);
10500
10501 this._originalBodyPadding = document.body.style.paddingRight || '';
10502
10503 if (this._isBodyOverflowing) {
10504 document.body.style.paddingRight = bodyPadding + this._scrollbarWidth + 'px';
10505 }
10506 }
10507 }, {
10508 key: '_resetScrollbar',
10509 value: function _resetScrollbar() {
10510 document.body.style.paddingRight = this._originalBodyPadding;
10511 }
10512 }, {
10513 key: '_getScrollbarWidth',
10514 value: function _getScrollbarWidth() {
10515 // thx d.walsh
10516 var scrollDiv = document.createElement('div');
10517 scrollDiv.className = ClassName.SCROLLBAR_MEASURER;
10518 document.body.appendChild(scrollDiv);
10519 var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
10520 document.body.removeChild(scrollDiv);
10521 return scrollbarWidth;
10522 }
10523
10524 // static
10525
10526 }], [{
10527 key: '_jQueryInterface',
10528 value: function _jQueryInterface(config, relatedTarget) {
10529 return this.each(function () {
10530 var data = $(this).data(DATA_KEY);
10531 var _config = $.extend({}, Modal.Default, $(this).data(), typeof config === 'object' && config);
10532
10533 if (!data) {
10534 data = new Modal(this, _config);
10535 $(this).data(DATA_KEY, data);
10536 }
10537
10538 if (typeof config === 'string') {
10539 if (data[config] === undefined) {
10540 throw new Error('No method named "' + config + '"');
10541 }
10542 data[config](relatedTarget);
10543 } else if (_config.show) {
10544 data.show(relatedTarget);
10545 }
10546 });
10547 }
10548 }, {
10549 key: 'VERSION',
10550 get: function get() {
10551 return VERSION;
10552 }
10553 }, {
10554 key: 'Default',
10555 get: function get() {
10556 return Default;
10557 }
10558 }]);
10559
10560 return Modal;
10561 })();
10562
10563 $(document).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
10564 var _this7 = this;
10565
10566 var target = undefined;
10567 var selector = _Util['default'].getSelectorFromElement(this);
10568
10569 if (selector) {
10570 target = $(selector)[0];
10571 }
10572
10573 var config = $(target).data(DATA_KEY) ? 'toggle' : $.extend({}, $(target).data(), $(this).data());
10574
10575 if (this.tagName === 'A') {
10576 event.preventDefault();
10577 }
10578
10579 var $target = $(target).one(Event.SHOW, function (showEvent) {
10580 if (showEvent.isDefaultPrevented()) {
10581 // only register focus restorer if modal will actually get shown
10582 return;
10583 }
10584
10585 $target.one(Event.HIDDEN, function () {
10586 if ($(_this7).is(':visible')) {
10587 _this7.focus();
10588 }
10589 });
10590 });
10591
10592 Modal._jQueryInterface.call($(target), config, this);
10593 });
10594
10595 /**
10596 * ------------------------------------------------------------------------
10597 * jQuery
10598 * ------------------------------------------------------------------------
10599 */
10600
10601 $.fn[NAME] = Modal._jQueryInterface;
10602 $.fn[NAME].Constructor = Modal;
10603 $.fn[NAME].noConflict = function () {
10604 $.fn[NAME] = JQUERY_NO_CONFLICT;
10605 return Modal._jQueryInterface;
10606 };
10607
10608 return Modal;
10609 })(jQuery);
10610
10611 module.exports = Modal;
10612});
10613/* jshint ignore:end */
10614
10615/***/ }),
10616/* 97 */
10617/***/ (function(module, exports, __webpack_require__) {
10618
10619var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* jshint ignore:start */
10620(function (global, factory) {
10621 if (true) {
10622 !(__WEBPACK_AMD_DEFINE_ARRAY__ = [exports, module], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
10623 __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
10624 (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
10625 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
10626 } else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
10627 factory(exports, module);
10628 } else {
10629 var mod = {
10630 exports: {}
10631 };
10632 factory(mod.exports, mod);
10633 global.util = mod.exports;
10634 }
10635})(this, function (exports, module) {
10636 /**
10637 * --------------------------------------------------------------------------
10638 * Bootstrap (v4.0.0-alpha.2): util.js
10639 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
10640 * --------------------------------------------------------------------------
10641 */
10642
10643 'use strict';
10644
10645 var Util = (function ($) {
10646
10647 /**
10648 * ------------------------------------------------------------------------
10649 * Private TransitionEnd Helpers
10650 * ------------------------------------------------------------------------
10651 */
10652
10653 var transition = false;
10654
10655 var MAX_UID = 1000000;
10656
10657 var TransitionEndEvent = {
10658 WebkitTransition: 'webkitTransitionEnd',
10659 MozTransition: 'transitionend',
10660 OTransition: 'oTransitionEnd otransitionend',
10661 transition: 'transitionend'
10662 };
10663
10664 // shoutout AngusCroll (https://goo.gl/pxwQGp)
10665 function toType(obj) {
10666 return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
10667 }
10668
10669 function isElement(obj) {
10670 return (obj[0] || obj).nodeType;
10671 }
10672
10673 function getSpecialTransitionEndEvent() {
10674 return {
10675 bindType: transition.end,
10676 delegateType: transition.end,
10677 handle: function handle(event) {
10678 if ($(event.target).is(this)) {
10679 return event.handleObj.handler.apply(this, arguments);
10680 }
10681 return undefined;
10682 }
10683 };
10684 }
10685
10686 function transitionEndTest() {
10687 if (window.QUnit) {
10688 return false;
10689 }
10690
10691 var el = document.createElement('bootstrap');
10692
10693 for (var _name in TransitionEndEvent) {
10694 if (el.style[_name] !== undefined) {
10695 return { end: TransitionEndEvent[_name] };
10696 }
10697 }
10698
10699 return false;
10700 }
10701
10702 function transitionEndEmulator(duration) {
10703 var _this = this;
10704
10705 var called = false;
10706
10707 $(this).one(Util.TRANSITION_END, function () {
10708 called = true;
10709 });
10710
10711 setTimeout(function () {
10712 if (!called) {
10713 Util.triggerTransitionEnd(_this);
10714 }
10715 }, duration);
10716
10717 return this;
10718 }
10719
10720 function setTransitionEndSupport() {
10721 transition = transitionEndTest();
10722
10723 $.fn.emulateTransitionEnd = transitionEndEmulator;
10724
10725 if (Util.supportsTransitionEnd()) {
10726 $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();
10727 }
10728 }
10729
10730 /**
10731 * --------------------------------------------------------------------------
10732 * Public Util Api
10733 * --------------------------------------------------------------------------
10734 */
10735
10736 var Util = {
10737
10738 TRANSITION_END: 'bsTransitionEnd',
10739
10740 getUID: function getUID(prefix) {
10741 do {
10742 /* eslint-disable no-bitwise */
10743 prefix += ~ ~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here
10744 /* eslint-enable no-bitwise */
10745 } while (document.getElementById(prefix));
10746 return prefix;
10747 },
10748
10749 getSelectorFromElement: function getSelectorFromElement(element) {
10750 var selector = element.getAttribute('data-target');
10751
10752 if (!selector) {
10753 selector = element.getAttribute('href') || '';
10754 selector = /^#[a-z]/i.test(selector) ? selector : null;
10755 }
10756
10757 return selector;
10758 },
10759
10760 reflow: function reflow(element) {
10761 new Function('bs', 'return bs')(element.offsetHeight);
10762 },
10763
10764 triggerTransitionEnd: function triggerTransitionEnd(element) {
10765 $(element).trigger(transition.end);
10766 },
10767
10768 supportsTransitionEnd: function supportsTransitionEnd() {
10769 return Boolean(transition);
10770 },
10771
10772 typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {
10773 for (var property in configTypes) {
10774 if (configTypes.hasOwnProperty(property)) {
10775 var expectedTypes = configTypes[property];
10776 var value = config[property];
10777 var valueType = undefined;
10778
10779 if (value && isElement(value)) {
10780 valueType = 'element';
10781 } else {
10782 valueType = toType(value);
10783 }
10784
10785 if (!new RegExp(expectedTypes).test(valueType)) {
10786 throw new Error(componentName.toUpperCase() + ': ' + ('Option "' + property + '" provided type "' + valueType + '" ') + ('but expected type "' + expectedTypes + '".'));
10787 }
10788 }
10789 }
10790 }
10791 };
10792
10793 setTransitionEndSupport();
10794
10795 return Util;
10796 })(jQuery);
10797
10798 module.exports = Util;
10799});
10800/* jshint ignore:end */
10801
10802/***/ }),
10803/* 98 */
10804/***/ (function(module, exports, __webpack_require__) {
10805
10806var View = __webpack_require__(5);
10807var hbs = __webpack_require__(7);
10808var Tmpl = __webpack_require__(99);
10809
10810module.exports = View.extend({
10811 template: hbs.compile(Tmpl),
10812
10813 initialize: function(options){
10814 options = options || {};
10815 this.message = options.message;
10816 this.raw = options.raw;
10817
10818 this.modal = {
10819 className: options.className,
10820 header: {
10821 title: options.title
10822 },
10823 footer: {
10824 buttons: [{
10825 action: 'close'
10826 }]
10827 }
10828 };
10829 },
10830
10831 templateHelpers: function(){
10832 var data = {};
10833 data.message = this.message;
10834 data.raw = this.raw;
10835 return data;
10836 },
10837
10838 ui: {
10839 raw: '*[data-action="raw"]',
10840 output: '.raw-output'
10841 },
10842
10843 events: {
10844 'click @ui.raw': 'toggleRaw'
10845 },
10846
10847 toggleRaw: function(e){
10848 e.preventDefault();
10849 this.ui.output.toggle();
10850 }
10851
10852});
10853
10854/***/ }),
10855/* 99 */
10856/***/ (function(module, exports) {
10857
10858module.exports = "<p>\r\n {{message}}\r\n {{#if raw}}\r\n <a href=\"#\" data-action=\"raw\"><i class=\"{{namespace 'icon-info-circle'}}\"></i></a>\r\n {{/if}}\r\n<p>\r\n{{#if raw}}\r\n <div class=\"raw-output\" style=\"display:none\">{{{raw}}}</div>\r\n{{/if}}"
10859
10860/***/ }),
10861/* 100 */
10862/***/ (function(module, exports, __webpack_require__) {
10863
10864var Service = __webpack_require__(12);
10865var TabsView = __webpack_require__(101);
10866var TabsCollection = __webpack_require__(104);
10867//var _ = require('lodash');
10868
10869module.exports = Service.extend({
10870 channelName: 'tabs',
10871
10872 initialize: function (){
10873 this.channel.reply({
10874 'view' : this.tabsView
10875 }, this);
10876 },
10877
10878 /**
10879 * returns an instance of the tabs view
10880 */
10881 tabsView: function(options){
10882 options = options || {};
10883 return new TabsView({
10884 collection: this.tabsCollection(options)
10885 });
10886 },
10887
10888 /**
10889 *
10890 */
10891 tabsCollection: function(options){
10892 return new TabsCollection(options.tabs);
10893 }
10894
10895});
10896
10897/***/ }),
10898/* 101 */
10899/***/ (function(module, exports, __webpack_require__) {
10900
10901var CollectionView = __webpack_require__(25);
10902var Tab = __webpack_require__(102);
10903
10904var View = CollectionView.extend({
10905 tagName: 'ul',
10906 childView: Tab,
10907 attributes: {
10908 'class' : 'tabs',
10909 'role' : 'tablist'
10910 },
10911
10912 setActive: function(id){
10913 var model = this.collection.get(id);
10914 model.set({active: true});
10915 },
10916
10917 setLabel: function(options){
10918 options = options || {};
10919 var model = this.collection.get(options.tab);
10920 model.set({label: options.label});
10921 },
10922
10923 onShow: function(){
10924 // last call for active tabs
10925 this.collection.ensureActiveTab();
10926 }
10927});
10928
10929module.exports = View;
10930
10931/***/ }),
10932/* 102 */
10933/***/ (function(module, exports, __webpack_require__) {
10934
10935var hbs = __webpack_require__(7);
10936var ItemView = __webpack_require__(5);
10937var Tmpl = __webpack_require__(103);
10938
10939var View = ItemView.extend({
10940 tagName: 'li',
10941 template: hbs.compile(Tmpl),
10942
10943 className: function () {
10944 if (this.model.get('active')) {
10945 return 'active';
10946 }
10947 },
10948
10949 modelEvents: {
10950 'change:active': 'toggleActive',
10951 'change:label' : 'render' // why does this not auto render?!
10952 },
10953
10954 toggleActive: function(){
10955 this.$el.toggleClass('active', this.model.get('active'));
10956 },
10957
10958 triggers: {
10959 'click': 'tab:clicked',
10960 'click *[data-action="remove"]': 'remove:tab'
10961 },
10962
10963 onTabClicked: function () {
10964 this.model.set({active: true});
10965 },
10966
10967 onRemoveTab: function(){
10968 this.model.collection.remove(this.model);
10969 }
10970
10971});
10972
10973module.exports = View;
10974
10975/***/ }),
10976/* 103 */
10977/***/ (function(module, exports) {
10978
10979module.exports = "{{#unless fixed}}\r\n<a href=\"#\" data-action=\"remove\">\r\n <i class=\"icon icon-times-circle\"></i>\r\n</a>\r\n{{/unless}}\r\n{{{ label }}}"
10980
10981/***/ }),
10982/* 104 */
10983/***/ (function(module, exports, __webpack_require__) {
10984
10985var Collection = __webpack_require__(14);
10986var Model = __webpack_require__(105);
10987
10988var TabsCollection = Collection.extend({
10989 model: Model,
10990
10991 initialize: function(){
10992 this.on({
10993 'change:active' : this.onChangeActive,
10994 'remove' : this.ensureActiveTab
10995 });
10996 },
10997
10998 onChangeActive: function(model, active){
10999 if(!active){ return; }
11000 this.each(function(m) {
11001 m.set({active: m === model});
11002 });
11003 this.trigger('active:tab', model);
11004 },
11005
11006 ensureActiveTab: function() {
11007 var activeTabs = this.where({'active': true});
11008 if( this.length > 0 && activeTabs.length === 0 ) {
11009 this.at(0).set({active: true});
11010 }
11011 }
11012
11013});
11014
11015module.exports = TabsCollection;
11016
11017/***/ }),
11018/* 105 */
11019/***/ (function(module, exports, __webpack_require__) {
11020
11021var Model = __webpack_require__(16);
11022
11023var TabModel = Model.extend({
11024 defaults: {
11025 id: '',
11026 label: 'Tab',
11027 active: false,
11028 fixed: true
11029 }
11030});
11031
11032module.exports = TabModel;
11033
11034/***/ }),
11035/* 106 */
11036/***/ (function(module, exports, __webpack_require__) {
11037
11038var Service = __webpack_require__(12);
11039var View = __webpack_require__(26);
11040
11041module.exports = Service.extend({
11042
11043 channelName: 'buttons',
11044
11045 initialize: function(){
11046
11047 this.channel.reply({
11048 'view' : this.view
11049 }, this);
11050
11051 },
11052
11053 view: function(options){
11054 var view = new View(options);
11055 return view;
11056 }
11057
11058});
11059
11060/***/ }),
11061/* 107 */
11062/***/ (function(module, exports) {
11063
11064module.exports = "{{#each buttons}}\r\n\r\n {{#if this.button}}\r\n <button class=\"btn {{this.className}}\"\r\n {{#if this.action}}data-action=\"{{this.action}}\"{{/if}}\r\n {{#if this.toggle}}data-toggle=\"{{this.toggle}}\"{{/if}}\r\n {{#if this.loading}}data-loading=\"{{this.loadingText}}\"{{/if}}\r\n {{#if this.icon}}data-icon=\"{{this.icon}}\"{{/if}}\r\n {{#if this.disabled}}disabled{{/if}}\r\n >\r\n {{this.label}}\r\n </button>\r\n {{/if}}\r\n\r\n {{#if this.link}}\r\n <a href=\"#\" class=\"btn {{this.className}}\"\r\n {{#if this.action}}data-action=\"{{this.action}}\"{{/if}}\r\n {{#if this.toggle}}data-toggle=\"{{this.toggle}}\"{{/if}}\r\n {{#if this.loading}}data-loading=\"{{this.loadingText}}\"{{/if}}\r\n {{#if this.icon}}data-icon=\"{{this.icon}}\"{{/if}}\r\n >\r\n {{this.label}}\r\n </a>\r\n {{/if}}\r\n\r\n {{#if this.input}}\r\n <input type=\"button\" class=\"btn {{this.className}}\" value=\"{{this.label}}\"\r\n {{#if this.action}}data-action=\"{{this.action}}\"{{/if}}\r\n {{#if this.toggle}}data-toggle=\"{{this.toggle}}\"{{/if}}\r\n {{#if this.loading}}data-loading=\"{{this.loadingText}}\"{{/if}}\r\n >\r\n {{/if}}\r\n\r\n {{#if this.message}}\r\n <p class=\"message {{this.className}}\"></p>\r\n {{/if}}\r\n\r\n{{/each}}"
11065
11066/***/ }),
11067/* 108 */
11068/***/ (function(module, exports, __webpack_require__) {
11069
11070var Behavior = __webpack_require__(15);
11071var App = __webpack_require__(1);
11072var $ = __webpack_require__(3);
11073var polyglot = __webpack_require__(6);
11074var d = 'disabled';
11075
11076var Buttons = Behavior.extend({
11077 loadingText: polyglot.t('messages.loading'),
11078
11079 ui: {
11080 btns : '.btn',
11081 action : '[data-action]',
11082 toggle : '[data-toggle]',
11083 message : '.message'
11084 },
11085
11086 events: {
11087 'click @ui.action': 'action',
11088 'click @ui.toggle': 'toggle',
11089 'state @ui.btns' : 'setState'
11090 },
11091
11092 namespace: function( str ){
11093 // test for wp-admin
11094 if(window.adminpage){
11095 str = 'wc_pos-' + str;
11096 }
11097 return str;
11098 },
11099
11100 action: function(e){
11101 e.preventDefault();
11102 var action = $(e.target).data('action');
11103 this.view.trigger('action:' + action, $(e.target), this.view, action );
11104 },
11105
11106 toggle: function(e){
11107 e.preventDefault();
11108 this.enable().disable($(e.target));
11109 var toggle = $(e.target).data('toggle');
11110 this.view.trigger('toggle:' + toggle, $(e.target), this.view, toggle);
11111 },
11112
11113 enable: function(btn){
11114 if(btn){
11115 btn.removeClass(d).prop(d, false);
11116 } else {
11117 this.ui.btns.each(function(){
11118 $(this).removeClass(d).prop(d, false);
11119 });
11120 }
11121 return this;
11122 },
11123
11124 disable: function(btn){
11125 if(btn){
11126 btn.addClass(d).prop(d, true);
11127 } else {
11128 this.ui.btns.each(function(){
11129 $(this).addClass(d).prop(d, true);
11130 });
11131 }
11132 return this;
11133 },
11134
11135 setState: function(e, state, message){
11136 var btn = $(e.target),
11137 prop = state === 'loading' ? 'disable' : 'enable';
11138 this[prop]();
11139 this.updateText(btn);
11140 if( btn.is('input') ){
11141 this.updateInput(btn, state);
11142 } else {
11143 this.updateIcon(btn, state);
11144 }
11145 if(message !== undefined){
11146 this.updateMessage(message, state);
11147 }
11148 },
11149
11150 updateText: function(btn){
11151 if(btn.data('loading') === undefined){ return; }
11152 var val = btn.is('input') ? 'val' : 'html';
11153 var text = btn[val]();
11154 var loadingText = btn.data('loading') || this.loadingText;
11155 btn.data('loading', text);
11156 btn[val](loadingText);
11157 },
11158
11159 updateIcon: function(btn, state){
11160 if(btn.data('icon') === undefined){ return; }
11161 var pos = btn.data('icon') || 'prepend';
11162 var icon = state !== 'reset' ? this.icon(state) : '';
11163 btn.children('i').remove();
11164 btn[pos](icon);
11165 },
11166
11167 icon: function(state){
11168 return '<i class="' + this.namespace( 'icon-' + state ) + '"></i>';
11169 },
11170
11171 updateInput: function(btn, state){
11172 btn.removeClass('loading success error');
11173 if(state !== 'reset'){
11174 btn.addClass(state);
11175 }
11176 },
11177
11178 updateMessage: function(message, state){
11179 if(message === null){
11180 message = polyglot.t('messages.' + state);
11181 }
11182 if(!state){
11183 state = message;
11184 message = polyglot.t('messages.' + message);
11185 }
11186 if(state === 'reset'){
11187 message = '';
11188 }
11189 this.ui.message
11190 .removeClass('loading success error')
11191 .addClass( this.namespace( 'text-' + state ) )
11192 .html(message);
11193 },
11194
11195 onMessage: function(message, state){
11196 this.updateMessage(message, state);
11197 },
11198
11199 onDisableButtons: function(){
11200 this.disable();
11201 },
11202
11203 onEnableButtons: function(){
11204 this.enable();
11205 }
11206
11207});
11208
11209module.exports = Buttons;
11210App.prototype.set('Behaviors.Buttons', Buttons);
11211
11212/***/ }),
11213/* 109 */
11214/***/ (function(module, exports, __webpack_require__) {
11215
11216var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// Backbone.Stickit v0.9.2, MIT Licensed
11217// Copyright (c) 2012-2015 The New York Times, CMS Group, Matthew DeLambo <delambo@gmail.com>
11218
11219(function (factory) {
11220
11221 // Set up Stickit appropriately for the environment. Start with AMD.
11222 if (true)
11223 !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(0), __webpack_require__(4), exports], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
11224 __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
11225 (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
11226 __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
11227
11228 // Next for Node.js or CommonJS.
11229 else if (typeof exports === 'object')
11230 factory(require('underscore'), require('backbone'), exports);
11231
11232 // Finally, as a browser global.
11233 else
11234 factory(_, Backbone, {});
11235
11236}(function (_, Backbone, Stickit) {
11237
11238 // Stickit Namespace
11239 // --------------------------
11240
11241 // Export onto Backbone object
11242 Backbone.Stickit = Stickit;
11243
11244 Stickit._handlers = [];
11245
11246 Stickit.addHandler = function(handlers) {
11247 // Fill-in default values.
11248 handlers = _.map(_.flatten([handlers]), function(handler) {
11249 return _.defaults({}, handler, {
11250 updateModel: true,
11251 updateView: true,
11252 updateMethod: 'text'
11253 });
11254 });
11255 this._handlers = this._handlers.concat(handlers);
11256 };
11257
11258 // Backbone.View Mixins
11259 // --------------------
11260
11261 Stickit.ViewMixin = {
11262
11263 // Collection of model event bindings.
11264 // [{model,event,fn,config}, ...]
11265 _modelBindings: null,
11266
11267 // Unbind the model and event bindings from `this._modelBindings` and
11268 // `this.$el`. If the optional `model` parameter is defined, then only
11269 // delete bindings for the given `model` and its corresponding view events.
11270 unstickit: function(model, bindingSelector) {
11271
11272 // Support passing a bindings hash in place of bindingSelector.
11273 if (_.isObject(bindingSelector)) {
11274 _.each(bindingSelector, function(v, selector) {
11275 this.unstickit(model, selector);
11276 }, this);
11277 return;
11278 }
11279
11280 var models = [], destroyFns = [];
11281 this._modelBindings = _.reject(this._modelBindings, function(binding) {
11282 if (model && binding.model !== model) return;
11283 if (bindingSelector && binding.config.selector != bindingSelector) return;
11284
11285 binding.model.off(binding.event, binding.fn);
11286 destroyFns.push(binding.config._destroy);
11287 models.push(binding.model);
11288 return true;
11289 });
11290
11291 // Trigger an event for each model that was unbound.
11292 _.invoke(_.uniq(models), 'trigger', 'stickit:unstuck', this.cid);
11293
11294 // Call `_destroy` on a unique list of the binding callbacks.
11295 _.each(_.uniq(destroyFns), function(fn) { fn.call(this); }, this);
11296
11297 this.$el.off('.stickit' + (model ? '.' + model.cid : ''), bindingSelector);
11298 },
11299
11300 // Initilize Stickit bindings for the view. Subsequent binding additions
11301 // can either call `stickit` with the new bindings, or add them directly
11302 // with `addBinding`. Both arguments to `stickit` are optional.
11303 stickit: function(optionalModel, optionalBindingsConfig) {
11304 var model = optionalModel || this.model,
11305 bindings = optionalBindingsConfig || _.result(this, "bindings") || {};
11306
11307 this._modelBindings || (this._modelBindings = []);
11308
11309 // Add bindings in bulk using `addBinding`.
11310 this.addBinding(model, bindings);
11311
11312 // Wrap `view.remove` to unbind stickit model and dom events.
11313 var remove = this.remove;
11314 if (!remove.stickitWrapped) {
11315 this.remove = function() {
11316 var ret = this;
11317 this.unstickit();
11318 if (remove) ret = remove.apply(this, arguments);
11319 return ret;
11320 };
11321 }
11322 this.remove.stickitWrapped = true;
11323 return this;
11324 },
11325
11326 // Add a single Stickit binding or a hash of bindings to the model. If
11327 // `optionalModel` is ommitted, will default to the view's `model` property.
11328 addBinding: function(optionalModel, selector, binding) {
11329 var model = optionalModel || this.model,
11330 namespace = '.stickit.' + model.cid;
11331
11332 binding = binding || {};
11333
11334 // Support jQuery-style {key: val} event maps.
11335 if (_.isObject(selector)) {
11336 var bindings = selector;
11337 _.each(bindings, function(val, key) {
11338 this.addBinding(model, key, val);
11339 }, this);
11340 return;
11341 }
11342
11343 // Special case the ':el' selector to use the view's this.$el.
11344 var $el = selector === ':el' ? this.$el : this.$(selector);
11345
11346 // Clear any previous matching bindings.
11347 this.unstickit(model, selector);
11348
11349 // Fail fast if the selector didn't match an element.
11350 if (!$el.length) return;
11351
11352 // Allow shorthand setting of model attributes - `'selector':'observe'`.
11353 if (_.isString(binding)) binding = {observe: binding};
11354
11355 // Handle case where `observe` is in the form of a function.
11356 if (_.isFunction(binding.observe)) binding.observe = binding.observe.call(this);
11357
11358 // Find all matching Stickit handlers that could apply to this element
11359 // and store in a config object.
11360 var config = getConfiguration($el, binding);
11361
11362 // The attribute we're observing in our config.
11363 var modelAttr = config.observe;
11364
11365 // Store needed properties for later.
11366 config.selector = selector;
11367 config.view = this;
11368
11369 // Create the model set options with a unique `bindId` so that we
11370 // can avoid double-binding in the `change:attribute` event handler.
11371 var bindId = config.bindId = _.uniqueId();
11372
11373 // Add a reference to the view for handlers of stickitChange events
11374 var options = _.extend({stickitChange: config}, config.setOptions);
11375
11376 // Add a `_destroy` callback to the configuration, in case `destroy`
11377 // is a named function and we need a unique function when unsticking.
11378 config._destroy = function() {
11379 applyViewFn.call(this, config.destroy, $el, model, config);
11380 };
11381
11382 initializeAttributes($el, config, model, modelAttr);
11383 initializeVisible($el, config, model, modelAttr);
11384 initializeClasses($el, config, model, modelAttr);
11385
11386 if (modelAttr) {
11387 // Setup one-way (input element -> model) bindings.
11388 _.each(config.events, function(type) {
11389 var eventName = type + namespace;
11390 var listener = function(event) {
11391 var val = applyViewFn.call(this, config.getVal, $el, event, config, slice.call(arguments, 1));
11392
11393 // Don't update the model if false is returned from the `updateModel` configuration.
11394 var currentVal = evaluateBoolean(config.updateModel, val, event, config);
11395 if (currentVal) setAttr(model, modelAttr, val, options, config);
11396 };
11397 var sel = selector === ':el'? '' : selector;
11398 this.$el.on(eventName, sel, _.bind(listener, this));
11399 }, this);
11400
11401 // Setup a `change:modelAttr` observer to keep the view element in sync.
11402 // `modelAttr` may be an array of attributes or a single string value.
11403 _.each(_.flatten([modelAttr]), function(attr) {
11404 observeModelEvent(model, 'change:' + attr, config, function(m, val, options) {
11405 var changeId = options && options.stickitChange && options.stickitChange.bindId;
11406 if (changeId !== bindId) {
11407 var currentVal = getAttr(model, modelAttr, config);
11408 updateViewBindEl($el, config, currentVal, model);
11409 }
11410 });
11411 });
11412
11413 var currentVal = getAttr(model, modelAttr, config);
11414 updateViewBindEl($el, config, currentVal, model, true);
11415 }
11416
11417 // After each binding is setup, call the `initialize` callback.
11418 applyViewFn.call(this, config.initialize, $el, model, config);
11419 }
11420 };
11421
11422 _.extend(Backbone.View.prototype, Stickit.ViewMixin);
11423
11424 // Helpers
11425 // -------
11426
11427 var slice = [].slice;
11428
11429 // Evaluates the given `path` (in object/dot-notation) relative to the given
11430 // `obj`. If the path is null/undefined, then the given `obj` is returned.
11431 var evaluatePath = function(obj, path) {
11432 var parts = (path || '').split('.');
11433 var result = _.reduce(parts, function(memo, i) { return memo[i]; }, obj);
11434 return result == null ? obj : result;
11435 };
11436
11437 // If the given `fn` is a string, then view[fn] is called, otherwise it is
11438 // a function that should be executed.
11439 var applyViewFn = function(fn) {
11440 fn = _.isString(fn) ? evaluatePath(this, fn) : fn;
11441 if (fn) return (fn).apply(this, slice.call(arguments, 1));
11442 };
11443
11444 // Given a function, string (view function reference), or a boolean
11445 // value, returns the truthy result. Any other types evaluate as false.
11446 // The first argument must be `reference` and the last must be `config`, but
11447 // middle arguments can be variadic.
11448 var evaluateBoolean = function(reference, val, config) {
11449 if (_.isBoolean(reference)) {
11450 return reference;
11451 } else if (_.isFunction(reference) || _.isString(reference)) {
11452 var view = _.last(arguments).view;
11453 return applyViewFn.apply(view, arguments);
11454 }
11455 return false;
11456 };
11457
11458 // Setup a model event binding with the given function, and track the event
11459 // in the view's _modelBindings.
11460 var observeModelEvent = function(model, event, config, fn) {
11461 var view = config.view;
11462 model.on(event, fn, view);
11463 view._modelBindings.push({model:model, event:event, fn:fn, config:config});
11464 };
11465
11466 // Prepares the given `val`ue and sets it into the `model`.
11467 var setAttr = function(model, attr, val, options, config) {
11468 var value = {}, view = config.view;
11469 if (config.onSet) {
11470 val = applyViewFn.call(view, config.onSet, val, config);
11471 }
11472
11473 if (config.set) {
11474 applyViewFn.call(view, config.set, attr, val, options, config);
11475 } else {
11476 value[attr] = val;
11477 // If `observe` is defined as an array and `onSet` returned
11478 // an array, then map attributes to their values.
11479 if (_.isArray(attr) && _.isArray(val)) {
11480 value = _.reduce(attr, function(memo, attribute, index) {
11481 memo[attribute] = _.has(val, index) ? val[index] : null;
11482 return memo;
11483 }, {});
11484 }
11485 model.set(value, options);
11486 }
11487 };
11488
11489 // Returns the given `attr`'s value from the `model`, escaping and
11490 // formatting if necessary. If `attr` is an array, then an array of
11491 // respective values will be returned.
11492 var getAttr = function(model, attr, config) {
11493 var view = config.view;
11494 var retrieveVal = function(field) {
11495 return model[config.escape ? 'escape' : 'get'](field);
11496 };
11497 var sanitizeVal = function(val) {
11498 return val == null ? '' : val;
11499 };
11500 var val = _.isArray(attr) ? _.map(attr, retrieveVal) : retrieveVal(attr);
11501 if (config.onGet) val = applyViewFn.call(view, config.onGet, val, config);
11502 return _.isArray(val) ? _.map(val, sanitizeVal) : sanitizeVal(val);
11503 };
11504
11505 // Find handlers in `Backbone.Stickit._handlers` with selectors that match
11506 // `$el` and generate a configuration by mixing them in the order that they
11507 // were found with the given `binding`.
11508 var getConfiguration = Stickit.getConfiguration = function($el, binding) {
11509 var handlers = [{
11510 updateModel: false,
11511 updateMethod: 'text',
11512 update: function($el, val, m, opts) { if ($el[opts.updateMethod]) $el[opts.updateMethod](val); },
11513 getVal: function($el, e, opts) { return $el[opts.updateMethod](); }
11514 }];
11515 handlers = handlers.concat(_.filter(Stickit._handlers, function(handler) {
11516 return $el.is(handler.selector);
11517 }));
11518 handlers.push(binding);
11519
11520 // Merge handlers into a single config object. Last props in wins.
11521 var config = _.extend.apply(_, handlers);
11522
11523 // `updateView` is defaulted to false for configutrations with
11524 // `visible`; otherwise, `updateView` is defaulted to true.
11525 if (!_.has(config, 'updateView')) config.updateView = !config.visible;
11526 return config;
11527 };
11528
11529 // Setup the attributes configuration - a list that maps an attribute or
11530 // property `name`, to an `observe`d model attribute, using an optional
11531 // `onGet` formatter.
11532 //
11533 // attributes: [{
11534 // name: 'attributeOrPropertyName',
11535 // observe: 'modelAttrName'
11536 // onGet: function(modelAttrVal, modelAttrName) { ... }
11537 // }, ...]
11538 //
11539 var initializeAttributes = function($el, config, model, modelAttr) {
11540 var props = ['autofocus', 'autoplay', 'async', 'checked', 'controls',
11541 'defer', 'disabled', 'hidden', 'indeterminate', 'loop', 'multiple',
11542 'open', 'readonly', 'required', 'scoped', 'selected'];
11543
11544 var view = config.view;
11545
11546 _.each(config.attributes || [], function(attrConfig) {
11547 attrConfig = _.clone(attrConfig);
11548 attrConfig.view = view;
11549
11550 var lastClass = '';
11551 var observed = attrConfig.observe || (attrConfig.observe = modelAttr);
11552 var updateAttr = function() {
11553 var updateType = _.contains(props, attrConfig.name) ? 'prop' : 'attr',
11554 val = getAttr(model, observed, attrConfig);
11555
11556 // If it is a class then we need to remove the last value and add the new.
11557 if (attrConfig.name === 'class') {
11558 $el.removeClass(lastClass).addClass(val);
11559 lastClass = val;
11560 } else {
11561 $el[updateType](attrConfig.name, val);
11562 }
11563 };
11564
11565 _.each(_.flatten([observed]), function(attr) {
11566 observeModelEvent(model, 'change:' + attr, config, updateAttr);
11567 });
11568
11569 // Initialize the matched element's state.
11570 updateAttr();
11571 });
11572 };
11573
11574 var initializeClasses = function($el, config, model, modelAttr) {
11575 _.each(config.classes || [], function(classConfig, name) {
11576 if (_.isString(classConfig)) classConfig = {observe: classConfig};
11577 classConfig.view = config.view;
11578
11579 var observed = classConfig.observe;
11580 var updateClass = function() {
11581 var val = getAttr(model, observed, classConfig);
11582 $el.toggleClass(name, !!val);
11583 };
11584
11585 _.each(_.flatten([observed]), function(attr) {
11586 observeModelEvent(model, 'change:' + attr, config, updateClass);
11587 });
11588 updateClass();
11589 });
11590 };
11591
11592 // If `visible` is configured, then the view element will be shown/hidden
11593 // based on the truthiness of the modelattr's value or the result of the
11594 // given callback. If a `visibleFn` is also supplied, then that callback
11595 // will be executed to manually handle showing/hiding the view element.
11596 //
11597 // observe: 'isRight',
11598 // visible: true, // or function(val, options) {}
11599 // visibleFn: function($el, isVisible, options) {} // optional handler
11600 //
11601 var initializeVisible = function($el, config, model, modelAttr) {
11602 if (config.visible == null) return;
11603 var view = config.view;
11604
11605 var visibleCb = function() {
11606 var visible = config.visible,
11607 visibleFn = config.visibleFn,
11608 val = getAttr(model, modelAttr, config),
11609 isVisible = !!val;
11610
11611 // If `visible` is a function then it should return a boolean result to show/hide.
11612 if (_.isFunction(visible) || _.isString(visible)) {
11613 isVisible = !!applyViewFn.call(view, visible, val, config);
11614 }
11615
11616 // Either use the custom `visibleFn`, if provided, or execute the standard show/hide.
11617 if (visibleFn) {
11618 applyViewFn.call(view, visibleFn, $el, isVisible, config);
11619 } else {
11620 $el.toggle(isVisible);
11621 }
11622 };
11623
11624 _.each(_.flatten([modelAttr]), function(attr) {
11625 observeModelEvent(model, 'change:' + attr, config, visibleCb);
11626 });
11627
11628 visibleCb();
11629 };
11630
11631 // Update the value of `$el` using the given configuration and trigger the
11632 // `afterUpdate` callback. This action may be blocked by `config.updateView`.
11633 //
11634 // update: function($el, val, model, options) {}, // handler for updating
11635 // updateView: true, // defaults to true
11636 // afterUpdate: function($el, val, options) {} // optional callback
11637 //
11638 var updateViewBindEl = function($el, config, val, model, isInitializing) {
11639 var view = config.view;
11640 if (!evaluateBoolean(config.updateView, val, config)) return;
11641 applyViewFn.call(view, config.update, $el, val, model, config);
11642 if (!isInitializing) applyViewFn.call(view, config.afterUpdate, $el, val, config);
11643 };
11644
11645 // Default Handlers
11646 // ----------------
11647
11648 Stickit.addHandler([{
11649 selector: '[contenteditable]',
11650 updateMethod: 'html',
11651 events: ['input', 'change']
11652 }, {
11653 selector: 'input',
11654 events: ['propertychange', 'input', 'change'],
11655 update: function($el, val) { $el.val(val); },
11656 getVal: function($el) {
11657 return $el.val();
11658 }
11659 }, {
11660 selector: 'textarea',
11661 events: ['propertychange', 'input', 'change'],
11662 update: function($el, val) { $el.val(val); },
11663 getVal: function($el) { return $el.val(); }
11664 }, {
11665 selector: 'input[type="radio"]',
11666 events: ['change'],
11667 update: function($el, val) {
11668 $el.filter('[value="'+val+'"]').prop('checked', true);
11669 },
11670 getVal: function($el) {
11671 return $el.filter(':checked').val();
11672 }
11673 }, {
11674 selector: 'input[type="checkbox"]',
11675 events: ['change'],
11676 update: function($el, val, model, options) {
11677 if ($el.length > 1) {
11678 // There are multiple checkboxes so we need to go through them and check
11679 // any that have value attributes that match what's in the array of `val`s.
11680 val || (val = []);
11681 $el.each(function(i, el) {
11682 var checkbox = Backbone.$(el);
11683 var checked = _.contains(val, checkbox.val());
11684 checkbox.prop('checked', checked);
11685 });
11686 } else {
11687 var checked = _.isBoolean(val) ? val : val === $el.val();
11688 $el.prop('checked', checked);
11689 }
11690 },
11691 getVal: function($el) {
11692 var val;
11693 if ($el.length > 1) {
11694 val = _.reduce($el, function(memo, el) {
11695 var checkbox = Backbone.$(el);
11696 if (checkbox.prop('checked')) memo.push(checkbox.val());
11697 return memo;
11698 }, []);
11699 } else {
11700 val = $el.prop('checked');
11701 // If the checkbox has a value attribute defined, then
11702 // use that value. Most browsers use "on" as a default.
11703 var boxval = $el.val();
11704 if (boxval !== 'on' && boxval != null) {
11705 val = val ? $el.val() : null;
11706 }
11707 }
11708 return val;
11709 }
11710 }, {
11711 selector: 'select',
11712 events: ['change'],
11713 update: function($el, val, model, options) {
11714 var optList,
11715 selectConfig = options.selectOptions,
11716 list = selectConfig && selectConfig.collection || undefined,
11717 isMultiple = $el.prop('multiple');
11718
11719 // If there are no `selectOptions` then we assume that the `<select>`
11720 // is pre-rendered and that we need to generate the collection.
11721 if (!selectConfig) {
11722 selectConfig = {};
11723 var getList = function($el) {
11724 return $el.map(function(index, option) {
11725 // Retrieve the text and value of the option, preferring "stickit-bind-val"
11726 // data attribute over value property.
11727 var dataVal = Backbone.$(option).data('stickit-bind-val');
11728 return {
11729 value: dataVal !== undefined ? dataVal : option.value,
11730 label: option.text
11731 };
11732 }).get();
11733 };
11734 if ($el.find('optgroup').length) {
11735 list = {opt_labels:[]};
11736 // Search for options without optgroup
11737 if ($el.find('> option').length) {
11738 list.opt_labels.push(undefined);
11739 _.each($el.find('> option'), function(el) {
11740 list[undefined] = getList(Backbone.$(el));
11741 });
11742 }
11743 _.each($el.find('optgroup'), function(el) {
11744 var label = Backbone.$(el).attr('label');
11745 list.opt_labels.push(label);
11746 list[label] = getList(Backbone.$(el).find('option'));
11747 });
11748 } else {
11749 list = getList($el.find('option'));
11750 }
11751 }
11752
11753 // Fill in default label and path values.
11754 selectConfig.valuePath = selectConfig.valuePath || 'value';
11755 selectConfig.labelPath = selectConfig.labelPath || 'label';
11756 selectConfig.disabledPath = selectConfig.disabledPath || 'disabled';
11757
11758 var addSelectOptions = function(optList, $el, fieldVal) {
11759 _.each(optList, function(obj) {
11760 var option = Backbone.$('<option/>'), optionVal = obj;
11761
11762 var fillOption = function(text, val, disabled) {
11763 option.text(text);
11764 optionVal = val;
11765 // Save the option value as data so that we can reference it later.
11766 option.data('stickit-bind-val', optionVal);
11767 if (!_.isArray(optionVal) && !_.isObject(optionVal)) option.val(optionVal);
11768
11769 if (disabled === true) option.prop('disabled', 'disabled');
11770 };
11771
11772 var text, val, disabled;
11773 if (obj === '__default__') {
11774 text = fieldVal.label,
11775 val = fieldVal.value,
11776 disabled = fieldVal.disabled;
11777 } else {
11778 text = evaluatePath(obj, selectConfig.labelPath),
11779 val = evaluatePath(obj, selectConfig.valuePath),
11780 disabled = evaluatePath(obj, selectConfig.disabledPath);
11781 }
11782 fillOption(text, val, disabled);
11783
11784 // Determine if this option is selected.
11785 var isSelected = function() {
11786 if (!isMultiple && optionVal != null && fieldVal != null && optionVal === fieldVal) {
11787 return true;
11788 } else if (_.isObject(fieldVal) && _.isEqual(optionVal, fieldVal)) {
11789 return true;
11790 }
11791 return false;
11792 };
11793
11794 if (isSelected()) {
11795 option.prop('selected', true);
11796 } else if (isMultiple && _.isArray(fieldVal)) {
11797 _.each(fieldVal, function(val) {
11798 if (_.isObject(val)) val = evaluatePath(val, selectConfig.valuePath);
11799 if (val === optionVal || (_.isObject(val) && _.isEqual(optionVal, val)))
11800 option.prop('selected', true);
11801 });
11802 }
11803
11804 $el.append(option);
11805 });
11806 };
11807
11808 $el.find('*').remove();
11809
11810 // The `list` configuration is a function that returns the options list or a string
11811 // which represents the path to the list relative to `window` or the view/`this`.
11812 if (_.isString(list)) {
11813 var context = window;
11814 if (list.indexOf('this.') === 0) context = this;
11815 list = list.replace(/^[a-z]*\.(.+)$/, '$1');
11816 optList = evaluatePath(context, list);
11817 } else if (_.isFunction(list)) {
11818 optList = applyViewFn.call(this, list, $el, options);
11819 } else {
11820 optList = list;
11821 }
11822
11823 // Support Backbone.Collection and deserialize.
11824 if (optList instanceof Backbone.Collection) {
11825 var collection = optList;
11826 var refreshSelectOptions = function() {
11827 var currentVal = getAttr(model, options.observe, options);
11828 applyViewFn.call(this, options.update, $el, currentVal, model, options);
11829 };
11830 // We need to call this function after unstickit and after an update so we don't end up
11831 // with multiple listeners doing the same thing
11832 var removeCollectionListeners = function() {
11833 collection.off('add remove reset sort', refreshSelectOptions);
11834 };
11835 var removeAllListeners = function() {
11836 removeCollectionListeners();
11837 collection.off('stickit:selectRefresh');
11838 model.off('stickit:selectRefresh');
11839 };
11840 // Remove previously set event listeners by triggering a custom event
11841 collection.trigger('stickit:selectRefresh');
11842 collection.once('stickit:selectRefresh', removeCollectionListeners, this);
11843
11844 // Listen to the collection and trigger an update of the select options
11845 collection.on('add remove reset sort', refreshSelectOptions, this);
11846
11847 // Remove the previous model event listener
11848 model.trigger('stickit:selectRefresh');
11849 model.once('stickit:selectRefresh', function() {
11850 model.off('stickit:unstuck', removeAllListeners);
11851 });
11852 // Remove collection event listeners once this binding is unstuck
11853 model.once('stickit:unstuck', removeAllListeners, this);
11854 optList = optList.toJSON();
11855 }
11856
11857 if (selectConfig.defaultOption) {
11858 var option = _.isFunction(selectConfig.defaultOption) ?
11859 selectConfig.defaultOption.call(this, $el, options) :
11860 selectConfig.defaultOption;
11861 addSelectOptions(["__default__"], $el, option);
11862 }
11863
11864 if (_.isArray(optList)) {
11865 addSelectOptions(optList, $el, val);
11866 } else if (optList.opt_labels) {
11867 // To define a select with optgroups, format selectOptions.collection as an object
11868 // with an 'opt_labels' property, as in the following:
11869 //
11870 // {
11871 // 'opt_labels': ['Looney Tunes', 'Three Stooges'],
11872 // 'Looney Tunes': [{id: 1, name: 'Bugs Bunny'}, {id: 2, name: 'Donald Duck'}],
11873 // 'Three Stooges': [{id: 3, name : 'moe'}, {id: 4, name : 'larry'}, {id: 5, name : 'curly'}]
11874 // }
11875 //
11876 _.each(optList.opt_labels, function(label) {
11877 var $group = Backbone.$('<optgroup/>').attr('label', label);
11878 addSelectOptions(optList[label], $group, val);
11879 $el.append($group);
11880 });
11881 // With no 'opt_labels' parameter, the object is assumed to be a simple value-label map.
11882 // Pass a selectOptions.comparator to override the default order of alphabetical by label.
11883 } else {
11884 var opts = [], opt;
11885 for (var i in optList) {
11886 opt = {};
11887 opt[selectConfig.valuePath] = i;
11888 opt[selectConfig.labelPath] = optList[i];
11889 opts.push(opt);
11890 }
11891 opts = _.sortBy(opts, selectConfig.comparator || selectConfig.labelPath);
11892 addSelectOptions(opts, $el, val);
11893 }
11894 },
11895 getVal: function($el) {
11896 var selected = $el.find('option:selected');
11897
11898 if ($el.prop('multiple')) {
11899 return _.map(selected, function(el) {
11900 return Backbone.$(el).data('stickit-bind-val');
11901 });
11902 } else {
11903 return selected.data('stickit-bind-val');
11904 }
11905 }
11906 }]);
11907
11908 return Stickit;
11909
11910}));
11911
11912
11913/***/ }),
11914/* 110 */
11915/***/ (function(module, exports, __webpack_require__) {
11916
11917// Backbone.Validation v0.11.5
11918//
11919// Copyright (c) 2011-2015 Thomas Pedersen
11920// Distributed under MIT License
11921//
11922// Documentation and full license available at:
11923// http://thedersen.com/projects/backbone-validation
11924(function (factory) {
11925 if (true) {
11926 module.exports = factory(__webpack_require__(4), __webpack_require__(0));
11927 } else if (typeof define === 'function' && define.amd) {
11928 define(['backbone', 'underscore'], factory);
11929 }
11930}(function (Backbone, _) {
11931 Backbone.Validation = (function(_){
11932 'use strict';
11933
11934 // Default options
11935 // ---------------
11936
11937 var defaultOptions = {
11938 forceUpdate: false,
11939 selector: 'name',
11940 labelFormatter: 'sentenceCase',
11941 valid: Function.prototype,
11942 invalid: Function.prototype
11943 };
11944
11945
11946 // Helper functions
11947 // ----------------
11948
11949 // Formatting functions used for formatting error messages
11950 var formatFunctions = {
11951 // Uses the configured label formatter to format the attribute name
11952 // to make it more readable for the user
11953 formatLabel: function(attrName, model) {
11954 return defaultLabelFormatters[defaultOptions.labelFormatter](attrName, model);
11955 },
11956
11957 // Replaces nummeric placeholders like {0} in a string with arguments
11958 // passed to the function
11959 format: function() {
11960 var args = Array.prototype.slice.call(arguments),
11961 text = args.shift();
11962 return text.replace(/\{(\d+)\}/g, function(match, number) {
11963 return typeof args[number] !== 'undefined' ? args[number] : match;
11964 });
11965 }
11966 };
11967
11968 // Flattens an object
11969 // eg:
11970 //
11971 // var o = {
11972 // owner: {
11973 // name: 'Backbone',
11974 // address: {
11975 // street: 'Street',
11976 // zip: 1234
11977 // }
11978 // }
11979 // };
11980 //
11981 // becomes:
11982 //
11983 // var o = {
11984 // 'owner': {
11985 // name: 'Backbone',
11986 // address: {
11987 // street: 'Street',
11988 // zip: 1234
11989 // }
11990 // },
11991 // 'owner.name': 'Backbone',
11992 // 'owner.address': {
11993 // street: 'Street',
11994 // zip: 1234
11995 // },
11996 // 'owner.address.street': 'Street',
11997 // 'owner.address.zip': 1234
11998 // };
11999 // This may seem redundant, but it allows for maximum flexibility
12000 // in validation rules.
12001 var flatten = function (obj, into, prefix) {
12002 into = into || {};
12003 prefix = prefix || '';
12004
12005 _.each(obj, function(val, key) {
12006 if(obj.hasOwnProperty(key)) {
12007 if (!!val && _.isArray(val)) {
12008 _.forEach(val, function(v, k) {
12009 flatten(v, into, prefix + key + '.' + k + '.');
12010 into[prefix + key + '.' + k] = v;
12011 });
12012 } else if (!!val && typeof val === 'object' && val.constructor === Object) {
12013 flatten(val, into, prefix + key + '.');
12014 }
12015
12016 // Register the current level object as well
12017 into[prefix + key] = val;
12018 }
12019 });
12020
12021 return into;
12022 };
12023
12024 // Validation
12025 // ----------
12026
12027 var Validation = (function(){
12028
12029 // Returns an object with undefined properties for all
12030 // attributes on the model that has defined one or more
12031 // validation rules.
12032 var getValidatedAttrs = function(model, attrs) {
12033 attrs = attrs || _.keys(_.result(model, 'validation') || {});
12034 return _.reduce(attrs, function(memo, key) {
12035 memo[key] = void 0;
12036 return memo;
12037 }, {});
12038 };
12039
12040 // Returns an array with attributes passed through options
12041 var getOptionsAttrs = function(options, view) {
12042 var attrs = options.attributes;
12043 if (_.isFunction(attrs)) {
12044 attrs = attrs(view);
12045 } else if (_.isString(attrs) && (_.isFunction(defaultAttributeLoaders[attrs]))) {
12046 attrs = defaultAttributeLoaders[attrs](view);
12047 }
12048 if (_.isArray(attrs)) {
12049 return attrs;
12050 }
12051 };
12052
12053
12054 // Looks on the model for validations for a specified
12055 // attribute. Returns an array of any validators defined,
12056 // or an empty array if none is defined.
12057 var getValidators = function(model, attr) {
12058 var attrValidationSet = model.validation ? _.result(model, 'validation')[attr] || {} : {};
12059
12060 // If the validator is a function or a string, wrap it in a function validator
12061 if (_.isFunction(attrValidationSet) || _.isString(attrValidationSet)) {
12062 attrValidationSet = {
12063 fn: attrValidationSet
12064 };
12065 }
12066
12067 // Stick the validator object into an array
12068 if(!_.isArray(attrValidationSet)) {
12069 attrValidationSet = [attrValidationSet];
12070 }
12071
12072 // Reduces the array of validators into a new array with objects
12073 // with a validation method to call, the value to validate against
12074 // and the specified error message, if any
12075 return _.reduce(attrValidationSet, function(memo, attrValidation) {
12076 _.each(_.without(_.keys(attrValidation), 'msg'), function(validator) {
12077 memo.push({
12078 fn: defaultValidators[validator],
12079 val: attrValidation[validator],
12080 msg: attrValidation.msg
12081 });
12082 });
12083 return memo;
12084 }, []);
12085 };
12086
12087 // Validates an attribute against all validators defined
12088 // for that attribute. If one or more errors are found,
12089 // the first error message is returned.
12090 // If the attribute is valid, an empty string is returned.
12091 var validateAttr = function(model, attr, value, computed) {
12092 // Reduces the array of validators to an error message by
12093 // applying all the validators and returning the first error
12094 // message, if any.
12095 return _.reduce(getValidators(model, attr), function(memo, validator){
12096 // Pass the format functions plus the default
12097 // validators as the context to the validator
12098 var ctx = _.extend({}, formatFunctions, defaultValidators),
12099 result = validator.fn.call(ctx, value, attr, validator.val, model, computed);
12100
12101 if(result === false || memo === false) {
12102 return false;
12103 }
12104 if (result && !memo) {
12105 return _.result(validator, 'msg') || result;
12106 }
12107 return memo;
12108 }, '');
12109 };
12110
12111 // Loops through the model's attributes and validates the specified attrs.
12112 // Returns and object containing names of invalid attributes
12113 // as well as error messages.
12114 var validateModel = function(model, attrs, validatedAttrs) {
12115 var error,
12116 invalidAttrs = {},
12117 isValid = true,
12118 computed = _.clone(attrs);
12119
12120 _.each(validatedAttrs, function(val, attr) {
12121 error = validateAttr(model, attr, val, computed);
12122 if (error) {
12123 invalidAttrs[attr] = error;
12124 isValid = false;
12125 }
12126 });
12127
12128 return {
12129 invalidAttrs: invalidAttrs,
12130 isValid: isValid
12131 };
12132 };
12133
12134 // Contains the methods that are mixed in on the model when binding
12135 var mixin = function(view, options) {
12136 return {
12137
12138 // Check whether or not a value, or a hash of values
12139 // passes validation without updating the model
12140 preValidate: function(attr, value) {
12141 var self = this,
12142 result = {},
12143 error;
12144
12145 if(_.isObject(attr)){
12146 _.each(attr, function(value, key) {
12147 error = self.preValidate(key, value);
12148 if(error){
12149 result[key] = error;
12150 }
12151 });
12152
12153 return _.isEmpty(result) ? undefined : result;
12154 }
12155 else {
12156 return validateAttr(this, attr, value, _.extend({}, this.attributes));
12157 }
12158 },
12159
12160 // Check to see if an attribute, an array of attributes or the
12161 // entire model is valid. Passing true will force a validation
12162 // of the model.
12163 isValid: function(option) {
12164 var flattened, attrs, error, invalidAttrs;
12165
12166 option = option || getOptionsAttrs(options, view);
12167
12168 if(_.isString(option)){
12169 attrs = [option];
12170 } else if(_.isArray(option)) {
12171 attrs = option;
12172 }
12173 if (attrs) {
12174 flattened = flatten(this.attributes);
12175 //Loop through all associated views
12176 _.each(this.associatedViews, function(view) {
12177 _.each(attrs, function (attr) {
12178 error = validateAttr(this, attr, flattened[attr], _.extend({}, this.attributes));
12179 if (error) {
12180 options.invalid(view, attr, error, options.selector);
12181 invalidAttrs = invalidAttrs || {};
12182 invalidAttrs[attr] = error;
12183 } else {
12184 options.valid(view, attr, options.selector);
12185 }
12186 }, this);
12187 }, this);
12188 }
12189
12190 if(option === true) {
12191 invalidAttrs = this.validate();
12192 }
12193 if (invalidAttrs) {
12194 this.trigger('invalid', this, invalidAttrs, {validationError: invalidAttrs});
12195 }
12196 return attrs ? !invalidAttrs : this.validation ? this._isValid : true;
12197 },
12198
12199 // This is called by Backbone when it needs to perform validation.
12200 // You can call it manually without any parameters to validate the
12201 // entire model.
12202 validate: function(attrs, setOptions){
12203 var model = this,
12204 validateAll = !attrs,
12205 opt = _.extend({}, options, setOptions),
12206 validatedAttrs = getValidatedAttrs(model, getOptionsAttrs(options, view)),
12207 allAttrs = _.extend({}, validatedAttrs, model.attributes, attrs),
12208 flattened = flatten(allAttrs),
12209 changedAttrs = attrs ? flatten(attrs) : flattened,
12210 result = validateModel(model, allAttrs, _.pick(flattened, _.keys(validatedAttrs)));
12211
12212 model._isValid = result.isValid;
12213
12214 //After validation is performed, loop through all associated views
12215 _.each(model.associatedViews, function(view){
12216
12217 // After validation is performed, loop through all validated and changed attributes
12218 // and call the valid and invalid callbacks so the view is updated.
12219 _.each(validatedAttrs, function(val, attr){
12220 var invalid = result.invalidAttrs.hasOwnProperty(attr),
12221 changed = changedAttrs.hasOwnProperty(attr);
12222
12223 if(!invalid){
12224 opt.valid(view, attr, opt.selector);
12225 }
12226 if(invalid && (changed || validateAll)){
12227 opt.invalid(view, attr, result.invalidAttrs[attr], opt.selector);
12228 }
12229 });
12230 });
12231
12232 // Trigger validated events.
12233 // Need to defer this so the model is actually updated before
12234 // the event is triggered.
12235 _.defer(function() {
12236 model.trigger('validated', model._isValid, model, result.invalidAttrs);
12237 model.trigger('validated:' + (model._isValid ? 'valid' : 'invalid'), model, result.invalidAttrs);
12238 });
12239
12240 // Return any error messages to Backbone, unless the forceUpdate flag is set.
12241 // Then we do not return anything and fools Backbone to believe the validation was
12242 // a success. That way Backbone will update the model regardless.
12243 if (!opt.forceUpdate && _.intersection(_.keys(result.invalidAttrs), _.keys(changedAttrs)).length > 0) {
12244 return result.invalidAttrs;
12245 }
12246 }
12247 };
12248 };
12249
12250 // Helper to mix in validation on a model. Stores the view in the associated views array.
12251 var bindModel = function(view, model, options) {
12252 if (model.associatedViews) {
12253 model.associatedViews.push(view);
12254 } else {
12255 model.associatedViews = [view];
12256 }
12257 _.extend(model, mixin(view, options));
12258 };
12259
12260 // Removes view from associated views of the model or the methods
12261 // added to a model if no view or single view provided
12262 var unbindModel = function(model, view) {
12263 if (view && model.associatedViews && model.associatedViews.length > 1){
12264 model.associatedViews = _.without(model.associatedViews, view);
12265 } else {
12266 delete model.validate;
12267 delete model.preValidate;
12268 delete model.isValid;
12269 delete model.associatedViews;
12270 }
12271 };
12272
12273 // Mix in validation on a model whenever a model is
12274 // added to a collection
12275 var collectionAdd = function(model) {
12276 bindModel(this.view, model, this.options);
12277 };
12278
12279 // Remove validation from a model whenever a model is
12280 // removed from a collection
12281 var collectionRemove = function(model) {
12282 unbindModel(model);
12283 };
12284
12285 // Returns the public methods on Backbone.Validation
12286 return {
12287
12288 // Current version of the library
12289 version: '0.11.3',
12290
12291 // Called to configure the default options
12292 configure: function(options) {
12293 _.extend(defaultOptions, options);
12294 },
12295
12296 // Hooks up validation on a view with a model
12297 // or collection
12298 bind: function(view, options) {
12299 options = _.extend({}, defaultOptions, defaultCallbacks, options);
12300
12301 var model = options.model || view.model,
12302 collection = options.collection || view.collection;
12303
12304 if(typeof model === 'undefined' && typeof collection === 'undefined'){
12305 throw 'Before you execute the binding your view must have a model or a collection.\n' +
12306 'See http://thedersen.com/projects/backbone-validation/#using-form-model-validation for more information.';
12307 }
12308
12309 if(model) {
12310 bindModel(view, model, options);
12311 }
12312 else if(collection) {
12313 collection.each(function(model){
12314 bindModel(view, model, options);
12315 });
12316 collection.bind('add', collectionAdd, {view: view, options: options});
12317 collection.bind('remove', collectionRemove);
12318 }
12319 },
12320
12321 // Removes validation from a view with a model
12322 // or collection
12323 unbind: function(view, options) {
12324 options = _.extend({}, options);
12325 var model = options.model || view.model,
12326 collection = options.collection || view.collection;
12327
12328 if(model) {
12329 unbindModel(model, view);
12330 }
12331 else if(collection) {
12332 collection.each(function(model){
12333 unbindModel(model, view);
12334 });
12335 collection.unbind('add', collectionAdd);
12336 collection.unbind('remove', collectionRemove);
12337 }
12338 },
12339
12340 // Used to extend the Backbone.Model.prototype
12341 // with validation
12342 mixin: mixin(null, defaultOptions)
12343 };
12344 }());
12345
12346
12347 // Callbacks
12348 // ---------
12349
12350 var defaultCallbacks = Validation.callbacks = {
12351
12352 // Gets called when a previously invalid field in the
12353 // view becomes valid. Removes any error message.
12354 // Should be overridden with custom functionality.
12355 valid: function(view, attr, selector) {
12356 view.$('[' + selector + '~="' + attr + '"]')
12357 .removeClass('invalid')
12358 .removeAttr('data-error');
12359 },
12360
12361 // Gets called when a field in the view becomes invalid.
12362 // Adds a error message.
12363 // Should be overridden with custom functionality.
12364 invalid: function(view, attr, error, selector) {
12365 view.$('[' + selector + '~="' + attr + '"]')
12366 .addClass('invalid')
12367 .attr('data-error', error);
12368 }
12369 };
12370
12371
12372 // Patterns
12373 // --------
12374
12375 var defaultPatterns = Validation.patterns = {
12376 // Matches any digit(s) (i.e. 0-9)
12377 digits: /^\d+$/,
12378
12379 // Matches any number (e.g. 100.000)
12380 number: /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/,
12381
12382 // Matches a valid email address (e.g. mail@example.com)
12383 email: /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,
12384
12385 // Mathes any valid url (e.g. http://www.xample.com)
12386 url: /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i
12387 };
12388
12389
12390 // Error messages
12391 // --------------
12392
12393 // Error message for the build in validators.
12394 // {x} gets swapped out with arguments form the validator.
12395 var defaultMessages = Validation.messages = {
12396 required: '{0} is required',
12397 acceptance: '{0} must be accepted',
12398 min: '{0} must be greater than or equal to {1}',
12399 max: '{0} must be less than or equal to {1}',
12400 range: '{0} must be between {1} and {2}',
12401 length: '{0} must be {1} characters',
12402 minLength: '{0} must be at least {1} characters',
12403 maxLength: '{0} must be at most {1} characters',
12404 rangeLength: '{0} must be between {1} and {2} characters',
12405 oneOf: '{0} must be one of: {1}',
12406 equalTo: '{0} must be the same as {1}',
12407 digits: '{0} must only contain digits',
12408 number: '{0} must be a number',
12409 email: '{0} must be a valid email',
12410 url: '{0} must be a valid url',
12411 inlinePattern: '{0} is invalid'
12412 };
12413
12414 // Label formatters
12415 // ----------------
12416
12417 // Label formatters are used to convert the attribute name
12418 // to a more human friendly label when using the built in
12419 // error messages.
12420 // Configure which one to use with a call to
12421 //
12422 // Backbone.Validation.configure({
12423 // labelFormatter: 'label'
12424 // });
12425 var defaultLabelFormatters = Validation.labelFormatters = {
12426
12427 // Returns the attribute name with applying any formatting
12428 none: function(attrName) {
12429 return attrName;
12430 },
12431
12432 // Converts attributeName or attribute_name to Attribute name
12433 sentenceCase: function(attrName) {
12434 return attrName.replace(/(?:^\w|[A-Z]|\b\w)/g, function(match, index) {
12435 return index === 0 ? match.toUpperCase() : ' ' + match.toLowerCase();
12436 }).replace(/_/g, ' ');
12437 },
12438
12439 // Looks for a label configured on the model and returns it
12440 //
12441 // var Model = Backbone.Model.extend({
12442 // validation: {
12443 // someAttribute: {
12444 // required: true
12445 // }
12446 // },
12447 //
12448 // labels: {
12449 // someAttribute: 'Custom label'
12450 // }
12451 // });
12452 label: function(attrName, model) {
12453 return (model.labels && model.labels[attrName]) || defaultLabelFormatters.sentenceCase(attrName, model);
12454 }
12455 };
12456
12457 // AttributeLoaders
12458
12459 var defaultAttributeLoaders = Validation.attributeLoaders = {
12460 inputNames: function (view) {
12461 var attrs = [];
12462 if (view) {
12463 view.$('form [name]').each(function () {
12464 if (/^(?:input|select|textarea)$/i.test(this.nodeName) && this.name &&
12465 this.type !== 'submit' && attrs.indexOf(this.name) === -1) {
12466 attrs.push(this.name);
12467 }
12468 });
12469 }
12470 return attrs;
12471 }
12472 };
12473
12474
12475 // Built in validators
12476 // -------------------
12477
12478 var defaultValidators = Validation.validators = (function(){
12479 // Use native trim when defined
12480 var trim = String.prototype.trim ?
12481 function(text) {
12482 return text === null ? '' : String.prototype.trim.call(text);
12483 } :
12484 function(text) {
12485 var trimLeft = /^\s+/,
12486 trimRight = /\s+$/;
12487
12488 return text === null ? '' : text.toString().replace(trimLeft, '').replace(trimRight, '');
12489 };
12490
12491 // Determines whether or not a value is a number
12492 var isNumber = function(value){
12493 return _.isNumber(value) || (_.isString(value) && value.match(defaultPatterns.number));
12494 };
12495
12496 // Determines whether or not a value is empty
12497 var hasValue = function(value) {
12498 return !(_.isNull(value) || _.isUndefined(value) || (_.isString(value) && trim(value) === '') || (_.isArray(value) && _.isEmpty(value)));
12499 };
12500
12501 return {
12502 // Function validator
12503 // Lets you implement a custom function used for validation
12504 fn: function(value, attr, fn, model, computed) {
12505 if(_.isString(fn)){
12506 fn = model[fn];
12507 }
12508 return fn.call(model, value, attr, computed);
12509 },
12510
12511 // Required validator
12512 // Validates if the attribute is required or not
12513 // This can be specified as either a boolean value or a function that returns a boolean value
12514 required: function(value, attr, required, model, computed) {
12515 var isRequired = _.isFunction(required) ? required.call(model, value, attr, computed) : required;
12516 if(!isRequired && !hasValue(value)) {
12517 return false; // overrides all other validators
12518 }
12519 if (isRequired && !hasValue(value)) {
12520 return this.format(defaultMessages.required, this.formatLabel(attr, model));
12521 }
12522 },
12523
12524 // Acceptance validator
12525 // Validates that something has to be accepted, e.g. terms of use
12526 // `true` or 'true' are valid
12527 acceptance: function(value, attr, accept, model) {
12528 if(value !== 'true' && (!_.isBoolean(value) || value === false)) {
12529 return this.format(defaultMessages.acceptance, this.formatLabel(attr, model));
12530 }
12531 },
12532
12533 // Min validator
12534 // Validates that the value has to be a number and equal to or greater than
12535 // the min value specified
12536 min: function(value, attr, minValue, model) {
12537 if (!isNumber(value) || value < minValue) {
12538 return this.format(defaultMessages.min, this.formatLabel(attr, model), minValue);
12539 }
12540 },
12541
12542 // Max validator
12543 // Validates that the value has to be a number and equal to or less than
12544 // the max value specified
12545 max: function(value, attr, maxValue, model) {
12546 if (!isNumber(value) || value > maxValue) {
12547 return this.format(defaultMessages.max, this.formatLabel(attr, model), maxValue);
12548 }
12549 },
12550
12551 // Range validator
12552 // Validates that the value has to be a number and equal to or between
12553 // the two numbers specified
12554 range: function(value, attr, range, model) {
12555 if(!isNumber(value) || value < range[0] || value > range[1]) {
12556 return this.format(defaultMessages.range, this.formatLabel(attr, model), range[0], range[1]);
12557 }
12558 },
12559
12560 // Length validator
12561 // Validates that the value has to be a string with length equal to
12562 // the length value specified
12563 length: function(value, attr, length, model) {
12564 if (!_.isString(value) || value.length !== length) {
12565 return this.format(defaultMessages.length, this.formatLabel(attr, model), length);
12566 }
12567 },
12568
12569 // Min length validator
12570 // Validates that the value has to be a string with length equal to or greater than
12571 // the min length value specified
12572 minLength: function(value, attr, minLength, model) {
12573 if (!_.isString(value) || value.length < minLength) {
12574 return this.format(defaultMessages.minLength, this.formatLabel(attr, model), minLength);
12575 }
12576 },
12577
12578 // Max length validator
12579 // Validates that the value has to be a string with length equal to or less than
12580 // the max length value specified
12581 maxLength: function(value, attr, maxLength, model) {
12582 if (!_.isString(value) || value.length > maxLength) {
12583 return this.format(defaultMessages.maxLength, this.formatLabel(attr, model), maxLength);
12584 }
12585 },
12586
12587 // Range length validator
12588 // Validates that the value has to be a string and equal to or between
12589 // the two numbers specified
12590 rangeLength: function(value, attr, range, model) {
12591 if (!_.isString(value) || value.length < range[0] || value.length > range[1]) {
12592 return this.format(defaultMessages.rangeLength, this.formatLabel(attr, model), range[0], range[1]);
12593 }
12594 },
12595
12596 // One of validator
12597 // Validates that the value has to be equal to one of the elements in
12598 // the specified array. Case sensitive matching
12599 oneOf: function(value, attr, values, model) {
12600 if(!_.include(values, value)){
12601 return this.format(defaultMessages.oneOf, this.formatLabel(attr, model), values.join(', '));
12602 }
12603 },
12604
12605 // Equal to validator
12606 // Validates that the value has to be equal to the value of the attribute
12607 // with the name specified
12608 equalTo: function(value, attr, equalTo, model, computed) {
12609 if(value !== computed[equalTo]) {
12610 return this.format(defaultMessages.equalTo, this.formatLabel(attr, model), this.formatLabel(equalTo, model));
12611 }
12612 },
12613
12614 // Pattern validator
12615 // Validates that the value has to match the pattern specified.
12616 // Can be a regular expression or the name of one of the built in patterns
12617 pattern: function(value, attr, pattern, model) {
12618 if (!hasValue(value) || !value.toString().match(defaultPatterns[pattern] || pattern)) {
12619 return this.format(defaultMessages[pattern] || defaultMessages.inlinePattern, this.formatLabel(attr, model), pattern);
12620 }
12621 }
12622 };
12623 }());
12624
12625 // Set the correct context for all validators
12626 // when used from within a method validator
12627 _.each(defaultValidators, function(validator, key){
12628 defaultValidators[key] = _.bind(defaultValidators[key], _.extend({}, formatFunctions, defaultValidators));
12629 });
12630
12631 return Validation;
12632 }(_));
12633 return Backbone.Validation;
12634}));
12635
12636/***/ }),
12637/* 111 */
12638/***/ (function(module, exports, __webpack_require__) {
12639
12640var bb = __webpack_require__(4);
12641var _ = __webpack_require__(0);
12642
12643/**
12644 * AutoGrow
12645 */
12646bb.Stickit.addHandler({
12647 selector: '.autogrow',
12648 afterUpdate: function($el){
12649 $el.trigger('input');
12650 }
12651});
12652
12653/**
12654 * Select2
12655 */
12656bb.Stickit.addHandler({
12657 selector: 'select.select2',
12658 initialize: function($el, model, opt){
12659 $el.trigger('stickit:init', opt.observe); // on-the-fly select options
12660 var options = _.get( opt, ['view', 'select2', opt.observe ], {} );
12661 $el.select2( options );
12662 },
12663 getVal: function($el){
12664 /**
12665 * below is the default select getVal method
12666 * it relies on data-stickit-bind-val attr
12667 */
12668
12669 //var selected = $el.find('option:selected');
12670 //
12671 //if ($el.prop('multiple')) {
12672 // return _.map(selected, function(el) {
12673 // return Backbone.$(el).data('stickit-bind-val');
12674 // });
12675 //} else {
12676 // return selected.data('stickit-bind-val');
12677 //}
12678
12679 return $el.val();
12680 }
12681});
12682
12683/**
12684 * Multiple selects with Select2
12685 * ... bit of a hack here, setting an array only registers a change
12686 * ie: if last element removed no change is registered
12687 */
12688bb.Stickit.addHandler({
12689 selector: 'select[multiple].select2',
12690 onSet: function(val, opts){
12691 if(_.isArray(val)){
12692 this.model.unset(opts.observe, {silent:true});
12693 }
12694 return val;
12695 }
12696});
12697
12698/***/ }),
12699/* 112 */,
12700/* 113 */
12701/***/ (function(module, exports, __webpack_require__) {
12702
12703var Service = __webpack_require__(12);
12704var View = __webpack_require__(114);
12705var _ = __webpack_require__(0);
12706var debug = __webpack_require__(8)('loading');
12707
12708module.exports = Service.extend({
12709 channelName: 'loading',
12710
12711 initialize: function (options) {
12712 _.defaults(options, {
12713 type : 'spinner',
12714 message : ''
12715 });
12716
12717 if(options.container && this[options.type]){
12718 this[options.type](options);
12719 } else {
12720 debug('invalid loading options', options);
12721 }
12722 },
12723
12724 spinner: function(options){
12725 var view = new View({
12726 message: options.message
12727 });
12728 options.container.show(view);
12729 },
12730
12731 opacity: function(options){
12732 options.container.currentView.$el.css({
12733 'opacity': 0.5
12734 });
12735 }
12736
12737});
12738
12739/***/ }),
12740/* 114 */
12741/***/ (function(module, exports, __webpack_require__) {
12742
12743var ItemView = __webpack_require__(5);
12744var _ = __webpack_require__(0);
12745var App = __webpack_require__(1);
12746
12747var View = ItemView.extend({
12748 className: 'loading',
12749 iconPrefix: 'icon-',
12750
12751 initialize: function () {
12752 this.on('update:message', this.render);
12753 this.timeout = setTimeout(_.bind(this.fail, this), 60000);
12754 // test for wp-admin
12755 if(window.adminpage){
12756 this.iconPrefix = 'wc_pos-icon-';
12757 }
12758 },
12759
12760 render: function () {
12761 var message = '';
12762 if (!_.isEmpty(this.options.message)) {
12763 message = '<p>' + this.options.message + '</p>';
12764 }
12765 this.$el.html('<p>' + this.icon() + '</p>' + message);
12766 return this;
12767 },
12768
12769 onBeforeDestroy: function () {
12770 clearTimeout(this.timeout);
12771 },
12772
12773 /**
12774 * Loading fail. Will automatically get called after 60s
12775 * @param message
12776 */
12777 fail: function (message) {
12778 if (message) {
12779 this.options.message = message;
12780 } else {
12781 this.options.message = 'Script Error';
12782 }
12783 this.render();
12784 this.$('i').removeClass('icon-spinner').addClass('icon-fail');
12785 },
12786
12787 icon: function(){
12788 return '<i class="' +
12789 this.iconPrefix + 'spinner ' +
12790 this.iconPrefix + 'lg"></i>';
12791 }
12792
12793});
12794
12795module.exports = View;
12796App.prototype.set('Components.Loading.View', View);
12797
12798/***/ }),
12799/* 115 */,
12800/* 116 */,
12801/* 117 */
12802/***/ (function(module, exports, __webpack_require__) {
12803
12804var _ = __webpack_require__(0);
12805var hbs = __webpack_require__(7);
12806var accounting = __webpack_require__(18);
12807var moment = __webpack_require__(35);
12808var Utils = __webpack_require__(13);
12809var App = __webpack_require__(1);
12810
12811/**
12812 * is, compare helpers taken from
12813 * https://github.com/assemble/handlebars-helpers
12814 */
12815
12816hbs.registerHelper('is', function (value, test, options) {
12817 if ( value && _.includes(test.split('|'), value) ) {
12818 return options.fn(this);
12819 } else {
12820 return options.inverse(this);
12821 }
12822});
12823
12824/*jshint -W071, -W074: suppress warnings */
12825hbs.registerHelper('compare', function(left, operator, right, options) {
12826
12827 if (arguments.length < 3) {
12828 throw new Error('Handlebars Helper "compare" needs 2 parameters');
12829 }
12830
12831 if (options === undefined) {
12832 options = right;
12833 right = operator;
12834 operator = '===';
12835 }
12836
12837 var operators = {
12838 //'==': function(l, r) {
12839 // return l == r;
12840 //},
12841 '===': function(l, r) {
12842 return l === r;
12843 },
12844 //'!=': function(l, r) {
12845 // return l != r;
12846 //},
12847 '!==': function(l, r) {
12848 return l !== r;
12849 },
12850 '<': function(l, r) {
12851 return l < r;
12852 },
12853 '>': function(l, r) {
12854 return l > r;
12855 },
12856 '<=': function(l, r) {
12857 return l <= r;
12858 },
12859 '>=': function(l, r) {
12860 return l >= r;
12861 }
12862 //'typeof': function(l, r) {
12863 // return typeof l == r;
12864 //}
12865 };
12866
12867 if (!operators[operator]) {
12868 throw new Error(
12869 'Handlebars Helper "compare" doesn\'t know the operator ' + operator
12870 );
12871 }
12872
12873 var result = operators[operator](left, right);
12874
12875 if (result) {
12876 return options.fn(this);
12877 } else {
12878 return options.inverse(this);
12879 }
12880});
12881/*jshint +W071, +W074 */
12882
12883hbs.registerHelper('list', function(items, sep, options) {
12884 if( _.isArray(items) || _.isObject(items) ){
12885 var list = _.map(items, options.fn);
12886 return list.join(sep);
12887 }
12888 return options.fn(items);
12889});
12890
12891hbs.registerHelper('csv', function(items, options) {
12892 return options.fn(items.join(', '));
12893});
12894
12895hbs.registerHelper('money', function(num, options){
12896 var defaultPrecision = accounting.settings.currency.precision,
12897 precision = options.hash.precision || defaultPrecision;
12898
12899 if( precision === 'auto' ) {
12900 precision = Utils.decimalPlaces(num);
12901 }
12902
12903 // round the number to even
12904 num = Utils.round(num, precision);
12905
12906 if(options.hash.negative) {
12907 num = num * -1;
12908 }
12909
12910 return accounting.formatMoney(num);
12911});
12912
12913hbs.registerHelper('number', function(num, options){
12914 var defaultPrecision = accounting.settings.number.precision,
12915 precision = options.hash.precision || defaultPrecision;
12916
12917 if( precision === 'auto' ) {
12918 precision = Utils.decimalPlaces(num);
12919 }
12920
12921 if(options.hash.negative) {
12922 num = num * -1;
12923 }
12924
12925 return accounting.formatNumber(num, precision);
12926});
12927
12928hbs.registerHelper('formatAddress', function(a, options){
12929 a = a || {};
12930
12931 var format = [
12932 [a.first_name, a.last_name],
12933 [a.company],
12934 [a.address_1],
12935 [a.address_2],
12936 [a.city, a.state, a.postcode]
12937 ];
12938
12939 // format address
12940 var address = _.chain(format)
12941 .map(function(line) { return _.compact(line).join(' '); })
12942 .compact()
12943 .join('<br>\n')
12944 .value();
12945
12946 // prepend title
12947 if( address !== '' && options.hash.title ) {
12948 address = '<h3>' + options.hash.title + '</h3>\n' + address;
12949 }
12950
12951 return new hbs.SafeString(address);
12952});
12953
12954hbs.registerHelper('formatDate', function(date, options){
12955 var f = options.hash.format || '';
12956 return moment(date).format(f);
12957});
12958
12959hbs.registerHelper('formatDay', function(day, options){
12960 var f = options.hash.format || '';
12961 var idx = parseInt(day, 10) + 1;
12962 return moment().isoWeekday(idx).format(f);
12963});
12964
12965hbs.registerHelper('debug', function(optionalValue) {
12966 console.log('Current Context');
12967 console.log('====================');
12968 console.log(this);
12969
12970 if (optionalValue) {
12971 console.log('Value');
12972 console.log('====================');
12973 console.log(optionalValue);
12974 }
12975});
12976
12977hbs.registerHelper('formatCustomerName', function(customer) {
12978 var name = _(customer).pick(['first_name','last_name'])
12979 .values()
12980 .map(function( value ){
12981 return value.trim();
12982 })
12983 .compact()
12984 .value()
12985 .join(' ');
12986
12987 if( customer && !name ){
12988 name = customer.username;
12989 }
12990
12991 return name;
12992});
12993
12994hbs.registerHelper('namespace', function(str){
12995 return App.prototype.namespace(str);
12996});
12997
12998//hbs.registerHelper('getOption', function(key){
12999// var lookup = key.split('.');
13000// var option = Radio.request( 'entities', 'get', {
13001// type: 'option',
13002// name: lookup.shift()
13003// });
13004// for(var i = 0; i < lookup.length; i++) {
13005// option = option[lookup[i]];
13006// }
13007// return option;
13008//});
13009
13010/***/ }),
13011/* 118 */,
13012/* 119 */,
13013/* 120 */,
13014/* 121 */,
13015/* 122 */,
13016/* 123 */,
13017/* 124 */,
13018/* 125 */,
13019/* 126 */,
13020/* 127 */,
13021/* 128 */,
13022/* 129 */,
13023/* 130 */,
13024/* 131 */,
13025/* 132 */,
13026/* 133 */,
13027/* 134 */,
13028/* 135 */,
13029/* 136 */,
13030/* 137 */,
13031/* 138 */,
13032/* 139 */,
13033/* 140 */,
13034/* 141 */,
13035/* 142 */,
13036/* 143 */,
13037/* 144 */,
13038/* 145 */,
13039/* 146 */,
13040/* 147 */,
13041/* 148 */,
13042/* 149 */,
13043/* 150 */,
13044/* 151 */,
13045/* 152 */,
13046/* 153 */,
13047/* 154 */,
13048/* 155 */,
13049/* 156 */,
13050/* 157 */,
13051/* 158 */,
13052/* 159 */,
13053/* 160 */,
13054/* 161 */,
13055/* 162 */,
13056/* 163 */,
13057/* 164 */,
13058/* 165 */,
13059/* 166 */,
13060/* 167 */,
13061/* 168 */,
13062/* 169 */,
13063/* 170 */,
13064/* 171 */,
13065/* 172 */,
13066/* 173 */,
13067/* 174 */,
13068/* 175 */,
13069/* 176 */,
13070/* 177 */,
13071/* 178 */,
13072/* 179 */,
13073/* 180 */,
13074/* 181 */,
13075/* 182 */,
13076/* 183 */,
13077/* 184 */,
13078/* 185 */,
13079/* 186 */,
13080/* 187 */,
13081/* 188 */,
13082/* 189 */,
13083/* 190 */,
13084/* 191 */,
13085/* 192 */,
13086/* 193 */,
13087/* 194 */,
13088/* 195 */,
13089/* 196 */,
13090/* 197 */,
13091/* 198 */,
13092/* 199 */,
13093/* 200 */,
13094/* 201 */,
13095/* 202 */,
13096/* 203 */,
13097/* 204 */,
13098/* 205 */,
13099/* 206 */,
13100/* 207 */,
13101/* 208 */,
13102/* 209 */,
13103/* 210 */,
13104/* 211 */,
13105/* 212 */,
13106/* 213 */,
13107/* 214 */,
13108/* 215 */,
13109/* 216 */,
13110/* 217 */,
13111/* 218 */,
13112/* 219 */,
13113/* 220 */,
13114/* 221 */,
13115/* 222 */,
13116/* 223 */,
13117/* 224 */
13118/***/ (function(module, exports, __webpack_require__) {
13119
13120var Application = __webpack_require__(225);
13121
13122/**
13123 * Services
13124 */
13125var EntitiesService = __webpack_require__(60);
13126var ModalService = __webpack_require__(91);
13127var TabsService = __webpack_require__(100);
13128var ButtonsService = __webpack_require__(106);
13129
13130/**
13131 * SubApps
13132 */
13133var SettingsRouter = __webpack_require__(227);
13134
13135/**
13136 * bootstrap Handlebars Helpers
13137 */
13138__webpack_require__(117);
13139
13140/**
13141 * Create the app
13142 */
13143var app = new Application();
13144
13145/**
13146 * ... add SubApps and Services
13147 */
13148app.entities = new EntitiesService({
13149 app: app
13150});
13151
13152app.settingsApp = new SettingsRouter({
13153 container: app.layout.getRegion('main')
13154});
13155
13156app.modalApp = new ModalService({
13157 container: app.layout.getRegion('modal')
13158});
13159
13160app.tabsService = new TabsService();
13161app.buttonsService = new ButtonsService();
13162
13163/**
13164 * Attach app to window for third party plugins
13165 */
13166module.exports = app;
13167
13168/***/ }),
13169/* 225 */
13170/***/ (function(module, exports, __webpack_require__) {
13171
13172var Application = __webpack_require__(1);
13173var bb = __webpack_require__(4);
13174var _ = __webpack_require__(0);
13175var LayoutView = __webpack_require__(226);
13176var debug = __webpack_require__(8)('admin');
13177var Radio = __webpack_require__(2);
13178var routerChannel = Radio.channel('router');
13179
13180module.exports = Application.extend({
13181
13182 initialize: function() {
13183
13184 // init Root LayoutView
13185 this.layout = new LayoutView();
13186 this.layout.render();
13187
13188 this.listenTo(routerChannel, {
13189 'before:enter:route' : this.onBeforeEnterRoute,
13190 'enter:route' : this.onEnterRoute,
13191 'error:route' : this.onErrorRoute
13192 });
13193 },
13194
13195 /**
13196 * Set up application with start params
13197 */
13198 onBeforeStart: function(options){
13199 options = options || {};
13200
13201 debug( 'starting WooCommerce POS admin app' );
13202
13203 // get settings tabs
13204 this.settingsApp.tabsArray = _.map(options.settings, function(setting){
13205 return _.pick(setting, ['id', 'label']);
13206 });
13207
13208 // get settings data
13209 var data = _.map(options.settings, function(setting){
13210 _.set(setting, ['data', 'id'], setting.id);
13211 return setting.data;
13212 });
13213
13214 // init settings
13215 var settings = Radio.request('entities', 'get', {
13216 type: 'collection',
13217 name: 'settings'
13218 });
13219
13220 settings.add( data );
13221 },
13222
13223 onStart: function(){
13224 bb.history.start();
13225 },
13226
13227 onBeforeEnterRoute: function() {
13228 //var self = this;
13229 this.transitioning = true;
13230 // Don't show for synchronous route changes
13231 //_.defer(function() {
13232 // if (self.transitioning) {
13233 // nprogress.start();
13234 // }
13235 //});
13236 },
13237
13238 onEnterRoute: function() {
13239 this.transitioning = false;
13240 //this.$body.scrollTop(0);
13241 //nprogress.done();
13242 },
13243
13244 onErrorRoute: function() {
13245 this.transitioning = false;
13246 //nprogress.done(true);
13247 }
13248});
13249
13250/***/ }),
13251/* 226 */
13252/***/ (function(module, exports, __webpack_require__) {
13253
13254var LayoutView = __webpack_require__(10);
13255
13256module.exports = LayoutView.extend({
13257
13258 el: '#wpbody-content .wrap',
13259
13260 template: function(){
13261 return '' +
13262 '<div id="wc_pos-admin"></div>' +
13263 '<div id="wc_pos-modal"></div>';
13264 },
13265
13266 regions: {
13267 main : '#wc_pos-admin',
13268 modal: '#wc_pos-modal'
13269 }
13270
13271});
13272
13273/***/ }),
13274/* 227 */
13275/***/ (function(module, exports, __webpack_require__) {
13276
13277var App = __webpack_require__(1);
13278var Router = __webpack_require__(39);
13279var LayoutView = __webpack_require__(228);
13280var General = __webpack_require__(229);
13281var Checkout = __webpack_require__(232);
13282var HotKeys = __webpack_require__(236);
13283var Access = __webpack_require__(238);
13284var Tools = __webpack_require__(240);
13285var Status = __webpack_require__(244);
13286var bb = __webpack_require__(4);
13287var Radio = bb.Radio;
13288var _ = __webpack_require__(0);
13289
13290var SettingsRouter = Router.extend({
13291 initialize: function(options) {
13292 this.container = options.container;
13293 this.collection = Radio.request('entities', 'get', {
13294 type: 'collection',
13295 name: 'settings'
13296 });
13297 },
13298
13299 onBeforeEnter: function() {
13300 this.layout = new LayoutView();
13301 this.listenTo(this.layout, 'show', this.showTabs);
13302 this.container.show(this.layout);
13303 },
13304
13305 routes: {
13306 '' : 'showGeneral',
13307 'general' : 'showGeneral',
13308 'checkout': 'showCheckout',
13309 'hotkeys' : 'showHotkeys',
13310 'access' : 'showAccess',
13311 'tools' : 'showTools',
13312 'status' : 'showStatus'
13313 },
13314
13315 onBeforeRoute: function() {
13316 this.layout.getRegion('footer').empty();
13317 },
13318
13319 showTabs: function(){
13320 var hash = bb.history.getHash() || 'general';
13321 var tab = _.findWhere( this.tabsArray, { id: hash } );
13322 if( tab ){
13323 tab.active = true;
13324 }
13325
13326 // this.tabsArray is added during POS.onBeforeStart
13327 var view = Radio.request('tabs', 'view', {
13328 tabs: this.tabsArray
13329 });
13330
13331 this.listenTo(view, 'show', function(){
13332 // use wordpress admin styles
13333 view.$el.addClass('nav-tab-wrapper');
13334 view.children.each(function(child){
13335 child.$el.addClass('nav-tab');
13336 });
13337 });
13338
13339 this.listenTo(view.collection, 'change:active', function(model, active){
13340 if(active){
13341 this.navigate(model.id, {
13342 trigger: true,
13343 replace: true
13344 });
13345 }
13346 });
13347
13348 this.layout.getRegion('tabs').show(view);
13349 },
13350
13351 showGeneral: function(){
13352 var model = this.collection.get('general');
13353 this.showFooter({model: model});
13354 return new General({
13355 container : this.layout.getRegion('settings'),
13356 model: model
13357 });
13358 },
13359
13360 showCheckout: function(){
13361 var model = this.collection.get('checkout');
13362 this.showFooter({model: model});
13363 return new Checkout({
13364 container : this.layout.getRegion('settings'),
13365 model: model
13366 });
13367 },
13368
13369 showHotkeys: function(){
13370 var model = this.collection.get('hotkeys');
13371 this.showFooter({model: model});
13372 return new HotKeys({
13373 container : this.layout.getRegion('settings'),
13374 model: model
13375 });
13376 },
13377
13378 showAccess: function(){
13379 var model = this.collection.get('access');
13380 this.showFooter({model: model});
13381 return new Access({
13382 container : this.layout.getRegion('settings'),
13383 model: model
13384 });
13385 },
13386
13387 showTools: function(){
13388 return new Tools({
13389 container : this.layout.getRegion('settings')
13390 });
13391 },
13392
13393 showStatus: function(){
13394 return new Status({
13395 container : this.layout.getRegion('settings')
13396 });
13397 },
13398
13399 showFooter: function(options){
13400
13401 _.defaults(options, {
13402 buttons: [
13403 {
13404 action : 'save',
13405 className : 'button-primary',
13406 icon : 'append'
13407 },{
13408 type: 'message'
13409 },{
13410 action : 'restore',
13411 className : 'button-secondary alignright',
13412 icon : 'prepend'
13413 }
13414 ]
13415 });
13416
13417 var view = Radio.request('buttons', 'view', options);
13418
13419 this.listenTo(view, {
13420 'action:save': function(btn){
13421 options.model.save([], { buttons: btn });
13422 },
13423 'action:restore': function(btn){
13424 options.model.destroy({ buttons: btn });
13425 }
13426 });
13427
13428 this.layout.getRegion('footer').show(view);
13429
13430 }
13431
13432});
13433
13434module.exports = SettingsRouter;
13435App.prototype.set('SettingsApp.Router', SettingsRouter);
13436
13437/***/ }),
13438/* 228 */
13439/***/ (function(module, exports, __webpack_require__) {
13440
13441var LayoutView = __webpack_require__(10);
13442var App = __webpack_require__(1);
13443
13444var Layout = LayoutView.extend({
13445
13446 template: function(){
13447 return '' +
13448 '<div id="wc_pos-settings-tabs"></div>' +
13449 '<div id="wc_pos-settings"></div>' +
13450 '<div id="wc_pos-settings-footer"></div>';
13451 },
13452
13453 regions: {
13454 tabs : '#wc_pos-settings-tabs',
13455 settings: '#wc_pos-settings',
13456 footer : '#wc_pos-settings-footer'
13457 }
13458
13459});
13460
13461module.exports = Layout;
13462App.prototype.set('SettingsApp.LayoutView', Layout);
13463
13464/***/ }),
13465/* 229 */
13466/***/ (function(module, exports, __webpack_require__) {
13467
13468var Route = __webpack_require__(11);
13469var App = __webpack_require__(1);
13470var View = __webpack_require__(230);
13471
13472var General = Route.extend({
13473
13474 initialize: function( options ) {
13475 options = options || {};
13476 this.container = options.container;
13477 this.model = options.model;
13478 },
13479
13480 fetch: function() {
13481 if(this.model && this.model.isNew()){
13482 return this.model.fetch();
13483 }
13484 },
13485
13486 render: function() {
13487 var view = new View({
13488 model: this.model
13489 });
13490 this.container.show(view);
13491 }
13492
13493});
13494
13495module.exports = General;
13496App.prototype.set('SettingsApp.General.Route', General);
13497
13498/***/ }),
13499/* 230 */
13500/***/ (function(module, exports, __webpack_require__) {
13501
13502var FormView = __webpack_require__(17);
13503var $ = __webpack_require__(3);
13504var App = __webpack_require__(1);
13505var CustomerSelect = __webpack_require__(231);
13506var Tooltip = __webpack_require__(24);
13507
13508var View = FormView.extend({
13509
13510 template: 'general',
13511
13512 attributes: {
13513 id: 'wc_pos-settings-general'
13514 },
13515
13516 behaviors: {
13517 Tooltip: {
13518 behaviorClass: Tooltip
13519 },
13520 CustomerSelect: {
13521 behaviorClass: CustomerSelect
13522 }
13523 },
13524
13525 select2: {
13526 'discount_quick_keys': {
13527 maximumSelectionLength: 4
13528 }
13529 },
13530
13531 modelEvents: {
13532 'change:id': 'render',
13533 'change:logged_in_user': function(model, toggle){
13534 this.ui.customerSelect.prop('disabled', toggle);
13535 }
13536 },
13537
13538 ui: {
13539 customerSelect: 'select[data-select="customer"]'
13540 },
13541
13542 onRender: function(){
13543 var self = this;
13544
13545 // bind ordinary elements
13546 this.$('input, select, textarea').each(function(){
13547 var name = $(this).attr('name');
13548 if(name){
13549 self.addBinding(null, '*[name="' + name + '"]', name);
13550 }
13551 });
13552
13553 // disable customer select if logged_in_user checked
13554 if( this.model.get('logged_in_user') ){
13555 this.ui.customerSelect.prop('disabled', true);
13556 }
13557 }
13558
13559});
13560
13561module.exports = View;
13562App.prototype.set('SettingsApp.General.View', View);
13563
13564/***/ }),
13565/* 231 */
13566/***/ (function(module, exports, __webpack_require__) {
13567
13568var Behavior = __webpack_require__(15);
13569var App = __webpack_require__(1);
13570var Radio = __webpack_require__(2);
13571var _ = __webpack_require__(0);
13572var $ = __webpack_require__(3);
13573var hbs = __webpack_require__(7);
13574
13575var CustomerSelect = Behavior.extend({
13576
13577 initialize: function(){
13578 var options = Radio.request('entities', 'get', {
13579 type: 'option',
13580 name: 'customers'
13581 });
13582 options.ajaxurl = Radio.request('entities', 'get', {
13583 type: 'option',
13584 name: 'ajaxurl'
13585 });
13586 options.wc_nonce = Radio.request('entities', 'get', {
13587 type: 'option',
13588 name: 'search_customers_nonce'
13589 });
13590 this.mergeOptions(options, ['guest', 'default', 'ajaxurl', 'wc_nonce']);
13591 },
13592
13593 ui: {
13594 select: 'select[data-select="customer"]'
13595 },
13596
13597 // using custom event to set select2 options
13598 events: {
13599 'stickit:init @ui.select': function( e, name ){
13600 // options
13601 var ajaxurl = this.getOption('ajaxurl');
13602 var nonce = this.getOption('wc_nonce');
13603 var guest = this.getOption('guest');
13604 this.view.select2 = this.view.select2 || {};
13605 this.view.select2[name] = {
13606 minimumInputLength: 3, // minimum 3 characters to trigger search
13607 ajax: {
13608 url: ajaxurl,
13609 dataType: 'json',
13610 delay: 250,
13611 data: function (params) {
13612 return {
13613 term : params.term, // search term
13614 action : 'woocommerce_json_search_customers',
13615 security : nonce
13616 };
13617 },
13618 processResults: function (data) {
13619 var terms = [];
13620 if ( data ) {
13621 $.each( data, function( id, text ) {
13622 terms.push({
13623 id: id,
13624 text: text
13625 });
13626 });
13627 }
13628 terms.unshift({
13629 id: '0',
13630 text: guest.first_name
13631 });
13632 return { results: terms };
13633 },
13634 cache: true
13635 },
13636 escapeMarkup: function( m ) {
13637 return m;
13638 }
13639 };
13640 }
13641 },
13642
13643 onRender: function(){
13644 // initSelection
13645 if( _.isEmpty( this.ui.select.data('placeholder') ) ){
13646 this.initSelection();
13647 }
13648
13649 },
13650
13651 initSelection: function(){
13652 var customer = this.getOption('default') || this.getOption('guest');
13653 var name = hbs.helpers.formatCustomerName( customer );
13654 this.ui.select
13655 .html( $('<option />').val(customer.id).text(name) )
13656 .trigger('change');
13657 }
13658
13659});
13660
13661module.exports = CustomerSelect;
13662App.prototype.set('Behaviors.CustomerSelect', CustomerSelect);
13663
13664/***/ }),
13665/* 232 */
13666/***/ (function(module, exports, __webpack_require__) {
13667
13668var Route = __webpack_require__(11);
13669var App = __webpack_require__(1);
13670var View = __webpack_require__(233);
13671var GatewaySettingsModal = __webpack_require__(235);
13672var Radio = __webpack_require__(2);
13673
13674var SettingsRoute = Route.extend({
13675
13676 initialize: function( options ) {
13677 options = options || {};
13678 this.container = options.container;
13679 this.model = options.model;
13680 },
13681
13682 fetch: function() {
13683 if(this.model.isNew()){
13684 return this.model.fetch();
13685 }
13686 },
13687
13688 render: function() {
13689 var view = new View({
13690 model: this.model
13691 });
13692 this.listenTo(view, 'open:modal', this.openModal);
13693 this.container.show(view);
13694 },
13695
13696 openModal: function(id, view){
13697 var model = this.model.collection.add({
13698 id: 'gateway_' + id
13699 });
13700
13701 if(!model.get('title')){
13702 this.initModalData(model, view);
13703 }
13704
13705 var modal = new GatewaySettingsModal({
13706 tmpl: view.modalTmpl,
13707 model: model
13708 });
13709
13710 var self = this;
13711 Radio.request('modal', 'open', modal)
13712 .then(function(args){
13713 var buttons = args.view.getButtons();
13714 self.listenTo(buttons, 'action:save', function(btn){
13715 model.save([], { buttons: btn });
13716 });
13717 });
13718
13719 },
13720
13721 initModalData: function(model, view){
13722 function element(attr){
13723 return '#' + model.id + ' .gateway-' + attr;
13724 }
13725 var data = {
13726 title: view.$(element('name')).html(),
13727 description: view.$(element('description')).html(),
13728 icon: view.$(element('icon')).data('show') ? true : false
13729 };
13730 data.hasIcon = view.$(element('icon')).data('icon');
13731 model.set(data);
13732 }
13733
13734});
13735
13736module.exports = SettingsRoute;
13737App.prototype.set('SettingsApp.Route', SettingsRoute);
13738
13739/***/ }),
13740/* 233 */
13741/***/ (function(module, exports, __webpack_require__) {
13742
13743var FormView = __webpack_require__(17);
13744var $ = __webpack_require__(3);
13745var App = __webpack_require__(1);
13746var Tooltip = __webpack_require__(24);
13747var Sortable = __webpack_require__(234);
13748
13749var View = FormView.extend({
13750 template: 'checkout',
13751
13752 attributes: {
13753 id: 'wc_pos-settings-checkout'
13754 },
13755
13756 modelEvents: {
13757 'change:id': 'render'
13758 },
13759
13760 onRender: function(){
13761 var self = this;
13762 this.$('input, select, textarea').each(function(){
13763 var name = $(this).attr('name');
13764 if(name){
13765 self.addBinding(null, '*[name="' + name + '"]', name);
13766 }
13767 });
13768 this.modalTmpl = this.$('#tmpl-gateway-settings-modal').html();
13769 },
13770
13771 ui: {
13772 settings: '.gateway-settings'
13773 },
13774
13775 events: {
13776 'click @ui.settings': 'openGatewaySettingsModal'
13777 },
13778
13779 behaviors: {
13780 Tooltip: {
13781 behaviorClass: Tooltip
13782 },
13783 Sortable: {
13784 behaviorClass: Sortable
13785 }
13786 },
13787
13788 openGatewaySettingsModal: function(e){
13789 e.preventDefault();
13790 var gateway = $(e.target).data('gateway');
13791 this.trigger('open:modal', gateway, this);
13792 }
13793
13794});
13795
13796module.exports = View;
13797App.prototype.set('SettingsApp.View');
13798
13799/***/ }),
13800/* 234 */
13801/***/ (function(module, exports, __webpack_require__) {
13802
13803var Behavior = __webpack_require__(15);
13804var App = __webpack_require__(1);
13805var $ = __webpack_require__(3);
13806var _ = __webpack_require__(0);
13807
13808var Sortable = Behavior.extend({
13809
13810 initialize: function(options){
13811
13812 this.options = _.defaults(options, {
13813 items:'tr',
13814 cursor:'move',
13815 axis:'y',
13816 handle: 'td',
13817 scrollSensitivity:40,
13818 helper:function(e,ui){
13819 ui.children().each(function(){
13820 $(this).width($(this).width());
13821 });
13822 return ui;
13823 },
13824 start:function(event,ui){
13825 ui.item.css('background-color','#f6f6f6');
13826 },
13827 stop:function(event,ui){
13828 ui.item.removeAttr('style');
13829 $('input.gateway_order', this).each(function(idx) {
13830 $(this).val(idx);
13831 $(this).trigger('input');
13832 });
13833 }
13834 });
13835
13836 },
13837
13838 ui: {
13839 sortable: '.sortable'
13840 },
13841
13842 onRender: function() {
13843 if( this.ui.sortable.length > 0 ) {
13844
13845 // Custom sorting for checkout settings table
13846 // TODO: move this to view callback
13847 var table = this.ui.sortable;
13848 var rows = table.find('tbody tr').get();
13849
13850 // sort according to input
13851 table.append(rows.sort(function(a, b) {
13852 return parseInt($(a).find('input.gateway_order').val(), 10) -
13853 parseInt($(b).find('input.gateway_order').val(), 10);
13854 }));
13855
13856 table.sortable( this.options );
13857 }
13858
13859 }
13860
13861});
13862
13863module.exports = Sortable;
13864App.prototype.set('Behaviors.Sortable', Sortable);
13865
13866/***/ }),
13867/* 235 */
13868/***/ (function(module, exports, __webpack_require__) {
13869
13870var FormView = __webpack_require__(17);
13871var $ = __webpack_require__(3);
13872var Tooltip = __webpack_require__(24);
13873var Radio = __webpack_require__(2);
13874
13875module.exports = FormView.extend({
13876
13877 tagName: 'table',
13878
13879 className: 'wc_pos-form-table',
13880
13881 initialize: function (options) {
13882 options = options || {};
13883 this.template = options.tmpl.trim();
13884 // modal setup
13885 this.modal = {
13886 header: {
13887 title: this.model.get('title')
13888 },
13889 footer: {
13890 buttons: [
13891 {
13892 type: 'message'
13893 },{
13894 action : 'save',
13895 className : 'button-primary',
13896 icon : 'prepend'
13897 }
13898 ]
13899 }
13900 };
13901 },
13902
13903 behaviors: {
13904 Tooltip: {
13905 behaviorClass: Tooltip
13906 }
13907 },
13908
13909 modelEvents: {
13910 'change:title': function(modal, value){
13911 var update = {};
13912 update.header = { title: value };
13913 Radio.request('modal', 'update', update);
13914 }
13915 },
13916
13917 onRender: function(){
13918 var self = this;
13919 this.$('input, select, textarea').each(function(){
13920 var name = $(this).attr('name');
13921 if(name){
13922 self.addBinding(null, '*[name="' + name + '"]', name);
13923 }
13924 });
13925
13926 if(this.model.get('hasIcon')){
13927 this.$('#icon').closest('tr').show();
13928 }
13929 }
13930
13931});
13932
13933/***/ }),
13934/* 236 */
13935/***/ (function(module, exports, __webpack_require__) {
13936
13937var Route = __webpack_require__(11);
13938var App = __webpack_require__(1);
13939var View = __webpack_require__(237);
13940
13941var HotKeys = Route.extend({
13942
13943 initialize: function( options ) {
13944 options = options || {};
13945 this.container = options.container;
13946 this.model = options.model;
13947 },
13948
13949 render: function() {
13950 var view = new View({
13951 model: this.model
13952 });
13953 this.container.show(view);
13954 }
13955
13956});
13957
13958module.exports = HotKeys;
13959App.prototype.set('SettingsApp.HotKeys.Route', HotKeys);
13960
13961/***/ }),
13962/* 237 */
13963/***/ (function(module, exports, __webpack_require__) {
13964
13965var FormView = __webpack_require__(17);
13966var $ = __webpack_require__(3);
13967var App = __webpack_require__(1);
13968var Tooltip = __webpack_require__(24);
13969
13970var View = FormView.extend({
13971
13972 template: 'hotkeys',
13973
13974 attributes: {
13975 id: 'wc_pos-settings-hotkeys'
13976 },
13977
13978 behaviors: {
13979 Tooltip: {
13980 behaviorClass: Tooltip
13981 }
13982 },
13983
13984 modelEvents: {
13985 'change:id': 'render'
13986 },
13987
13988 onRender: function(){
13989 var self = this;
13990
13991 // bind ordinary elements
13992 this.$('input, select, textarea').each(function(){
13993 var name = $(this).attr('name');
13994 if(name){
13995 self.addBinding(null, '*[name="' + name + '"]', name);
13996 }
13997 });
13998
13999 }
14000
14001});
14002
14003module.exports = View;
14004App.prototype.set('SettingsApp.HotKeys.View');
14005
14006/***/ }),
14007/* 238 */
14008/***/ (function(module, exports, __webpack_require__) {
14009
14010var Route = __webpack_require__(11);
14011var App = __webpack_require__(1);
14012var View = __webpack_require__(239);
14013
14014var Access = Route.extend({
14015
14016 initialize: function( options ) {
14017 options = options || {};
14018 this.container = options.container;
14019 this.model = options.model;
14020 },
14021
14022 fetch: function() {
14023 if(this.model.isNew()){
14024 return this.model.fetch();
14025 }
14026 },
14027
14028 render: function() {
14029 var view = new View({
14030 model: this.model
14031 });
14032 this.container.show(view);
14033 }
14034
14035});
14036
14037module.exports = Access;
14038App.prototype.set('SettingsApp.Access.Route', Access);
14039
14040/***/ }),
14041/* 239 */
14042/***/ (function(module, exports, __webpack_require__) {
14043
14044var FormView = __webpack_require__(17);
14045var App = __webpack_require__(1);
14046var $ = __webpack_require__(3);
14047
14048var View = FormView.extend({
14049
14050 template: 'access',
14051
14052 attributes: {
14053 id: 'wc_pos-settings-access'
14054 },
14055
14056 ui: {
14057 tabs : '.wc_pos-access-tabs > li',
14058 options : '.wc_pos-access-panel > li'
14059 },
14060
14061 events: {
14062 'click @ui.tabs' : 'onTabClick'
14063 },
14064
14065 modelEvents: {
14066 'change:id': 'render'
14067 },
14068
14069 onRender: function(){
14070 var self = this;
14071
14072 // bind ordinary elements
14073 this.$('input, select, textarea').each(function(){
14074 var name = $(this).attr('name');
14075 if(name){
14076 self.addBinding(null, '*[name="' + name + '"]', name);
14077 }
14078 });
14079
14080 // init the first tab
14081 this.ui.tabs.first().addClass('active');
14082 this.ui.options.first().addClass('active');
14083 },
14084
14085 onTabClick: function(e){
14086 this.ui.tabs.each(function(){
14087 $(this).removeClass('active');
14088 });
14089 this.ui.options.each(function(){
14090 $(this).removeClass('active');
14091 });
14092 $(e.currentTarget).addClass('active');
14093 var option = $(e.currentTarget).data('id');
14094 $('#' + option).addClass('active');
14095 }
14096
14097});
14098
14099module.exports = View;
14100App.prototype.set('SettingsApp.Access.View');
14101
14102/***/ }),
14103/* 240 */
14104/***/ (function(module, exports, __webpack_require__) {
14105
14106var Route = __webpack_require__(11);
14107var App = __webpack_require__(1);
14108var View = __webpack_require__(241);
14109var TranslationModal = __webpack_require__(242);
14110var DataDeleteModal = __webpack_require__(243);
14111var Radio = __webpack_require__(2);
14112
14113var Tools = Route.extend({
14114
14115 initialize: function( options ) {
14116 options = options || {};
14117 this.container = options.container;
14118 },
14119
14120 render: function() {
14121 var view = new View();
14122 this.listenTo(view, {
14123 'translation:update': this.openTranslationModal,
14124 'data:delete' : this.openDataDeleteModal
14125 });
14126 this.container.show(view);
14127 },
14128
14129 openTranslationModal: function(args){
14130 var title = args.view
14131 .$('[data-action="translation"]')
14132 .data('title');
14133
14134 var view = new TranslationModal({
14135 title: title
14136 });
14137 Radio.request('modal', 'open', view);
14138 },
14139
14140 openDataDeleteModal: function(args){
14141 var title = args.view
14142 .$('[data-action="delete-local-data"]')
14143 .data('title');
14144
14145 var view = new DataDeleteModal({
14146 title: title
14147 });
14148 Radio.request('modal', 'open', view);
14149 }
14150
14151});
14152
14153module.exports = Tools;
14154App.prototype.set('SettingsApp.Tools.Route', Tools);
14155
14156/***/ }),
14157/* 241 */
14158/***/ (function(module, exports, __webpack_require__) {
14159
14160var ItemView = __webpack_require__(5);
14161var App = __webpack_require__(1);
14162var EmulateHTTP = __webpack_require__(40);
14163
14164var View = ItemView.extend({
14165
14166 template: 'tools',
14167
14168 attributes: {
14169 id: 'wc_pos-settings-tools'
14170 },
14171
14172 behaviors: {
14173 EmulateHTTP: {
14174 behaviorClass: EmulateHTTP
14175 }
14176 },
14177
14178 ui: {
14179 translation: '*[data-action="translation"]',
14180 deleteData: '*[data-action="delete-local-data"]'
14181 },
14182
14183 triggers: {
14184 'click @ui.translation': 'translation:update',
14185 'click @ui.deleteData' : 'data:delete'
14186 }
14187
14188});
14189
14190module.exports = View;
14191App.prototype.set('SettingsApp.Tools.View');
14192
14193/***/ }),
14194/* 242 */
14195/***/ (function(module, exports, __webpack_require__) {
14196
14197/* WEBPACK VAR INJECTION */(function(global) {var ItemView = __webpack_require__(5);
14198var Radio = __webpack_require__(2);
14199var EventSource = global['EventSource'];
14200
14201module.exports = ItemView.extend({
14202 template: function(){
14203 return '<i class="wc_pos-icon-loading"></i>';
14204 },
14205
14206 initialize: function (options) {
14207 options = options || {};
14208
14209 this.modal = {
14210 header: {
14211 title: options.title
14212 },
14213 footer: {
14214 show: false,
14215 buttons: [{
14216 action: 'close',
14217 className: 'button'
14218 }]
14219 }
14220 };
14221 },
14222
14223 ui: {
14224 loading: '.wc_pos-icon-loading'
14225 },
14226
14227 onShow: function() {
14228 var view = this,
14229 url = this.constructURL(),
14230 stream = new EventSource(url);
14231
14232 stream.onmessage = function(e){
14233 if( e.data === 'complete' ){
14234 this.close();
14235 view.ui.loading.hide();
14236 Radio.request('modal', 'update', { footer: {
14237 show: true
14238 }});
14239 } else {
14240 view.ui.loading.before('<p>' + e.data + '</p>');
14241 }
14242 };
14243 },
14244
14245 constructURL: function(){
14246 var ajaxurl = Radio.request('entities', 'get', {
14247 type: 'option',
14248 name: 'ajaxurl'
14249 });
14250 var nonce = Radio.request('entities', 'get', {
14251 type: 'option',
14252 name: 'nonce'
14253 });
14254
14255 return ajaxurl + '?action=wc_pos_update_translations&security=' + nonce;
14256 }
14257});
14258/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(33)))
14259
14260/***/ }),
14261/* 243 */
14262/***/ (function(module, exports, __webpack_require__) {
14263
14264/**
14265 * crude deleteDatabase functionality
14266 * @todo refactor with db checking
14267 */
14268
14269var ItemView = __webpack_require__(5);
14270
14271module.exports = ItemView.extend({
14272
14273 dbs: [
14274 'wc_pos_products',
14275 'wc_pos_cart',
14276 'wc_pos_orders',
14277 'wc_pos_customers',
14278 'wc_pos_coupons'
14279 ],
14280
14281 template: function(){
14282 return '<i class="wc_pos-icon-loading"></i>';
14283 },
14284
14285 initialize: function (options) {
14286 options = options || {};
14287
14288 this.modal = {
14289 header: {
14290 title: options.title
14291 },
14292 footer: {
14293 show: false,
14294 buttons: [{
14295 action: 'close',
14296 className: 'button'
14297 }]
14298 }
14299 };
14300 },
14301
14302 ui: {
14303 loading: '.wc_pos-icon-loading'
14304 },
14305
14306 onShow: function() {
14307 if(!window.indexedDB || !window.indexedDB.deleteDatabase){
14308 this.printToScreen('Browser does not support IndexedDB deleteDatabase!');
14309 return;
14310 }
14311
14312 this.deleteDatabases();
14313 },
14314
14315 printToScreen: function(str){
14316 this.ui.loading.before(str + ' ');
14317 },
14318
14319 deleteDatabases: function(){
14320 var self = this;
14321 var dbName = this.dbs.shift();
14322 var DBDeleteRequest = window.indexedDB.deleteDatabase(dbName);
14323
14324 DBDeleteRequest.onerror = function() {
14325 self.printToScreen('' +
14326 'Error deleting database, ' +
14327 'please make sure the POS is not open in another tab.'
14328 );
14329 };
14330
14331 DBDeleteRequest.onsuccess = function() {
14332
14333 // remove db version also
14334 window.localStorage.removeItem(dbName + '_idbVersion');
14335
14336 if( self.dbs.length === 0 ){
14337 self.ui.loading.hide();
14338 self.printToScreen('All local data deleted successfully.');
14339 } else {
14340 self.printToScreen('.');
14341 self.deleteDatabases();
14342 }
14343
14344 };
14345 }
14346
14347});
14348
14349/***/ }),
14350/* 244 */
14351/***/ (function(module, exports, __webpack_require__) {
14352
14353var Route = __webpack_require__(11);
14354var App = __webpack_require__(1);
14355var View = __webpack_require__(245);
14356
14357var Status = Route.extend({
14358
14359 initialize: function( options ) {
14360 options = options || {};
14361 this.container = options.container;
14362 },
14363
14364 fetch: function(){
14365
14366 },
14367
14368 render: function() {
14369 var view = new View();
14370 this.container.show(view);
14371 }
14372
14373});
14374
14375module.exports = Status;
14376App.prototype.set('SettingsApp.Status.Route', Status);
14377
14378/***/ }),
14379/* 245 */
14380/***/ (function(module, exports, __webpack_require__) {
14381
14382var ItemView = __webpack_require__(5);
14383var App = __webpack_require__(1);
14384var EmulateHTTP = __webpack_require__(40);
14385
14386var View = ItemView.extend({
14387
14388 template: 'status',
14389
14390 attributes: {
14391 id: 'wc_pos-settings-status'
14392 },
14393
14394 behaviors: {
14395 EmulateHTTP: {
14396 behaviorClass: EmulateHTTP
14397 }
14398 }
14399
14400});
14401
14402module.exports = View;
14403App.prototype.set('SettingsApp.Status.View');
14404
14405/***/ })
14406/******/ ]);