diff --git a/bower.json b/bower.json index 7b80af7445..868184f00a 100644 --- a/bower.json +++ b/bower.json @@ -34,7 +34,8 @@ "jSignature": "brinley/jSignature#^2.1.0", "select2": "select2-dist#^4.0.3", "mousetrap": "^1.6.0", - "tablesorter": "jquery.tablesorter#^2.28.4" + "tablesorter": "jquery.tablesorter#^2.28.4", + "card": "^2.1.1" }, "resolutions": { "jquery": "~1.11" diff --git a/gulpfile.js b/gulpfile.js index e1e7bb4edc..c79457f692 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -95,6 +95,10 @@ elixir(function(mix) { bowerDir + '/bootstrap-daterangepicker/daterangepicker.js' ], 'public/js/daterangepicker.min.js'); + mix.scripts([ + bowerDir + '/card/dist/card.js', + ], 'public/js/card.min.js'); + mix.scripts([ bowerDir + '/tablesorter/dist/js/jquery.tablesorter.combined.js', bowerDir + '/tablesorter/dist/js/widgets/widget-grouping.min.js', diff --git a/public/css/card.css b/public/css/card.css new file mode 100644 index 0000000000..ee5d3d6ff7 --- /dev/null +++ b/public/css/card.css @@ -0,0 +1,2497 @@ +var card = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(global) {var Card, QJ, extend, payment, + __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + __webpack_require__(1); + + QJ = __webpack_require__(5); + + payment = __webpack_require__(6); + + extend = __webpack_require__(7); + + Card = (function() { + var bindVal; + + Card.prototype.initializedDataAttr = "data-jp-card-initialized"; + + Card.prototype.cardTemplate = '' + '
' + '
' + '' + '' + '
' + '
'; + + Card.prototype.template = function(tpl, data) { + return tpl.replace(/\{\{(.*?)\}\}/g, function(match, key, str) { + return data[key]; + }); + }; + + Card.prototype.cardTypes = ['jp-card-amex', 'jp-card-dankort', 'jp-card-dinersclub', 'jp-card-discover', 'jp-card-jcb', 'jp-card-laser', 'jp-card-maestro', 'jp-card-mastercard', 'jp-card-unionpay', 'jp-card-visa', 'jp-card-visaelectron', 'jp-card-elo']; + + Card.prototype.defaults = { + formatting: true, + formSelectors: { + numberInput: 'input[name="number"]', + expiryInput: 'input[name="expiry"]', + cvcInput: 'input[name="cvc"]', + nameInput: 'input[name="name"]' + }, + cardSelectors: { + cardContainer: '.jp-card-container', + card: '.jp-card', + numberDisplay: '.jp-card-number', + expiryDisplay: '.jp-card-expiry', + cvcDisplay: '.jp-card-cvc', + nameDisplay: '.jp-card-name' + }, + messages: { + validDate: 'valid\nthru', + monthYear: 'month/year' + }, + placeholders: { + number: '•••• •••• •••• ••••', + cvc: '•••', + expiry: '••/••', + name: 'Full Name' + }, + masks: { + cardNumber: false + }, + classes: { + valid: 'jp-card-valid', + invalid: 'jp-card-invalid' + }, + debug: false + }; + + function Card(opts) { + this.maskCardNumber = __bind(this.maskCardNumber, this); + var toInitialize; + this.options = extend(true, this.defaults, opts); + if (!this.options.form) { + console.log("Please provide a form"); + return; + } + this.$el = QJ(this.options.form); + if (!this.options.container) { + console.log("Please provide a container"); + return; + } + this.$container = QJ(this.options.container); + toInitialize = QJ.isDOMElement(this.$container) ? this.$container : this.$container[0]; + if (toInitialize.getAttribute(this.initializedDataAttr)) { + return; + } + toInitialize.setAttribute(this.initializedDataAttr, true); + this.render(); + this.attachHandlers(); + this.handleInitialPlaceholders(); + } + + Card.prototype.render = function() { + var $cardContainer, baseWidth, name, obj, selector, ua, _ref, _ref1; + QJ.append(this.$container, this.template(this.cardTemplate, extend({}, this.options.messages, this.options.placeholders))); + _ref = this.options.cardSelectors; + for (name in _ref) { + selector = _ref[name]; + this["$" + name] = QJ.find(this.$container, selector); + } + _ref1 = this.options.formSelectors; + for (name in _ref1) { + selector = _ref1[name]; + selector = this.options[name] ? this.options[name] : selector; + obj = QJ.find(this.$el, selector); + if (!obj.length && this.options.debug) { + console.error("Card can't find a " + name + " in your form."); + } + this["$" + name] = obj; + } + if (this.options.formatting) { + Payment.formatCardNumber(this.$numberInput); + Payment.formatCardCVC(this.$cvcInput); + Payment.formatCardExpiry(this.$expiryInput); + } + if (this.options.width) { + $cardContainer = QJ(this.options.cardSelectors.cardContainer)[0]; + baseWidth = parseInt($cardContainer.clientWidth || window.getComputedStyle($cardContainer).width); + $cardContainer.style.transform = "scale(" + (this.options.width / baseWidth) + ")"; + } + if (typeof navigator !== "undefined" && navigator !== null ? navigator.userAgent : void 0) { + ua = navigator.userAgent.toLowerCase(); + if (ua.indexOf('safari') !== -1 && ua.indexOf('chrome') === -1) { + QJ.addClass(this.$card, 'jp-card-safari'); + } + } + if (/MSIE 10\./i.test(navigator.userAgent)) { + QJ.addClass(this.$card, 'jp-card-ie-10'); + } + if (/rv:11.0/i.test(navigator.userAgent)) { + return QJ.addClass(this.$card, 'jp-card-ie-11'); + } + }; + + Card.prototype.attachHandlers = function() { + var expiryFilters, numberInputFilters; + numberInputFilters = [this.validToggler('cardNumber')]; + if (this.options.masks.cardNumber) { + numberInputFilters.push(this.maskCardNumber); + } + bindVal(this.$numberInput, this.$numberDisplay, { + fill: false, + filters: numberInputFilters + }); + QJ.on(this.$numberInput, 'payment.cardType', this.handle('setCardType')); + expiryFilters = [ + function(val) { + return val.replace(/(\s+)/g, ''); + } + ]; + expiryFilters.push(this.validToggler('cardExpiry')); + bindVal(this.$expiryInput, this.$expiryDisplay, { + join: function(text) { + if (text[0].length === 2 || text[1]) { + return "/"; + } else { + return ""; + } + }, + filters: expiryFilters + }); + bindVal(this.$cvcInput, this.$cvcDisplay, { + filters: this.validToggler('cardCVC') + }); + QJ.on(this.$cvcInput, 'focus', this.handle('flipCard')); + QJ.on(this.$cvcInput, 'blur', this.handle('unflipCard')); + return bindVal(this.$nameInput, this.$nameDisplay, { + fill: false, + filters: this.validToggler('cardHolderName'), + join: ' ' + }); + }; + + Card.prototype.handleInitialPlaceholders = function() { + var el, name, selector, _ref, _results; + _ref = this.options.formSelectors; + _results = []; + for (name in _ref) { + selector = _ref[name]; + el = this["$" + name]; + if (QJ.val(el)) { + QJ.trigger(el, 'paste'); + _results.push(setTimeout(function() { + return QJ.trigger(el, 'keyup'); + })); + } else { + _results.push(void 0); + } + } + return _results; + }; + + Card.prototype.handle = function(fn) { + return (function(_this) { + return function(e) { + var args; + args = Array.prototype.slice.call(arguments); + args.unshift(e.target); + return _this.handlers[fn].apply(_this, args); + }; + })(this); + }; + + Card.prototype.validToggler = function(validatorName) { + var isValid; + if (validatorName === "cardExpiry") { + isValid = function(val) { + var objVal; + objVal = Payment.fns.cardExpiryVal(val); + return Payment.fns.validateCardExpiry(objVal.month, objVal.year); + }; + } else if (validatorName === "cardCVC") { + isValid = (function(_this) { + return function(val) { + return Payment.fns.validateCardCVC(val, _this.cardType); + }; + })(this); + } else if (validatorName === "cardNumber") { + isValid = function(val) { + return Payment.fns.validateCardNumber(val); + }; + } else if (validatorName === "cardHolderName") { + isValid = function(val) { + return val !== ""; + }; + } + return (function(_this) { + return function(val, $in, $out) { + var result; + result = isValid(val); + _this.toggleValidClass($in, result); + _this.toggleValidClass($out, result); + return val; + }; + })(this); + }; + + Card.prototype.toggleValidClass = function(el, test) { + QJ.toggleClass(el, this.options.classes.valid, test); + return QJ.toggleClass(el, this.options.classes.invalid, !test); + }; + + Card.prototype.maskCardNumber = function(val, el, out) { + var mask, numbers; + mask = this.options.masks.cardNumber; + numbers = val.split(' '); + if (numbers.length >= 3) { + numbers.forEach(function(item, idx) { + if (idx !== numbers.length - 1) { + return numbers[idx] = numbers[idx].replace(/\d/g, mask); + } + }); + return numbers.join(' '); + } else { + return val.replace(/\d/g, mask); + } + }; + + Card.prototype.handlers = { + setCardType: function($el, e) { + var cardType; + cardType = e.data; + if (!QJ.hasClass(this.$card, cardType)) { + QJ.removeClass(this.$card, 'jp-card-unknown'); + QJ.removeClass(this.$card, this.cardTypes.join(' ')); + QJ.addClass(this.$card, "jp-card-" + cardType); + QJ.toggleClass(this.$card, 'jp-card-identified', cardType !== 'unknown'); + return this.cardType = cardType; + } + }, + flipCard: function() { + return QJ.addClass(this.$card, 'jp-card-flipped'); + }, + unflipCard: function() { + return QJ.removeClass(this.$card, 'jp-card-flipped'); + } + }; + + bindVal = function(el, out, opts) { + var joiner, o, outDefaults; + if (opts == null) { + opts = {}; + } + opts.fill = opts.fill || false; + opts.filters = opts.filters || []; + if (!(opts.filters instanceof Array)) { + opts.filters = [opts.filters]; + } + opts.join = opts.join || ""; + if (!(typeof opts.join === "function")) { + joiner = opts.join; + opts.join = function() { + return joiner; + }; + } + outDefaults = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = out.length; _i < _len; _i++) { + o = out[_i]; + _results.push(o.textContent); + } + return _results; + })(); + QJ.on(el, 'focus', function() { + return QJ.addClass(out, 'jp-card-focused'); + }); + QJ.on(el, 'blur', function() { + return QJ.removeClass(out, 'jp-card-focused'); + }); + QJ.on(el, 'keyup change paste', function(e) { + var elem, filter, i, join, outEl, outVal, val, _i, _j, _len, _len1, _ref, _results; + val = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = el.length; _i < _len; _i++) { + elem = el[_i]; + _results.push(QJ.val(elem)); + } + return _results; + })(); + join = opts.join(val); + val = val.join(join); + if (val === join) { + val = ""; + } + _ref = opts.filters; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + filter = _ref[_i]; + val = filter(val, el, out); + } + _results = []; + for (i = _j = 0, _len1 = out.length; _j < _len1; i = ++_j) { + outEl = out[i]; + if (opts.fill) { + outVal = val + outDefaults[i].substring(val.length); + } else { + outVal = val || outDefaults[i]; + } + _results.push(outEl.textContent = outVal); + } + return _results; + }); + return el; + }; + + return Card; + + })(); + + module.exports = Card; + + global.Card = Card; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }, +/* 1 */ +/***/ function(module, exports, __webpack_require__) { + + // style-loader: Adds some css to the DOM by adding a