diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/amd/build/config.min.js b/amd/build/config.min.js new file mode 100755 index 0000000000..690de45399 --- /dev/null +++ b/amd/build/config.min.js @@ -0,0 +1,2 @@ +define ("enrol_pagseguro/config",[],function(){window.requirejs.config({paths:{jqmask:M.cfg.wwwroot+"/enrol/pagseguro/vendor/jquery-mask/dist/jquery.mask.min"},shim:{jqmask:{exports:"jqmask"}}})}); +//# sourceMappingURL=config.min.js.map diff --git a/amd/build/config.min.js.map b/amd/build/config.min.js.map new file mode 100755 index 0000000000..48bf7085d5 --- /dev/null +++ b/amd/build/config.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/config.js"],"names":["define","window","requirejs","config","paths","M","cfg","wwwroot","shim","exports"],"mappings":"AAAAA,OAAM,0BAAC,EAAD,CAAK,UAAY,CACnBC,MAAM,CAACC,SAAP,CAAiBC,MAAjB,CAAwB,CACpBC,KAAK,CAAE,CAEH,OAAUC,CAAC,CAACC,GAAF,CAAMC,OAAN,CAAgB,0DAFvB,CADa,CAKpBC,IAAI,CAAE,CAEF,OAAU,CAAEC,OAAO,CAAE,QAAX,CAFR,CALc,CAAxB,CAUH,CAXK,CAAN","sourcesContent":["define([], function () {\n window.requirejs.config({\n paths: {\n // Enter the paths to your required java-script files.\n \"jqmask\": M.cfg.wwwroot + \"/enrol/pagseguro/vendor/jquery-mask/dist/jquery.mask.min\"\n },\n shim: {\n // Enter the \"names\" that will be used to refer to your libraries.\n \"jqmask\": { exports: \"jqmask\"}\n }\n });\n});\n"],"file":"config.min.js"} \ No newline at end of file diff --git a/amd/build/jqmask.min.js b/amd/build/jqmask.min.js new file mode 100755 index 0000000000..de480f6c91 --- /dev/null +++ b/amd/build/jqmask.min.js @@ -0,0 +1,2 @@ +define ("enrol_pagseguro/jqmask",["enrol_pagseguro/config","jqmask"],function(a,b){return b}); +//# sourceMappingURL=jqmask.min.js.map diff --git a/amd/build/jqmask.min.js.map b/amd/build/jqmask.min.js.map new file mode 100755 index 0000000000..dbed02c52b --- /dev/null +++ b/amd/build/jqmask.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/jqmask.js"],"names":["define","unused","jqmask"],"mappings":"AAAAA,OAAM,0BAAC,CAAC,wBAAD,CAA2B,QAA3B,CAAD,CAAuC,SAASC,CAAT,CAAgBC,CAAhB,CAAwB,CACjE,MAAOA,CAAAA,CACV,CAFK,CAAN","sourcesContent":["define(['enrol_pagseguro/config', 'jqmask'], function(unused,jqmask) {\n return jqmask;\n});\n"],"file":"jqmask.min.js"} \ No newline at end of file diff --git a/amd/build/jquery.mask.min.js b/amd/build/jquery.mask.min.js new file mode 100644 index 0000000000..d6ec683f59 --- /dev/null +++ b/amd/build/jquery.mask.min.js @@ -0,0 +1,2 @@ +function _typeof(a){"@babel/helpers - typeof";if("function"==typeof Symbol&&"symbol"==typeof Symbol.iterator){_typeof=function(a){return typeof a}}else{_typeof=function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a}}return _typeof(a)}(function(a,b,c){if("function"==typeof define&&define.amd){define ("enrol_pagseguro/jquery.mask",["jquery"],a)}else if("object"===("undefined"==typeof exports?"undefined":_typeof(exports))&&"undefined"==typeof Meteor){module.exports=a(require("jquery"))}else{a(b||c)}})(function(a){'use strict';var b=function(b,c,d){var f={invalid:[],getCaret:function getCaret(){try{var a,c=0,d=b.get(0),e=document.selection,g=d.selectionStart;if(e&&-1===navigator.appVersion.indexOf("MSIE 10")){a=e.createRange();a.moveStart("character",-f.val().length);c=a.text.length}else if(g||"0"===g){c=g}return c}catch(a){}},setCaret:function setCaret(a){try{if(b.is(":focus")){var c,d=b.get(0);if(d.setSelectionRange){d.setSelectionRange(a,a)}else{c=d.createTextRange();c.collapse(!0);c.moveEnd("character",a);c.moveStart("character",a);c.select()}}}catch(a){}},events:function events(){b.on("keydown.mask",function(a){b.data("mask-keycode",a.keyCode||a.which);b.data("mask-previus-value",b.val());b.data("mask-previus-caret-pos",f.getCaret());f.maskDigitPosMapOld=f.maskDigitPosMap}).on(a.jMaskGlobals.useInput?"input.mask":"keyup.mask",f.behaviour).on("paste.mask drop.mask",function(){setTimeout(function(){b.keydown().keyup()},100)}).on("change.mask",function(){b.data("changed",!0)}).on("blur.mask",function(){if(h!==f.val()&&!b.data("changed")){b.trigger("change")}b.data("changed",!1)}).on("blur.mask",function(){h=f.val()}).on("focus.mask",function(b){if(!0===d.selectOnFocus){a(b.target).select()}}).on("focusout.mask",function(){if(d.clearIfNotMatch&&!j.test(f.val())){f.val("")}})},getRegexMask:function getRegexMask(){for(var a=[],b,d,e,f,h,j,k=0;kh){d=10*g}else if(e>=d&&e!==h){if(!f.maskDigitPosMapOld[d]){var o=d;d-=m-l;d-=j;if(f.maskDigitPosMap[d]){d=o}}}else if(d>e){d+=l-m;d+=k}}return d},behaviour:function behaviour(c){c=c||window.event;f.invalid=[];var d=b.data("mask-keycode");if(-1===a.inArray(d,g.byPassKeys)){var h=f.getMasked(),i=f.getCaret(),j=b.data("mask-previus-value")||"";setTimeout(function(){f.setCaret(f.calculateCaretPosition(j))},a.jMaskGlobals.keyStrokeCompensation);f.val(h);f.setCaret(i);return f.callbacks(c)}},getMasked:function getMasked(a,b){var e=[],h=b===void 0?f.val():b+"",i=0,j=c.length,k=0,l=h.length,n=1,o="push",p=-1,q=0,r=[],s,t;if(d.reverse){o="unshift";n=-1;s=0;i=j-1;k=l-1;t=function(){return-1 0) {\n if (el[method]() !== v) {\n el[method](v);\n }\n r = el;\n } else {\n r = el[method]();\n }\n\n return r;\n },\n calculateCaretPosition: function(oldVal) {\n var newVal = p.getMasked(),\n caretPosNew = p.getCaret();\n if (oldVal !== newVal) {\n var caretPosOld = el.data('mask-previus-caret-pos') || 0,\n newValL = newVal.length,\n oldValL = oldVal.length,\n maskDigitsBeforeCaret = 0,\n maskDigitsAfterCaret = 0,\n maskDigitsBeforeCaretAll = 0,\n maskDigitsBeforeCaretAllOld = 0,\n i = 0;\n\n for (i = caretPosNew; i < newValL; i++) {\n if (!p.maskDigitPosMap[i]) {\n break;\n }\n maskDigitsAfterCaret++;\n }\n\n for (i = caretPosNew - 1; i >= 0; i--) {\n if (!p.maskDigitPosMap[i]) {\n break;\n }\n maskDigitsBeforeCaret++;\n }\n\n for (i = caretPosNew - 1; i >= 0; i--) {\n if (p.maskDigitPosMap[i]) {\n maskDigitsBeforeCaretAll++;\n }\n }\n\n for (i = caretPosOld - 1; i >= 0; i--) {\n if (p.maskDigitPosMapOld[i]) {\n maskDigitsBeforeCaretAllOld++;\n }\n }\n\n // if the cursor is at the end keep it there\n if (caretPosNew > oldValL) {\n caretPosNew = newValL * 10;\n } else if (caretPosOld >= caretPosNew && caretPosOld !== oldValL) {\n if (!p.maskDigitPosMapOld[caretPosNew]) {\n var caretPos = caretPosNew;\n caretPosNew -= maskDigitsBeforeCaretAllOld - maskDigitsBeforeCaretAll;\n caretPosNew -= maskDigitsBeforeCaret;\n if (p.maskDigitPosMap[caretPosNew]) {\n caretPosNew = caretPos;\n }\n }\n }\n else if (caretPosNew > caretPosOld) {\n caretPosNew += maskDigitsBeforeCaretAll - maskDigitsBeforeCaretAllOld;\n caretPosNew += maskDigitsAfterCaret;\n }\n }\n return caretPosNew;\n },\n behaviour: function(e) {\n e = e || window.event;\n p.invalid = [];\n\n var keyCode = el.data('mask-keycode');\n\n if ($.inArray(keyCode, jMask.byPassKeys) === -1) {\n var newVal = p.getMasked(),\n caretPos = p.getCaret(),\n oldVal = el.data('mask-previus-value') || '';\n\n // this is a compensation to devices/browsers that don't compensate\n // caret positioning the right way\n setTimeout(function() {\n p.setCaret(p.calculateCaretPosition(oldVal));\n }, $.jMaskGlobals.keyStrokeCompensation);\n\n p.val(newVal);\n p.setCaret(caretPos);\n return p.callbacks(e);\n }\n },\n getMasked: function(skipMaskChars, val) {\n var buf = [],\n value = val === undefined ? p.val() : val + '',\n m = 0, maskLen = mask.length,\n v = 0, valLen = value.length,\n offset = 1, addMethod = 'push',\n resetPos = -1,\n maskDigitCount = 0,\n maskDigitPosArr = [],\n lastMaskChar,\n check;\n\n if (options.reverse) {\n addMethod = 'unshift';\n offset = -1;\n lastMaskChar = 0;\n m = maskLen - 1;\n v = valLen - 1;\n check = function () {\n return m > -1 && v > -1;\n };\n } else {\n lastMaskChar = maskLen - 1;\n check = function () {\n return m < maskLen && v < valLen;\n };\n }\n\n var lastUntranslatedMaskChar;\n while (check()) {\n var maskDigit = mask.charAt(m),\n valDigit = value.charAt(v),\n translation = jMask.translation[maskDigit];\n\n if (translation) {\n if (valDigit.match(translation.pattern)) {\n buf[addMethod](valDigit);\n if (translation.recursive) {\n if (resetPos === -1) {\n resetPos = m;\n } else if (m === lastMaskChar && m !== resetPos) {\n m = resetPos - offset;\n }\n\n if (lastMaskChar === resetPos) {\n m -= offset;\n }\n }\n m += offset;\n } else if (valDigit === lastUntranslatedMaskChar) {\n // matched the last untranslated (raw) mask character that we encountered\n // likely an insert offset the mask character from the last entry; fall\n // through and only increment v\n maskDigitCount--;\n lastUntranslatedMaskChar = undefined;\n } else if (translation.optional) {\n m += offset;\n v -= offset;\n } else if (translation.fallback) {\n buf[addMethod](translation.fallback);\n m += offset;\n v -= offset;\n } else {\n p.invalid.push({p: v, v: valDigit, e: translation.pattern});\n }\n v += offset;\n } else {\n if (!skipMaskChars) {\n buf[addMethod](maskDigit);\n }\n\n if (valDigit === maskDigit) {\n maskDigitPosArr.push(v);\n v += offset;\n } else {\n lastUntranslatedMaskChar = maskDigit;\n maskDigitPosArr.push(v + maskDigitCount);\n maskDigitCount++;\n }\n\n m += offset;\n }\n }\n\n var lastMaskCharDigit = mask.charAt(lastMaskChar);\n if (maskLen === valLen + 1 && !jMask.translation[lastMaskCharDigit]) {\n buf.push(lastMaskCharDigit);\n }\n\n var newVal = buf.join('');\n p.mapMaskdigitPositions(newVal, maskDigitPosArr, valLen);\n return newVal;\n },\n mapMaskdigitPositions: function(newVal, maskDigitPosArr, valLen) {\n var maskDiff = options.reverse ? newVal.length - valLen : 0;\n p.maskDigitPosMap = {};\n for (var i = 0; i < maskDigitPosArr.length; i++) {\n p.maskDigitPosMap[maskDigitPosArr[i] + maskDiff] = 1;\n }\n },\n callbacks: function (e) {\n var val = p.val(),\n changed = val !== oldValue,\n defaultArgs = [val, e, el, options],\n callback = function(name, criteria, args) {\n if (typeof options[name] === 'function' && criteria) {\n options[name].apply(this, args);\n }\n };\n\n callback('onChange', changed === true, defaultArgs);\n callback('onKeyPress', changed === true, defaultArgs);\n callback('onComplete', val.length === mask.length, defaultArgs);\n callback('onInvalid', p.invalid.length > 0, [val, e, el, p.invalid, options]);\n }\n };\n\n el = $(el);\n var jMask = this, oldValue = p.val(), regexMask;\n\n mask = typeof mask === 'function' ? mask(p.val(), undefined, el, options) : mask;\n\n // public methods\n jMask.mask = mask;\n jMask.options = options;\n jMask.remove = function() {\n var caret = p.getCaret();\n if (jMask.options.placeholder) {\n el.removeAttr('placeholder');\n }\n if (el.data('mask-maxlength')) {\n el.removeAttr('maxlength');\n }\n p.destroyEvents();\n p.val(jMask.getCleanVal());\n p.setCaret(caret);\n return el;\n };\n\n // get value without mask\n jMask.getCleanVal = function() {\n return p.getMasked(true);\n };\n\n // get masked value without the value being in the input or element\n jMask.getMaskedVal = function(val) {\n return p.getMasked(false, val);\n };\n\n jMask.init = function(onlyMask) {\n onlyMask = onlyMask || false;\n options = options || {};\n\n jMask.clearIfNotMatch = $.jMaskGlobals.clearIfNotMatch;\n jMask.byPassKeys = $.jMaskGlobals.byPassKeys;\n jMask.translation = $.extend({}, $.jMaskGlobals.translation, options.translation);\n\n jMask = $.extend(true, {}, jMask, options);\n\n regexMask = p.getRegexMask();\n\n if (onlyMask) {\n p.events();\n p.val(p.getMasked());\n } else {\n if (options.placeholder) {\n el.attr('placeholder' , options.placeholder);\n }\n\n // this is necessary, otherwise if the user submit the form\n // and then press the \"back\" button, the autocomplete will erase\n // the data. Works fine on IE9+, FF, Opera, Safari.\n if (el.data('mask')) {\n el.attr('autocomplete', 'off');\n }\n\n // detect if is necessary let the user type freely.\n // for is a lot faster than forEach.\n for (var i = 0, maxlength = true; i < mask.length; i++) {\n var translation = jMask.translation[mask.charAt(i)];\n if (translation && translation.recursive) {\n maxlength = false;\n break;\n }\n }\n\n if (maxlength) {\n el.attr('maxlength', mask.length).data('mask-maxlength', true);\n }\n\n p.destroyEvents();\n p.events();\n\n var caret = p.getCaret();\n p.val(p.getMasked());\n p.setCaret(caret);\n }\n };\n\n jMask.init(!el.is('input'));\n };\n\n $.maskWatchers = {};\n var HTMLAttributes = function () {\n var input = $(this),\n options = {},\n prefix = 'data-mask-',\n mask = input.attr('data-mask');\n\n if (input.attr(prefix + 'reverse')) {\n options.reverse = true;\n }\n\n if (input.attr(prefix + 'clearifnotmatch')) {\n options.clearIfNotMatch = true;\n }\n\n if (input.attr(prefix + 'selectonfocus') === 'true') {\n options.selectOnFocus = true;\n }\n\n if (notSameMaskObject(input, mask, options)) {\n return input.data('mask', new Mask(this, mask, options));\n }\n },\n notSameMaskObject = function(field, mask, options) {\n options = options || {};\n var maskObject = $(field).data('mask'),\n stringify = JSON.stringify,\n value = $(field).val() || $(field).text();\n try {\n if (typeof mask === 'function') {\n mask = mask(value);\n }\n return typeof maskObject !== 'object' || stringify(maskObject.options) !== stringify(options) || maskObject.mask !== mask;\n } catch (e) {}\n },\n eventSupported = function(eventName) {\n var el = document.createElement('div'), isSupported;\n\n eventName = 'on' + eventName;\n isSupported = (eventName in el);\n\n if ( !isSupported ) {\n el.setAttribute(eventName, 'return;');\n isSupported = typeof el[eventName] === 'function';\n }\n el = null;\n\n return isSupported;\n };\n\n $.fn.mask = function(mask, options) {\n options = options || {};\n var selector = this.selector,\n globals = $.jMaskGlobals,\n interval = globals.watchInterval,\n watchInputs = options.watchInputs || globals.watchInputs,\n maskFunction = function() {\n if (notSameMaskObject(this, mask, options)) {\n return $(this).data('mask', new Mask(this, mask, options));\n }\n };\n\n $(this).each(maskFunction);\n\n if (selector && selector !== '' && watchInputs) {\n clearInterval($.maskWatchers[selector]);\n $.maskWatchers[selector] = setInterval(function(){\n $(document).find(selector).each(maskFunction);\n }, interval);\n }\n return this;\n };\n\n $.fn.masked = function(val) {\n return this.data('mask').getMaskedVal(val);\n };\n\n $.fn.unmask = function() {\n clearInterval($.maskWatchers[this.selector]);\n delete $.maskWatchers[this.selector];\n return this.each(function() {\n var dataMask = $(this).data('mask');\n if (dataMask) {\n dataMask.remove().removeData('mask');\n }\n });\n };\n\n $.fn.cleanVal = function() {\n return this.data('mask').getCleanVal();\n };\n\n $.applyDataMask = function(selector) {\n selector = selector || $.jMaskGlobals.maskElements;\n var $selector = (selector instanceof $) ? selector : $(selector);\n $selector.filter($.jMaskGlobals.dataMaskAttr).each(HTMLAttributes);\n };\n\n var globals = {\n maskElements: 'input,td,span,div',\n dataMaskAttr: '[data-mask]',\n dataMask: true,\n watchInterval: 300,\n watchInputs: true,\n keyStrokeCompensation: 10,\n // old versions of chrome dont work great with input event\n useInput: !/Chrome\\/[2-4][0-9]|SamsungBrowser/.test(window.navigator.userAgent) && eventSupported('input'),\n watchDataMask: false,\n byPassKeys: [9, 16, 17, 18, 36, 37, 38, 39, 40, 91],\n translation: {\n '0': {pattern: /\\d/},\n '9': {pattern: /\\d/, optional: true},\n '#': {pattern: /\\d/, recursive: true},\n 'A': {pattern: /[a-zA-Z0-9]/},\n 'S': {pattern: /[a-zA-Z]/}\n }\n };\n\n $.jMaskGlobals = $.jMaskGlobals || {};\n globals = $.jMaskGlobals = $.extend(true, {}, globals, $.jMaskGlobals);\n\n // looking for inputs with data-mask attribute\n if (globals.dataMask) {\n $.applyDataMask();\n }\n\n setInterval(function() {\n if ($.jMaskGlobals.watchDataMask) {\n $.applyDataMask();\n }\n }, globals.watchInterval);\n}, window.jQuery, window.Zepto));\n"],"file":"jquery.mask.min.js"} \ No newline at end of file diff --git a/amd/build/transparent-checkout.min.js b/amd/build/transparent-checkout.min.js new file mode 100755 index 0000000000..24782f3b4c --- /dev/null +++ b/amd/build/transparent-checkout.min.js @@ -0,0 +1,2 @@ +var brandName="",ghash="";require(["jquery"],function(a){a(document).on("submit","#pagseguro_boleto_form",function(b){if(boletoValidateFields()){a("#pagseguro_boleto_form input[name=sender_hash]").val(ghash);var c=new URLSearchParams(window.location.search);a("#boleto_courseid").val(c.get("id"))}else{b.preventDefault()}});a(document).on("click","#cc_submit",function(){if(ccValidateFields()){var b=a("input[name=ccnumber]").val().replace(/\s/g,""),c=a("input[name=cvv]").val(),d=a("input[name=ccvalid]").val().split("/");PagSeguroDirectPayment.createCardToken({cardNumber:b,brand:brandName,cvv:c,expirationMonth:d[0],expirationYear:d[1],success:function success(b){a("#cc_token").val(b.card.token);var c=new URLSearchParams(window.location.search);a("#cc_courseid").val(c.get("id"));a("#cc_instval").val(a("#installments").find(":selected").data("installment-value"));a("#pagseguro_cc_form").submit()},error:function error(){},complete:function complete(){}})}});a(document).on("focusout","#billingpostcode",function(){var b=a("#billingpostcode").val().replace(/\D/g,"");if(""!=b){if(/^[0-9]{8}$/.test(b)){a("#billingstreet").val("...");a("#billingdistrict").val("...");a("#billingcity").val("...");a("#billingstate").val("...");a("#ibge").val("...");a.getJSON("https://viacep.com.br/ws/"+b+"/json/?callback=?",function(b){if(!("erro"in b)){a("#billingstreet").val(b.logradouro);a("#billingdistrict").val(b.bairro);a("#billingcity").val(b.localidade);a("#billingstate").val(b.uf);a("#ibge").val(b.ibge)}else{limpa_formulário_cep();alert("CEP n\xE3o encontrado.")}})}else{limpa_formulário_cep();alert("Formato de CEP inv\xE1lido.")}}else{limpa_formulário_cep()}})});function loadDoc(a,b){require(["core/ajax"],function(c){var d=c.call([{methodname:"enrol_pagseguro_get_session",args:{courseP:b}}]);d[0].done(function(b){setPagueSeguroWSSessionId(b.stoken,a,b.courseP)}).fail(function(){})})}function setPagueSeguroWSSessionId(a,b,c){PagSeguroDirectPayment.setSessionId(a);PagSeguroDirectPayment.getPaymentMethods({success:function success(){require(["jquery","core/ajax","core/templates","core/notification"],function(d,e,f,g){var h=e.call([{methodname:"enrol_pagseguro_get_forms",args:{sessionId:a,courseId:b,courseP:c}}]);h[0].done(function(a){f.render("enrol_pagseguro/checkout_form",JSON.parse(a)).done(function(a,b){d("#modal-return").html(a);f.runTemplateJS(b);PagSeguroDirectPayment.onSenderHashReady(function(a){if("error"==a.status){return!1}var b=a.senderHash;ghash=b;createMasks()})}).fail(g.exception)}).fail(function(){})})},error:function error(a){document.getElementById("return").innerHTML=JSON.stringify(a)},complete:function complete(){}})}function createMasks(){require(["jquery","enrol_pagseguro/jqmask"],function(a){a(".input-phone").mask("(00) 0000-0000",{onKeyPress:function onKeyPress(b,c,d,e){var f=["(00) 0000-00009","(00) 0 0000-0000"],g=14");installments(brandName,b)})},error:function error(){},complete:function complete(){}})}}function installments(a,b){var c=Number.parseFloat(b).toFixed(2);PagSeguroDirectPayment.getInstallments({amount:c,brand:a,success:function success(b){require(["jquery"],function(c){if(!b.error){var d=""}c("#card-installments").html(""+d+"")})},error:function error(){},complete:function complete(){}})}function ccValidateFields(){var a=!0;require(["jquery"],function(b){if(!b("#ccEmail").val().trim()){a=!1;b("#ccEmail-error").html("Favor preencher email corretamente")}else{b("#ccEmail-error").html("")}if(!b("#ccPhone").val().trim()){a=!1;b("#ccPhone-error").html("Favor preencher telefone corretamente")}else{b("#ccPhone-error").html("")}if(!b("#ccCPFCNPJ").val().trim()){a=!1;b("#ccCPFCNPJ-error").html("Favor preencher CPF/CNPJ corretamente")}else{b("#ccCPFCNPJ-error").html("")}if(!b("#ccName").val().trim()){a=!1;b("#ccName-error").html("Favor preencher Nome corretamente")}else{b("#ccName-error").html("")}if(!b("#ccNumber").val().trim()){a=!1;b("#ccNumber-error").html("Favor preencher N\xFAmero do cart\xE3o corretamente")}else{b("#ccNumber-error").html("")}if(!b("#ccvalid").val().trim()){a=!1;b("#ccvalid-error").html("Favor preencher Validade do cart\xE3o corretamente")}else{b("#ccvalid-error").html("")}if(!b("#cvv").val().trim()){a=!1;b("#cvv-error").html("Favor preencher CVV corretamente")}else{b("#cvv-error").html("")}if(!b("#billingpostcode").val().trim()){a=!1;b("#billingpostcode-error").html("Favor preencher cep corretamente")}else{b("#billingpostcode-error").html("")}if(!b("#billingstreet").val().trim()){a=!1;b("#billingstreet-error").html("Favor preencher campo corretamente")}else{b("#billingstreet-error").html("")}if(!b("#billingstate").val().trim()){a=!1;b("#billingstate-error").html("Favor preencher estado corretamente")}else{b("#billingstate-error").html("")}if(!b("#billingdistrict").val().trim()){a=!1;b("#billingdistrict-error").html("Favor preencher bairro corretamente")}else{b("#billingdistrict-error").html("")}if(!b("#billingcity").val().trim()){a=!1;b("#billingcity-error").html("Favor preencher cidade corretamente")}else{b("#billingcity-error").html("")}});return a}function boletoValidateFields(){var a=!0;require(["jquery"],function(b){if(!b("#boleto_nome").val().trim()){a=!1;b("#boleto_nome-error").html("Favor preencher o nome corretamente")}else{b("#boleto_nome-error").html("")}if(!b("#boleto_email").val().trim()){a=!1;b("#boleto_email-error").html("Favor preencher email corretamente")}else{b("#boleto_email-error").html("")}if(!b("#boleto_phone").val().trim()){a=!1;b("#boleto_phone-error").html("Favor preencher telefone corretamente")}else{b("#boleto_phone-error").html("")}if(!b("#boleto_doc").val().trim()){a=!1;b("#boleto_doc-error").html("Favor preencher CPF/CNPJ corretamente")}else{b("#boleto_doc-error").html("")}});return a} +//# sourceMappingURL=transparent-checkout.min.js.map diff --git a/amd/build/transparent-checkout.min.js.map b/amd/build/transparent-checkout.min.js.map new file mode 100755 index 0000000000..7aa97c12a9 --- /dev/null +++ b/amd/build/transparent-checkout.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/transparent-checkout.js"],"names":["brandName","ghash","require","$","document","on","e","boletoValidateFields","val","urlParams","URLSearchParams","window","location","search","get","preventDefault","ccValidateFields","ccNum","replace","ccCvv","ccExp","split","PagSeguroDirectPayment","createCardToken","cardNumber","brand","cvv","expirationMonth","expirationYear","success","response","card","token","find","data","submit","error","complete","cep","test","getJSON","dados","logradouro","bairro","localidade","uf","ibge","limpa_formulário_cep","alert","loadDoc","courseid","p","ajax","promises","call","methodname","args","done","setPagueSeguroWSSessionId","stoken","courseP","fail","sessionId","courseId","setSessionId","getPaymentMethods","templates","notification","render","JSON","parse","html","js","runTemplateJS","onSenderHashReady","status","hash","senderHash","createMasks","exception","getElementById","innerHTML","stringify","mask","onKeyPress","ph","field","ph_options","masks","length","doc","options","checkBrand","el","cp","cardnum","value","getBrand","cardBin","substring","name","installments","n","Number","parseFloat","toFixed","getInstallments","amount","sel_installments","forEach","inst","rtn","trim"],"mappings":"GAyBIA,CAAAA,SAAS,CAAG,E,CACZC,KAAK,CAAG,E,CAEZC,OAAO,CAAC,CAAC,QAAD,CAAD,CAAa,SAASC,CAAT,CAAW,CAC3BA,CAAC,CAACC,QAAD,CAAD,CAAYC,EAAZ,CAAe,QAAf,CAAyB,wBAAzB,CAAmD,SAASC,CAAT,CAAY,CAC3D,GAAGC,oBAAoB,EAAvB,CAA0B,CACtBJ,CAAC,CAAC,gDAAD,CAAD,CAAoDK,GAApD,CAAwDP,KAAxD,EACA,GAAIQ,CAAAA,CAAS,CAAG,GAAIC,CAAAA,eAAJ,CAAoBC,MAAM,CAACC,QAAP,CAAgBC,MAApC,CAAhB,CACAV,CAAC,CAAC,kBAAD,CAAD,CAAsBK,GAAtB,CAA0BC,CAAS,CAACK,GAAV,CAAc,IAAd,CAA1B,CACH,CAJD,IAIO,CACHR,CAAC,CAACS,cAAF,EACH,CACJ,CARD,EASAZ,CAAC,CAACC,QAAD,CAAD,CAAYC,EAAZ,CAAe,OAAf,CAAwB,YAAxB,CAAsC,UAAW,CAC7C,GAAGW,gBAAgB,EAAnB,CAAsB,IACdC,CAAAA,CAAK,CAAGd,CAAC,CAAC,sBAAD,CAAD,CAA0BK,GAA1B,GAAgCU,OAAhC,CAAwC,KAAxC,CAA+C,EAA/C,CADM,CAEdC,CAAK,CAAGhB,CAAC,CAAC,iBAAD,CAAD,CAAqBK,GAArB,EAFM,CAGdY,CAAK,CAAGjB,CAAC,CAAC,qBAAD,CAAD,CAAyBK,GAAzB,GAA+Ba,KAA/B,CAAqC,GAArC,CAHM,CAIlBC,sBAAsB,CAACC,eAAvB,CAAuC,CACnCC,UAAU,CAAEP,CADuB,CAEnCQ,KAAK,CAAEzB,SAF4B,CAGnC0B,GAAG,CAAEP,CAH8B,CAInCQ,eAAe,CAAEP,CAAK,CAAC,CAAD,CAJa,CAKnCQ,cAAc,CAAER,CAAK,CAAC,CAAD,CALc,CAMnCS,OAAO,CAAE,iBAASC,CAAT,CAAmB,CACxB3B,CAAC,CAAC,WAAD,CAAD,CAAeK,GAAf,CAAmBsB,CAAQ,CAACC,IAAT,CAAcC,KAAjC,EACA,GAAIvB,CAAAA,CAAS,CAAG,GAAIC,CAAAA,eAAJ,CAAoBC,MAAM,CAACC,QAAP,CAAgBC,MAApC,CAAhB,CACAV,CAAC,CAAC,cAAD,CAAD,CAAkBK,GAAlB,CAAsBC,CAAS,CAACK,GAAV,CAAc,IAAd,CAAtB,EACAX,CAAC,CAAC,aAAD,CAAD,CAAiBK,GAAjB,CAAqBL,CAAC,CAAC,eAAD,CAAD,CAAmB8B,IAAnB,CAAwB,WAAxB,EAAqCC,IAArC,CAA0C,mBAA1C,CAArB,EACA/B,CAAC,CAAC,oBAAD,CAAD,CAAwBgC,MAAxB,EACH,CAZkC,CAanCC,KAAK,CAAE,gBAAW,CAEjB,CAfkC,CAgBnCC,QAAQ,CAAE,mBAAW,CAEpB,CAlBkC,CAAvC,CAoBH,CACJ,CA1BD,EA4BAlC,CAAC,CAACC,QAAD,CAAD,CAAYC,EAAZ,CAAe,UAAf,CAA2B,kBAA3B,CAA+C,UAAW,CACtD,GAAIiC,CAAAA,CAAG,CAAGnC,CAAC,CAAC,kBAAD,CAAD,CAAsBK,GAAtB,GAA4BU,OAA5B,CAAoC,KAApC,CAA2C,EAA3C,CAAV,CAEA,GAAW,EAAP,EAAAoB,CAAJ,CAAe,CAIX,GAFgB,YAEb,CAAUC,IAAV,CAAeD,CAAf,CAAH,CAAwB,CAEpBnC,CAAC,CAAC,gBAAD,CAAD,CAAoBK,GAApB,CAAwB,KAAxB,EACAL,CAAC,CAAC,kBAAD,CAAD,CAAsBK,GAAtB,CAA0B,KAA1B,EACAL,CAAC,CAAC,cAAD,CAAD,CAAkBK,GAAlB,CAAsB,KAAtB,EACAL,CAAC,CAAC,eAAD,CAAD,CAAmBK,GAAnB,CAAuB,KAAvB,EACAL,CAAC,CAAC,OAAD,CAAD,CAAWK,GAAX,CAAe,KAAf,EAEAL,CAAC,CAACqC,OAAF,CAAU,4BAA8BF,CAA9B,CAAoC,mBAA9C,CAAmE,SAASG,CAAT,CAAgB,CAC/E,GAAI,EAAE,QAAUA,CAAAA,CAAZ,CAAJ,CAAwB,CAEpBtC,CAAC,CAAC,gBAAD,CAAD,CAAoBK,GAApB,CAAwBiC,CAAK,CAACC,UAA9B,EACAvC,CAAC,CAAC,kBAAD,CAAD,CAAsBK,GAAtB,CAA0BiC,CAAK,CAACE,MAAhC,EACAxC,CAAC,CAAC,cAAD,CAAD,CAAkBK,GAAlB,CAAsBiC,CAAK,CAACG,UAA5B,EACAzC,CAAC,CAAC,eAAD,CAAD,CAAmBK,GAAnB,CAAuBiC,CAAK,CAACI,EAA7B,EACA1C,CAAC,CAAC,OAAD,CAAD,CAAWK,GAAX,CAAeiC,CAAK,CAACK,IAArB,CACH,CAPD,IAOO,CAEHC,oBAAoB,GACpBC,KAAK,CAAC,wBAAD,CACR,CACJ,CAbD,CAcH,CAtBD,IAsBO,CACHD,oBAAoB,GACpBC,KAAK,CAAC,6BAAD,CACR,CACJ,CA9BD,IA8BO,CAEHD,oBAAoB,EACvB,CACJ,CArCD,CAsCH,CA5EM,CAAP,CA8EA,QAASE,CAAAA,OAAT,CAAiBC,CAAjB,CAA2BC,CAA3B,CAA6B,CACzBjD,OAAO,CAAC,CAAC,WAAD,CAAD,CAAgB,SAASkD,CAAT,CAAe,CAClC,GAAIC,CAAAA,CAAQ,CAAGD,CAAI,CAACE,IAAL,CAAU,CAAC,CACtBC,UAAU,CAAE,6BADU,CAEtBC,IAAI,CAAC,CAAC,QAAWL,CAAZ,CAFiB,CAAD,CAAV,CAAf,CAIAE,CAAQ,CAAC,CAAD,CAAR,CAAYI,IAAZ,CAAiB,SAAS3B,CAAT,CAAmB,CAChC4B,yBAAyB,CAAC5B,CAAQ,CAAC6B,MAAV,CAAiBT,CAAjB,CAA2BpB,CAAQ,CAAC8B,OAApC,CAC5B,CAFD,EAEGC,IAFH,CAEQ,UAAW,CAElB,CAJD,CAKH,CAVM,CAWV,CAED,QAASH,CAAAA,yBAAT,CAAmCI,CAAnC,CAA6CC,CAA7C,CAAuDH,CAAvD,CAA+D,CAC3DtC,sBAAsB,CAAC0C,YAAvB,CAAoCF,CAApC,EACAxC,sBAAsB,CAAC2C,iBAAvB,CAAyC,CACrCpC,OAAO,CAAE,kBAAW,CAEhB3B,OAAO,CAAC,CAAC,QAAD,CAAW,WAAX,CAAwB,gBAAxB,CAA0C,mBAA1C,CAAD,CACP,SAASC,CAAT,CAAYiD,CAAZ,CAAkBc,CAAlB,CAA6BC,CAA7B,CAA2C,CACvC,GAAId,CAAAA,CAAQ,CAAGD,CAAI,CAACE,IAAL,CAAU,CAAC,CACtBC,UAAU,CAAE,2BADU,CAEtBC,IAAI,CAAC,CAAE,UAAcM,CAAhB,CAA2B,SAAYC,CAAvC,CAAiD,QAAWH,CAA5D,CAFiB,CAAD,CAAV,CAAf,CAIAP,CAAQ,CAAC,CAAD,CAAR,CAAYI,IAAZ,CAAiB,SAAS3B,CAAT,CAAmB,CAChCoC,CAAS,CAACE,MAAV,CAAiB,+BAAjB,CAAkDC,IAAI,CAACC,KAAL,CAAWxC,CAAX,CAAlD,EAAwE2B,IAAxE,CAA6E,SAASc,CAAT,CAAeC,CAAf,CAAmB,CAC5FrE,CAAC,CAAC,eAAD,CAAD,CAAmBoE,IAAnB,CAAwBA,CAAxB,EACAL,CAAS,CAACO,aAAV,CAAwBD,CAAxB,EACAlD,sBAAsB,CAACoD,iBAAvB,CAAyC,SAAS5C,CAAT,CAAkB,CACvD,GAAsB,OAAnB,EAAAA,CAAQ,CAAC6C,MAAZ,CAA+B,CAC3B,QACH,CACD,GAAIC,CAAAA,CAAI,CAAG9C,CAAQ,CAAC+C,UAApB,CACA5E,KAAK,CAAG2E,CAAR,CACAE,WAAW,EACd,CAPD,CAQH,CAXD,EAWGjB,IAXH,CAWQM,CAAY,CAACY,SAXrB,CAaH,CAdD,EAcGlB,IAdH,CAcQ,UAAW,CAElB,CAhBD,CAiBH,CAvBM,CAwBV,CA3BoC,CA4BrCzB,KAAK,CAAE,eAASN,CAAT,CAAmB,CAEtB1B,QAAQ,CAAC4E,cAAT,CAAwB,QAAxB,EAAkCC,SAAlC,CAA8CZ,IAAI,CAACa,SAAL,CAAepD,CAAf,CACjD,CA/BoC,CAgCrCO,QAAQ,CAAE,mBAAW,CAEpB,CAlCoC,CAAzC,CAoCH,CAED,QAASyC,CAAAA,WAAT,EAAsB,CAClB5E,OAAO,CAAC,CAAC,QAAD,CAAW,wBAAX,CAAD,CAAuC,SAASC,CAAT,CAAmB,CAQ7DA,CAAC,CAAC,cAAD,CAAD,CAAkBgF,IAAlB,CAAuB,gBAAvB,CAPiB,CACbC,UAAU,CAAE,oBAASC,CAAT,CAAa/E,CAAb,CAAgBgF,CAAhB,CAAuBC,CAAvB,CAAkC,IACtCC,CAAAA,CAAK,CAAG,CAAC,iBAAD,CAAoB,kBAApB,CAD8B,CAEtCL,CAAI,CAAgB,EAAZ,CAAAE,CAAE,CAACI,MAAJ,CAAmBD,CAAK,CAAC,CAAD,CAAxB,CAA8BA,CAAK,CAAE,CAAF,CAFJ,CAG1CrF,CAAC,CAAC,cAAD,CAAD,CAAkBgF,IAAlB,CAAuBA,CAAvB,CAA6BI,CAA7B,CACH,CALY,CAOjB,EAQApF,CAAC,CAAC,gBAAD,CAAD,CAAoBgF,IAApB,CAAyB,iBAAzB,CAPc,CACVC,UAAU,CAAE,oBAASM,CAAT,CAAcpF,CAAd,CAAiBgF,CAAjB,CAAwBK,CAAxB,CAAgC,IACpCH,CAAAA,CAAK,CAAG,CAAC,iBAAD,CAAoB,oBAApB,CAD4B,CAEpCL,CAAI,CAAiB,EAAb,CAAAO,CAAG,CAACD,MAAL,CAAoBD,CAAK,CAAC,CAAD,CAAzB,CAA+BA,CAAK,CAAE,CAAF,CAFP,CAGxCrF,CAAC,CAAC,gBAAD,CAAD,CAAoBgF,IAApB,CAAyBA,CAAzB,CAA+BQ,CAA/B,CACH,CALS,CAOd,EACAxF,CAAC,CAAC,iBAAD,CAAD,CAAqBgF,IAArB,CAA0B,qBAA1B,EACAhF,CAAC,CAAC,gBAAD,CAAD,CAAoBgF,IAApB,CAAyB,SAAzB,EACAhF,CAAC,CAAC,YAAD,CAAD,CAAgBgF,IAAhB,CAAqB,KAArB,EACAhF,CAAC,CAAC,YAAD,CAAD,CAAgBgF,IAAhB,CAAqB,WAArB,CACH,CArBM,CAsBV,CAED,QAASpC,CAAAA,oBAAT,EAAgC,CAE5B7C,OAAO,CAAC,CAAC,QAAD,CAAD,CAAY,SAASC,CAAT,CAAW,CAC1BA,CAAC,CAAC,gBAAD,CAAD,CAAoBK,GAApB,CAAwB,EAAxB,EACAL,CAAC,CAAC,kBAAD,CAAD,CAAsBK,GAAtB,CAA0B,EAA1B,EACAL,CAAC,CAAC,cAAD,CAAD,CAAkBK,GAAlB,CAAsB,EAAtB,EACAL,CAAC,CAAC,eAAD,CAAD,CAAmBK,GAAnB,CAAuB,EAAvB,EACAL,CAAC,CAAC,OAAD,CAAD,CAAWK,GAAX,CAAe,EAAf,CACH,CANM,CAOV,CAED,QAASoF,CAAAA,UAAT,CAAoBC,CAApB,CAAwBC,CAAxB,CAA2B,CACvB,GAAIC,CAAAA,CAAO,CAAGF,CAAE,CAACG,KAAH,CAAS9E,OAAT,CAAiB,KAAjB,CAAwB,EAAxB,CAAd,CACA,GAAqB,CAAlB,EAAA6E,CAAO,CAACN,MAAX,CAAuB,CACnBnE,sBAAsB,CAAC2E,QAAvB,CAAgC,CAC5BC,OAAO,EAASH,CAAO,CAACI,SAAR,CAAkB,CAAlB,CAAoB,CAApB,CADY,CAE5BtE,OAAO,CAAE,iBAASC,CAAT,CAAmB,CACxB5B,OAAO,CAAC,CAAC,QAAD,CAAD,CAAY,SAASC,CAAT,CAAW,CAC1BH,SAAS,CAAG8B,CAAQ,CAACL,KAAT,CAAe2E,IAA3B,CAEAjG,CAAC,CAAC,YAAD,CAAD,CAAgBoE,IAAhB,CAAqB,sFAAyBzC,CAAQ,CAACL,KAAT,CAAe2E,IAAxC,CAA+C,WAApE,EACAC,YAAY,CAACrG,SAAD,CAAW8F,CAAX,CACf,CALM,CAMV,CAT2B,CAU5B1D,KAAK,CAAE,gBAAW,CAEjB,CAZ2B,CAa5BC,QAAQ,CAAE,mBAAW,CAEpB,CAf2B,CAAhC,CAiBH,CACJ,CAED,QAASgE,CAAAA,YAAT,CAAsBrG,CAAtB,CAAgC8F,CAAhC,CAAmC,CAC/B,GAAIQ,CAAAA,CAAC,CAAGC,MAAM,CAACC,UAAP,CAAkBV,CAAlB,EAAsBW,OAAtB,CAA8B,CAA9B,CAAR,CACAnF,sBAAsB,CAACoF,eAAvB,CAAuC,CACnCC,MAAM,CAAEL,CAD2B,CAEnC7E,KAAK,CAAEzB,CAF4B,CAGnC6B,OAAO,CAAE,iBAASC,CAAT,CAAkB,CAEvB5B,OAAO,CAAC,CAAC,QAAD,CAAD,CAAY,SAASC,CAAT,CAAW,CAC1B,GAAG,CAAC2B,CAAQ,MAAZ,CAAsB,CAClB,GAAI8E,CAAAA,CAAgB,CAAG,sDAAvB,CACA9E,CAAQ,aAAR,CAAyB9B,CAAzB,EAAoC6G,OAApC,CAA4C,SAASC,CAAT,CAAc,CACtDF,CAAgB,EAAI,mBAAoBE,CAAI,SAA5C,CACAF,CAAgB,EAAI,+BAA+BE,CAAI,kBAAJ,CAA0BL,OAA1B,CAAkC,CAAlC,CAA/B,CAAsE,MAA1F,CACAG,CAAgB,EAAIE,CAAI,SAAJ,CAAmB,OAAnB,CAA6BA,CAAI,kBAAJ,CAA0BL,OAA1B,CAAkC,CAAlC,CAAjD,CACAG,CAAgB,EAAI,WACvB,CALD,EAMAA,CAAgB,EAAI,WACvB,CACDzG,CAAC,CAAC,oBAAD,CAAD,CAAwBoE,IAAxB,CAA6B,SAAWqC,CAAX,CAA8B,SAA3D,CACH,CAZM,CAcV,CAnBkC,CAoBnCxE,KAAK,CAAE,gBAAW,CAEjB,CAtBkC,CAuBnCC,QAAQ,CAAE,mBAAU,CAEnB,CAzBkC,CAAvC,CA4BH,CAuDD,QAASrB,CAAAA,gBAAT,EAA2B,CACvB,GAAI+F,CAAAA,CAAG,GAAP,CACA7G,OAAO,CAAC,CAAC,QAAD,CAAD,CAAY,SAASC,CAAT,CAAW,CAC1B,GAAG,CAACA,CAAC,CAAC,UAAD,CAAD,CAAcK,GAAd,GAAoBwG,IAApB,EAAJ,CAA+B,CAC3BD,CAAG,GAAH,CACA5G,CAAC,CAAC,gBAAD,CAAD,CAAoBoE,IAApB,CAAyB,oCAAzB,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,gBAAD,CAAD,CAAoBoE,IAApB,CAAyB,EAAzB,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,UAAD,CAAD,CAAcK,GAAd,GAAoBwG,IAApB,EAAJ,CAA+B,CAC3BD,CAAG,GAAH,CACA5G,CAAC,CAAC,gBAAD,CAAD,CAAoBoE,IAApB,CAAyB,uCAAzB,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,gBAAD,CAAD,CAAoBoE,IAApB,CAAyB,EAAzB,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,YAAD,CAAD,CAAgBK,GAAhB,GAAsBwG,IAAtB,EAAJ,CAAiC,CAC7BD,CAAG,GAAH,CACA5G,CAAC,CAAC,kBAAD,CAAD,CAAsBoE,IAAtB,CAA2B,uCAA3B,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,kBAAD,CAAD,CAAsBoE,IAAtB,CAA2B,EAA3B,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,SAAD,CAAD,CAAaK,GAAb,GAAmBwG,IAAnB,EAAJ,CAA8B,CAC1BD,CAAG,GAAH,CACA5G,CAAC,CAAC,eAAD,CAAD,CAAmBoE,IAAnB,CAAwB,mCAAxB,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,eAAD,CAAD,CAAmBoE,IAAnB,CAAwB,EAAxB,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,WAAD,CAAD,CAAeK,GAAf,GAAqBwG,IAArB,EAAJ,CAAgC,CAC5BD,CAAG,GAAH,CACA5G,CAAC,CAAC,iBAAD,CAAD,CAAqBoE,IAArB,CAA0B,qDAA1B,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,iBAAD,CAAD,CAAqBoE,IAArB,CAA0B,EAA1B,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,UAAD,CAAD,CAAcK,GAAd,GAAoBwG,IAApB,EAAJ,CAA+B,CAC3BD,CAAG,GAAH,CACA5G,CAAC,CAAC,gBAAD,CAAD,CAAoBoE,IAApB,CAAyB,oDAAzB,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,gBAAD,CAAD,CAAoBoE,IAApB,CAAyB,EAAzB,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,MAAD,CAAD,CAAUK,GAAV,GAAgBwG,IAAhB,EAAJ,CAA2B,CACvBD,CAAG,GAAH,CACA5G,CAAC,CAAC,YAAD,CAAD,CAAgBoE,IAAhB,CAAqB,kCAArB,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,YAAD,CAAD,CAAgBoE,IAAhB,CAAqB,EAArB,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,kBAAD,CAAD,CAAsBK,GAAtB,GAA4BwG,IAA5B,EAAJ,CAAuC,CACnCD,CAAG,GAAH,CACA5G,CAAC,CAAC,wBAAD,CAAD,CAA4BoE,IAA5B,CAAiC,kCAAjC,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,wBAAD,CAAD,CAA4BoE,IAA5B,CAAiC,EAAjC,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,gBAAD,CAAD,CAAoBK,GAApB,GAA0BwG,IAA1B,EAAJ,CAAqC,CACjCD,CAAG,GAAH,CACA5G,CAAC,CAAC,sBAAD,CAAD,CAA0BoE,IAA1B,CAA+B,oCAA/B,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,sBAAD,CAAD,CAA0BoE,IAA1B,CAA+B,EAA/B,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,eAAD,CAAD,CAAmBK,GAAnB,GAAyBwG,IAAzB,EAAJ,CAAoC,CAChCD,CAAG,GAAH,CACA5G,CAAC,CAAC,qBAAD,CAAD,CAAyBoE,IAAzB,CAA8B,qCAA9B,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,qBAAD,CAAD,CAAyBoE,IAAzB,CAA8B,EAA9B,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,kBAAD,CAAD,CAAsBK,GAAtB,GAA4BwG,IAA5B,EAAJ,CAAuC,CACnCD,CAAG,GAAH,CACA5G,CAAC,CAAC,wBAAD,CAAD,CAA4BoE,IAA5B,CAAiC,qCAAjC,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,wBAAD,CAAD,CAA4BoE,IAA5B,CAAiC,EAAjC,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,cAAD,CAAD,CAAkBK,GAAlB,GAAwBwG,IAAxB,EAAJ,CAAmC,CAC/BD,CAAG,GAAH,CACA5G,CAAC,CAAC,oBAAD,CAAD,CAAwBoE,IAAxB,CAA6B,qCAA7B,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,oBAAD,CAAD,CAAwBoE,IAAxB,CAA6B,EAA7B,CACH,CACJ,CAzEM,CAAP,CA2EA,MAAOwC,CAAAA,CACV,CAED,QAASxG,CAAAA,oBAAT,EAA+B,CAC3B,GAAIwG,CAAAA,CAAG,GAAP,CACA7G,OAAO,CAAC,CAAC,QAAD,CAAD,CAAY,SAASC,CAAT,CAAW,CAC1B,GAAG,CAACA,CAAC,CAAC,cAAD,CAAD,CAAkBK,GAAlB,GAAwBwG,IAAxB,EAAJ,CAAmC,CAC/BD,CAAG,GAAH,CACA5G,CAAC,CAAC,oBAAD,CAAD,CAAwBoE,IAAxB,CAA6B,qCAA7B,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,oBAAD,CAAD,CAAwBoE,IAAxB,CAA6B,EAA7B,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,eAAD,CAAD,CAAmBK,GAAnB,GAAyBwG,IAAzB,EAAJ,CAAoC,CAChCD,CAAG,GAAH,CACA5G,CAAC,CAAC,qBAAD,CAAD,CAAyBoE,IAAzB,CAA8B,oCAA9B,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,qBAAD,CAAD,CAAyBoE,IAAzB,CAA8B,EAA9B,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,eAAD,CAAD,CAAmBK,GAAnB,GAAyBwG,IAAzB,EAAJ,CAAoC,CAChCD,CAAG,GAAH,CACA5G,CAAC,CAAC,qBAAD,CAAD,CAAyBoE,IAAzB,CAA8B,uCAA9B,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,qBAAD,CAAD,CAAyBoE,IAAzB,CAA8B,EAA9B,CACH,CACD,GAAG,CAACpE,CAAC,CAAC,aAAD,CAAD,CAAiBK,GAAjB,GAAuBwG,IAAvB,EAAJ,CAAkC,CAC9BD,CAAG,GAAH,CACA5G,CAAC,CAAC,mBAAD,CAAD,CAAuBoE,IAAvB,CAA4B,uCAA5B,CACH,CAHD,IAGK,CACDpE,CAAC,CAAC,mBAAD,CAAD,CAAuBoE,IAAvB,CAA4B,EAA5B,CACH,CACJ,CAzBM,CAAP,CA0BA,MAAOwC,CAAAA,CACV","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Potential user selector module.\n *\n * @module enrol_manual/form-potential-user-selector\n * @class form-potential-user-selector\n * @package enrol_manual\n * @copyright 2016 Damyon Wiese\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nvar brandName = '';\nvar ghash = '';\n\nrequire(['jquery'], function($){\n $(document).on('submit', '#pagseguro_boleto_form', function(e) {\n if(boletoValidateFields()){\n $(\"#pagseguro_boleto_form input[name=sender_hash]\").val(ghash);\n var urlParams = new URLSearchParams(window.location.search);\n $(\"#boleto_courseid\").val(urlParams.get('id'));\n } else {\n e.preventDefault();\n }\n });\n $(document).on('click', '#cc_submit', function() {\n if(ccValidateFields()){\n var ccNum = $(\"input[name=ccnumber]\").val().replace(/\\s/g, '');\n var ccCvv = $(\"input[name=cvv]\").val();\n var ccExp = $(\"input[name=ccvalid]\").val().split(\"/\");\n PagSeguroDirectPayment.createCardToken({\n cardNumber: ccNum, // Número do cartão de crédito.\n brand: brandName, // Bandeira do cartão.\n cvv: ccCvv, // CVV do cartão.\n expirationMonth: ccExp[0], // Mês da expiração do cartão.\n expirationYear: ccExp[1], // Ano da expiração do cartão, é necessário os 4 dígitos.\n success: function(response) {\n $(\"#cc_token\").val(response.card.token);\n var urlParams = new URLSearchParams(window.location.search);\n $(\"#cc_courseid\").val(urlParams.get('id'));\n $(\"#cc_instval\").val($(\"#installments\").find(':selected').data('installment-value'));\n $(\"#pagseguro_cc_form\").submit();\n },\n error: function() {\n // Callback para chamadas que falharam.\n },\n complete: function() {\n // Callback para todas chamadas.\n }\n });\n }\n });\n\n $(document).on('focusout', '#billingpostcode', function() {\n var cep = $('#billingpostcode').val().replace(/\\D/g, '');\n // Verifica se campo cep possui valor informado.\n if (cep != \"\") {\n // Expressão regular para validar o CEP.\n var validacep = /^[0-9]{8}$/;\n // Valida o formato do CEP.\n if(validacep.test(cep)) {\n // Preenche os campos com \"...\" enquanto consulta webservice.\n $(\"#billingstreet\").val(\"...\");\n $(\"#billingdistrict\").val(\"...\");\n $(\"#billingcity\").val(\"...\");\n $(\"#billingstate\").val(\"...\");\n $(\"#ibge\").val(\"...\");\n // Consulta o webservice viacep.com.br.\n $.getJSON(\"https://viacep.com.br/ws/\" + cep + \"/json/?callback=?\", function(dados) {\n if (!(\"erro\" in dados)) {\n // Atualiza os campos com os valores da consulta.\n $(\"#billingstreet\").val(dados.logradouro);\n $(\"#billingdistrict\").val(dados.bairro);\n $(\"#billingcity\").val(dados.localidade);\n $(\"#billingstate\").val(dados.uf);\n $(\"#ibge\").val(dados.ibge);\n } else {\n // CEP pesquisado não foi encontrado.\n limpa_formulário_cep();\n alert(\"CEP não encontrado.\");\n }\n });\n } else {\n limpa_formulário_cep();\n alert(\"Formato de CEP inválido.\");\n }\n } else {\n // Cep sem valor, limpa formulário.\n limpa_formulário_cep();\n }\n });\n});\n\nfunction loadDoc(courseid, p){\n require(['core/ajax'], function(ajax) {\n var promises = ajax.call([{\n methodname: 'enrol_pagseguro_get_session',\n args:{'courseP': p }\n }]);\n promises[0].done(function(response) {\n setPagueSeguroWSSessionId(response.stoken,courseid, response.courseP);\n }).fail(function() {\n // Do something with the exception.\n });\n });\n}\n\nfunction setPagueSeguroWSSessionId(sessionId,courseId, courseP){\n PagSeguroDirectPayment.setSessionId(sessionId);\n PagSeguroDirectPayment.getPaymentMethods({\n success: function() {\n // Retorna os meios de pagamento disponíveis.\n require(['jquery', 'core/ajax', 'core/templates', 'core/notification'],\n function($, ajax, templates, notification) {\n var promises = ajax.call([{\n methodname: 'enrol_pagseguro_get_forms',\n args:{ 'sessionId' : sessionId, 'courseId': courseId, 'courseP': courseP }\n }]);\n promises[0].done(function(response) {\n templates.render('enrol_pagseguro/checkout_form', JSON.parse(response)).done(function(html, js) {\n $('#modal-return').html(html);\n templates.runTemplateJS(js);\n PagSeguroDirectPayment.onSenderHashReady(function(response){\n if(response.status == 'error') {\n return false;\n }\n var hash = response.senderHash; // Hash estará disponível nesta variável.\n ghash = hash;\n createMasks();\n });\n }).fail(notification.exception);\n\n }).fail(function() {\n // Do something with the exception.\n });\n });\n },\n error: function(response) {\n // Callback para chamadas que falharam.\n document.getElementById(\"return\").innerHTML = JSON.stringify(response);\n },\n complete: function() {\n // Callback para todas chamadas.\n }\n });\n}\n\nfunction createMasks(){\n require(['jquery', 'enrol_pagseguro/jqmask'], function($, jqmask){\n var ph_options = {\n onKeyPress: function(ph, e, field, ph_options){\n var masks = ['(00) 0000-00009', '(00) 0 0000-0000'];\n var mask = (ph.length > 14) ? masks[1] : masks [0];\n $('.input-phone').mask(mask, ph_options);\n }\n };\n $('.input-phone').mask(\"(00) 0000-0000\", ph_options);\n var options = {\n onKeyPress: function(doc, e, field, options){\n var masks = ['000.000.000-009', '00.000.000/0000-00'];\n var mask = (doc.length > 14) ? masks[1] : masks [0];\n $('.input-cpfcnpj').mask(mask, options);\n }\n };\n $('.input-cpfcnpj').mask(\"000.000.000-009\", options);\n $('.input-ccnumber').mask('0000 0000 0000 0000');\n $('.input-ccvalid').mask('00/0000');\n $('.input-cvv').mask('000');\n $('.input-cep').mask('00000-000');\n });\n}\n\nfunction limpa_formulário_cep() {\n // Limpa valores do formulário de cep.\n require(['jquery'],function($){\n $(\"#billingstreet\").val(\"\");\n $(\"#billingdistrict\").val(\"\");\n $(\"#billingcity\").val(\"\");\n $(\"#billingstate\").val(\"\");\n $(\"#ibge\").val(\"\");\n });\n}\n\nfunction checkBrand(el, cp){\n var cardnum = el.value.replace(/\\s/g, '');\n if(cardnum.length >= 6){\n PagSeguroDirectPayment.getBrand({\n cardBin: Number(cardnum.substring(0,6)),\n success: function(response) {\n require(['jquery'],function($){\n brandName = response.brand.name;\n var imgsrc = \"https://stc.pagseguro.uol.com.br/public/img/payment-methods-flags/42x20/\";\n $('#cardbrand').html(\"\" );\n installments(brandName,cp);\n });\n },\n error: function() {\n\n },\n complete: function() {\n\n }\n });\n }\n}\n\nfunction installments(brandName,cp){\n var n = Number.parseFloat(cp).toFixed(2);\n PagSeguroDirectPayment.getInstallments({\n amount: n,\n brand: brandName,\n success: function(response){\n // Retorna as opções de parcelamento disponíveis.\n require(['jquery'],function($){\n if(!response[\"error\"]){\n var sel_installments = '';\n }\n $('#card-installments').html(\"\" + sel_installments + \"\");\n });\n\n },\n error: function() {\n // Callback para chamadas que falharam.\n },\n complete: function(){\n // Callback para todas chamadas.\n }\n });\n\n}\n\n//function paycc(){\n// if(!ccValidateFields()){\n// return;\n// }else{\n// require(['jquery'], function($){\n// var ccNum = $(\"input[name=ccnumber]\").val().replace(/\\s/g, '');\n// var ccCvv = $(\"input[name=cvv]\").val();\n// var ccExp = $(\"input[name=ccvalid]\").val().split(\"/\");\n// PagSeguroDirectPayment.createCardToken({\n// cardNumber: ccNum, // Número do cartão de crédito.\n// brand: brandName, // Bandeira do cartão.\n// cvv: ccCvv, // CVV do cartão.\n// expirationMonth: ccExp[0], // Mês da expiração do cartão.\n// expirationYear: ccExp[1], // Ano da expiração do cartão, é necessário os 4 dígitos.\n// success: function(response) {\n// if(ccValidateFields()){\n// $(\"input[name=cc_token]\").val(response.card.token);\n// var urlParams = new URLSearchParams(window.location.search);\n// $(\"input[name=courseid]\").val(urlParams.get('id'));\n// $(\"input[name=inst_val]\").val($(\"#installments\").data('data-installment-value'));\n// $(\"#pagseguro_cc_form\").submit();\n// }\n// },\n// error: function() {\n// // Callback para chamadas que falharam.\n// },\n// complete: function() {\n// // Callback para todas chamadas.\n// }\n// });\n// });\n// }\n//}\n\n//function payboleto(e){\n// require(['jquery'], function($){\n// $(\"#pagseguro_boleto_form\").submit(function(e) {\n// e.preventDefault();\n// console.log(\"submit prevented\");\n// $(\"#pagseguro_boleto_form input[name=sender_hash]\").val(ghash);\n// var urlParams = new URLSearchParams(window.location.search);\n// $(\"#boleto_courseid\").val(urlParams.get('id'));\n// });\n// });\n// } else {\n// require(['jquery'], function($){\n// $(\"#pagseguro_boleto_form\").on('submit', function(e){\n// e.preventDefault();\n// });\n// });\n// }\n//}\n\nfunction ccValidateFields(){\n var rtn = true;\n require(['jquery'],function($){\n if(!$(\"#ccEmail\").val().trim()){\n rtn = false;\n $(\"#ccEmail-error\").html('Favor preencher email corretamente');\n }else{\n $(\"#ccEmail-error\").html('');\n }\n if(!$(\"#ccPhone\").val().trim()){\n rtn = false;\n $(\"#ccPhone-error\").html('Favor preencher telefone corretamente');\n }else{\n $(\"#ccPhone-error\").html('');\n }\n if(!$(\"#ccCPFCNPJ\").val().trim()){\n rtn = false;\n $(\"#ccCPFCNPJ-error\").html('Favor preencher CPF/CNPJ corretamente');\n }else{\n $(\"#ccCPFCNPJ-error\").html('');\n }\n if(!$(\"#ccName\").val().trim()){\n rtn = false;\n $(\"#ccName-error\").html('Favor preencher Nome corretamente');\n }else{\n $(\"#ccName-error\").html('');\n }\n if(!$(\"#ccNumber\").val().trim()){\n rtn = false;\n $(\"#ccNumber-error\").html('Favor preencher Número do cartão corretamente');\n }else{\n $(\"#ccNumber-error\").html('');\n }\n if(!$(\"#ccvalid\").val().trim()){\n rtn = false;\n $(\"#ccvalid-error\").html('Favor preencher Validade do cartão corretamente');\n }else{\n $(\"#ccvalid-error\").html('');\n }\n if(!$(\"#cvv\").val().trim()){\n rtn = false;\n $(\"#cvv-error\").html('Favor preencher CVV corretamente');\n }else{\n $(\"#cvv-error\").html('');\n }\n if(!$(\"#billingpostcode\").val().trim()){\n rtn = false;\n $(\"#billingpostcode-error\").html('Favor preencher cep corretamente');\n }else{\n $(\"#billingpostcode-error\").html('');\n }\n if(!$(\"#billingstreet\").val().trim()){\n rtn = false;\n $(\"#billingstreet-error\").html('Favor preencher campo corretamente');\n }else{\n $(\"#billingstreet-error\").html('');\n }\n if(!$(\"#billingstate\").val().trim()){\n rtn = false;\n $(\"#billingstate-error\").html('Favor preencher estado corretamente');\n }else{\n $(\"#billingstate-error\").html('');\n }\n if(!$(\"#billingdistrict\").val().trim()){\n rtn = false;\n $(\"#billingdistrict-error\").html('Favor preencher bairro corretamente');\n }else{\n $(\"#billingdistrict-error\").html('');\n }\n if(!$(\"#billingcity\").val().trim()){\n rtn = false;\n $(\"#billingcity-error\").html('Favor preencher cidade corretamente');\n }else{\n $(\"#billingcity-error\").html('');\n }\n });\n\n return rtn;\n}\n\nfunction boletoValidateFields(){\n var rtn = true;\n require(['jquery'],function($){\n if(!$(\"#boleto_nome\").val().trim()){\n rtn = false;\n $(\"#boleto_nome-error\").html('Favor preencher o nome corretamente');\n }else{\n $(\"#boleto_nome-error\").html('');\n }\n if(!$(\"#boleto_email\").val().trim()){\n rtn = false;\n $(\"#boleto_email-error\").html('Favor preencher email corretamente');\n }else{\n $(\"#boleto_email-error\").html('');\n }\n if(!$(\"#boleto_phone\").val().trim()){\n rtn = false;\n $(\"#boleto_phone-error\").html('Favor preencher telefone corretamente');\n }else{\n $(\"#boleto_phone-error\").html('');\n }\n if(!$(\"#boleto_doc\").val().trim()){\n rtn = false;\n $(\"#boleto_doc-error\").html('Favor preencher CPF/CNPJ corretamente');\n }else{\n $(\"#boleto_doc-error\").html('');\n }\n });\n return rtn;\n}\n"],"file":"transparent-checkout.min.js"} \ No newline at end of file diff --git a/amd/src/config.js b/amd/src/config.js new file mode 100755 index 0000000000..32e2564f03 --- /dev/null +++ b/amd/src/config.js @@ -0,0 +1,12 @@ +define([], function () { + window.requirejs.config({ + paths: { + // Enter the paths to your required java-script files. + "jqmask": M.cfg.wwwroot + "/enrol/pagseguro/vendor/jquery-mask/dist/jquery.mask.min" + }, + shim: { + // Enter the "names" that will be used to refer to your libraries. + "jqmask": { exports: "jqmask"} + } + }); +}); diff --git a/amd/src/jqmask.js b/amd/src/jqmask.js new file mode 100755 index 0000000000..ff3145b1c6 --- /dev/null +++ b/amd/src/jqmask.js @@ -0,0 +1,3 @@ +define(['enrol_pagseguro/config', 'jqmask'], function(unused,jqmask) { + return jqmask; +}); diff --git a/amd/src/transparent-checkout.js b/amd/src/transparent-checkout.js new file mode 100755 index 0000000000..e7c2356d1e --- /dev/null +++ b/amd/src/transparent-checkout.js @@ -0,0 +1,414 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Potential user selector module. + * + * @module enrol_manual/form-potential-user-selector + * @class form-potential-user-selector + * @package enrol_manual + * @copyright 2016 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +var brandName = ''; +var ghash = ''; + +require(['jquery'], function($){ + $(document).on('submit', '#pagseguro_boleto_form', function(e) { + if(boletoValidateFields()){ + $("#pagseguro_boleto_form input[name=sender_hash]").val(ghash); + var urlParams = new URLSearchParams(window.location.search); + $("#boleto_courseid").val(urlParams.get('id')); + } else { + e.preventDefault(); + } + }); + $(document).on('click', '#cc_submit', function() { + if(ccValidateFields()){ + var ccNum = $("input[name=ccnumber]").val().replace(/\s/g, ''); + var ccCvv = $("input[name=cvv]").val(); + var ccExp = $("input[name=ccvalid]").val().split("/"); + PagSeguroDirectPayment.createCardToken({ + cardNumber: ccNum, // Número do cartão de crédito. + brand: brandName, // Bandeira do cartão. + cvv: ccCvv, // CVV do cartão. + expirationMonth: ccExp[0], // Mês da expiração do cartão. + expirationYear: ccExp[1], // Ano da expiração do cartão, é necessário os 4 dígitos. + success: function(response) { + $("#cc_token").val(response.card.token); + var urlParams = new URLSearchParams(window.location.search); + $("#cc_courseid").val(urlParams.get('id')); + $("#cc_instval").val($("#installments").find(':selected').data('installment-value')); + $("#pagseguro_cc_form").submit(); + }, + error: function() { + // Callback para chamadas que falharam. + }, + complete: function() { + // Callback para todas chamadas. + } + }); + } + }); + + $(document).on('focusout', '#billingpostcode', function() { + var cep = $('#billingpostcode').val().replace(/\D/g, ''); + // Verifica se campo cep possui valor informado. + if (cep != "") { + // Expressão regular para validar o CEP. + var validacep = /^[0-9]{8}$/; + // Valida o formato do CEP. + if(validacep.test(cep)) { + // Preenche os campos com "..." enquanto consulta webservice. + $("#billingstreet").val("..."); + $("#billingdistrict").val("..."); + $("#billingcity").val("..."); + $("#billingstate").val("..."); + $("#ibge").val("..."); + // Consulta o webservice viacep.com.br. + $.getJSON("https://viacep.com.br/ws/" + cep + "/json/?callback=?", function(dados) { + if (!("erro" in dados)) { + // Atualiza os campos com os valores da consulta. + $("#billingstreet").val(dados.logradouro); + $("#billingdistrict").val(dados.bairro); + $("#billingcity").val(dados.localidade); + $("#billingstate").val(dados.uf); + $("#ibge").val(dados.ibge); + } else { + // CEP pesquisado não foi encontrado. + limpa_formulário_cep(); + alert("CEP não encontrado."); + } + }); + } else { + limpa_formulário_cep(); + alert("Formato de CEP inválido."); + } + } else { + // Cep sem valor, limpa formulário. + limpa_formulário_cep(); + } + }); +}); + +function loadDoc(courseid, p){ + require(['core/ajax'], function(ajax) { + var promises = ajax.call([{ + methodname: 'enrol_pagseguro_get_session', + args:{'courseP': p } + }]); + promises[0].done(function(response) { + setPagueSeguroWSSessionId(response.stoken,courseid, response.courseP); + }).fail(function() { + // Do something with the exception. + }); + }); +} + +function setPagueSeguroWSSessionId(sessionId,courseId, courseP){ + PagSeguroDirectPayment.setSessionId(sessionId); + PagSeguroDirectPayment.getPaymentMethods({ + success: function() { + // Retorna os meios de pagamento disponíveis. + require(['jquery', 'core/ajax', 'core/templates', 'core/notification'], + function($, ajax, templates, notification) { + var promises = ajax.call([{ + methodname: 'enrol_pagseguro_get_forms', + args:{ 'sessionId' : sessionId, 'courseId': courseId, 'courseP': courseP } + }]); + promises[0].done(function(response) { + templates.render('enrol_pagseguro/checkout_form', JSON.parse(response)).done(function(html, js) { + $('#modal-return').html(html); + templates.runTemplateJS(js); + PagSeguroDirectPayment.onSenderHashReady(function(response){ + if(response.status == 'error') { + return false; + } + var hash = response.senderHash; // Hash estará disponível nesta variável. + ghash = hash; + createMasks(); + }); + }).fail(notification.exception); + + }).fail(function() { + // Do something with the exception. + }); + }); + }, + error: function(response) { + // Callback para chamadas que falharam. + document.getElementById("return").innerHTML = JSON.stringify(response); + }, + complete: function() { + // Callback para todas chamadas. + } + }); +} + +function createMasks(){ + require(['jquery', 'enrol_pagseguro/jqmask'], function($, jqmask){ + var ph_options = { + onKeyPress: function(ph, e, field, ph_options){ + var masks = ['(00) 0000-00009', '(00) 0 0000-0000']; + var mask = (ph.length > 14) ? masks[1] : masks [0]; + $('.input-phone').mask(mask, ph_options); + } + }; + $('.input-phone').mask("(00) 0000-0000", ph_options); + var options = { + onKeyPress: function(doc, e, field, options){ + var masks = ['000.000.000-009', '00.000.000/0000-00']; + var mask = (doc.length > 14) ? masks[1] : masks [0]; + $('.input-cpfcnpj').mask(mask, options); + } + }; + $('.input-cpfcnpj').mask("000.000.000-009", options); + $('.input-ccnumber').mask('0000 0000 0000 0000'); + $('.input-ccvalid').mask('00/0000'); + $('.input-cvv').mask('000'); + $('.input-cep').mask('00000-000'); + }); +} + +function limpa_formulário_cep() { + // Limpa valores do formulário de cep. + require(['jquery'],function($){ + $("#billingstreet").val(""); + $("#billingdistrict").val(""); + $("#billingcity").val(""); + $("#billingstate").val(""); + $("#ibge").val(""); + }); +} + +function checkBrand(el, cp){ + var cardnum = el.value.replace(/\s/g, ''); + if(cardnum.length >= 6){ + PagSeguroDirectPayment.getBrand({ + cardBin: Number(cardnum.substring(0,6)), + success: function(response) { + require(['jquery'],function($){ + brandName = response.brand.name; + var imgsrc = "https://stc.pagseguro.uol.com.br/public/img/payment-methods-flags/42x20/"; + $('#cardbrand').html("" ); + installments(brandName,cp); + }); + }, + error: function() { + + }, + complete: function() { + + } + }); + } +} + +function installments(brandName,cp){ + var n = Number.parseFloat(cp).toFixed(2); + PagSeguroDirectPayment.getInstallments({ + amount: n, + brand: brandName, + success: function(response){ + // Retorna as opções de parcelamento disponíveis. + require(['jquery'],function($){ + if(!response["error"]){ + var sel_installments = ''; + } + $('#card-installments').html("" + sel_installments + ""); + }); + + }, + error: function() { + // Callback para chamadas que falharam. + }, + complete: function(){ + // Callback para todas chamadas. + } + }); + +} + +//function paycc(){ +// if(!ccValidateFields()){ +// return; +// }else{ +// require(['jquery'], function($){ +// var ccNum = $("input[name=ccnumber]").val().replace(/\s/g, ''); +// var ccCvv = $("input[name=cvv]").val(); +// var ccExp = $("input[name=ccvalid]").val().split("/"); +// PagSeguroDirectPayment.createCardToken({ +// cardNumber: ccNum, // Número do cartão de crédito. +// brand: brandName, // Bandeira do cartão. +// cvv: ccCvv, // CVV do cartão. +// expirationMonth: ccExp[0], // Mês da expiração do cartão. +// expirationYear: ccExp[1], // Ano da expiração do cartão, é necessário os 4 dígitos. +// success: function(response) { +// if(ccValidateFields()){ +// $("input[name=cc_token]").val(response.card.token); +// var urlParams = new URLSearchParams(window.location.search); +// $("input[name=courseid]").val(urlParams.get('id')); +// $("input[name=inst_val]").val($("#installments").data('data-installment-value')); +// $("#pagseguro_cc_form").submit(); +// } +// }, +// error: function() { +// // Callback para chamadas que falharam. +// }, +// complete: function() { +// // Callback para todas chamadas. +// } +// }); +// }); +// } +//} + +//function payboleto(e){ +// require(['jquery'], function($){ +// $("#pagseguro_boleto_form").submit(function(e) { +// e.preventDefault(); +// console.log("submit prevented"); +// $("#pagseguro_boleto_form input[name=sender_hash]").val(ghash); +// var urlParams = new URLSearchParams(window.location.search); +// $("#boleto_courseid").val(urlParams.get('id')); +// }); +// }); +// } else { +// require(['jquery'], function($){ +// $("#pagseguro_boleto_form").on('submit', function(e){ +// e.preventDefault(); +// }); +// }); +// } +//} + +function ccValidateFields(){ + var rtn = true; + require(['jquery'],function($){ + if(!$("#ccEmail").val().trim()){ + rtn = false; + $("#ccEmail-error").html('Favor preencher email corretamente'); + }else{ + $("#ccEmail-error").html(''); + } + if(!$("#ccPhone").val().trim()){ + rtn = false; + $("#ccPhone-error").html('Favor preencher telefone corretamente'); + }else{ + $("#ccPhone-error").html(''); + } + if(!$("#ccCPFCNPJ").val().trim()){ + rtn = false; + $("#ccCPFCNPJ-error").html('Favor preencher CPF/CNPJ corretamente'); + }else{ + $("#ccCPFCNPJ-error").html(''); + } + if(!$("#ccName").val().trim()){ + rtn = false; + $("#ccName-error").html('Favor preencher Nome corretamente'); + }else{ + $("#ccName-error").html(''); + } + if(!$("#ccNumber").val().trim()){ + rtn = false; + $("#ccNumber-error").html('Favor preencher Número do cartão corretamente'); + }else{ + $("#ccNumber-error").html(''); + } + if(!$("#ccvalid").val().trim()){ + rtn = false; + $("#ccvalid-error").html('Favor preencher Validade do cartão corretamente'); + }else{ + $("#ccvalid-error").html(''); + } + if(!$("#cvv").val().trim()){ + rtn = false; + $("#cvv-error").html('Favor preencher CVV corretamente'); + }else{ + $("#cvv-error").html(''); + } + if(!$("#billingpostcode").val().trim()){ + rtn = false; + $("#billingpostcode-error").html('Favor preencher cep corretamente'); + }else{ + $("#billingpostcode-error").html(''); + } + if(!$("#billingstreet").val().trim()){ + rtn = false; + $("#billingstreet-error").html('Favor preencher campo corretamente'); + }else{ + $("#billingstreet-error").html(''); + } + if(!$("#billingstate").val().trim()){ + rtn = false; + $("#billingstate-error").html('Favor preencher estado corretamente'); + }else{ + $("#billingstate-error").html(''); + } + if(!$("#billingdistrict").val().trim()){ + rtn = false; + $("#billingdistrict-error").html('Favor preencher bairro corretamente'); + }else{ + $("#billingdistrict-error").html(''); + } + if(!$("#billingcity").val().trim()){ + rtn = false; + $("#billingcity-error").html('Favor preencher cidade corretamente'); + }else{ + $("#billingcity-error").html(''); + } + }); + + return rtn; +} + +function boletoValidateFields(){ + var rtn = true; + require(['jquery'],function($){ + if(!$("#boleto_nome").val().trim()){ + rtn = false; + $("#boleto_nome-error").html('Favor preencher o nome corretamente'); + }else{ + $("#boleto_nome-error").html(''); + } + if(!$("#boleto_email").val().trim()){ + rtn = false; + $("#boleto_email-error").html('Favor preencher email corretamente'); + }else{ + $("#boleto_email-error").html(''); + } + if(!$("#boleto_phone").val().trim()){ + rtn = false; + $("#boleto_phone-error").html('Favor preencher telefone corretamente'); + }else{ + $("#boleto_phone-error").html(''); + } + if(!$("#boleto_doc").val().trim()){ + rtn = false; + $("#boleto_doc-error").html('Favor preencher CPF/CNPJ corretamente'); + }else{ + $("#boleto_doc-error").html(''); + } + }); + return rtn; +} diff --git a/classes/event/payment_receive.php b/classes/event/payment_receive.php new file mode 100644 index 0000000000..4c693ce4dd --- /dev/null +++ b/classes/event/payment_receive.php @@ -0,0 +1,53 @@ +. + +/** + * Event class to execute after payment is received. + * + * + * @package enrol_pagseguro + * @copyright 2020 Daniel Neis Araujo + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace enrol_pagseguro\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event class to execute after payment is received. + * @author Igor Agatti + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class payment_receive extends \core\event\base { + + public static function get_name() { + return "pagseguro_payment_receive"; + } + + public function get_description() { + return "pagseguro_payment_receive"; + } + + public function get_legacy_logdata() { + return null; + } + + protected function init() { + $this->data['crud'] = 'c'; + $this->data['edulevel'] = self::LEVEL_OTHER; + } +} diff --git a/classes/output/checkout_form.php b/classes/output/checkout_form.php new file mode 100755 index 0000000000..83d854c383 --- /dev/null +++ b/classes/output/checkout_form.php @@ -0,0 +1,83 @@ +. + +/** + * Class containing data for index page + * + * @package enrol_pagseguro + * @copyright 2020 Igor Agatti Lima + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace enrol_pagseguro\output; + +defined('MOODLE_INTERNAL') || die; + +require_once("$CFG->dirroot/webservice/externallib.php"); + +use renderable; +use templatable; +use renderer_base; +use stdClass; + +/** + * Class containing data for pagseguro modal form + * + * @copyright 2020 Igor Agatti Lima + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class checkout_form implements renderable, templatable { + + + /** @var array $formparams */ + public $formparams = array(); + + /** + * Constructor class that sets formparams. + * + * @param array $fparams + * @return stdClass + */ + public function __construct(array $fparams = array()) { + $this->formparams = $fparams; + } + + /** + * Export this data so it can be used as the context for a mustache template. + * + * @param renderer_base $output + * @return stdClass $dataobj + */ + public function export_for_template(renderer_base $output) { + global $USER, $COURSE, $PAGE; + + $data = array(); + $data["courseid"] = $PAGE->course->id; + $data["email"] = $USER->email; + $data["fullname"] = $USER->firstname." ".$USER->lastname; + if ($USER->cpf) { + $data["cpf"] = $USER->cpf; + } + if ($USER->phone) { + $data["phone"] = $USER->phone; + } + $data["dt"] = userdate(time()) . ' ' . rand(); + if ($this->formparams['courseP']) { + $data["price"] = $this->formparams['courseP']; + } + $dataobj = json_encode($data); + return $dataobj; + } +} diff --git a/classes/output/renderer.php b/classes/output/renderer.php new file mode 100755 index 0000000000..c9dcbc5e1c --- /dev/null +++ b/classes/output/renderer.php @@ -0,0 +1,50 @@ +. + +/** + * Renderer class for local hackfest. + * + * @package enrol_pagseguro + * @copyright 2020 Igor Agatti Lima + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace enrol_pagseguro\output; + +defined('MOODLE_INTERNAL') || die; + +use plugin_renderer_base; + +/** + * Renderer class for the pagseguro form in modal. + * + * @copyright 2020 Igor Agatti Lima + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class renderer extends plugin_renderer_base { + + /** + * Defer to template. + * + * @param checkout_form $page + * + * @return string html for the page + */ + public function render_checkout_form($page) { + $data = $page->export_for_template($this); + return parent::render_from_template('enrol_pagseguro/checkout_form', $data); + } + +} diff --git a/component/external/transparentcheckoutservice.php b/component/external/transparentcheckoutservice.php new file mode 100755 index 0000000000..c5b08dd746 --- /dev/null +++ b/component/external/transparentcheckoutservice.php @@ -0,0 +1,115 @@ +. + +/** + * External Web Service that connects with pagseguro checkout service. + * + * @package enrol_pagseguro + * @copyright Igor Agatti Lima + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +require_once($CFG->libdir . "/externallib.php"); + +/** + * External Web Service that connects with pagseguro checkout service. + * + * @copyright Igor Agatti Lima + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_pagseguro_external extends external_api { + + /** + * Returns description of method parameters + * @return external_function_parameters + */ + public static function get_session_parameters() { + return new external_function_parameters(); + } + + /** + * Expose to AJAX + * @return boolean + */ + public static function get_session_is_allowed_from_ajax() { + return true; + } + + /** + * Connects to pagseguro webservice and retrieves session token. + * + * @return string $sessionToken + */ + public static function get_session() { + global $USER; + + // Parameter validation. + // REQUIRED. + $params = self::validate_parameters(self::hello_world_parameters(), array()); + + // Context validation. + // OPTIONAL but in most web service it should present. + $context = get_context_instance(CONTEXT_USER, $USER->id); + self::validate_context($context); + + // Capability checking. + // OPTIONAL but in most web service it should present. + if (!has_capability('moodle/user:viewdetails', $context)) { + throw new moodle_exception('cannotviewprofile'); + } + + if (get_config('enrol_pagseguro', 'usesandbox') == 1) { + $url = 'https://ws.sandbox.pagseguro.uol.com.br/v2/sessions'; + } else { + $url = 'https://ws.pagseguro.uol.com.br/v2/sessions' + } + + $psemail = get_config('enrol_pagseguro', 'pagsegurobusiness'); + $pstoken = get_config('enrol_pagseguro', 'pagsegurotoken'); + + $data = array('email' => $psemail, 'token' => $pstoken); + + // Use key 'http' even if you send the request to https://... + $options = array( + 'http' => array( + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'method' => 'POST', + 'content' => http_build_query($data) + ) + ); + $context = stream_context_create($options); + $result = file_get_contents($url, false, $context); + if ($result === false) { + return false; + } + + $resultxml = simplexml_load_string($result); + $rtn = $resultxml->id; + + return $rtn; + } + + /** + * Returns the session token from pagseguro. + * @return external_description + */ + public static function get_session_returns() { + return new external_value(PARAM_TEXT, 'PagSeguro Session Token'); + } + +} diff --git a/composer.json b/composer.json old mode 100644 new mode 100755 diff --git a/db/access.php b/db/access.php old mode 100644 new mode 100755 diff --git a/db/install.xml b/db/install.xml old mode 100644 new mode 100755 index 67cf495fc5..cb47a67731 --- a/db/install.xml +++ b/db/install.xml @@ -6,22 +6,41 @@ - - - - - + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + @@ -29,4 +48,4 @@
- \ No newline at end of file + diff --git a/db/messages.php b/db/messages.php old mode 100644 new mode 100755 diff --git a/db/services.php b/db/services.php new file mode 100755 index 0000000000..d5b4b63b1e --- /dev/null +++ b/db/services.php @@ -0,0 +1,49 @@ +. + +/** + * Web service local plugin template external functions and service definitions. + * + * @package enrol_pagseguro + * @copyright 2011 Jerome Mouneyrac + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +// We defined the web service functions to install. + +defined('MOODLE_INTERNAL') || die; + +$functions = array( + + 'enrol_pagseguro_get_session' => array( + 'classname' => 'enrol_pagseguro_external', + 'methodname' => 'get_session', + 'classpath' => 'enrol/pagseguro/externallib.php', + 'description' => 'Gets the session token from PagSeguro.', + 'ajax' => true, + 'type' => 'read', + ), + + 'enrol_pagseguro_get_forms' => array( + 'classname' => 'enrol_pagseguro_external', + 'methodname' => 'get_forms', + 'classpath' => 'enrol/pagseguro/externallib.php', + 'description' => 'Renders the form for PagSeguro Transparent Checkout.', + 'ajax' => true, + 'type' => 'read', + ), +); + diff --git a/db/upgrade.php b/db/upgrade.php old mode 100644 new mode 100755 index db45ff63c1..ed30daf570 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -18,16 +18,35 @@ * This file keeps track of upgrades to the pagseguro enrolment plugin * * @package enrol_pagseguro - * @copyright 2020 Daniel Neis Araujo + * @subpackage pagseguro + * @copyright 2010 Eugene Venter + * @author Eugene Venter * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -defined('MOODLE_INTERNAL') || die(); +// Sometimes, changes between versions involve +// alterations to database structures and other +// major things that may break installations. +// +// The upgrade function in this file will attempt +// to perform all the necessary actions to upgrade +// your older installation to the current version. +// +// If there's something it cannot do itself, it +// will tell you what you need to do. +// +// The commands in here will all be database-neutral, +// using the methods of database_manager class +// +// Please do not forget to use upgrade_set_timeout() +// before any action that may take longer time to finish. +defined('MOODLE_INTERNAL') || die; /** - * Function to upgrade enrol_pagseguro. - * @param int $oldversion the version we are upgrading from - * @return bool result + * This function will attempt to upgrade from older versions + * + * @param mixed $oldversion + * @return boolean */ function xmldb_enrol_pagseguro_upgrade($oldversion) { return true; diff --git a/edit.php b/edit.php old mode 100644 new mode 100755 index 6a864219a9..159d92c4f5 --- a/edit.php +++ b/edit.php @@ -15,8 +15,7 @@ // along with Moodle. If not, see . /** - * Adds new instance of enrol_pagseguro to specified course - * or edits current instance. + * Adds new instance of enrol_pagseguro to specified course or edits current instance. * * @package enrol_pagseguro * @copyright 2020 Daniel Neis Araujo @@ -46,10 +45,12 @@ $plugin = enrol_get_plugin('pagseguro'); if ($instanceid) { - $instanceparams = ['courseid' => $course->id, 'enrol' => 'pagseguro', 'id' => $instanceid]; - $instance = $DB->get_record('enrol', $instanceparams, '*', MUST_EXIST); + $instance = $DB->get_record('enrol', + array('courseid' => $course->id, 'enrol' => 'pagseguro', 'id' => $instanceid), + '*', MUST_EXIST); } else { require_capability('moodle/course:enrolconfig', $context); + // No instance yet, we have to add new instance. navigation_node::override_active_url(new moodle_url('/enrol/instances.php', array('id' => $course->id))); $instance = new stdClass(); $instance->id = null; diff --git a/edit_form.php b/edit_form.php old mode 100644 new mode 100755 index 81ba457f36..b5ff2eefe5 --- a/edit_form.php +++ b/edit_form.php @@ -15,8 +15,7 @@ // along with Moodle. If not, see . /** - * Adds new instance of enrol_pagseguro to specified course - * or edits current instance. + * Adds new instance of enrol_pagseguro to specified course or edits current instance. * * @package enrol_pagseguro * @copyright 2020 Daniel Neis Araujo @@ -27,8 +26,19 @@ require_once($CFG->libdir.'/formslib.php'); +/** + * Adds new instance of enrol_pagseguro to specified course or edits current instance. + * + * @copyright 2020 Daniel Neis Araujo + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ class enrol_pagseguro_edit_form extends moodleform { + /** + * Creates edit form for single course enrolment settings. + * + * @return void + */ public function definition() { $mform = $this->_form; @@ -84,6 +94,14 @@ public function definition() { $this->set_data($instance); } + /** + * Validates form against enrolment instance status, enrolment date, + * and the cost value. + * + * @param mixed $data + * @param mixed $files + * @return mixed $errors + */ public function validation($data, $files) { $errors = parent::validation($data, $files); diff --git a/error_log b/error_log old mode 100644 new mode 100755 diff --git a/externallib.php b/externallib.php new file mode 100755 index 0000000000..9e4a4cc520 --- /dev/null +++ b/externallib.php @@ -0,0 +1,153 @@ +. + +/** + * External Web Service that connects with pagseguro checkout service. + * + * @package enrol_pagseguro + * @copyright Igor Agatti Lima + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +require_once($CFG->libdir . "/externallib.php"); + +/** + * External Web Service that connects with pagseguro checkout service. + * + * @package enrol_pagseguro + * @copyright Igor Agatti Lima + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_pagseguro_external extends external_api { + + /** + * Returns description of method parameters + * @return external_function_parameters + */ + public static function get_session_parameters() { + return new external_function_parameters( + array( 'courseP' => new external_value(PARAM_FLOAT, 'Price of course that is being bought') ) + ); + } + + /** + * Connects to pagseguro webservice and retrieves session token. + * + * @param string $courseprice + * @return string $sessionToken + */ + public static function get_session($courseprice) { + global $USER; + + $psemail = get_config('enrol_pagseguro', 'pagsegurobusiness'); + $pstoken = get_config('enrol_pagseguro', 'pagsegurotoken'); + if (get_config('enrol_pagseguro', 'usesandbox') == 1) { + $baseurl = 'https://ws.sandbox.pagseguro.uol.com.br/v2/sessions?email='; + } else { + $baseurl = 'https://ws.pagseguro.uol.com.br/v2/sessions?email='; + } + + $params = self::validate_parameters(self::get_session_parameters(), + array( + 'courseP' => $courseprice + ) + ); + + $url = $baseurl . urlencode($psemail) . '&token=' . $pstoken; + + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_HTTPHEADER, Array("Content-Type: application/xml; charset=UTF-8")); + curl_setopt($curl, CURLOPT_POSTFIELDS, array()); // To be sure it's a POST request. + $xml = curl_exec($curl); + + $resultxml = simplexml_load_string($xml); + $rtn = array(); + + $rtn['stoken'] = $resultxml->id->__toString(); + $rtn['courseP'] = $courseprice; + + return $rtn; + } + + /** + * Returns description of method result value + * @return external_description + * + */ + public static function get_session_returns() { + return new external_single_structure( + array( + 'stoken' => new external_value(PARAM_TEXT, 'PagSeguro Session Token'), + 'courseP' => new external_value(PARAM_TEXT, 'Price of course that is being bought') + ) + ); + } + + /** + * Returns description of method parameters + * @return external_function_parameters + */ + public static function get_forms_parameters() { + return new external_function_parameters( + array( + 'sessionId' => new external_value(PARAM_TEXT, 'Session ID from Pagseguro'), + 'courseId' => new external_value(PARAM_TEXT, 'Course ID that is being bought'), + 'courseP' => new external_value(PARAM_TEXT, 'Price of course that is being bought') + ) + ); + } + + + /** + * Renders the form inside pagseguro modal. + * + * @param string $sessionid + * @param string $courseid + * @param string $courseprice + * @return string $sessionToken + */ + public static function get_forms($sessionid, $courseid, $courseprice) { + global $PAGE; + + $params = self::validate_parameters(self::get_forms_parameters(), + array( + 'sessionId' => $sessionid, + 'courseId' => $courseid, + 'courseP' => $courseprice + ) + ); + + $PAGE->set_context(context_system::instance()); + $renderer = $PAGE->get_renderer('enrol_pagseguro'); + $page = new \enrol_pagseguro\output\checkout_form($params); + + return $page->export_for_template($renderer); + } + + /** + * Returns description of method result value + * @return external_description + * + */ + public static function get_forms_returns() { + $result = new external_value(PARAM_RAW, 'the current time'); + return $result; + } + +} diff --git a/js/jquery-mask/.gitignore b/js/jquery-mask/.gitignore new file mode 100755 index 0000000000..061d2ba9be --- /dev/null +++ b/js/jquery-mask/.gitignore @@ -0,0 +1,9 @@ +index.html +css/* +img/* +js/* +node_modules/ +bower_components/ +.sparkleshare +libpeerconnection.log +.versions diff --git a/js/jquery-mask/.jshintrc b/js/jquery-mask/.jshintrc new file mode 100755 index 0000000000..79f07e041f --- /dev/null +++ b/js/jquery-mask/.jshintrc @@ -0,0 +1,34 @@ +{ + "bitwise": true, + "browser": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "esnext": true, + "expr": true, + "globals": { + "console": false, + "define": false, + "document": false, + "expect": false, + "module": false, + "require": false, + "window": false + }, + "immed": true, + "indent": 4, + "latedef": false, + "maxcomplexity": 15, + "newcap": true, + "noarg": true, + "node": true, + "noempty": true, + "nonstandard": true, + "quotmark": "single", + "regexp": true, + "smarttabs": true, + "strict": false, + "trailing": true, + "undef": true, + "unused": true +} diff --git a/js/jquery-mask/.ruby-version b/js/jquery-mask/.ruby-version new file mode 100755 index 0000000000..600bcfd1ae --- /dev/null +++ b/js/jquery-mask/.ruby-version @@ -0,0 +1 @@ +2.0.0p598 diff --git a/js/jquery-mask/.travis.yml b/js/jquery-mask/.travis.yml new file mode 100755 index 0000000000..c6ea430daa --- /dev/null +++ b/js/jquery-mask/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: + - "8.9.3" +before_script: + - npm install -g grunt-cli + - npm install +script: grunt test diff --git a/js/jquery-mask/CHANGELOG.md b/js/jquery-mask/CHANGELOG.md new file mode 100755 index 0000000000..a1d00616b2 --- /dev/null +++ b/js/jquery-mask/CHANGELOG.md @@ -0,0 +1,921 @@ +== v1.14.16 (Jul/31 2019 16:32 +0100 by Igor Escobar) == + +Bugfixes: + +* Fixed oldVal being updated prior to caret position calculation +* Solve loading JQuery as module on Meteor + +== v1.14.15 (Mar/08 2018 22:59 +0000 by Igor Escobar) == + +Bugfixes: + +* rolling back change to fix caret positioning. it didn’t worked on some devices + +== v1.14.14 (Mar/02 2018 16:55 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing mask positioning delays +* unmask: also removing place holder if added on the first place. +* unmask: unsetting maxlength if we set it in the first place + +== v1.14.13 (Dec/11 2017 18:59 +0000 by Igor Escobar) == + +Bugfixes: + +* fixes caret issue explained on #636 +* fixing use strict issue + +== v1.14.12 (Oct/04 2017 09:57 +0100 by Igor Escobar) == + +Bugfixes: + +* bug fixing on caret positioning on some devices + +== v1.14.11 (May/30 2017 21:53 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing a lot of caret positioning issues. Thanks to @onuradsay + +== v1.14.10 (Feb/13 2017 14:18 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing exception when oValue in undefined + +== v1.14.9 (Jan/25 2017 11:17 +0000 by Igor Escobar) == + +Bugfixes: + +* don’t use input event when using samsung browser or old chrome versions + +== v1.14.8 (Dec/26 2016 13:18 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing caret on android with chrome 28 + +== v1.14.7 (Dec/25 2016 03:51 +0000 by Igor Escobar) == + +Bugfixes: + +* improving caret positioning when cursor is on the middle + +== v1.14.6 (Dec/24 2016 17:14 +0000 by Igor Escobar) == + +Bugfixes: + +* fix caret positioning with multiple mask chars + +== v1.14.5 (Dec/24 2016 14:42 +0000 by Igor Escobar) == + +Changes: + +* fixing reserved word + +== v1.14.4 (Dec/24 2016 14:38 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing android cursor positioning (special thanks to @felipejunges and @fernandobandeira) + +== v1.14.3 (Nov/28 2016 11:53 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing caret positioning on safari + +== v1.14.2 (Nov/27 2016 20:04 +0000 by Igor Escobar) == + +Bugfixes: + +* apply auto maxlength in case the mask doesn't have recursive pattern + +== v1.14.1 (Nov/27 2016 19:20 +0000 by Igor Escobar) == + +Bugfixes: + +* Fix input value mangling when inserting before a static mask character +* fixing caret position issue + +== v1.14.0 (Apr/03 2016 17:52 +0100 by Igor Escobar) == + +Bugfixes: + +* Fix cursor jumping while editing in non-IE browsers. Thanks to @archwyrm + +Features: + +* adding masked function for better angular use + +== v1.13.9 (Mar/20 2016 16:17 +0000 by Igor Escobar) == + +Changes: + +* giving the opportunity to pass watchInputs locally + +== v1.13.8 (Mar/06 2016 23:25 +0000 by Igor Escobar) == + +Changes: + +* adding support for meteor + +== v1.13.7 (Mar/06 2016 22:46 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing onChange behaviour + +== v1.13.6 (Mar/06 2016 22:14 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing deploy procedure + +== v1.13.5 (Mar/06 2016 22:01 +0000 by Igor Escobar) == + +Changes: + +* adding clearIfNotMatch to globalOptions + +Bugfixes: + +* fixing some bugs when using non-input elements +* fixing mobile issues at #348. +* using input event when supported + +== v1.13.4 (Aug/07 2015 14:21 +0100 by Igor Escobar) == + +Bugfixes: + +* Add check to ensure that there are input elements before using them + +== v1.13.3 (Jul/16 2015 16:11 +0100 by Igor Escobar) == + +Changes: + +* adding main property to package.json + +== v1.13.2 (Jul/16 2015 16:06 +0100 by Igor Escobar) == + +Bugfixes: + +* change event wasnt being triggered in some cases + +== v1.13.1 (Jul/07 2015 15:38 +0100 by Igor Escobar) == + +Bugfixes: + +* destroying input event too + +== v1.13.0 (Jul/07 2015 15:26 +0100 by Igor Escobar) == + +Changes: + +* removing the autocomplete default. + +Bugfixes: + +* fixing bower file thanks to @lazyants + +Features: + +* prevent glitch when invalid chars. +* turning off autocomplete when browsers doesn't support oninput event. + +== v1.12.0 (Jul/07 2015 11:37 +0100 by Igor Escobar) == + +Features: + +* giving an alternative to the autocomplete/autofill problem. + +== v1.11.4 (Feb/26 2015 22:11 +0000 by Igor Escobar) == + +Changes: + +* grunt, jshint and better applyDataMask. Thanks to @lagden +* automated deploy to npm + +== v1.11.3 (Jan/28 2015 15:41 +0000 by Igor Escobar) == + +Changes: + +* Added commonjs module definition + +== v1.11.2 (Dec/26 2014 15:36 +0000 by Igor Escobar) == + +Bugfixes: + +* unreachable code + +== v1.11.1 (Dec/26 2014 15:34 +0000 by Igor Escobar) == + +Bugfixes: + +* unreachable code + +== v1.11.0 (Dec/26 2014 15:33 +0000 by Igor Escobar) == + +Features: + +* implementing selectOnFocus and data-mask-selectonfocus option +* adding public method called: .applyDataMask in case you want to decide whether to apply masks in data-mask fields + +== v1.10.13 (Nov/19 2014 16:06 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing bug with watchInputs feature when mask is used as a function and not a string. + +== v1.10.12 (Nov/06 2014 13:08 +0000 by Igor Escobar) == + +Changes: + +* making a few improvements to make selection, copy events easier + +== v1.10.11 (Nov/06 2014 11:26 +0000 by Igor Escobar) == + +Bugfixes: + +* we need to revaluate dataMask flags everytime + +== v1.10.10 (Nov/06 2014 10:41 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing dynamically data-mask added elements + +== v1.10.9 (Nov/05 2014 10:52 +0000 by Igor Escobar) == + +Bugfixes: + +* data-mask wasnt working + +== v1.10.8 (Nov/01 2014 13:49 +0000 by Igor Escobar) == + +Changes: + +* we dont need to seek for data-mask every time + +== v1.10.7 (Nov/01 2014 13:18 +0000 by Igor Escobar) == + +Changes: + +* little optimization + +== v1.10.6 (Oct/28 2014 13:59 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing weird cursor problems in weird cases. +* dynamically added inputs wasnt working + +== v1.10.5 (Oct/23 2014 11:41 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing weird cursor problems in weird cases. + +== v1.10.4 (Oct/23 2014 11:02 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing on the fly mask change feature. + +== v1.10.3 (Oct/22 2014 09:50 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing unmask method. + +== v1.10.2 (Oct/20 2014 16:38 +0100 by Igor Escobar) == + +Bugfixes: + +* onChange event fired at the wrong time when the field already has a value. + +== v1.10.1 (Oct/20 2014 16:08 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing onChange event behaviour + +== v1.10.0 (Oct/20 2014 10:56 +0100 by Igor Escobar) == + +Features: + +* adding a way to change global settings like translation object and the byPassKeys object. + +== v1.9.2 (Oct/20 2014 10:08 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing fallback digits implementation. Thanks @A1rPun + +== v1.9.1 (Oct/18 2014 12:27 +0100 by Igor Escobar) == + +Bugfixes: + +* cant convert circular json exception + +== v1.9.0 (Oct/18 2014 12:07 +0100 by Igor Escobar) == + +Features: + +* adding onInvalid callback + +== v1.8.0 (Oct/17 2014 11:35 +0100 by Igor Escobar) == + +Changes: + +* removing automatic maxlength support +* making a few optimizations to make it faster and retro compatible with other libraries +* creating globalOptions to make it more fast and flexible + +Bugfixes: + +* fixing issue #196 + +Features: + +* adding the fallback translation option + +== v1.7.8 (Oct/15 2014 10:55 +0100 by Igor Escobar) == + +Bugfixes: + +* change event may experience issues +* avoid maximum call stack trace error + +== v1.7.7 (Sep/10 2014 22:31 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing clojure compile issue + +== v1.7.6 (Sep/10 2014 22:14 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing clearifnotmatch in masks with literal digits + +== v1.7.5 (Sep/09 2014 15:43 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing paste inside of empty fields. + +== v1.7.4 (Aug/11 2014 14:53 +0100 by Igor Escobar) == + +Changes: + +* smaller and reliable code + +== v1.7.3 (Aug/11 2014 11:28 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing issue #185 + +== v1.7.2 (Aug/08 2014 11:11 +0100 by Igor Escobar) == + +Changes: + +* smaller code + +Bugfixes: + +* fixing remove bug + +== v1.7.1 (Aug/08 2014 00:55 +0100 by Igor Escobar) == + +Changes: + +* upgrading zepto, smaller syntax and fixing build + +== v1.7.0 (Aug/07 2014 23:56 +0100 by Igor Escobar) == + +Features: + +* applying masks to dynamically added elements. (html/javascript notation) + +== v1.6.5 (Jun/30 2014 10:24 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing clearIfNotMatch feature in cases of optional and recursive digits + +== v1.6.4 (May/08 2014 23:54 +0100 by Igor Escobar) == + +Changes: + +* testing some deployment stunts + +== v1.6.3 (May/08 2014 23:51 +0100 by Igor Escobar) == + +Changes: + +* testing some deployment stunts + +== v1.6.2 (May/08 2014 23:45 +0100 by Igor Escobar) == + +Bugfixes: + +* fuckin typo + +== v1.6.1 (May/08 2014 23:39 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing autofocus bug + +== v1.6.0 (May/07 2014 21:13 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing autofocus bug + +Features: + +* adding support to the clearIfNotMatch option +* HTML5 placeholder support + +== v1.5.7 (May/01 2014 18:37 +0100 by Igor Escobar) == + +Changes: + +* some cleanup and stuff + +== v1.5.6 (May/01 2014 18:30 +0100 by Igor Escobar) == + +Bugfixes: + +* Bug in calculating difference between mask characters between old and new field values +* Fix stack limit exceeded + +== v1.5.5 (Apr/27 2014 13:47 +0100 by Igor Escobar) == + +Changes: + +* UMD (Universal Module Definition) patterns for JavaScript modules + +Bugfixes: + +* caret position correction +* 114 - Fix onChange Event error + +== v1.5.4 (Feb/09 2014 12:02 +0000 by Igor Escobar) == + +Changes: + +* optmizing code + +== v1.5.3 (Feb/08 2014 14:59 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing ctrl a bug + +== v1.5.2 (Dec/20 2013 16:35 +0000 by Igor Escobar) == + +Changes: + +* smaller source code + +== v1.5.1 (Dec/18 2013 22:34 +0000 by Igor Escobar) == + +Changes: + +* fixing some code climate problems + +== v1.5.0 (Dec/18 2013 22:10 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing getCleanVal() + +Features: + +* new public method called cleanVal + +== v1.4.2 (Dec/16 2013 15:48 +0000 by Igor Escobar) == + +Bugfixes: + +* Dirty fix for masks not completing with a literal + +== v1.4.1 (Dec/09 2013 21:23 +0000 by Igor Escobar) == + +Changes: + +* revising ignored keys + +== v1.4.0 (Nov/28 2013 18:06 +0000 by Igor Escobar) == + +Features: + +* caret positioning implementation + +== v1.3.1 (Oct/08 2013 20:38 +0100 by Igor Escobar) == + +Changes: + +* adding more keys to ignore list to make the char navigation smoothly + +Bugfixes: + +* Sounds like 'options' has disappeared for some reason + +== v1.3.0 (Sep/13 2013 10:37 +0100 by Igor Escobar) == + +Features: + +* creating the maxlength option + +== v1.2.0 (Sep/07 2013 12:07 +0100 by Igor Escobar) == + +Features: + +* adding the possibility to put recursive digits inside masks + +== v1.1.3 (Sep/04 2013 21:21 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing late masking + +== v1.1.2 (Aug/26 2013 15:08 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing mask on div,span etc + +== v1.1.1 (Aug/26 2013 14:42 +0100 by Igor Escobar) == + +Bugfixes: + +* better callback handling + +== v1.1.0 (Aug/24 2013 15:59 +0100 by Igor Escobar) == + +Features: + +* adding onchange support + +== v1.0.3 (Aug/23 2013 23:10 +0100 by Igor Escobar) == + +Changes: + +* optimizations to mask on non html fields + +== v1.0.2 (Aug/23 2013 22:46 +0100 by Igor Escobar) == + +Bugfixes: + +* adding remask method do improve callback performance + +== v1.0.1 (Aug/23 2013 22:01 +0100 by Igor Escobar) == + +Changes: + +* normal releases again + +== v1.0.0 (Aug/23 2013 21:59 +0100 by Igor Escobar) == + +Features: + +* huge refactoring focusing no reduce source code weight and bugfixing + +== v0.11.5 (Aug/20 2013 17:11 +0100 by Igor Escobar) == + +Bugfixes: + +* bug fixing when mask range is bigger than 2 digits. + +== v0.11.4 (Aug/19 2013 10:24 +0100 by Igor Escobar) == + +Changes: + +* adding de delete key to byPassKeys + +== v0.11.3 (Aug/18 2013 00:48 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing zepto compatibily + +== v0.11.2 (Aug/17 2013 18:39 +0100 by Igor Escobar) == + +Bugfixes: + +* jmask iterate all items + +== v0.11.1 (Aug/17 2013 18:32 +0100 by Igor Escobar) == + +Changes: + +* a little bit smaller source code + +== v0.11.0 (Aug/16 2013 21:27 +0100 by Igor Escobar) == + +Bugfixes: + +* Altered "ignored keys" hook to run events (i.e. onKeyPress) afterwards. Otherwise, we miss key triggered events when the user deletes the entire text box, etc. + +Features: + +* adding support to method getCleanVal + +== v0.10.1 (Jul/26 2013 09:35 +0100 by ) == + + + +== v0.10.0 (Jul/19 2013 23:07 +0100 by Igor Escobar) == + +Features: + +* adding data-mask support + +== v0.9.1 (Jul/19 2013 22:35 +0100 by Igor Escobar) == + +Changes: + +* jQuery-Mask-Plugin is now available at bower.io + +Bugfixes: + +* fixing addEventListener on IE7 + +== v0.9.0 (Apr/24 2013 07:44 +0100 by Igor Escobar) == + +Features: + +* Adding compatibility with Zepto.js + +== v0.8.0 (Apr/07 2013 18:39 +0100 by Igor Escobar) == + +Features: + +* applying masks anything != than input :) +* implementing the possibility of range chars ex: A{1,3} + +== v0.7.11 (Apr/05 2013 22:12 +0100 by Igor Escobar) == + +Changes: + +* now when you type a wrong char, the plugin will make your text fit inside of the mask instead of lose your data. + +== v0.7.10 (Apr/04 2013 22:14 +0100 by Igor Escobar) == + +Changes: + +* changing yui-compressor to clojure-compiler + +== v0.7.9 (Apr/04 2013 22:04 +0100 by Igor Escobar) == + +Changes: + +* refactoring and implementation of optional mask digits + +Bugfixes: + +* fixing maxlength and adding a smarter mask removal. issue #18 + +== v0.7.8 (Mar/30 2013 00:48 +0000 by Igor Escobar) == + +Changes: + +* a few changes to get the code smallest possible. +* removing unnecessary methods and making code smaller. + +== v0.7.7 (Mar/29 2013 12:38 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing copy and paste problem related on issue #15 + +== v0.7.6 (Mar/29 2013 00:28 +0000 by Igor Escobar) == + +Bugfixes: + +* correcting mask formatationg problem related on issue #16 + +== v0.7.5 (Mar/03 2013 20:56 +0000 by Igor Escobar) == + +Changes: + +* generating .gz file on deploy + +== v0.7.4 (Mar/03 2013 20:38 +0000 by Igor Escobar) == + +Changes: + +* changing minifier jsmin to yui compressor. + +== v0.7.3 (Mar/02 2013 01:12 +0000 by Igor Escobar) == + +Bugfixes: + +* bug fixing when typed wrong data type on mixing masks. + +== v0.7.2 (Feb/24 2013 22:02 +0000 by Igor Escobar) == + +Bugfixes: + +* fuckin stupid comma. + +== v0.7.1 (Feb/24 2013 21:57 +0000 by Igor Escobar) == + +Changes: + +* testing the private method maskToRegex +* a little bit of changes to make the code more testable + +== v0.7.0 (Feb/12 2013 00:30 +0000 by Igor Escobar) == + +Features: + +* Now you can decide for jquery mask plugin how to interpret 0 to 9, A and S and even teach him how to reconize patterns. + +== v0.6.3 (Feb/11 2013 12:20 +0000 by Igor Escobar) == + +Bugfixes: + +* When the user paste a text and the last char is valid sanitize may fail + +== v0.6.2 (Feb/11 2013 00:02 +0000 by Igor Escobar) == + +Bugfixes: + +* allowing the user type the same character as the mask without erasing it. + +== v0.6.1 (Jan/20 2013 23:57 +0000 by Igor Escobar) == + +Changes: + +* changing the way ta deployment occurs to correct jquery plugins deployments. + +== v0.6.0 (Jan/18 2013 17:19 +0000 by Igor Escobar) == + +Changes: + +* Now pushing jQuery Mask Plugin to jQuery Plugins Repository + +== v0.5.4 (Jan/17 2013 23:06 +0000 by Igor Escobar) == + +Changes: + +* upgrading jquery plugins manifest file + +== v0.5.3 (Jan/17 2013 22:48 +0000 by Igor Escobar) == + +Bugfixes: + +* correctly generating jmask version inside of jquery mask source + +== v0.5.2 (Jan/17 2013 22:43 +0000 by Igor Escobar) == + +Changes: + +* Now pushing to jQuery Plugin Repository + +== v0.5.1 (Jan/07 2013 23:33 +0000 by Igor Escobar) == + +Changes: + +* improving the deploy process with the new stepup's upgrade. + +== v0.5.0 (Oct/27 2012 13:40 +0100 by Igor Escobar) == + +Bugfixes: + +* Bug fixes on OnSupport method with Firefox. + +Features: + +* the first parameter of the .mask() function, now accepts a string or a anonymous function + +== v0.4.7 (Aug/06 2012 22:56 +0100 by Igor Escobar) == + +Changes: + +* Nothing big, just class refactoring + +== v0.4.6 (Aug/06 2012 01:25 +0100 by Igor Escobar) == + +Changes: + +- better OOP design +- implementing the jquery data object on each mask field +- implementing the public method .remove to disable and remove the mask + +== v0.4.5 (Aug/04 2012 01:31 +0100 by Igor Escobar) == + +Changes: + +- improving support to complex jquery selectors +- performance improvement. +- callback handling improvement + +== v0.4.4 (Jun/03 2012 21:01 +0100 by Igor Escobar) == + +Bugfixes: + +* Bug fixes on Internet Explorer 8. + +== v0.4.3 (Mar/19 2012 21:52 +0000 by Igor Escobar) == + +Bugfixes: + +* Corrigindo bug para mascaras com + + +== v0.4.2 (Mar/18 2012 15:28 +0000 by Igor Escobar) == + +Bugfixes: + +* Mascara não pararecia no firefox + +== v0.4.1 (Mar/18 2012 15:01 +0000 by Igor Escobar) == + +Bugfixes: + +* Corrigindo tim das macaras. + +== v0.4.0 (Mar/18 2012 14:51 +0000 by Igor Escobar) == + +Features: + +* Implementado mascara reversa para moeda/cpf/rg/etc. +* Nova engine. + +== v0.3.0 (Mar/14 2012 10:14 +0000 by Igor Escobar) == + +Changes: + +* License and comments up to date. + +Features: + +* On-the-fly mask change. +* onComplete and onKeyPress new callbacks. + +== v0.2.5 (Mar/13 2012 22:55 +0000 by Igor Escobar) == + +Bugfixes: + +- Corrigindo ctrl+v com mascara errada. - Cortando dados que exceder a mascara no ctrl+v ou se segurar alguma tecla. - Refatorando algumas partes do código. + +== v0.2.4 (Mar/13 2012 11:06 +0000 by Igor Escobar) == + +Changes: + +* Codigo refatorado, otimizado, validação mais precisa e efetiva. + +== v0.2.3 (Mar/13 2012 01:01 +0000 by Igor Escobar) == + +Changes: + +* Melhorando expressoes regulares. + +== v0.2.2 (Mar/13 2012 00:50 +0000 by Igor Escobar) == + +Bugfixes: + +* Corrindo regex de validação + +== v0.2.1 (Mar/13 2012 00:41 +0000 by Igor Escobar) == + +Bugfixes: + +* Corrigida validação alphanumerica. + +== v0.2.0 (Mar/13 2012 00:24 +0000 by Igor Escobar) == + +Features: + +- Input Data Type Validation. +- Automatic MaxLength (When are not defined). +- Live Event Implemented for Ajax-based Apps. +- Mixed mask with validation. +* S for string digit +* A for alphanumeric digit +* 0 to 9 for numeric digit. + +== v0.1.1 (Mar/10 2012 14:05 +0000 by Igor Escobar) == + +Bugfixes: + +* Implementando Crossbrowser event handling. + +== v0.1.0 (Mar/10 2012 13:10 +0000 by Igor Escobar) == + +Features: + +* Implementando mascaras com espaço para data e hora + +== v0.0.1 (Mar/10 2012 04:42 +0000 by Igor Escobar) == + +Changes: + +* Refatorando o codigo para suportar multiplas instancias diff --git a/js/jquery-mask/CONTRIBUTING.md b/js/jquery-mask/CONTRIBUTING.md new file mode 100755 index 0000000000..65367176c1 --- /dev/null +++ b/js/jquery-mask/CONTRIBUTING.md @@ -0,0 +1,9 @@ +### Have you take a look into our docs? +https://igorescobar.github.io/jQuery-Mask-Plugin/ + +### Want to contribute? Make sure you read this first +https://github.com/igorescobar/jQuery-Mask-Plugin#contributing + +Is this plugin helping you out? Buy me a beer and cheers! :beer: + +:bowtie: https://www.paypal.me/igorcescobar diff --git a/js/jquery-mask/Dockerfile b/js/jquery-mask/Dockerfile new file mode 100755 index 0000000000..db59cb7141 --- /dev/null +++ b/js/jquery-mask/Dockerfile @@ -0,0 +1,36 @@ +FROM phusion/baseimage:0.9.17 + +# Use baseimage-docker's init system. +CMD ["/sbin/my_init"] + +# Java 8 for Google's clojure compiler +RUN \ + echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \ + echo "deb http://dl.bintray.com/sbt/debian /" | tee -a /etc/apt/sources.list.d/sbt.list && \ + add-apt-repository -y ppa:webupd8team/java && \ + apt-get update && \ + apt-get install -y oracle-java8-installer git unzip ruby-full && \ + rm -rf /var/lib/apt/lists/* && \ + rm -rf /var/cache/oracle-jdk8-installer + +# Define commonly used JAVA_HOME variable +ENV JAVA_HOME /usr/lib/jvm/java-8-oracle + +RUN mkdir /app +RUN mkdir /app/clojure-compiler + +# Clojure compiler +RUN \ + curl -O http://dl.google.com/closure-compiler/compiler-latest.zip && \ + unzip compiler-latest.zip -d /app/clojure-compiler && \ + chmod a+x /app/clojure-compiler && \ + rm compiler-latest.zip + +RUN gem install bundler pry step-up --no-rdoc --no-ri + +# Install Node.js +RUN curl --silent --location https://deb.nodesource.com/setup_0.12 | sudo bash - +RUN apt-get install --yes nodejs + +RUN npm install -g grunt-cli +WORKDIR /app/jquery-mask-plugin diff --git a/js/jquery-mask/Gruntfile.js b/js/jquery-mask/Gruntfile.js new file mode 100755 index 0000000000..e89370fea7 --- /dev/null +++ b/js/jquery-mask/Gruntfile.js @@ -0,0 +1,42 @@ +module.exports = function(grunt) { + require('load-grunt-tasks')(grunt); + require('time-grunt')(grunt); + + grunt.initConfig({ + jshint: { + options: { + jshintrc: '.jshintrc', + reporter: require('jshint-stylish') + }, + all: ['src/{,*/}*.js'] + }, + connect: { + server: { + options: { + port: 9001, + base: './' + } + } + }, + qunit: { + all: { + options: { + urls: [ + 'http://localhost:9001/test/test-for-jquery-1.11.1.html', + 'http://localhost:9001/test/test-for-jquery-1.7.2.html', + 'http://localhost:9001/test/test-for-jquery-1.8.3.html', + 'http://localhost:9001/test/test-for-jquery-1.9.1.html', + 'http://localhost:9001/test/test-for-jquery-2.1.1.html', + 'http://localhost:9001/test/test-for-jquery-3.0.0.html', + 'http://localhost:9001/test/test-for-zepto.html' + ] + } + } + } + }); + + // A convenient task alias. + grunt.registerTask('test', ['jshint', 'connect', 'qunit']); + grunt.registerTask('default', ['test']); + +}; diff --git a/js/jquery-mask/ISSUE_TEMPLATE.md b/js/jquery-mask/ISSUE_TEMPLATE.md new file mode 100755 index 0000000000..001550aa45 --- /dev/null +++ b/js/jquery-mask/ISSUE_TEMPLATE.md @@ -0,0 +1,22 @@ +### Have you take a look into our docs? +https://igorescobar.github.io/jQuery-Mask-Plugin/ + +### Make sure your read this before opening a new issue: +https://github.com/igorescobar/jQuery-Mask-Plugin#problems-or-questions + +#### Device +[...] + +#### Browser (and version)? +[...] + +#### Functional `jsfiddle` exemplifying your problem: +You can use this one as exemple: http://jsfiddle.net/igorescobar/6pco4om7/ + +#### Describe de problem depth: +[...] + + +Is this plugin helping you out? Buy me a beer and cheers! :beer: + +:bowtie: https://www.paypal.me/igorcescobar diff --git a/js/jquery-mask/LICENSE b/js/jquery-mask/LICENSE new file mode 100755 index 0000000000..49285f3457 --- /dev/null +++ b/js/jquery-mask/LICENSE @@ -0,0 +1,26 @@ + Created by Igor Escobar on 2012-03-10. Please report any bug at http://blog.igorescobar.com + + Copyright (c) 2012 Igor Escobar http://blog.igorescobar.com + + The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/js/jquery-mask/README.md b/js/jquery-mask/README.md new file mode 100755 index 0000000000..144513cbdc --- /dev/null +++ b/js/jquery-mask/README.md @@ -0,0 +1,137 @@ +# jQuery Mask Plugin +A jQuery Plugin to make masks on form fields and HTML elements. + +[![Build Status](https://travis-ci.org/igorescobar/jQuery-Mask-Plugin.png)](https://travis-ci.org/igorescobar/jQuery-Mask-Plugin) +[![Code Climate](https://codeclimate.com/github/igorescobar/jQuery-Mask-Plugin.png)](https://codeclimate.com/github/igorescobar/jQuery-Mask-Plugin) +[![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/jquery-mask-plugin/badge?style=rounded)](https://www.jsdelivr.com/package/npm/jquery-mask-plugin) +[![CDNJS](https://img.shields.io/cdnjs/v/jquery.mask.svg)](https://cdnjs.com/libraries/jquery.mask) + +# Documentation, Demos & Usage Examples +https://igorescobar.github.io/jQuery-Mask-Plugin/ + +## Features + + * Lightweight (~2kb minified, ~1kb gziped). + * Built-in support for dynamically added elements. + * Masks on any HTML element (no need to server-side mask anymore!)! + * HTML notation support (data-mask, data-mask-recursive, data-mask-clearifnotmatch). + * String/Numeric/Alpha/Mixed masks. + * Reverse mask support for masks on numeric fields. + * Sanitization. + * Optional digits. + * Recursive Digits. + * Fallback Digits. + * Advanced mask initialization. + * Advanced Callbacks. + * On-the-fly mask change. + * Mask removal. + * Full customization. + * Compatibility with React/UMD/Zepto.js/Angular.JS. + * HTML5 placeholder support. + * Clear the field if it not matches support. + +## Want to buy me a beer? :heart_eyes: +http://paypal.me/igorcescobar + +## Install it via Package Managers +### Bower +`bower install jquery-mask-plugin` +### NPM +`npm i jquery-mask-plugin` +### Meteor +`meteor add igorescobar:jquery-mask-plugin` +### Packagist/Composer +`composer require igorescobar/jquery-mask-plugin` + +## CDNs +### CDNjs +https://cdnjs.com/libraries/jquery.mask +### JSDelivr +http://www.jsdelivr.com/projects/jquery.mask + +## RubyGems +```ruby +gem 'jquery_mask_rails' # more details at http://bit.ly/jquery-mask-gem +``` + +## Tutorials +### English + * [Masks with jQuery Mask Plugin](http://bit.ly/masks-with-jquery-mask-plugin) + * [Using jQuery Mask Plugin With Zepto.js](http://bit.ly/using-jquery-mask-plugin-with-zeptojs) + +### Portuguese + * [Mascaras com JQuery Mask Plugin](http://bit.ly/mascaras-com-jquery-mask-plugin) + * [Mascara Javascript para os novos telefones de São Paulo](http://bit.ly/mascara-javascript-para-os-novos-telefones-de-sao-paulo) + +### Fun (or not) facts + * [I’ve had the chance to troll Donald Trump. But I didn’t.](http://www.igorescobar.com/blog/2016/08/21/ive-the-chance-to-troll-donald-trump-but-i-didnt/) + +## Compatibility +jQuery Mask Plugin has been tested with jQuery 1.7+ on all major browsers: + + * Firefox 2+ (Win, Mac, Linux); + * IE7+ (Win); + * Chrome 6+ (Win, Mac, Linux, Android, iPhone); + * Safari 3.2+ (Win, Mac, iPhone); + * Opera 8+ (Win, Mac, Linux, Android, iPhone). + * Android Default Browser v4+ + +## Typescript support +Definition can be found [here](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/jquery-mask-plugin). + +To install, open terminal and navigate to your working directory. + +### Typescript 1.x users + * Install [typings](https://github.com/typings/typings) by running `npm install typings --global`. + * Then install the definition by running `typings install dt~jquery-mask-plugin --global --save`. +### Typescript 2.x users + * Use npm `npm install --save-dev @types/jquery-mask-plugin`. + +For configuration options and troubleshooting refer to these repositories: +* [Typings](https://github.com/typings/typings) +* [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) +* [Typescript](https://github.com/Microsoft/TypeScript) + + +## Problems or Questions? +Before opening a new [issue](https://github.com/igorescobar/jQuery-Mask-Plugin/issues) take a look on those frequently asked questions: +#### [How to integrate with React.js?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/498) +#### [How to integrate with Angular.js?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/499) +#### [How to integrate with Vue.js?](https://github.com/ankurk91/vue-jquery-mask) +#### [Problems with old versions of Android keyboard](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/135) +#### [Negative numbers, or currency related problems](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/436#issuecomment-253176511) +#### [Prefix or sufix on the Mask](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/166) +#### [Add validation?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/387#issuecomment-192998092) +#### [Field type number, email not working?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/450#issuecomment-253225719) +#### [Want to keep the placeholder as the user types?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/633#issuecomment-350819224) +#### [E-mail mask?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/582) + +## Bugs? +Did you read our [docs](https://igorescobar.github.io/jQuery-Mask-Plugin/docs.html)? Yes? Cool! So now... make sure that you have a *functional* [jsfiddle](http://jsfiddle.net/) exemplifying your problem and open an [issue](https://github.com/igorescobar/jQuery-Mask-Plugin/issues) for us. Don't know how to do it? Use this [fiddle example](http://jsfiddle.net/igorescobar/6pco4om7/). + +## Contributing + * **Bug Reporting**: Yes! You can contribute opening [issues](https://github.com/igorescobar/jQuery-Mask-Plugin/issues)! + * **Documenting**: Do you think that something in our [docs](https://github.com/igorescobar/jQuery-Mask-Plugin/tree/gh-pages) should be better? Do you have a cool idea to increase the awesomeness? Summit your pull request with your idea! + * **Bug Fixing**: No time to lose? Fix it and help others! Write some [tests](https://github.com/igorescobar/jQuery-Mask-Plugin/tree/master/test) to make sure that everything are working propertly. + * **Improving**: Open an [issue](https://github.com/igorescobar/jQuery-Mask-Plugin/issues) and lets discuss it. Just to make sure that you're on the right track. + * **Sharing**: Yes! Have we saved some of your time? Are you enjoying our mask plugin? Sharing is caring! Tweet it! Facebook it! Linkedin It(?!) :D + * **Donating**: Hey, now that you don't need to worry about masks again... buy me a coffee, beer or a PlayStation 4 (Xbox One also accepted!) :o) + +### Unit Tests +We use [QUnit](http://qunitjs.com/) and [GruntJS](http://gruntjs.com/). To run our test suit is just run: ```grunt test``` in your console or you can open those ```test-for*.html``` files inside of our ```test/``` folder. + +In case you're familiar with [Docker](https://www.docker.com/) here is how you can use it: +```bash +docker build -t jquery-mask . +CONTAINER_ID=$(docker run -d -v $PWD:/app/jquery-mask-plugin jquery-mask) +docker exec $CONTAINER_ID sh -c "npm install" +docker exec -it $CONTAINER_ID /bin/bash +grunt test +``` + +## Contributors + * [Igor Lima](https://github.com/igorlima) + * [Mark Simmons](https://github.com/Markipelago) + * [Gabriel Schammah](https://github.com/gschammah) + * [Marcelo Manzan](https://github.com/kawamanza) + * [See the full list](https://github.com/igorescobar/jQuery-Mask-Plugin/graphs/contributors) diff --git a/js/jquery-mask/bower.json b/js/jquery-mask/bower.json new file mode 100755 index 0000000000..1ec7ea6f90 --- /dev/null +++ b/js/jquery-mask/bower.json @@ -0,0 +1,12 @@ +{ + "name": "jquery-mask-plugin", + "version": "1.14.16", + "main": "dist/jquery.mask.js", + "ignore": [ + "deploy.rb", + "jquery.mask.json", + "Gruntfile.js", + "test/*", + ".*" + ] +} diff --git a/js/jquery-mask/component.json b/js/jquery-mask/component.json new file mode 100755 index 0000000000..d8263ef0dd --- /dev/null +++ b/js/jquery-mask/component.json @@ -0,0 +1,10 @@ +{ + "name": "jQuery-Mask-Plugin", + "description": "A jQuery Plugin to make masks on form fields and HTML elements.", + "version": "1.14.16", + "keywords": ["javascript", "mask", "form"], + "scripts": [ + "dist/jquery.mask.js" + ], + "main": "dist/jquery.mask.js" +} diff --git a/js/jquery-mask/composer.json b/js/jquery-mask/composer.json new file mode 100755 index 0000000000..f9a7541017 --- /dev/null +++ b/js/jquery-mask/composer.json @@ -0,0 +1,19 @@ +{ + "name": "igorescobar/jquery-mask-plugin", + "type": "library", + "description": "A jQuery Plugin to make masks on form fields and html elements.", + "keywords": ["jquery", "mask", "plugin"], + "homepage": "https://github.com/igorescobar/jQuery-Mask-Plugin", + "license": "MIT", + "authors": [ + { + "name": "Igor Escobar", + "email": "blog@igorescobar.com", + "homepage": "https://about.me/igorescobar", + "role": "Developer" + } + ], + "support": { + "issues": "https://github.com/igorescobar/jQuery-Mask-Plugin/issues" + } +} diff --git a/js/jquery-mask/deploy.rb b/js/jquery-mask/deploy.rb new file mode 100755 index 0000000000..acfbc78356 --- /dev/null +++ b/js/jquery-mask/deploy.rb @@ -0,0 +1,77 @@ +require 'rubygems' +require 'zlib' + +JMASK_FILE = 'src/jquery.mask.js' +JMASK_MIN_FILE = 'dist/jquery.mask.min.js' +GHPAGES_JMASK_MIN_FILE = 'js/jquery.mask.min.js' +JMASK_VERSION = `stepup version --next-release`.delete("\n") +BOWER_MANIFEST_FILE = 'bower.json' +NPM_MANIFEST_FILE = 'package.json' +METEOR_MANIFEST_FILE = 'package.js' +COMPONENT_MANIFEST_FILE = 'component.json' + +abort("No notes, do deal.") if JMASK_VERSION.empty? + +puts '# PUTTING NEW VERSION INSIDE OF JQUERY MASK FILE' +unversioned_jmask_file = File.open(JMASK_FILE, 'rb') { |file| file.read } +File.open(JMASK_FILE, 'w') do |file| + file.write(unversioned_jmask_file.gsub(/\* @version: (v[0-9.+]+)/, "\* @version: #{JMASK_VERSION}")) +end + +puts '# COPYING NEW JMASK FILE TO DIST/' +`yes | cp #{JMASK_FILE} dist/` + +[BOWER_MANIFEST_FILE, NPM_MANIFEST_FILE, COMPONENT_MANIFEST_FILE, METEOR_MANIFEST_FILE].each { |manifest_name| + puts "# UPGRADING #{manifest_name} " + manifest_file = File.open(manifest_name, 'rb') { |file| file.read } + File.open(manifest_name, 'w') do |file| + file.write(manifest_file.gsub(/"version": "([0-9.+]+)"/, "\"version\": \"#{JMASK_VERSION.gsub("v", "")}\"")) + end +} + +puts '# GENERATING MIN FILE' +jquery_mask_min_file = nil +File.open(JMASK_FILE, 'r') do |file| + minFile = File.open(JMASK_MIN_FILE, 'w') + minFile.puts("// jQuery Mask Plugin #{JMASK_VERSION}") + minFile.puts("// github.com/igorescobar/jQuery-Mask-Plugin") + jquery_mask_min_file = `java -jar ../clojure-compiler/compiler.jar --js src/jquery.mask.js --charset UTF-8` + minFile.puts(jquery_mask_min_file) + minFile.close +end + +puts '# GENERATING A NEW COMMIT WITH VERSIONED FILEs' +`git commit -am 'generating jquery mask files #{JMASK_VERSION}'` + +puts '# PUSHING CHANGES TO REMOTE' +`git pull --rebase && git push` + +puts '# CREATING NEW VERSION' +`stepup version create --no-editor` + +puts '# UPGRATING CHANGELOG' +`stepup changelog --format=wiki > CHANGELOG.md` +`git commit -am "upgrading changelog"` +`git push` + +puts '# UPGRADING gh-pages' +`git checkout gh-pages` +`git pull origin gh-pages` + +minFile = File.open(GHPAGES_JMASK_MIN_FILE, 'w') +minFile.puts("// jQuery Mask Plugin #{JMASK_VERSION}") +minFile.puts("// github.com/igorescobar/jQuery-Mask-Plugin") +minFile.puts(jquery_mask_min_file) +minFile.close + +`git commit -am "upgrading plugin file"` +`git push` +`git checkout master` + +puts '# PUBLISHING NPM PACKAGE' +`npm publish` + +puts '# PUBLISHING METEOR PACKAGE' +`meteor publish` + +puts '# DONE!' diff --git a/js/jquery-mask/dist/jquery.mask.js b/js/jquery-mask/dist/jquery.mask.js new file mode 100755 index 0000000000..7e0216cbc6 --- /dev/null +++ b/js/jquery-mask/dist/jquery.mask.js @@ -0,0 +1,604 @@ +/** + * jquery.mask.js + * @version: v1.14.16 + * @author: Igor Escobar + * + * Created by Igor Escobar on 2012-03-10. Please report any bug at github.com/igorescobar/jQuery-Mask-Plugin + * + * Copyright (c) 2012 Igor Escobar http://igorescobar.com + * + * The MIT License (http://www.opensource.org/licenses/mit-license.php) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* jshint laxbreak: true */ +/* jshint maxcomplexity:17 */ +/* global define */ + +// UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere. +// https://github.com/umdjs/umd/blob/master/templates/jqueryPlugin.js +(function (factory, jQuery, Zepto) { + + if (typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } else if (typeof exports === 'object' && typeof Meteor === 'undefined') { + module.exports = factory(require('jquery')); + } else { + factory(jQuery || Zepto); + } + +}(function ($) { + 'use strict'; + + var Mask = function (el, mask, options) { + + var p = { + invalid: [], + getCaret: function () { + try { + var sel, + pos = 0, + ctrl = el.get(0), + dSel = document.selection, + cSelStart = ctrl.selectionStart; + + // IE Support + if (dSel && navigator.appVersion.indexOf('MSIE 10') === -1) { + sel = dSel.createRange(); + sel.moveStart('character', -p.val().length); + pos = sel.text.length; + } + // Firefox support + else if (cSelStart || cSelStart === '0') { + pos = cSelStart; + } + + return pos; + } catch (e) {} + }, + setCaret: function(pos) { + try { + if (el.is(':focus')) { + var range, ctrl = el.get(0); + + // Firefox, WebKit, etc.. + if (ctrl.setSelectionRange) { + ctrl.setSelectionRange(pos, pos); + } else { // IE + range = ctrl.createTextRange(); + range.collapse(true); + range.moveEnd('character', pos); + range.moveStart('character', pos); + range.select(); + } + } + } catch (e) {} + }, + events: function() { + el + .on('keydown.mask', function(e) { + el.data('mask-keycode', e.keyCode || e.which); + el.data('mask-previus-value', el.val()); + el.data('mask-previus-caret-pos', p.getCaret()); + p.maskDigitPosMapOld = p.maskDigitPosMap; + }) + .on($.jMaskGlobals.useInput ? 'input.mask' : 'keyup.mask', p.behaviour) + .on('paste.mask drop.mask', function() { + setTimeout(function() { + el.keydown().keyup(); + }, 100); + }) + .on('change.mask', function(){ + el.data('changed', true); + }) + .on('blur.mask', function(){ + if (oldValue !== p.val() && !el.data('changed')) { + el.trigger('change'); + } + el.data('changed', false); + }) + // it's very important that this callback remains in this position + // otherwhise oldValue it's going to work buggy + .on('blur.mask', function() { + oldValue = p.val(); + }) + // select all text on focus + .on('focus.mask', function (e) { + if (options.selectOnFocus === true) { + $(e.target).select(); + } + }) + // clear the value if it not complete the mask + .on('focusout.mask', function() { + if (options.clearIfNotMatch && !regexMask.test(p.val())) { + p.val(''); + } + }); + }, + getRegexMask: function() { + var maskChunks = [], translation, pattern, optional, recursive, oRecursive, r; + + for (var i = 0; i < mask.length; i++) { + translation = jMask.translation[mask.charAt(i)]; + + if (translation) { + + pattern = translation.pattern.toString().replace(/.{1}$|^.{1}/g, ''); + optional = translation.optional; + recursive = translation.recursive; + + if (recursive) { + maskChunks.push(mask.charAt(i)); + oRecursive = {digit: mask.charAt(i), pattern: pattern}; + } else { + maskChunks.push(!optional && !recursive ? pattern : (pattern + '?')); + } + + } else { + maskChunks.push(mask.charAt(i).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')); + } + } + + r = maskChunks.join(''); + + if (oRecursive) { + r = r.replace(new RegExp('(' + oRecursive.digit + '(.*' + oRecursive.digit + ')?)'), '($1)?') + .replace(new RegExp(oRecursive.digit, 'g'), oRecursive.pattern); + } + + return new RegExp(r); + }, + destroyEvents: function() { + el.off(['input', 'keydown', 'keyup', 'paste', 'drop', 'blur', 'focusout', ''].join('.mask ')); + }, + val: function(v) { + var isInput = el.is('input'), + method = isInput ? 'val' : 'text', + r; + + if (arguments.length > 0) { + if (el[method]() !== v) { + el[method](v); + } + r = el; + } else { + r = el[method](); + } + + return r; + }, + calculateCaretPosition: function(oldVal) { + var newVal = p.getMasked(), + caretPosNew = p.getCaret(); + if (oldVal !== newVal) { + var caretPosOld = el.data('mask-previus-caret-pos') || 0, + newValL = newVal.length, + oldValL = oldVal.length, + maskDigitsBeforeCaret = 0, + maskDigitsAfterCaret = 0, + maskDigitsBeforeCaretAll = 0, + maskDigitsBeforeCaretAllOld = 0, + i = 0; + + for (i = caretPosNew; i < newValL; i++) { + if (!p.maskDigitPosMap[i]) { + break; + } + maskDigitsAfterCaret++; + } + + for (i = caretPosNew - 1; i >= 0; i--) { + if (!p.maskDigitPosMap[i]) { + break; + } + maskDigitsBeforeCaret++; + } + + for (i = caretPosNew - 1; i >= 0; i--) { + if (p.maskDigitPosMap[i]) { + maskDigitsBeforeCaretAll++; + } + } + + for (i = caretPosOld - 1; i >= 0; i--) { + if (p.maskDigitPosMapOld[i]) { + maskDigitsBeforeCaretAllOld++; + } + } + + // if the cursor is at the end keep it there + if (caretPosNew > oldValL) { + caretPosNew = newValL * 10; + } else if (caretPosOld >= caretPosNew && caretPosOld !== oldValL) { + if (!p.maskDigitPosMapOld[caretPosNew]) { + var caretPos = caretPosNew; + caretPosNew -= maskDigitsBeforeCaretAllOld - maskDigitsBeforeCaretAll; + caretPosNew -= maskDigitsBeforeCaret; + if (p.maskDigitPosMap[caretPosNew]) { + caretPosNew = caretPos; + } + } + } + else if (caretPosNew > caretPosOld) { + caretPosNew += maskDigitsBeforeCaretAll - maskDigitsBeforeCaretAllOld; + caretPosNew += maskDigitsAfterCaret; + } + } + return caretPosNew; + }, + behaviour: function(e) { + e = e || window.event; + p.invalid = []; + + var keyCode = el.data('mask-keycode'); + + if ($.inArray(keyCode, jMask.byPassKeys) === -1) { + var newVal = p.getMasked(), + caretPos = p.getCaret(), + oldVal = el.data('mask-previus-value') || ''; + + // this is a compensation to devices/browsers that don't compensate + // caret positioning the right way + setTimeout(function() { + p.setCaret(p.calculateCaretPosition(oldVal)); + }, $.jMaskGlobals.keyStrokeCompensation); + + p.val(newVal); + p.setCaret(caretPos); + return p.callbacks(e); + } + }, + getMasked: function(skipMaskChars, val) { + var buf = [], + value = val === undefined ? p.val() : val + '', + m = 0, maskLen = mask.length, + v = 0, valLen = value.length, + offset = 1, addMethod = 'push', + resetPos = -1, + maskDigitCount = 0, + maskDigitPosArr = [], + lastMaskChar, + check; + + if (options.reverse) { + addMethod = 'unshift'; + offset = -1; + lastMaskChar = 0; + m = maskLen - 1; + v = valLen - 1; + check = function () { + return m > -1 && v > -1; + }; + } else { + lastMaskChar = maskLen - 1; + check = function () { + return m < maskLen && v < valLen; + }; + } + + var lastUntranslatedMaskChar; + while (check()) { + var maskDigit = mask.charAt(m), + valDigit = value.charAt(v), + translation = jMask.translation[maskDigit]; + + if (translation) { + if (valDigit.match(translation.pattern)) { + buf[addMethod](valDigit); + if (translation.recursive) { + if (resetPos === -1) { + resetPos = m; + } else if (m === lastMaskChar && m !== resetPos) { + m = resetPos - offset; + } + + if (lastMaskChar === resetPos) { + m -= offset; + } + } + m += offset; + } else if (valDigit === lastUntranslatedMaskChar) { + // matched the last untranslated (raw) mask character that we encountered + // likely an insert offset the mask character from the last entry; fall + // through and only increment v + maskDigitCount--; + lastUntranslatedMaskChar = undefined; + } else if (translation.optional) { + m += offset; + v -= offset; + } else if (translation.fallback) { + buf[addMethod](translation.fallback); + m += offset; + v -= offset; + } else { + p.invalid.push({p: v, v: valDigit, e: translation.pattern}); + } + v += offset; + } else { + if (!skipMaskChars) { + buf[addMethod](maskDigit); + } + + if (valDigit === maskDigit) { + maskDigitPosArr.push(v); + v += offset; + } else { + lastUntranslatedMaskChar = maskDigit; + maskDigitPosArr.push(v + maskDigitCount); + maskDigitCount++; + } + + m += offset; + } + } + + var lastMaskCharDigit = mask.charAt(lastMaskChar); + if (maskLen === valLen + 1 && !jMask.translation[lastMaskCharDigit]) { + buf.push(lastMaskCharDigit); + } + + var newVal = buf.join(''); + p.mapMaskdigitPositions(newVal, maskDigitPosArr, valLen); + return newVal; + }, + mapMaskdigitPositions: function(newVal, maskDigitPosArr, valLen) { + var maskDiff = options.reverse ? newVal.length - valLen : 0; + p.maskDigitPosMap = {}; + for (var i = 0; i < maskDigitPosArr.length; i++) { + p.maskDigitPosMap[maskDigitPosArr[i] + maskDiff] = 1; + } + }, + callbacks: function (e) { + var val = p.val(), + changed = val !== oldValue, + defaultArgs = [val, e, el, options], + callback = function(name, criteria, args) { + if (typeof options[name] === 'function' && criteria) { + options[name].apply(this, args); + } + }; + + callback('onChange', changed === true, defaultArgs); + callback('onKeyPress', changed === true, defaultArgs); + callback('onComplete', val.length === mask.length, defaultArgs); + callback('onInvalid', p.invalid.length > 0, [val, e, el, p.invalid, options]); + } + }; + + el = $(el); + var jMask = this, oldValue = p.val(), regexMask; + + mask = typeof mask === 'function' ? mask(p.val(), undefined, el, options) : mask; + + // public methods + jMask.mask = mask; + jMask.options = options; + jMask.remove = function() { + var caret = p.getCaret(); + if (jMask.options.placeholder) { + el.removeAttr('placeholder'); + } + if (el.data('mask-maxlength')) { + el.removeAttr('maxlength'); + } + p.destroyEvents(); + p.val(jMask.getCleanVal()); + p.setCaret(caret); + return el; + }; + + // get value without mask + jMask.getCleanVal = function() { + return p.getMasked(true); + }; + + // get masked value without the value being in the input or element + jMask.getMaskedVal = function(val) { + return p.getMasked(false, val); + }; + + jMask.init = function(onlyMask) { + onlyMask = onlyMask || false; + options = options || {}; + + jMask.clearIfNotMatch = $.jMaskGlobals.clearIfNotMatch; + jMask.byPassKeys = $.jMaskGlobals.byPassKeys; + jMask.translation = $.extend({}, $.jMaskGlobals.translation, options.translation); + + jMask = $.extend(true, {}, jMask, options); + + regexMask = p.getRegexMask(); + + if (onlyMask) { + p.events(); + p.val(p.getMasked()); + } else { + if (options.placeholder) { + el.attr('placeholder' , options.placeholder); + } + + // this is necessary, otherwise if the user submit the form + // and then press the "back" button, the autocomplete will erase + // the data. Works fine on IE9+, FF, Opera, Safari. + if (el.data('mask')) { + el.attr('autocomplete', 'off'); + } + + // detect if is necessary let the user type freely. + // for is a lot faster than forEach. + for (var i = 0, maxlength = true; i < mask.length; i++) { + var translation = jMask.translation[mask.charAt(i)]; + if (translation && translation.recursive) { + maxlength = false; + break; + } + } + + if (maxlength) { + el.attr('maxlength', mask.length).data('mask-maxlength', true); + } + + p.destroyEvents(); + p.events(); + + var caret = p.getCaret(); + p.val(p.getMasked()); + p.setCaret(caret); + } + }; + + jMask.init(!el.is('input')); + }; + + $.maskWatchers = {}; + var HTMLAttributes = function () { + var input = $(this), + options = {}, + prefix = 'data-mask-', + mask = input.attr('data-mask'); + + if (input.attr(prefix + 'reverse')) { + options.reverse = true; + } + + if (input.attr(prefix + 'clearifnotmatch')) { + options.clearIfNotMatch = true; + } + + if (input.attr(prefix + 'selectonfocus') === 'true') { + options.selectOnFocus = true; + } + + if (notSameMaskObject(input, mask, options)) { + return input.data('mask', new Mask(this, mask, options)); + } + }, + notSameMaskObject = function(field, mask, options) { + options = options || {}; + var maskObject = $(field).data('mask'), + stringify = JSON.stringify, + value = $(field).val() || $(field).text(); + try { + if (typeof mask === 'function') { + mask = mask(value); + } + return typeof maskObject !== 'object' || stringify(maskObject.options) !== stringify(options) || maskObject.mask !== mask; + } catch (e) {} + }, + eventSupported = function(eventName) { + var el = document.createElement('div'), isSupported; + + eventName = 'on' + eventName; + isSupported = (eventName in el); + + if ( !isSupported ) { + el.setAttribute(eventName, 'return;'); + isSupported = typeof el[eventName] === 'function'; + } + el = null; + + return isSupported; + }; + + $.fn.mask = function(mask, options) { + options = options || {}; + var selector = this.selector, + globals = $.jMaskGlobals, + interval = globals.watchInterval, + watchInputs = options.watchInputs || globals.watchInputs, + maskFunction = function() { + if (notSameMaskObject(this, mask, options)) { + return $(this).data('mask', new Mask(this, mask, options)); + } + }; + + $(this).each(maskFunction); + + if (selector && selector !== '' && watchInputs) { + clearInterval($.maskWatchers[selector]); + $.maskWatchers[selector] = setInterval(function(){ + $(document).find(selector).each(maskFunction); + }, interval); + } + return this; + }; + + $.fn.masked = function(val) { + return this.data('mask').getMaskedVal(val); + }; + + $.fn.unmask = function() { + clearInterval($.maskWatchers[this.selector]); + delete $.maskWatchers[this.selector]; + return this.each(function() { + var dataMask = $(this).data('mask'); + if (dataMask) { + dataMask.remove().removeData('mask'); + } + }); + }; + + $.fn.cleanVal = function() { + return this.data('mask').getCleanVal(); + }; + + $.applyDataMask = function(selector) { + selector = selector || $.jMaskGlobals.maskElements; + var $selector = (selector instanceof $) ? selector : $(selector); + $selector.filter($.jMaskGlobals.dataMaskAttr).each(HTMLAttributes); + }; + + var globals = { + maskElements: 'input,td,span,div', + dataMaskAttr: '*[data-mask]', + dataMask: true, + watchInterval: 300, + watchInputs: true, + keyStrokeCompensation: 10, + // old versions of chrome dont work great with input event + useInput: !/Chrome\/[2-4][0-9]|SamsungBrowser/.test(window.navigator.userAgent) && eventSupported('input'), + watchDataMask: false, + byPassKeys: [9, 16, 17, 18, 36, 37, 38, 39, 40, 91], + translation: { + '0': {pattern: /\d/}, + '9': {pattern: /\d/, optional: true}, + '#': {pattern: /\d/, recursive: true}, + 'A': {pattern: /[a-zA-Z0-9]/}, + 'S': {pattern: /[a-zA-Z]/} + } + }; + + $.jMaskGlobals = $.jMaskGlobals || {}; + globals = $.jMaskGlobals = $.extend(true, {}, globals, $.jMaskGlobals); + + // looking for inputs with data-mask attribute + if (globals.dataMask) { + $.applyDataMask(); + } + + setInterval(function() { + if ($.jMaskGlobals.watchDataMask) { + $.applyDataMask(); + } + }, globals.watchInterval); +}, window.jQuery, window.Zepto)); diff --git a/js/jquery-mask/dist/jquery.mask.min.js b/js/jquery-mask/dist/jquery.mask.min.js new file mode 100755 index 0000000000..1f22376e7d --- /dev/null +++ b/js/jquery-mask/dist/jquery.mask.min.js @@ -0,0 +1,19 @@ +// jQuery Mask Plugin v1.14.16 +// github.com/igorescobar/jQuery-Mask-Plugin +var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(a,n,f){a instanceof String&&(a=String(a));for(var p=a.length,k=0;kg?h=10*d:e>=h&&e!==g?c.maskDigitPosMapOld[h]||(e=h,h=h-(k-l)-a,c.maskDigitPosMap[h]&&(h=e)):h>e&&(h=h+(l-k)+f)}return h},behaviour:function(d){d= +d||window.event;c.invalid=[];var e=b.data("mask-keycode");if(-1===a.inArray(e,l.byPassKeys)){e=c.getMasked();var h=c.getCaret(),g=b.data("mask-previus-value")||"";setTimeout(function(){c.setCaret(c.calculateCaretPosition(g))},a.jMaskGlobals.keyStrokeCompensation);c.val(e);c.setCaret(h);return c.callbacks(d)}},getMasked:function(a,b){var h=[],f=void 0===b?c.val():b+"",g=0,k=d.length,n=0,p=f.length,m=1,r="push",u=-1,w=0;b=[];if(e.reverse){r="unshift";m=-1;var x=0;g=k-1;n=p-1;var A=function(){return-1< +g&&-1= 1.3.1 < 2" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "http2": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/http2/-/http2-3.3.7.tgz", + "integrity": "sha512-puSi8M8WNlFJm9Pk4c/Mbz9Gwparuj3gO9/RRO5zv6piQ0FY+9Qywp0PdWshYgsMJSalixFY7eC6oPu0zRxLAQ==", + "dev": true + }, + "https-proxy-agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", + "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jshint": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.10.2.tgz", + "integrity": "sha512-e7KZgCSXMJxznE/4WULzybCMNXNAd/bf5TSrvVEq78Q/K8ZwFpmBqQeDtNiHc3l49nV4E/+YeHU/JZjSUIrLAA==", + "dev": true, + "requires": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.11", + "minimatch": "~3.0.2", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x" + } + }, + "jshint-stylish": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/jshint-stylish/-/jshint-stylish-1.0.2.tgz", + "integrity": "sha1-6Z88w0CvsY4qdwL4eY10AMoxRGo=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "log-symbols": "^1.0.0", + "string-length": "^1.0.0", + "text-table": "^0.2.0" + } + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "load-grunt-tasks": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-3.5.2.tgz", + "integrity": "sha1-ByhWEYD9IP+KaSdQWFL8WKrqDIg=", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "multimatch": "^2.0.0", + "pkg-up": "^1.0.0", + "resolve-pkg": "^0.1.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "maxmin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz", + "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "figures": "^1.0.1", + "gzip-size": "^1.0.0", + "pretty-bytes": "^1.0.0" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "~1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "morgan": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", + "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", + "dev": true, + "requires": { + "basic-auth": "~2.0.0", + "debug": "2.6.9", + "depd": "~1.1.2", + "on-finished": "~2.3.0", + "on-headers": "~1.0.1" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multimatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "dev": true, + "requires": { + "array-differ": "^1.0.0", + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "minimatch": "^3.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-ms": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz", + "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=", + "dev": true + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + } + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-up": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", + "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + }, + "plur": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz", + "integrity": "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY=", + "dev": true + }, + "portscanner": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-1.2.0.tgz", + "integrity": "sha1-sUu9olfRTDEPqcwJaCrwLUCWGAI=", + "dev": true, + "requires": { + "async": "1.5.2" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } + } + }, + "pretty-bytes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "meow": "^3.1.0" + } + }, + "pretty-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz", + "integrity": "sha1-QlfCVt8/sLRR1q/6qwIYhBJpgdw=", + "dev": true, + "requires": { + "is-finite": "^1.0.1", + "parse-ms": "^1.0.0", + "plur": "^1.0.0" + } + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "dev": true + }, + "psl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.2.0.tgz", + "integrity": "sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "puppeteer": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.19.0.tgz", + "integrity": "sha512-2S6E6ygpoqcECaagDbBopoSOPDv0pAZvTbnBgUY+6hq0/XDFDOLEMNlHF/SKJlzcaZ9ckiKjKDuueWI3FN/WXw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "extract-zip": "^1.6.6", + "https-proxy-agent": "^2.2.1", + "mime": "^2.0.3", + "progress": "^2.0.1", + "proxy-from-env": "^1.0.0", + "rimraf": "^2.6.1", + "ws": "^6.1.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + } + } + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", + "dev": true + }, + "resolve-pkg": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-0.1.0.tgz", + "integrity": "sha1-AsyZNBDik2livZcWahsHfalyVTE=", + "dev": true, + "requires": { + "resolve-from": "^2.0.0" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + }, + "send": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.1", + "destroy": "~1.0.4", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.3.1" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + } + }, + "serve-static": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", + "dev": true, + "requires": { + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.1" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", + "dev": true + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "requires": { + "spdx-license-ids": "^1.0.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + }, + "string-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", + "integrity": "sha1-VpcPscOFWOnnC3KL894mmsRa36w=", + "dev": true, + "requires": { + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "time-grunt": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/time-grunt/-/time-grunt-1.4.0.tgz", + "integrity": "sha1-BiIT5mDJB+hvRAVWwB6mWXtxJCA=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "date-time": "^1.1.0", + "figures": "^1.0.0", + "hooker": "^0.2.3", + "number-is-nan": "^1.0.0", + "pretty-ms": "^2.1.0", + "text-table": "^0.2.0" + } + }, + "time-zone": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-0.1.0.tgz", + "integrity": "sha1-Sncotqwo2w4Aj1FAQ/1VW9VXO0Y=", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-js": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.2.2.tgz", + "integrity": "sha512-++1NO/zZIEdWf6cDIGceSJQPX31SqIpbVAHwFG5+240MtZqPG/NIPoinj8zlXQtAfMBqEt1Jyv2FiLP3n9gVhQ==", + "dev": true, + "requires": { + "commander": "~2.12.1", + "source-map": "~0.6.1" + } + }, + "underscore.string": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", + "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", + "dev": true, + "requires": { + "sprintf-js": "^1.0.3", + "util-deprecate": "^1.0.2" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "uri-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", + "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, + "requires": { + "fd-slicer": "~1.0.1" + } + } + } +} diff --git a/js/jquery-mask/package.js b/js/jquery-mask/package.js new file mode 100755 index 0000000000..03ecce8214 --- /dev/null +++ b/js/jquery-mask/package.js @@ -0,0 +1,14 @@ +Package.describe({ + "name": "igorescobar:jquery-mask-plugin", + "version": "1.14.16", + "summary": "A jQuery Plugin to make masks on form fields and HTML elements.", + "git": "git@github.com:igorescobar/jQuery-Mask-Plugin.git", + "documentation": "README.md" +}); + +Package.onUse(function(api) { + api.versionsFrom('1.2.1'); + api.use('ecmascript'); + api.addFiles('dist/jquery.mask.js', 'client'); + api.addFiles('dist/jquery.mask.min.js', 'client'); +}); diff --git a/js/jquery-mask/package.json b/js/jquery-mask/package.json new file mode 100755 index 0000000000..4e4c6d78ff --- /dev/null +++ b/js/jquery-mask/package.json @@ -0,0 +1,34 @@ +{ + "name": "jquery-mask-plugin", + "version": "1.14.16", + "description": "A jQuery Plugin to make masks on form fields and html elements.", + "author": "Igor Escobar ", + "homepage": "http://igorescobar.github.io/jQuery-Mask-Plugin/", + "main": "./dist/jquery.mask.js", + "repository": { + "type": "git", + "url": "https://github.com/igorescobar/jQuery-Mask-Plugin" + }, + "bugs": { + "url": "https://github.com/igorescobar/jQuery-Mask-Plugin/issues" + }, + "keywords": [ + "mask", + "masks", + "form", + "input", + "jquery-plugin" + ], + "license": "MIT", + "devDependencies": { + "grunt": "^1.0.4", + "grunt-contrib-connect": "*", + "grunt-contrib-jshint": "^2.1.0", + "grunt-contrib-qunit": "^3.1.0", + "grunt-contrib-uglify": "*", + "jshint-stylish": "^1.0.0", + "load-grunt-tasks": "^3.1.0", + "request": "2.88.0", + "time-grunt": "^1.0.0" + } +} diff --git a/js/jquery-mask/src/jquery.mask.js b/js/jquery-mask/src/jquery.mask.js new file mode 100755 index 0000000000..54f171c946 --- /dev/null +++ b/js/jquery-mask/src/jquery.mask.js @@ -0,0 +1,604 @@ +/** + * jquery.mask.js + * @version: v1.14.16 + * @author: Igor Escobar + * + * Created by Igor Escobar on 2012-03-10. Please report any bug at github.com/igorescobar/jQuery-Mask-Plugin + * + * Copyright (c) 2012 Igor Escobar http://igorescobar.com + * + * The MIT License (http://www.opensource.org/licenses/mit-license.php) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* jshint laxbreak: true */ +/* jshint maxcomplexity:17 */ +/* global define */ + +// UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere. +// https://github.com/umdjs/umd/blob/master/templates/jqueryPlugin.js +(function (factory, jQuery, Zepto) { + + if (typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } else if (typeof exports === 'object' && typeof Meteor === 'undefined') { + module.exports = factory(require('jquery')); + } else { + factory(jQuery || Zepto); + } + +}(function ($) { + 'use strict'; + + var Mask = function (el, mask, options) { + + var p = { + invalid: [], + getCaret: function () { + try { + var sel, + pos = 0, + ctrl = el.get(0), + dSel = document.selection, + cSelStart = ctrl.selectionStart; + + // IE Support + if (dSel && navigator.appVersion.indexOf('MSIE 10') === -1) { + sel = dSel.createRange(); + sel.moveStart('character', -p.val().length); + pos = sel.text.length; + } + // Firefox support + else if (cSelStart || cSelStart === '0') { + pos = cSelStart; + } + + return pos; + } catch (e) {} + }, + setCaret: function(pos) { + try { + if (el.is(':focus')) { + var range, ctrl = el.get(0); + + // Firefox, WebKit, etc.. + if (ctrl.setSelectionRange) { + ctrl.setSelectionRange(pos, pos); + } else { // IE + range = ctrl.createTextRange(); + range.collapse(true); + range.moveEnd('character', pos); + range.moveStart('character', pos); + range.select(); + } + } + } catch (e) {} + }, + events: function() { + el + .on('keydown.mask', function(e) { + el.data('mask-keycode', e.keyCode || e.which); + el.data('mask-previus-value', el.val()); + el.data('mask-previus-caret-pos', p.getCaret()); + p.maskDigitPosMapOld = p.maskDigitPosMap; + }) + .on($.jMaskGlobals.useInput ? 'input.mask' : 'keyup.mask', p.behaviour) + .on('paste.mask drop.mask', function() { + setTimeout(function() { + el.keydown().keyup(); + }, 100); + }) + .on('change.mask', function(){ + el.data('changed', true); + }) + .on('blur.mask', function(){ + if (oldValue !== p.val() && !el.data('changed')) { + el.trigger('change'); + } + el.data('changed', false); + }) + // it's very important that this callback remains in this position + // otherwhise oldValue it's going to work buggy + .on('blur.mask', function() { + oldValue = p.val(); + }) + // select all text on focus + .on('focus.mask', function (e) { + if (options.selectOnFocus === true) { + $(e.target).select(); + } + }) + // clear the value if it not complete the mask + .on('focusout.mask', function() { + if (options.clearIfNotMatch && !regexMask.test(p.val())) { + p.val(''); + } + }); + }, + getRegexMask: function() { + var maskChunks = [], translation, pattern, optional, recursive, oRecursive, r; + + for (var i = 0; i < mask.length; i++) { + translation = jMask.translation[mask.charAt(i)]; + + if (translation) { + + pattern = translation.pattern.toString().replace(/.{1}$|^.{1}/g, ''); + optional = translation.optional; + recursive = translation.recursive; + + if (recursive) { + maskChunks.push(mask.charAt(i)); + oRecursive = {digit: mask.charAt(i), pattern: pattern}; + } else { + maskChunks.push(!optional && !recursive ? pattern : (pattern + '?')); + } + + } else { + maskChunks.push(mask.charAt(i).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')); + } + } + + r = maskChunks.join(''); + + if (oRecursive) { + r = r.replace(new RegExp('(' + oRecursive.digit + '(.*' + oRecursive.digit + ')?)'), '($1)?') + .replace(new RegExp(oRecursive.digit, 'g'), oRecursive.pattern); + } + + return new RegExp(r); + }, + destroyEvents: function() { + el.off(['input', 'keydown', 'keyup', 'paste', 'drop', 'blur', 'focusout', ''].join('.mask ')); + }, + val: function(v) { + var isInput = el.is('input'), + method = isInput ? 'val' : 'text', + r; + + if (arguments.length > 0) { + if (el[method]() !== v) { + el[method](v); + } + r = el; + } else { + r = el[method](); + } + + return r; + }, + calculateCaretPosition: function(oldVal) { + var newVal = p.getMasked(), + caretPosNew = p.getCaret(); + if (oldVal !== newVal) { + var caretPosOld = el.data('mask-previus-caret-pos') || 0, + newValL = newVal.length, + oldValL = oldVal.length, + maskDigitsBeforeCaret = 0, + maskDigitsAfterCaret = 0, + maskDigitsBeforeCaretAll = 0, + maskDigitsBeforeCaretAllOld = 0, + i = 0; + + for (i = caretPosNew; i < newValL; i++) { + if (!p.maskDigitPosMap[i]) { + break; + } + maskDigitsAfterCaret++; + } + + for (i = caretPosNew - 1; i >= 0; i--) { + if (!p.maskDigitPosMap[i]) { + break; + } + maskDigitsBeforeCaret++; + } + + for (i = caretPosNew - 1; i >= 0; i--) { + if (p.maskDigitPosMap[i]) { + maskDigitsBeforeCaretAll++; + } + } + + for (i = caretPosOld - 1; i >= 0; i--) { + if (p.maskDigitPosMapOld[i]) { + maskDigitsBeforeCaretAllOld++; + } + } + + // if the cursor is at the end keep it there + if (caretPosNew > oldValL) { + caretPosNew = newValL * 10; + } else if (caretPosOld >= caretPosNew && caretPosOld !== oldValL) { + if (!p.maskDigitPosMapOld[caretPosNew]) { + var caretPos = caretPosNew; + caretPosNew -= maskDigitsBeforeCaretAllOld - maskDigitsBeforeCaretAll; + caretPosNew -= maskDigitsBeforeCaret; + if (p.maskDigitPosMap[caretPosNew]) { + caretPosNew = caretPos; + } + } + } + else if (caretPosNew > caretPosOld) { + caretPosNew += maskDigitsBeforeCaretAll - maskDigitsBeforeCaretAllOld; + caretPosNew += maskDigitsAfterCaret; + } + } + return caretPosNew; + }, + behaviour: function(e) { + e = e || window.event; + p.invalid = []; + + var keyCode = el.data('mask-keycode'); + + if ($.inArray(keyCode, jMask.byPassKeys) === -1) { + var newVal = p.getMasked(), + caretPos = p.getCaret(), + oldVal = el.data('mask-previus-value') || ''; + + // this is a compensation to devices/browsers that don't compensate + // caret positioning the right way + setTimeout(function() { + p.setCaret(p.calculateCaretPosition(oldVal)); + }, $.jMaskGlobals.keyStrokeCompensation); + + p.val(newVal); + p.setCaret(caretPos); + return p.callbacks(e); + } + }, + getMasked: function(skipMaskChars, val) { + var buf = [], + value = val === undefined ? p.val() : val + '', + m = 0, maskLen = mask.length, + v = 0, valLen = value.length, + offset = 1, addMethod = 'push', + resetPos = -1, + maskDigitCount = 0, + maskDigitPosArr = [], + lastMaskChar, + check; + + if (options.reverse) { + addMethod = 'unshift'; + offset = -1; + lastMaskChar = 0; + m = maskLen - 1; + v = valLen - 1; + check = function () { + return m > -1 && v > -1; + }; + } else { + lastMaskChar = maskLen - 1; + check = function () { + return m < maskLen && v < valLen; + }; + } + + var lastUntranslatedMaskChar; + while (check()) { + var maskDigit = mask.charAt(m), + valDigit = value.charAt(v), + translation = jMask.translation[maskDigit]; + + if (translation) { + if (valDigit.match(translation.pattern)) { + buf[addMethod](valDigit); + if (translation.recursive) { + if (resetPos === -1) { + resetPos = m; + } else if (m === lastMaskChar && m !== resetPos) { + m = resetPos - offset; + } + + if (lastMaskChar === resetPos) { + m -= offset; + } + } + m += offset; + } else if (valDigit === lastUntranslatedMaskChar) { + // matched the last untranslated (raw) mask character that we encountered + // likely an insert offset the mask character from the last entry; fall + // through and only increment v + maskDigitCount--; + lastUntranslatedMaskChar = undefined; + } else if (translation.optional) { + m += offset; + v -= offset; + } else if (translation.fallback) { + buf[addMethod](translation.fallback); + m += offset; + v -= offset; + } else { + p.invalid.push({p: v, v: valDigit, e: translation.pattern}); + } + v += offset; + } else { + if (!skipMaskChars) { + buf[addMethod](maskDigit); + } + + if (valDigit === maskDigit) { + maskDigitPosArr.push(v); + v += offset; + } else { + lastUntranslatedMaskChar = maskDigit; + maskDigitPosArr.push(v + maskDigitCount); + maskDigitCount++; + } + + m += offset; + } + } + + var lastMaskCharDigit = mask.charAt(lastMaskChar); + if (maskLen === valLen + 1 && !jMask.translation[lastMaskCharDigit]) { + buf.push(lastMaskCharDigit); + } + + var newVal = buf.join(''); + p.mapMaskdigitPositions(newVal, maskDigitPosArr, valLen); + return newVal; + }, + mapMaskdigitPositions: function(newVal, maskDigitPosArr, valLen) { + var maskDiff = options.reverse ? newVal.length - valLen : 0; + p.maskDigitPosMap = {}; + for (var i = 0; i < maskDigitPosArr.length; i++) { + p.maskDigitPosMap[maskDigitPosArr[i] + maskDiff] = 1; + } + }, + callbacks: function (e) { + var val = p.val(), + changed = val !== oldValue, + defaultArgs = [val, e, el, options], + callback = function(name, criteria, args) { + if (typeof options[name] === 'function' && criteria) { + options[name].apply(this, args); + } + }; + + callback('onChange', changed === true, defaultArgs); + callback('onKeyPress', changed === true, defaultArgs); + callback('onComplete', val.length === mask.length, defaultArgs); + callback('onInvalid', p.invalid.length > 0, [val, e, el, p.invalid, options]); + } + }; + + el = $(el); + var jMask = this, oldValue = p.val(), regexMask; + + mask = typeof mask === 'function' ? mask(p.val(), undefined, el, options) : mask; + + // public methods + jMask.mask = mask; + jMask.options = options; + jMask.remove = function() { + var caret = p.getCaret(); + if (jMask.options.placeholder) { + el.removeAttr('placeholder'); + } + if (el.data('mask-maxlength')) { + el.removeAttr('maxlength'); + } + p.destroyEvents(); + p.val(jMask.getCleanVal()); + p.setCaret(caret); + return el; + }; + + // get value without mask + jMask.getCleanVal = function() { + return p.getMasked(true); + }; + + // get masked value without the value being in the input or element + jMask.getMaskedVal = function(val) { + return p.getMasked(false, val); + }; + + jMask.init = function(onlyMask) { + onlyMask = onlyMask || false; + options = options || {}; + + jMask.clearIfNotMatch = $.jMaskGlobals.clearIfNotMatch; + jMask.byPassKeys = $.jMaskGlobals.byPassKeys; + jMask.translation = $.extend({}, $.jMaskGlobals.translation, options.translation); + + jMask = $.extend(true, {}, jMask, options); + + regexMask = p.getRegexMask(); + + if (onlyMask) { + p.events(); + p.val(p.getMasked()); + } else { + if (options.placeholder) { + el.attr('placeholder' , options.placeholder); + } + + // this is necessary, otherwise if the user submit the form + // and then press the "back" button, the autocomplete will erase + // the data. Works fine on IE9+, FF, Opera, Safari. + if (el.data('mask')) { + el.attr('autocomplete', 'off'); + } + + // detect if is necessary let the user type freely. + // for is a lot faster than forEach. + for (var i = 0, maxlength = true; i < mask.length; i++) { + var translation = jMask.translation[mask.charAt(i)]; + if (translation && translation.recursive) { + maxlength = false; + break; + } + } + + if (maxlength) { + el.attr('maxlength', mask.length).data('mask-maxlength', true); + } + + p.destroyEvents(); + p.events(); + + var caret = p.getCaret(); + p.val(p.getMasked()); + p.setCaret(caret); + } + }; + + jMask.init(!el.is('input')); + }; + + $.maskWatchers = {}; + var HTMLAttributes = function () { + var input = $(this), + options = {}, + prefix = 'data-mask-', + mask = input.attr('data-mask'); + + if (input.attr(prefix + 'reverse')) { + options.reverse = true; + } + + if (input.attr(prefix + 'clearifnotmatch')) { + options.clearIfNotMatch = true; + } + + if (input.attr(prefix + 'selectonfocus') === 'true') { + options.selectOnFocus = true; + } + + if (notSameMaskObject(input, mask, options)) { + return input.data('mask', new Mask(this, mask, options)); + } + }, + notSameMaskObject = function(field, mask, options) { + options = options || {}; + var maskObject = $(field).data('mask'), + stringify = JSON.stringify, + value = $(field).val() || $(field).text(); + try { + if (typeof mask === 'function') { + mask = mask(value); + } + return typeof maskObject !== 'object' || stringify(maskObject.options) !== stringify(options) || maskObject.mask !== mask; + } catch (e) {} + }, + eventSupported = function(eventName) { + var el = document.createElement('div'), isSupported; + + eventName = 'on' + eventName; + isSupported = (eventName in el); + + if ( !isSupported ) { + el.setAttribute(eventName, 'return;'); + isSupported = typeof el[eventName] === 'function'; + } + el = null; + + return isSupported; + }; + + $.fn.mask = function(mask, options) { + options = options || {}; + var selector = this.selector, + globals = $.jMaskGlobals, + interval = globals.watchInterval, + watchInputs = options.watchInputs || globals.watchInputs, + maskFunction = function() { + if (notSameMaskObject(this, mask, options)) { + return $(this).data('mask', new Mask(this, mask, options)); + } + }; + + $(this).each(maskFunction); + + if (selector && selector !== '' && watchInputs) { + clearInterval($.maskWatchers[selector]); + $.maskWatchers[selector] = setInterval(function(){ + $(document).find(selector).each(maskFunction); + }, interval); + } + return this; + }; + + $.fn.masked = function(val) { + return this.data('mask').getMaskedVal(val); + }; + + $.fn.unmask = function() { + clearInterval($.maskWatchers[this.selector]); + delete $.maskWatchers[this.selector]; + return this.each(function() { + var dataMask = $(this).data('mask'); + if (dataMask) { + dataMask.remove().removeData('mask'); + } + }); + }; + + $.fn.cleanVal = function() { + return this.data('mask').getCleanVal(); + }; + + $.applyDataMask = function(selector) { + selector = selector || $.jMaskGlobals.maskElements; + var $selector = (selector instanceof $) ? selector : $(selector); + $selector.filter($.jMaskGlobals.dataMaskAttr).each(HTMLAttributes); + }; + + var globals = { + maskElements: 'input,td,span,div', + dataMaskAttr: '[data-mask]', + dataMask: true, + watchInterval: 300, + watchInputs: true, + keyStrokeCompensation: 10, + // old versions of chrome dont work great with input event + useInput: !/Chrome\/[2-4][0-9]|SamsungBrowser/.test(window.navigator.userAgent) && eventSupported('input'), + watchDataMask: false, + byPassKeys: [9, 16, 17, 18, 36, 37, 38, 39, 40, 91], + translation: { + '0': {pattern: /\d/}, + '9': {pattern: /\d/, optional: true}, + '#': {pattern: /\d/, recursive: true}, + 'A': {pattern: /[a-zA-Z0-9]/}, + 'S': {pattern: /[a-zA-Z]/} + } + }; + + $.jMaskGlobals = $.jMaskGlobals || {}; + globals = $.jMaskGlobals = $.extend(true, {}, globals, $.jMaskGlobals); + + // looking for inputs with data-mask attribute + if (globals.dataMask) { + $.applyDataMask(); + } + + setInterval(function() { + if ($.jMaskGlobals.watchDataMask) { + $.applyDataMask(); + } + }, globals.watchInterval); +}, window.jQuery, window.Zepto)); diff --git a/js/jquery-mask/test/jquery.mask.test.js b/js/jquery-mask/test/jquery.mask.test.js new file mode 100755 index 0000000000..378aebb286 --- /dev/null +++ b/js/jquery-mask/test/jquery.mask.test.js @@ -0,0 +1,718 @@ +var QUNIT = true; +$(document).ready(function(){ + + var testfield = $('.simple-field'), + testfieldDataMask = $('.simple-field-data-mask'), + testfieldDataMaskWithReverse = $('.simple-field-data-mask-reverse'), + testfieldDataMaskWithClearIfNotMatch = $('.simple-field-data-mask-clearifnotmatch'), + testfieldDataMaskWithClearIfNotMatchAndOptionalMask = $('.simple-field-data-mask-clearifnotmatch-and-optional-mask'), + testdiv = $('.simple-div'), + typeTest = function (typedValue, obj) { + obj = typeof obj === "undefined" ? testfield : obj; + + return obj.keydown().val(typedValue).trigger('input').val(); + }, + typeDivTest = function(typedValue){ + return testdiv.keydown().text(typedValue).trigger('input').text(); + }; + + module('Setting Up'); + test("test if the mask method exists after plugin insertion", function() { + equal( typeof testfield.mask , "function" , "mask function should exists" ); + }); + + module('Simple Masks'); + test("Masks with only numbers.", function(){ + testfield.mask('000000'); + + equal( typeTest("1."), "1"); + equal( typeTest('1éáa2aaaaqwo'), "12"); + equal( typeTest('1234567'), "123456"); + + }); + + test("When I change the mask on-the-fly things should work normally", function(){ + testfield.mask('0000.0000'); + + equal( typeTest("1."), "1"); + equal( typeTest('1éáa2aaaaqwo'), "12"); + equal( typeTest('1234567'), "1234.567"); + + // changing on-the-fly + testfield.mask('0.000.000'); + + equal( typeTest("1."), "1."); + equal( typeTest('1éáa2aaaaqwo'), "1.2"); + equal( typeTest('1234567'), "1.234.567"); + + }); + + test("When I change the mask on-the-fly with onChange callback things should work normally", function(){ + + var masks = ['0000.00009', '0.0000.0000']; + var SPphoneMask = function(phone){ + return phone.length <= 9 ? masks[0] : masks[1]; + }; + + testfield.mask(SPphoneMask, {onChange: function(phone, e, currentField, options){ + $(currentField).mask(SPphoneMask(phone), options); + }}); + + equal( typeTest("1"), "1"); + equal( typeTest("12"), "12"); + equal( typeTest("123"), "123"); + equal( typeTest("1234"), "1234"); + equal( typeTest("12345"), "1234.5"); + equal( typeTest("123456"), "1234.56"); + equal( typeTest("1234567"), "1234.567"); + equal( typeTest("12345678"), "1234.5678"); + equal( typeTest("123456789"), "1.2345.6789"); + + }); + + test("When I change the mask on-the-fly with onKeyPress callback things should work normally", function(){ + + var masks = ['0000.00009', '0.0000.0000']; + var SPphoneMask = function(phone){ + return phone.length <= 9 ? masks[0] : masks[1]; + }; + + testfield.mask(SPphoneMask, {onKeyPress: function(phone, e, currentField, options){ + $(currentField).mask(SPphoneMask(phone), options); + }}); + + equal( typeTest("1"), "1"); + equal( typeTest("12"), "12"); + equal( typeTest("123"), "123"); + equal( typeTest("1234"), "1234"); + equal( typeTest("12345"), "1234.5"); + equal( typeTest("123456"), "1234.56"); + equal( typeTest("1234567"), "1234.567"); + equal( typeTest("12345678"), "1234.5678"); + equal( typeTest("123456789"), "1.2345.6789"); + + }); + + test("#onInvalid callback. should call when invalid", function(){ + testfield.mask('00/00/0000', {onInvalid: function(val, e, el, invalid, options){ + equal(val, "1") + equal(typeof e, "object") + equal(typeof el, "object") + equal(invalid.length, 1); + equal(invalid[0]["e"], "/\\d/"); + equal(invalid[0]["p"], 1); + equal(invalid[0]["v"], "a"); + equal(typeof options.onInvalid, "function"); + }}); + + equal( typeTest("1a") , "1"); + }); + + test("#onInvalid callback. should not call when valid", function(){ + var callback = sinon.spy(); + testfield.mask('00/00/0000', {onInvalid: callback}); + + equal( typeTest("11") , "11"); + equal(callback.called, false) + }); + + test('When I typed a char thats the same as the mask char', function(){ + testfield.unmask(); + testfield.mask('00/00/0000'); + + equal( typeTest("00/"), "00/"); + equal( typeTest("00a"), "00/"); + equal( typeTest("00a00/00"), "00/00/00"); + equal( typeTest("0a/00/00"), "00/00/0"); + equal( typeTest("0a/0a/00"), "00/00"); + + }); + + test('When I typed exactly the same as the mask', function(){ + testfield.mask('00/00/0000'); + equal( typeTest("00"), "00"); + equal( typeTest("00/"), "00/"); + equal( typeTest("aa/"), ""); + equal( typeTest("00/0"), "00/0"); + equal( typeTest("00/00"), "00/00"); + equal( typeTest("00/00/0"), "00/00/0"); + equal( typeTest("00/00/00"), "00/00/00"); + }); + + test("Testing masks with a literal on the last char", function () { + testfield.mask("(99)"); + + equal( typeTest("(99"), "(99)"); + }); + + + module('Masks with numbers and especial characters'); + + test("Masks with numbers and special characters.", function(){ + testfield.mask('(000) 000-0000'); + + equal( typeTest("1"), "(1"); + equal( typeTest('12'), "(12"); + equal( typeTest('123'), "(123"); + equal( typeTest('1234'), "(123) 4"); + equal( typeTest('12345'), "(123) 45"); + equal( typeTest('(123) 456'), "(123) 456"); + equal( typeTest('(123) 4567'), "(123) 456-7"); + + }); + + test("Testing masks with a annonymous function", function(){ + testfield.mask(function(){ + return "(123) 456-7899" + }); + + equal( typeTest("1"), "(1"); + equal( typeTest('12'), "(12"); + equal( typeTest('123'), "(123"); + equal( typeTest('1234'), "(123) 4"); + equal( typeTest('12345'), "(123) 45"); + equal( typeTest('123456'), "(123) 456"); + equal( typeTest('1234567'), "(123) 456-7"); + + }); + + test("Masks with numbers, strings e special characters", function(){ + testfield.mask('(999) A99-SSSS'); + + equal( typeTest("(1"), "(1"); + equal( typeTest('(12'), "(12"); + equal( typeTest('(123'), "(123"); + equal( typeTest('(123) 4'), "(123) 4"); + equal( typeTest('(123) A'), "(123) A"); + equal( typeTest('123.'), "(123) "); + equal( typeTest('(123) 45'), "(123) 45"); + equal( typeTest('(123) 456'), "(123) 456"); + equal( typeTest('(123) 456-A'), "(123) 456-A"); + equal( typeTest('(123) 456-AB'), "(123) 456-AB"); + equal( typeTest('(123) 456-ABC'), "(123) 456-ABC"); + equal( typeTest('(123) 456-ABCD'), "(123) 456-ABCD"); + equal( typeTest('(123) 456-ABCDE'), "(123) 456-ABCD"); + equal( typeTest('(123) 456-ABCD1'), "(123) 456-ABCD"); + + }); + + test("Masks with numbers, strings e special characters #2 ", function(){ + testfield.mask('AAA 000-S0S'); + + equal( typeTest("1"), "1"); + equal( typeTest('12'), "12"); + equal( typeTest('123'), "123"); + equal( typeTest('123 4'), "123 4"); + equal( typeTest('123 45'), "123 45"); + equal( typeTest('123 456'), "123 456"); + equal( typeTest('123 456-7'), "123 456-"); + + }); + + module("Testing Reversible Masks"); + + test("Testing a CPF Mask", function(){ + testfield.mask('000.000.000-00', {reverse: true}); + + equal( typeTest("1"), "1"); + equal( typeTest("12"), "12"); + equal( typeTest("123"), "1-23"); + equal( typeTest("12-34"), "12-34"); + equal( typeTest("123-45"), "123-45"); + equal( typeTest("1.234-56"), "1.234-56"); + equal( typeTest("12.345-67"), "12.345-67"); + equal( typeTest("123.456-78"), "123.456-78"); + equal( typeTest("1.234.567-89"), "1.234.567-89"); + equal( typeTest("12.345.678-90"), "12.345.678-90"); + equal( typeTest("123.456.789-00"), "123.456.789-00"); + equal( typeTest("123.456.789-00"), "123.456.789-00"); + + equal( typeTest("123.456.789a00"), "123.456.789-00"); + equal( typeTest("123-a5"), "12-35"); + + equal( typeTest("1"), "1"); + equal( typeTest("12"), "12"); + equal( typeTest("1-23"), "1-23"); + equal( typeTest("12-34"), "12-34"); + equal( typeTest("12-345"), "123-45"); + equal( typeTest("1.234-56"), "1.234-56"); + equal( typeTest("12.345-67"), "12.345-67"); + equal( typeTest("123.456-78"), "123.456-78"); + equal( typeTest("1.234.567-89"), "1.234.567-89"); + equal( typeTest("12.345.678-90"), "12.345.678-90"); + equal( typeTest("123.456.789-00"), "123.456.789-00"); + equal( typeTest("123.456.789-00"), "123.456.789-00"); + equal( typeTest("123.456.789a00"), "123.456.789-00"); + }); + + test("Testing Reverse numbers with recursive mask", function(){ + testfield.mask("#.##0,00", {reverse: true}); + + equal(typeTest(""), ""); + equal(typeTest("1"), "1"); + equal(typeTest("12"), "12"); + equal(typeTest("123"), "1,23"); + equal(typeTest("1,234"), "12,34"); + equal(typeTest("12,345"), "123,45"); + equal(typeTest("123,456"), "1.234,56"); + equal(typeTest("1.234,567"), "12.345,67"); + equal(typeTest("12.345,678"), "123.456,78"); + equal(typeTest("123.456,789"), "1.234.567,89"); + equal(typeTest("1.234.567,890"), "12.345.678,90"); + equal(typeTest("12.345.678,901"), "123.456.789,01"); + equal(typeTest("123.456.789,012"), "1.234.567.890,12"); + equal(typeTest("1.234.567.890,1"), "123.456.789,01"); + equal(typeTest("123.456.789,0"), "12.345.678,90"); + equal(typeTest("12.345.678,9"), "1.234.567,89"); + equal(typeTest("1.234.567,8"), "123.456,78"); + }); + + test("Testing numbers with recursive mask", function(){ + testfield.mask("0#.#"); + + equal(typeTest(""), ""); + equal(typeTest("1"), "1"); + equal(typeTest("12"), "12"); + equal(typeTest("12."), "12."); + equal(typeTest("12.3"), "12.3"); + equal(typeTest("12.34"), "12.34"); + equal(typeTest("12.345"), "12.34.5"); + equal(typeTest("12.34.5."), "12.34.5"); + equal(typeTest("12.34.56"), "12.34.56"); + equal(typeTest("12.34.567"), "12.34.56.7"); + equal(typeTest("12.34.56."), "12.34.56."); + equal(typeTest("12.34.56"), "12.34.56"); + equal(typeTest("12.34.5"), "12.34.5"); + }); + + test("Testing numbers with recursive mask with one #", function(){ + testfield.mask("0#", {}); + + equal(typeTest(""), ""); + equal(typeTest("1"), "1"); + equal(typeTest("12"), "12"); + equal(typeTest("123"), "123"); + equal(typeTest("1234"), "1234"); + equal(typeTest("12345"), "12345"); + equal(typeTest("12345"), "12345"); + equal(typeTest("123456"), "123456"); + equal(typeTest("1234567"), "1234567"); + equal(typeTest("123456."), "123456"); + equal(typeTest("123456"), "123456"); + equal(typeTest("12345"), "12345"); + }); + test("Testing numbers with recursive mask with one # and reverse", function(){ + testfield.mask("#0", {reverse: true}); + + equal(typeTest(""), ""); + equal(typeTest("1"), "1"); + equal(typeTest("12"), "12"); + equal(typeTest("123"), "123"); + equal(typeTest("1234"), "1234"); + equal(typeTest("12345"), "12345"); + equal(typeTest("12345"), "12345"); + equal(typeTest("123456"), "123456"); + equal(typeTest("1234567"), "1234567"); + equal(typeTest("123456."), "123456"); + equal(typeTest("123456"), "123456"); + equal(typeTest("12345"), "12345"); + }); + test("Testing reversible masks with a literal on the last char", function () { + testfield.mask("(99)"); + + equal( typeTest("(99"), "(99)"); + }); + + module('Removing mask'); + + test("when I get the unmasked value", function(){ + testfield.mask('(00) 0000-0000', { placeholder: '(__) ____-____' }); + + equal(typeTest("1299999999"), "(12) 9999-9999"); + testfield.unmask() + equal(testfield.val(), "1299999999"); + + if (window.Zepto) { + equal(testfield.attr('placeholder'), ''); + equal(testfield.attr('maxlength'), null); + } else { + equal(testfield.attr('placeholder'), undefined); + equal(testfield.attr('maxlength'), undefined); + } + }); + + module('Getting Unmasked Value'); + + test("when I get the unmasked value", function(){ + testfield.mask('(00) 0000-0000'); + + equal( typeTest("1299999999"), "(12) 9999-9999"); + equal( testfield.cleanVal(), "1299999999"); + }); + + test("when I get the unmasked value with recursive mask", function(){ + testfield.mask('#.##0,00', {reverse:true}); + + equal( typeTest("123123123123123123", testfield), "1.231.231.231.231.231,23"); + equal( testfield.cleanVal(), "123123123123123123"); + }); + + module('Masking a value programmatically'); + + test("when I get the masked value programmatically", function(){ + testfield.mask('(00) 0000-0000'); + typeTest("1299999999", testfield); + equal( testfield.masked("3488888888"), "(34) 8888-8888"); + }); + + module('personalized settings') + + test("when adding more itens to the table translation",function(){ + testfield.mask('00/00/0000', {'translation': {0: {pattern: /[0-9*]/}}}); + + equal( typeTest('12/34/5678'), '12/34/5678'); + equal( typeTest('**/34/5678'), '**/34/5678'); + }); + + test("when adding more itens to the table translation #2",function(){ + testfield.mask('00/YY/0000', {'translation': {'Y': {pattern: /[0-9*]/}}}); + + equal( typeTest('12/34/5678'), '12/34/5678'); + equal( typeTest('12/**/5678'), '12/**/5678'); + }); + + test("when adding more itens to the table translation #3",function(){ + var old_translation = $.jMaskGlobals.translation + $.jMaskGlobals.translation = { + '1': {pattern: /\d/}, + '9': {pattern: /\d/, optional: true}, + '#': {pattern: /\d/, recursive: true}, + 'A': {pattern: /[a-zA-Z0-9]/}, + 'S': {pattern: /[a-zA-Z]/} + }; + + testfield.mask('00/11/1111'); + + equal( typeTest('12/12/5678'), '00/12/1256'); + + testfield.mask('11/00/1111'); + equal( typeTest('12/12/5678'), '12/00/1256'); + + $.jMaskGlobals.translation = old_translation; + }); + + test("when adding more itens to the table translation #fallback",function(){ + testfield.mask('zz/z0/0000', {'translation': {'z': {pattern: /[0-9*]/, fallback: '*'}}}); + + equal( typeTest('12/:4/5678'), '12/*4/5678'); + equal( typeTest('::/:4/5678'), '**/*4/5678'); + }); + + test("test the translation #fallback #1" , function(){ + testfield.mask('00t00', {'translation': {'t': {pattern: /[:,.]/, fallback: ':'}}}); + + equal( typeTest('1'), '1'); + equal( typeTest('13'), '13'); + equal( typeTest('137'), '13:7'); + equal( typeTest('1337'), '13:37'); + equal( typeTest('13z00'), '13:00'); + }); + + test("test the translation #fallback #2" , function(){ + testfield.mask('00/t0/t0', {'translation': {'t': {pattern: /[:,.*]/, fallback: '*'}}}); + + equal( typeTest('1'), '1'); + equal( typeTest('13'), '13'); + equal( typeTest('13/'), '13/'); + equal( typeTest('13/a'), '13/*'); + equal( typeTest('13/a1z1'), '13/*1/*1'); + }); + + test("test the translation #fallback #3" , function(){ + testfield.mask('tt/00/00', {'translation': {'t': {pattern: /[:,.*]/, fallback: '*'}}}); + + equal( typeTest('*'), '*'); + equal( typeTest('13'), '**/13'); + equal( typeTest('13/'), '**/13/'); + equal( typeTest('13/a'), '**/13/'); + equal( typeTest('13/a1z1'), '**/13/11'); + }); + + test("when adding opcional chars",function(){ + testfield.mask('099.099.099.099'); + + equal( typeTest('0.0.0.0'), '0.0.0.0'); + equal( typeTest('00.00.00.00'), '00.00.00.00'); + equal( typeTest('00.000.00.000'), '00.000.00.000'); + equal( typeTest('000.00.000.00'), '000.00.000.00'); + equal( typeTest('000.000.000.000'), '000.000.000.000'); + equal( typeTest('000000000000'), '000.000.000.000'); + equal( typeTest('0'), '0'); + equal( typeTest('00'), '00'); + equal( typeTest('00.'), '00.'); + equal( typeTest('00.0'), '00.0'); + equal( typeTest('00.00'), '00.00'); + equal( typeTest('00.00.'), '00.00.'); + equal( typeTest('00.00.000'), '00.00.000'); + equal( typeTest('00.00.000.'), '00.00.000.'); + equal( typeTest('00.00.000.0'), '00.00.000.0'); + equal( typeTest('00..'), '00.'); + }); + + test("when aplying mask on a element different than a form field",function(){ + testdiv.mask('000.000.000-00', {reverse: true}); + + equal( typeDivTest('12312312312'), '123.123.123-12'); + equal( typeDivTest('123.123.123-12'), '123.123.123-12'); + equal( typeDivTest('123.123a123-12'), '123.123.123-12'); + equal( typeDivTest('191'), '1-91'); + + testdiv.mask('00/00/0000'); + equal( typeDivTest('000000'), '00/00/00'); + equal( typeDivTest('00000000'), '00/00/0000'); + equal( typeDivTest('00/00/0000'), '00/00/0000'); + equal( typeDivTest('0a/00/0000'), '00/00/000'); + + }); + + module('Testing data-mask attribute support'); + + test("Testing data-mask attribute", function(){ + equal( typeTest("00/", testfieldDataMask), "00/"); + equal( typeTest("00a", testfieldDataMask), "00/"); + equal( typeTest("00a00/00", testfieldDataMask), "00/00/00"); + equal( typeTest("0a/00/00", testfieldDataMask), "00/00/0"); + equal( typeTest("0a/0a/00", testfieldDataMask), "00/00"); + equal( typeTest("00000000", testfieldDataMask), "00/00/0000"); + }); + + test("Testing data-mask-reverse attribute", function(){ + equal( typeTest("0000", testfieldDataMaskWithReverse), "00,00"); + equal( typeTest("000000", testfieldDataMaskWithReverse), "0.000,00"); + equal( typeTest("0000000000", testfieldDataMaskWithReverse), "00.000.000,00"); + }); + + module('Event fire test'); + + // TODO: need to understand why zepto.js isnt calling change event! + if(!window.Zepto) { + test('onChange Test', 2, function(){ + testfield.unmask(); + + var callback = sinon.spy(); + var mock = sinon.mock() + var typeAndBlur = function(typedValue){ + testfield.trigger('keydown'); + testfield.val(typedValue); + testfield.trigger('input'); + testfield.trigger("blur"); + }; + + testfield.mask('000.(000).000/0-0'); + + testfield.on("change", callback); + + typeAndBlur(""); + typeAndBlur("1"); + typeAndBlur("12"); + typeAndBlur("123"); + typeAndBlur("1234"); + typeAndBlur("12345"); + typeAndBlur("123456"); + typeAndBlur("1234567"); + typeAndBlur("12345678"); + typeAndBlur("123456789"); + typeAndBlur("123456789"); + typeAndBlur("1234567891"); + typeAndBlur("12345678912"); + + equal(testfield.val(), "123.(456).789/1-2" ); + equal(true, sinon.match(11).or(12).test(callback.callCount)) + + testfield.off("change"); + testfield.unmask(); + + }); + } + + + test('onDrop Test', function(){ + ok(true, "todo"); + }); + + module('testing Remove If Not Match Feature'); + + test('test when clearifnotmatch javascript notation', 4, function(){ + var typeAndFocusOut = function(typedValue){ + testfield.keydown().val(typedValue).trigger('input'); + testfield.trigger("focusout"); + }; + + testfield.mask('000'); + + typeAndFocusOut("1"); + equal( testfield.val(), "1" ); + + testfield.mask('000', {clearIfNotMatch: true}); + + typeAndFocusOut("1"); + equal( testfield.val(), "" ); + + typeAndFocusOut("12"); + equal( testfield.val(), "" ); + + typeAndFocusOut("123"); + equal( testfield.val(), "123" ); + }); + + test('test when clearifnotmatch javascript notation #2', 4, function(){ + var typeAndFocusOut = function(typedValue){ + testfield.keydown().val(typedValue).trigger('input'); + testfield.trigger("focusout"); + }; + + testfield.mask('7 (000) 000-0000'); + + typeAndFocusOut("1"); + equal( testfield.val(), "7 (1" ); + + testfield.mask('7 (000) 000-0000', {clearIfNotMatch: true}); + + typeAndFocusOut("1"); + equal( testfield.val(), "" ); + + typeAndFocusOut("12"); + equal( testfield.val(), "" ); + + typeAndFocusOut("7 (123) 123-1234"); + equal( testfield.val(), "7 (123) 123-1234" ); + }); + + test('test when clearifnotmatch is HTML notation', 3, function(){ + var typeAndFocusOut = function(typedValue){ + testfieldDataMaskWithClearIfNotMatch.keydown().val(typedValue).trigger('input'); + testfieldDataMaskWithClearIfNotMatch.trigger("focusout"); + }; + + typeAndFocusOut("1"); + equal( testfieldDataMaskWithClearIfNotMatch.val(), "" ); + + typeAndFocusOut("12"); + equal( testfieldDataMaskWithClearIfNotMatch.val(), "" ); + + typeAndFocusOut("123"); + equal( testfieldDataMaskWithClearIfNotMatch.val(), "123" ); + }); + + module('testing Remove If Not Match Feature'); + + test('test when clearifnotmatch javascript notation', 1, function(){ + + testfield.mask('000', {placeholder: '___'}); + equal( testfield.attr('placeholder'), "___" ); + + }); + + test('test when clearifnotmatch with optional mask', 9, function(){ + // html notation + var typeAndBlur = function(field, typedValue){ + field.keydown().val(typedValue).trigger('input'); + field.trigger("focusout"); + }; + + typeAndBlur(testfieldDataMaskWithClearIfNotMatchAndOptionalMask, "1"); + equal( testfieldDataMaskWithClearIfNotMatchAndOptionalMask.val(), "" ); + + typeAndBlur(testfieldDataMaskWithClearIfNotMatchAndOptionalMask, "12"); + equal( testfieldDataMaskWithClearIfNotMatchAndOptionalMask.val(), "12" ); + + typeAndBlur(testfieldDataMaskWithClearIfNotMatchAndOptionalMask, "123"); + equal( testfieldDataMaskWithClearIfNotMatchAndOptionalMask.val(), "123" ); + + // javascript notation + testfield.mask('099.099.099.099', {clearIfNotMatch: true}); + + typeAndBlur(testfield, "1"); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "123."); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "123.0"); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "123.01.000."); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "123.01.000.123"); + equal( testfield.val(), "123.01.000.123" ); + + typeAndBlur(testfield, "0.0.0.0"); + equal( testfield.val(), "0.0.0.0" ); + }); + + test('test when clearifnotmatch with recursive mask', 4, function(){ + // html notation + var typeAndBlur = function(field, typedValue){ + field.keydown().val(typedValue).trigger('input'); + field.trigger("focusout"); + }; + + // javascript notation + testfield.mask('#.##0,00', {clearIfNotMatch: true, reverse: true}); + + typeAndBlur(testfield, "0"); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "00"); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "0,00"); + equal( testfield.val(), "0,00" ); + + typeAndBlur(testfield, "1.000,00"); + equal( testfield.val(), "1.000,00" ); + + }); + + module('dynamically loaded elements') + test('#non-inputs', function(){ + expect(5); + + var $container = $('#container-dy-non-inputs'); + var clock = this.clock; + var ticker; + var tester; + var c = 0; + + function write() { + + if (c >= 5) { + clearInterval(ticker); + clearInterval(tester); + return; + } + + c++; + + $container.append('
' + c + c + c + c + '
'); + clock.tick(1000); + }; + + function testIt() { + + var cs = $container.find('.c'); + $.each(cs, function(k, field){ + var t = k + 1; + equal($(field).text(), '' + t + t + ':' + t + t); + t++; + }); + }; + + ticker = setInterval(write, 1000); + + write(); + $('.c', $container).mask('00:00'); + testIt() + }); +}); diff --git a/js/jquery-mask/test/qunit.css b/js/jquery-mask/test/qunit.css new file mode 100755 index 0000000000..cb4815b793 --- /dev/null +++ b/js/jquery-mask/test/qunit.css @@ -0,0 +1,244 @@ +/** + * QUnit v1.11.0 - A JavaScript Unit Testing Framework + * + * http://qunitjs.com + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +/** Font Family and Sizes */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { + font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; +} + +#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } +#qunit-tests { font-size: smaller; } + + +/** Resets */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { + margin: 0; + padding: 0; +} + + +/** Header */ + +#qunit-header { + padding: 0.5em 0 0.5em 1em; + + color: #8699a4; + background-color: #0d3349; + + font-size: 1.5em; + line-height: 1em; + font-weight: normal; + + border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-top-right-radius: 5px; + -webkit-border-top-left-radius: 5px; +} + +#qunit-header a { + text-decoration: none; + color: #c2ccd1; +} + +#qunit-header a:hover, +#qunit-header a:focus { + color: #fff; +} + +#qunit-testrunner-toolbar label { + display: inline-block; + padding: 0 .5em 0 .1em; +} + +#qunit-banner { + height: 5px; +} + +#qunit-testrunner-toolbar { + padding: 0.5em 0 0.5em 2em; + color: #5E740B; + background-color: #eee; + overflow: hidden; +} + +#qunit-userAgent { + padding: 0.5em 0 0.5em 2.5em; + background-color: #2b81af; + color: #fff; + text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; +} + +#qunit-modulefilter-container { + float: right; +} + +/** Tests: Pass/Fail */ + +#qunit-tests { + list-style-position: inside; +} + +#qunit-tests li { + padding: 0.4em 0.5em 0.4em 2.5em; + border-bottom: 1px solid #fff; + list-style-position: inside; +} + +#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { + display: none; +} + +#qunit-tests li strong { + cursor: pointer; +} + +#qunit-tests li a { + padding: 0.5em; + color: #c2ccd1; + text-decoration: none; +} +#qunit-tests li a:hover, +#qunit-tests li a:focus { + color: #000; +} + +#qunit-tests li .runtime { + float: right; + font-size: smaller; +} + +.qunit-assert-list { + margin-top: 0.5em; + padding: 0.5em; + + background-color: #fff; + + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.qunit-collapsed { + display: none; +} + +#qunit-tests table { + border-collapse: collapse; + margin-top: .2em; +} + +#qunit-tests th { + text-align: right; + vertical-align: top; + padding: 0 .5em 0 0; +} + +#qunit-tests td { + vertical-align: top; +} + +#qunit-tests pre { + margin: 0; + white-space: pre-wrap; + word-wrap: break-word; +} + +#qunit-tests del { + background-color: #e0f2be; + color: #374e0c; + text-decoration: none; +} + +#qunit-tests ins { + background-color: #ffcaca; + color: #500; + text-decoration: none; +} + +/*** Test Counts */ + +#qunit-tests b.counts { color: black; } +#qunit-tests b.passed { color: #5E740B; } +#qunit-tests b.failed { color: #710909; } + +#qunit-tests li li { + padding: 5px; + background-color: #fff; + border-bottom: none; + list-style-position: inside; +} + +/*** Passing Styles */ + +#qunit-tests li li.pass { + color: #3c510c; + background-color: #fff; + border-left: 10px solid #C6E746; +} + +#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } +#qunit-tests .pass .test-name { color: #366097; } + +#qunit-tests .pass .test-actual, +#qunit-tests .pass .test-expected { color: #999999; } + +#qunit-banner.qunit-pass { background-color: #C6E746; } + +/*** Failing Styles */ + +#qunit-tests li li.fail { + color: #710909; + background-color: #fff; + border-left: 10px solid #EE5757; + white-space: pre; +} + +#qunit-tests > li:last-child { + border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + -webkit-border-bottom-right-radius: 5px; + -webkit-border-bottom-left-radius: 5px; +} + +#qunit-tests .fail { color: #000000; background-color: #EE5757; } +#qunit-tests .fail .test-name, +#qunit-tests .fail .module-name { color: #000000; } + +#qunit-tests .fail .test-actual { color: #EE5757; } +#qunit-tests .fail .test-expected { color: green; } + +#qunit-banner.qunit-fail { background-color: #EE5757; } + + +/** Result */ + +#qunit-testresult { + padding: 0.5em 0.5em 0.5em 2.5em; + + color: #2b81af; + background-color: #D2E0E6; + + border-bottom: 1px solid white; +} +#qunit-testresult .module-name { + font-weight: bold; +} + +/** Fixture */ + +#qunit-fixture { + position: absolute; + top: -10000px; + left: -10000px; + width: 1000px; + height: 1000px; +} \ No newline at end of file diff --git a/js/jquery-mask/test/qunit.js b/js/jquery-mask/test/qunit.js new file mode 100755 index 0000000000..9729418707 --- /dev/null +++ b/js/jquery-mask/test/qunit.js @@ -0,0 +1,2152 @@ +/** + * QUnit v1.11.0 - A JavaScript Unit Testing Framework + * + * http://qunitjs.com + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +(function( window ) { + +var QUnit, + assert, + config, + onErrorFnPrev, + testId = 0, + fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + // Keep a local reference to Date (GH-283) + Date = window.Date, + defined = { + setTimeout: typeof window.setTimeout !== "undefined", + sessionStorage: (function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch( e ) { + return false; + } + }()) + }, + /** + * Provides a normalized error string, correcting an issue + * with IE 7 (and prior) where Error.prototype.toString is + * not properly implemented + * + * Based on http://es5.github.com/#x15.11.4.4 + * + * @param {String|Error} error + * @return {String} error message + */ + errorString = function( error ) { + var name, message, + errorString = error.toString(); + if ( errorString.substring( 0, 7 ) === "[object" ) { + name = error.name ? error.name.toString() : "Error"; + message = error.message ? error.message.toString() : ""; + if ( name && message ) { + return name + ": " + message; + } else if ( name ) { + return name; + } else if ( message ) { + return message; + } else { + return "Error"; + } + } else { + return errorString; + } + }, + /** + * Makes a clone of an object using only Array or Object as base, + * and copies over the own enumerable properties. + * + * @param {Object} obj + * @return {Object} New object with only the own properties (recursively). + */ + objectValues = function( obj ) { + // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392. + /*jshint newcap: false */ + var key, val, + vals = QUnit.is( "array", obj ) ? [] : {}; + for ( key in obj ) { + if ( hasOwn.call( obj, key ) ) { + val = obj[key]; + vals[key] = val === Object(val) ? objectValues(val) : val; + } + } + return vals; + }; + +function Test( settings ) { + extend( this, settings ); + this.assertions = []; + this.testNumber = ++Test.count; +} + +Test.count = 0; + +Test.prototype = { + init: function() { + var a, b, li, + tests = id( "qunit-tests" ); + + if ( tests ) { + b = document.createElement( "strong" ); + b.innerHTML = this.nameHtml; + + // `a` initialized at top of scope + a = document.createElement( "a" ); + a.innerHTML = "Rerun"; + a.href = QUnit.url({ testNumber: this.testNumber }); + + li = document.createElement( "li" ); + li.appendChild( b ); + li.appendChild( a ); + li.className = "running"; + li.id = this.id = "qunit-test-output" + testId++; + + tests.appendChild( li ); + } + }, + setup: function() { + if ( this.module !== config.previousModule ) { + if ( config.previousModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.previousModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0 }; + runLoggingCallbacks( "moduleStart", QUnit, { + name: this.module + }); + } else if ( config.autorun ) { + runLoggingCallbacks( "moduleStart", QUnit, { + name: this.module + }); + } + + config.current = this; + + this.testEnvironment = extend({ + setup: function() {}, + teardown: function() {} + }, this.moduleTestEnvironment ); + + this.started = +new Date(); + runLoggingCallbacks( "testStart", QUnit, { + name: this.testName, + module: this.module + }); + + // allow utility functions to access the current test environment + // TODO why?? + QUnit.current_testEnvironment = this.testEnvironment; + + if ( !config.pollution ) { + saveGlobal(); + } + if ( config.notrycatch ) { + this.testEnvironment.setup.call( this.testEnvironment ); + return; + } + try { + this.testEnvironment.setup.call( this.testEnvironment ); + } catch( e ) { + QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); + } + }, + run: function() { + config.current = this; + + var running = id( "qunit-testresult" ); + + if ( running ) { + running.innerHTML = "Running:
" + this.nameHtml; + } + + if ( this.async ) { + QUnit.stop(); + } + + this.callbackStarted = +new Date(); + + if ( config.notrycatch ) { + this.callback.call( this.testEnvironment, QUnit.assert ); + this.callbackRuntime = +new Date() - this.callbackStarted; + return; + } + + try { + this.callback.call( this.testEnvironment, QUnit.assert ); + this.callbackRuntime = +new Date() - this.callbackStarted; + } catch( e ) { + this.callbackRuntime = +new Date() - this.callbackStarted; + + QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + QUnit.start(); + } + } + }, + teardown: function() { + config.current = this; + if ( config.notrycatch ) { + if ( typeof this.callbackRuntime === "undefined" ) { + this.callbackRuntime = +new Date() - this.callbackStarted; + } + this.testEnvironment.teardown.call( this.testEnvironment ); + return; + } else { + try { + this.testEnvironment.teardown.call( this.testEnvironment ); + } catch( e ) { + QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); + } + } + checkPollution(); + }, + finish: function() { + config.current = this; + if ( config.requireExpects && this.expected === null ) { + QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); + } else if ( this.expected !== null && this.expected !== this.assertions.length ) { + QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); + } else if ( this.expected === null && !this.assertions.length ) { + QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); + } + + var i, assertion, a, b, time, li, ol, + test = this, + good = 0, + bad = 0, + tests = id( "qunit-tests" ); + + this.runtime = +new Date() - this.started; + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + if ( tests ) { + ol = document.createElement( "ol" ); + ol.className = "qunit-assert-list"; + + for ( i = 0; i < this.assertions.length; i++ ) { + assertion = this.assertions[i]; + + li = document.createElement( "li" ); + li.className = assertion.result ? "pass" : "fail"; + li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); + ol.appendChild( li ); + + if ( assertion.result ) { + good++; + } else { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + // store result when possible + if ( QUnit.config.reorder && defined.sessionStorage ) { + if ( bad ) { + sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); + } else { + sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); + } + } + + if ( bad === 0 ) { + addClass( ol, "qunit-collapsed" ); + } + + // `b` initialized at top of scope + b = document.createElement( "strong" ); + b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; + + addEvent(b, "click", function() { + var next = b.parentNode.lastChild, + collapsed = hasClass( next, "qunit-collapsed" ); + ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" ); + }); + + addEvent(b, "dblclick", function( e ) { + var target = e && e.target ? e.target : window.event.srcElement; + if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) { + target = target.parentNode; + } + if ( window.location && target.nodeName.toLowerCase() === "strong" ) { + window.location = QUnit.url({ testNumber: test.testNumber }); + } + }); + + // `time` initialized at top of scope + time = document.createElement( "span" ); + time.className = "runtime"; + time.innerHTML = this.runtime + " ms"; + + // `li` initialized at top of scope + li = id( this.id ); + li.className = bad ? "fail" : "pass"; + li.removeChild( li.firstChild ); + a = li.firstChild; + li.appendChild( b ); + li.appendChild( a ); + li.appendChild( time ); + li.appendChild( ol ); + + } else { + for ( i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[i].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + } + + runLoggingCallbacks( "testDone", QUnit, { + name: this.testName, + module: this.module, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length, + duration: this.runtime + }); + + QUnit.reset(); + + config.current = undefined; + }, + + queue: function() { + var bad, + test = this; + + synchronize(function() { + test.init(); + }); + function run() { + // each of these can by async + synchronize(function() { + test.setup(); + }); + synchronize(function() { + test.run(); + }); + synchronize(function() { + test.teardown(); + }); + synchronize(function() { + test.finish(); + }); + } + + // `bad` initialized at top of scope + // defer when previous test run passed, if storage is available + bad = QUnit.config.reorder && defined.sessionStorage && + +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); + + if ( bad ) { + run(); + } else { + synchronize( run, true ); + } + } +}; + +// Root QUnit object. +// `QUnit` initialized at top of scope +QUnit = { + + // call on start of module test to prepend name to all tests + module: function( name, testEnvironment ) { + config.currentModule = name; + config.currentModuleTestEnvironment = testEnvironment; + config.modules[name] = true; + }, + + asyncTest: function( testName, expected, callback ) { + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + QUnit.test( testName, expected, callback, true ); + }, + + test: function( testName, expected, callback, async ) { + var test, + nameHtml = "" + escapeText( testName ) + ""; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + if ( config.currentModule ) { + nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml; + } + + test = new Test({ + nameHtml: nameHtml, + testName: testName, + expected: expected, + async: async, + callback: callback, + module: config.currentModule, + moduleTestEnvironment: config.currentModuleTestEnvironment, + stack: sourceFromStacktrace( 2 ) + }); + + if ( !validTest( test ) ) { + return; + } + + test.queue(); + }, + + // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. + expect: function( asserts ) { + if (arguments.length === 1) { + config.current.expected = asserts; + } else { + return config.current.expected; + } + }, + + start: function( count ) { + // QUnit hasn't been initialized yet. + // Note: RequireJS (et al) may delay onLoad + if ( config.semaphore === undefined ) { + QUnit.begin(function() { + // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first + setTimeout(function() { + QUnit.start( count ); + }); + }); + return; + } + + config.semaphore -= count || 1; + // don't start until equal number of stop-calls + if ( config.semaphore > 0 ) { + return; + } + // ignore if start is called more often then stop + if ( config.semaphore < 0 ) { + config.semaphore = 0; + QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) ); + return; + } + // A slight delay, to avoid any current callbacks + if ( defined.setTimeout ) { + window.setTimeout(function() { + if ( config.semaphore > 0 ) { + return; + } + if ( config.timeout ) { + clearTimeout( config.timeout ); + } + + config.blocking = false; + process( true ); + }, 13); + } else { + config.blocking = false; + process( true ); + } + }, + + stop: function( count ) { + config.semaphore += count || 1; + config.blocking = true; + + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout( config.timeout ); + config.timeout = window.setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + config.semaphore = 1; + QUnit.start(); + }, config.testTimeout ); + } + } +}; + +// `assert` initialized at top of scope +// Asssert helpers +// All of these must either call QUnit.push() or manually do: +// - runLoggingCallbacks( "log", .. ); +// - config.current.assertions.push({ .. }); +// We attach it to the QUnit object *after* we expose the public API, +// otherwise `assert` will become a global variable in browsers (#341). +assert = { + /** + * Asserts rough true-ish result. + * @name ok + * @function + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function( result, msg ) { + if ( !config.current ) { + throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + result = !!result; + + var source, + details = { + module: config.current.module, + name: config.current.testName, + result: result, + message: msg + }; + + msg = escapeText( msg || (result ? "okay" : "failed" ) ); + msg = "" + msg + ""; + + if ( !result ) { + source = sourceFromStacktrace( 2 ); + if ( source ) { + details.source = source; + msg += "
Source:
" + escapeText( source ) + "
"; + } + } + runLoggingCallbacks( "log", QUnit, details ); + config.current.assertions.push({ + result: result, + message: msg + }); + }, + + /** + * Assert that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * @name equal + * @function + * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); + */ + equal: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + QUnit.push( expected == actual, actual, expected, message ); + }, + + /** + * @name notEqual + * @function + */ + notEqual: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + QUnit.push( expected != actual, actual, expected, message ); + }, + + /** + * @name propEqual + * @function + */ + propEqual: function( actual, expected, message ) { + actual = objectValues(actual); + expected = objectValues(expected); + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name notPropEqual + * @function + */ + notPropEqual: function( actual, expected, message ) { + actual = objectValues(actual); + expected = objectValues(expected); + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name deepEqual + * @function + */ + deepEqual: function( actual, expected, message ) { + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name notDeepEqual + * @function + */ + notDeepEqual: function( actual, expected, message ) { + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name strictEqual + * @function + */ + strictEqual: function( actual, expected, message ) { + QUnit.push( expected === actual, actual, expected, message ); + }, + + /** + * @name notStrictEqual + * @function + */ + notStrictEqual: function( actual, expected, message ) { + QUnit.push( expected !== actual, actual, expected, message ); + }, + + "throws": function( block, expected, message ) { + var actual, + expectedOutput = expected, + ok = false; + + // 'expected' is optional + if ( typeof expected === "string" ) { + message = expected; + expected = null; + } + + config.current.ignoreGlobalErrors = true; + try { + block.call( config.current.testEnvironment ); + } catch (e) { + actual = e; + } + config.current.ignoreGlobalErrors = false; + + if ( actual ) { + // we don't want to validate thrown error + if ( !expected ) { + ok = true; + expectedOutput = null; + // expected is a regexp + } else if ( QUnit.objectType( expected ) === "regexp" ) { + ok = expected.test( errorString( actual ) ); + // expected is a constructor + } else if ( actual instanceof expected ) { + ok = true; + // expected is a validation function which returns true is validation passed + } else if ( expected.call( {}, actual ) === true ) { + expectedOutput = null; + ok = true; + } + + QUnit.push( ok, actual, expectedOutput, message ); + } else { + QUnit.pushFailure( message, null, 'No exception was thrown.' ); + } + } +}; + +/** + * @deprecate since 1.8.0 + * Kept assertion helpers in root for backwards compatibility. + */ +extend( QUnit, assert ); + +/** + * @deprecated since 1.9.0 + * Kept root "raises()" for backwards compatibility. + * (Note that we don't introduce assert.raises). + */ +QUnit.raises = assert[ "throws" ]; + +/** + * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 + * Kept to avoid TypeErrors for undefined methods. + */ +QUnit.equals = function() { + QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); +}; +QUnit.same = function() { + QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); +}; + +// We want access to the constructor's prototype +(function() { + function F() {} + F.prototype = QUnit; + QUnit = new F(); + // Make F QUnit's constructor so that we can add to the prototype later + QUnit.constructor = F; +}()); + +/** + * Config object: Maintain internal state + * Later exposed as QUnit.config + * `config` initialized at top of scope + */ +config = { + // The queue of tests to run + queue: [], + + // block until document ready + blocking: true, + + // when enabled, show only failing tests + // gets persisted through sessionStorage and can be changed in UI via checkbox + hidepassed: false, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + // by default, modify document.title when suite is done + altertitle: true, + + // when enabled, all tests must call expect() + requireExpects: false, + + // add checkboxes that are persisted in the query-string + // when enabled, the id is set to `true` as a `QUnit.config` property + urlConfig: [ + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." + } + ], + + // Set of all modules. + modules: {}, + + // logging callback queues + begin: [], + done: [], + log: [], + testStart: [], + testDone: [], + moduleStart: [], + moduleDone: [] +}; + +// Export global variables, unless an 'exports' object exists, +// in that case we assume we're in CommonJS (dealt with on the bottom of the script) +if ( typeof exports === "undefined" ) { + extend( window, QUnit ); + + // Expose QUnit object + window.QUnit = QUnit; +} + +// Initialize more QUnit.config and QUnit.urlParams +(function() { + var i, + location = window.location || { search: "", protocol: "file:" }, + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}, + current; + + if ( params[ 0 ] ) { + for ( i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + urlParams[ current[ 0 ] ] = current[ 1 ]; + } + } + + QUnit.urlParams = urlParams; + + // String search anywhere in moduleName+testName + config.filter = urlParams.filter; + + // Exact match of the module name + config.module = urlParams.module; + + config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; + + // Figure out if we're running the tests from a server or not + QUnit.isLocal = location.protocol === "file:"; +}()); + +// Extend QUnit object, +// these after set here because they should not be exposed as global functions +extend( QUnit, { + assert: assert, + + config: config, + + // Initialize the configuration options + init: function() { + extend( config, { + stats: { all: 0, bad: 0 }, + moduleStats: { all: 0, bad: 0 }, + started: +new Date(), + updateRate: 1000, + blocking: false, + autostart: true, + autorun: false, + filter: "", + queue: [], + semaphore: 1 + }); + + var tests, banner, result, + qunit = id( "qunit" ); + + if ( qunit ) { + qunit.innerHTML = + "

" + escapeText( document.title ) + "

" + + "

" + + "
" + + "

" + + "
    "; + } + + tests = id( "qunit-tests" ); + banner = id( "qunit-banner" ); + result = id( "qunit-testresult" ); + + if ( tests ) { + tests.innerHTML = ""; + } + + if ( banner ) { + banner.className = ""; + } + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...
     "; + } + }, + + // Resets the test setup. Useful for tests that modify the DOM. + reset: function() { + var fixture = id( "qunit-fixture" ); + if ( fixture ) { + fixture.innerHTML = config.fixture; + } + }, + + // Trigger an event on an element. + // @example triggerEvent( document.body, "click" ); + triggerEvent: function( elem, type, event ) { + if ( document.createEvent ) { + event = document.createEvent( "MouseEvents" ); + event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + + elem.dispatchEvent( event ); + } else if ( elem.fireEvent ) { + elem.fireEvent( "on" + type ); + } + }, + + // Safe object type checking + is: function( type, obj ) { + return QUnit.objectType( obj ) === type; + }, + + objectType: function( obj ) { + if ( typeof obj === "undefined" ) { + return "undefined"; + // consider: typeof null === object + } + if ( obj === null ) { + return "null"; + } + + var match = toString.call( obj ).match(/^\[object\s(.*)\]$/), + type = match && match[1] || ""; + + switch ( type ) { + case "Number": + if ( isNaN(obj) ) { + return "nan"; + } + return "number"; + case "String": + case "Boolean": + case "Array": + case "Date": + case "RegExp": + case "Function": + return type.toLowerCase(); + } + if ( typeof obj === "object" ) { + return "object"; + } + return undefined; + }, + + push: function( result, actual, expected, message ) { + if ( !config.current ) { + throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); + } + + var output, source, + details = { + module: config.current.module, + name: config.current.testName, + result: result, + message: message, + actual: actual, + expected: expected + }; + + message = escapeText( message ) || ( result ? "okay" : "failed" ); + message = "" + message + ""; + output = message; + + if ( !result ) { + expected = escapeText( QUnit.jsDump.parse(expected) ); + actual = escapeText( QUnit.jsDump.parse(actual) ); + output += ""; + + if ( actual !== expected ) { + output += ""; + output += ""; + } + + source = sourceFromStacktrace(); + + if ( source ) { + details.source = source; + output += ""; + } + + output += "
    Expected:
    " + expected + "
    Result:
    " + actual + "
    Diff:
    " + QUnit.diff( expected, actual ) + "
    Source:
    " + escapeText( source ) + "
    "; + } + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: !!result, + message: output + }); + }, + + pushFailure: function( message, source, actual ) { + if ( !config.current ) { + throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + + var output, + details = { + module: config.current.module, + name: config.current.testName, + result: false, + message: message + }; + + message = escapeText( message ) || "error"; + message = "" + message + ""; + output = message; + + output += ""; + + if ( actual ) { + output += ""; + } + + if ( source ) { + details.source = source; + output += ""; + } + + output += "
    Result:
    " + escapeText( actual ) + "
    Source:
    " + escapeText( source ) + "
    "; + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: false, + message: output + }); + }, + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var key, + querystring = "?"; + + for ( key in params ) { + if ( !hasOwn.call( params, key ) ) { + continue; + } + querystring += encodeURIComponent( key ) + "=" + + encodeURIComponent( params[ key ] ) + "&"; + } + return window.location.protocol + "//" + window.location.host + + window.location.pathname + querystring.slice( 0, -1 ); + }, + + extend: extend, + id: id, + addEvent: addEvent + // load, equiv, jsDump, diff: Attached later +}); + +/** + * @deprecated: Created for backwards compatibility with test runner that set the hook function + * into QUnit.{hook}, instead of invoking it and passing the hook function. + * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. + * Doing this allows us to tell if the following methods have been overwritten on the actual + * QUnit object. + */ +extend( QUnit.constructor.prototype, { + + // Logging callbacks; all receive a single argument with the listed properties + // run test/logs.html for any related changes + begin: registerLoggingCallback( "begin" ), + + // done: { failed, passed, total, runtime } + done: registerLoggingCallback( "done" ), + + // log: { result, actual, expected, message } + log: registerLoggingCallback( "log" ), + + // testStart: { name } + testStart: registerLoggingCallback( "testStart" ), + + // testDone: { name, failed, passed, total, duration } + testDone: registerLoggingCallback( "testDone" ), + + // moduleStart: { name } + moduleStart: registerLoggingCallback( "moduleStart" ), + + // moduleDone: { name, failed, passed, total } + moduleDone: registerLoggingCallback( "moduleDone" ) +}); + +if ( typeof document === "undefined" || document.readyState === "complete" ) { + config.autorun = true; +} + +QUnit.load = function() { + runLoggingCallbacks( "begin", QUnit, {} ); + + // Initialize the config, saving the execution queue + var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, + urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter, + numModules = 0, + moduleFilterHtml = "", + urlConfigHtml = "", + oldconfig = extend( {}, config ); + + QUnit.init(); + extend(config, oldconfig); + + config.blocking = false; + + len = config.urlConfig.length; + + for ( i = 0; i < len; i++ ) { + val = config.urlConfig[i]; + if ( typeof val === "string" ) { + val = { + id: val, + label: val, + tooltip: "[no tooltip available]" + }; + } + config[ val.id ] = QUnit.urlParams[ val.id ]; + urlConfigHtml += ""; + } + + moduleFilterHtml += ""; + + // `userAgent` initialized at top of scope + userAgent = id( "qunit-userAgent" ); + if ( userAgent ) { + userAgent.innerHTML = navigator.userAgent; + } + + // `banner` initialized at top of scope + banner = id( "qunit-header" ); + if ( banner ) { + banner.innerHTML = "" + banner.innerHTML + " "; + } + + // `toolbar` initialized at top of scope + toolbar = id( "qunit-testrunner-toolbar" ); + if ( toolbar ) { + // `filter` initialized at top of scope + filter = document.createElement( "input" ); + filter.type = "checkbox"; + filter.id = "qunit-filter-pass"; + + addEvent( filter, "click", function() { + var tmp, + ol = document.getElementById( "qunit-tests" ); + + if ( filter.checked ) { + ol.className = ol.className + " hidepass"; + } else { + tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; + ol.className = tmp.replace( / hidepass /, " " ); + } + if ( defined.sessionStorage ) { + if (filter.checked) { + sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); + } else { + sessionStorage.removeItem( "qunit-filter-passed-tests" ); + } + } + }); + + if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { + filter.checked = true; + // `ol` initialized at top of scope + ol = document.getElementById( "qunit-tests" ); + ol.className = ol.className + " hidepass"; + } + toolbar.appendChild( filter ); + + // `label` initialized at top of scope + label = document.createElement( "label" ); + label.setAttribute( "for", "qunit-filter-pass" ); + label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." ); + label.innerHTML = "Hide passed tests"; + toolbar.appendChild( label ); + + urlConfigCheckboxesContainer = document.createElement("span"); + urlConfigCheckboxesContainer.innerHTML = urlConfigHtml; + urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input"); + // For oldIE support: + // * Add handlers to the individual elements instead of the container + // * Use "click" instead of "change" + // * Fallback from event.target to event.srcElement + addEvents( urlConfigCheckboxes, "click", function( event ) { + var params = {}, + target = event.target || event.srcElement; + params[ target.name ] = target.checked ? true : undefined; + window.location = QUnit.url( params ); + }); + toolbar.appendChild( urlConfigCheckboxesContainer ); + + if (numModules > 1) { + moduleFilter = document.createElement( 'span' ); + moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' ); + moduleFilter.innerHTML = moduleFilterHtml; + addEvent( moduleFilter.lastChild, "change", function() { + var selectBox = moduleFilter.getElementsByTagName("select")[0], + selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value); + + window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } ); + }); + toolbar.appendChild(moduleFilter); + } + } + + // `main` initialized at top of scope + main = id( "qunit-fixture" ); + if ( main ) { + config.fixture = main.innerHTML; + } + + if ( config.autostart ) { + QUnit.start(); + } +}; + +addEvent( window, "load", QUnit.load ); + +// `onErrorFnPrev` initialized at top of scope +// Preserve other handlers +onErrorFnPrev = window.onerror; + +// Cover uncaught exceptions +// Returning true will surpress the default browser handler, +// returning false will let it run. +window.onerror = function ( error, filePath, linerNr ) { + var ret = false; + if ( onErrorFnPrev ) { + ret = onErrorFnPrev( error, filePath, linerNr ); + } + + // Treat return value as window.onerror itself does, + // Only do our handling if not surpressed. + if ( ret !== true ) { + if ( QUnit.config.current ) { + if ( QUnit.config.current.ignoreGlobalErrors ) { + return true; + } + QUnit.pushFailure( error, filePath + ":" + linerNr ); + } else { + QUnit.test( "global failure", extend( function() { + QUnit.pushFailure( error, filePath + ":" + linerNr ); + }, { validTest: validTest } ) ); + } + return false; + } + + return ret; +}; + +function done() { + config.autorun = true; + + // Log the last module results + if ( config.currentModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.currentModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + + var i, key, + banner = id( "qunit-banner" ), + tests = id( "qunit-tests" ), + runtime = +new Date() - config.started, + passed = config.stats.all - config.stats.bad, + html = [ + "Tests completed in ", + runtime, + " milliseconds.
    ", + "", + passed, + " assertions of ", + config.stats.all, + " passed, ", + config.stats.bad, + " failed." + ].join( "" ); + + if ( banner ) { + banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); + } + + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } + + if ( config.altertitle && typeof document !== "undefined" && document.title ) { + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + ( config.stats.bad ? "\u2716" : "\u2714" ), + document.title.replace( /^[\u2714\u2716] /i, "" ) + ].join( " " ); + } + + // clear own sessionStorage items if all tests passed + if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { + // `key` & `i` initialized at top of scope + for ( i = 0; i < sessionStorage.length; i++ ) { + key = sessionStorage.key( i++ ); + if ( key.indexOf( "qunit-test-" ) === 0 ) { + sessionStorage.removeItem( key ); + } + } + } + + // scroll back to top to show results + if ( window.scrollTo ) { + window.scrollTo(0, 0); + } + + runLoggingCallbacks( "done", QUnit, { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + }); +} + +/** @return Boolean: true if this test should be ran */ +function validTest( test ) { + var include, + filter = config.filter && config.filter.toLowerCase(), + module = config.module && config.module.toLowerCase(), + fullName = (test.module + ": " + test.testName).toLowerCase(); + + // Internally-generated tests are always valid + if ( test.callback && test.callback.validTest === validTest ) { + delete test.callback.validTest; + return true; + } + + if ( config.testNumber ) { + return test.testNumber === config.testNumber; + } + + if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { + return false; + } + + if ( !filter ) { + return true; + } + + include = filter.charAt( 0 ) !== "!"; + if ( !include ) { + filter = filter.slice( 1 ); + } + + // If the filter matches, we need to honour include + if ( fullName.indexOf( filter ) !== -1 ) { + return include; + } + + // Otherwise, do the opposite + return !include; +} + +// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) +// Later Safari and IE10 are supposed to support error.stack as well +// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack +function extractStacktrace( e, offset ) { + offset = offset === undefined ? 3 : offset; + + var stack, include, i; + + if ( e.stacktrace ) { + // Opera + return e.stacktrace.split( "\n" )[ offset + 3 ]; + } else if ( e.stack ) { + // Firefox, Chrome + stack = e.stack.split( "\n" ); + if (/^error$/i.test( stack[0] ) ) { + stack.shift(); + } + if ( fileName ) { + include = []; + for ( i = offset; i < stack.length; i++ ) { + if ( stack[ i ].indexOf( fileName ) !== -1 ) { + break; + } + include.push( stack[ i ] ); + } + if ( include.length ) { + return include.join( "\n" ); + } + } + return stack[ offset ]; + } else if ( e.sourceURL ) { + // Safari, PhantomJS + // hopefully one day Safari provides actual stacktraces + // exclude useless self-reference for generated Error objects + if ( /qunit.js$/.test( e.sourceURL ) ) { + return; + } + // for actual exceptions, this is useful + return e.sourceURL + ":" + e.line; + } +} +function sourceFromStacktrace( offset ) { + try { + throw new Error(); + } catch ( e ) { + return extractStacktrace( e, offset ); + } +} + +/** + * Escape text for attribute or text content. + */ +function escapeText( s ) { + if ( !s ) { + return ""; + } + s = s + ""; + // Both single quotes and double quotes (for attributes) + return s.replace( /['"<>&]/g, function( s ) { + switch( s ) { + case '\'': + return '''; + case '"': + return '"'; + case '<': + return '<'; + case '>': + return '>'; + case '&': + return '&'; + } + }); +} + +function synchronize( callback, last ) { + config.queue.push( callback ); + + if ( config.autorun && !config.blocking ) { + process( last ); + } +} + +function process( last ) { + function next() { + process( last ); + } + var start = new Date().getTime(); + config.depth = config.depth ? config.depth + 1 : 1; + + while ( config.queue.length && !config.blocking ) { + if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { + config.queue.shift()(); + } else { + window.setTimeout( next, 13 ); + break; + } + } + config.depth--; + if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { + done(); + } +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in window ) { + // in Opera sometimes DOM element ids show up here, ignore them + if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) { + continue; + } + config.pollution.push( key ); + } + } +} + +function checkPollution() { + var newGlobals, + deletedGlobals, + old = config.pollution; + + saveGlobal(); + + newGlobals = diff( config.pollution, old ); + if ( newGlobals.length > 0 ) { + QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); + } + + deletedGlobals = diff( old, config.pollution ); + if ( deletedGlobals.length > 0 ) { + QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); + } +} + +// returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var i, j, + result = a.slice(); + + for ( i = 0; i < result.length; i++ ) { + for ( j = 0; j < b.length; j++ ) { + if ( result[i] === b[j] ) { + result.splice( i, 1 ); + i--; + break; + } + } + } + return result; +} + +function extend( a, b ) { + for ( var prop in b ) { + if ( b[ prop ] === undefined ) { + delete a[ prop ]; + + // Avoid "Member not found" error in IE8 caused by setting window.constructor + } else if ( prop !== "constructor" || a !== window ) { + a[ prop ] = b[ prop ]; + } + } + + return a; +} + +/** + * @param {HTMLElement} elem + * @param {string} type + * @param {Function} fn + */ +function addEvent( elem, type, fn ) { + // Standards-based browsers + if ( elem.addEventListener ) { + elem.addEventListener( type, fn, false ); + // IE + } else { + elem.attachEvent( "on" + type, fn ); + } +} + +/** + * @param {Array|NodeList} elems + * @param {string} type + * @param {Function} fn + */ +function addEvents( elems, type, fn ) { + var i = elems.length; + while ( i-- ) { + addEvent( elems[i], type, fn ); + } +} + +function hasClass( elem, name ) { + return (" " + elem.className + " ").indexOf(" " + name + " ") > -1; +} + +function addClass( elem, name ) { + if ( !hasClass( elem, name ) ) { + elem.className += (elem.className ? " " : "") + name; + } +} + +function removeClass( elem, name ) { + var set = " " + elem.className + " "; + // Class name may appear multiple times + while ( set.indexOf(" " + name + " ") > -1 ) { + set = set.replace(" " + name + " " , " "); + } + // If possible, trim it for prettiness, but not neccecarily + elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set ); +} + +function id( name ) { + return !!( typeof document !== "undefined" && document && document.getElementById ) && + document.getElementById( name ); +} + +function registerLoggingCallback( key ) { + return function( callback ) { + config[key].push( callback ); + }; +} + +// Supports deprecated method of completely overwriting logging callbacks +function runLoggingCallbacks( key, scope, args ) { + var i, callbacks; + if ( QUnit.hasOwnProperty( key ) ) { + QUnit[ key ].call(scope, args ); + } else { + callbacks = config[ key ]; + for ( i = 0; i < callbacks.length; i++ ) { + callbacks[ i ].call( scope, args ); + } + } +} + +// Test for equality any JavaScript type. +// Author: Philippe Rathé +QUnit.equiv = (function() { + + // Call the o related callback with the given arguments. + function bindCallbacks( o, callbacks, args ) { + var prop = QUnit.objectType( o ); + if ( prop ) { + if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { + return callbacks[ prop ].apply( callbacks, args ); + } else { + return callbacks[ prop ]; // or undefined + } + } + } + + // the real equiv function + var innerEquiv, + // stack to decide between skip/abort functions + callers = [], + // stack to avoiding loops from circular referencing + parents = [], + + getProto = Object.getPrototypeOf || function ( obj ) { + return obj.__proto__; + }, + callbacks = (function () { + + // for string, boolean, number and null + function useStrictEquality( b, a ) { + /*jshint eqeqeq:false */ + if ( b instanceof a.constructor || a instanceof b.constructor ) { + // to catch short annotaion VS 'new' annotation of a + // declaration + // e.g. var i = 1; + // var j = new Number(1); + return a == b; + } else { + return a === b; + } + } + + return { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + + "nan": function( b ) { + return isNaN( b ); + }, + + "date": function( b, a ) { + return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function( b, a ) { + return QUnit.objectType( b ) === "regexp" && + // the regex itself + a.source === b.source && + // and its modifers + a.global === b.global && + // (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline && + a.sticky === b.sticky; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function() { + var caller = callers[callers.length - 1]; + return caller !== Object && typeof caller !== "undefined"; + }, + + "array": function( b, a ) { + var i, j, len, loop; + + // b could be an object literal here + if ( QUnit.objectType( b ) !== "array" ) { + return false; + } + + len = a.length; + if ( len !== b.length ) { + // safe and faster + return false; + } + + // track reference to avoid circular references + parents.push( a ); + for ( i = 0; i < len; i++ ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + if ( parents[j] === a[i] ) { + loop = true;// dont rewalk array + } + } + if ( !loop && !innerEquiv(a[i], b[i]) ) { + parents.pop(); + return false; + } + } + parents.pop(); + return true; + }, + + "object": function( b, a ) { + var i, j, loop, + // Default to true + eq = true, + aProperties = [], + bProperties = []; + + // comparing constructors is more strict than using + // instanceof + if ( a.constructor !== b.constructor ) { + // Allow objects with no prototype to be equivalent to + // objects with Object as their constructor. + if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || + ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { + return false; + } + } + + // stack constructor before traversing properties + callers.push( a.constructor ); + // track reference to avoid circular references + parents.push( a ); + + for ( i in a ) { // be strict: don't ensures hasOwnProperty + // and go deep + loop = false; + for ( j = 0; j < parents.length; j++ ) { + if ( parents[j] === a[i] ) { + // don't go down the same path twice + loop = true; + } + } + aProperties.push(i); // collect a's properties + + if (!loop && !innerEquiv( a[i], b[i] ) ) { + eq = false; + break; + } + } + + callers.pop(); // unstack, we are done + parents.pop(); + + for ( i in b ) { + bProperties.push( i ); // collect b's properties + } + + // Ensures identical properties name + return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); + } + }; + }()); + + innerEquiv = function() { // can take multiple arguments + var args = [].slice.apply( arguments ); + if ( args.length < 2 ) { + return true; // end transition + } + + return (function( a, b ) { + if ( a === b ) { + return true; // catch the most you can + } else if ( a === null || b === null || typeof a === "undefined" || + typeof b === "undefined" || + QUnit.objectType(a) !== QUnit.objectType(b) ) { + return false; // don't lose time with error prone cases + } else { + return bindCallbacks(a, callbacks, [ b, a ]); + } + + // apply transition with (1..n) arguments + }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) ); + }; + + return innerEquiv; +}()); + +/** + * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | + * http://flesler.blogspot.com Licensed under BSD + * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 + * + * @projectDescription Advanced and extensible data dumping for Javascript. + * @version 1.0.0 + * @author Ariel Flesler + * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} + */ +QUnit.jsDump = (function() { + function quote( str ) { + return '"' + str.toString().replace( /"/g, '\\"' ) + '"'; + } + function literal( o ) { + return o + ""; + } + function join( pre, arr, post ) { + var s = jsDump.separator(), + base = jsDump.indent(), + inner = jsDump.indent(1); + if ( arr.join ) { + arr = arr.join( "," + s + inner ); + } + if ( !arr ) { + return pre + post; + } + return [ pre, inner + arr, base + post ].join(s); + } + function array( arr, stack ) { + var i = arr.length, ret = new Array(i); + this.up(); + while ( i-- ) { + ret[i] = this.parse( arr[i] , undefined , stack); + } + this.down(); + return join( "[", ret, "]" ); + } + + var reName = /^function (\w+)/, + jsDump = { + // type is used mostly internally, you can fix a (custom)type in advance + parse: function( obj, type, stack ) { + stack = stack || [ ]; + var inStack, res, + parser = this.parsers[ type || this.typeOf(obj) ]; + + type = typeof parser; + inStack = inArray( obj, stack ); + + if ( inStack !== -1 ) { + return "recursion(" + (inStack - stack.length) + ")"; + } + if ( type === "function" ) { + stack.push( obj ); + res = parser.call( this, obj, stack ); + stack.pop(); + return res; + } + return ( type === "string" ) ? parser : this.parsers.error; + }, + typeOf: function( obj ) { + var type; + if ( obj === null ) { + type = "null"; + } else if ( typeof obj === "undefined" ) { + type = "undefined"; + } else if ( QUnit.is( "regexp", obj) ) { + type = "regexp"; + } else if ( QUnit.is( "date", obj) ) { + type = "date"; + } else if ( QUnit.is( "function", obj) ) { + type = "function"; + } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { + type = "window"; + } else if ( obj.nodeType === 9 ) { + type = "document"; + } else if ( obj.nodeType ) { + type = "node"; + } else if ( + // native arrays + toString.call( obj ) === "[object Array]" || + // NodeList objects + ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) + ) { + type = "array"; + } else if ( obj.constructor === Error.prototype.constructor ) { + type = "error"; + } else { + type = typeof obj; + } + return type; + }, + separator: function() { + return this.multiline ? this.HTML ? "
    " : "\n" : this.HTML ? " " : " "; + }, + // extra can be a number, shortcut for increasing-calling-decreasing + indent: function( extra ) { + if ( !this.multiline ) { + return ""; + } + var chr = this.indentChar; + if ( this.HTML ) { + chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); + } + return new Array( this._depth_ + (extra||0) ).join(chr); + }, + up: function( a ) { + this._depth_ += a || 1; + }, + down: function( a ) { + this._depth_ -= a || 1; + }, + setParser: function( name, parser ) { + this.parsers[name] = parser; + }, + // The next 3 are exposed so you can use them + quote: quote, + literal: literal, + join: join, + // + _depth_: 1, + // This is the list of parsers, to modify them, use jsDump.setParser + parsers: { + window: "[Window]", + document: "[Document]", + error: function(error) { + return "Error(\"" + error.message + "\")"; + }, + unknown: "[Unknown]", + "null": "null", + "undefined": "undefined", + "function": function( fn ) { + var ret = "function", + // functions never have name in IE + name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1]; + + if ( name ) { + ret += " " + name; + } + ret += "( "; + + ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); + return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); + }, + array: array, + nodelist: array, + "arguments": array, + object: function( map, stack ) { + var ret = [ ], keys, key, val, i; + QUnit.jsDump.up(); + keys = []; + for ( key in map ) { + keys.push( key ); + } + keys.sort(); + for ( i = 0; i < keys.length; i++ ) { + key = keys[ i ]; + val = map[ key ]; + ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); + } + QUnit.jsDump.down(); + return join( "{", ret, "}" ); + }, + node: function( node ) { + var len, i, val, + open = QUnit.jsDump.HTML ? "<" : "<", + close = QUnit.jsDump.HTML ? ">" : ">", + tag = node.nodeName.toLowerCase(), + ret = open + tag, + attrs = node.attributes; + + if ( attrs ) { + for ( i = 0, len = attrs.length; i < len; i++ ) { + val = attrs[i].nodeValue; + // IE6 includes all attributes in .attributes, even ones not explicitly set. + // Those have values like undefined, null, 0, false, "" or "inherit". + if ( val && val !== "inherit" ) { + ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" ); + } + } + } + ret += close; + + // Show content of TextNode or CDATASection + if ( node.nodeType === 3 || node.nodeType === 4 ) { + ret += node.nodeValue; + } + + return ret + open + "/" + tag + close; + }, + // function calls it internally, it's the arguments part of the function + functionArgs: function( fn ) { + var args, + l = fn.length; + + if ( !l ) { + return ""; + } + + args = new Array(l); + while ( l-- ) { + // 97 is 'a' + args[l] = String.fromCharCode(97+l); + } + return " " + args.join( ", " ) + " "; + }, + // object calls it internally, the key part of an item in a map + key: quote, + // function calls it internally, it's the content of the function + functionCode: "[code]", + // node calls it internally, it's an html attribute value + attribute: quote, + string: quote, + date: quote, + regexp: literal, + number: literal, + "boolean": literal + }, + // if true, entities are escaped ( <, >, \t, space and \n ) + HTML: false, + // indentation unit + indentChar: " ", + // if true, items in a collection, are separated by a \n, else just a space. + multiline: true + }; + + return jsDump; +}()); + +// from jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; +} + +/* + * Javascript Diff Algorithm + * By John Resig (http://ejohn.org/) + * Modified by Chu Alan "sprite" + * + * Released under the MIT license. + * + * More Info: + * http://ejohn.org/projects/javascript-diff-algorithm/ + * + * Usage: QUnit.diff(expected, actual) + * + * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" + */ +QUnit.diff = (function() { + /*jshint eqeqeq:false, eqnull:true */ + function diff( o, n ) { + var i, + ns = {}, + os = {}; + + for ( i = 0; i < n.length; i++ ) { + if ( !hasOwn.call( ns, n[i] ) ) { + ns[ n[i] ] = { + rows: [], + o: null + }; + } + ns[ n[i] ].rows.push( i ); + } + + for ( i = 0; i < o.length; i++ ) { + if ( !hasOwn.call( os, o[i] ) ) { + os[ o[i] ] = { + rows: [], + n: null + }; + } + os[ o[i] ].rows.push( i ); + } + + for ( i in ns ) { + if ( !hasOwn.call( ns, i ) ) { + continue; + } + if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) { + n[ ns[i].rows[0] ] = { + text: n[ ns[i].rows[0] ], + row: os[i].rows[0] + }; + o[ os[i].rows[0] ] = { + text: o[ os[i].rows[0] ], + row: ns[i].rows[0] + }; + } + } + + for ( i = 0; i < n.length - 1; i++ ) { + if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && + n[ i + 1 ] == o[ n[i].row + 1 ] ) { + + n[ i + 1 ] = { + text: n[ i + 1 ], + row: n[i].row + 1 + }; + o[ n[i].row + 1 ] = { + text: o[ n[i].row + 1 ], + row: i + 1 + }; + } + } + + for ( i = n.length - 1; i > 0; i-- ) { + if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && + n[ i - 1 ] == o[ n[i].row - 1 ]) { + + n[ i - 1 ] = { + text: n[ i - 1 ], + row: n[i].row - 1 + }; + o[ n[i].row - 1 ] = { + text: o[ n[i].row - 1 ], + row: i - 1 + }; + } + } + + return { + o: o, + n: n + }; + } + + return function( o, n ) { + o = o.replace( /\s+$/, "" ); + n = n.replace( /\s+$/, "" ); + + var i, pre, + str = "", + out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), + oSpace = o.match(/\s+/g), + nSpace = n.match(/\s+/g); + + if ( oSpace == null ) { + oSpace = [ " " ]; + } + else { + oSpace.push( " " ); + } + + if ( nSpace == null ) { + nSpace = [ " " ]; + } + else { + nSpace.push( " " ); + } + + if ( out.n.length === 0 ) { + for ( i = 0; i < out.o.length; i++ ) { + str += "" + out.o[i] + oSpace[i] + ""; + } + } + else { + if ( out.n[0].text == null ) { + for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { + str += "" + out.o[n] + oSpace[n] + ""; + } + } + + for ( i = 0; i < out.n.length; i++ ) { + if (out.n[i].text == null) { + str += "" + out.n[i] + nSpace[i] + ""; + } + else { + // `pre` initialized at top of scope + pre = ""; + + for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { + pre += "" + out.o[n] + oSpace[n] + ""; + } + str += " " + out.n[i].text + nSpace[i] + pre; + } + } + } + + return str; + }; +}()); + +// for CommonJS enviroments, export everything +if ( typeof exports !== "undefined" ) { + extend( exports, QUnit ); +} + +// get at whatever the global object is, like window in browsers +}( (function() {return this;}.call()) )); \ No newline at end of file diff --git a/js/jquery-mask/test/sinon-1.10.3.js b/js/jquery-mask/test/sinon-1.10.3.js new file mode 100755 index 0000000000..703414dd49 --- /dev/null +++ b/js/jquery-mask/test/sinon-1.10.3.js @@ -0,0 +1,5073 @@ +/** + * Sinon.JS 1.10.3, 2014/07/11 + * + * @author Christian Johansen (christian@cjohansen.no) + * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS + * + * (The BSD License) + * + * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Christian Johansen nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +this.sinon = (function () { +var samsam, formatio; +function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else if (typeof fn === "function") { formatio = fn(samsam); } } +define.amd = {}; +((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) || + (typeof module === "object" && + function (m) { module.exports = m(); }) || // Node + function (m) { this.samsam = m(); } // Browser globals +)(function () { + var o = Object.prototype; + var div = typeof document !== "undefined" && document.createElement("div"); + + function isNaN(value) { + // Unlike global isNaN, this avoids type coercion + // typeof check avoids IE host object issues, hat tip to + // lodash + var val = value; // JsLint thinks value !== value is "weird" + return typeof value === "number" && value !== val; + } + + function getClass(value) { + // Returns the internal [[Class]] by calling Object.prototype.toString + // with the provided value as this. Return value is a string, naming the + // internal class, e.g. "Array" + return o.toString.call(value).split(/[ \]]/)[1]; + } + + /** + * @name samsam.isArguments + * @param Object object + * + * Returns ``true`` if ``object`` is an ``arguments`` object, + * ``false`` otherwise. + */ + function isArguments(object) { + if (typeof object !== "object" || typeof object.length !== "number" || + getClass(object) === "Array") { + return false; + } + if (typeof object.callee == "function") { return true; } + try { + object[object.length] = 6; + delete object[object.length]; + } catch (e) { + return true; + } + return false; + } + + /** + * @name samsam.isElement + * @param Object object + * + * Returns ``true`` if ``object`` is a DOM element node. Unlike + * Underscore.js/lodash, this function will return ``false`` if ``object`` + * is an *element-like* object, i.e. a regular object with a ``nodeType`` + * property that holds the value ``1``. + */ + function isElement(object) { + if (!object || object.nodeType !== 1 || !div) { return false; } + try { + object.appendChild(div); + object.removeChild(div); + } catch (e) { + return false; + } + return true; + } + + /** + * @name samsam.keys + * @param Object object + * + * Return an array of own property names. + */ + function keys(object) { + var ks = [], prop; + for (prop in object) { + if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); } + } + return ks; + } + + /** + * @name samsam.isDate + * @param Object value + * + * Returns true if the object is a ``Date``, or *date-like*. Duck typing + * of date objects work by checking that the object has a ``getTime`` + * function whose return value equals the return value from the object's + * ``valueOf``. + */ + function isDate(value) { + return typeof value.getTime == "function" && + value.getTime() == value.valueOf(); + } + + /** + * @name samsam.isNegZero + * @param Object value + * + * Returns ``true`` if ``value`` is ``-0``. + */ + function isNegZero(value) { + return value === 0 && 1 / value === -Infinity; + } + + /** + * @name samsam.equal + * @param Object obj1 + * @param Object obj2 + * + * Returns ``true`` if two objects are strictly equal. Compared to + * ``===`` there are two exceptions: + * + * - NaN is considered equal to NaN + * - -0 and +0 are not considered equal + */ + function identical(obj1, obj2) { + if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) { + return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2); + } + } + + + /** + * @name samsam.deepEqual + * @param Object obj1 + * @param Object obj2 + * + * Deep equal comparison. Two values are "deep equal" if: + * + * - They are equal, according to samsam.identical + * - They are both date objects representing the same time + * - They are both arrays containing elements that are all deepEqual + * - They are objects with the same set of properties, and each property + * in ``obj1`` is deepEqual to the corresponding property in ``obj2`` + * + * Supports cyclic objects. + */ + function deepEqualCyclic(obj1, obj2) { + + // used for cyclic comparison + // contain already visited objects + var objects1 = [], + objects2 = [], + // contain pathes (position in the object structure) + // of the already visited objects + // indexes same as in objects arrays + paths1 = [], + paths2 = [], + // contains combinations of already compared objects + // in the manner: { "$1['ref']$2['ref']": true } + compared = {}; + + /** + * used to check, if the value of a property is an object + * (cyclic logic is only needed for objects) + * only needed for cyclic logic + */ + function isObject(value) { + + if (typeof value === 'object' && value !== null && + !(value instanceof Boolean) && + !(value instanceof Date) && + !(value instanceof Number) && + !(value instanceof RegExp) && + !(value instanceof String)) { + + return true; + } + + return false; + } + + /** + * returns the index of the given object in the + * given objects array, -1 if not contained + * only needed for cyclic logic + */ + function getIndex(objects, obj) { + + var i; + for (i = 0; i < objects.length; i++) { + if (objects[i] === obj) { + return i; + } + } + + return -1; + } + + // does the recursion for the deep equal check + return (function deepEqual(obj1, obj2, path1, path2) { + var type1 = typeof obj1; + var type2 = typeof obj2; + + // == null also matches undefined + if (obj1 === obj2 || + isNaN(obj1) || isNaN(obj2) || + obj1 == null || obj2 == null || + type1 !== "object" || type2 !== "object") { + + return identical(obj1, obj2); + } + + // Elements are only equal if identical(expected, actual) + if (isElement(obj1) || isElement(obj2)) { return false; } + + var isDate1 = isDate(obj1), isDate2 = isDate(obj2); + if (isDate1 || isDate2) { + if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) { + return false; + } + } + + if (obj1 instanceof RegExp && obj2 instanceof RegExp) { + if (obj1.toString() !== obj2.toString()) { return false; } + } + + var class1 = getClass(obj1); + var class2 = getClass(obj2); + var keys1 = keys(obj1); + var keys2 = keys(obj2); + + if (isArguments(obj1) || isArguments(obj2)) { + if (obj1.length !== obj2.length) { return false; } + } else { + if (type1 !== type2 || class1 !== class2 || + keys1.length !== keys2.length) { + return false; + } + } + + var key, i, l, + // following vars are used for the cyclic logic + value1, value2, + isObject1, isObject2, + index1, index2, + newPath1, newPath2; + + for (i = 0, l = keys1.length; i < l; i++) { + key = keys1[i]; + if (!o.hasOwnProperty.call(obj2, key)) { + return false; + } + + // Start of the cyclic logic + + value1 = obj1[key]; + value2 = obj2[key]; + + isObject1 = isObject(value1); + isObject2 = isObject(value2); + + // determine, if the objects were already visited + // (it's faster to check for isObject first, than to + // get -1 from getIndex for non objects) + index1 = isObject1 ? getIndex(objects1, value1) : -1; + index2 = isObject2 ? getIndex(objects2, value2) : -1; + + // determine the new pathes of the objects + // - for non cyclic objects the current path will be extended + // by current property name + // - for cyclic objects the stored path is taken + newPath1 = index1 !== -1 + ? paths1[index1] + : path1 + '[' + JSON.stringify(key) + ']'; + newPath2 = index2 !== -1 + ? paths2[index2] + : path2 + '[' + JSON.stringify(key) + ']'; + + // stop recursion if current objects are already compared + if (compared[newPath1 + newPath2]) { + return true; + } + + // remember the current objects and their pathes + if (index1 === -1 && isObject1) { + objects1.push(value1); + paths1.push(newPath1); + } + if (index2 === -1 && isObject2) { + objects2.push(value2); + paths2.push(newPath2); + } + + // remember that the current objects are already compared + if (isObject1 && isObject2) { + compared[newPath1 + newPath2] = true; + } + + // End of cyclic logic + + // neither value1 nor value2 is a cycle + // continue with next level + if (!deepEqual(value1, value2, newPath1, newPath2)) { + return false; + } + } + + return true; + + }(obj1, obj2, '$1', '$2')); + } + + var match; + + function arrayContains(array, subset) { + if (subset.length === 0) { return true; } + var i, l, j, k; + for (i = 0, l = array.length; i < l; ++i) { + if (match(array[i], subset[0])) { + for (j = 0, k = subset.length; j < k; ++j) { + if (!match(array[i + j], subset[j])) { return false; } + } + return true; + } + } + return false; + } + + /** + * @name samsam.match + * @param Object object + * @param Object matcher + * + * Compare arbitrary value ``object`` with matcher. + */ + match = function match(object, matcher) { + if (matcher && typeof matcher.test === "function") { + return matcher.test(object); + } + + if (typeof matcher === "function") { + return matcher(object) === true; + } + + if (typeof matcher === "string") { + matcher = matcher.toLowerCase(); + var notNull = typeof object === "string" || !!object; + return notNull && + (String(object)).toLowerCase().indexOf(matcher) >= 0; + } + + if (typeof matcher === "number") { + return matcher === object; + } + + if (typeof matcher === "boolean") { + return matcher === object; + } + + if (getClass(object) === "Array" && getClass(matcher) === "Array") { + return arrayContains(object, matcher); + } + + if (matcher && typeof matcher === "object") { + var prop; + for (prop in matcher) { + if (!match(object[prop], matcher[prop])) { + return false; + } + } + return true; + } + + throw new Error("Matcher was not a string, a number, a " + + "function, a boolean or an object"); + }; + + return { + isArguments: isArguments, + isElement: isElement, + isDate: isDate, + isNegZero: isNegZero, + identical: identical, + deepEqual: deepEqualCyclic, + match: match, + keys: keys + }; +}); +((typeof define === "function" && define.amd && function (m) { + define("formatio", ["samsam"], m); +}) || (typeof module === "object" && function (m) { + module.exports = m(require("samsam")); +}) || function (m) { this.formatio = m(this.samsam); } +)(function (samsam) { + + var formatio = { + excludeConstructors: ["Object", /^.$/], + quoteStrings: true + }; + + var hasOwn = Object.prototype.hasOwnProperty; + + var specialObjects = []; + if (typeof global !== "undefined") { + specialObjects.push({ object: global, value: "[object global]" }); + } + if (typeof document !== "undefined") { + specialObjects.push({ + object: document, + value: "[object HTMLDocument]" + }); + } + if (typeof window !== "undefined") { + specialObjects.push({ object: window, value: "[object Window]" }); + } + + function functionName(func) { + if (!func) { return ""; } + if (func.displayName) { return func.displayName; } + if (func.name) { return func.name; } + var matches = func.toString().match(/function\s+([^\(]+)/m); + return (matches && matches[1]) || ""; + } + + function constructorName(f, object) { + var name = functionName(object && object.constructor); + var excludes = f.excludeConstructors || + formatio.excludeConstructors || []; + + var i, l; + for (i = 0, l = excludes.length; i < l; ++i) { + if (typeof excludes[i] === "string" && excludes[i] === name) { + return ""; + } else if (excludes[i].test && excludes[i].test(name)) { + return ""; + } + } + + return name; + } + + function isCircular(object, objects) { + if (typeof object !== "object") { return false; } + var i, l; + for (i = 0, l = objects.length; i < l; ++i) { + if (objects[i] === object) { return true; } + } + return false; + } + + function ascii(f, object, processed, indent) { + if (typeof object === "string") { + var qs = f.quoteStrings; + var quote = typeof qs !== "boolean" || qs; + return processed || quote ? '"' + object + '"' : object; + } + + if (typeof object === "function" && !(object instanceof RegExp)) { + return ascii.func(object); + } + + processed = processed || []; + + if (isCircular(object, processed)) { return "[Circular]"; } + + if (Object.prototype.toString.call(object) === "[object Array]") { + return ascii.array.call(f, object, processed); + } + + if (!object) { return String((1/object) === -Infinity ? "-0" : object); } + if (samsam.isElement(object)) { return ascii.element(object); } + + if (typeof object.toString === "function" && + object.toString !== Object.prototype.toString) { + return object.toString(); + } + + var i, l; + for (i = 0, l = specialObjects.length; i < l; i++) { + if (object === specialObjects[i].object) { + return specialObjects[i].value; + } + } + + return ascii.object.call(f, object, processed, indent); + } + + ascii.func = function (func) { + return "function " + functionName(func) + "() {}"; + }; + + ascii.array = function (array, processed) { + processed = processed || []; + processed.push(array); + var i, l, pieces = []; + for (i = 0, l = array.length; i < l; ++i) { + pieces.push(ascii(this, array[i], processed)); + } + return "[" + pieces.join(", ") + "]"; + }; + + ascii.object = function (object, processed, indent) { + processed = processed || []; + processed.push(object); + indent = indent || 0; + var pieces = [], properties = samsam.keys(object).sort(); + var length = 3; + var prop, str, obj, i, l; + + for (i = 0, l = properties.length; i < l; ++i) { + prop = properties[i]; + obj = object[prop]; + + if (isCircular(obj, processed)) { + str = "[Circular]"; + } else { + str = ascii(this, obj, processed, indent + 2); + } + + str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str; + length += str.length; + pieces.push(str); + } + + var cons = constructorName(this, object); + var prefix = cons ? "[" + cons + "] " : ""; + var is = ""; + for (i = 0, l = indent; i < l; ++i) { is += " "; } + + if (length + indent > 80) { + return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + + is + "}"; + } + return prefix + "{ " + pieces.join(", ") + " }"; + }; + + ascii.element = function (element) { + var tagName = element.tagName.toLowerCase(); + var attrs = element.attributes, attr, pairs = [], attrName, i, l, val; + + for (i = 0, l = attrs.length; i < l; ++i) { + attr = attrs.item(i); + attrName = attr.nodeName.toLowerCase().replace("html:", ""); + val = attr.nodeValue; + if (attrName !== "contenteditable" || val !== "inherit") { + if (!!val) { pairs.push(attrName + "=\"" + val + "\""); } + } + } + + var formatted = "<" + tagName + (pairs.length > 0 ? " " : ""); + var content = element.innerHTML; + + if (content.length > 20) { + content = content.substr(0, 20) + "[...]"; + } + + var res = formatted + pairs.join(" ") + ">" + content + + ""; + + return res.replace(/ contentEditable="inherit"/, ""); + }; + + function Formatio(options) { + for (var opt in options) { + this[opt] = options[opt]; + } + } + + Formatio.prototype = { + functionName: functionName, + + configure: function (options) { + return new Formatio(options); + }, + + constructorName: function (object) { + return constructorName(this, object); + }, + + ascii: function (object, processed, indent) { + return ascii(this, object, processed, indent); + } + }; + + return Formatio.prototype; +}); +/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/ +/*global module, require, __dirname, document*/ +/** + * Sinon core utilities. For internal use only. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +var sinon = (function (formatio) { + var div = typeof document != "undefined" && document.createElement("div"); + var hasOwn = Object.prototype.hasOwnProperty; + + function isDOMNode(obj) { + var success = false; + + try { + obj.appendChild(div); + success = div.parentNode == obj; + } catch (e) { + return false; + } finally { + try { + obj.removeChild(div); + } catch (e) { + // Remove failed, not much we can do about that + } + } + + return success; + } + + function isElement(obj) { + return div && obj && obj.nodeType === 1 && isDOMNode(obj); + } + + function isFunction(obj) { + return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply); + } + + function isReallyNaN(val) { + return typeof val === 'number' && isNaN(val); + } + + function mirrorProperties(target, source) { + for (var prop in source) { + if (!hasOwn.call(target, prop)) { + target[prop] = source[prop]; + } + } + } + + function isRestorable (obj) { + return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon; + } + + var sinon = { + wrapMethod: function wrapMethod(object, property, method) { + if (!object) { + throw new TypeError("Should wrap property of object"); + } + + if (typeof method != "function") { + throw new TypeError("Method wrapper should be function"); + } + + var wrappedMethod = object[property], + error; + + if (!isFunction(wrappedMethod)) { + error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + + property + " as function"); + } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) { + error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); + } else if (wrappedMethod.calledBefore) { + var verb = !!wrappedMethod.returns ? "stubbed" : "spied on"; + error = new TypeError("Attempted to wrap " + property + " which is already " + verb); + } + + if (error) { + if (wrappedMethod && wrappedMethod._stack) { + error.stack += '\n--------------\n' + wrappedMethod._stack; + } + throw error; + } + + // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem + // when using hasOwn.call on objects from other frames. + var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property); + object[property] = method; + method.displayName = property; + // Set up a stack trace which can be used later to find what line of + // code the original method was created on. + method._stack = (new Error('Stack Trace for original')).stack; + + method.restore = function () { + // For prototype properties try to reset by delete first. + // If this fails (ex: localStorage on mobile safari) then force a reset + // via direct assignment. + if (!owned) { + delete object[property]; + } + if (object[property] === method) { + object[property] = wrappedMethod; + } + }; + + method.restore.sinon = true; + mirrorProperties(method, wrappedMethod); + + return method; + }, + + extend: function extend(target) { + for (var i = 1, l = arguments.length; i < l; i += 1) { + for (var prop in arguments[i]) { + if (arguments[i].hasOwnProperty(prop)) { + target[prop] = arguments[i][prop]; + } + + // DONT ENUM bug, only care about toString + if (arguments[i].hasOwnProperty("toString") && + arguments[i].toString != target.toString) { + target.toString = arguments[i].toString; + } + } + } + + return target; + }, + + create: function create(proto) { + var F = function () {}; + F.prototype = proto; + return new F(); + }, + + deepEqual: function deepEqual(a, b) { + if (sinon.match && sinon.match.isMatcher(a)) { + return a.test(b); + } + + if (typeof a != 'object' || typeof b != 'object') { + if (isReallyNaN(a) && isReallyNaN(b)) { + return true; + } else { + return a === b; + } + } + + if (isElement(a) || isElement(b)) { + return a === b; + } + + if (a === b) { + return true; + } + + if ((a === null && b !== null) || (a !== null && b === null)) { + return false; + } + + if (a instanceof RegExp && b instanceof RegExp) { + return (a.source === b.source) && (a.global === b.global) && + (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline); + } + + var aString = Object.prototype.toString.call(a); + if (aString != Object.prototype.toString.call(b)) { + return false; + } + + if (aString == "[object Date]") { + return a.valueOf() === b.valueOf(); + } + + var prop, aLength = 0, bLength = 0; + + if (aString == "[object Array]" && a.length !== b.length) { + return false; + } + + for (prop in a) { + aLength += 1; + + if (!(prop in b)) { + return false; + } + + if (!deepEqual(a[prop], b[prop])) { + return false; + } + } + + for (prop in b) { + bLength += 1; + } + + return aLength == bLength; + }, + + functionName: function functionName(func) { + var name = func.displayName || func.name; + + // Use function decomposition as a last resort to get function + // name. Does not rely on function decomposition to work - if it + // doesn't debugging will be slightly less informative + // (i.e. toString will say 'spy' rather than 'myFunc'). + if (!name) { + var matches = func.toString().match(/function ([^\s\(]+)/); + name = matches && matches[1]; + } + + return name; + }, + + functionToString: function toString() { + if (this.getCall && this.callCount) { + var thisValue, prop, i = this.callCount; + + while (i--) { + thisValue = this.getCall(i).thisValue; + + for (prop in thisValue) { + if (thisValue[prop] === this) { + return prop; + } + } + } + } + + return this.displayName || "sinon fake"; + }, + + getConfig: function (custom) { + var config = {}; + custom = custom || {}; + var defaults = sinon.defaultConfig; + + for (var prop in defaults) { + if (defaults.hasOwnProperty(prop)) { + config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop]; + } + } + + return config; + }, + + format: function (val) { + return "" + val; + }, + + defaultConfig: { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "server", "requests"], + useFakeTimers: true, + useFakeServer: true + }, + + timesInWords: function timesInWords(count) { + return count == 1 && "once" || + count == 2 && "twice" || + count == 3 && "thrice" || + (count || 0) + " times"; + }, + + calledInOrder: function (spies) { + for (var i = 1, l = spies.length; i < l; i++) { + if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) { + return false; + } + } + + return true; + }, + + orderByFirstCall: function (spies) { + return spies.sort(function (a, b) { + // uuid, won't ever be equal + var aCall = a.getCall(0); + var bCall = b.getCall(0); + var aId = aCall && aCall.callId || -1; + var bId = bCall && bCall.callId || -1; + + return aId < bId ? -1 : 1; + }); + }, + + log: function () {}, + + logError: function (label, err) { + var msg = label + " threw exception: "; + sinon.log(msg + "[" + err.name + "] " + err.message); + if (err.stack) { sinon.log(err.stack); } + + setTimeout(function () { + err.message = msg + err.message; + throw err; + }, 0); + }, + + typeOf: function (value) { + if (value === null) { + return "null"; + } + else if (value === undefined) { + return "undefined"; + } + var string = Object.prototype.toString.call(value); + return string.substring(8, string.length - 1).toLowerCase(); + }, + + createStubInstance: function (constructor) { + if (typeof constructor !== "function") { + throw new TypeError("The constructor should be a function."); + } + return sinon.stub(sinon.create(constructor.prototype)); + }, + + restore: function (object) { + if (object !== null && typeof object === "object") { + for (var prop in object) { + if (isRestorable(object[prop])) { + object[prop].restore(); + } + } + } + else if (isRestorable(object)) { + object.restore(); + } + } + }; + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd; + + function makePublicAPI(require, exports, module) { + module.exports = sinon; + sinon.spy = require("./sinon/spy"); + sinon.spyCall = require("./sinon/call"); + sinon.behavior = require("./sinon/behavior"); + sinon.stub = require("./sinon/stub"); + sinon.mock = require("./sinon/mock"); + sinon.collection = require("./sinon/collection"); + sinon.assert = require("./sinon/assert"); + sinon.sandbox = require("./sinon/sandbox"); + sinon.test = require("./sinon/test"); + sinon.testCase = require("./sinon/test_case"); + sinon.match = require("./sinon/match"); + } + + if (isAMD) { + define(makePublicAPI); + } else if (isNode) { + try { + formatio = require("formatio"); + } catch (e) {} + makePublicAPI(require, exports, module); + } + + if (formatio) { + var formatter = formatio.configure({ quoteStrings: false }); + sinon.format = function () { + return formatter.ascii.apply(formatter, arguments); + }; + } else if (isNode) { + try { + var util = require("util"); + sinon.format = function (value) { + return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value; + }; + } catch (e) { + /* Node, but no util module - would be very old, but better safe than + sorry */ + } + } + + return sinon; +}(typeof formatio == "object" && formatio)); + +/* @depend ../sinon.js */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Match functions + * + * @author Maximilian Antoni (mail@maxantoni.de) + * @license BSD + * + * Copyright (c) 2012 Maximilian Antoni + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function assertType(value, type, name) { + var actual = sinon.typeOf(value); + if (actual !== type) { + throw new TypeError("Expected type of " + name + " to be " + + type + ", but was " + actual); + } + } + + var matcher = { + toString: function () { + return this.message; + } + }; + + function isMatcher(object) { + return matcher.isPrototypeOf(object); + } + + function matchObject(expectation, actual) { + if (actual === null || actual === undefined) { + return false; + } + for (var key in expectation) { + if (expectation.hasOwnProperty(key)) { + var exp = expectation[key]; + var act = actual[key]; + if (match.isMatcher(exp)) { + if (!exp.test(act)) { + return false; + } + } else if (sinon.typeOf(exp) === "object") { + if (!matchObject(exp, act)) { + return false; + } + } else if (!sinon.deepEqual(exp, act)) { + return false; + } + } + } + return true; + } + + matcher.or = function (m2) { + if (!arguments.length) { + throw new TypeError("Matcher expected"); + } else if (!isMatcher(m2)) { + m2 = match(m2); + } + var m1 = this; + var or = sinon.create(matcher); + or.test = function (actual) { + return m1.test(actual) || m2.test(actual); + }; + or.message = m1.message + ".or(" + m2.message + ")"; + return or; + }; + + matcher.and = function (m2) { + if (!arguments.length) { + throw new TypeError("Matcher expected"); + } else if (!isMatcher(m2)) { + m2 = match(m2); + } + var m1 = this; + var and = sinon.create(matcher); + and.test = function (actual) { + return m1.test(actual) && m2.test(actual); + }; + and.message = m1.message + ".and(" + m2.message + ")"; + return and; + }; + + var match = function (expectation, message) { + var m = sinon.create(matcher); + var type = sinon.typeOf(expectation); + switch (type) { + case "object": + if (typeof expectation.test === "function") { + m.test = function (actual) { + return expectation.test(actual) === true; + }; + m.message = "match(" + sinon.functionName(expectation.test) + ")"; + return m; + } + var str = []; + for (var key in expectation) { + if (expectation.hasOwnProperty(key)) { + str.push(key + ": " + expectation[key]); + } + } + m.test = function (actual) { + return matchObject(expectation, actual); + }; + m.message = "match(" + str.join(", ") + ")"; + break; + case "number": + m.test = function (actual) { + return expectation == actual; + }; + break; + case "string": + m.test = function (actual) { + if (typeof actual !== "string") { + return false; + } + return actual.indexOf(expectation) !== -1; + }; + m.message = "match(\"" + expectation + "\")"; + break; + case "regexp": + m.test = function (actual) { + if (typeof actual !== "string") { + return false; + } + return expectation.test(actual); + }; + break; + case "function": + m.test = expectation; + if (message) { + m.message = message; + } else { + m.message = "match(" + sinon.functionName(expectation) + ")"; + } + break; + default: + m.test = function (actual) { + return sinon.deepEqual(expectation, actual); + }; + } + if (!m.message) { + m.message = "match(" + expectation + ")"; + } + return m; + }; + + match.isMatcher = isMatcher; + + match.any = match(function () { + return true; + }, "any"); + + match.defined = match(function (actual) { + return actual !== null && actual !== undefined; + }, "defined"); + + match.truthy = match(function (actual) { + return !!actual; + }, "truthy"); + + match.falsy = match(function (actual) { + return !actual; + }, "falsy"); + + match.same = function (expectation) { + return match(function (actual) { + return expectation === actual; + }, "same(" + expectation + ")"); + }; + + match.typeOf = function (type) { + assertType(type, "string", "type"); + return match(function (actual) { + return sinon.typeOf(actual) === type; + }, "typeOf(\"" + type + "\")"); + }; + + match.instanceOf = function (type) { + assertType(type, "function", "type"); + return match(function (actual) { + return actual instanceof type; + }, "instanceOf(" + sinon.functionName(type) + ")"); + }; + + function createPropertyMatcher(propertyTest, messagePrefix) { + return function (property, value) { + assertType(property, "string", "property"); + var onlyProperty = arguments.length === 1; + var message = messagePrefix + "(\"" + property + "\""; + if (!onlyProperty) { + message += ", " + value; + } + message += ")"; + return match(function (actual) { + if (actual === undefined || actual === null || + !propertyTest(actual, property)) { + return false; + } + return onlyProperty || sinon.deepEqual(value, actual[property]); + }, message); + }; + } + + match.has = createPropertyMatcher(function (actual, property) { + if (typeof actual === "object") { + return property in actual; + } + return actual[property] !== undefined; + }, "has"); + + match.hasOwn = createPropertyMatcher(function (actual, property) { + return actual.hasOwnProperty(property); + }, "hasOwn"); + + match.bool = match.typeOf("boolean"); + match.number = match.typeOf("number"); + match.string = match.typeOf("string"); + match.object = match.typeOf("object"); + match.func = match.typeOf("function"); + match.array = match.typeOf("array"); + match.regexp = match.typeOf("regexp"); + match.date = match.typeOf("date"); + + sinon.match = match; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = match; }); + } else if (commonJSModule) { + module.exports = match; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend match.js + */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Spy calls + * + * @author Christian Johansen (christian@cjohansen.no) + * @author Maximilian Antoni (mail@maxantoni.de) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + * Copyright (c) 2013 Maximilian Antoni + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function throwYieldError(proxy, text, args) { + var msg = sinon.functionName(proxy) + text; + if (args.length) { + msg += " Received [" + slice.call(args).join(", ") + "]"; + } + throw new Error(msg); + } + + var slice = Array.prototype.slice; + + var callProto = { + calledOn: function calledOn(thisValue) { + if (sinon.match && sinon.match.isMatcher(thisValue)) { + return thisValue.test(this.thisValue); + } + return this.thisValue === thisValue; + }, + + calledWith: function calledWith() { + for (var i = 0, l = arguments.length; i < l; i += 1) { + if (!sinon.deepEqual(arguments[i], this.args[i])) { + return false; + } + } + + return true; + }, + + calledWithMatch: function calledWithMatch() { + for (var i = 0, l = arguments.length; i < l; i += 1) { + var actual = this.args[i]; + var expectation = arguments[i]; + if (!sinon.match || !sinon.match(expectation).test(actual)) { + return false; + } + } + return true; + }, + + calledWithExactly: function calledWithExactly() { + return arguments.length == this.args.length && + this.calledWith.apply(this, arguments); + }, + + notCalledWith: function notCalledWith() { + return !this.calledWith.apply(this, arguments); + }, + + notCalledWithMatch: function notCalledWithMatch() { + return !this.calledWithMatch.apply(this, arguments); + }, + + returned: function returned(value) { + return sinon.deepEqual(value, this.returnValue); + }, + + threw: function threw(error) { + if (typeof error === "undefined" || !this.exception) { + return !!this.exception; + } + + return this.exception === error || this.exception.name === error; + }, + + calledWithNew: function calledWithNew() { + return this.proxy.prototype && this.thisValue instanceof this.proxy; + }, + + calledBefore: function (other) { + return this.callId < other.callId; + }, + + calledAfter: function (other) { + return this.callId > other.callId; + }, + + callArg: function (pos) { + this.args[pos](); + }, + + callArgOn: function (pos, thisValue) { + this.args[pos].apply(thisValue); + }, + + callArgWith: function (pos) { + this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1))); + }, + + callArgOnWith: function (pos, thisValue) { + var args = slice.call(arguments, 2); + this.args[pos].apply(thisValue, args); + }, + + "yield": function () { + this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0))); + }, + + yieldOn: function (thisValue) { + var args = this.args; + for (var i = 0, l = args.length; i < l; ++i) { + if (typeof args[i] === "function") { + args[i].apply(thisValue, slice.call(arguments, 1)); + return; + } + } + throwYieldError(this.proxy, " cannot yield since no callback was passed.", args); + }, + + yieldTo: function (prop) { + this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1))); + }, + + yieldToOn: function (prop, thisValue) { + var args = this.args; + for (var i = 0, l = args.length; i < l; ++i) { + if (args[i] && typeof args[i][prop] === "function") { + args[i][prop].apply(thisValue, slice.call(arguments, 2)); + return; + } + } + throwYieldError(this.proxy, " cannot yield to '" + prop + + "' since no callback was passed.", args); + }, + + toString: function () { + var callStr = this.proxy.toString() + "("; + var args = []; + + for (var i = 0, l = this.args.length; i < l; ++i) { + args.push(sinon.format(this.args[i])); + } + + callStr = callStr + args.join(", ") + ")"; + + if (typeof this.returnValue != "undefined") { + callStr += " => " + sinon.format(this.returnValue); + } + + if (this.exception) { + callStr += " !" + this.exception.name; + + if (this.exception.message) { + callStr += "(" + this.exception.message + ")"; + } + } + + return callStr; + } + }; + + callProto.invokeCallback = callProto.yield; + + function createSpyCall(spy, thisValue, args, returnValue, exception, id) { + if (typeof id !== "number") { + throw new TypeError("Call id is not a number"); + } + var proxyCall = sinon.create(callProto); + proxyCall.proxy = spy; + proxyCall.thisValue = thisValue; + proxyCall.args = args; + proxyCall.returnValue = returnValue; + proxyCall.exception = exception; + proxyCall.callId = id; + + return proxyCall; + } + createSpyCall.toString = callProto.toString; // used by mocks + + sinon.spyCall = createSpyCall; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = createSpyCall; }); + } else if (commonJSModule) { + module.exports = createSpyCall; + } +}(typeof sinon == "object" && sinon || null)); + + +/** + * @depend ../sinon.js + * @depend call.js + */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Spy functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + var push = Array.prototype.push; + var slice = Array.prototype.slice; + var callId = 0; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function spy(object, property) { + if (!property && typeof object == "function") { + return spy.create(object); + } + + if (!object && !property) { + return spy.create(function () { }); + } + + var method = object[property]; + return sinon.wrapMethod(object, property, spy.create(method)); + } + + function matchingFake(fakes, args, strict) { + if (!fakes) { + return; + } + + for (var i = 0, l = fakes.length; i < l; i++) { + if (fakes[i].matches(args, strict)) { + return fakes[i]; + } + } + } + + function incrementCallCount() { + this.called = true; + this.callCount += 1; + this.notCalled = false; + this.calledOnce = this.callCount == 1; + this.calledTwice = this.callCount == 2; + this.calledThrice = this.callCount == 3; + } + + function createCallProperties() { + this.firstCall = this.getCall(0); + this.secondCall = this.getCall(1); + this.thirdCall = this.getCall(2); + this.lastCall = this.getCall(this.callCount - 1); + } + + var vars = "a,b,c,d,e,f,g,h,i,j,k,l"; + function createProxy(func) { + // Retain the function length: + var p; + if (func.length) { + eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) + + ") { return p.invoke(func, this, slice.call(arguments)); });"); + } + else { + p = function proxy() { + return p.invoke(func, this, slice.call(arguments)); + }; + } + return p; + } + + var uuid = 0; + + // Public API + var spyApi = { + reset: function () { + this.called = false; + this.notCalled = true; + this.calledOnce = false; + this.calledTwice = false; + this.calledThrice = false; + this.callCount = 0; + this.firstCall = null; + this.secondCall = null; + this.thirdCall = null; + this.lastCall = null; + this.args = []; + this.returnValues = []; + this.thisValues = []; + this.exceptions = []; + this.callIds = []; + if (this.fakes) { + for (var i = 0; i < this.fakes.length; i++) { + this.fakes[i].reset(); + } + } + }, + + create: function create(func) { + var name; + + if (typeof func != "function") { + func = function () { }; + } else { + name = sinon.functionName(func); + } + + var proxy = createProxy(func); + + sinon.extend(proxy, spy); + delete proxy.create; + sinon.extend(proxy, func); + + proxy.reset(); + proxy.prototype = func.prototype; + proxy.displayName = name || "spy"; + proxy.toString = sinon.functionToString; + proxy._create = sinon.spy.create; + proxy.id = "spy#" + uuid++; + + return proxy; + }, + + invoke: function invoke(func, thisValue, args) { + var matching = matchingFake(this.fakes, args); + var exception, returnValue; + + incrementCallCount.call(this); + push.call(this.thisValues, thisValue); + push.call(this.args, args); + push.call(this.callIds, callId++); + + // Make call properties available from within the spied function: + createCallProperties.call(this); + + try { + if (matching) { + returnValue = matching.invoke(func, thisValue, args); + } else { + returnValue = (this.func || func).apply(thisValue, args); + } + + var thisCall = this.getCall(this.callCount - 1); + if (thisCall.calledWithNew() && typeof returnValue !== 'object') { + returnValue = thisValue; + } + } catch (e) { + exception = e; + } + + push.call(this.exceptions, exception); + push.call(this.returnValues, returnValue); + + // Make return value and exception available in the calls: + createCallProperties.call(this); + + if (exception !== undefined) { + throw exception; + } + + return returnValue; + }, + + named: function named(name) { + this.displayName = name; + return this; + }, + + getCall: function getCall(i) { + if (i < 0 || i >= this.callCount) { + return null; + } + + return sinon.spyCall(this, this.thisValues[i], this.args[i], + this.returnValues[i], this.exceptions[i], + this.callIds[i]); + }, + + getCalls: function () { + var calls = []; + var i; + + for (i = 0; i < this.callCount; i++) { + calls.push(this.getCall(i)); + } + + return calls; + }, + + calledBefore: function calledBefore(spyFn) { + if (!this.called) { + return false; + } + + if (!spyFn.called) { + return true; + } + + return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1]; + }, + + calledAfter: function calledAfter(spyFn) { + if (!this.called || !spyFn.called) { + return false; + } + + return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1]; + }, + + withArgs: function () { + var args = slice.call(arguments); + + if (this.fakes) { + var match = matchingFake(this.fakes, args, true); + + if (match) { + return match; + } + } else { + this.fakes = []; + } + + var original = this; + var fake = this._create(); + fake.matchingAguments = args; + fake.parent = this; + push.call(this.fakes, fake); + + fake.withArgs = function () { + return original.withArgs.apply(original, arguments); + }; + + for (var i = 0; i < this.args.length; i++) { + if (fake.matches(this.args[i])) { + incrementCallCount.call(fake); + push.call(fake.thisValues, this.thisValues[i]); + push.call(fake.args, this.args[i]); + push.call(fake.returnValues, this.returnValues[i]); + push.call(fake.exceptions, this.exceptions[i]); + push.call(fake.callIds, this.callIds[i]); + } + } + createCallProperties.call(fake); + + return fake; + }, + + matches: function (args, strict) { + var margs = this.matchingAguments; + + if (margs.length <= args.length && + sinon.deepEqual(margs, args.slice(0, margs.length))) { + return !strict || margs.length == args.length; + } + }, + + printf: function (format) { + var spy = this; + var args = slice.call(arguments, 1); + var formatter; + + return (format || "").replace(/%(.)/g, function (match, specifyer) { + formatter = spyApi.formatters[specifyer]; + + if (typeof formatter == "function") { + return formatter.call(null, spy, args); + } else if (!isNaN(parseInt(specifyer, 10))) { + return sinon.format(args[specifyer - 1]); + } + + return "%" + specifyer; + }); + } + }; + + function delegateToCalls(method, matchAny, actual, notCalled) { + spyApi[method] = function () { + if (!this.called) { + if (notCalled) { + return notCalled.apply(this, arguments); + } + return false; + } + + var currentCall; + var matches = 0; + + for (var i = 0, l = this.callCount; i < l; i += 1) { + currentCall = this.getCall(i); + + if (currentCall[actual || method].apply(currentCall, arguments)) { + matches += 1; + + if (matchAny) { + return true; + } + } + } + + return matches === this.callCount; + }; + } + + delegateToCalls("calledOn", true); + delegateToCalls("alwaysCalledOn", false, "calledOn"); + delegateToCalls("calledWith", true); + delegateToCalls("calledWithMatch", true); + delegateToCalls("alwaysCalledWith", false, "calledWith"); + delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch"); + delegateToCalls("calledWithExactly", true); + delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly"); + delegateToCalls("neverCalledWith", false, "notCalledWith", + function () { return true; }); + delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch", + function () { return true; }); + delegateToCalls("threw", true); + delegateToCalls("alwaysThrew", false, "threw"); + delegateToCalls("returned", true); + delegateToCalls("alwaysReturned", false, "returned"); + delegateToCalls("calledWithNew", true); + delegateToCalls("alwaysCalledWithNew", false, "calledWithNew"); + delegateToCalls("callArg", false, "callArgWith", function () { + throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); + }); + spyApi.callArgWith = spyApi.callArg; + delegateToCalls("callArgOn", false, "callArgOnWith", function () { + throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); + }); + spyApi.callArgOnWith = spyApi.callArgOn; + delegateToCalls("yield", false, "yield", function () { + throw new Error(this.toString() + " cannot yield since it was not yet invoked."); + }); + // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode. + spyApi.invokeCallback = spyApi.yield; + delegateToCalls("yieldOn", false, "yieldOn", function () { + throw new Error(this.toString() + " cannot yield since it was not yet invoked."); + }); + delegateToCalls("yieldTo", false, "yieldTo", function (property) { + throw new Error(this.toString() + " cannot yield to '" + property + + "' since it was not yet invoked."); + }); + delegateToCalls("yieldToOn", false, "yieldToOn", function (property) { + throw new Error(this.toString() + " cannot yield to '" + property + + "' since it was not yet invoked."); + }); + + spyApi.formatters = { + "c": function (spy) { + return sinon.timesInWords(spy.callCount); + }, + + "n": function (spy) { + return spy.toString(); + }, + + "C": function (spy) { + var calls = []; + + for (var i = 0, l = spy.callCount; i < l; ++i) { + var stringifiedCall = " " + spy.getCall(i).toString(); + if (/\n/.test(calls[i - 1])) { + stringifiedCall = "\n" + stringifiedCall; + } + push.call(calls, stringifiedCall); + } + + return calls.length > 0 ? "\n" + calls.join("\n") : ""; + }, + + "t": function (spy) { + var objects = []; + + for (var i = 0, l = spy.callCount; i < l; ++i) { + push.call(objects, sinon.format(spy.thisValues[i])); + } + + return objects.join(", "); + }, + + "*": function (spy, args) { + var formatted = []; + + for (var i = 0, l = args.length; i < l; ++i) { + push.call(formatted, sinon.format(args[i])); + } + + return formatted.join(", "); + } + }; + + sinon.extend(spy, spyApi); + + spy.spyCall = sinon.spyCall; + sinon.spy = spy; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = spy; }); + } else if (commonJSModule) { + module.exports = spy; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + */ +/*jslint eqeqeq: false, onevar: false*/ +/*global module, require, sinon, process, setImmediate, setTimeout*/ +/** + * Stub behavior + * + * @author Christian Johansen (christian@cjohansen.no) + * @author Tim Fischbach (mail@timfischbach.de) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + var slice = Array.prototype.slice; + var join = Array.prototype.join; + var proto; + + var nextTick = (function () { + if (typeof process === "object" && typeof process.nextTick === "function") { + return process.nextTick; + } else if (typeof setImmediate === "function") { + return setImmediate; + } else { + return function (callback) { + setTimeout(callback, 0); + }; + } + })(); + + function throwsException(error, message) { + if (typeof error == "string") { + this.exception = new Error(message || ""); + this.exception.name = error; + } else if (!error) { + this.exception = new Error("Error"); + } else { + this.exception = error; + } + + return this; + } + + function getCallback(behavior, args) { + var callArgAt = behavior.callArgAt; + + if (callArgAt < 0) { + var callArgProp = behavior.callArgProp; + + for (var i = 0, l = args.length; i < l; ++i) { + if (!callArgProp && typeof args[i] == "function") { + return args[i]; + } + + if (callArgProp && args[i] && + typeof args[i][callArgProp] == "function") { + return args[i][callArgProp]; + } + } + + return null; + } + + return args[callArgAt]; + } + + function getCallbackError(behavior, func, args) { + if (behavior.callArgAt < 0) { + var msg; + + if (behavior.callArgProp) { + msg = sinon.functionName(behavior.stub) + + " expected to yield to '" + behavior.callArgProp + + "', but no object with such a property was passed."; + } else { + msg = sinon.functionName(behavior.stub) + + " expected to yield, but no callback was passed."; + } + + if (args.length > 0) { + msg += " Received [" + join.call(args, ", ") + "]"; + } + + return msg; + } + + return "argument at index " + behavior.callArgAt + " is not a function: " + func; + } + + function callCallback(behavior, args) { + if (typeof behavior.callArgAt == "number") { + var func = getCallback(behavior, args); + + if (typeof func != "function") { + throw new TypeError(getCallbackError(behavior, func, args)); + } + + if (behavior.callbackAsync) { + nextTick(function() { + func.apply(behavior.callbackContext, behavior.callbackArguments); + }); + } else { + func.apply(behavior.callbackContext, behavior.callbackArguments); + } + } + } + + proto = { + create: function(stub) { + var behavior = sinon.extend({}, sinon.behavior); + delete behavior.create; + behavior.stub = stub; + + return behavior; + }, + + isPresent: function() { + return (typeof this.callArgAt == 'number' || + this.exception || + typeof this.returnArgAt == 'number' || + this.returnThis || + this.returnValueDefined); + }, + + invoke: function(context, args) { + callCallback(this, args); + + if (this.exception) { + throw this.exception; + } else if (typeof this.returnArgAt == 'number') { + return args[this.returnArgAt]; + } else if (this.returnThis) { + return context; + } + + return this.returnValue; + }, + + onCall: function(index) { + return this.stub.onCall(index); + }, + + onFirstCall: function() { + return this.stub.onFirstCall(); + }, + + onSecondCall: function() { + return this.stub.onSecondCall(); + }, + + onThirdCall: function() { + return this.stub.onThirdCall(); + }, + + withArgs: function(/* arguments */) { + throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' + + 'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.'); + }, + + callsArg: function callsArg(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.callArgAt = pos; + this.callbackArguments = []; + this.callbackContext = undefined; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + callsArgOn: function callsArgOn(pos, context) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = pos; + this.callbackArguments = []; + this.callbackContext = context; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + callsArgWith: function callsArgWith(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.callArgAt = pos; + this.callbackArguments = slice.call(arguments, 1); + this.callbackContext = undefined; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + callsArgOnWith: function callsArgWith(pos, context) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = pos; + this.callbackArguments = slice.call(arguments, 2); + this.callbackContext = context; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + yields: function () { + this.callArgAt = -1; + this.callbackArguments = slice.call(arguments, 0); + this.callbackContext = undefined; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + yieldsOn: function (context) { + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = -1; + this.callbackArguments = slice.call(arguments, 1); + this.callbackContext = context; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + yieldsTo: function (prop) { + this.callArgAt = -1; + this.callbackArguments = slice.call(arguments, 1); + this.callbackContext = undefined; + this.callArgProp = prop; + this.callbackAsync = false; + + return this; + }, + + yieldsToOn: function (prop, context) { + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = -1; + this.callbackArguments = slice.call(arguments, 2); + this.callbackContext = context; + this.callArgProp = prop; + this.callbackAsync = false; + + return this; + }, + + + "throws": throwsException, + throwsException: throwsException, + + returns: function returns(value) { + this.returnValue = value; + this.returnValueDefined = true; + + return this; + }, + + returnsArg: function returnsArg(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.returnArgAt = pos; + + return this; + }, + + returnsThis: function returnsThis() { + this.returnThis = true; + + return this; + } + }; + + // create asynchronous versions of callsArg* and yields* methods + for (var method in proto) { + // need to avoid creating anotherasync versions of the newly added async methods + if (proto.hasOwnProperty(method) && + method.match(/^(callsArg|yields)/) && + !method.match(/Async/)) { + proto[method + 'Async'] = (function (syncFnName) { + return function () { + var result = this[syncFnName].apply(this, arguments); + this.callbackAsync = true; + return result; + }; + })(method); + } + } + + sinon.behavior = proto; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = proto; }); + } else if (commonJSModule) { + module.exports = proto; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend spy.js + * @depend behavior.js + */ +/*jslint eqeqeq: false, onevar: false*/ +/*global module, require, sinon*/ +/** + * Stub functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function stub(object, property, func) { + if (!!func && typeof func != "function") { + throw new TypeError("Custom stub should be function"); + } + + var wrapper; + + if (func) { + wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; + } else { + wrapper = stub.create(); + } + + if (!object && typeof property === "undefined") { + return sinon.stub.create(); + } + + if (typeof property === "undefined" && typeof object == "object") { + for (var prop in object) { + if (typeof object[prop] === "function") { + stub(object, prop); + } + } + + return object; + } + + return sinon.wrapMethod(object, property, wrapper); + } + + function getDefaultBehavior(stub) { + return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub); + } + + function getParentBehaviour(stub) { + return (stub.parent && getCurrentBehavior(stub.parent)); + } + + function getCurrentBehavior(stub) { + var behavior = stub.behaviors[stub.callCount - 1]; + return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub); + } + + var uuid = 0; + + sinon.extend(stub, (function () { + var proto = { + create: function create() { + var functionStub = function () { + return getCurrentBehavior(functionStub).invoke(this, arguments); + }; + + functionStub.id = "stub#" + uuid++; + var orig = functionStub; + functionStub = sinon.spy.create(functionStub); + functionStub.func = orig; + + sinon.extend(functionStub, stub); + functionStub._create = sinon.stub.create; + functionStub.displayName = "stub"; + functionStub.toString = sinon.functionToString; + + functionStub.defaultBehavior = null; + functionStub.behaviors = []; + + return functionStub; + }, + + resetBehavior: function () { + var i; + + this.defaultBehavior = null; + this.behaviors = []; + + delete this.returnValue; + delete this.returnArgAt; + this.returnThis = false; + + if (this.fakes) { + for (i = 0; i < this.fakes.length; i++) { + this.fakes[i].resetBehavior(); + } + } + }, + + onCall: function(index) { + if (!this.behaviors[index]) { + this.behaviors[index] = sinon.behavior.create(this); + } + + return this.behaviors[index]; + }, + + onFirstCall: function() { + return this.onCall(0); + }, + + onSecondCall: function() { + return this.onCall(1); + }, + + onThirdCall: function() { + return this.onCall(2); + } + }; + + for (var method in sinon.behavior) { + if (sinon.behavior.hasOwnProperty(method) && + !proto.hasOwnProperty(method) && + method != 'create' && + method != 'withArgs' && + method != 'invoke') { + proto[method] = (function(behaviorMethod) { + return function() { + this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this); + this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments); + return this; + }; + }(method)); + } + } + + return proto; + }())); + + sinon.stub = stub; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = stub; }); + } else if (commonJSModule) { + module.exports = stub; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend stub.js + */ +/*jslint eqeqeq: false, onevar: false, nomen: false*/ +/*global module, require, sinon*/ +/** + * Mock functions. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + var push = [].push; + var match; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + match = sinon.match; + + if (!match && commonJSModule) { + match = require("./match"); + } + + function mock(object) { + if (!object) { + return sinon.expectation.create("Anonymous mock"); + } + + return mock.create(object); + } + + sinon.mock = mock; + + sinon.extend(mock, (function () { + function each(collection, callback) { + if (!collection) { + return; + } + + for (var i = 0, l = collection.length; i < l; i += 1) { + callback(collection[i]); + } + } + + return { + create: function create(object) { + if (!object) { + throw new TypeError("object is null"); + } + + var mockObject = sinon.extend({}, mock); + mockObject.object = object; + delete mockObject.create; + + return mockObject; + }, + + expects: function expects(method) { + if (!method) { + throw new TypeError("method is falsy"); + } + + if (!this.expectations) { + this.expectations = {}; + this.proxies = []; + } + + if (!this.expectations[method]) { + this.expectations[method] = []; + var mockObject = this; + + sinon.wrapMethod(this.object, method, function () { + return mockObject.invokeMethod(method, this, arguments); + }); + + push.call(this.proxies, method); + } + + var expectation = sinon.expectation.create(method); + push.call(this.expectations[method], expectation); + + return expectation; + }, + + restore: function restore() { + var object = this.object; + + each(this.proxies, function (proxy) { + if (typeof object[proxy].restore == "function") { + object[proxy].restore(); + } + }); + }, + + verify: function verify() { + var expectations = this.expectations || {}; + var messages = [], met = []; + + each(this.proxies, function (proxy) { + each(expectations[proxy], function (expectation) { + if (!expectation.met()) { + push.call(messages, expectation.toString()); + } else { + push.call(met, expectation.toString()); + } + }); + }); + + this.restore(); + + if (messages.length > 0) { + sinon.expectation.fail(messages.concat(met).join("\n")); + } else { + sinon.expectation.pass(messages.concat(met).join("\n")); + } + + return true; + }, + + invokeMethod: function invokeMethod(method, thisValue, args) { + var expectations = this.expectations && this.expectations[method]; + var length = expectations && expectations.length || 0, i; + + for (i = 0; i < length; i += 1) { + if (!expectations[i].met() && + expectations[i].allowsCall(thisValue, args)) { + return expectations[i].apply(thisValue, args); + } + } + + var messages = [], available, exhausted = 0; + + for (i = 0; i < length; i += 1) { + if (expectations[i].allowsCall(thisValue, args)) { + available = available || expectations[i]; + } else { + exhausted += 1; + } + push.call(messages, " " + expectations[i].toString()); + } + + if (exhausted === 0) { + return available.apply(thisValue, args); + } + + messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ + proxy: method, + args: args + })); + + sinon.expectation.fail(messages.join("\n")); + } + }; + }())); + + var times = sinon.timesInWords; + + sinon.expectation = (function () { + var slice = Array.prototype.slice; + var _invoke = sinon.spy.invoke; + + function callCountInWords(callCount) { + if (callCount == 0) { + return "never called"; + } else { + return "called " + times(callCount); + } + } + + function expectedCallCountInWords(expectation) { + var min = expectation.minCalls; + var max = expectation.maxCalls; + + if (typeof min == "number" && typeof max == "number") { + var str = times(min); + + if (min != max) { + str = "at least " + str + " and at most " + times(max); + } + + return str; + } + + if (typeof min == "number") { + return "at least " + times(min); + } + + return "at most " + times(max); + } + + function receivedMinCalls(expectation) { + var hasMinLimit = typeof expectation.minCalls == "number"; + return !hasMinLimit || expectation.callCount >= expectation.minCalls; + } + + function receivedMaxCalls(expectation) { + if (typeof expectation.maxCalls != "number") { + return false; + } + + return expectation.callCount == expectation.maxCalls; + } + + function verifyMatcher(possibleMatcher, arg){ + if (match && match.isMatcher(possibleMatcher)) { + return possibleMatcher.test(arg); + } else { + return true; + } + } + + return { + minCalls: 1, + maxCalls: 1, + + create: function create(methodName) { + var expectation = sinon.extend(sinon.stub.create(), sinon.expectation); + delete expectation.create; + expectation.method = methodName; + + return expectation; + }, + + invoke: function invoke(func, thisValue, args) { + this.verifyCallAllowed(thisValue, args); + + return _invoke.apply(this, arguments); + }, + + atLeast: function atLeast(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not number"); + } + + if (!this.limitsSet) { + this.maxCalls = null; + this.limitsSet = true; + } + + this.minCalls = num; + + return this; + }, + + atMost: function atMost(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not number"); + } + + if (!this.limitsSet) { + this.minCalls = null; + this.limitsSet = true; + } + + this.maxCalls = num; + + return this; + }, + + never: function never() { + return this.exactly(0); + }, + + once: function once() { + return this.exactly(1); + }, + + twice: function twice() { + return this.exactly(2); + }, + + thrice: function thrice() { + return this.exactly(3); + }, + + exactly: function exactly(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not a number"); + } + + this.atLeast(num); + return this.atMost(num); + }, + + met: function met() { + return !this.failed && receivedMinCalls(this); + }, + + verifyCallAllowed: function verifyCallAllowed(thisValue, args) { + if (receivedMaxCalls(this)) { + this.failed = true; + sinon.expectation.fail(this.method + " already called " + times(this.maxCalls)); + } + + if ("expectedThis" in this && this.expectedThis !== thisValue) { + sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " + + this.expectedThis); + } + + if (!("expectedArguments" in this)) { + return; + } + + if (!args) { + sinon.expectation.fail(this.method + " received no arguments, expected " + + sinon.format(this.expectedArguments)); + } + + if (args.length < this.expectedArguments.length) { + sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) + + "), expected " + sinon.format(this.expectedArguments)); + } + + if (this.expectsExactArgCount && + args.length != this.expectedArguments.length) { + sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) + + "), expected " + sinon.format(this.expectedArguments)); + } + + for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { + + if (!verifyMatcher(this.expectedArguments[i],args[i])) { + sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + + ", didn't match " + this.expectedArguments.toString()); + } + + if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { + sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + + ", expected " + sinon.format(this.expectedArguments)); + } + } + }, + + allowsCall: function allowsCall(thisValue, args) { + if (this.met() && receivedMaxCalls(this)) { + return false; + } + + if ("expectedThis" in this && this.expectedThis !== thisValue) { + return false; + } + + if (!("expectedArguments" in this)) { + return true; + } + + args = args || []; + + if (args.length < this.expectedArguments.length) { + return false; + } + + if (this.expectsExactArgCount && + args.length != this.expectedArguments.length) { + return false; + } + + for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { + if (!verifyMatcher(this.expectedArguments[i],args[i])) { + return false; + } + + if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { + return false; + } + } + + return true; + }, + + withArgs: function withArgs() { + this.expectedArguments = slice.call(arguments); + return this; + }, + + withExactArgs: function withExactArgs() { + this.withArgs.apply(this, arguments); + this.expectsExactArgCount = true; + return this; + }, + + on: function on(thisValue) { + this.expectedThis = thisValue; + return this; + }, + + toString: function () { + var args = (this.expectedArguments || []).slice(); + + if (!this.expectsExactArgCount) { + push.call(args, "[...]"); + } + + var callStr = sinon.spyCall.toString.call({ + proxy: this.method || "anonymous mock expectation", + args: args + }); + + var message = callStr.replace(", [...", "[, ...") + " " + + expectedCallCountInWords(this); + + if (this.met()) { + return "Expectation met: " + message; + } + + return "Expected " + message + " (" + + callCountInWords(this.callCount) + ")"; + }, + + verify: function verify() { + if (!this.met()) { + sinon.expectation.fail(this.toString()); + } else { + sinon.expectation.pass(this.toString()); + } + + return true; + }, + + pass: function(message) { + sinon.assert.pass(message); + }, + fail: function (message) { + var exception = new Error(message); + exception.name = "ExpectationError"; + + throw exception; + } + }; + }()); + + sinon.mock = mock; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = mock; }); + } else if (commonJSModule) { + module.exports = mock; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend stub.js + * @depend mock.js + */ +/*jslint eqeqeq: false, onevar: false, forin: true*/ +/*global module, require, sinon*/ +/** + * Collections of stubs, spies and mocks. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + var push = [].push; + var hasOwnProperty = Object.prototype.hasOwnProperty; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function getFakes(fakeCollection) { + if (!fakeCollection.fakes) { + fakeCollection.fakes = []; + } + + return fakeCollection.fakes; + } + + function each(fakeCollection, method) { + var fakes = getFakes(fakeCollection); + + for (var i = 0, l = fakes.length; i < l; i += 1) { + if (typeof fakes[i][method] == "function") { + fakes[i][method](); + } + } + } + + function compact(fakeCollection) { + var fakes = getFakes(fakeCollection); + var i = 0; + while (i < fakes.length) { + fakes.splice(i, 1); + } + } + + var collection = { + verify: function resolve() { + each(this, "verify"); + }, + + restore: function restore() { + each(this, "restore"); + compact(this); + }, + + verifyAndRestore: function verifyAndRestore() { + var exception; + + try { + this.verify(); + } catch (e) { + exception = e; + } + + this.restore(); + + if (exception) { + throw exception; + } + }, + + add: function add(fake) { + push.call(getFakes(this), fake); + return fake; + }, + + spy: function spy() { + return this.add(sinon.spy.apply(sinon, arguments)); + }, + + stub: function stub(object, property, value) { + if (property) { + var original = object[property]; + + if (typeof original != "function") { + if (!hasOwnProperty.call(object, property)) { + throw new TypeError("Cannot stub non-existent own property " + property); + } + + object[property] = value; + + return this.add({ + restore: function () { + object[property] = original; + } + }); + } + } + if (!property && !!object && typeof object == "object") { + var stubbedObj = sinon.stub.apply(sinon, arguments); + + for (var prop in stubbedObj) { + if (typeof stubbedObj[prop] === "function") { + this.add(stubbedObj[prop]); + } + } + + return stubbedObj; + } + + return this.add(sinon.stub.apply(sinon, arguments)); + }, + + mock: function mock() { + return this.add(sinon.mock.apply(sinon, arguments)); + }, + + inject: function inject(obj) { + var col = this; + + obj.spy = function () { + return col.spy.apply(col, arguments); + }; + + obj.stub = function () { + return col.stub.apply(col, arguments); + }; + + obj.mock = function () { + return col.mock.apply(col, arguments); + }; + + return obj; + } + }; + + sinon.collection = collection; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = collection; }); + } else if (commonJSModule) { + module.exports = collection; + } +}(typeof sinon == "object" && sinon || null)); + +/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/ +/*global module, require, window*/ +/** + * Fake timer API + * setTimeout + * setInterval + * clearTimeout + * clearInterval + * tick + * reset + * Date + * + * Inspired by jsUnitMockTimeOut from JsUnit + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof sinon == "undefined") { + var sinon = {}; +} + +(function (global) { + // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref() + // browsers, a number. + // see https://github.com/cjohansen/Sinon.JS/pull/436 + var timeoutResult = setTimeout(function() {}, 0); + var addTimerReturnsObject = typeof timeoutResult === 'object'; + clearTimeout(timeoutResult); + + var id = 1; + + function addTimer(args, recurring) { + if (args.length === 0) { + throw new Error("Function requires at least 1 parameter"); + } + + if (typeof args[0] === "undefined") { + throw new Error("Callback must be provided to timer calls"); + } + + var toId = id++; + var delay = args[1] || 0; + + if (!this.timeouts) { + this.timeouts = {}; + } + + this.timeouts[toId] = { + id: toId, + func: args[0], + callAt: this.now + delay, + invokeArgs: Array.prototype.slice.call(args, 2) + }; + + if (recurring === true) { + this.timeouts[toId].interval = delay; + } + + if (addTimerReturnsObject) { + return { + id: toId, + ref: function() {}, + unref: function() {} + }; + } + else { + return toId; + } + } + + function parseTime(str) { + if (!str) { + return 0; + } + + var strings = str.split(":"); + var l = strings.length, i = l; + var ms = 0, parsed; + + if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { + throw new Error("tick only understands numbers and 'h:m:s'"); + } + + while (i--) { + parsed = parseInt(strings[i], 10); + + if (parsed >= 60) { + throw new Error("Invalid time " + str); + } + + ms += parsed * Math.pow(60, (l - i - 1)); + } + + return ms * 1000; + } + + function createObject(object) { + var newObject; + + if (Object.create) { + newObject = Object.create(object); + } else { + var F = function () {}; + F.prototype = object; + newObject = new F(); + } + + newObject.Date.clock = newObject; + return newObject; + } + + sinon.clock = { + now: 0, + + create: function create(now) { + var clock = createObject(this); + + if (typeof now == "number") { + clock.now = now; + } + + if (!!now && typeof now == "object") { + throw new TypeError("now should be milliseconds since UNIX epoch"); + } + + return clock; + }, + + setTimeout: function setTimeout(callback, timeout) { + return addTimer.call(this, arguments, false); + }, + + clearTimeout: function clearTimeout(timerId) { + if (!timerId) { + // null appears to be allowed in most browsers, and appears to be relied upon by some libraries, like Bootstrap carousel + return; + } + if (!this.timeouts) { + this.timeouts = []; + } + // in Node, timerId is an object with .ref()/.unref(), and + // its .id field is the actual timer id. + if (typeof timerId === 'object') { + timerId = timerId.id + } + if (timerId in this.timeouts) { + delete this.timeouts[timerId]; + } + }, + + setInterval: function setInterval(callback, timeout) { + return addTimer.call(this, arguments, true); + }, + + clearInterval: function clearInterval(timerId) { + this.clearTimeout(timerId); + }, + + setImmediate: function setImmediate(callback) { + var passThruArgs = Array.prototype.slice.call(arguments, 1); + + return addTimer.call(this, [callback, 0].concat(passThruArgs), false); + }, + + clearImmediate: function clearImmediate(timerId) { + this.clearTimeout(timerId); + }, + + tick: function tick(ms) { + ms = typeof ms == "number" ? ms : parseTime(ms); + var tickFrom = this.now, tickTo = this.now + ms, previous = this.now; + var timer = this.firstTimerInRange(tickFrom, tickTo); + + var firstException; + while (timer && tickFrom <= tickTo) { + if (this.timeouts[timer.id]) { + tickFrom = this.now = timer.callAt; + try { + this.callTimer(timer); + } catch (e) { + firstException = firstException || e; + } + } + + timer = this.firstTimerInRange(previous, tickTo); + previous = tickFrom; + } + + this.now = tickTo; + + if (firstException) { + throw firstException; + } + + return this.now; + }, + + firstTimerInRange: function (from, to) { + var timer, smallest = null, originalTimer; + + for (var id in this.timeouts) { + if (this.timeouts.hasOwnProperty(id)) { + if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) { + continue; + } + + if (smallest === null || this.timeouts[id].callAt < smallest) { + originalTimer = this.timeouts[id]; + smallest = this.timeouts[id].callAt; + + timer = { + func: this.timeouts[id].func, + callAt: this.timeouts[id].callAt, + interval: this.timeouts[id].interval, + id: this.timeouts[id].id, + invokeArgs: this.timeouts[id].invokeArgs + }; + } + } + } + + return timer || null; + }, + + callTimer: function (timer) { + if (typeof timer.interval == "number") { + this.timeouts[timer.id].callAt += timer.interval; + } else { + delete this.timeouts[timer.id]; + } + + try { + if (typeof timer.func == "function") { + timer.func.apply(null, timer.invokeArgs); + } else { + eval(timer.func); + } + } catch (e) { + var exception = e; + } + + if (!this.timeouts[timer.id]) { + if (exception) { + throw exception; + } + return; + } + + if (exception) { + throw exception; + } + }, + + reset: function reset() { + this.timeouts = {}; + }, + + Date: (function () { + var NativeDate = Date; + + function ClockDate(year, month, date, hour, minute, second, ms) { + // Defensive and verbose to avoid potential harm in passing + // explicit undefined when user does not pass argument + switch (arguments.length) { + case 0: + return new NativeDate(ClockDate.clock.now); + case 1: + return new NativeDate(year); + case 2: + return new NativeDate(year, month); + case 3: + return new NativeDate(year, month, date); + case 4: + return new NativeDate(year, month, date, hour); + case 5: + return new NativeDate(year, month, date, hour, minute); + case 6: + return new NativeDate(year, month, date, hour, minute, second); + default: + return new NativeDate(year, month, date, hour, minute, second, ms); + } + } + + return mirrorDateProperties(ClockDate, NativeDate); + }()) + }; + + function mirrorDateProperties(target, source) { + if (source.now) { + target.now = function now() { + return target.clock.now; + }; + } else { + delete target.now; + } + + if (source.toSource) { + target.toSource = function toSource() { + return source.toSource(); + }; + } else { + delete target.toSource; + } + + target.toString = function toString() { + return source.toString(); + }; + + target.prototype = source.prototype; + target.parse = source.parse; + target.UTC = source.UTC; + target.prototype.toUTCString = source.prototype.toUTCString; + + for (var prop in source) { + if (source.hasOwnProperty(prop)) { + target[prop] = source[prop]; + } + } + + return target; + } + + var methods = ["Date", "setTimeout", "setInterval", + "clearTimeout", "clearInterval"]; + + if (typeof global.setImmediate !== "undefined") { + methods.push("setImmediate"); + } + + if (typeof global.clearImmediate !== "undefined") { + methods.push("clearImmediate"); + } + + function restore() { + var method; + + for (var i = 0, l = this.methods.length; i < l; i++) { + method = this.methods[i]; + + if (global[method].hadOwnProperty) { + global[method] = this["_" + method]; + } else { + try { + delete global[method]; + } catch (e) {} + } + } + + // Prevent multiple executions which will completely remove these props + this.methods = []; + } + + function stubGlobal(method, clock) { + clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method); + clock["_" + method] = global[method]; + + if (method == "Date") { + var date = mirrorDateProperties(clock[method], global[method]); + global[method] = date; + } else { + global[method] = function () { + return clock[method].apply(clock, arguments); + }; + + for (var prop in clock[method]) { + if (clock[method].hasOwnProperty(prop)) { + global[method][prop] = clock[method][prop]; + } + } + } + + global[method].clock = clock; + } + + sinon.useFakeTimers = function useFakeTimers(now) { + var clock = sinon.clock.create(now); + clock.restore = restore; + clock.methods = Array.prototype.slice.call(arguments, + typeof now == "number" ? 1 : 0); + + if (clock.methods.length === 0) { + clock.methods = methods; + } + + for (var i = 0, l = clock.methods.length; i < l; i++) { + stubGlobal(clock.methods[i], clock); + } + + return clock; + }; +}(typeof global != "undefined" && typeof global !== "function" ? global : this)); + +sinon.timers = { + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), + clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined), + setInterval: setInterval, + clearInterval: clearInterval, + Date: Date +}; + +if (typeof module !== 'undefined' && module.exports) { + module.exports = sinon; +} + +/*jslint eqeqeq: false, onevar: false*/ +/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ +/** + * Minimal Event interface implementation + * + * Original implementation by Sven Fuchs: https://gist.github.com/995028 + * Modifications and tests by Christian Johansen. + * + * @author Sven Fuchs (svenfuchs@artweb-design.de) + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2011 Sven Fuchs, Christian Johansen + */ + +if (typeof sinon == "undefined") { + this.sinon = {}; +} + +(function () { + var push = [].push; + + sinon.Event = function Event(type, bubbles, cancelable, target) { + this.initEvent(type, bubbles, cancelable, target); + }; + + sinon.Event.prototype = { + initEvent: function(type, bubbles, cancelable, target) { + this.type = type; + this.bubbles = bubbles; + this.cancelable = cancelable; + this.target = target; + }, + + stopPropagation: function () {}, + + preventDefault: function () { + this.defaultPrevented = true; + } + }; + + sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) { + this.initEvent(type, false, false, target); + this.loaded = progressEventRaw.loaded || null; + this.total = progressEventRaw.total || null; + }; + + sinon.ProgressEvent.prototype = new sinon.Event(); + + sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent; + + sinon.CustomEvent = function CustomEvent(type, customData, target) { + this.initEvent(type, false, false, target); + this.detail = customData.detail || null; + }; + + sinon.CustomEvent.prototype = new sinon.Event(); + + sinon.CustomEvent.prototype.constructor = sinon.CustomEvent; + + sinon.EventTarget = { + addEventListener: function addEventListener(event, listener) { + this.eventListeners = this.eventListeners || {}; + this.eventListeners[event] = this.eventListeners[event] || []; + push.call(this.eventListeners[event], listener); + }, + + removeEventListener: function removeEventListener(event, listener) { + var listeners = this.eventListeners && this.eventListeners[event] || []; + + for (var i = 0, l = listeners.length; i < l; ++i) { + if (listeners[i] == listener) { + return listeners.splice(i, 1); + } + } + }, + + dispatchEvent: function dispatchEvent(event) { + var type = event.type; + var listeners = this.eventListeners && this.eventListeners[type] || []; + + for (var i = 0; i < listeners.length; i++) { + if (typeof listeners[i] == "function") { + listeners[i].call(this, event); + } else { + listeners[i].handleEvent(event); + } + } + + return !!event.defaultPrevented; + } + }; +}()); + +/** + * @depend ../../sinon.js + * @depend event.js + */ +/*jslint eqeqeq: false, onevar: false*/ +/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ +/** + * Fake XMLHttpRequest object + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +// wrapper for global +(function(global) { + if (typeof sinon === "undefined") { + global.sinon = {}; + } + + var supportsProgress = typeof ProgressEvent !== "undefined"; + var supportsCustomEvent = typeof CustomEvent !== "undefined"; + sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest }; + var xhr = sinon.xhr; + xhr.GlobalXMLHttpRequest = global.XMLHttpRequest; + xhr.GlobalActiveXObject = global.ActiveXObject; + xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined"; + xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined"; + xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX + ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false; + xhr.supportsCORS = xhr.supportsXHR && 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest()); + + /*jsl:ignore*/ + var unsafeHeaders = { + "Accept-Charset": true, + "Accept-Encoding": true, + "Connection": true, + "Content-Length": true, + "Cookie": true, + "Cookie2": true, + "Content-Transfer-Encoding": true, + "Date": true, + "Expect": true, + "Host": true, + "Keep-Alive": true, + "Referer": true, + "TE": true, + "Trailer": true, + "Transfer-Encoding": true, + "Upgrade": true, + "User-Agent": true, + "Via": true + }; + /*jsl:end*/ + + function FakeXMLHttpRequest() { + this.readyState = FakeXMLHttpRequest.UNSENT; + this.requestHeaders = {}; + this.requestBody = null; + this.status = 0; + this.statusText = ""; + this.upload = new UploadProgress(); + if (sinon.xhr.supportsCORS) { + this.withCredentials = false; + } + + + var xhr = this; + var events = ["loadstart", "load", "abort", "loadend"]; + + function addEventListener(eventName) { + xhr.addEventListener(eventName, function (event) { + var listener = xhr["on" + eventName]; + + if (listener && typeof listener == "function") { + listener.call(this, event); + } + }); + } + + for (var i = events.length - 1; i >= 0; i--) { + addEventListener(events[i]); + } + + if (typeof FakeXMLHttpRequest.onCreate == "function") { + FakeXMLHttpRequest.onCreate(this); + } + } + + // An upload object is created for each + // FakeXMLHttpRequest and allows upload + // events to be simulated using uploadProgress + // and uploadError. + function UploadProgress() { + this.eventListeners = { + "progress": [], + "load": [], + "abort": [], + "error": [] + } + } + + UploadProgress.prototype.addEventListener = function(event, listener) { + this.eventListeners[event].push(listener); + }; + + UploadProgress.prototype.removeEventListener = function(event, listener) { + var listeners = this.eventListeners[event] || []; + + for (var i = 0, l = listeners.length; i < l; ++i) { + if (listeners[i] == listener) { + return listeners.splice(i, 1); + } + } + }; + + UploadProgress.prototype.dispatchEvent = function(event) { + var listeners = this.eventListeners[event.type] || []; + + for (var i = 0, listener; (listener = listeners[i]) != null; i++) { + listener(event); + } + }; + + function verifyState(xhr) { + if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { + throw new Error("INVALID_STATE_ERR"); + } + + if (xhr.sendFlag) { + throw new Error("INVALID_STATE_ERR"); + } + } + + // filtering to enable a white-list version of Sinon FakeXhr, + // where whitelisted requests are passed through to real XHR + function each(collection, callback) { + if (!collection) return; + for (var i = 0, l = collection.length; i < l; i += 1) { + callback(collection[i]); + } + } + function some(collection, callback) { + for (var index = 0; index < collection.length; index++) { + if(callback(collection[index]) === true) return true; + } + return false; + } + // largest arity in XHR is 5 - XHR#open + var apply = function(obj,method,args) { + switch(args.length) { + case 0: return obj[method](); + case 1: return obj[method](args[0]); + case 2: return obj[method](args[0],args[1]); + case 3: return obj[method](args[0],args[1],args[2]); + case 4: return obj[method](args[0],args[1],args[2],args[3]); + case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]); + } + }; + + FakeXMLHttpRequest.filters = []; + FakeXMLHttpRequest.addFilter = function(fn) { + this.filters.push(fn) + }; + var IE6Re = /MSIE 6/; + FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) { + var xhr = new sinon.xhr.workingXHR(); + each(["open","setRequestHeader","send","abort","getResponseHeader", + "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"], + function(method) { + fakeXhr[method] = function() { + return apply(xhr,method,arguments); + }; + }); + + var copyAttrs = function(args) { + each(args, function(attr) { + try { + fakeXhr[attr] = xhr[attr] + } catch(e) { + if(!IE6Re.test(navigator.userAgent)) throw e; + } + }); + }; + + var stateChange = function() { + fakeXhr.readyState = xhr.readyState; + if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) { + copyAttrs(["status","statusText"]); + } + if(xhr.readyState >= FakeXMLHttpRequest.LOADING) { + copyAttrs(["responseText"]); + } + if(xhr.readyState === FakeXMLHttpRequest.DONE) { + copyAttrs(["responseXML"]); + } + if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr }); + }; + if(xhr.addEventListener) { + for(var event in fakeXhr.eventListeners) { + if(fakeXhr.eventListeners.hasOwnProperty(event)) { + each(fakeXhr.eventListeners[event],function(handler) { + xhr.addEventListener(event, handler); + }); + } + } + xhr.addEventListener("readystatechange",stateChange); + } else { + xhr.onreadystatechange = stateChange; + } + apply(xhr,"open",xhrArgs); + }; + FakeXMLHttpRequest.useFilters = false; + + function verifyRequestOpened(xhr) { + if (xhr.readyState != FakeXMLHttpRequest.OPENED) { + throw new Error("INVALID_STATE_ERR - " + xhr.readyState); + } + } + + function verifyRequestSent(xhr) { + if (xhr.readyState == FakeXMLHttpRequest.DONE) { + throw new Error("Request done"); + } + } + + function verifyHeadersReceived(xhr) { + if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) { + throw new Error("No headers received"); + } + } + + function verifyResponseBodyType(body) { + if (typeof body != "string") { + var error = new Error("Attempted to respond to fake XMLHttpRequest with " + + body + ", which is not a string."); + error.name = "InvalidBodyException"; + throw error; + } + } + + sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, { + async: true, + + open: function open(method, url, async, username, password) { + this.method = method; + this.url = url; + this.async = typeof async == "boolean" ? async : true; + this.username = username; + this.password = password; + this.responseText = null; + this.responseXML = null; + this.requestHeaders = {}; + this.sendFlag = false; + if(sinon.FakeXMLHttpRequest.useFilters === true) { + var xhrArgs = arguments; + var defake = some(FakeXMLHttpRequest.filters,function(filter) { + return filter.apply(this,xhrArgs) + }); + if (defake) { + return sinon.FakeXMLHttpRequest.defake(this,arguments); + } + } + this.readyStateChange(FakeXMLHttpRequest.OPENED); + }, + + readyStateChange: function readyStateChange(state) { + this.readyState = state; + + if (typeof this.onreadystatechange == "function") { + try { + this.onreadystatechange(); + } catch (e) { + sinon.logError("Fake XHR onreadystatechange handler", e); + } + } + + this.dispatchEvent(new sinon.Event("readystatechange")); + + switch (this.readyState) { + case FakeXMLHttpRequest.DONE: + this.dispatchEvent(new sinon.Event("load", false, false, this)); + this.dispatchEvent(new sinon.Event("loadend", false, false, this)); + this.upload.dispatchEvent(new sinon.Event("load", false, false, this)); + if (supportsProgress) { + this.upload.dispatchEvent(new sinon.ProgressEvent('progress', {loaded: 100, total: 100})); + } + break; + } + }, + + setRequestHeader: function setRequestHeader(header, value) { + verifyState(this); + + if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) { + throw new Error("Refused to set unsafe header \"" + header + "\""); + } + + if (this.requestHeaders[header]) { + this.requestHeaders[header] += "," + value; + } else { + this.requestHeaders[header] = value; + } + }, + + // Helps testing + setResponseHeaders: function setResponseHeaders(headers) { + verifyRequestOpened(this); + this.responseHeaders = {}; + + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + this.responseHeaders[header] = headers[header]; + } + } + + if (this.async) { + this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED); + } else { + this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED; + } + }, + + // Currently treats ALL data as a DOMString (i.e. no Document) + send: function send(data) { + verifyState(this); + + if (!/^(get|head)$/i.test(this.method)) { + if (this.requestHeaders["Content-Type"]) { + var value = this.requestHeaders["Content-Type"].split(";"); + this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8"; + } else { + this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; + } + + this.requestBody = data; + } + + this.errorFlag = false; + this.sendFlag = this.async; + this.readyStateChange(FakeXMLHttpRequest.OPENED); + + if (typeof this.onSend == "function") { + this.onSend(this); + } + + this.dispatchEvent(new sinon.Event("loadstart", false, false, this)); + }, + + abort: function abort() { + this.aborted = true; + this.responseText = null; + this.errorFlag = true; + this.requestHeaders = {}; + + if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) { + this.readyStateChange(sinon.FakeXMLHttpRequest.DONE); + this.sendFlag = false; + } + + this.readyState = sinon.FakeXMLHttpRequest.UNSENT; + + this.dispatchEvent(new sinon.Event("abort", false, false, this)); + + this.upload.dispatchEvent(new sinon.Event("abort", false, false, this)); + + if (typeof this.onerror === "function") { + this.onerror(); + } + }, + + getResponseHeader: function getResponseHeader(header) { + if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { + return null; + } + + if (/^Set-Cookie2?$/i.test(header)) { + return null; + } + + header = header.toLowerCase(); + + for (var h in this.responseHeaders) { + if (h.toLowerCase() == header) { + return this.responseHeaders[h]; + } + } + + return null; + }, + + getAllResponseHeaders: function getAllResponseHeaders() { + if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { + return ""; + } + + var headers = ""; + + for (var header in this.responseHeaders) { + if (this.responseHeaders.hasOwnProperty(header) && + !/^Set-Cookie2?$/i.test(header)) { + headers += header + ": " + this.responseHeaders[header] + "\r\n"; + } + } + + return headers; + }, + + setResponseBody: function setResponseBody(body) { + verifyRequestSent(this); + verifyHeadersReceived(this); + verifyResponseBodyType(body); + + var chunkSize = this.chunkSize || 10; + var index = 0; + this.responseText = ""; + + do { + if (this.async) { + this.readyStateChange(FakeXMLHttpRequest.LOADING); + } + + this.responseText += body.substring(index, index + chunkSize); + index += chunkSize; + } while (index < body.length); + + var type = this.getResponseHeader("Content-Type"); + + if (this.responseText && + (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) { + try { + this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); + } catch (e) { + // Unable to parse XML - no biggie + } + } + + if (this.async) { + this.readyStateChange(FakeXMLHttpRequest.DONE); + } else { + this.readyState = FakeXMLHttpRequest.DONE; + } + }, + + respond: function respond(status, headers, body) { + this.status = typeof status == "number" ? status : 200; + this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; + this.setResponseHeaders(headers || {}); + this.setResponseBody(body || ""); + }, + + uploadProgress: function uploadProgress(progressEventRaw) { + if (supportsProgress) { + this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); + } + }, + + uploadError: function uploadError(error) { + if (supportsCustomEvent) { + this.upload.dispatchEvent(new sinon.CustomEvent("error", {"detail": error})); + } + } + }); + + sinon.extend(FakeXMLHttpRequest, { + UNSENT: 0, + OPENED: 1, + HEADERS_RECEIVED: 2, + LOADING: 3, + DONE: 4 + }); + + // Borrowed from JSpec + FakeXMLHttpRequest.parseXML = function parseXML(text) { + var xmlDoc; + + if (typeof DOMParser != "undefined") { + var parser = new DOMParser(); + xmlDoc = parser.parseFromString(text, "text/xml"); + } else { + xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); + xmlDoc.async = "false"; + xmlDoc.loadXML(text); + } + + return xmlDoc; + }; + + FakeXMLHttpRequest.statusCodes = { + 100: "Continue", + 101: "Switching Protocols", + 200: "OK", + 201: "Created", + 202: "Accepted", + 203: "Non-Authoritative Information", + 204: "No Content", + 205: "Reset Content", + 206: "Partial Content", + 300: "Multiple Choice", + 301: "Moved Permanently", + 302: "Found", + 303: "See Other", + 304: "Not Modified", + 305: "Use Proxy", + 307: "Temporary Redirect", + 400: "Bad Request", + 401: "Unauthorized", + 402: "Payment Required", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 406: "Not Acceptable", + 407: "Proxy Authentication Required", + 408: "Request Timeout", + 409: "Conflict", + 410: "Gone", + 411: "Length Required", + 412: "Precondition Failed", + 413: "Request Entity Too Large", + 414: "Request-URI Too Long", + 415: "Unsupported Media Type", + 416: "Requested Range Not Satisfiable", + 417: "Expectation Failed", + 422: "Unprocessable Entity", + 500: "Internal Server Error", + 501: "Not Implemented", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", + 505: "HTTP Version Not Supported" + }; + + sinon.useFakeXMLHttpRequest = function () { + sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) { + if (xhr.supportsXHR) { + global.XMLHttpRequest = xhr.GlobalXMLHttpRequest; + } + + if (xhr.supportsActiveX) { + global.ActiveXObject = xhr.GlobalActiveXObject; + } + + delete sinon.FakeXMLHttpRequest.restore; + + if (keepOnCreate !== true) { + delete sinon.FakeXMLHttpRequest.onCreate; + } + }; + if (xhr.supportsXHR) { + global.XMLHttpRequest = sinon.FakeXMLHttpRequest; + } + + if (xhr.supportsActiveX) { + global.ActiveXObject = function ActiveXObject(objId) { + if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { + + return new sinon.FakeXMLHttpRequest(); + } + + return new xhr.GlobalActiveXObject(objId); + }; + } + + return sinon.FakeXMLHttpRequest; + }; + + sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; + +})((function(){ return typeof global === "object" ? global : this; })()); + +if (typeof module !== 'undefined' && module.exports) { + module.exports = sinon; +} + +/** + * @depend fake_xml_http_request.js + */ +/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/ +/*global module, require, window*/ +/** + * The Sinon "server" mimics a web server that receives requests from + * sinon.FakeXMLHttpRequest and provides an API to respond to those requests, + * both synchronously and asynchronously. To respond synchronuously, canned + * answers have to be provided upfront. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof sinon == "undefined") { + var sinon = {}; +} + +sinon.fakeServer = (function () { + var push = [].push; + function F() {} + + function create(proto) { + F.prototype = proto; + return new F(); + } + + function responseArray(handler) { + var response = handler; + + if (Object.prototype.toString.call(handler) != "[object Array]") { + response = [200, {}, handler]; + } + + if (typeof response[2] != "string") { + throw new TypeError("Fake server response body should be string, but was " + + typeof response[2]); + } + + return response; + } + + var wloc = typeof window !== "undefined" ? window.location : {}; + var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); + + function matchOne(response, reqMethod, reqUrl) { + var rmeth = response.method; + var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase(); + var url = response.url; + var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl)); + + return matchMethod && matchUrl; + } + + function match(response, request) { + var requestUrl = request.url; + + if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) { + requestUrl = requestUrl.replace(rCurrLoc, ""); + } + + if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { + if (typeof response.response == "function") { + var ru = response.url; + var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []); + return response.response.apply(response, args); + } + + return true; + } + + return false; + } + + return { + create: function () { + var server = create(this); + this.xhr = sinon.useFakeXMLHttpRequest(); + server.requests = []; + + this.xhr.onCreate = function (xhrObj) { + server.addRequest(xhrObj); + }; + + return server; + }, + + addRequest: function addRequest(xhrObj) { + var server = this; + push.call(this.requests, xhrObj); + + xhrObj.onSend = function () { + server.handleRequest(this); + + if (server.autoRespond && !server.responding) { + setTimeout(function () { + server.responding = false; + server.respond(); + }, server.autoRespondAfter || 10); + + server.responding = true; + } + }; + }, + + getHTTPMethod: function getHTTPMethod(request) { + if (this.fakeHTTPMethods && /post/i.test(request.method)) { + var matches = (request.requestBody || "").match(/_method=([^\b;]+)/); + return !!matches ? matches[1] : request.method; + } + + return request.method; + }, + + handleRequest: function handleRequest(xhr) { + if (xhr.async) { + if (!this.queue) { + this.queue = []; + } + + push.call(this.queue, xhr); + } else { + this.processRequest(xhr); + } + }, + + log: function(response, request) { + var str; + + str = "Request:\n" + sinon.format(request) + "\n\n"; + str += "Response:\n" + sinon.format(response) + "\n\n"; + + sinon.log(str); + }, + + respondWith: function respondWith(method, url, body) { + if (arguments.length == 1 && typeof method != "function") { + this.response = responseArray(method); + return; + } + + if (!this.responses) { this.responses = []; } + + if (arguments.length == 1) { + body = method; + url = method = null; + } + + if (arguments.length == 2) { + body = url; + url = method; + method = null; + } + + push.call(this.responses, { + method: method, + url: url, + response: typeof body == "function" ? body : responseArray(body) + }); + }, + + respond: function respond() { + if (arguments.length > 0) this.respondWith.apply(this, arguments); + var queue = this.queue || []; + var requests = queue.splice(0, queue.length); + var request; + + while(request = requests.shift()) { + this.processRequest(request); + } + }, + + processRequest: function processRequest(request) { + try { + if (request.aborted) { + return; + } + + var response = this.response || [404, {}, ""]; + + if (this.responses) { + for (var l = this.responses.length, i = l - 1; i >= 0; i--) { + if (match.call(this, this.responses[i], request)) { + response = this.responses[i].response; + break; + } + } + } + + if (request.readyState != 4) { + sinon.fakeServer.log(response, request); + + request.respond(response[0], response[1], response[2]); + } + } catch (e) { + sinon.logError("Fake server request processing", e); + } + }, + + restore: function restore() { + return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments); + } + }; +}()); + +if (typeof module !== 'undefined' && module.exports) { + module.exports = sinon; +} + +/** + * @depend fake_server.js + * @depend fake_timers.js + */ +/*jslint browser: true, eqeqeq: false, onevar: false*/ +/*global sinon*/ +/** + * Add-on for sinon.fakeServer that automatically handles a fake timer along with + * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery + * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead, + * it polls the object for completion with setInterval. Dispite the direct + * motivation, there is nothing jQuery-specific in this file, so it can be used + * in any environment where the ajax implementation depends on setInterval or + * setTimeout. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function () { + function Server() {} + Server.prototype = sinon.fakeServer; + + sinon.fakeServerWithClock = new Server(); + + sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { + if (xhr.async) { + if (typeof setTimeout.clock == "object") { + this.clock = setTimeout.clock; + } else { + this.clock = sinon.useFakeTimers(); + this.resetClock = true; + } + + if (!this.longestTimeout) { + var clockSetTimeout = this.clock.setTimeout; + var clockSetInterval = this.clock.setInterval; + var server = this; + + this.clock.setTimeout = function (fn, timeout) { + server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); + + return clockSetTimeout.apply(this, arguments); + }; + + this.clock.setInterval = function (fn, timeout) { + server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); + + return clockSetInterval.apply(this, arguments); + }; + } + } + + return sinon.fakeServer.addRequest.call(this, xhr); + }; + + sinon.fakeServerWithClock.respond = function respond() { + var returnVal = sinon.fakeServer.respond.apply(this, arguments); + + if (this.clock) { + this.clock.tick(this.longestTimeout || 0); + this.longestTimeout = 0; + + if (this.resetClock) { + this.clock.restore(); + this.resetClock = false; + } + } + + return returnVal; + }; + + sinon.fakeServerWithClock.restore = function restore() { + if (this.clock) { + this.clock.restore(); + } + + return sinon.fakeServer.restore.apply(this, arguments); + }; +}()); + +/** + * @depend ../sinon.js + * @depend collection.js + * @depend util/fake_timers.js + * @depend util/fake_server_with_clock.js + */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global require, module*/ +/** + * Manages fake collections as well as fake utilities such as Sinon's + * timers and fake XHR implementation in one convenient object. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof module !== "undefined" && module.exports && typeof require == "function") { + var sinon = require("../sinon"); + sinon.extend(sinon, require("./util/fake_timers")); +} + +(function () { + var push = [].push; + + function exposeValue(sandbox, config, key, value) { + if (!value) { + return; + } + + if (config.injectInto && !(key in config.injectInto)) { + config.injectInto[key] = value; + sandbox.injectedKeys.push(key); + } else { + push.call(sandbox.args, value); + } + } + + function prepareSandboxFromConfig(config) { + var sandbox = sinon.create(sinon.sandbox); + + if (config.useFakeServer) { + if (typeof config.useFakeServer == "object") { + sandbox.serverPrototype = config.useFakeServer; + } + + sandbox.useFakeServer(); + } + + if (config.useFakeTimers) { + if (typeof config.useFakeTimers == "object") { + sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); + } else { + sandbox.useFakeTimers(); + } + } + + return sandbox; + } + + sinon.sandbox = sinon.extend(sinon.create(sinon.collection), { + useFakeTimers: function useFakeTimers() { + this.clock = sinon.useFakeTimers.apply(sinon, arguments); + + return this.add(this.clock); + }, + + serverPrototype: sinon.fakeServer, + + useFakeServer: function useFakeServer() { + var proto = this.serverPrototype || sinon.fakeServer; + + if (!proto || !proto.create) { + return null; + } + + this.server = proto.create(); + return this.add(this.server); + }, + + inject: function (obj) { + sinon.collection.inject.call(this, obj); + + if (this.clock) { + obj.clock = this.clock; + } + + if (this.server) { + obj.server = this.server; + obj.requests = this.server.requests; + } + + return obj; + }, + + restore: function () { + sinon.collection.restore.apply(this, arguments); + this.restoreContext(); + }, + + restoreContext: function () { + if (this.injectedKeys) { + for (var i = 0, j = this.injectedKeys.length; i < j; i++) { + delete this.injectInto[this.injectedKeys[i]]; + } + this.injectedKeys = []; + } + }, + + create: function (config) { + if (!config) { + return sinon.create(sinon.sandbox); + } + + var sandbox = prepareSandboxFromConfig(config); + sandbox.args = sandbox.args || []; + sandbox.injectedKeys = []; + sandbox.injectInto = config.injectInto; + var prop, value, exposed = sandbox.inject({}); + + if (config.properties) { + for (var i = 0, l = config.properties.length; i < l; i++) { + prop = config.properties[i]; + value = exposed[prop] || prop == "sandbox" && sandbox; + exposeValue(sandbox, config, prop, value); + } + } else { + exposeValue(sandbox, config, "sandbox", value); + } + + return sandbox; + } + }); + + sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = sinon.sandbox; }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = sinon.sandbox; + } +}()); + +/** + * @depend ../sinon.js + * @depend stub.js + * @depend mock.js + * @depend sandbox.js + */ +/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Test function, sandboxes fakes + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function test(callback) { + var type = typeof callback; + + if (type != "function") { + throw new TypeError("sinon.test needs to wrap a test function, got " + type); + } + + function sinonSandboxedTest() { + var config = sinon.getConfig(sinon.config); + config.injectInto = config.injectIntoThis && this || config.injectInto; + var sandbox = sinon.sandbox.create(config); + var exception, result; + var args = Array.prototype.slice.call(arguments).concat(sandbox.args); + + try { + result = callback.apply(this, args); + } catch (e) { + exception = e; + } + + if (typeof exception !== "undefined") { + sandbox.restore(); + throw exception; + } + else { + sandbox.verifyAndRestore(); + } + + return result; + }; + + if (callback.length) { + return function sinonAsyncSandboxedTest(callback) { + return sinonSandboxedTest.apply(this, arguments); + }; + } + + return sinonSandboxedTest; + } + + test.config = { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "server", "requests"], + useFakeTimers: true, + useFakeServer: true + }; + + sinon.test = test; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = test; }); + } else if (commonJSModule) { + module.exports = test; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend test.js + */ +/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/ +/*global module, require, sinon*/ +/** + * Test case, sandboxes all test functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon || !Object.prototype.hasOwnProperty) { + return; + } + + function createTest(property, setUp, tearDown) { + return function () { + if (setUp) { + setUp.apply(this, arguments); + } + + var exception, result; + + try { + result = property.apply(this, arguments); + } catch (e) { + exception = e; + } + + if (tearDown) { + tearDown.apply(this, arguments); + } + + if (exception) { + throw exception; + } + + return result; + }; + } + + function testCase(tests, prefix) { + /*jsl:ignore*/ + if (!tests || typeof tests != "object") { + throw new TypeError("sinon.testCase needs an object with test functions"); + } + /*jsl:end*/ + + prefix = prefix || "test"; + var rPrefix = new RegExp("^" + prefix); + var methods = {}, testName, property, method; + var setUp = tests.setUp; + var tearDown = tests.tearDown; + + for (testName in tests) { + if (tests.hasOwnProperty(testName)) { + property = tests[testName]; + + if (/^(setUp|tearDown)$/.test(testName)) { + continue; + } + + if (typeof property == "function" && rPrefix.test(testName)) { + method = property; + + if (setUp || tearDown) { + method = createTest(property, setUp, tearDown); + } + + methods[testName] = sinon.test(method); + } else { + methods[testName] = tests[testName]; + } + } + } + + return methods; + } + + sinon.testCase = testCase; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = testCase; }); + } else if (commonJSModule) { + module.exports = testCase; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend stub.js + */ +/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Assertions matching the test spy retrieval interface. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon, global) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + var slice = Array.prototype.slice; + var assert; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function verifyIsStub() { + var method; + + for (var i = 0, l = arguments.length; i < l; ++i) { + method = arguments[i]; + + if (!method) { + assert.fail("fake is not a spy"); + } + + if (typeof method != "function") { + assert.fail(method + " is not a function"); + } + + if (typeof method.getCall != "function") { + assert.fail(method + " is not stubbed"); + } + } + } + + function failAssertion(object, msg) { + object = object || global; + var failMethod = object.fail || assert.fail; + failMethod.call(object, msg); + } + + function mirrorPropAsAssertion(name, method, message) { + if (arguments.length == 2) { + message = method; + method = name; + } + + assert[name] = function (fake) { + verifyIsStub(fake); + + var args = slice.call(arguments, 1); + var failed = false; + + if (typeof method == "function") { + failed = !method(fake); + } else { + failed = typeof fake[method] == "function" ? + !fake[method].apply(fake, args) : !fake[method]; + } + + if (failed) { + failAssertion(this, fake.printf.apply(fake, [message].concat(args))); + } else { + assert.pass(name); + } + }; + } + + function exposedName(prefix, prop) { + return !prefix || /^fail/.test(prop) ? prop : + prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1); + } + + assert = { + failException: "AssertError", + + fail: function fail(message) { + var error = new Error(message); + error.name = this.failException || assert.failException; + + throw error; + }, + + pass: function pass(assertion) {}, + + callOrder: function assertCallOrder() { + verifyIsStub.apply(null, arguments); + var expected = "", actual = ""; + + if (!sinon.calledInOrder(arguments)) { + try { + expected = [].join.call(arguments, ", "); + var calls = slice.call(arguments); + var i = calls.length; + while (i) { + if (!calls[--i].called) { + calls.splice(i, 1); + } + } + actual = sinon.orderByFirstCall(calls).join(", "); + } catch (e) { + // If this fails, we'll just fall back to the blank string + } + + failAssertion(this, "expected " + expected + " to be " + + "called in order but were called as " + actual); + } else { + assert.pass("callOrder"); + } + }, + + callCount: function assertCallCount(method, count) { + verifyIsStub(method); + + if (method.callCount != count) { + var msg = "expected %n to be called " + sinon.timesInWords(count) + + " but was called %c%C"; + failAssertion(this, method.printf(msg)); + } else { + assert.pass("callCount"); + } + }, + + expose: function expose(target, options) { + if (!target) { + throw new TypeError("target is null or undefined"); + } + + var o = options || {}; + var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix; + var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail; + + for (var method in this) { + if (method != "export" && (includeFail || !/^(fail)/.test(method))) { + target[exposedName(prefix, method)] = this[method]; + } + } + + return target; + }, + + match: function match(actual, expectation) { + var matcher = sinon.match(expectation); + if (matcher.test(actual)) { + assert.pass("match"); + } else { + var formatted = [ + "expected value to match", + " expected = " + sinon.format(expectation), + " actual = " + sinon.format(actual) + ] + failAssertion(this, formatted.join("\n")); + } + } + }; + + mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called"); + mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; }, + "expected %n to not have been called but was called %c%C"); + mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C"); + mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C"); + mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C"); + mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t"); + mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t"); + mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new"); + mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new"); + mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C"); + mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C"); + mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C"); + mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C"); + mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C"); + mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C"); + mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C"); + mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C"); + mirrorPropAsAssertion("threw", "%n did not throw exception%C"); + mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C"); + + sinon.assert = assert; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = assert; }); + } else if (commonJSModule) { + module.exports = assert; + } +}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global)); + +/** + * @depend ../../sinon.js + * @depend event.js + */ +/*jslint eqeqeq: false, onevar: false*/ +/*global sinon, module, require, XDomainRequest*/ +/** + * Fake XDomainRequest object + */ + +if (typeof sinon == "undefined") { + this.sinon = {}; +} +sinon.xdr = { XDomainRequest: this.XDomainRequest }; + +// wrapper for global +(function (global) { + var xdr = sinon.xdr; + xdr.GlobalXDomainRequest = global.XDomainRequest; + xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined"; + xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false; + + function FakeXDomainRequest() { + this.readyState = FakeXDomainRequest.UNSENT; + this.requestBody = null; + this.requestHeaders = {}; + this.status = 0; + this.timeout = null; + + if (typeof FakeXDomainRequest.onCreate == "function") { + FakeXDomainRequest.onCreate(this); + } + } + + function verifyState(xdr) { + if (xdr.readyState !== FakeXDomainRequest.OPENED) { + throw new Error("INVALID_STATE_ERR"); + } + + if (xdr.sendFlag) { + throw new Error("INVALID_STATE_ERR"); + } + } + + function verifyRequestSent(xdr) { + if (xdr.readyState == FakeXDomainRequest.UNSENT) { + throw new Error("Request not sent"); + } + if (xdr.readyState == FakeXDomainRequest.DONE) { + throw new Error("Request done"); + } + } + + function verifyResponseBodyType(body) { + if (typeof body != "string") { + var error = new Error("Attempted to respond to fake XDomainRequest with " + + body + ", which is not a string."); + error.name = "InvalidBodyException"; + throw error; + } + } + + sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, { + open: function open(method, url) { + this.method = method; + this.url = url; + + this.responseText = null; + this.sendFlag = false; + + this.readyStateChange(FakeXDomainRequest.OPENED); + }, + + readyStateChange: function readyStateChange(state) { + this.readyState = state; + var eventName = ''; + switch (this.readyState) { + case FakeXDomainRequest.UNSENT: + break; + case FakeXDomainRequest.OPENED: + break; + case FakeXDomainRequest.LOADING: + if (this.sendFlag){ + //raise the progress event + eventName = 'onprogress'; + } + break; + case FakeXDomainRequest.DONE: + if (this.isTimeout){ + eventName = 'ontimeout' + } + else if (this.errorFlag || (this.status < 200 || this.status > 299)) { + eventName = 'onerror'; + } + else { + eventName = 'onload' + } + break; + } + + // raising event (if defined) + if (eventName) { + if (typeof this[eventName] == "function") { + try { + this[eventName](); + } catch (e) { + sinon.logError("Fake XHR " + eventName + " handler", e); + } + } + } + }, + + send: function send(data) { + verifyState(this); + + if (!/^(get|head)$/i.test(this.method)) { + this.requestBody = data; + } + this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; + + this.errorFlag = false; + this.sendFlag = true; + this.readyStateChange(FakeXDomainRequest.OPENED); + + if (typeof this.onSend == "function") { + this.onSend(this); + } + }, + + abort: function abort() { + this.aborted = true; + this.responseText = null; + this.errorFlag = true; + + if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) { + this.readyStateChange(sinon.FakeXDomainRequest.DONE); + this.sendFlag = false; + } + }, + + setResponseBody: function setResponseBody(body) { + verifyRequestSent(this); + verifyResponseBodyType(body); + + var chunkSize = this.chunkSize || 10; + var index = 0; + this.responseText = ""; + + do { + this.readyStateChange(FakeXDomainRequest.LOADING); + this.responseText += body.substring(index, index + chunkSize); + index += chunkSize; + } while (index < body.length); + + this.readyStateChange(FakeXDomainRequest.DONE); + }, + + respond: function respond(status, contentType, body) { + // content-type ignored, since XDomainRequest does not carry this + // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease + // test integration across browsers + this.status = typeof status == "number" ? status : 200; + this.setResponseBody(body || ""); + }, + + simulatetimeout: function(){ + this.status = 0; + this.isTimeout = true; + // Access to this should actually throw an error + this.responseText = undefined; + this.readyStateChange(FakeXDomainRequest.DONE); + } + }); + + sinon.extend(FakeXDomainRequest, { + UNSENT: 0, + OPENED: 1, + LOADING: 3, + DONE: 4 + }); + + sinon.useFakeXDomainRequest = function () { + sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) { + if (xdr.supportsXDR) { + global.XDomainRequest = xdr.GlobalXDomainRequest; + } + + delete sinon.FakeXDomainRequest.restore; + + if (keepOnCreate !== true) { + delete sinon.FakeXDomainRequest.onCreate; + } + }; + if (xdr.supportsXDR) { + global.XDomainRequest = sinon.FakeXDomainRequest; + } + return sinon.FakeXDomainRequest; + }; + + sinon.FakeXDomainRequest = FakeXDomainRequest; +})(this); + +if (typeof module == "object" && typeof require == "function") { + module.exports = sinon; +} + +return sinon;}.call(typeof window != 'undefined' && window || {})); diff --git a/js/jquery-mask/test/sinon-qunit-1.0.0.js b/js/jquery-mask/test/sinon-qunit-1.0.0.js new file mode 100755 index 0000000000..c26232fae7 --- /dev/null +++ b/js/jquery-mask/test/sinon-qunit-1.0.0.js @@ -0,0 +1,62 @@ +/** + * sinon-qunit 1.0.0, 2010/12/09 + * + * @author Christian Johansen (christian@cjohansen.no) + * + * (The BSD License) + * + * Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Christian Johansen nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*global sinon, QUnit, test*/ +sinon.assert.fail = function (msg) { + QUnit.ok(false, msg); +}; + +sinon.assert.pass = function (assertion) { + QUnit.ok(true, assertion); +}; + +sinon.config = { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "sandbox"], + useFakeTimers: true, + useFakeServer: false +}; + +(function (global) { + var qTest = QUnit.test; + + QUnit.test = global.test = function (testName, expected, callback, async) { + if (arguments.length === 2) { + callback = expected; + expected = null; + } + + return qTest(testName, expected, sinon.test(callback), async); + }; +}(this)); diff --git a/js/jquery-mask/test/sinon-qunit.js b/js/jquery-mask/test/sinon-qunit.js new file mode 100755 index 0000000000..c26232fae7 --- /dev/null +++ b/js/jquery-mask/test/sinon-qunit.js @@ -0,0 +1,62 @@ +/** + * sinon-qunit 1.0.0, 2010/12/09 + * + * @author Christian Johansen (christian@cjohansen.no) + * + * (The BSD License) + * + * Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Christian Johansen nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*global sinon, QUnit, test*/ +sinon.assert.fail = function (msg) { + QUnit.ok(false, msg); +}; + +sinon.assert.pass = function (assertion) { + QUnit.ok(true, assertion); +}; + +sinon.config = { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "sandbox"], + useFakeTimers: true, + useFakeServer: false +}; + +(function (global) { + var qTest = QUnit.test; + + QUnit.test = global.test = function (testName, expected, callback, async) { + if (arguments.length === 2) { + callback = expected; + expected = null; + } + + return qTest(testName, expected, sinon.test(callback), async); + }; +}(this)); diff --git a/js/jquery-mask/test/test-for-jquery-1.11.1.html b/js/jquery-mask/test/test-for-jquery-1.11.1.html new file mode 100755 index 0000000000..23de894934 --- /dev/null +++ b/js/jquery-mask/test/test-for-jquery-1.11.1.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

    jQuery-Mask-Plugin QUnit Tests

    +

    +
    +

    +
      +
      test markup, will be hidden
      + + + + + + + + +
      +
      + + + + + + + + + + + + diff --git a/js/jquery-mask/test/test-for-jquery-1.7.2.html b/js/jquery-mask/test/test-for-jquery-1.7.2.html new file mode 100755 index 0000000000..e50d43ae4e --- /dev/null +++ b/js/jquery-mask/test/test-for-jquery-1.7.2.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

      jQuery-Mask-Plugin QUnit Tests

      +

      +
      +

      +
        +
        test markup, will be hidden
        + + + + + + + + +
        +
        + + + + + + + + + + + + diff --git a/js/jquery-mask/test/test-for-jquery-1.8.3.html b/js/jquery-mask/test/test-for-jquery-1.8.3.html new file mode 100755 index 0000000000..c037820ad0 --- /dev/null +++ b/js/jquery-mask/test/test-for-jquery-1.8.3.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

        jQuery-Mask-Plugin QUnit Tests

        +

        +
        +

        +
          +
          test markup, will be hidden
          + + + + + + + + +
          +
          + + + + + + + + + + + + diff --git a/js/jquery-mask/test/test-for-jquery-1.9.1.html b/js/jquery-mask/test/test-for-jquery-1.9.1.html new file mode 100755 index 0000000000..65765858b2 --- /dev/null +++ b/js/jquery-mask/test/test-for-jquery-1.9.1.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

          jQuery-Mask-Plugin QUnit Tests

          +

          +
          +

          +
            +
            test markup, will be hidden
            + + + + + + + + +
            +
            + + + + + + + + + + + + diff --git a/js/jquery-mask/test/test-for-jquery-2.1.1.html b/js/jquery-mask/test/test-for-jquery-2.1.1.html new file mode 100755 index 0000000000..052517a829 --- /dev/null +++ b/js/jquery-mask/test/test-for-jquery-2.1.1.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

            jQuery-Mask-Plugin QUnit Tests

            +

            +
            +

            +
              +
              test markup, will be hidden
              + + + + + + + + +
              +
              + + + + + + + + + + + + diff --git a/js/jquery-mask/test/test-for-jquery-3.0.0.html b/js/jquery-mask/test/test-for-jquery-3.0.0.html new file mode 100755 index 0000000000..283b5cdf4a --- /dev/null +++ b/js/jquery-mask/test/test-for-jquery-3.0.0.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

              jQuery-Mask-Plugin QUnit Tests

              +

              +
              +

              +
                +
                test markup, will be hidden
                + + + + + + + + +
                +
                + + + + + + + + + + + + diff --git a/js/jquery-mask/test/test-for-zepto.html b/js/jquery-mask/test/test-for-zepto.html new file mode 100755 index 0000000000..abb593232f --- /dev/null +++ b/js/jquery-mask/test/test-for-zepto.html @@ -0,0 +1,36 @@ + + + Zepto-Mask-Plugin UnitTesting + + + + +

                Zepto-Mask-Plugin QUnit Tests

                +

                +
                +

                +
                  +
                  test markup, will be hidden
                  + + + + + + + + +
                  +
                  + + + + + + + + + + + + + \ No newline at end of file diff --git a/js/jquery-mask/test/zepto/data.js b/js/jquery-mask/test/zepto/data.js new file mode 100755 index 0000000000..8a9f9db3a2 --- /dev/null +++ b/js/jquery-mask/test/zepto/data.js @@ -0,0 +1,80 @@ +// Zepto.js +// (c) 2010-2014 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +// The following code is heavily inspired by jQuery's $.fn.data() + +;(function($){ + var data = {}, dataAttr = $.fn.data, camelize = $.camelCase, + exp = $.expando = 'Zepto' + (+new Date()), emptyArray = [] + + // Get value from node: + // 1. first try key as given, + // 2. then try camelized key, + // 3. fall back to reading "data-*" attribute. + function getData(node, name) { + var id = node[exp], store = id && data[id] + if (name === undefined) return store || setData(node) + else { + if (store) { + if (name in store) return store[name] + var camelName = camelize(name) + if (camelName in store) return store[camelName] + } + return dataAttr.call($(node), name) + } + } + + // Store value under camelized key on node + function setData(node, name, value) { + var id = node[exp] || (node[exp] = ++$.uuid), + store = data[id] || (data[id] = attributeData(node)) + if (name !== undefined) store[camelize(name)] = value + return store + } + + // Read all "data-*" attributes from a node + function attributeData(node) { + var store = {} + $.each(node.attributes || emptyArray, function(i, attr){ + if (attr.name.indexOf('data-') == 0) + store[camelize(attr.name.replace('data-', ''))] = + $.zepto.deserializeValue(attr.value) + }) + return store + } + + $.fn.data = function(name, value) { + return value === undefined ? + // set multiple values via object + $.isPlainObject(name) ? + this.each(function(i, node){ + $.each(name, function(key, value){ setData(node, key, value) }) + }) : + // get value from first element + (0 in this ? getData(this[0], name) : undefined) : + // set value on all elements + this.each(function(){ setData(this, name, value) }) + } + + $.fn.removeData = function(names) { + if (typeof names == 'string') names = names.split(/\s+/) + return this.each(function(){ + var id = this[exp], store = id && data[id] + if (store) $.each(names || store, function(key){ + delete store[names ? camelize(this) : key] + }) + }) + } + + // Generate extended `remove` and `empty` functions + ;['remove', 'empty'].forEach(function(methodName){ + var origFn = $.fn[methodName] + $.fn[methodName] = function() { + var elements = this.find('*') + if (methodName === 'remove') elements = elements.add(this) + elements.removeData() + return origFn.call(this) + } + }) +})(Zepto) diff --git a/js/jquery-mask/test/zepto/event.js b/js/jquery-mask/test/zepto/event.js new file mode 100755 index 0000000000..a7d2ec1a70 --- /dev/null +++ b/js/jquery-mask/test/zepto/event.js @@ -0,0 +1,282 @@ +// Zepto.js +// (c) 2010-2014 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + var _zid = 1, undefined, + slice = Array.prototype.slice, + isFunction = $.isFunction, + isString = function(obj){ return typeof obj == 'string' }, + handlers = {}, + specialEvents={}, + focusinSupported = 'onfocusin' in window, + focus = { focus: 'focusin', blur: 'focusout' }, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } + + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' + + function zid(element) { + return element._zid || (element._zid = _zid++) + } + function findHandlers(element, event, fn, selector) { + event = parse(event) + if (event.ns) var matcher = matcherFor(event.ns) + return (handlers[zid(element)] || []).filter(function(handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector) + }) + } + function parse(event) { + var parts = ('' + event).split('.') + return {e: parts[0], ns: parts.slice(1).sort().join(' ')} + } + function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') + } + + function eventCapture(handler, captureSetting) { + return handler.del && + (!focusinSupported && (handler.e in focus)) || + !!captureSetting + } + + function realEvent(type) { + return hover[type] || (focusinSupported && focus[type]) || type + } + + function add(element, events, fn, data, selector, delegator, capture){ + var id = zid(element), set = (handlers[id] || (handlers[id] = [])) + events.split(/\s/).forEach(function(event){ + if (event == 'ready') return $(document).ready(fn) + var handler = parse(event) + handler.fn = fn + handler.sel = selector + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function(e){ + var related = e.relatedTarget + if (!related || (related !== this && !$.contains(this, related))) + return handler.fn.apply(this, arguments) + } + handler.del = delegator + var callback = delegator || fn + handler.proxy = function(e){ + e = compatible(e) + if (e.isImmediatePropagationStopped()) return + e.data = data + var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)) + if (result === false) e.preventDefault(), e.stopPropagation() + return result + } + handler.i = set.length + set.push(handler) + if ('addEventListener' in element) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + } + function remove(element, events, fn, selector, capture){ + var id = zid(element) + ;(events || '').split(/\s/).forEach(function(event){ + findHandlers(element, event, fn, selector).forEach(function(handler){ + delete handlers[id][handler.i] + if ('removeEventListener' in element) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + }) + } + + $.event = { add: add, remove: remove } + + $.proxy = function(fn, context) { + var args = (2 in arguments) && slice.call(arguments, 2) + if (isFunction(fn)) { + var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) } + proxyFn._zid = zid(fn) + return proxyFn + } else if (isString(context)) { + if (args) { + args.unshift(fn[context], fn) + return $.proxy.apply(null, args) + } else { + return $.proxy(fn[context], fn) + } + } else { + throw new TypeError("expected function") + } + } + + $.fn.bind = function(event, data, callback){ + return this.on(event, data, callback) + } + $.fn.unbind = function(event, callback){ + return this.off(event, callback) + } + $.fn.one = function(event, selector, data, callback){ + return this.on(event, selector, data, callback, 1) + } + + var returnTrue = function(){return true}, + returnFalse = function(){return false}, + ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + } + + function compatible(event, source) { + if (source || !event.isDefaultPrevented) { + source || (source = event) + + $.each(eventMethods, function(name, predicate) { + var sourceMethod = source[name] + event[name] = function(){ + this[predicate] = returnTrue + return sourceMethod && sourceMethod.apply(source, arguments) + } + event[predicate] = returnFalse + }) + + if (source.defaultPrevented !== undefined ? source.defaultPrevented : + 'returnValue' in source ? source.returnValue === false : + source.getPreventDefault && source.getPreventDefault()) + event.isDefaultPrevented = returnTrue + } + return event + } + + function createProxy(event) { + var key, proxy = { originalEvent: event } + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] + + return compatible(proxy, event) + } + + $.fn.delegate = function(selector, event, callback){ + return this.on(event, selector, callback) + } + $.fn.undelegate = function(selector, event, callback){ + return this.off(event, selector, callback) + } + + $.fn.live = function(event, callback){ + $(document.body).delegate(this.selector, event, callback) + return this + } + $.fn.die = function(event, callback){ + $(document.body).undelegate(this.selector, event, callback) + return this + } + + $.fn.on = function(event, selector, data, callback, one){ + var autoRemove, delegator, $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.on(type, selector, data, fn, one) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = data, data = selector, selector = undefined + if (isFunction(data) || data === false) + callback = data, data = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(_, element){ + if (one) autoRemove = function(e){ + remove(element, e.type, callback) + return callback.apply(this, arguments) + } + + if (selector) delegator = function(e){ + var evt, match = $(e.target).closest(selector, element).get(0) + if (match && match !== element) { + evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) + return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))) + } + } + + add(element, event, callback, data, selector, delegator || autoRemove) + }) + } + $.fn.off = function(event, selector, callback){ + var $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.off(type, selector, fn) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = selector, selector = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(){ + remove(this, event, callback, selector) + }) + } + + $.fn.trigger = function(event, args){ + event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event) + event._args = args + return this.each(function(){ + // items in the collection might not be DOM elements + if('dispatchEvent' in this) this.dispatchEvent(event) + else $(this).triggerHandler(event, args) + }) + } + + // triggers event handlers on current element just as if an event occurred, + // doesn't trigger an actual event, doesn't bubble + $.fn.triggerHandler = function(event, args){ + var e, result + this.each(function(i, element){ + e = createProxy(isString(event) ? $.Event(event) : event) + e._args = args + e.target = element + $.each(findHandlers(element, event.type || event), function(i, handler){ + result = handler.proxy(e) + if (e.isImmediatePropagationStopped()) return false + }) + }) + return result + } + + // shortcut methods for `.bind(event, fn)` for each event type + ;('focusin focusout load resize scroll unload click dblclick '+ + 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ + 'change select keydown keypress keyup error').split(' ').forEach(function(event) { + $.fn[event] = function(callback) { + return callback ? + this.bind(event, callback) : + this.trigger(event) + } + }) + + ;['focus', 'blur'].forEach(function(name) { + $.fn[name] = function(callback) { + if (callback) this.bind(name, callback) + else this.each(function(){ + try { this[name]() } + catch(e) {} + }) + return this + } + }) + + $.Event = function(type, props) { + if (!isString(type)) props = type, type = props.type + var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true + if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) + event.initEvent(type, bubbles, true) + return compatible(event) + } + +})(Zepto) diff --git a/js/jquery-mask/test/zepto/zepto.min.js b/js/jquery-mask/test/zepto/zepto.min.js new file mode 100755 index 0000000000..99949a36cd --- /dev/null +++ b/js/jquery-mask/test/zepto/zepto.min.js @@ -0,0 +1,1580 @@ +/* Zepto v1.1.4 - zepto event ajax form ie - zeptojs.com/license */ + +var Zepto = (function() { + var undefined, key, $, classList, emptyArray = [], slice = emptyArray.slice, filter = emptyArray.filter, + document = window.document, + elementDisplay = {}, classCache = {}, + cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 }, + fragmentRE = /^\s*<(\w+|!)[^>]*>/, + singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + capitalRE = /([A-Z])/g, + + // special attributes that should be get/set via method calls + methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], + + adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ], + table = document.createElement('table'), + tableRow = document.createElement('tr'), + containers = { + 'tr': document.createElement('tbody'), + 'tbody': table, 'thead': table, 'tfoot': table, + 'td': tableRow, 'th': tableRow, + '*': document.createElement('div') + }, + readyRE = /complete|loaded|interactive/, + simpleSelectorRE = /^[\w-]*$/, + class2type = {}, + toString = class2type.toString, + zepto = {}, + camelize, uniq, + tempParent = document.createElement('div'), + propMap = { + 'tabindex': 'tabIndex', + 'readonly': 'readOnly', + 'for': 'htmlFor', + 'class': 'className', + 'maxlength': 'maxLength', + 'cellspacing': 'cellSpacing', + 'cellpadding': 'cellPadding', + 'rowspan': 'rowSpan', + 'colspan': 'colSpan', + 'usemap': 'useMap', + 'frameborder': 'frameBorder', + 'contenteditable': 'contentEditable' + }, + isArray = Array.isArray || + function(object){ return object instanceof Array } + + zepto.matches = function(element, selector) { + if (!selector || !element || element.nodeType !== 1) return false + var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector || + element.oMatchesSelector || element.matchesSelector + if (matchesSelector) return matchesSelector.call(element, selector) + // fall back to performing a selector: + var match, parent = element.parentNode, temp = !parent + if (temp) (parent = tempParent).appendChild(element) + match = ~zepto.qsa(parent, selector).indexOf(element) + temp && tempParent.removeChild(element) + return match + } + + function type(obj) { + return obj == null ? String(obj) : + class2type[toString.call(obj)] || "object" + } + + function isFunction(value) { return type(value) == "function" } + function isWindow(obj) { return obj != null && obj == obj.window } + function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } + function isObject(obj) { return type(obj) == "object" } + function isPlainObject(obj) { + return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype + } + function likeArray(obj) { return typeof obj.length == 'number' } + + function compact(array) { return filter.call(array, function(item){ return item != null }) } + function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array } + camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) } + function dasherize(str) { + return str.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/_/g, '-') + .toLowerCase() + } + uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) } + + function classRE(name) { + return name in classCache ? + classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')) + } + + function maybeAddPx(name, value) { + return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value + } + + function defaultDisplay(nodeName) { + var element, display + if (!elementDisplay[nodeName]) { + element = document.createElement(nodeName) + document.body.appendChild(element) + display = getComputedStyle(element, '').getPropertyValue("display") + element.parentNode.removeChild(element) + display == "none" && (display = "block") + elementDisplay[nodeName] = display + } + return elementDisplay[nodeName] + } + + function children(element) { + return 'children' in element ? + slice.call(element.children) : + $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node }) + } + + // `$.zepto.fragment` takes a html string and an optional tag name + // to generate DOM nodes nodes from the given html string. + // The generated DOM nodes are returned as an array. + // This function can be overriden in plugins for example to make + // it compatible with browsers that don't support the DOM fully. + zepto.fragment = function(html, name, properties) { + var dom, nodes, container + + // A special case optimization for a single tag + if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1)) + + if (!dom) { + if (html.replace) html = html.replace(tagExpanderRE, "<$1>") + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 + if (!(name in containers)) name = '*' + + container = containers[name] + container.innerHTML = '' + html + dom = $.each(slice.call(container.childNodes), function(){ + container.removeChild(this) + }) + } + + if (isPlainObject(properties)) { + nodes = $(dom) + $.each(properties, function(key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value) + else nodes.attr(key, value) + }) + } + + return dom + } + + // `$.zepto.Z` swaps out the prototype of the given `dom` array + // of nodes with `$.fn` and thus supplying all the Zepto functions + // to the array. Note that `__proto__` is not supported on Internet + // Explorer. This method can be overriden in plugins. + zepto.Z = function(dom, selector) { + dom = dom || [] + dom.__proto__ = $.fn + dom.selector = selector || '' + return dom + } + + // `$.zepto.isZ` should return `true` if the given object is a Zepto + // collection. This method can be overriden in plugins. + zepto.isZ = function(object) { + return object instanceof zepto.Z + } + + // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and + // takes a CSS selector and an optional context (and handles various + // special cases). + // This method can be overriden in plugins. + zepto.init = function(selector, context) { + var dom + // If nothing given, return an empty Zepto collection + if (!selector) return zepto.Z() + // Optimize for string selectors + else if (typeof selector == 'string') { + selector = selector.trim() + // If it's a html fragment, create nodes from it + // Note: In both Chrome 21 and Firefox 15, DOM error 12 + // is thrown if the fragment doesn't begin with < + if (selector[0] == '<' && fragmentRE.test(selector)) + dom = zepto.fragment(selector, RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // If it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) return $(document).ready(selector) + // If a Zepto collection is given, just return it + else if (zepto.isZ(selector)) return selector + else { + // normalize array if an array of nodes is given + if (isArray(selector)) dom = compact(selector) + // Wrap DOM nodes. + else if (isObject(selector)) + dom = [selector], selector = null + // If it's a html fragment, create nodes from it + else if (fragmentRE.test(selector)) + dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // And last but no least, if it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // create a new Zepto collection from the nodes found + return zepto.Z(dom, selector) + } + + // `$` will be the base `Zepto` object. When calling this + // function just call `$.zepto.init, which makes the implementation + // details of selecting nodes and creating Zepto collections + // patchable in plugins. + $ = function(selector, context){ + return zepto.init(selector, context) + } + + function extend(target, source, deep) { + for (key in source) + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) + target[key] = {} + if (isArray(source[key]) && !isArray(target[key])) + target[key] = [] + extend(target[key], source[key], deep) + } + else if (source[key] !== undefined) target[key] = source[key] + } + + // Copy all but undefined properties from one or more + // objects to the `target` object. + $.extend = function(target){ + var deep, args = slice.call(arguments, 1) + if (typeof target == 'boolean') { + deep = target + target = args.shift() + } + args.forEach(function(arg){ extend(target, arg, deep) }) + return target + } + + // `$.zepto.qsa` is Zepto's CSS selector implementation which + // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`. + // This method can be overriden in plugins. + zepto.qsa = function(element, selector){ + var found, + maybeID = selector[0] == '#', + maybeClass = !maybeID && selector[0] == '.', + nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked + isSimple = simpleSelectorRE.test(nameOnly) + return (isDocument(element) && isSimple && maybeID) ? + ( (found = element.getElementById(nameOnly)) ? [found] : [] ) : + (element.nodeType !== 1 && element.nodeType !== 9) ? [] : + slice.call( + isSimple && !maybeID ? + maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class + element.getElementsByTagName(selector) : // Or a tag + element.querySelectorAll(selector) // Or it's not simple, and we need to query all + ) + } + + function filtered(nodes, selector) { + return selector == null ? $(nodes) : $(nodes).filter(selector) + } + + $.contains = document.documentElement.contains ? + function(parent, node) { + return parent !== node && parent.contains(node) + } : + function(parent, node) { + while (node && (node = node.parentNode)) + if (node === parent) return true + return false + } + + function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg + } + + function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value) + } + + // access className property while respecting SVGAnimatedString + function className(node, value){ + var klass = node.className, + svg = klass && klass.baseVal !== undefined + + if (value === undefined) return svg ? klass.baseVal : klass + svg ? (klass.baseVal = value) : (node.className = value) + } + + // "true" => true + // "false" => false + // "null" => null + // "42" => 42 + // "42.5" => 42.5 + // "08" => "08" + // JSON => parse if valid + // String => self + function deserializeValue(value) { + var num + try { + return value ? + value == "true" || + ( value == "false" ? false : + value == "null" ? null : + !/^0/.test(value) && !isNaN(num = Number(value)) ? num : + /^[\[\{]/.test(value) ? $.parseJSON(value) : + value ) + : value + } catch(e) { + return value + } + } + + $.type = type + $.isFunction = isFunction + $.isWindow = isWindow + $.isArray = isArray + $.isPlainObject = isPlainObject + + $.isEmptyObject = function(obj) { + var name + for (name in obj) return false + return true + } + + $.inArray = function(elem, array, i){ + return emptyArray.indexOf.call(array, elem, i) + } + + $.camelCase = camelize + $.trim = function(str) { + return str == null ? "" : String.prototype.trim.call(str) + } + + // plugin compatibility + $.uuid = 0 + $.support = { } + $.expr = { } + + $.map = function(elements, callback){ + var value, values = [], i, key + if (likeArray(elements)) + for (i = 0; i < elements.length; i++) { + value = callback(elements[i], i) + if (value != null) values.push(value) + } + else + for (key in elements) { + value = callback(elements[key], key) + if (value != null) values.push(value) + } + return flatten(values) + } + + $.each = function(elements, callback){ + var i, key + if (likeArray(elements)) { + for (i = 0; i < elements.length; i++) + if (callback.call(elements[i], i, elements[i]) === false) return elements + } else { + for (key in elements) + if (callback.call(elements[key], key, elements[key]) === false) return elements + } + + return elements + } + + $.grep = function(elements, callback){ + return filter.call(elements, callback) + } + + if (window.JSON) $.parseJSON = JSON.parse + + // Populate the class2type map + $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase() + }) + + // Define methods that will be available on all + // Zepto collections + $.fn = { + // Because a collection acts like an array + // copy over these useful array functions. + forEach: emptyArray.forEach, + reduce: emptyArray.reduce, + push: emptyArray.push, + sort: emptyArray.sort, + indexOf: emptyArray.indexOf, + concat: emptyArray.concat, + + // `map` and `slice` in the jQuery API work differently + // from their array counterparts + map: function(fn){ + return $($.map(this, function(el, i){ return fn.call(el, i, el) })) + }, + slice: function(){ + return $(slice.apply(this, arguments)) + }, + + ready: function(callback){ + // need to check if document.body exists for IE as that browser reports + // document ready when it hasn't yet created the body element + if (readyRE.test(document.readyState) && document.body) callback($) + else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false) + return this + }, + get: function(idx){ + return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length] + }, + toArray: function(){ return this.get() }, + size: function(){ + return this.length + }, + remove: function(){ + return this.each(function(){ + if (this.parentNode != null) + this.parentNode.removeChild(this) + }) + }, + each: function(callback){ + emptyArray.every.call(this, function(el, idx){ + return callback.call(el, idx, el) !== false + }) + return this + }, + filter: function(selector){ + if (isFunction(selector)) return this.not(this.not(selector)) + return $(filter.call(this, function(element){ + return zepto.matches(element, selector) + })) + }, + add: function(selector,context){ + return $(uniq(this.concat($(selector,context)))) + }, + is: function(selector){ + return this.length > 0 && zepto.matches(this[0], selector) + }, + not: function(selector){ + var nodes=[] + if (isFunction(selector) && selector.call !== undefined) + this.each(function(idx){ + if (!selector.call(this,idx)) nodes.push(this) + }) + else { + var excludes = typeof selector == 'string' ? this.filter(selector) : + (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector) + this.forEach(function(el){ + if (excludes.indexOf(el) < 0) nodes.push(el) + }) + } + return $(nodes) + }, + has: function(selector){ + return this.filter(function(){ + return isObject(selector) ? + $.contains(this, selector) : + $(this).find(selector).size() + }) + }, + eq: function(idx){ + return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1) + }, + first: function(){ + var el = this[0] + return el && !isObject(el) ? el : $(el) + }, + last: function(){ + var el = this[this.length - 1] + return el && !isObject(el) ? el : $(el) + }, + find: function(selector){ + var result, $this = this + if (!selector) result = [] + else if (typeof selector == 'object') + result = $(selector).filter(function(){ + var node = this + return emptyArray.some.call($this, function(parent){ + return $.contains(parent, node) + }) + }) + else if (this.length == 1) result = $(zepto.qsa(this[0], selector)) + else result = this.map(function(){ return zepto.qsa(this, selector) }) + return result + }, + closest: function(selector, context){ + var node = this[0], collection = false + if (typeof selector == 'object') collection = $(selector) + while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector))) + node = node !== context && !isDocument(node) && node.parentNode + return $(node) + }, + parents: function(selector){ + var ancestors = [], nodes = this + while (nodes.length > 0) + nodes = $.map(nodes, function(node){ + if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) { + ancestors.push(node) + return node + } + }) + return filtered(ancestors, selector) + }, + parent: function(selector){ + return filtered(uniq(this.pluck('parentNode')), selector) + }, + children: function(selector){ + return filtered(this.map(function(){ return children(this) }), selector) + }, + contents: function() { + return this.map(function() { return slice.call(this.childNodes) }) + }, + siblings: function(selector){ + return filtered(this.map(function(i, el){ + return filter.call(children(el.parentNode), function(child){ return child!==el }) + }), selector) + }, + empty: function(){ + return this.each(function(){ this.innerHTML = '' }) + }, + // `pluck` is borrowed from Prototype.js + pluck: function(property){ + return $.map(this, function(el){ return el[property] }) + }, + show: function(){ + return this.each(function(){ + this.style.display == "none" && (this.style.display = '') + if (getComputedStyle(this, '').getPropertyValue("display") == "none") + this.style.display = defaultDisplay(this.nodeName) + }) + }, + replaceWith: function(newContent){ + return this.before(newContent).remove() + }, + wrap: function(structure){ + var func = isFunction(structure) + if (this[0] && !func) + var dom = $(structure).get(0), + clone = dom.parentNode || this.length > 1 + + return this.each(function(index){ + $(this).wrapAll( + func ? structure.call(this, index) : + clone ? dom.cloneNode(true) : dom + ) + }) + }, + wrapAll: function(structure){ + if (this[0]) { + $(this[0]).before(structure = $(structure)) + var children + // drill down to the inmost element + while ((children = structure.children()).length) structure = children.first() + $(structure).append(this) + } + return this + }, + wrapInner: function(structure){ + var func = isFunction(structure) + return this.each(function(index){ + var self = $(this), contents = self.contents(), + dom = func ? structure.call(this, index) : structure + contents.length ? contents.wrapAll(dom) : self.append(dom) + }) + }, + unwrap: function(){ + this.parent().each(function(){ + $(this).replaceWith($(this).children()) + }) + return this + }, + clone: function(){ + return this.map(function(){ return this.cloneNode(true) }) + }, + hide: function(){ + return this.css("display", "none") + }, + toggle: function(setting){ + return this.each(function(){ + var el = $(this) + ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide() + }) + }, + prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') }, + next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') }, + html: function(html){ + return 0 in arguments ? + this.each(function(idx){ + var originHtml = this.innerHTML + $(this).empty().append( funcArg(this, html, idx, originHtml) ) + }) : + (0 in this ? this[0].innerHTML : null) + }, + text: function(text){ + return 0 in arguments ? + this.each(function(idx){ + var newText = funcArg(this, text, idx, this.textContent) + this.textContent = newText == null ? '' : ''+newText + }) : + (0 in this ? this[0].textContent : null) + }, + attr: function(name, value){ + var result + return (typeof name == 'string' && !(1 in arguments)) ? + (!this.length || this[0].nodeType !== 1 ? undefined : + (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result + ) : + this.each(function(idx){ + if (this.nodeType !== 1) return + if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) + else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) + }) + }, + removeAttr: function(name){ + return this.each(function(){ this.nodeType === 1 && setAttribute(this, name) }) + }, + prop: function(name, value){ + name = propMap[name] || name + return (1 in arguments) ? + this.each(function(idx){ + this[name] = funcArg(this, value, idx, this[name]) + }) : + (this[0] && this[0][name]) + }, + data: function(name, value){ + var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase() + + var data = (1 in arguments) ? + this.attr(attrName, value) : + this.attr(attrName) + + return data !== null ? deserializeValue(data) : undefined + }, + val: function(value){ + return 0 in arguments ? + this.each(function(idx){ + this.value = funcArg(this, value, idx, this.value) + }) : + (this[0] && (this[0].multiple ? + $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') : + this[0].value) + ) + }, + offset: function(coordinates){ + if (coordinates) return this.each(function(index){ + var $this = $(this), + coords = funcArg(this, coordinates, index, $this.offset()), + parentOffset = $this.offsetParent().offset(), + props = { + top: coords.top - parentOffset.top, + left: coords.left - parentOffset.left + } + + if ($this.css('position') == 'static') props['position'] = 'relative' + $this.css(props) + }) + if (!this.length) return null + var obj = this[0].getBoundingClientRect() + return { + left: obj.left + window.pageXOffset, + top: obj.top + window.pageYOffset, + width: Math.round(obj.width), + height: Math.round(obj.height) + } + }, + css: function(property, value){ + if (arguments.length < 2) { + var element = this[0], computedStyle = getComputedStyle(element, '') + if(!element) return + if (typeof property == 'string') + return element.style[camelize(property)] || computedStyle.getPropertyValue(property) + else if (isArray(property)) { + var props = {} + $.each(isArray(property) ? property: [property], function(_, prop){ + props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop)) + }) + return props + } + } + + var css = '' + if (type(property) == 'string') { + if (!value && value !== 0) + this.each(function(){ this.style.removeProperty(dasherize(property)) }) + else + css = dasherize(property) + ":" + maybeAddPx(property, value) + } else { + for (key in property) + if (!property[key] && property[key] !== 0) + this.each(function(){ this.style.removeProperty(dasherize(key)) }) + else + css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' + } + + return this.each(function(){ this.style.cssText += ';' + css }) + }, + index: function(element){ + return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]) + }, + hasClass: function(name){ + if (!name) return false + return emptyArray.some.call(this, function(el){ + return this.test(className(el)) + }, classRE(name)) + }, + addClass: function(name){ + if (!name) return this + return this.each(function(idx){ + classList = [] + var cls = className(this), newName = funcArg(this, name, idx, cls) + newName.split(/\s+/g).forEach(function(klass){ + if (!$(this).hasClass(klass)) classList.push(klass) + }, this) + classList.length && className(this, cls + (cls ? " " : "") + classList.join(" ")) + }) + }, + removeClass: function(name){ + return this.each(function(idx){ + if (name === undefined) return className(this, '') + classList = className(this) + funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){ + classList = classList.replace(classRE(klass), " ") + }) + className(this, classList.trim()) + }) + }, + toggleClass: function(name, when){ + if (!name) return this + return this.each(function(idx){ + var $this = $(this), names = funcArg(this, name, idx, className(this)) + names.split(/\s+/g).forEach(function(klass){ + (when === undefined ? !$this.hasClass(klass) : when) ? + $this.addClass(klass) : $this.removeClass(klass) + }) + }) + }, + scrollTop: function(value){ + if (!this.length) return + var hasScrollTop = 'scrollTop' in this[0] + if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset + return this.each(hasScrollTop ? + function(){ this.scrollTop = value } : + function(){ this.scrollTo(this.scrollX, value) }) + }, + scrollLeft: function(value){ + if (!this.length) return + var hasScrollLeft = 'scrollLeft' in this[0] + if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset + return this.each(hasScrollLeft ? + function(){ this.scrollLeft = value } : + function(){ this.scrollTo(value, this.scrollY) }) + }, + position: function() { + if (!this.length) return + + var elem = this[0], + // Get *real* offsetParent + offsetParent = this.offsetParent(), + // Get correct offsets + offset = this.offset(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset() + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( $(elem).css('margin-top') ) || 0 + offset.left -= parseFloat( $(elem).css('margin-left') ) || 0 + + // Add offsetParent borders + parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0 + parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0 + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + } + }, + offsetParent: function() { + return this.map(function(){ + var parent = this.offsetParent || document.body + while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static") + parent = parent.offsetParent + return parent + }) + } + } + + // for now + $.fn.detach = $.fn.remove + + // Generate the `width` and `height` functions + ;['width', 'height'].forEach(function(dimension){ + var dimensionProperty = + dimension.replace(/./, function(m){ return m[0].toUpperCase() }) + + $.fn[dimension] = function(value){ + var offset, el = this[0] + if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] : + isDocument(el) ? el.documentElement['scroll' + dimensionProperty] : + (offset = this.offset()) && offset[dimension] + else return this.each(function(idx){ + el = $(this) + el.css(dimension, funcArg(this, value, idx, el[dimension]())) + }) + } + }) + + function traverseNode(node, fun) { + fun(node) + for (var i = 0, len = node.childNodes.length; i < len; i++) + traverseNode(node.childNodes[i], fun) + } + + // Generate the `after`, `prepend`, `before`, `append`, + // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods. + adjacencyOperators.forEach(function(operator, operatorIndex) { + var inside = operatorIndex % 2 //=> prepend, append + + $.fn[operator] = function(){ + // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings + var argType, nodes = $.map(arguments, function(arg) { + argType = type(arg) + return argType == "object" || argType == "array" || arg == null ? + arg : zepto.fragment(arg) + }), + parent, copyByClone = this.length > 1 + if (nodes.length < 1) return this + + return this.each(function(_, target){ + parent = inside ? target : target.parentNode + + // convert all methods to a "before" operation + target = operatorIndex == 0 ? target.nextSibling : + operatorIndex == 1 ? target.firstChild : + operatorIndex == 2 ? target : + null + + var parentInDocument = $.contains(document.documentElement, parent) + + nodes.forEach(function(node){ + if (copyByClone) node = node.cloneNode(true) + else if (!parent) return $(node).remove() + + parent.insertBefore(node, target) + if (parentInDocument) traverseNode(node, function(el){ + if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && + (!el.type || el.type === 'text/javascript') && !el.src) + window['eval'].call(window, el.innerHTML) + }) + }) + }) + } + + // after => insertAfter + // prepend => prependTo + // before => insertBefore + // append => appendTo + $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){ + $(html)[operator](this) + return this + } + }) + + zepto.Z.prototype = $.fn + + // Export internal API functions in the `$.zepto` namespace + zepto.uniq = uniq + zepto.deserializeValue = deserializeValue + $.zepto = zepto + + return $ +})() + +window.Zepto = Zepto +window.$ === undefined && (window.$ = Zepto) + +;(function($){ + var _zid = 1, undefined, + slice = Array.prototype.slice, + isFunction = $.isFunction, + isString = function(obj){ return typeof obj == 'string' }, + handlers = {}, + specialEvents={}, + focusinSupported = 'onfocusin' in window, + focus = { focus: 'focusin', blur: 'focusout' }, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } + + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' + + function zid(element) { + return element._zid || (element._zid = _zid++) + } + function findHandlers(element, event, fn, selector) { + event = parse(event) + if (event.ns) var matcher = matcherFor(event.ns) + return (handlers[zid(element)] || []).filter(function(handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector) + }) + } + function parse(event) { + var parts = ('' + event).split('.') + return {e: parts[0], ns: parts.slice(1).sort().join(' ')} + } + function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') + } + + function eventCapture(handler, captureSetting) { + return handler.del && + (!focusinSupported && (handler.e in focus)) || + !!captureSetting + } + + function realEvent(type) { + return hover[type] || (focusinSupported && focus[type]) || type + } + + function add(element, events, fn, data, selector, delegator, capture){ + var id = zid(element), set = (handlers[id] || (handlers[id] = [])) + events.split(/\s/).forEach(function(event){ + if (event == 'ready') return $(document).ready(fn) + var handler = parse(event) + handler.fn = fn + handler.sel = selector + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function(e){ + var related = e.relatedTarget + if (!related || (related !== this && !$.contains(this, related))) + return handler.fn.apply(this, arguments) + } + handler.del = delegator + var callback = delegator || fn + handler.proxy = function(e){ + e = compatible(e) + if (e.isImmediatePropagationStopped()) return + e.data = data + var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)) + if (result === false) e.preventDefault(), e.stopPropagation() + return result + } + handler.i = set.length + set.push(handler) + if ('addEventListener' in element) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + } + function remove(element, events, fn, selector, capture){ + var id = zid(element) + ;(events || '').split(/\s/).forEach(function(event){ + findHandlers(element, event, fn, selector).forEach(function(handler){ + delete handlers[id][handler.i] + if ('removeEventListener' in element) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + }) + } + + $.event = { add: add, remove: remove } + + $.proxy = function(fn, context) { + var args = (2 in arguments) && slice.call(arguments, 2) + if (isFunction(fn)) { + var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) } + proxyFn._zid = zid(fn) + return proxyFn + } else if (isString(context)) { + if (args) { + args.unshift(fn[context], fn) + return $.proxy.apply(null, args) + } else { + return $.proxy(fn[context], fn) + } + } else { + throw new TypeError("expected function") + } + } + + $.fn.bind = function(event, data, callback){ + return this.on(event, data, callback) + } + $.fn.unbind = function(event, callback){ + return this.off(event, callback) + } + $.fn.one = function(event, selector, data, callback){ + return this.on(event, selector, data, callback, 1) + } + + var returnTrue = function(){return true}, + returnFalse = function(){return false}, + ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + } + + function compatible(event, source) { + if (source || !event.isDefaultPrevented) { + source || (source = event) + + $.each(eventMethods, function(name, predicate) { + var sourceMethod = source[name] + event[name] = function(){ + this[predicate] = returnTrue + return sourceMethod && sourceMethod.apply(source, arguments) + } + event[predicate] = returnFalse + }) + + if (source.defaultPrevented !== undefined ? source.defaultPrevented : + 'returnValue' in source ? source.returnValue === false : + source.getPreventDefault && source.getPreventDefault()) + event.isDefaultPrevented = returnTrue + } + return event + } + + function createProxy(event) { + var key, proxy = { originalEvent: event } + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] + + return compatible(proxy, event) + } + + $.fn.delegate = function(selector, event, callback){ + return this.on(event, selector, callback) + } + $.fn.undelegate = function(selector, event, callback){ + return this.off(event, selector, callback) + } + + $.fn.live = function(event, callback){ + $(document.body).delegate(this.selector, event, callback) + return this + } + $.fn.die = function(event, callback){ + $(document.body).undelegate(this.selector, event, callback) + return this + } + + $.fn.on = function(event, selector, data, callback, one){ + var autoRemove, delegator, $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.on(type, selector, data, fn, one) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = data, data = selector, selector = undefined + if (isFunction(data) || data === false) + callback = data, data = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(_, element){ + if (one) autoRemove = function(e){ + remove(element, e.type, callback) + return callback.apply(this, arguments) + } + + if (selector) delegator = function(e){ + var evt, match = $(e.target).closest(selector, element).get(0) + if (match && match !== element) { + evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) + return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))) + } + } + + add(element, event, callback, data, selector, delegator || autoRemove) + }) + } + $.fn.off = function(event, selector, callback){ + var $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.off(type, selector, fn) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = selector, selector = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(){ + remove(this, event, callback, selector) + }) + } + + $.fn.trigger = function(event, args){ + event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event) + event._args = args + return this.each(function(){ + // items in the collection might not be DOM elements + if('dispatchEvent' in this) this.dispatchEvent(event) + else $(this).triggerHandler(event, args) + }) + } + + // triggers event handlers on current element just as if an event occurred, + // doesn't trigger an actual event, doesn't bubble + $.fn.triggerHandler = function(event, args){ + var e, result + this.each(function(i, element){ + e = createProxy(isString(event) ? $.Event(event) : event) + e._args = args + e.target = element + $.each(findHandlers(element, event.type || event), function(i, handler){ + result = handler.proxy(e) + if (e.isImmediatePropagationStopped()) return false + }) + }) + return result + } + + // shortcut methods for `.bind(event, fn)` for each event type + ;('focusin focusout load resize scroll unload click dblclick '+ + 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ + 'change select keydown keypress keyup error').split(' ').forEach(function(event) { + $.fn[event] = function(callback) { + return callback ? + this.bind(event, callback) : + this.trigger(event) + } + }) + + ;['focus', 'blur'].forEach(function(name) { + $.fn[name] = function(callback) { + if (callback) this.bind(name, callback) + else this.each(function(){ + try { this[name]() } + catch(e) {} + }) + return this + } + }) + + $.Event = function(type, props) { + if (!isString(type)) props = type, type = props.type + var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true + if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) + event.initEvent(type, bubbles, true) + return compatible(event) + } + +})(Zepto) + +;(function($){ + var jsonpID = 0, + document = window.document, + key, + name, + rscript = /)<[^<]*)*<\/script>/gi, + scriptTypeRE = /^(?:text|application)\/javascript/i, + xmlTypeRE = /^(?:text|application)\/xml/i, + jsonType = 'application/json', + htmlType = 'text/html', + blankRE = /^\s*$/ + + // trigger a custom event and return false if it was cancelled + function triggerAndReturn(context, eventName, data) { + var event = $.Event(eventName) + $(context).trigger(event, data) + return !event.isDefaultPrevented() + } + + // trigger an Ajax "global" event + function triggerGlobal(settings, context, eventName, data) { + if (settings.global) return triggerAndReturn(context || document, eventName, data) + } + + // Number of active Ajax requests + $.active = 0 + + function ajaxStart(settings) { + if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart') + } + function ajaxStop(settings) { + if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop') + } + + // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable + function ajaxBeforeSend(xhr, settings) { + var context = settings.context + if (settings.beforeSend.call(context, xhr, settings) === false || + triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false) + return false + + triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]) + } + function ajaxSuccess(data, xhr, settings, deferred) { + var context = settings.context, status = 'success' + settings.success.call(context, data, status, xhr) + if (deferred) deferred.resolveWith(context, [data, status, xhr]) + triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]) + ajaxComplete(status, xhr, settings) + } + // type: "timeout", "error", "abort", "parsererror" + function ajaxError(error, type, xhr, settings, deferred) { + var context = settings.context + settings.error.call(context, xhr, type, error) + if (deferred) deferred.rejectWith(context, [xhr, type, error]) + triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error || type]) + ajaxComplete(type, xhr, settings) + } + // status: "success", "notmodified", "error", "timeout", "abort", "parsererror" + function ajaxComplete(status, xhr, settings) { + var context = settings.context + settings.complete.call(context, xhr, status) + triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]) + ajaxStop(settings) + } + + // Empty function, used as default callback + function empty() {} + + $.ajaxJSONP = function(options, deferred){ + if (!('type' in options)) return $.ajax(options) + + var _callbackName = options.jsonpCallback, + callbackName = ($.isFunction(_callbackName) ? + _callbackName() : _callbackName) || ('jsonp' + (++jsonpID)), + script = document.createElement('script'), + originalCallback = window[callbackName], + responseData, + abort = function(errorType) { + $(script).triggerHandler('error', errorType || 'abort') + }, + xhr = { abort: abort }, abortTimeout + + if (deferred) deferred.promise(xhr) + + $(script).on('load error', function(e, errorType){ + clearTimeout(abortTimeout) + $(script).off().remove() + + if (e.type == 'error' || !responseData) { + ajaxError(null, errorType || 'error', xhr, options, deferred) + } else { + ajaxSuccess(responseData[0], xhr, options, deferred) + } + + window[callbackName] = originalCallback + if (responseData && $.isFunction(originalCallback)) + originalCallback(responseData[0]) + + originalCallback = responseData = undefined + }) + + if (ajaxBeforeSend(xhr, options) === false) { + abort('abort') + return xhr + } + + window[callbackName] = function(){ + responseData = arguments + } + + script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName) + document.head.appendChild(script) + + if (options.timeout > 0) abortTimeout = setTimeout(function(){ + abort('timeout') + }, options.timeout) + + return xhr + } + + $.ajaxSettings = { + // Default type of request + type: 'GET', + // Callback that is executed before request + beforeSend: empty, + // Callback that is executed if the request succeeds + success: empty, + // Callback that is executed the the server drops error + error: empty, + // Callback that is executed on request complete (both: error and success) + complete: empty, + // The context for the callbacks + context: null, + // Whether to trigger "global" Ajax events + global: true, + // Transport + xhr: function () { + return new window.XMLHttpRequest() + }, + // MIME types mapping + // IIS returns Javascript as "application/x-javascript" + accepts: { + script: 'text/javascript, application/javascript, application/x-javascript', + json: jsonType, + xml: 'application/xml, text/xml', + html: htmlType, + text: 'text/plain' + }, + // Whether the request is to another domain + crossDomain: false, + // Default timeout + timeout: 0, + // Whether data should be serialized to string + processData: true, + // Whether the browser should be allowed to cache GET responses + cache: true + } + + function mimeToDataType(mime) { + if (mime) mime = mime.split(';', 2)[0] + return mime && ( mime == htmlType ? 'html' : + mime == jsonType ? 'json' : + scriptTypeRE.test(mime) ? 'script' : + xmlTypeRE.test(mime) && 'xml' ) || 'text' + } + + function appendQuery(url, query) { + if (query == '') return url + return (url + '&' + query).replace(/[&?]{1,2}/, '?') + } + + // serialize payload and append it to the URL for GET requests + function serializeData(options) { + if (options.processData && options.data && $.type(options.data) != "string") + options.data = $.param(options.data, options.traditional) + if (options.data && (!options.type || options.type.toUpperCase() == 'GET')) + options.url = appendQuery(options.url, options.data), options.data = undefined + } + + $.ajax = function(options){ + var settings = $.extend({}, options || {}), + deferred = $.Deferred && $.Deferred() + for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key] + + ajaxStart(settings) + + if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && + RegExp.$2 != window.location.host + + if (!settings.url) settings.url = window.location.toString() + serializeData(settings) + + var dataType = settings.dataType, hasPlaceholder = /\?.+=\?/.test(settings.url) + if (hasPlaceholder) dataType = 'jsonp' + + if (settings.cache === false || ( + (!options || options.cache !== true) && + ('script' == dataType || 'jsonp' == dataType) + )) + settings.url = appendQuery(settings.url, '_=' + Date.now()) + + if ('jsonp' == dataType) { + if (!hasPlaceholder) + settings.url = appendQuery(settings.url, + settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?') + return $.ajaxJSONP(settings, deferred) + } + + var mime = settings.accepts[dataType], + headers = { }, + setHeader = function(name, value) { headers[name.toLowerCase()] = [name, value] }, + protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol, + xhr = settings.xhr(), + nativeSetHeader = xhr.setRequestHeader, + abortTimeout + + if (deferred) deferred.promise(xhr) + + if (!settings.crossDomain) setHeader('X-Requested-With', 'XMLHttpRequest') + setHeader('Accept', mime || '*/*') + if (mime = settings.mimeType || mime) { + if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0] + xhr.overrideMimeType && xhr.overrideMimeType(mime) + } + if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) + setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded') + + if (settings.headers) for (name in settings.headers) setHeader(name, settings.headers[name]) + xhr.setRequestHeader = setHeader + + xhr.onreadystatechange = function(){ + if (xhr.readyState == 4) { + xhr.onreadystatechange = empty + clearTimeout(abortTimeout) + var result, error = false + if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) { + dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type')) + result = xhr.responseText + + try { + // http://perfectionkills.com/global-eval-what-are-the-options/ + if (dataType == 'script') (1,eval)(result) + else if (dataType == 'xml') result = xhr.responseXML + else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result) + } catch (e) { error = e } + + if (error) ajaxError(error, 'parsererror', xhr, settings, deferred) + else ajaxSuccess(result, xhr, settings, deferred) + } else { + ajaxError(xhr.statusText || null, xhr.status ? 'error' : 'abort', xhr, settings, deferred) + } + } + } + + if (ajaxBeforeSend(xhr, settings) === false) { + xhr.abort() + ajaxError(null, 'abort', xhr, settings, deferred) + return xhr + } + + if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name] + + var async = 'async' in settings ? settings.async : true + xhr.open(settings.type, settings.url, async, settings.username, settings.password) + + for (name in headers) nativeSetHeader.apply(xhr, headers[name]) + + if (settings.timeout > 0) abortTimeout = setTimeout(function(){ + xhr.onreadystatechange = empty + xhr.abort() + ajaxError(null, 'timeout', xhr, settings, deferred) + }, settings.timeout) + + // avoid sending empty string (#319) + xhr.send(settings.data ? settings.data : null) + return xhr + } + + // handle optional data/success arguments + function parseArguments(url, data, success, dataType) { + if ($.isFunction(data)) dataType = success, success = data, data = undefined + if (!$.isFunction(success)) dataType = success, success = undefined + return { + url: url + , data: data + , success: success + , dataType: dataType + } + } + + $.get = function(/* url, data, success, dataType */){ + return $.ajax(parseArguments.apply(null, arguments)) + } + + $.post = function(/* url, data, success, dataType */){ + var options = parseArguments.apply(null, arguments) + options.type = 'POST' + return $.ajax(options) + } + + $.getJSON = function(/* url, data, success */){ + var options = parseArguments.apply(null, arguments) + options.dataType = 'json' + return $.ajax(options) + } + + $.fn.load = function(url, data, success){ + if (!this.length) return this + var self = this, parts = url.split(/\s/), selector, + options = parseArguments(url, data, success), + callback = options.success + if (parts.length > 1) options.url = parts[0], selector = parts[1] + options.success = function(response){ + self.html(selector ? + $('
                  ').html(response.replace(rscript, "")).find(selector) + : response) + callback && callback.apply(self, arguments) + } + $.ajax(options) + return this + } + + var escape = encodeURIComponent + + function serialize(params, obj, traditional, scope){ + var type, array = $.isArray(obj), hash = $.isPlainObject(obj) + $.each(obj, function(key, value) { + type = $.type(value) + if (scope) key = traditional ? scope : + scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']' + // handle data in serializeArray() format + if (!scope && array) params.add(value.name, value.value) + // recurse into nested objects + else if (type == "array" || (!traditional && type == "object")) + serialize(params, value, traditional, key) + else params.add(key, value) + }) + } + + $.param = function(obj, traditional){ + var params = [] + params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) } + serialize(params, obj, traditional) + return params.join('&').replace(/%20/g, '+') + } +})(Zepto) + +;(function($){ + $.fn.serializeArray = function() { + var result = [], el + $([].slice.call(this.get(0).elements)).each(function(){ + el = $(this) + var type = el.attr('type') + if (this.nodeName.toLowerCase() != 'fieldset' && + !this.disabled && type != 'submit' && type != 'reset' && type != 'button' && + ((type != 'radio' && type != 'checkbox') || this.checked)) + result.push({ + name: el.attr('name'), + value: el.val() + }) + }) + return result + } + + $.fn.serialize = function(){ + var result = [] + this.serializeArray().forEach(function(elm){ + result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value)) + }) + return result.join('&') + } + + $.fn.submit = function(callback) { + if (callback) this.bind('submit', callback) + else if (this.length) { + var event = $.Event('submit') + this.eq(0).trigger(event) + if (!event.isDefaultPrevented()) this.get(0).submit() + } + return this + } + +})(Zepto) + +;(function($){ + // __proto__ doesn't exist on IE<11, so redefine + // the Z function to use object extension instead + if (!('__proto__' in {})) { + $.extend($.zepto, { + Z: function(dom, selector){ + dom = dom || [] + $.extend(dom, $.fn) + dom.selector = selector || '' + dom.__Z = true + return dom + }, + // this is a kludge but works + isZ: function(object){ + return $.type(object) === 'array' && '__Z' in object + } + }) + } + + // getComputedStyle shouldn't freak out when called + // without a valid element as argument + try { + getComputedStyle(undefined) + } catch(e) { + var nativeGetComputedStyle = getComputedStyle; + window.getComputedStyle = function(element){ + try { + return nativeGetComputedStyle(element) + } catch(e) { + return null + } + } + } +})(Zepto) diff --git a/lang/en/enrol_pagseguro.php b/lang/en/enrol_pagseguro.php old mode 100644 new mode 100755 index 63019841f8..9fe2ce0e61 --- a/lang/en/enrol_pagseguro.php +++ b/lang/en/enrol_pagseguro.php @@ -65,5 +65,7 @@ $string['status'] = 'Allow PagSeguro enrolments'; $string['status_desc'] = 'Allow users to use PagSeguro to enrol into a course by default.'; $string['unenrolselfconfirm'] = 'Do you really want to unenrol yourself from course "{$a}"?'; +$string['transparentcheckout'] = 'Transparent Checkout'; +$string['usesandbox'] = 'Use Sandbox'; $string['usesandbox'] = 'Use sandbox'; $string['usesandboxdesc'] = 'Check this if you want to use a sandbox account (requests will be sent to sandbox.pagseguro.uol.com.br test site instead of the production site)'; diff --git a/lib.php b/lib.php old mode 100644 new mode 100755 index d5b00ff17f..3f1e21f2e6 --- a/lib.php +++ b/lib.php @@ -49,18 +49,41 @@ public function get_info_icons(array $instances) { return array(new pix_icon('icon', get_string('pluginname', 'enrol_pagseguro'), 'enrol_pagseguro')); } + /** + * Checks if there are any protected roles. + * + * @return boolean + */ public function roles_protected() { return false; } + /** + * Checks if there are any protected roles. + * + * @param stdClass $instance + * @return boolean + */ public function allow_unenrol(stdClass $instance) { return true; } + /** + * Checks if management is allowed. + * + * @param stdClass $instance + * @return boolean + */ public function allow_manage(stdClass $instance) { return true; } + /** + * Shows the self enrolment link. + * + * @param stdClass $instance + * @return boolean + */ public function show_enrolme_link(stdClass $instance) { return ($instance->status == ENROL_INSTANCE_ENABLED); } @@ -68,7 +91,8 @@ public function show_enrolme_link(stdClass $instance) { /** * Sets up navigation entries. * - * @param object $instance + * @param mixed $instancesnode + * @param stdClass $instance * @return void */ public function add_course_navigation($instancesnode, stdClass $instance) { @@ -180,7 +204,30 @@ public function enrol_page_hook(stdClass $instance) { '

                  ', get_string('needsignuporlogin', 'enrol_pagseguro'), '

                  ', '

                  ', get_string('loginsite'), '

                  ', '
                  '; + } else if ( $this->get_config('transparentcheckout') == 1 ) { + + $tcdata = array(); + $tcdata["requestPayment"] = get_string('paymentrequired', 'enrol_pagseguro', $instance); + $tcdata["instanceName"] = $this->get_instance_name($instance); + $tcdata["instanceId"] = $instance->courseid; + $tcdata["buttonString"] = get_string('sendpaymentbutton', 'enrol_pagseguro'); + $tcdata["cfgRoot"] = $CFG->wwwroot; + $tcdata["courseP"] = (float) $instance->cost; + $tcdata["getSessionUrl"] = new moodle_url('/enrol/pagseguro/tr_process.php'); + + if (get_config('enrol_pagseguro', 'usesandbox') == 1) { + $tcdata['js_url'] = + 'https://stc.sandbox.pagseguro.uol.com.br/pagseguro/api/v2/checkout/pagseguro.directpayment.js'; + } else { + $tcdata['js_url'] = 'https://stc.pagseguro.uol.com.br/pagseguro/api/v2/checkout/pagseguro.directpayment.js'; + } + + $output = $OUTPUT->render_from_template("enrol_pagseguro/transparentcheckout", $tcdata); + + return $output; + } else { + require_once("$CFG->dirroot/enrol/pagseguro/locallib.php"); // Sanitise some fields before building the pagseguro form. $coursefullname = format_string($course->fullname, true, array('context' => $context)); @@ -196,6 +243,7 @@ public function enrol_page_hook(stdClass $instance) { ob_start(); $form->display(); + echo $this->get_config('transparentcheckout'); $output = ob_get_clean(); return $OUTPUT->box($output); } diff --git a/locallib.php b/locallib.php old mode 100644 new mode 100755 index 7a60a08a90..20d9b6cb4b --- a/locallib.php +++ b/locallib.php @@ -26,8 +26,19 @@ require_once("$CFG->libdir/formslib.php"); +/** + * Pagseguro enrol plugin implementation. + * + * @copyright 2015 Daniel Neis + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ class enrol_pagseguro_enrol_form extends moodleform { + /** + * Creates edit form for single course enrolment settings. + * + * @return void + */ public function definition() { $mform = $this->_form; $mform = $this->_form; diff --git a/logs/translogs.txt b/logs/translogs.txt old mode 100644 new mode 100755 diff --git a/pix/icon.gif b/pix/icon.gif old mode 100644 new mode 100755 diff --git a/process.php b/process.php old mode 100644 new mode 100755 index 530743769d..a8a4824f32 --- a/process.php +++ b/process.php @@ -87,6 +87,14 @@ pagseguro_handle_old_notification_system($pagsegurowsbaseurl, $notificationcode, $email, $token); } +/** + * Handles the transaction xml sent from pagseguro + * + * @param string $transactionxml + * @param boolean $redirect + * + * @return void + */ function pagseguro_handle_transaction($transactionxml, $redirect = true) { global $CFG, $USER, $DB; @@ -313,6 +321,14 @@ function pagseguro_handle_transaction($transactionxml, $redirect = true) { redirect(new moodle_url('/enrol/pagseguro/return.php', array('id' => $data->courseid))); } +/** + * Sends an error message to admin, in case of error + * + * @param string $subject + * @param mixed $data + * + * @return void + */ function pagseguro_message_error_to_admin($subject, $data) { $admin = get_admin(); @@ -338,6 +354,20 @@ function pagseguro_message_error_to_admin($subject, $data) { message_send($eventdata); } +/** + * Handles checkout + * + * @param string $pagsegurowsbaseurl webservice base url + * @param string $pagsegurobaseurl base url + * @param string $email email of receiver in Pagseguro account + * @param string $token token of receiver in Pagseguro account + * @param string $courseid id of the course being bought + * @param stdClass $plugin pagseguro plugin + * @param stdClass $plugininstance the instance of the plugin in the course + * @param stdClass $course the course that is being bought + * + * @return void + */ function pagseguro_handle_checkout($pagsegurowsbaseurl, $pagsegurobaseurl, $email, $token, $courseid, $plugin, $plugininstance, $course) { @@ -398,6 +428,16 @@ function pagseguro_handle_checkout($pagsegurowsbaseurl, $pagsegurobaseurl, $emai header('Location: '. $pagsegurobaseurl . '/v2/checkout/payment.html?code='.$xml->code); } +/** + * Redirects user back to Moodle site in case of Unauthorized error + * + * @param string $pagsegurobaseurl base url + * @param string $transactionid + * @param string $email email of receiver in Pagseguro account + * @param string $token token of receiver in Pagseguro account + * + * @return void + */ function pagseguro_handle_redirect_back($pagsegurobaseurl, $transactionid, $email, $token) { $url = "{$pagsegurobaseurl}/v2/transactions/{$transactionid}?email={$email}&token={$token}"; @@ -415,6 +455,16 @@ function pagseguro_handle_redirect_back($pagsegurobaseurl, $transactionid, $emai } } +/** + * Handles the old notification system from pagseguro + * + * @param string $pagsegurobaseurl base url + * @param string $notificationcode + * @param string $email email of receiver in Pagseguro account + * @param string $token token of receiver in Pagseguro account + * + * @return void + */ function pagseguro_handle_old_notification_system($pagsegurobaseurl, $notificationcode, $email, $token) { $transactionsv2url = $pagsegurobaseurl .'/v2/transactions/notifications/'; diff --git a/return.php b/return.php old mode 100644 new mode 100755 diff --git a/settings.php b/settings.php old mode 100644 new mode 100755 index 40b8249275..7aea973878 --- a/settings.php +++ b/settings.php @@ -58,6 +58,18 @@ get_string('automaticenrolboleto_desc', 'enrol_pagseguro'), 0)); + $settings->add(new admin_setting_configcheckbox( + 'enrol_pagseguro/transparentcheckout', + get_string('transparentcheckout', 'enrol_pagseguro'), + '', + 0)); + + $settings->add(new admin_setting_configcheckbox( + 'enrol_pagseguro/usesandbox', + get_string('usesandbox', 'enrol_pagseguro'), + '', + 0)); + $settings->add(new admin_setting_heading('enrol_pagseguro_defaults', get_string('enrolinstancedefaults', 'admin'), get_string('enrolinstancedefaults_desc', 'admin'))); diff --git a/templates/checkout_form.mustache b/templates/checkout_form.mustache new file mode 100755 index 0000000000..6b414d475c --- /dev/null +++ b/templates/checkout_form.mustache @@ -0,0 +1,209 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + @template enrol_pagseguro/checkout_form + + The content to display when editing a tool. + + Classes required for JS: + * none + + Data attributes required for JS: + * none + + Context variables required for this template: + * rows An array of objects with label, hidelabel, text and id + + Example context (json): + { + "rows": [ + { + "label": "Tool URL", + "text": "http://example.com/", + "id": "toolurl", + "hidelabel": false + }, + { + "label": "Secret", + "text": "ABCDEF1234567890", + "id": "secret", + "hidelabel": true + } + ] + } +}} + + + + +
                  +
                  +
                  +
                  +
                  +
                  +
                  + +
                  + +
                  +
                  +
                  +
                  +
                  + +
                  + +
                  + +
                  + +
                  +
                  +
                  +
                  +
                  + + +
                  +
                  +
                  + + + +
                  +
                  +
                  +
                  + +
                  + +
                  + +
                  + +
                  +
                  +
                  + +
                  + + +
                  +
                  +
                  +
                  + +
                  + +
                  + +
                  + +
                  +
                  +
                  +
                  + +
                  + +
                  + +
                  +
                  +
                  + +
                  + +
                  + +
                  + +
                  +
                  +
                  +
                  +
                  + +
                  + +
                  + +
                  + +
                  +
                  +
                  +
                  + Pagar +
                  + + + + + +
                  + +
                  +
                  +
                  +
                  +
                  +
                  +
                  + + +
                  +
                  +
                  + +
                  + +
                  +
                  +
                  +
                  +
                  + +
                  + +
                  + +
                  + +
                  +
                  +
                  +
                  + +
                  + + + +
                  +
                  +
                  diff --git a/templates/transparentcheckout.mustache b/templates/transparentcheckout.mustache new file mode 100755 index 0000000000..836b28949a --- /dev/null +++ b/templates/transparentcheckout.mustache @@ -0,0 +1,83 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + @template enrol_pagseguro/transparentcheckout + + The content to display when editing a tool. + + Classes required for JS: + * none + + Data attributes required for JS: + * none + + Context variables required for this template: + * rows An array of objects with label, hidelabel, text and id + + Example context (json): + { + "rows": [ + { + "label": "Tool URL", + "text": "http://example.com/", + "id": "toolurl", + "hidelabel": false + }, + { + "label": "Secret", + "text": "ABCDEF1234567890", + "id": "secret", + "hidelabel": true + } + ] + } +}} + +
                  +

                  {{requestPayment}}

                  +


                  + +


                  + + +
                  + + + + diff --git a/tests/behat/enrol_pagseguro.feature b/tests/behat/enrol_pagseguro.feature old mode 100644 new mode 100755 diff --git a/thirdpartylibs.xml b/thirdpartylibs.xml new file mode 100644 index 0000000000..f421f0ae30 --- /dev/null +++ b/thirdpartylibs.xml @@ -0,0 +1,9 @@ + + + + vendor/jquery-mask + jquery-mask + v1.14.16 + MIT + + diff --git a/tr_process.php b/tr_process.php new file mode 100755 index 0000000000..462f1f3df7 --- /dev/null +++ b/tr_process.php @@ -0,0 +1,565 @@ +. + +/** + * Listens for Instant Payment Notification from pagseguro + * + * This script waits for Payment notification from pagseguro, + * then double checks that data by sending it back to pagseguro. + * If pagseguro verifies this then it sets up the enrolment for that + * user. + * + * @package enrol_pagseguro + * @copyright 2010 Eugene Venter + * @copyright 2015 Daniel Neis Araujo + * @author Eugene Venter - based on code by others + * @author Daniel Neis Araujo based on code by Eugene Venter and others + * @author Igor Agatti Lima based on code by Eugene Venter, Daniel Neis Araujo and others + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +// @codingStandardsIgnoreLine +require('../../config.php'); +require_once("lib.php"); +require_once($CFG->libdir.'/enrollib.php'); + +header("access-control-allow-origin: https://sandbox.pagseguro.uol.com.br"); + +define('COMMERCE_PAGSEGURO_STATUS_AWAITING', 1); +define('COMMERCE_PAGSEGURO_STATUS_IN_ANALYSIS', 2); +define('COMMERCE_PAGSEGURO_STATUS_PAID', 3); +define('COMMERCE_PAGSEGURO_STATUS_AVAILABLE', 4); +define('COMMERCE_PAGSEGURO_STATUS_DISPUTED', 5); +define('COMMERCE_PAGSEGURO_STATUS_REFUNDED', 6); +define('COMMERCE_PAGSEGURO_STATUS_CANCELED', 7); +define('COMMERCE_PAGSEGURO_STATUS_DEBITED', 8); // Valor devolvido para o comprador. +define('COMMERCE_PAGSEGURO_STATUS_WITHHELD', 9); // Retenção temporária. +define('COMMERCE_PAYMENT_STATUS_SUCCESS', 'success'); +define('COMMERCE_PAYMENT_STATUS_FAILURE', 'failure'); +define('COMMERCE_PAYMENT_STATUS_PENDING', 'pending'); + +$plugin = enrol_get_plugin('pagseguro'); +$email = $plugin->get_config('pagsegurobusiness'); +$token = $plugin->get_config('pagsegurotoken'); + +if (get_config('enrol_pagseguro', 'usesandbox') == 1) { + $baseurl = 'https://ws.sandbox.pagseguro.uol.com.br'; +} else { + $baseurl = 'https://ws.pagseguro.uol.com.br'; +} + +$notificationcode = optional_param('notificationCode', '', PARAM_RAW); +$notificationtype = optional_param('notificationType', '', PARAM_RAW); + +$paymentmethod = optional_param('pay_method', '', PARAM_RAW); + +if ($paymentmethod == 'cc') { + + // Build array with all parameters from the form. + $params = []; + + $courseid = optional_param('courseid', '0', PARAM_INT); + $plugininstance = $DB->get_record('enrol', array('courseid' => $courseid, 'enrol' => 'pagseguro')); + $wholephone = optional_param('senderphonenumber', '', PARAM_RAW); + $instval = optional_param('inst_val', '', PARAM_RAW); + + $params['courseid'] = $courseid; + $params['instanceid'] = $plugininstance->id; + + // Continue building array of parameters from the form. + $params['name'] = optional_param('ccholdername', '', PARAM_RAW); + $params['email'] = optional_param('senderemail', '', PARAM_RAW); + $params['phone_area'] = substr($wholephone, 1, 2); + $params['phone_number'] = trim(preg_replace("(\D)", "", substr($wholephone, 5))); + $params['doc_number'] = preg_replace("(\D)", "", optional_param('sendercpfcnpj', '', PARAM_RAW)); + $params['doc_type'] = strlen($params['doc_number']) == 14 ? 'CNPJ' : 'CPF'; + $params['currency'] = 'BRL'; + $params['notification_url'] = new moodle_url('/enrol/pagseguro/tr_process.php'); + $params['item_desc'] = empty($course->fullname) ? 'Curso moodle' : mb_substr($course->fullname, 0, 100); + $params['item_amount'] = number_format($plugininstance->cost, 2); + $params['item_amount'] = str_replace(',', '', $params['item_amount']); + $params['item_qty'] = 1; + $params['cc_token'] = optional_param('cc_token', '', PARAM_RAW); + $params['cc_installment_quantity'] = optional_param('ccinstallments', '', PARAM_RAW); + $params['cc_installment_value'] = number_format($instval, 2); + $params['address_street'] = optional_param('billingstreet', '', PARAM_RAW); + $params['address_number'] = optional_param('billingnumber', '', PARAM_RAW); + $params['address_complement'] = optional_param('billingcomplement', '', PARAM_RAW); + $params['address_district'] = optional_param('billingdistrict', '', PARAM_RAW); + $params['address_city'] = optional_param('billingcity', '', PARAM_RAW); + $params['address_state'] = optional_param('billingstate', '', PARAM_RAW); + $params['address_country'] = 'BRA'; + $params['address_postcode'] = optional_param('billingpostcode', '', PARAM_RAW); + + $params['payment_status'] = COMMERCE_PAYMENT_STATUS_PENDING; + + // Handle Credit Card Checkout. + pagseguro_transparent_cc_checkout($params, $email, $token, $baseurl); +} + +if ($paymentmethod == 'boleto') { + + $courseid = optional_param('courseid', '0', PARAM_INT); + $plugininstance = $DB->get_record('enrol', array('courseid' => $courseid, 'enrol' => 'pagseguro')); + + $wholephone = optional_param('senderphonenumber', '', PARAM_RAW); + + $params = []; + $params['courseid'] = $courseid; + $params['instanceid'] = $plugininstance->id; + + $params['name'] = optional_param('sendername', '', PARAM_RAW); + $params['email'] = optional_param('senderemail', '', PARAM_RAW); + $params['phone_area'] = substr($wholephone, 1, 2); + $params['phone_number'] = trim(preg_replace("(\D)", "", substr($wholephone, 5))); + $params['doc_number'] = preg_replace("(\D)", "", optional_param('sendercpfcnpj', '', PARAM_RAW)); + $params['doc_type'] = strlen($params['doc_number']) == 14 ? 'CNPJ' : 'CPF'; + $params['currency'] = 'BRL'; + $params['notification_url'] = new moodle_url('/enrol/pagseguro/tr_process.php'); + $params['item_desc'] = empty($course->fullname) ? 'Curso moodle' : mb_substr($course->fullname, 0, 100); + $params['item_amount'] = number_format($plugininstance->cost, 2); + $params['item_amount'] = str_replace(',', '', $params['item_amount']); + $params['item_qty'] = 1; + $params['sender_hash'] = optional_param('sender_hash', '', PARAM_RAW); + $params['plugininstance'] = $plugininstance; + + pagseguro_transparent_boletocheckout($params, $email, $token, $baseurl); +} + +if (!empty($notificationcode) && $notificationtype == 'transaction') { + pagseguro_transparent_notificationrequest($notificationcode, $email, $token, $baseurl); +} + +/** + * Controller function of the credit card checkout + * + * @param array $params array of information about the order, gathered from the form + * @param string $email Pagseguro seller email + * @param string $token Pagseguro seller token + * @param string $baseurl defines if uses sandbox or production environment + * + * @return void + */ +function pagseguro_transparent_cc_checkout($params, $email, $token, $baseurl) { + + // First we insert the order into the database, so the customer's info isn't lost. + $refid = pagseguro_transparent_insertorder($params, $email, $token); + $params['reference'] = $refid; + + $reqxml = pagseguro_transparent_ccxml($params); + + $url = $baseurl."/v2/transactions?email={$email}&token={$token}"; + + $data = pagseguro_transparent_sendpaymentdetails($reqxml, $url); + + if ($data == 'Unauthorized') { + $params['payment_status'] = COMMERCE_PAYMENT_STATUS_FAILURE; + pagseguro_transparent_updateorder($params, $email, $token); + redirect(new moodle_url('/enrol/pagseguro/return.php', array('id' => $params['courseid'], 'error' => 'unauthorized'))); + } + + if (count($data->error) > 0) { + $params['payment_status'] = COMMERCE_PAYMENT_STATUS_FAILURE; + pagseguro_transparent_updateorder($params, $email, $token); + redirect(new moodle_url('/enrol/pagseguro/return.php', array('id' => $params['courseid'], 'error' => 'generic'))); + } + + $transactionresponse = simplexml_load_string($data); + + pagseguro_transparent_handletransactionresponse($transactionresponse); + + redirect(new moodle_url('/enrol/pagseguro/return.php', array('id' => $params['courseid'] ))); +} + +/** + * Controller function of the boleto checkout + * + * @param array $params array of information about the order, gathered from the form + * @param string $email Pagseguro seller email + * @param string $token Pagseguro seller token + * @param string $baseurl defines if uses sandbox or production environment + * + * @return void + */ +function pagseguro_transparent_boletocheckout($params, $email, $token, $baseurl) { + + // First we insert the order into the database, so the customer's info isn't lost. + $refid = pagseguro_transparent_insertorder($params, $email, $token); + $params['reference'] = $refid; + + $reqxml = pagseguro_transparent_boletoxml($params); + + $url = $baseurl."/v2/transactions?email={$email}&token={$token}"; + + $data = pagseguro_transparent_sendpaymentdetails($reqxml, $url); + + if ($data == 'Unauthorized') { + $params['payment_status'] = COMMERCE_PAYMENT_STATUS_FAILURE; + pagseguro_transparent_updateorder($params, $email, $token); + redirect(new moodle_url('/enrol/pagseguro/return.php', array('id' => $params['courseid'], 'error' => 'unauthorized'))); + } + + if (count($data->error) > 0) { + $params['payment_status'] = COMMERCE_PAYMENT_STATUS_FAILURE; + pagseguro_transparent_updateorder($params, $email, $token); + redirect(new moodle_url('/enrol/pagseguro/return.php', array('id' => $params['courseid'], 'error' => 'generic'))); + } + + $transactionresponse = simplexml_load_string($data); + + pagseguro_transparent_handletransactionresponse($transactionresponse); + + redirect(new moodle_url('/enrol/pagseguro/return.php', array('id' => $params['courseid'] ))); + +} + +/** + * Controller function of the notification receiver + * + * @param string $notificationcode the notification code sent by Pagseguro + * @param string $email Pagseguro seller email + * @param string $token Pagseguro seller token + * @param string $baseurl defines if uses sandbox or production environment + * + * @return void + */ +function pagseguro_transparent_notificationrequest($notificationcode, $email, $token, $baseurl) { + + $url = $baseurl."/v3/transactions/notifications/{$notificationcode}?email={$email}&token={$token}"; + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/x-www-form-urlencoded; charset=ISO-8859-1")); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $data = curl_exec($ch); + curl_close($ch); + + $transaction = simplexml_load_string($data); + + $rec = pagseguro_transparent_handletransactionresponse($transaction); + + pagseguro_transparent_handleenrolment($rec); + +} + +/** + * Sends payment details with an XML string to a URL using the curl request system. + * + * @param string $xml the XML file to be sent to URL + * @param string $url + * + * @return mixed $data the response from the curl request + */ +function pagseguro_transparent_sendpaymentdetails($xml, $url) { + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/xml; charset=ISO-8859-1")); + curl_setopt($ch, CURLOPT_POST, 1); + + curl_setopt($ch, CURLOPT_POSTFIELDS, $xml ); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + + $data = curl_exec($ch); + curl_close($ch); + + return $data; + +} + +/** + * Inserts preliminary order information into enrol_pagseguro table. + * + * @param array $params information about the order, gathered from the form + * @param string $email Pagseguro seller email + * @param string $token Pagseguro seller token + * + * @return string ID of the record inserted + */ +function pagseguro_transparent_insertorder($params, $email, $token) { + global $USER, $DB; + + $rec = new stdClass(); + $rec->pagseguro_token = $token; + $rec->pagseguro_email = $email; + $rec->courseid = $params['courseid']; + $rec->userid = $USER->id; + $rec->instanceid = $params['instanceid']; + $rec->date = date("Y-m-d"); + $rec->payment_status = COMMERCE_PAYMENT_STATUS_PENDING; + + return $DB->insert_record("enrol_pagseguro", $rec); + +} + +/** + * Updates the order information in enrol_pagseguro table. + * + * @param array $params information about the order, gathered from the form or pagseguro notification + * @param string $email Pagseguro seller email + * @param string $token Pagseguro seller token + * + * @return void + */ +function pagseguro_transparent_updateorder($params, $email, $token) { + global $USER, $DB; + + $rec = new stdClass(); + $rec->id = $params['reference']; + $rec->pagseguro_token = $token; + $rec->pagseguro_email = $email; + $rec->courseid = $params['courseid']; + $rec->userid = $USER->id; + $rec->instanceid = $params['instanceid']; + $rec->date = date("Y-m-d"); + $rec->payment_status = $params['payment_status']; + + $DB->update_record("enrol_pagseguro", $rec); + +} + +/** + * Receives transaction data and updates the database. + * + * @param stdClass $data + * + * @return string $id the record id of the updated record in the database + */ +function pagseguro_transparent_handletransactionresponse($data) { + + global $DB; + + $rec = new stdClass(); + $rec->id = $data->reference->__toString(); + $rec->code = $data->code->__toString(); + $rec->type = $data->type->__toString(); + $rec->status = intval($data->status->__toString()); + $rec->paymentmethod_type = $data->paymentMethod->type->__toString(); + $rec->paymentmethod_code = $data->paymentMethod->code->__toString(); + $rec->grossamount = number_format($data->grossAmount->__toString(), 2); + $rec->discountedamount = $data->discountAmount->__toString(); + + switch($rec->status){ + case COMMERCE_PAGSEGURO_STATUS_AWAITING: + case COMMERCE_PAGSEGURO_STATUS_IN_ANALYSIS: + $rec->payment_status = COMMERCE_PAYMENT_STATUS_PENDING; + break; + case COMMERCE_PAGSEGURO_STATUS_PAID: + case COMMERCE_PAGSEGURO_STATUS_AVAILABLE: + $rec->payment_status = COMMERCE_PAYMENT_STATUS_SUCCESS; + break; + case COMMERCE_PAGSEGURO_STATUS_DISPUTED: + case COMMERCE_PAGSEGURO_STATUS_REFUNDED: + case COMMERCE_PAGSEGURO_STATUS_CANCELED: + case COMMERCE_PAGSEGURO_STATUS_DEBITED: + case COMMERCE_PAGSEGURO_STATUS_WITHHELD: + $rec->payment_status = COMMERCE_PAYMENT_STATUS_FAILURE; + break; + + } + + $DB->update_record("enrol_pagseguro", $rec); + + $record = $DB->get_record("enrol_pagseguro", ['id' => $rec->id]); + if ($record->payment_status == COMMERCE_PAYMENT_STATUS_SUCCESS) { + enrol_pagseguro_coursepaidevent($record); + } + + return $record; + +} + +/** + * Triggers payment received event. + * + * @param stdClass $rec (the record in the database for which the payment was received) + * + * @return void + */ +function enrol_pagseguro_coursepaidevent($rec) { + + $context = context_course::instance($rec->courseid); + + $data = (array) $rec; + + $param = array( + 'context' => $context, + 'other' => $data, + ); + + $event = \enrol_pagseguro\event\payment_receive::create($param); + $event->trigger(); +} + + +/** + * Enrols or unenrols user depending on the database record. + * + * @param stdClass $rec the record in the database + * + * @return void + */ +function pagseguro_transparent_handleenrolment($rec) { + global $DB; + + $plugin = enrol_get_plugin('pagseguro'); + $plugininstance = $DB->get_record('enrol', array('courseid' => $rec->courseid, 'enrol' => 'pagseguro')); + + if ($plugininstance->enrolperiod) { + $timestart = time(); + $timeend = $timestart + $plugininstance->enrolperiod; + } else { + $timestart = 0; + $timeend = 0; + } + + switch ($rec->payment_status) { + case COMMERCE_PAYMENT_STATUS_SUCCESS: + $plugin->enrol_user($plugininstance, $rec->userid, $plugininstance->roleid, $timestart, $timeend); + break; + case COMMERCE_PAYMENT_STATUS_FAILURE: + $plugin->unenrol_user($plugininstance, $rec->userid); + break; + } + +} + +/** + * Builds the xml to send bank ticket request to pagseguro + * + * @param array $params fields from the form and plugin settings. + * + * @return string of data in xml format + */ +function pagseguro_transparent_boletoxml($params) { + return " + + default + boleto + + ".$params['name']." + ".$params['email']." + + ".$params['phone_area']." + ".$params['phone_number']." + + + + ".$params['doc_type']." + ".$params['doc_number']." + + + ".$params['sender_hash']." + + ".$params['currency']." + ".$params['notification_url']." + + + ".$params['courseid']." + ".$params['item_desc']." + ".$params['item_amount']." + ".$params['item_qty']." + + + 0.00 + ".$params['reference']." + + false + + "; +} + +/** + * Builds the xml to send credit card request to pagseguro + * + * @param array $params fields from the form and plugin settings. + * + * @return string of data in xml format + */ +function pagseguro_transparent_ccxml($params) { + return " + + default + creditCard + + ".$params['name']." + ".$params['email']." + + ".$params['phone_area']." + ".$params['phone_number']." + + + + ".$params['doc_type']." + ".$params['doc_number']." + + + + ".$params['currency']." + ".$params['notification_url']." + + + ".$params['courseid']." + ".$params['item_desc']." + ".$params['item_amount']." + ".$params['item_qty']." + + + 0.00 + ".$params['reference']." + + false + + + ".$params['cc_token']." + + ".$params['cc_installment_quantity']." + ".$params['cc_installment_value']." + + + ".$params['name']." + + + ".$params['doc_type']." + ".$params['doc_number']." + + + ".$params['birthday']." + + ".$params['phone_area']." + ".$params['phone_number']." + + + + ".$params['address_street']." + ".$params['address_number']." + ".$params['address_complement']." + ".$params['address_district']." + ".$params['address_city']." + ".$params['address_state']." + ".$params['address_country']." + ".$params['address_postcode']." + + + "; +} + + diff --git a/unenrolself.php b/unenrolself.php old mode 100644 new mode 100755 diff --git a/vendor/jquery-mask/.gitignore b/vendor/jquery-mask/.gitignore new file mode 100755 index 0000000000..061d2ba9be --- /dev/null +++ b/vendor/jquery-mask/.gitignore @@ -0,0 +1,9 @@ +index.html +css/* +img/* +js/* +node_modules/ +bower_components/ +.sparkleshare +libpeerconnection.log +.versions diff --git a/vendor/jquery-mask/.jshintrc b/vendor/jquery-mask/.jshintrc new file mode 100755 index 0000000000..79f07e041f --- /dev/null +++ b/vendor/jquery-mask/.jshintrc @@ -0,0 +1,34 @@ +{ + "bitwise": true, + "browser": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "esnext": true, + "expr": true, + "globals": { + "console": false, + "define": false, + "document": false, + "expect": false, + "module": false, + "require": false, + "window": false + }, + "immed": true, + "indent": 4, + "latedef": false, + "maxcomplexity": 15, + "newcap": true, + "noarg": true, + "node": true, + "noempty": true, + "nonstandard": true, + "quotmark": "single", + "regexp": true, + "smarttabs": true, + "strict": false, + "trailing": true, + "undef": true, + "unused": true +} diff --git a/vendor/jquery-mask/.ruby-version b/vendor/jquery-mask/.ruby-version new file mode 100755 index 0000000000..600bcfd1ae --- /dev/null +++ b/vendor/jquery-mask/.ruby-version @@ -0,0 +1 @@ +2.0.0p598 diff --git a/vendor/jquery-mask/.travis.yml b/vendor/jquery-mask/.travis.yml new file mode 100755 index 0000000000..c6ea430daa --- /dev/null +++ b/vendor/jquery-mask/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: + - "8.9.3" +before_script: + - npm install -g grunt-cli + - npm install +script: grunt test diff --git a/vendor/jquery-mask/CHANGELOG.md b/vendor/jquery-mask/CHANGELOG.md new file mode 100755 index 0000000000..a1d00616b2 --- /dev/null +++ b/vendor/jquery-mask/CHANGELOG.md @@ -0,0 +1,921 @@ +== v1.14.16 (Jul/31 2019 16:32 +0100 by Igor Escobar) == + +Bugfixes: + +* Fixed oldVal being updated prior to caret position calculation +* Solve loading JQuery as module on Meteor + +== v1.14.15 (Mar/08 2018 22:59 +0000 by Igor Escobar) == + +Bugfixes: + +* rolling back change to fix caret positioning. it didn’t worked on some devices + +== v1.14.14 (Mar/02 2018 16:55 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing mask positioning delays +* unmask: also removing place holder if added on the first place. +* unmask: unsetting maxlength if we set it in the first place + +== v1.14.13 (Dec/11 2017 18:59 +0000 by Igor Escobar) == + +Bugfixes: + +* fixes caret issue explained on #636 +* fixing use strict issue + +== v1.14.12 (Oct/04 2017 09:57 +0100 by Igor Escobar) == + +Bugfixes: + +* bug fixing on caret positioning on some devices + +== v1.14.11 (May/30 2017 21:53 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing a lot of caret positioning issues. Thanks to @onuradsay + +== v1.14.10 (Feb/13 2017 14:18 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing exception when oValue in undefined + +== v1.14.9 (Jan/25 2017 11:17 +0000 by Igor Escobar) == + +Bugfixes: + +* don’t use input event when using samsung browser or old chrome versions + +== v1.14.8 (Dec/26 2016 13:18 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing caret on android with chrome 28 + +== v1.14.7 (Dec/25 2016 03:51 +0000 by Igor Escobar) == + +Bugfixes: + +* improving caret positioning when cursor is on the middle + +== v1.14.6 (Dec/24 2016 17:14 +0000 by Igor Escobar) == + +Bugfixes: + +* fix caret positioning with multiple mask chars + +== v1.14.5 (Dec/24 2016 14:42 +0000 by Igor Escobar) == + +Changes: + +* fixing reserved word + +== v1.14.4 (Dec/24 2016 14:38 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing android cursor positioning (special thanks to @felipejunges and @fernandobandeira) + +== v1.14.3 (Nov/28 2016 11:53 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing caret positioning on safari + +== v1.14.2 (Nov/27 2016 20:04 +0000 by Igor Escobar) == + +Bugfixes: + +* apply auto maxlength in case the mask doesn't have recursive pattern + +== v1.14.1 (Nov/27 2016 19:20 +0000 by Igor Escobar) == + +Bugfixes: + +* Fix input value mangling when inserting before a static mask character +* fixing caret position issue + +== v1.14.0 (Apr/03 2016 17:52 +0100 by Igor Escobar) == + +Bugfixes: + +* Fix cursor jumping while editing in non-IE browsers. Thanks to @archwyrm + +Features: + +* adding masked function for better angular use + +== v1.13.9 (Mar/20 2016 16:17 +0000 by Igor Escobar) == + +Changes: + +* giving the opportunity to pass watchInputs locally + +== v1.13.8 (Mar/06 2016 23:25 +0000 by Igor Escobar) == + +Changes: + +* adding support for meteor + +== v1.13.7 (Mar/06 2016 22:46 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing onChange behaviour + +== v1.13.6 (Mar/06 2016 22:14 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing deploy procedure + +== v1.13.5 (Mar/06 2016 22:01 +0000 by Igor Escobar) == + +Changes: + +* adding clearIfNotMatch to globalOptions + +Bugfixes: + +* fixing some bugs when using non-input elements +* fixing mobile issues at #348. +* using input event when supported + +== v1.13.4 (Aug/07 2015 14:21 +0100 by Igor Escobar) == + +Bugfixes: + +* Add check to ensure that there are input elements before using them + +== v1.13.3 (Jul/16 2015 16:11 +0100 by Igor Escobar) == + +Changes: + +* adding main property to package.json + +== v1.13.2 (Jul/16 2015 16:06 +0100 by Igor Escobar) == + +Bugfixes: + +* change event wasnt being triggered in some cases + +== v1.13.1 (Jul/07 2015 15:38 +0100 by Igor Escobar) == + +Bugfixes: + +* destroying input event too + +== v1.13.0 (Jul/07 2015 15:26 +0100 by Igor Escobar) == + +Changes: + +* removing the autocomplete default. + +Bugfixes: + +* fixing bower file thanks to @lazyants + +Features: + +* prevent glitch when invalid chars. +* turning off autocomplete when browsers doesn't support oninput event. + +== v1.12.0 (Jul/07 2015 11:37 +0100 by Igor Escobar) == + +Features: + +* giving an alternative to the autocomplete/autofill problem. + +== v1.11.4 (Feb/26 2015 22:11 +0000 by Igor Escobar) == + +Changes: + +* grunt, jshint and better applyDataMask. Thanks to @lagden +* automated deploy to npm + +== v1.11.3 (Jan/28 2015 15:41 +0000 by Igor Escobar) == + +Changes: + +* Added commonjs module definition + +== v1.11.2 (Dec/26 2014 15:36 +0000 by Igor Escobar) == + +Bugfixes: + +* unreachable code + +== v1.11.1 (Dec/26 2014 15:34 +0000 by Igor Escobar) == + +Bugfixes: + +* unreachable code + +== v1.11.0 (Dec/26 2014 15:33 +0000 by Igor Escobar) == + +Features: + +* implementing selectOnFocus and data-mask-selectonfocus option +* adding public method called: .applyDataMask in case you want to decide whether to apply masks in data-mask fields + +== v1.10.13 (Nov/19 2014 16:06 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing bug with watchInputs feature when mask is used as a function and not a string. + +== v1.10.12 (Nov/06 2014 13:08 +0000 by Igor Escobar) == + +Changes: + +* making a few improvements to make selection, copy events easier + +== v1.10.11 (Nov/06 2014 11:26 +0000 by Igor Escobar) == + +Bugfixes: + +* we need to revaluate dataMask flags everytime + +== v1.10.10 (Nov/06 2014 10:41 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing dynamically data-mask added elements + +== v1.10.9 (Nov/05 2014 10:52 +0000 by Igor Escobar) == + +Bugfixes: + +* data-mask wasnt working + +== v1.10.8 (Nov/01 2014 13:49 +0000 by Igor Escobar) == + +Changes: + +* we dont need to seek for data-mask every time + +== v1.10.7 (Nov/01 2014 13:18 +0000 by Igor Escobar) == + +Changes: + +* little optimization + +== v1.10.6 (Oct/28 2014 13:59 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing weird cursor problems in weird cases. +* dynamically added inputs wasnt working + +== v1.10.5 (Oct/23 2014 11:41 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing weird cursor problems in weird cases. + +== v1.10.4 (Oct/23 2014 11:02 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing on the fly mask change feature. + +== v1.10.3 (Oct/22 2014 09:50 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing unmask method. + +== v1.10.2 (Oct/20 2014 16:38 +0100 by Igor Escobar) == + +Bugfixes: + +* onChange event fired at the wrong time when the field already has a value. + +== v1.10.1 (Oct/20 2014 16:08 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing onChange event behaviour + +== v1.10.0 (Oct/20 2014 10:56 +0100 by Igor Escobar) == + +Features: + +* adding a way to change global settings like translation object and the byPassKeys object. + +== v1.9.2 (Oct/20 2014 10:08 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing fallback digits implementation. Thanks @A1rPun + +== v1.9.1 (Oct/18 2014 12:27 +0100 by Igor Escobar) == + +Bugfixes: + +* cant convert circular json exception + +== v1.9.0 (Oct/18 2014 12:07 +0100 by Igor Escobar) == + +Features: + +* adding onInvalid callback + +== v1.8.0 (Oct/17 2014 11:35 +0100 by Igor Escobar) == + +Changes: + +* removing automatic maxlength support +* making a few optimizations to make it faster and retro compatible with other libraries +* creating globalOptions to make it more fast and flexible + +Bugfixes: + +* fixing issue #196 + +Features: + +* adding the fallback translation option + +== v1.7.8 (Oct/15 2014 10:55 +0100 by Igor Escobar) == + +Bugfixes: + +* change event may experience issues +* avoid maximum call stack trace error + +== v1.7.7 (Sep/10 2014 22:31 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing clojure compile issue + +== v1.7.6 (Sep/10 2014 22:14 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing clearifnotmatch in masks with literal digits + +== v1.7.5 (Sep/09 2014 15:43 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing paste inside of empty fields. + +== v1.7.4 (Aug/11 2014 14:53 +0100 by Igor Escobar) == + +Changes: + +* smaller and reliable code + +== v1.7.3 (Aug/11 2014 11:28 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing issue #185 + +== v1.7.2 (Aug/08 2014 11:11 +0100 by Igor Escobar) == + +Changes: + +* smaller code + +Bugfixes: + +* fixing remove bug + +== v1.7.1 (Aug/08 2014 00:55 +0100 by Igor Escobar) == + +Changes: + +* upgrading zepto, smaller syntax and fixing build + +== v1.7.0 (Aug/07 2014 23:56 +0100 by Igor Escobar) == + +Features: + +* applying masks to dynamically added elements. (html/javascript notation) + +== v1.6.5 (Jun/30 2014 10:24 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing clearIfNotMatch feature in cases of optional and recursive digits + +== v1.6.4 (May/08 2014 23:54 +0100 by Igor Escobar) == + +Changes: + +* testing some deployment stunts + +== v1.6.3 (May/08 2014 23:51 +0100 by Igor Escobar) == + +Changes: + +* testing some deployment stunts + +== v1.6.2 (May/08 2014 23:45 +0100 by Igor Escobar) == + +Bugfixes: + +* fuckin typo + +== v1.6.1 (May/08 2014 23:39 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing autofocus bug + +== v1.6.0 (May/07 2014 21:13 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing autofocus bug + +Features: + +* adding support to the clearIfNotMatch option +* HTML5 placeholder support + +== v1.5.7 (May/01 2014 18:37 +0100 by Igor Escobar) == + +Changes: + +* some cleanup and stuff + +== v1.5.6 (May/01 2014 18:30 +0100 by Igor Escobar) == + +Bugfixes: + +* Bug in calculating difference between mask characters between old and new field values +* Fix stack limit exceeded + +== v1.5.5 (Apr/27 2014 13:47 +0100 by Igor Escobar) == + +Changes: + +* UMD (Universal Module Definition) patterns for JavaScript modules + +Bugfixes: + +* caret position correction +* 114 - Fix onChange Event error + +== v1.5.4 (Feb/09 2014 12:02 +0000 by Igor Escobar) == + +Changes: + +* optmizing code + +== v1.5.3 (Feb/08 2014 14:59 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing ctrl a bug + +== v1.5.2 (Dec/20 2013 16:35 +0000 by Igor Escobar) == + +Changes: + +* smaller source code + +== v1.5.1 (Dec/18 2013 22:34 +0000 by Igor Escobar) == + +Changes: + +* fixing some code climate problems + +== v1.5.0 (Dec/18 2013 22:10 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing getCleanVal() + +Features: + +* new public method called cleanVal + +== v1.4.2 (Dec/16 2013 15:48 +0000 by Igor Escobar) == + +Bugfixes: + +* Dirty fix for masks not completing with a literal + +== v1.4.1 (Dec/09 2013 21:23 +0000 by Igor Escobar) == + +Changes: + +* revising ignored keys + +== v1.4.0 (Nov/28 2013 18:06 +0000 by Igor Escobar) == + +Features: + +* caret positioning implementation + +== v1.3.1 (Oct/08 2013 20:38 +0100 by Igor Escobar) == + +Changes: + +* adding more keys to ignore list to make the char navigation smoothly + +Bugfixes: + +* Sounds like 'options' has disappeared for some reason + +== v1.3.0 (Sep/13 2013 10:37 +0100 by Igor Escobar) == + +Features: + +* creating the maxlength option + +== v1.2.0 (Sep/07 2013 12:07 +0100 by Igor Escobar) == + +Features: + +* adding the possibility to put recursive digits inside masks + +== v1.1.3 (Sep/04 2013 21:21 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing late masking + +== v1.1.2 (Aug/26 2013 15:08 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing mask on div,span etc + +== v1.1.1 (Aug/26 2013 14:42 +0100 by Igor Escobar) == + +Bugfixes: + +* better callback handling + +== v1.1.0 (Aug/24 2013 15:59 +0100 by Igor Escobar) == + +Features: + +* adding onchange support + +== v1.0.3 (Aug/23 2013 23:10 +0100 by Igor Escobar) == + +Changes: + +* optimizations to mask on non html fields + +== v1.0.2 (Aug/23 2013 22:46 +0100 by Igor Escobar) == + +Bugfixes: + +* adding remask method do improve callback performance + +== v1.0.1 (Aug/23 2013 22:01 +0100 by Igor Escobar) == + +Changes: + +* normal releases again + +== v1.0.0 (Aug/23 2013 21:59 +0100 by Igor Escobar) == + +Features: + +* huge refactoring focusing no reduce source code weight and bugfixing + +== v0.11.5 (Aug/20 2013 17:11 +0100 by Igor Escobar) == + +Bugfixes: + +* bug fixing when mask range is bigger than 2 digits. + +== v0.11.4 (Aug/19 2013 10:24 +0100 by Igor Escobar) == + +Changes: + +* adding de delete key to byPassKeys + +== v0.11.3 (Aug/18 2013 00:48 +0100 by Igor Escobar) == + +Bugfixes: + +* fixing zepto compatibily + +== v0.11.2 (Aug/17 2013 18:39 +0100 by Igor Escobar) == + +Bugfixes: + +* jmask iterate all items + +== v0.11.1 (Aug/17 2013 18:32 +0100 by Igor Escobar) == + +Changes: + +* a little bit smaller source code + +== v0.11.0 (Aug/16 2013 21:27 +0100 by Igor Escobar) == + +Bugfixes: + +* Altered "ignored keys" hook to run events (i.e. onKeyPress) afterwards. Otherwise, we miss key triggered events when the user deletes the entire text box, etc. + +Features: + +* adding support to method getCleanVal + +== v0.10.1 (Jul/26 2013 09:35 +0100 by ) == + + + +== v0.10.0 (Jul/19 2013 23:07 +0100 by Igor Escobar) == + +Features: + +* adding data-mask support + +== v0.9.1 (Jul/19 2013 22:35 +0100 by Igor Escobar) == + +Changes: + +* jQuery-Mask-Plugin is now available at bower.io + +Bugfixes: + +* fixing addEventListener on IE7 + +== v0.9.0 (Apr/24 2013 07:44 +0100 by Igor Escobar) == + +Features: + +* Adding compatibility with Zepto.js + +== v0.8.0 (Apr/07 2013 18:39 +0100 by Igor Escobar) == + +Features: + +* applying masks anything != than input :) +* implementing the possibility of range chars ex: A{1,3} + +== v0.7.11 (Apr/05 2013 22:12 +0100 by Igor Escobar) == + +Changes: + +* now when you type a wrong char, the plugin will make your text fit inside of the mask instead of lose your data. + +== v0.7.10 (Apr/04 2013 22:14 +0100 by Igor Escobar) == + +Changes: + +* changing yui-compressor to clojure-compiler + +== v0.7.9 (Apr/04 2013 22:04 +0100 by Igor Escobar) == + +Changes: + +* refactoring and implementation of optional mask digits + +Bugfixes: + +* fixing maxlength and adding a smarter mask removal. issue #18 + +== v0.7.8 (Mar/30 2013 00:48 +0000 by Igor Escobar) == + +Changes: + +* a few changes to get the code smallest possible. +* removing unnecessary methods and making code smaller. + +== v0.7.7 (Mar/29 2013 12:38 +0000 by Igor Escobar) == + +Bugfixes: + +* fixing copy and paste problem related on issue #15 + +== v0.7.6 (Mar/29 2013 00:28 +0000 by Igor Escobar) == + +Bugfixes: + +* correcting mask formatationg problem related on issue #16 + +== v0.7.5 (Mar/03 2013 20:56 +0000 by Igor Escobar) == + +Changes: + +* generating .gz file on deploy + +== v0.7.4 (Mar/03 2013 20:38 +0000 by Igor Escobar) == + +Changes: + +* changing minifier jsmin to yui compressor. + +== v0.7.3 (Mar/02 2013 01:12 +0000 by Igor Escobar) == + +Bugfixes: + +* bug fixing when typed wrong data type on mixing masks. + +== v0.7.2 (Feb/24 2013 22:02 +0000 by Igor Escobar) == + +Bugfixes: + +* fuckin stupid comma. + +== v0.7.1 (Feb/24 2013 21:57 +0000 by Igor Escobar) == + +Changes: + +* testing the private method maskToRegex +* a little bit of changes to make the code more testable + +== v0.7.0 (Feb/12 2013 00:30 +0000 by Igor Escobar) == + +Features: + +* Now you can decide for jquery mask plugin how to interpret 0 to 9, A and S and even teach him how to reconize patterns. + +== v0.6.3 (Feb/11 2013 12:20 +0000 by Igor Escobar) == + +Bugfixes: + +* When the user paste a text and the last char is valid sanitize may fail + +== v0.6.2 (Feb/11 2013 00:02 +0000 by Igor Escobar) == + +Bugfixes: + +* allowing the user type the same character as the mask without erasing it. + +== v0.6.1 (Jan/20 2013 23:57 +0000 by Igor Escobar) == + +Changes: + +* changing the way ta deployment occurs to correct jquery plugins deployments. + +== v0.6.0 (Jan/18 2013 17:19 +0000 by Igor Escobar) == + +Changes: + +* Now pushing jQuery Mask Plugin to jQuery Plugins Repository + +== v0.5.4 (Jan/17 2013 23:06 +0000 by Igor Escobar) == + +Changes: + +* upgrading jquery plugins manifest file + +== v0.5.3 (Jan/17 2013 22:48 +0000 by Igor Escobar) == + +Bugfixes: + +* correctly generating jmask version inside of jquery mask source + +== v0.5.2 (Jan/17 2013 22:43 +0000 by Igor Escobar) == + +Changes: + +* Now pushing to jQuery Plugin Repository + +== v0.5.1 (Jan/07 2013 23:33 +0000 by Igor Escobar) == + +Changes: + +* improving the deploy process with the new stepup's upgrade. + +== v0.5.0 (Oct/27 2012 13:40 +0100 by Igor Escobar) == + +Bugfixes: + +* Bug fixes on OnSupport method with Firefox. + +Features: + +* the first parameter of the .mask() function, now accepts a string or a anonymous function + +== v0.4.7 (Aug/06 2012 22:56 +0100 by Igor Escobar) == + +Changes: + +* Nothing big, just class refactoring + +== v0.4.6 (Aug/06 2012 01:25 +0100 by Igor Escobar) == + +Changes: + +- better OOP design +- implementing the jquery data object on each mask field +- implementing the public method .remove to disable and remove the mask + +== v0.4.5 (Aug/04 2012 01:31 +0100 by Igor Escobar) == + +Changes: + +- improving support to complex jquery selectors +- performance improvement. +- callback handling improvement + +== v0.4.4 (Jun/03 2012 21:01 +0100 by Igor Escobar) == + +Bugfixes: + +* Bug fixes on Internet Explorer 8. + +== v0.4.3 (Mar/19 2012 21:52 +0000 by Igor Escobar) == + +Bugfixes: + +* Corrigindo bug para mascaras com + + +== v0.4.2 (Mar/18 2012 15:28 +0000 by Igor Escobar) == + +Bugfixes: + +* Mascara não pararecia no firefox + +== v0.4.1 (Mar/18 2012 15:01 +0000 by Igor Escobar) == + +Bugfixes: + +* Corrigindo tim das macaras. + +== v0.4.0 (Mar/18 2012 14:51 +0000 by Igor Escobar) == + +Features: + +* Implementado mascara reversa para moeda/cpf/rg/etc. +* Nova engine. + +== v0.3.0 (Mar/14 2012 10:14 +0000 by Igor Escobar) == + +Changes: + +* License and comments up to date. + +Features: + +* On-the-fly mask change. +* onComplete and onKeyPress new callbacks. + +== v0.2.5 (Mar/13 2012 22:55 +0000 by Igor Escobar) == + +Bugfixes: + +- Corrigindo ctrl+v com mascara errada. - Cortando dados que exceder a mascara no ctrl+v ou se segurar alguma tecla. - Refatorando algumas partes do código. + +== v0.2.4 (Mar/13 2012 11:06 +0000 by Igor Escobar) == + +Changes: + +* Codigo refatorado, otimizado, validação mais precisa e efetiva. + +== v0.2.3 (Mar/13 2012 01:01 +0000 by Igor Escobar) == + +Changes: + +* Melhorando expressoes regulares. + +== v0.2.2 (Mar/13 2012 00:50 +0000 by Igor Escobar) == + +Bugfixes: + +* Corrindo regex de validação + +== v0.2.1 (Mar/13 2012 00:41 +0000 by Igor Escobar) == + +Bugfixes: + +* Corrigida validação alphanumerica. + +== v0.2.0 (Mar/13 2012 00:24 +0000 by Igor Escobar) == + +Features: + +- Input Data Type Validation. +- Automatic MaxLength (When are not defined). +- Live Event Implemented for Ajax-based Apps. +- Mixed mask with validation. +* S for string digit +* A for alphanumeric digit +* 0 to 9 for numeric digit. + +== v0.1.1 (Mar/10 2012 14:05 +0000 by Igor Escobar) == + +Bugfixes: + +* Implementando Crossbrowser event handling. + +== v0.1.0 (Mar/10 2012 13:10 +0000 by Igor Escobar) == + +Features: + +* Implementando mascaras com espaço para data e hora + +== v0.0.1 (Mar/10 2012 04:42 +0000 by Igor Escobar) == + +Changes: + +* Refatorando o codigo para suportar multiplas instancias diff --git a/vendor/jquery-mask/CONTRIBUTING.md b/vendor/jquery-mask/CONTRIBUTING.md new file mode 100755 index 0000000000..65367176c1 --- /dev/null +++ b/vendor/jquery-mask/CONTRIBUTING.md @@ -0,0 +1,9 @@ +### Have you take a look into our docs? +https://igorescobar.github.io/jQuery-Mask-Plugin/ + +### Want to contribute? Make sure you read this first +https://github.com/igorescobar/jQuery-Mask-Plugin#contributing + +Is this plugin helping you out? Buy me a beer and cheers! :beer: + +:bowtie: https://www.paypal.me/igorcescobar diff --git a/vendor/jquery-mask/Dockerfile b/vendor/jquery-mask/Dockerfile new file mode 100755 index 0000000000..db59cb7141 --- /dev/null +++ b/vendor/jquery-mask/Dockerfile @@ -0,0 +1,36 @@ +FROM phusion/baseimage:0.9.17 + +# Use baseimage-docker's init system. +CMD ["/sbin/my_init"] + +# Java 8 for Google's clojure compiler +RUN \ + echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \ + echo "deb http://dl.bintray.com/sbt/debian /" | tee -a /etc/apt/sources.list.d/sbt.list && \ + add-apt-repository -y ppa:webupd8team/java && \ + apt-get update && \ + apt-get install -y oracle-java8-installer git unzip ruby-full && \ + rm -rf /var/lib/apt/lists/* && \ + rm -rf /var/cache/oracle-jdk8-installer + +# Define commonly used JAVA_HOME variable +ENV JAVA_HOME /usr/lib/jvm/java-8-oracle + +RUN mkdir /app +RUN mkdir /app/clojure-compiler + +# Clojure compiler +RUN \ + curl -O http://dl.google.com/closure-compiler/compiler-latest.zip && \ + unzip compiler-latest.zip -d /app/clojure-compiler && \ + chmod a+x /app/clojure-compiler && \ + rm compiler-latest.zip + +RUN gem install bundler pry step-up --no-rdoc --no-ri + +# Install Node.js +RUN curl --silent --location https://deb.nodesource.com/setup_0.12 | sudo bash - +RUN apt-get install --yes nodejs + +RUN npm install -g grunt-cli +WORKDIR /app/jquery-mask-plugin diff --git a/vendor/jquery-mask/Gruntfile.js b/vendor/jquery-mask/Gruntfile.js new file mode 100755 index 0000000000..e89370fea7 --- /dev/null +++ b/vendor/jquery-mask/Gruntfile.js @@ -0,0 +1,42 @@ +module.exports = function(grunt) { + require('load-grunt-tasks')(grunt); + require('time-grunt')(grunt); + + grunt.initConfig({ + jshint: { + options: { + jshintrc: '.jshintrc', + reporter: require('jshint-stylish') + }, + all: ['src/{,*/}*.js'] + }, + connect: { + server: { + options: { + port: 9001, + base: './' + } + } + }, + qunit: { + all: { + options: { + urls: [ + 'http://localhost:9001/test/test-for-jquery-1.11.1.html', + 'http://localhost:9001/test/test-for-jquery-1.7.2.html', + 'http://localhost:9001/test/test-for-jquery-1.8.3.html', + 'http://localhost:9001/test/test-for-jquery-1.9.1.html', + 'http://localhost:9001/test/test-for-jquery-2.1.1.html', + 'http://localhost:9001/test/test-for-jquery-3.0.0.html', + 'http://localhost:9001/test/test-for-zepto.html' + ] + } + } + } + }); + + // A convenient task alias. + grunt.registerTask('test', ['jshint', 'connect', 'qunit']); + grunt.registerTask('default', ['test']); + +}; diff --git a/vendor/jquery-mask/ISSUE_TEMPLATE.md b/vendor/jquery-mask/ISSUE_TEMPLATE.md new file mode 100755 index 0000000000..001550aa45 --- /dev/null +++ b/vendor/jquery-mask/ISSUE_TEMPLATE.md @@ -0,0 +1,22 @@ +### Have you take a look into our docs? +https://igorescobar.github.io/jQuery-Mask-Plugin/ + +### Make sure your read this before opening a new issue: +https://github.com/igorescobar/jQuery-Mask-Plugin#problems-or-questions + +#### Device +[...] + +#### Browser (and version)? +[...] + +#### Functional `jsfiddle` exemplifying your problem: +You can use this one as exemple: http://jsfiddle.net/igorescobar/6pco4om7/ + +#### Describe de problem depth: +[...] + + +Is this plugin helping you out? Buy me a beer and cheers! :beer: + +:bowtie: https://www.paypal.me/igorcescobar diff --git a/vendor/jquery-mask/LICENSE b/vendor/jquery-mask/LICENSE new file mode 100755 index 0000000000..49285f3457 --- /dev/null +++ b/vendor/jquery-mask/LICENSE @@ -0,0 +1,26 @@ + Created by Igor Escobar on 2012-03-10. Please report any bug at http://blog.igorescobar.com + + Copyright (c) 2012 Igor Escobar http://blog.igorescobar.com + + The MIT License (http://www.opensource.org/licenses/mit-license.php) + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/jquery-mask/README.md b/vendor/jquery-mask/README.md new file mode 100755 index 0000000000..144513cbdc --- /dev/null +++ b/vendor/jquery-mask/README.md @@ -0,0 +1,137 @@ +# jQuery Mask Plugin +A jQuery Plugin to make masks on form fields and HTML elements. + +[![Build Status](https://travis-ci.org/igorescobar/jQuery-Mask-Plugin.png)](https://travis-ci.org/igorescobar/jQuery-Mask-Plugin) +[![Code Climate](https://codeclimate.com/github/igorescobar/jQuery-Mask-Plugin.png)](https://codeclimate.com/github/igorescobar/jQuery-Mask-Plugin) +[![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/jquery-mask-plugin/badge?style=rounded)](https://www.jsdelivr.com/package/npm/jquery-mask-plugin) +[![CDNJS](https://img.shields.io/cdnjs/v/jquery.mask.svg)](https://cdnjs.com/libraries/jquery.mask) + +# Documentation, Demos & Usage Examples +https://igorescobar.github.io/jQuery-Mask-Plugin/ + +## Features + + * Lightweight (~2kb minified, ~1kb gziped). + * Built-in support for dynamically added elements. + * Masks on any HTML element (no need to server-side mask anymore!)! + * HTML notation support (data-mask, data-mask-recursive, data-mask-clearifnotmatch). + * String/Numeric/Alpha/Mixed masks. + * Reverse mask support for masks on numeric fields. + * Sanitization. + * Optional digits. + * Recursive Digits. + * Fallback Digits. + * Advanced mask initialization. + * Advanced Callbacks. + * On-the-fly mask change. + * Mask removal. + * Full customization. + * Compatibility with React/UMD/Zepto.js/Angular.JS. + * HTML5 placeholder support. + * Clear the field if it not matches support. + +## Want to buy me a beer? :heart_eyes: +http://paypal.me/igorcescobar + +## Install it via Package Managers +### Bower +`bower install jquery-mask-plugin` +### NPM +`npm i jquery-mask-plugin` +### Meteor +`meteor add igorescobar:jquery-mask-plugin` +### Packagist/Composer +`composer require igorescobar/jquery-mask-plugin` + +## CDNs +### CDNjs +https://cdnjs.com/libraries/jquery.mask +### JSDelivr +http://www.jsdelivr.com/projects/jquery.mask + +## RubyGems +```ruby +gem 'jquery_mask_rails' # more details at http://bit.ly/jquery-mask-gem +``` + +## Tutorials +### English + * [Masks with jQuery Mask Plugin](http://bit.ly/masks-with-jquery-mask-plugin) + * [Using jQuery Mask Plugin With Zepto.js](http://bit.ly/using-jquery-mask-plugin-with-zeptojs) + +### Portuguese + * [Mascaras com JQuery Mask Plugin](http://bit.ly/mascaras-com-jquery-mask-plugin) + * [Mascara Javascript para os novos telefones de São Paulo](http://bit.ly/mascara-javascript-para-os-novos-telefones-de-sao-paulo) + +### Fun (or not) facts + * [I’ve had the chance to troll Donald Trump. But I didn’t.](http://www.igorescobar.com/blog/2016/08/21/ive-the-chance-to-troll-donald-trump-but-i-didnt/) + +## Compatibility +jQuery Mask Plugin has been tested with jQuery 1.7+ on all major browsers: + + * Firefox 2+ (Win, Mac, Linux); + * IE7+ (Win); + * Chrome 6+ (Win, Mac, Linux, Android, iPhone); + * Safari 3.2+ (Win, Mac, iPhone); + * Opera 8+ (Win, Mac, Linux, Android, iPhone). + * Android Default Browser v4+ + +## Typescript support +Definition can be found [here](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/jquery-mask-plugin). + +To install, open terminal and navigate to your working directory. + +### Typescript 1.x users + * Install [typings](https://github.com/typings/typings) by running `npm install typings --global`. + * Then install the definition by running `typings install dt~jquery-mask-plugin --global --save`. +### Typescript 2.x users + * Use npm `npm install --save-dev @types/jquery-mask-plugin`. + +For configuration options and troubleshooting refer to these repositories: +* [Typings](https://github.com/typings/typings) +* [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) +* [Typescript](https://github.com/Microsoft/TypeScript) + + +## Problems or Questions? +Before opening a new [issue](https://github.com/igorescobar/jQuery-Mask-Plugin/issues) take a look on those frequently asked questions: +#### [How to integrate with React.js?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/498) +#### [How to integrate with Angular.js?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/499) +#### [How to integrate with Vue.js?](https://github.com/ankurk91/vue-jquery-mask) +#### [Problems with old versions of Android keyboard](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/135) +#### [Negative numbers, or currency related problems](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/436#issuecomment-253176511) +#### [Prefix or sufix on the Mask](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/166) +#### [Add validation?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/387#issuecomment-192998092) +#### [Field type number, email not working?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/450#issuecomment-253225719) +#### [Want to keep the placeholder as the user types?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/633#issuecomment-350819224) +#### [E-mail mask?](https://github.com/igorescobar/jQuery-Mask-Plugin/issues/582) + +## Bugs? +Did you read our [docs](https://igorescobar.github.io/jQuery-Mask-Plugin/docs.html)? Yes? Cool! So now... make sure that you have a *functional* [jsfiddle](http://jsfiddle.net/) exemplifying your problem and open an [issue](https://github.com/igorescobar/jQuery-Mask-Plugin/issues) for us. Don't know how to do it? Use this [fiddle example](http://jsfiddle.net/igorescobar/6pco4om7/). + +## Contributing + * **Bug Reporting**: Yes! You can contribute opening [issues](https://github.com/igorescobar/jQuery-Mask-Plugin/issues)! + * **Documenting**: Do you think that something in our [docs](https://github.com/igorescobar/jQuery-Mask-Plugin/tree/gh-pages) should be better? Do you have a cool idea to increase the awesomeness? Summit your pull request with your idea! + * **Bug Fixing**: No time to lose? Fix it and help others! Write some [tests](https://github.com/igorescobar/jQuery-Mask-Plugin/tree/master/test) to make sure that everything are working propertly. + * **Improving**: Open an [issue](https://github.com/igorescobar/jQuery-Mask-Plugin/issues) and lets discuss it. Just to make sure that you're on the right track. + * **Sharing**: Yes! Have we saved some of your time? Are you enjoying our mask plugin? Sharing is caring! Tweet it! Facebook it! Linkedin It(?!) :D + * **Donating**: Hey, now that you don't need to worry about masks again... buy me a coffee, beer or a PlayStation 4 (Xbox One also accepted!) :o) + +### Unit Tests +We use [QUnit](http://qunitjs.com/) and [GruntJS](http://gruntjs.com/). To run our test suit is just run: ```grunt test``` in your console or you can open those ```test-for*.html``` files inside of our ```test/``` folder. + +In case you're familiar with [Docker](https://www.docker.com/) here is how you can use it: +```bash +docker build -t jquery-mask . +CONTAINER_ID=$(docker run -d -v $PWD:/app/jquery-mask-plugin jquery-mask) +docker exec $CONTAINER_ID sh -c "npm install" +docker exec -it $CONTAINER_ID /bin/bash +grunt test +``` + +## Contributors + * [Igor Lima](https://github.com/igorlima) + * [Mark Simmons](https://github.com/Markipelago) + * [Gabriel Schammah](https://github.com/gschammah) + * [Marcelo Manzan](https://github.com/kawamanza) + * [See the full list](https://github.com/igorescobar/jQuery-Mask-Plugin/graphs/contributors) diff --git a/vendor/jquery-mask/bower.json b/vendor/jquery-mask/bower.json new file mode 100755 index 0000000000..1ec7ea6f90 --- /dev/null +++ b/vendor/jquery-mask/bower.json @@ -0,0 +1,12 @@ +{ + "name": "jquery-mask-plugin", + "version": "1.14.16", + "main": "dist/jquery.mask.js", + "ignore": [ + "deploy.rb", + "jquery.mask.json", + "Gruntfile.js", + "test/*", + ".*" + ] +} diff --git a/vendor/jquery-mask/component.json b/vendor/jquery-mask/component.json new file mode 100755 index 0000000000..d8263ef0dd --- /dev/null +++ b/vendor/jquery-mask/component.json @@ -0,0 +1,10 @@ +{ + "name": "jQuery-Mask-Plugin", + "description": "A jQuery Plugin to make masks on form fields and HTML elements.", + "version": "1.14.16", + "keywords": ["javascript", "mask", "form"], + "scripts": [ + "dist/jquery.mask.js" + ], + "main": "dist/jquery.mask.js" +} diff --git a/vendor/jquery-mask/composer.json b/vendor/jquery-mask/composer.json new file mode 100755 index 0000000000..f9a7541017 --- /dev/null +++ b/vendor/jquery-mask/composer.json @@ -0,0 +1,19 @@ +{ + "name": "igorescobar/jquery-mask-plugin", + "type": "library", + "description": "A jQuery Plugin to make masks on form fields and html elements.", + "keywords": ["jquery", "mask", "plugin"], + "homepage": "https://github.com/igorescobar/jQuery-Mask-Plugin", + "license": "MIT", + "authors": [ + { + "name": "Igor Escobar", + "email": "blog@igorescobar.com", + "homepage": "https://about.me/igorescobar", + "role": "Developer" + } + ], + "support": { + "issues": "https://github.com/igorescobar/jQuery-Mask-Plugin/issues" + } +} diff --git a/vendor/jquery-mask/deploy.rb b/vendor/jquery-mask/deploy.rb new file mode 100755 index 0000000000..acfbc78356 --- /dev/null +++ b/vendor/jquery-mask/deploy.rb @@ -0,0 +1,77 @@ +require 'rubygems' +require 'zlib' + +JMASK_FILE = 'src/jquery.mask.js' +JMASK_MIN_FILE = 'dist/jquery.mask.min.js' +GHPAGES_JMASK_MIN_FILE = 'js/jquery.mask.min.js' +JMASK_VERSION = `stepup version --next-release`.delete("\n") +BOWER_MANIFEST_FILE = 'bower.json' +NPM_MANIFEST_FILE = 'package.json' +METEOR_MANIFEST_FILE = 'package.js' +COMPONENT_MANIFEST_FILE = 'component.json' + +abort("No notes, do deal.") if JMASK_VERSION.empty? + +puts '# PUTTING NEW VERSION INSIDE OF JQUERY MASK FILE' +unversioned_jmask_file = File.open(JMASK_FILE, 'rb') { |file| file.read } +File.open(JMASK_FILE, 'w') do |file| + file.write(unversioned_jmask_file.gsub(/\* @version: (v[0-9.+]+)/, "\* @version: #{JMASK_VERSION}")) +end + +puts '# COPYING NEW JMASK FILE TO DIST/' +`yes | cp #{JMASK_FILE} dist/` + +[BOWER_MANIFEST_FILE, NPM_MANIFEST_FILE, COMPONENT_MANIFEST_FILE, METEOR_MANIFEST_FILE].each { |manifest_name| + puts "# UPGRADING #{manifest_name} " + manifest_file = File.open(manifest_name, 'rb') { |file| file.read } + File.open(manifest_name, 'w') do |file| + file.write(manifest_file.gsub(/"version": "([0-9.+]+)"/, "\"version\": \"#{JMASK_VERSION.gsub("v", "")}\"")) + end +} + +puts '# GENERATING MIN FILE' +jquery_mask_min_file = nil +File.open(JMASK_FILE, 'r') do |file| + minFile = File.open(JMASK_MIN_FILE, 'w') + minFile.puts("// jQuery Mask Plugin #{JMASK_VERSION}") + minFile.puts("// github.com/igorescobar/jQuery-Mask-Plugin") + jquery_mask_min_file = `java -jar ../clojure-compiler/compiler.jar --js src/jquery.mask.js --charset UTF-8` + minFile.puts(jquery_mask_min_file) + minFile.close +end + +puts '# GENERATING A NEW COMMIT WITH VERSIONED FILEs' +`git commit -am 'generating jquery mask files #{JMASK_VERSION}'` + +puts '# PUSHING CHANGES TO REMOTE' +`git pull --rebase && git push` + +puts '# CREATING NEW VERSION' +`stepup version create --no-editor` + +puts '# UPGRATING CHANGELOG' +`stepup changelog --format=wiki > CHANGELOG.md` +`git commit -am "upgrading changelog"` +`git push` + +puts '# UPGRADING gh-pages' +`git checkout gh-pages` +`git pull origin gh-pages` + +minFile = File.open(GHPAGES_JMASK_MIN_FILE, 'w') +minFile.puts("// jQuery Mask Plugin #{JMASK_VERSION}") +minFile.puts("// github.com/igorescobar/jQuery-Mask-Plugin") +minFile.puts(jquery_mask_min_file) +minFile.close + +`git commit -am "upgrading plugin file"` +`git push` +`git checkout master` + +puts '# PUBLISHING NPM PACKAGE' +`npm publish` + +puts '# PUBLISHING METEOR PACKAGE' +`meteor publish` + +puts '# DONE!' diff --git a/vendor/jquery-mask/dist/jquery.mask.js b/vendor/jquery-mask/dist/jquery.mask.js new file mode 100755 index 0000000000..7e0216cbc6 --- /dev/null +++ b/vendor/jquery-mask/dist/jquery.mask.js @@ -0,0 +1,604 @@ +/** + * jquery.mask.js + * @version: v1.14.16 + * @author: Igor Escobar + * + * Created by Igor Escobar on 2012-03-10. Please report any bug at github.com/igorescobar/jQuery-Mask-Plugin + * + * Copyright (c) 2012 Igor Escobar http://igorescobar.com + * + * The MIT License (http://www.opensource.org/licenses/mit-license.php) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* jshint laxbreak: true */ +/* jshint maxcomplexity:17 */ +/* global define */ + +// UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere. +// https://github.com/umdjs/umd/blob/master/templates/jqueryPlugin.js +(function (factory, jQuery, Zepto) { + + if (typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } else if (typeof exports === 'object' && typeof Meteor === 'undefined') { + module.exports = factory(require('jquery')); + } else { + factory(jQuery || Zepto); + } + +}(function ($) { + 'use strict'; + + var Mask = function (el, mask, options) { + + var p = { + invalid: [], + getCaret: function () { + try { + var sel, + pos = 0, + ctrl = el.get(0), + dSel = document.selection, + cSelStart = ctrl.selectionStart; + + // IE Support + if (dSel && navigator.appVersion.indexOf('MSIE 10') === -1) { + sel = dSel.createRange(); + sel.moveStart('character', -p.val().length); + pos = sel.text.length; + } + // Firefox support + else if (cSelStart || cSelStart === '0') { + pos = cSelStart; + } + + return pos; + } catch (e) {} + }, + setCaret: function(pos) { + try { + if (el.is(':focus')) { + var range, ctrl = el.get(0); + + // Firefox, WebKit, etc.. + if (ctrl.setSelectionRange) { + ctrl.setSelectionRange(pos, pos); + } else { // IE + range = ctrl.createTextRange(); + range.collapse(true); + range.moveEnd('character', pos); + range.moveStart('character', pos); + range.select(); + } + } + } catch (e) {} + }, + events: function() { + el + .on('keydown.mask', function(e) { + el.data('mask-keycode', e.keyCode || e.which); + el.data('mask-previus-value', el.val()); + el.data('mask-previus-caret-pos', p.getCaret()); + p.maskDigitPosMapOld = p.maskDigitPosMap; + }) + .on($.jMaskGlobals.useInput ? 'input.mask' : 'keyup.mask', p.behaviour) + .on('paste.mask drop.mask', function() { + setTimeout(function() { + el.keydown().keyup(); + }, 100); + }) + .on('change.mask', function(){ + el.data('changed', true); + }) + .on('blur.mask', function(){ + if (oldValue !== p.val() && !el.data('changed')) { + el.trigger('change'); + } + el.data('changed', false); + }) + // it's very important that this callback remains in this position + // otherwhise oldValue it's going to work buggy + .on('blur.mask', function() { + oldValue = p.val(); + }) + // select all text on focus + .on('focus.mask', function (e) { + if (options.selectOnFocus === true) { + $(e.target).select(); + } + }) + // clear the value if it not complete the mask + .on('focusout.mask', function() { + if (options.clearIfNotMatch && !regexMask.test(p.val())) { + p.val(''); + } + }); + }, + getRegexMask: function() { + var maskChunks = [], translation, pattern, optional, recursive, oRecursive, r; + + for (var i = 0; i < mask.length; i++) { + translation = jMask.translation[mask.charAt(i)]; + + if (translation) { + + pattern = translation.pattern.toString().replace(/.{1}$|^.{1}/g, ''); + optional = translation.optional; + recursive = translation.recursive; + + if (recursive) { + maskChunks.push(mask.charAt(i)); + oRecursive = {digit: mask.charAt(i), pattern: pattern}; + } else { + maskChunks.push(!optional && !recursive ? pattern : (pattern + '?')); + } + + } else { + maskChunks.push(mask.charAt(i).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')); + } + } + + r = maskChunks.join(''); + + if (oRecursive) { + r = r.replace(new RegExp('(' + oRecursive.digit + '(.*' + oRecursive.digit + ')?)'), '($1)?') + .replace(new RegExp(oRecursive.digit, 'g'), oRecursive.pattern); + } + + return new RegExp(r); + }, + destroyEvents: function() { + el.off(['input', 'keydown', 'keyup', 'paste', 'drop', 'blur', 'focusout', ''].join('.mask ')); + }, + val: function(v) { + var isInput = el.is('input'), + method = isInput ? 'val' : 'text', + r; + + if (arguments.length > 0) { + if (el[method]() !== v) { + el[method](v); + } + r = el; + } else { + r = el[method](); + } + + return r; + }, + calculateCaretPosition: function(oldVal) { + var newVal = p.getMasked(), + caretPosNew = p.getCaret(); + if (oldVal !== newVal) { + var caretPosOld = el.data('mask-previus-caret-pos') || 0, + newValL = newVal.length, + oldValL = oldVal.length, + maskDigitsBeforeCaret = 0, + maskDigitsAfterCaret = 0, + maskDigitsBeforeCaretAll = 0, + maskDigitsBeforeCaretAllOld = 0, + i = 0; + + for (i = caretPosNew; i < newValL; i++) { + if (!p.maskDigitPosMap[i]) { + break; + } + maskDigitsAfterCaret++; + } + + for (i = caretPosNew - 1; i >= 0; i--) { + if (!p.maskDigitPosMap[i]) { + break; + } + maskDigitsBeforeCaret++; + } + + for (i = caretPosNew - 1; i >= 0; i--) { + if (p.maskDigitPosMap[i]) { + maskDigitsBeforeCaretAll++; + } + } + + for (i = caretPosOld - 1; i >= 0; i--) { + if (p.maskDigitPosMapOld[i]) { + maskDigitsBeforeCaretAllOld++; + } + } + + // if the cursor is at the end keep it there + if (caretPosNew > oldValL) { + caretPosNew = newValL * 10; + } else if (caretPosOld >= caretPosNew && caretPosOld !== oldValL) { + if (!p.maskDigitPosMapOld[caretPosNew]) { + var caretPos = caretPosNew; + caretPosNew -= maskDigitsBeforeCaretAllOld - maskDigitsBeforeCaretAll; + caretPosNew -= maskDigitsBeforeCaret; + if (p.maskDigitPosMap[caretPosNew]) { + caretPosNew = caretPos; + } + } + } + else if (caretPosNew > caretPosOld) { + caretPosNew += maskDigitsBeforeCaretAll - maskDigitsBeforeCaretAllOld; + caretPosNew += maskDigitsAfterCaret; + } + } + return caretPosNew; + }, + behaviour: function(e) { + e = e || window.event; + p.invalid = []; + + var keyCode = el.data('mask-keycode'); + + if ($.inArray(keyCode, jMask.byPassKeys) === -1) { + var newVal = p.getMasked(), + caretPos = p.getCaret(), + oldVal = el.data('mask-previus-value') || ''; + + // this is a compensation to devices/browsers that don't compensate + // caret positioning the right way + setTimeout(function() { + p.setCaret(p.calculateCaretPosition(oldVal)); + }, $.jMaskGlobals.keyStrokeCompensation); + + p.val(newVal); + p.setCaret(caretPos); + return p.callbacks(e); + } + }, + getMasked: function(skipMaskChars, val) { + var buf = [], + value = val === undefined ? p.val() : val + '', + m = 0, maskLen = mask.length, + v = 0, valLen = value.length, + offset = 1, addMethod = 'push', + resetPos = -1, + maskDigitCount = 0, + maskDigitPosArr = [], + lastMaskChar, + check; + + if (options.reverse) { + addMethod = 'unshift'; + offset = -1; + lastMaskChar = 0; + m = maskLen - 1; + v = valLen - 1; + check = function () { + return m > -1 && v > -1; + }; + } else { + lastMaskChar = maskLen - 1; + check = function () { + return m < maskLen && v < valLen; + }; + } + + var lastUntranslatedMaskChar; + while (check()) { + var maskDigit = mask.charAt(m), + valDigit = value.charAt(v), + translation = jMask.translation[maskDigit]; + + if (translation) { + if (valDigit.match(translation.pattern)) { + buf[addMethod](valDigit); + if (translation.recursive) { + if (resetPos === -1) { + resetPos = m; + } else if (m === lastMaskChar && m !== resetPos) { + m = resetPos - offset; + } + + if (lastMaskChar === resetPos) { + m -= offset; + } + } + m += offset; + } else if (valDigit === lastUntranslatedMaskChar) { + // matched the last untranslated (raw) mask character that we encountered + // likely an insert offset the mask character from the last entry; fall + // through and only increment v + maskDigitCount--; + lastUntranslatedMaskChar = undefined; + } else if (translation.optional) { + m += offset; + v -= offset; + } else if (translation.fallback) { + buf[addMethod](translation.fallback); + m += offset; + v -= offset; + } else { + p.invalid.push({p: v, v: valDigit, e: translation.pattern}); + } + v += offset; + } else { + if (!skipMaskChars) { + buf[addMethod](maskDigit); + } + + if (valDigit === maskDigit) { + maskDigitPosArr.push(v); + v += offset; + } else { + lastUntranslatedMaskChar = maskDigit; + maskDigitPosArr.push(v + maskDigitCount); + maskDigitCount++; + } + + m += offset; + } + } + + var lastMaskCharDigit = mask.charAt(lastMaskChar); + if (maskLen === valLen + 1 && !jMask.translation[lastMaskCharDigit]) { + buf.push(lastMaskCharDigit); + } + + var newVal = buf.join(''); + p.mapMaskdigitPositions(newVal, maskDigitPosArr, valLen); + return newVal; + }, + mapMaskdigitPositions: function(newVal, maskDigitPosArr, valLen) { + var maskDiff = options.reverse ? newVal.length - valLen : 0; + p.maskDigitPosMap = {}; + for (var i = 0; i < maskDigitPosArr.length; i++) { + p.maskDigitPosMap[maskDigitPosArr[i] + maskDiff] = 1; + } + }, + callbacks: function (e) { + var val = p.val(), + changed = val !== oldValue, + defaultArgs = [val, e, el, options], + callback = function(name, criteria, args) { + if (typeof options[name] === 'function' && criteria) { + options[name].apply(this, args); + } + }; + + callback('onChange', changed === true, defaultArgs); + callback('onKeyPress', changed === true, defaultArgs); + callback('onComplete', val.length === mask.length, defaultArgs); + callback('onInvalid', p.invalid.length > 0, [val, e, el, p.invalid, options]); + } + }; + + el = $(el); + var jMask = this, oldValue = p.val(), regexMask; + + mask = typeof mask === 'function' ? mask(p.val(), undefined, el, options) : mask; + + // public methods + jMask.mask = mask; + jMask.options = options; + jMask.remove = function() { + var caret = p.getCaret(); + if (jMask.options.placeholder) { + el.removeAttr('placeholder'); + } + if (el.data('mask-maxlength')) { + el.removeAttr('maxlength'); + } + p.destroyEvents(); + p.val(jMask.getCleanVal()); + p.setCaret(caret); + return el; + }; + + // get value without mask + jMask.getCleanVal = function() { + return p.getMasked(true); + }; + + // get masked value without the value being in the input or element + jMask.getMaskedVal = function(val) { + return p.getMasked(false, val); + }; + + jMask.init = function(onlyMask) { + onlyMask = onlyMask || false; + options = options || {}; + + jMask.clearIfNotMatch = $.jMaskGlobals.clearIfNotMatch; + jMask.byPassKeys = $.jMaskGlobals.byPassKeys; + jMask.translation = $.extend({}, $.jMaskGlobals.translation, options.translation); + + jMask = $.extend(true, {}, jMask, options); + + regexMask = p.getRegexMask(); + + if (onlyMask) { + p.events(); + p.val(p.getMasked()); + } else { + if (options.placeholder) { + el.attr('placeholder' , options.placeholder); + } + + // this is necessary, otherwise if the user submit the form + // and then press the "back" button, the autocomplete will erase + // the data. Works fine on IE9+, FF, Opera, Safari. + if (el.data('mask')) { + el.attr('autocomplete', 'off'); + } + + // detect if is necessary let the user type freely. + // for is a lot faster than forEach. + for (var i = 0, maxlength = true; i < mask.length; i++) { + var translation = jMask.translation[mask.charAt(i)]; + if (translation && translation.recursive) { + maxlength = false; + break; + } + } + + if (maxlength) { + el.attr('maxlength', mask.length).data('mask-maxlength', true); + } + + p.destroyEvents(); + p.events(); + + var caret = p.getCaret(); + p.val(p.getMasked()); + p.setCaret(caret); + } + }; + + jMask.init(!el.is('input')); + }; + + $.maskWatchers = {}; + var HTMLAttributes = function () { + var input = $(this), + options = {}, + prefix = 'data-mask-', + mask = input.attr('data-mask'); + + if (input.attr(prefix + 'reverse')) { + options.reverse = true; + } + + if (input.attr(prefix + 'clearifnotmatch')) { + options.clearIfNotMatch = true; + } + + if (input.attr(prefix + 'selectonfocus') === 'true') { + options.selectOnFocus = true; + } + + if (notSameMaskObject(input, mask, options)) { + return input.data('mask', new Mask(this, mask, options)); + } + }, + notSameMaskObject = function(field, mask, options) { + options = options || {}; + var maskObject = $(field).data('mask'), + stringify = JSON.stringify, + value = $(field).val() || $(field).text(); + try { + if (typeof mask === 'function') { + mask = mask(value); + } + return typeof maskObject !== 'object' || stringify(maskObject.options) !== stringify(options) || maskObject.mask !== mask; + } catch (e) {} + }, + eventSupported = function(eventName) { + var el = document.createElement('div'), isSupported; + + eventName = 'on' + eventName; + isSupported = (eventName in el); + + if ( !isSupported ) { + el.setAttribute(eventName, 'return;'); + isSupported = typeof el[eventName] === 'function'; + } + el = null; + + return isSupported; + }; + + $.fn.mask = function(mask, options) { + options = options || {}; + var selector = this.selector, + globals = $.jMaskGlobals, + interval = globals.watchInterval, + watchInputs = options.watchInputs || globals.watchInputs, + maskFunction = function() { + if (notSameMaskObject(this, mask, options)) { + return $(this).data('mask', new Mask(this, mask, options)); + } + }; + + $(this).each(maskFunction); + + if (selector && selector !== '' && watchInputs) { + clearInterval($.maskWatchers[selector]); + $.maskWatchers[selector] = setInterval(function(){ + $(document).find(selector).each(maskFunction); + }, interval); + } + return this; + }; + + $.fn.masked = function(val) { + return this.data('mask').getMaskedVal(val); + }; + + $.fn.unmask = function() { + clearInterval($.maskWatchers[this.selector]); + delete $.maskWatchers[this.selector]; + return this.each(function() { + var dataMask = $(this).data('mask'); + if (dataMask) { + dataMask.remove().removeData('mask'); + } + }); + }; + + $.fn.cleanVal = function() { + return this.data('mask').getCleanVal(); + }; + + $.applyDataMask = function(selector) { + selector = selector || $.jMaskGlobals.maskElements; + var $selector = (selector instanceof $) ? selector : $(selector); + $selector.filter($.jMaskGlobals.dataMaskAttr).each(HTMLAttributes); + }; + + var globals = { + maskElements: 'input,td,span,div', + dataMaskAttr: '*[data-mask]', + dataMask: true, + watchInterval: 300, + watchInputs: true, + keyStrokeCompensation: 10, + // old versions of chrome dont work great with input event + useInput: !/Chrome\/[2-4][0-9]|SamsungBrowser/.test(window.navigator.userAgent) && eventSupported('input'), + watchDataMask: false, + byPassKeys: [9, 16, 17, 18, 36, 37, 38, 39, 40, 91], + translation: { + '0': {pattern: /\d/}, + '9': {pattern: /\d/, optional: true}, + '#': {pattern: /\d/, recursive: true}, + 'A': {pattern: /[a-zA-Z0-9]/}, + 'S': {pattern: /[a-zA-Z]/} + } + }; + + $.jMaskGlobals = $.jMaskGlobals || {}; + globals = $.jMaskGlobals = $.extend(true, {}, globals, $.jMaskGlobals); + + // looking for inputs with data-mask attribute + if (globals.dataMask) { + $.applyDataMask(); + } + + setInterval(function() { + if ($.jMaskGlobals.watchDataMask) { + $.applyDataMask(); + } + }, globals.watchInterval); +}, window.jQuery, window.Zepto)); diff --git a/vendor/jquery-mask/dist/jquery.mask.min.js b/vendor/jquery-mask/dist/jquery.mask.min.js new file mode 100755 index 0000000000..1f22376e7d --- /dev/null +++ b/vendor/jquery-mask/dist/jquery.mask.min.js @@ -0,0 +1,19 @@ +// jQuery Mask Plugin v1.14.16 +// github.com/igorescobar/jQuery-Mask-Plugin +var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(a,n,f){a instanceof String&&(a=String(a));for(var p=a.length,k=0;kg?h=10*d:e>=h&&e!==g?c.maskDigitPosMapOld[h]||(e=h,h=h-(k-l)-a,c.maskDigitPosMap[h]&&(h=e)):h>e&&(h=h+(l-k)+f)}return h},behaviour:function(d){d= +d||window.event;c.invalid=[];var e=b.data("mask-keycode");if(-1===a.inArray(e,l.byPassKeys)){e=c.getMasked();var h=c.getCaret(),g=b.data("mask-previus-value")||"";setTimeout(function(){c.setCaret(c.calculateCaretPosition(g))},a.jMaskGlobals.keyStrokeCompensation);c.val(e);c.setCaret(h);return c.callbacks(d)}},getMasked:function(a,b){var h=[],f=void 0===b?c.val():b+"",g=0,k=d.length,n=0,p=f.length,m=1,r="push",u=-1,w=0;b=[];if(e.reverse){r="unshift";m=-1;var x=0;g=k-1;n=p-1;var A=function(){return-1< +g&&-1= 1.3.1 < 2" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "http2": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/http2/-/http2-3.3.7.tgz", + "integrity": "sha512-puSi8M8WNlFJm9Pk4c/Mbz9Gwparuj3gO9/RRO5zv6piQ0FY+9Qywp0PdWshYgsMJSalixFY7eC6oPu0zRxLAQ==", + "dev": true + }, + "https-proxy-agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", + "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jshint": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.10.2.tgz", + "integrity": "sha512-e7KZgCSXMJxznE/4WULzybCMNXNAd/bf5TSrvVEq78Q/K8ZwFpmBqQeDtNiHc3l49nV4E/+YeHU/JZjSUIrLAA==", + "dev": true, + "requires": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.11", + "minimatch": "~3.0.2", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x" + } + }, + "jshint-stylish": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/jshint-stylish/-/jshint-stylish-1.0.2.tgz", + "integrity": "sha1-6Z88w0CvsY4qdwL4eY10AMoxRGo=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "log-symbols": "^1.0.0", + "string-length": "^1.0.0", + "text-table": "^0.2.0" + } + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "load-grunt-tasks": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-3.5.2.tgz", + "integrity": "sha1-ByhWEYD9IP+KaSdQWFL8WKrqDIg=", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "multimatch": "^2.0.0", + "pkg-up": "^1.0.0", + "resolve-pkg": "^0.1.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "maxmin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz", + "integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "figures": "^1.0.1", + "gzip-size": "^1.0.0", + "pretty-bytes": "^1.0.0" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "~1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "morgan": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", + "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", + "dev": true, + "requires": { + "basic-auth": "~2.0.0", + "debug": "2.6.9", + "depd": "~1.1.2", + "on-finished": "~2.3.0", + "on-headers": "~1.0.1" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multimatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "dev": true, + "requires": { + "array-differ": "^1.0.0", + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "minimatch": "^3.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-ms": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz", + "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=", + "dev": true + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + } + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-up": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", + "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", + "dev": true, + "requires": { + "find-up": "^1.0.0" + } + }, + "plur": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz", + "integrity": "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY=", + "dev": true + }, + "portscanner": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-1.2.0.tgz", + "integrity": "sha1-sUu9olfRTDEPqcwJaCrwLUCWGAI=", + "dev": true, + "requires": { + "async": "1.5.2" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } + } + }, + "pretty-bytes": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", + "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "meow": "^3.1.0" + } + }, + "pretty-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz", + "integrity": "sha1-QlfCVt8/sLRR1q/6qwIYhBJpgdw=", + "dev": true, + "requires": { + "is-finite": "^1.0.1", + "parse-ms": "^1.0.0", + "plur": "^1.0.0" + } + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "dev": true + }, + "psl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.2.0.tgz", + "integrity": "sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "puppeteer": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.19.0.tgz", + "integrity": "sha512-2S6E6ygpoqcECaagDbBopoSOPDv0pAZvTbnBgUY+6hq0/XDFDOLEMNlHF/SKJlzcaZ9ckiKjKDuueWI3FN/WXw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "extract-zip": "^1.6.6", + "https-proxy-agent": "^2.2.1", + "mime": "^2.0.3", + "progress": "^2.0.1", + "proxy-from-env": "^1.0.0", + "rimraf": "^2.6.1", + "ws": "^6.1.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + } + } + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", + "dev": true + }, + "resolve-pkg": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-0.1.0.tgz", + "integrity": "sha1-AsyZNBDik2livZcWahsHfalyVTE=", + "dev": true, + "requires": { + "resolve-from": "^2.0.0" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + }, + "send": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.1", + "destroy": "~1.0.4", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.3.1" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + } + }, + "serve-static": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", + "dev": true, + "requires": { + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.1" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", + "dev": true + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "requires": { + "spdx-license-ids": "^1.0.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + }, + "string-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", + "integrity": "sha1-VpcPscOFWOnnC3KL894mmsRa36w=", + "dev": true, + "requires": { + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "time-grunt": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/time-grunt/-/time-grunt-1.4.0.tgz", + "integrity": "sha1-BiIT5mDJB+hvRAVWwB6mWXtxJCA=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "date-time": "^1.1.0", + "figures": "^1.0.0", + "hooker": "^0.2.3", + "number-is-nan": "^1.0.0", + "pretty-ms": "^2.1.0", + "text-table": "^0.2.0" + } + }, + "time-zone": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-0.1.0.tgz", + "integrity": "sha1-Sncotqwo2w4Aj1FAQ/1VW9VXO0Y=", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-js": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.2.2.tgz", + "integrity": "sha512-++1NO/zZIEdWf6cDIGceSJQPX31SqIpbVAHwFG5+240MtZqPG/NIPoinj8zlXQtAfMBqEt1Jyv2FiLP3n9gVhQ==", + "dev": true, + "requires": { + "commander": "~2.12.1", + "source-map": "~0.6.1" + } + }, + "underscore.string": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", + "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", + "dev": true, + "requires": { + "sprintf-js": "^1.0.3", + "util-deprecate": "^1.0.2" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "uri-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", + "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, + "requires": { + "fd-slicer": "~1.0.1" + } + } + } +} diff --git a/vendor/jquery-mask/package.js b/vendor/jquery-mask/package.js new file mode 100755 index 0000000000..03ecce8214 --- /dev/null +++ b/vendor/jquery-mask/package.js @@ -0,0 +1,14 @@ +Package.describe({ + "name": "igorescobar:jquery-mask-plugin", + "version": "1.14.16", + "summary": "A jQuery Plugin to make masks on form fields and HTML elements.", + "git": "git@github.com:igorescobar/jQuery-Mask-Plugin.git", + "documentation": "README.md" +}); + +Package.onUse(function(api) { + api.versionsFrom('1.2.1'); + api.use('ecmascript'); + api.addFiles('dist/jquery.mask.js', 'client'); + api.addFiles('dist/jquery.mask.min.js', 'client'); +}); diff --git a/vendor/jquery-mask/package.json b/vendor/jquery-mask/package.json new file mode 100755 index 0000000000..4e4c6d78ff --- /dev/null +++ b/vendor/jquery-mask/package.json @@ -0,0 +1,34 @@ +{ + "name": "jquery-mask-plugin", + "version": "1.14.16", + "description": "A jQuery Plugin to make masks on form fields and html elements.", + "author": "Igor Escobar ", + "homepage": "http://igorescobar.github.io/jQuery-Mask-Plugin/", + "main": "./dist/jquery.mask.js", + "repository": { + "type": "git", + "url": "https://github.com/igorescobar/jQuery-Mask-Plugin" + }, + "bugs": { + "url": "https://github.com/igorescobar/jQuery-Mask-Plugin/issues" + }, + "keywords": [ + "mask", + "masks", + "form", + "input", + "jquery-plugin" + ], + "license": "MIT", + "devDependencies": { + "grunt": "^1.0.4", + "grunt-contrib-connect": "*", + "grunt-contrib-jshint": "^2.1.0", + "grunt-contrib-qunit": "^3.1.0", + "grunt-contrib-uglify": "*", + "jshint-stylish": "^1.0.0", + "load-grunt-tasks": "^3.1.0", + "request": "2.88.0", + "time-grunt": "^1.0.0" + } +} diff --git a/vendor/jquery-mask/src/jquery.mask.js b/vendor/jquery-mask/src/jquery.mask.js new file mode 100755 index 0000000000..54f171c946 --- /dev/null +++ b/vendor/jquery-mask/src/jquery.mask.js @@ -0,0 +1,604 @@ +/** + * jquery.mask.js + * @version: v1.14.16 + * @author: Igor Escobar + * + * Created by Igor Escobar on 2012-03-10. Please report any bug at github.com/igorescobar/jQuery-Mask-Plugin + * + * Copyright (c) 2012 Igor Escobar http://igorescobar.com + * + * The MIT License (http://www.opensource.org/licenses/mit-license.php) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* jshint laxbreak: true */ +/* jshint maxcomplexity:17 */ +/* global define */ + +// UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere. +// https://github.com/umdjs/umd/blob/master/templates/jqueryPlugin.js +(function (factory, jQuery, Zepto) { + + if (typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } else if (typeof exports === 'object' && typeof Meteor === 'undefined') { + module.exports = factory(require('jquery')); + } else { + factory(jQuery || Zepto); + } + +}(function ($) { + 'use strict'; + + var Mask = function (el, mask, options) { + + var p = { + invalid: [], + getCaret: function () { + try { + var sel, + pos = 0, + ctrl = el.get(0), + dSel = document.selection, + cSelStart = ctrl.selectionStart; + + // IE Support + if (dSel && navigator.appVersion.indexOf('MSIE 10') === -1) { + sel = dSel.createRange(); + sel.moveStart('character', -p.val().length); + pos = sel.text.length; + } + // Firefox support + else if (cSelStart || cSelStart === '0') { + pos = cSelStart; + } + + return pos; + } catch (e) {} + }, + setCaret: function(pos) { + try { + if (el.is(':focus')) { + var range, ctrl = el.get(0); + + // Firefox, WebKit, etc.. + if (ctrl.setSelectionRange) { + ctrl.setSelectionRange(pos, pos); + } else { // IE + range = ctrl.createTextRange(); + range.collapse(true); + range.moveEnd('character', pos); + range.moveStart('character', pos); + range.select(); + } + } + } catch (e) {} + }, + events: function() { + el + .on('keydown.mask', function(e) { + el.data('mask-keycode', e.keyCode || e.which); + el.data('mask-previus-value', el.val()); + el.data('mask-previus-caret-pos', p.getCaret()); + p.maskDigitPosMapOld = p.maskDigitPosMap; + }) + .on($.jMaskGlobals.useInput ? 'input.mask' : 'keyup.mask', p.behaviour) + .on('paste.mask drop.mask', function() { + setTimeout(function() { + el.keydown().keyup(); + }, 100); + }) + .on('change.mask', function(){ + el.data('changed', true); + }) + .on('blur.mask', function(){ + if (oldValue !== p.val() && !el.data('changed')) { + el.trigger('change'); + } + el.data('changed', false); + }) + // it's very important that this callback remains in this position + // otherwhise oldValue it's going to work buggy + .on('blur.mask', function() { + oldValue = p.val(); + }) + // select all text on focus + .on('focus.mask', function (e) { + if (options.selectOnFocus === true) { + $(e.target).select(); + } + }) + // clear the value if it not complete the mask + .on('focusout.mask', function() { + if (options.clearIfNotMatch && !regexMask.test(p.val())) { + p.val(''); + } + }); + }, + getRegexMask: function() { + var maskChunks = [], translation, pattern, optional, recursive, oRecursive, r; + + for (var i = 0; i < mask.length; i++) { + translation = jMask.translation[mask.charAt(i)]; + + if (translation) { + + pattern = translation.pattern.toString().replace(/.{1}$|^.{1}/g, ''); + optional = translation.optional; + recursive = translation.recursive; + + if (recursive) { + maskChunks.push(mask.charAt(i)); + oRecursive = {digit: mask.charAt(i), pattern: pattern}; + } else { + maskChunks.push(!optional && !recursive ? pattern : (pattern + '?')); + } + + } else { + maskChunks.push(mask.charAt(i).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')); + } + } + + r = maskChunks.join(''); + + if (oRecursive) { + r = r.replace(new RegExp('(' + oRecursive.digit + '(.*' + oRecursive.digit + ')?)'), '($1)?') + .replace(new RegExp(oRecursive.digit, 'g'), oRecursive.pattern); + } + + return new RegExp(r); + }, + destroyEvents: function() { + el.off(['input', 'keydown', 'keyup', 'paste', 'drop', 'blur', 'focusout', ''].join('.mask ')); + }, + val: function(v) { + var isInput = el.is('input'), + method = isInput ? 'val' : 'text', + r; + + if (arguments.length > 0) { + if (el[method]() !== v) { + el[method](v); + } + r = el; + } else { + r = el[method](); + } + + return r; + }, + calculateCaretPosition: function(oldVal) { + var newVal = p.getMasked(), + caretPosNew = p.getCaret(); + if (oldVal !== newVal) { + var caretPosOld = el.data('mask-previus-caret-pos') || 0, + newValL = newVal.length, + oldValL = oldVal.length, + maskDigitsBeforeCaret = 0, + maskDigitsAfterCaret = 0, + maskDigitsBeforeCaretAll = 0, + maskDigitsBeforeCaretAllOld = 0, + i = 0; + + for (i = caretPosNew; i < newValL; i++) { + if (!p.maskDigitPosMap[i]) { + break; + } + maskDigitsAfterCaret++; + } + + for (i = caretPosNew - 1; i >= 0; i--) { + if (!p.maskDigitPosMap[i]) { + break; + } + maskDigitsBeforeCaret++; + } + + for (i = caretPosNew - 1; i >= 0; i--) { + if (p.maskDigitPosMap[i]) { + maskDigitsBeforeCaretAll++; + } + } + + for (i = caretPosOld - 1; i >= 0; i--) { + if (p.maskDigitPosMapOld[i]) { + maskDigitsBeforeCaretAllOld++; + } + } + + // if the cursor is at the end keep it there + if (caretPosNew > oldValL) { + caretPosNew = newValL * 10; + } else if (caretPosOld >= caretPosNew && caretPosOld !== oldValL) { + if (!p.maskDigitPosMapOld[caretPosNew]) { + var caretPos = caretPosNew; + caretPosNew -= maskDigitsBeforeCaretAllOld - maskDigitsBeforeCaretAll; + caretPosNew -= maskDigitsBeforeCaret; + if (p.maskDigitPosMap[caretPosNew]) { + caretPosNew = caretPos; + } + } + } + else if (caretPosNew > caretPosOld) { + caretPosNew += maskDigitsBeforeCaretAll - maskDigitsBeforeCaretAllOld; + caretPosNew += maskDigitsAfterCaret; + } + } + return caretPosNew; + }, + behaviour: function(e) { + e = e || window.event; + p.invalid = []; + + var keyCode = el.data('mask-keycode'); + + if ($.inArray(keyCode, jMask.byPassKeys) === -1) { + var newVal = p.getMasked(), + caretPos = p.getCaret(), + oldVal = el.data('mask-previus-value') || ''; + + // this is a compensation to devices/browsers that don't compensate + // caret positioning the right way + setTimeout(function() { + p.setCaret(p.calculateCaretPosition(oldVal)); + }, $.jMaskGlobals.keyStrokeCompensation); + + p.val(newVal); + p.setCaret(caretPos); + return p.callbacks(e); + } + }, + getMasked: function(skipMaskChars, val) { + var buf = [], + value = val === undefined ? p.val() : val + '', + m = 0, maskLen = mask.length, + v = 0, valLen = value.length, + offset = 1, addMethod = 'push', + resetPos = -1, + maskDigitCount = 0, + maskDigitPosArr = [], + lastMaskChar, + check; + + if (options.reverse) { + addMethod = 'unshift'; + offset = -1; + lastMaskChar = 0; + m = maskLen - 1; + v = valLen - 1; + check = function () { + return m > -1 && v > -1; + }; + } else { + lastMaskChar = maskLen - 1; + check = function () { + return m < maskLen && v < valLen; + }; + } + + var lastUntranslatedMaskChar; + while (check()) { + var maskDigit = mask.charAt(m), + valDigit = value.charAt(v), + translation = jMask.translation[maskDigit]; + + if (translation) { + if (valDigit.match(translation.pattern)) { + buf[addMethod](valDigit); + if (translation.recursive) { + if (resetPos === -1) { + resetPos = m; + } else if (m === lastMaskChar && m !== resetPos) { + m = resetPos - offset; + } + + if (lastMaskChar === resetPos) { + m -= offset; + } + } + m += offset; + } else if (valDigit === lastUntranslatedMaskChar) { + // matched the last untranslated (raw) mask character that we encountered + // likely an insert offset the mask character from the last entry; fall + // through and only increment v + maskDigitCount--; + lastUntranslatedMaskChar = undefined; + } else if (translation.optional) { + m += offset; + v -= offset; + } else if (translation.fallback) { + buf[addMethod](translation.fallback); + m += offset; + v -= offset; + } else { + p.invalid.push({p: v, v: valDigit, e: translation.pattern}); + } + v += offset; + } else { + if (!skipMaskChars) { + buf[addMethod](maskDigit); + } + + if (valDigit === maskDigit) { + maskDigitPosArr.push(v); + v += offset; + } else { + lastUntranslatedMaskChar = maskDigit; + maskDigitPosArr.push(v + maskDigitCount); + maskDigitCount++; + } + + m += offset; + } + } + + var lastMaskCharDigit = mask.charAt(lastMaskChar); + if (maskLen === valLen + 1 && !jMask.translation[lastMaskCharDigit]) { + buf.push(lastMaskCharDigit); + } + + var newVal = buf.join(''); + p.mapMaskdigitPositions(newVal, maskDigitPosArr, valLen); + return newVal; + }, + mapMaskdigitPositions: function(newVal, maskDigitPosArr, valLen) { + var maskDiff = options.reverse ? newVal.length - valLen : 0; + p.maskDigitPosMap = {}; + for (var i = 0; i < maskDigitPosArr.length; i++) { + p.maskDigitPosMap[maskDigitPosArr[i] + maskDiff] = 1; + } + }, + callbacks: function (e) { + var val = p.val(), + changed = val !== oldValue, + defaultArgs = [val, e, el, options], + callback = function(name, criteria, args) { + if (typeof options[name] === 'function' && criteria) { + options[name].apply(this, args); + } + }; + + callback('onChange', changed === true, defaultArgs); + callback('onKeyPress', changed === true, defaultArgs); + callback('onComplete', val.length === mask.length, defaultArgs); + callback('onInvalid', p.invalid.length > 0, [val, e, el, p.invalid, options]); + } + }; + + el = $(el); + var jMask = this, oldValue = p.val(), regexMask; + + mask = typeof mask === 'function' ? mask(p.val(), undefined, el, options) : mask; + + // public methods + jMask.mask = mask; + jMask.options = options; + jMask.remove = function() { + var caret = p.getCaret(); + if (jMask.options.placeholder) { + el.removeAttr('placeholder'); + } + if (el.data('mask-maxlength')) { + el.removeAttr('maxlength'); + } + p.destroyEvents(); + p.val(jMask.getCleanVal()); + p.setCaret(caret); + return el; + }; + + // get value without mask + jMask.getCleanVal = function() { + return p.getMasked(true); + }; + + // get masked value without the value being in the input or element + jMask.getMaskedVal = function(val) { + return p.getMasked(false, val); + }; + + jMask.init = function(onlyMask) { + onlyMask = onlyMask || false; + options = options || {}; + + jMask.clearIfNotMatch = $.jMaskGlobals.clearIfNotMatch; + jMask.byPassKeys = $.jMaskGlobals.byPassKeys; + jMask.translation = $.extend({}, $.jMaskGlobals.translation, options.translation); + + jMask = $.extend(true, {}, jMask, options); + + regexMask = p.getRegexMask(); + + if (onlyMask) { + p.events(); + p.val(p.getMasked()); + } else { + if (options.placeholder) { + el.attr('placeholder' , options.placeholder); + } + + // this is necessary, otherwise if the user submit the form + // and then press the "back" button, the autocomplete will erase + // the data. Works fine on IE9+, FF, Opera, Safari. + if (el.data('mask')) { + el.attr('autocomplete', 'off'); + } + + // detect if is necessary let the user type freely. + // for is a lot faster than forEach. + for (var i = 0, maxlength = true; i < mask.length; i++) { + var translation = jMask.translation[mask.charAt(i)]; + if (translation && translation.recursive) { + maxlength = false; + break; + } + } + + if (maxlength) { + el.attr('maxlength', mask.length).data('mask-maxlength', true); + } + + p.destroyEvents(); + p.events(); + + var caret = p.getCaret(); + p.val(p.getMasked()); + p.setCaret(caret); + } + }; + + jMask.init(!el.is('input')); + }; + + $.maskWatchers = {}; + var HTMLAttributes = function () { + var input = $(this), + options = {}, + prefix = 'data-mask-', + mask = input.attr('data-mask'); + + if (input.attr(prefix + 'reverse')) { + options.reverse = true; + } + + if (input.attr(prefix + 'clearifnotmatch')) { + options.clearIfNotMatch = true; + } + + if (input.attr(prefix + 'selectonfocus') === 'true') { + options.selectOnFocus = true; + } + + if (notSameMaskObject(input, mask, options)) { + return input.data('mask', new Mask(this, mask, options)); + } + }, + notSameMaskObject = function(field, mask, options) { + options = options || {}; + var maskObject = $(field).data('mask'), + stringify = JSON.stringify, + value = $(field).val() || $(field).text(); + try { + if (typeof mask === 'function') { + mask = mask(value); + } + return typeof maskObject !== 'object' || stringify(maskObject.options) !== stringify(options) || maskObject.mask !== mask; + } catch (e) {} + }, + eventSupported = function(eventName) { + var el = document.createElement('div'), isSupported; + + eventName = 'on' + eventName; + isSupported = (eventName in el); + + if ( !isSupported ) { + el.setAttribute(eventName, 'return;'); + isSupported = typeof el[eventName] === 'function'; + } + el = null; + + return isSupported; + }; + + $.fn.mask = function(mask, options) { + options = options || {}; + var selector = this.selector, + globals = $.jMaskGlobals, + interval = globals.watchInterval, + watchInputs = options.watchInputs || globals.watchInputs, + maskFunction = function() { + if (notSameMaskObject(this, mask, options)) { + return $(this).data('mask', new Mask(this, mask, options)); + } + }; + + $(this).each(maskFunction); + + if (selector && selector !== '' && watchInputs) { + clearInterval($.maskWatchers[selector]); + $.maskWatchers[selector] = setInterval(function(){ + $(document).find(selector).each(maskFunction); + }, interval); + } + return this; + }; + + $.fn.masked = function(val) { + return this.data('mask').getMaskedVal(val); + }; + + $.fn.unmask = function() { + clearInterval($.maskWatchers[this.selector]); + delete $.maskWatchers[this.selector]; + return this.each(function() { + var dataMask = $(this).data('mask'); + if (dataMask) { + dataMask.remove().removeData('mask'); + } + }); + }; + + $.fn.cleanVal = function() { + return this.data('mask').getCleanVal(); + }; + + $.applyDataMask = function(selector) { + selector = selector || $.jMaskGlobals.maskElements; + var $selector = (selector instanceof $) ? selector : $(selector); + $selector.filter($.jMaskGlobals.dataMaskAttr).each(HTMLAttributes); + }; + + var globals = { + maskElements: 'input,td,span,div', + dataMaskAttr: '[data-mask]', + dataMask: true, + watchInterval: 300, + watchInputs: true, + keyStrokeCompensation: 10, + // old versions of chrome dont work great with input event + useInput: !/Chrome\/[2-4][0-9]|SamsungBrowser/.test(window.navigator.userAgent) && eventSupported('input'), + watchDataMask: false, + byPassKeys: [9, 16, 17, 18, 36, 37, 38, 39, 40, 91], + translation: { + '0': {pattern: /\d/}, + '9': {pattern: /\d/, optional: true}, + '#': {pattern: /\d/, recursive: true}, + 'A': {pattern: /[a-zA-Z0-9]/}, + 'S': {pattern: /[a-zA-Z]/} + } + }; + + $.jMaskGlobals = $.jMaskGlobals || {}; + globals = $.jMaskGlobals = $.extend(true, {}, globals, $.jMaskGlobals); + + // looking for inputs with data-mask attribute + if (globals.dataMask) { + $.applyDataMask(); + } + + setInterval(function() { + if ($.jMaskGlobals.watchDataMask) { + $.applyDataMask(); + } + }, globals.watchInterval); +}, window.jQuery, window.Zepto)); diff --git a/vendor/jquery-mask/test/jquery.mask.test.js b/vendor/jquery-mask/test/jquery.mask.test.js new file mode 100755 index 0000000000..378aebb286 --- /dev/null +++ b/vendor/jquery-mask/test/jquery.mask.test.js @@ -0,0 +1,718 @@ +var QUNIT = true; +$(document).ready(function(){ + + var testfield = $('.simple-field'), + testfieldDataMask = $('.simple-field-data-mask'), + testfieldDataMaskWithReverse = $('.simple-field-data-mask-reverse'), + testfieldDataMaskWithClearIfNotMatch = $('.simple-field-data-mask-clearifnotmatch'), + testfieldDataMaskWithClearIfNotMatchAndOptionalMask = $('.simple-field-data-mask-clearifnotmatch-and-optional-mask'), + testdiv = $('.simple-div'), + typeTest = function (typedValue, obj) { + obj = typeof obj === "undefined" ? testfield : obj; + + return obj.keydown().val(typedValue).trigger('input').val(); + }, + typeDivTest = function(typedValue){ + return testdiv.keydown().text(typedValue).trigger('input').text(); + }; + + module('Setting Up'); + test("test if the mask method exists after plugin insertion", function() { + equal( typeof testfield.mask , "function" , "mask function should exists" ); + }); + + module('Simple Masks'); + test("Masks with only numbers.", function(){ + testfield.mask('000000'); + + equal( typeTest("1."), "1"); + equal( typeTest('1éáa2aaaaqwo'), "12"); + equal( typeTest('1234567'), "123456"); + + }); + + test("When I change the mask on-the-fly things should work normally", function(){ + testfield.mask('0000.0000'); + + equal( typeTest("1."), "1"); + equal( typeTest('1éáa2aaaaqwo'), "12"); + equal( typeTest('1234567'), "1234.567"); + + // changing on-the-fly + testfield.mask('0.000.000'); + + equal( typeTest("1."), "1."); + equal( typeTest('1éáa2aaaaqwo'), "1.2"); + equal( typeTest('1234567'), "1.234.567"); + + }); + + test("When I change the mask on-the-fly with onChange callback things should work normally", function(){ + + var masks = ['0000.00009', '0.0000.0000']; + var SPphoneMask = function(phone){ + return phone.length <= 9 ? masks[0] : masks[1]; + }; + + testfield.mask(SPphoneMask, {onChange: function(phone, e, currentField, options){ + $(currentField).mask(SPphoneMask(phone), options); + }}); + + equal( typeTest("1"), "1"); + equal( typeTest("12"), "12"); + equal( typeTest("123"), "123"); + equal( typeTest("1234"), "1234"); + equal( typeTest("12345"), "1234.5"); + equal( typeTest("123456"), "1234.56"); + equal( typeTest("1234567"), "1234.567"); + equal( typeTest("12345678"), "1234.5678"); + equal( typeTest("123456789"), "1.2345.6789"); + + }); + + test("When I change the mask on-the-fly with onKeyPress callback things should work normally", function(){ + + var masks = ['0000.00009', '0.0000.0000']; + var SPphoneMask = function(phone){ + return phone.length <= 9 ? masks[0] : masks[1]; + }; + + testfield.mask(SPphoneMask, {onKeyPress: function(phone, e, currentField, options){ + $(currentField).mask(SPphoneMask(phone), options); + }}); + + equal( typeTest("1"), "1"); + equal( typeTest("12"), "12"); + equal( typeTest("123"), "123"); + equal( typeTest("1234"), "1234"); + equal( typeTest("12345"), "1234.5"); + equal( typeTest("123456"), "1234.56"); + equal( typeTest("1234567"), "1234.567"); + equal( typeTest("12345678"), "1234.5678"); + equal( typeTest("123456789"), "1.2345.6789"); + + }); + + test("#onInvalid callback. should call when invalid", function(){ + testfield.mask('00/00/0000', {onInvalid: function(val, e, el, invalid, options){ + equal(val, "1") + equal(typeof e, "object") + equal(typeof el, "object") + equal(invalid.length, 1); + equal(invalid[0]["e"], "/\\d/"); + equal(invalid[0]["p"], 1); + equal(invalid[0]["v"], "a"); + equal(typeof options.onInvalid, "function"); + }}); + + equal( typeTest("1a") , "1"); + }); + + test("#onInvalid callback. should not call when valid", function(){ + var callback = sinon.spy(); + testfield.mask('00/00/0000', {onInvalid: callback}); + + equal( typeTest("11") , "11"); + equal(callback.called, false) + }); + + test('When I typed a char thats the same as the mask char', function(){ + testfield.unmask(); + testfield.mask('00/00/0000'); + + equal( typeTest("00/"), "00/"); + equal( typeTest("00a"), "00/"); + equal( typeTest("00a00/00"), "00/00/00"); + equal( typeTest("0a/00/00"), "00/00/0"); + equal( typeTest("0a/0a/00"), "00/00"); + + }); + + test('When I typed exactly the same as the mask', function(){ + testfield.mask('00/00/0000'); + equal( typeTest("00"), "00"); + equal( typeTest("00/"), "00/"); + equal( typeTest("aa/"), ""); + equal( typeTest("00/0"), "00/0"); + equal( typeTest("00/00"), "00/00"); + equal( typeTest("00/00/0"), "00/00/0"); + equal( typeTest("00/00/00"), "00/00/00"); + }); + + test("Testing masks with a literal on the last char", function () { + testfield.mask("(99)"); + + equal( typeTest("(99"), "(99)"); + }); + + + module('Masks with numbers and especial characters'); + + test("Masks with numbers and special characters.", function(){ + testfield.mask('(000) 000-0000'); + + equal( typeTest("1"), "(1"); + equal( typeTest('12'), "(12"); + equal( typeTest('123'), "(123"); + equal( typeTest('1234'), "(123) 4"); + equal( typeTest('12345'), "(123) 45"); + equal( typeTest('(123) 456'), "(123) 456"); + equal( typeTest('(123) 4567'), "(123) 456-7"); + + }); + + test("Testing masks with a annonymous function", function(){ + testfield.mask(function(){ + return "(123) 456-7899" + }); + + equal( typeTest("1"), "(1"); + equal( typeTest('12'), "(12"); + equal( typeTest('123'), "(123"); + equal( typeTest('1234'), "(123) 4"); + equal( typeTest('12345'), "(123) 45"); + equal( typeTest('123456'), "(123) 456"); + equal( typeTest('1234567'), "(123) 456-7"); + + }); + + test("Masks with numbers, strings e special characters", function(){ + testfield.mask('(999) A99-SSSS'); + + equal( typeTest("(1"), "(1"); + equal( typeTest('(12'), "(12"); + equal( typeTest('(123'), "(123"); + equal( typeTest('(123) 4'), "(123) 4"); + equal( typeTest('(123) A'), "(123) A"); + equal( typeTest('123.'), "(123) "); + equal( typeTest('(123) 45'), "(123) 45"); + equal( typeTest('(123) 456'), "(123) 456"); + equal( typeTest('(123) 456-A'), "(123) 456-A"); + equal( typeTest('(123) 456-AB'), "(123) 456-AB"); + equal( typeTest('(123) 456-ABC'), "(123) 456-ABC"); + equal( typeTest('(123) 456-ABCD'), "(123) 456-ABCD"); + equal( typeTest('(123) 456-ABCDE'), "(123) 456-ABCD"); + equal( typeTest('(123) 456-ABCD1'), "(123) 456-ABCD"); + + }); + + test("Masks with numbers, strings e special characters #2 ", function(){ + testfield.mask('AAA 000-S0S'); + + equal( typeTest("1"), "1"); + equal( typeTest('12'), "12"); + equal( typeTest('123'), "123"); + equal( typeTest('123 4'), "123 4"); + equal( typeTest('123 45'), "123 45"); + equal( typeTest('123 456'), "123 456"); + equal( typeTest('123 456-7'), "123 456-"); + + }); + + module("Testing Reversible Masks"); + + test("Testing a CPF Mask", function(){ + testfield.mask('000.000.000-00', {reverse: true}); + + equal( typeTest("1"), "1"); + equal( typeTest("12"), "12"); + equal( typeTest("123"), "1-23"); + equal( typeTest("12-34"), "12-34"); + equal( typeTest("123-45"), "123-45"); + equal( typeTest("1.234-56"), "1.234-56"); + equal( typeTest("12.345-67"), "12.345-67"); + equal( typeTest("123.456-78"), "123.456-78"); + equal( typeTest("1.234.567-89"), "1.234.567-89"); + equal( typeTest("12.345.678-90"), "12.345.678-90"); + equal( typeTest("123.456.789-00"), "123.456.789-00"); + equal( typeTest("123.456.789-00"), "123.456.789-00"); + + equal( typeTest("123.456.789a00"), "123.456.789-00"); + equal( typeTest("123-a5"), "12-35"); + + equal( typeTest("1"), "1"); + equal( typeTest("12"), "12"); + equal( typeTest("1-23"), "1-23"); + equal( typeTest("12-34"), "12-34"); + equal( typeTest("12-345"), "123-45"); + equal( typeTest("1.234-56"), "1.234-56"); + equal( typeTest("12.345-67"), "12.345-67"); + equal( typeTest("123.456-78"), "123.456-78"); + equal( typeTest("1.234.567-89"), "1.234.567-89"); + equal( typeTest("12.345.678-90"), "12.345.678-90"); + equal( typeTest("123.456.789-00"), "123.456.789-00"); + equal( typeTest("123.456.789-00"), "123.456.789-00"); + equal( typeTest("123.456.789a00"), "123.456.789-00"); + }); + + test("Testing Reverse numbers with recursive mask", function(){ + testfield.mask("#.##0,00", {reverse: true}); + + equal(typeTest(""), ""); + equal(typeTest("1"), "1"); + equal(typeTest("12"), "12"); + equal(typeTest("123"), "1,23"); + equal(typeTest("1,234"), "12,34"); + equal(typeTest("12,345"), "123,45"); + equal(typeTest("123,456"), "1.234,56"); + equal(typeTest("1.234,567"), "12.345,67"); + equal(typeTest("12.345,678"), "123.456,78"); + equal(typeTest("123.456,789"), "1.234.567,89"); + equal(typeTest("1.234.567,890"), "12.345.678,90"); + equal(typeTest("12.345.678,901"), "123.456.789,01"); + equal(typeTest("123.456.789,012"), "1.234.567.890,12"); + equal(typeTest("1.234.567.890,1"), "123.456.789,01"); + equal(typeTest("123.456.789,0"), "12.345.678,90"); + equal(typeTest("12.345.678,9"), "1.234.567,89"); + equal(typeTest("1.234.567,8"), "123.456,78"); + }); + + test("Testing numbers with recursive mask", function(){ + testfield.mask("0#.#"); + + equal(typeTest(""), ""); + equal(typeTest("1"), "1"); + equal(typeTest("12"), "12"); + equal(typeTest("12."), "12."); + equal(typeTest("12.3"), "12.3"); + equal(typeTest("12.34"), "12.34"); + equal(typeTest("12.345"), "12.34.5"); + equal(typeTest("12.34.5."), "12.34.5"); + equal(typeTest("12.34.56"), "12.34.56"); + equal(typeTest("12.34.567"), "12.34.56.7"); + equal(typeTest("12.34.56."), "12.34.56."); + equal(typeTest("12.34.56"), "12.34.56"); + equal(typeTest("12.34.5"), "12.34.5"); + }); + + test("Testing numbers with recursive mask with one #", function(){ + testfield.mask("0#", {}); + + equal(typeTest(""), ""); + equal(typeTest("1"), "1"); + equal(typeTest("12"), "12"); + equal(typeTest("123"), "123"); + equal(typeTest("1234"), "1234"); + equal(typeTest("12345"), "12345"); + equal(typeTest("12345"), "12345"); + equal(typeTest("123456"), "123456"); + equal(typeTest("1234567"), "1234567"); + equal(typeTest("123456."), "123456"); + equal(typeTest("123456"), "123456"); + equal(typeTest("12345"), "12345"); + }); + test("Testing numbers with recursive mask with one # and reverse", function(){ + testfield.mask("#0", {reverse: true}); + + equal(typeTest(""), ""); + equal(typeTest("1"), "1"); + equal(typeTest("12"), "12"); + equal(typeTest("123"), "123"); + equal(typeTest("1234"), "1234"); + equal(typeTest("12345"), "12345"); + equal(typeTest("12345"), "12345"); + equal(typeTest("123456"), "123456"); + equal(typeTest("1234567"), "1234567"); + equal(typeTest("123456."), "123456"); + equal(typeTest("123456"), "123456"); + equal(typeTest("12345"), "12345"); + }); + test("Testing reversible masks with a literal on the last char", function () { + testfield.mask("(99)"); + + equal( typeTest("(99"), "(99)"); + }); + + module('Removing mask'); + + test("when I get the unmasked value", function(){ + testfield.mask('(00) 0000-0000', { placeholder: '(__) ____-____' }); + + equal(typeTest("1299999999"), "(12) 9999-9999"); + testfield.unmask() + equal(testfield.val(), "1299999999"); + + if (window.Zepto) { + equal(testfield.attr('placeholder'), ''); + equal(testfield.attr('maxlength'), null); + } else { + equal(testfield.attr('placeholder'), undefined); + equal(testfield.attr('maxlength'), undefined); + } + }); + + module('Getting Unmasked Value'); + + test("when I get the unmasked value", function(){ + testfield.mask('(00) 0000-0000'); + + equal( typeTest("1299999999"), "(12) 9999-9999"); + equal( testfield.cleanVal(), "1299999999"); + }); + + test("when I get the unmasked value with recursive mask", function(){ + testfield.mask('#.##0,00', {reverse:true}); + + equal( typeTest("123123123123123123", testfield), "1.231.231.231.231.231,23"); + equal( testfield.cleanVal(), "123123123123123123"); + }); + + module('Masking a value programmatically'); + + test("when I get the masked value programmatically", function(){ + testfield.mask('(00) 0000-0000'); + typeTest("1299999999", testfield); + equal( testfield.masked("3488888888"), "(34) 8888-8888"); + }); + + module('personalized settings') + + test("when adding more itens to the table translation",function(){ + testfield.mask('00/00/0000', {'translation': {0: {pattern: /[0-9*]/}}}); + + equal( typeTest('12/34/5678'), '12/34/5678'); + equal( typeTest('**/34/5678'), '**/34/5678'); + }); + + test("when adding more itens to the table translation #2",function(){ + testfield.mask('00/YY/0000', {'translation': {'Y': {pattern: /[0-9*]/}}}); + + equal( typeTest('12/34/5678'), '12/34/5678'); + equal( typeTest('12/**/5678'), '12/**/5678'); + }); + + test("when adding more itens to the table translation #3",function(){ + var old_translation = $.jMaskGlobals.translation + $.jMaskGlobals.translation = { + '1': {pattern: /\d/}, + '9': {pattern: /\d/, optional: true}, + '#': {pattern: /\d/, recursive: true}, + 'A': {pattern: /[a-zA-Z0-9]/}, + 'S': {pattern: /[a-zA-Z]/} + }; + + testfield.mask('00/11/1111'); + + equal( typeTest('12/12/5678'), '00/12/1256'); + + testfield.mask('11/00/1111'); + equal( typeTest('12/12/5678'), '12/00/1256'); + + $.jMaskGlobals.translation = old_translation; + }); + + test("when adding more itens to the table translation #fallback",function(){ + testfield.mask('zz/z0/0000', {'translation': {'z': {pattern: /[0-9*]/, fallback: '*'}}}); + + equal( typeTest('12/:4/5678'), '12/*4/5678'); + equal( typeTest('::/:4/5678'), '**/*4/5678'); + }); + + test("test the translation #fallback #1" , function(){ + testfield.mask('00t00', {'translation': {'t': {pattern: /[:,.]/, fallback: ':'}}}); + + equal( typeTest('1'), '1'); + equal( typeTest('13'), '13'); + equal( typeTest('137'), '13:7'); + equal( typeTest('1337'), '13:37'); + equal( typeTest('13z00'), '13:00'); + }); + + test("test the translation #fallback #2" , function(){ + testfield.mask('00/t0/t0', {'translation': {'t': {pattern: /[:,.*]/, fallback: '*'}}}); + + equal( typeTest('1'), '1'); + equal( typeTest('13'), '13'); + equal( typeTest('13/'), '13/'); + equal( typeTest('13/a'), '13/*'); + equal( typeTest('13/a1z1'), '13/*1/*1'); + }); + + test("test the translation #fallback #3" , function(){ + testfield.mask('tt/00/00', {'translation': {'t': {pattern: /[:,.*]/, fallback: '*'}}}); + + equal( typeTest('*'), '*'); + equal( typeTest('13'), '**/13'); + equal( typeTest('13/'), '**/13/'); + equal( typeTest('13/a'), '**/13/'); + equal( typeTest('13/a1z1'), '**/13/11'); + }); + + test("when adding opcional chars",function(){ + testfield.mask('099.099.099.099'); + + equal( typeTest('0.0.0.0'), '0.0.0.0'); + equal( typeTest('00.00.00.00'), '00.00.00.00'); + equal( typeTest('00.000.00.000'), '00.000.00.000'); + equal( typeTest('000.00.000.00'), '000.00.000.00'); + equal( typeTest('000.000.000.000'), '000.000.000.000'); + equal( typeTest('000000000000'), '000.000.000.000'); + equal( typeTest('0'), '0'); + equal( typeTest('00'), '00'); + equal( typeTest('00.'), '00.'); + equal( typeTest('00.0'), '00.0'); + equal( typeTest('00.00'), '00.00'); + equal( typeTest('00.00.'), '00.00.'); + equal( typeTest('00.00.000'), '00.00.000'); + equal( typeTest('00.00.000.'), '00.00.000.'); + equal( typeTest('00.00.000.0'), '00.00.000.0'); + equal( typeTest('00..'), '00.'); + }); + + test("when aplying mask on a element different than a form field",function(){ + testdiv.mask('000.000.000-00', {reverse: true}); + + equal( typeDivTest('12312312312'), '123.123.123-12'); + equal( typeDivTest('123.123.123-12'), '123.123.123-12'); + equal( typeDivTest('123.123a123-12'), '123.123.123-12'); + equal( typeDivTest('191'), '1-91'); + + testdiv.mask('00/00/0000'); + equal( typeDivTest('000000'), '00/00/00'); + equal( typeDivTest('00000000'), '00/00/0000'); + equal( typeDivTest('00/00/0000'), '00/00/0000'); + equal( typeDivTest('0a/00/0000'), '00/00/000'); + + }); + + module('Testing data-mask attribute support'); + + test("Testing data-mask attribute", function(){ + equal( typeTest("00/", testfieldDataMask), "00/"); + equal( typeTest("00a", testfieldDataMask), "00/"); + equal( typeTest("00a00/00", testfieldDataMask), "00/00/00"); + equal( typeTest("0a/00/00", testfieldDataMask), "00/00/0"); + equal( typeTest("0a/0a/00", testfieldDataMask), "00/00"); + equal( typeTest("00000000", testfieldDataMask), "00/00/0000"); + }); + + test("Testing data-mask-reverse attribute", function(){ + equal( typeTest("0000", testfieldDataMaskWithReverse), "00,00"); + equal( typeTest("000000", testfieldDataMaskWithReverse), "0.000,00"); + equal( typeTest("0000000000", testfieldDataMaskWithReverse), "00.000.000,00"); + }); + + module('Event fire test'); + + // TODO: need to understand why zepto.js isnt calling change event! + if(!window.Zepto) { + test('onChange Test', 2, function(){ + testfield.unmask(); + + var callback = sinon.spy(); + var mock = sinon.mock() + var typeAndBlur = function(typedValue){ + testfield.trigger('keydown'); + testfield.val(typedValue); + testfield.trigger('input'); + testfield.trigger("blur"); + }; + + testfield.mask('000.(000).000/0-0'); + + testfield.on("change", callback); + + typeAndBlur(""); + typeAndBlur("1"); + typeAndBlur("12"); + typeAndBlur("123"); + typeAndBlur("1234"); + typeAndBlur("12345"); + typeAndBlur("123456"); + typeAndBlur("1234567"); + typeAndBlur("12345678"); + typeAndBlur("123456789"); + typeAndBlur("123456789"); + typeAndBlur("1234567891"); + typeAndBlur("12345678912"); + + equal(testfield.val(), "123.(456).789/1-2" ); + equal(true, sinon.match(11).or(12).test(callback.callCount)) + + testfield.off("change"); + testfield.unmask(); + + }); + } + + + test('onDrop Test', function(){ + ok(true, "todo"); + }); + + module('testing Remove If Not Match Feature'); + + test('test when clearifnotmatch javascript notation', 4, function(){ + var typeAndFocusOut = function(typedValue){ + testfield.keydown().val(typedValue).trigger('input'); + testfield.trigger("focusout"); + }; + + testfield.mask('000'); + + typeAndFocusOut("1"); + equal( testfield.val(), "1" ); + + testfield.mask('000', {clearIfNotMatch: true}); + + typeAndFocusOut("1"); + equal( testfield.val(), "" ); + + typeAndFocusOut("12"); + equal( testfield.val(), "" ); + + typeAndFocusOut("123"); + equal( testfield.val(), "123" ); + }); + + test('test when clearifnotmatch javascript notation #2', 4, function(){ + var typeAndFocusOut = function(typedValue){ + testfield.keydown().val(typedValue).trigger('input'); + testfield.trigger("focusout"); + }; + + testfield.mask('7 (000) 000-0000'); + + typeAndFocusOut("1"); + equal( testfield.val(), "7 (1" ); + + testfield.mask('7 (000) 000-0000', {clearIfNotMatch: true}); + + typeAndFocusOut("1"); + equal( testfield.val(), "" ); + + typeAndFocusOut("12"); + equal( testfield.val(), "" ); + + typeAndFocusOut("7 (123) 123-1234"); + equal( testfield.val(), "7 (123) 123-1234" ); + }); + + test('test when clearifnotmatch is HTML notation', 3, function(){ + var typeAndFocusOut = function(typedValue){ + testfieldDataMaskWithClearIfNotMatch.keydown().val(typedValue).trigger('input'); + testfieldDataMaskWithClearIfNotMatch.trigger("focusout"); + }; + + typeAndFocusOut("1"); + equal( testfieldDataMaskWithClearIfNotMatch.val(), "" ); + + typeAndFocusOut("12"); + equal( testfieldDataMaskWithClearIfNotMatch.val(), "" ); + + typeAndFocusOut("123"); + equal( testfieldDataMaskWithClearIfNotMatch.val(), "123" ); + }); + + module('testing Remove If Not Match Feature'); + + test('test when clearifnotmatch javascript notation', 1, function(){ + + testfield.mask('000', {placeholder: '___'}); + equal( testfield.attr('placeholder'), "___" ); + + }); + + test('test when clearifnotmatch with optional mask', 9, function(){ + // html notation + var typeAndBlur = function(field, typedValue){ + field.keydown().val(typedValue).trigger('input'); + field.trigger("focusout"); + }; + + typeAndBlur(testfieldDataMaskWithClearIfNotMatchAndOptionalMask, "1"); + equal( testfieldDataMaskWithClearIfNotMatchAndOptionalMask.val(), "" ); + + typeAndBlur(testfieldDataMaskWithClearIfNotMatchAndOptionalMask, "12"); + equal( testfieldDataMaskWithClearIfNotMatchAndOptionalMask.val(), "12" ); + + typeAndBlur(testfieldDataMaskWithClearIfNotMatchAndOptionalMask, "123"); + equal( testfieldDataMaskWithClearIfNotMatchAndOptionalMask.val(), "123" ); + + // javascript notation + testfield.mask('099.099.099.099', {clearIfNotMatch: true}); + + typeAndBlur(testfield, "1"); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "123."); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "123.0"); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "123.01.000."); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "123.01.000.123"); + equal( testfield.val(), "123.01.000.123" ); + + typeAndBlur(testfield, "0.0.0.0"); + equal( testfield.val(), "0.0.0.0" ); + }); + + test('test when clearifnotmatch with recursive mask', 4, function(){ + // html notation + var typeAndBlur = function(field, typedValue){ + field.keydown().val(typedValue).trigger('input'); + field.trigger("focusout"); + }; + + // javascript notation + testfield.mask('#.##0,00', {clearIfNotMatch: true, reverse: true}); + + typeAndBlur(testfield, "0"); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "00"); + equal( testfield.val(), "" ); + + typeAndBlur(testfield, "0,00"); + equal( testfield.val(), "0,00" ); + + typeAndBlur(testfield, "1.000,00"); + equal( testfield.val(), "1.000,00" ); + + }); + + module('dynamically loaded elements') + test('#non-inputs', function(){ + expect(5); + + var $container = $('#container-dy-non-inputs'); + var clock = this.clock; + var ticker; + var tester; + var c = 0; + + function write() { + + if (c >= 5) { + clearInterval(ticker); + clearInterval(tester); + return; + } + + c++; + + $container.append('
                  ' + c + c + c + c + '
                  '); + clock.tick(1000); + }; + + function testIt() { + + var cs = $container.find('.c'); + $.each(cs, function(k, field){ + var t = k + 1; + equal($(field).text(), '' + t + t + ':' + t + t); + t++; + }); + }; + + ticker = setInterval(write, 1000); + + write(); + $('.c', $container).mask('00:00'); + testIt() + }); +}); diff --git a/vendor/jquery-mask/test/qunit.css b/vendor/jquery-mask/test/qunit.css new file mode 100755 index 0000000000..cb4815b793 --- /dev/null +++ b/vendor/jquery-mask/test/qunit.css @@ -0,0 +1,244 @@ +/** + * QUnit v1.11.0 - A JavaScript Unit Testing Framework + * + * http://qunitjs.com + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +/** Font Family and Sizes */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { + font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; +} + +#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } +#qunit-tests { font-size: smaller; } + + +/** Resets */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { + margin: 0; + padding: 0; +} + + +/** Header */ + +#qunit-header { + padding: 0.5em 0 0.5em 1em; + + color: #8699a4; + background-color: #0d3349; + + font-size: 1.5em; + line-height: 1em; + font-weight: normal; + + border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-top-right-radius: 5px; + -webkit-border-top-left-radius: 5px; +} + +#qunit-header a { + text-decoration: none; + color: #c2ccd1; +} + +#qunit-header a:hover, +#qunit-header a:focus { + color: #fff; +} + +#qunit-testrunner-toolbar label { + display: inline-block; + padding: 0 .5em 0 .1em; +} + +#qunit-banner { + height: 5px; +} + +#qunit-testrunner-toolbar { + padding: 0.5em 0 0.5em 2em; + color: #5E740B; + background-color: #eee; + overflow: hidden; +} + +#qunit-userAgent { + padding: 0.5em 0 0.5em 2.5em; + background-color: #2b81af; + color: #fff; + text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; +} + +#qunit-modulefilter-container { + float: right; +} + +/** Tests: Pass/Fail */ + +#qunit-tests { + list-style-position: inside; +} + +#qunit-tests li { + padding: 0.4em 0.5em 0.4em 2.5em; + border-bottom: 1px solid #fff; + list-style-position: inside; +} + +#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { + display: none; +} + +#qunit-tests li strong { + cursor: pointer; +} + +#qunit-tests li a { + padding: 0.5em; + color: #c2ccd1; + text-decoration: none; +} +#qunit-tests li a:hover, +#qunit-tests li a:focus { + color: #000; +} + +#qunit-tests li .runtime { + float: right; + font-size: smaller; +} + +.qunit-assert-list { + margin-top: 0.5em; + padding: 0.5em; + + background-color: #fff; + + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.qunit-collapsed { + display: none; +} + +#qunit-tests table { + border-collapse: collapse; + margin-top: .2em; +} + +#qunit-tests th { + text-align: right; + vertical-align: top; + padding: 0 .5em 0 0; +} + +#qunit-tests td { + vertical-align: top; +} + +#qunit-tests pre { + margin: 0; + white-space: pre-wrap; + word-wrap: break-word; +} + +#qunit-tests del { + background-color: #e0f2be; + color: #374e0c; + text-decoration: none; +} + +#qunit-tests ins { + background-color: #ffcaca; + color: #500; + text-decoration: none; +} + +/*** Test Counts */ + +#qunit-tests b.counts { color: black; } +#qunit-tests b.passed { color: #5E740B; } +#qunit-tests b.failed { color: #710909; } + +#qunit-tests li li { + padding: 5px; + background-color: #fff; + border-bottom: none; + list-style-position: inside; +} + +/*** Passing Styles */ + +#qunit-tests li li.pass { + color: #3c510c; + background-color: #fff; + border-left: 10px solid #C6E746; +} + +#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } +#qunit-tests .pass .test-name { color: #366097; } + +#qunit-tests .pass .test-actual, +#qunit-tests .pass .test-expected { color: #999999; } + +#qunit-banner.qunit-pass { background-color: #C6E746; } + +/*** Failing Styles */ + +#qunit-tests li li.fail { + color: #710909; + background-color: #fff; + border-left: 10px solid #EE5757; + white-space: pre; +} + +#qunit-tests > li:last-child { + border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + -webkit-border-bottom-right-radius: 5px; + -webkit-border-bottom-left-radius: 5px; +} + +#qunit-tests .fail { color: #000000; background-color: #EE5757; } +#qunit-tests .fail .test-name, +#qunit-tests .fail .module-name { color: #000000; } + +#qunit-tests .fail .test-actual { color: #EE5757; } +#qunit-tests .fail .test-expected { color: green; } + +#qunit-banner.qunit-fail { background-color: #EE5757; } + + +/** Result */ + +#qunit-testresult { + padding: 0.5em 0.5em 0.5em 2.5em; + + color: #2b81af; + background-color: #D2E0E6; + + border-bottom: 1px solid white; +} +#qunit-testresult .module-name { + font-weight: bold; +} + +/** Fixture */ + +#qunit-fixture { + position: absolute; + top: -10000px; + left: -10000px; + width: 1000px; + height: 1000px; +} \ No newline at end of file diff --git a/vendor/jquery-mask/test/qunit.js b/vendor/jquery-mask/test/qunit.js new file mode 100755 index 0000000000..9729418707 --- /dev/null +++ b/vendor/jquery-mask/test/qunit.js @@ -0,0 +1,2152 @@ +/** + * QUnit v1.11.0 - A JavaScript Unit Testing Framework + * + * http://qunitjs.com + * + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +(function( window ) { + +var QUnit, + assert, + config, + onErrorFnPrev, + testId = 0, + fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + // Keep a local reference to Date (GH-283) + Date = window.Date, + defined = { + setTimeout: typeof window.setTimeout !== "undefined", + sessionStorage: (function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch( e ) { + return false; + } + }()) + }, + /** + * Provides a normalized error string, correcting an issue + * with IE 7 (and prior) where Error.prototype.toString is + * not properly implemented + * + * Based on http://es5.github.com/#x15.11.4.4 + * + * @param {String|Error} error + * @return {String} error message + */ + errorString = function( error ) { + var name, message, + errorString = error.toString(); + if ( errorString.substring( 0, 7 ) === "[object" ) { + name = error.name ? error.name.toString() : "Error"; + message = error.message ? error.message.toString() : ""; + if ( name && message ) { + return name + ": " + message; + } else if ( name ) { + return name; + } else if ( message ) { + return message; + } else { + return "Error"; + } + } else { + return errorString; + } + }, + /** + * Makes a clone of an object using only Array or Object as base, + * and copies over the own enumerable properties. + * + * @param {Object} obj + * @return {Object} New object with only the own properties (recursively). + */ + objectValues = function( obj ) { + // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392. + /*jshint newcap: false */ + var key, val, + vals = QUnit.is( "array", obj ) ? [] : {}; + for ( key in obj ) { + if ( hasOwn.call( obj, key ) ) { + val = obj[key]; + vals[key] = val === Object(val) ? objectValues(val) : val; + } + } + return vals; + }; + +function Test( settings ) { + extend( this, settings ); + this.assertions = []; + this.testNumber = ++Test.count; +} + +Test.count = 0; + +Test.prototype = { + init: function() { + var a, b, li, + tests = id( "qunit-tests" ); + + if ( tests ) { + b = document.createElement( "strong" ); + b.innerHTML = this.nameHtml; + + // `a` initialized at top of scope + a = document.createElement( "a" ); + a.innerHTML = "Rerun"; + a.href = QUnit.url({ testNumber: this.testNumber }); + + li = document.createElement( "li" ); + li.appendChild( b ); + li.appendChild( a ); + li.className = "running"; + li.id = this.id = "qunit-test-output" + testId++; + + tests.appendChild( li ); + } + }, + setup: function() { + if ( this.module !== config.previousModule ) { + if ( config.previousModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.previousModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0 }; + runLoggingCallbacks( "moduleStart", QUnit, { + name: this.module + }); + } else if ( config.autorun ) { + runLoggingCallbacks( "moduleStart", QUnit, { + name: this.module + }); + } + + config.current = this; + + this.testEnvironment = extend({ + setup: function() {}, + teardown: function() {} + }, this.moduleTestEnvironment ); + + this.started = +new Date(); + runLoggingCallbacks( "testStart", QUnit, { + name: this.testName, + module: this.module + }); + + // allow utility functions to access the current test environment + // TODO why?? + QUnit.current_testEnvironment = this.testEnvironment; + + if ( !config.pollution ) { + saveGlobal(); + } + if ( config.notrycatch ) { + this.testEnvironment.setup.call( this.testEnvironment ); + return; + } + try { + this.testEnvironment.setup.call( this.testEnvironment ); + } catch( e ) { + QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); + } + }, + run: function() { + config.current = this; + + var running = id( "qunit-testresult" ); + + if ( running ) { + running.innerHTML = "Running:
                  " + this.nameHtml; + } + + if ( this.async ) { + QUnit.stop(); + } + + this.callbackStarted = +new Date(); + + if ( config.notrycatch ) { + this.callback.call( this.testEnvironment, QUnit.assert ); + this.callbackRuntime = +new Date() - this.callbackStarted; + return; + } + + try { + this.callback.call( this.testEnvironment, QUnit.assert ); + this.callbackRuntime = +new Date() - this.callbackStarted; + } catch( e ) { + this.callbackRuntime = +new Date() - this.callbackStarted; + + QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + QUnit.start(); + } + } + }, + teardown: function() { + config.current = this; + if ( config.notrycatch ) { + if ( typeof this.callbackRuntime === "undefined" ) { + this.callbackRuntime = +new Date() - this.callbackStarted; + } + this.testEnvironment.teardown.call( this.testEnvironment ); + return; + } else { + try { + this.testEnvironment.teardown.call( this.testEnvironment ); + } catch( e ) { + QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); + } + } + checkPollution(); + }, + finish: function() { + config.current = this; + if ( config.requireExpects && this.expected === null ) { + QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); + } else if ( this.expected !== null && this.expected !== this.assertions.length ) { + QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); + } else if ( this.expected === null && !this.assertions.length ) { + QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); + } + + var i, assertion, a, b, time, li, ol, + test = this, + good = 0, + bad = 0, + tests = id( "qunit-tests" ); + + this.runtime = +new Date() - this.started; + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + if ( tests ) { + ol = document.createElement( "ol" ); + ol.className = "qunit-assert-list"; + + for ( i = 0; i < this.assertions.length; i++ ) { + assertion = this.assertions[i]; + + li = document.createElement( "li" ); + li.className = assertion.result ? "pass" : "fail"; + li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); + ol.appendChild( li ); + + if ( assertion.result ) { + good++; + } else { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + // store result when possible + if ( QUnit.config.reorder && defined.sessionStorage ) { + if ( bad ) { + sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); + } else { + sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); + } + } + + if ( bad === 0 ) { + addClass( ol, "qunit-collapsed" ); + } + + // `b` initialized at top of scope + b = document.createElement( "strong" ); + b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; + + addEvent(b, "click", function() { + var next = b.parentNode.lastChild, + collapsed = hasClass( next, "qunit-collapsed" ); + ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" ); + }); + + addEvent(b, "dblclick", function( e ) { + var target = e && e.target ? e.target : window.event.srcElement; + if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) { + target = target.parentNode; + } + if ( window.location && target.nodeName.toLowerCase() === "strong" ) { + window.location = QUnit.url({ testNumber: test.testNumber }); + } + }); + + // `time` initialized at top of scope + time = document.createElement( "span" ); + time.className = "runtime"; + time.innerHTML = this.runtime + " ms"; + + // `li` initialized at top of scope + li = id( this.id ); + li.className = bad ? "fail" : "pass"; + li.removeChild( li.firstChild ); + a = li.firstChild; + li.appendChild( b ); + li.appendChild( a ); + li.appendChild( time ); + li.appendChild( ol ); + + } else { + for ( i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[i].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + } + + runLoggingCallbacks( "testDone", QUnit, { + name: this.testName, + module: this.module, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length, + duration: this.runtime + }); + + QUnit.reset(); + + config.current = undefined; + }, + + queue: function() { + var bad, + test = this; + + synchronize(function() { + test.init(); + }); + function run() { + // each of these can by async + synchronize(function() { + test.setup(); + }); + synchronize(function() { + test.run(); + }); + synchronize(function() { + test.teardown(); + }); + synchronize(function() { + test.finish(); + }); + } + + // `bad` initialized at top of scope + // defer when previous test run passed, if storage is available + bad = QUnit.config.reorder && defined.sessionStorage && + +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); + + if ( bad ) { + run(); + } else { + synchronize( run, true ); + } + } +}; + +// Root QUnit object. +// `QUnit` initialized at top of scope +QUnit = { + + // call on start of module test to prepend name to all tests + module: function( name, testEnvironment ) { + config.currentModule = name; + config.currentModuleTestEnvironment = testEnvironment; + config.modules[name] = true; + }, + + asyncTest: function( testName, expected, callback ) { + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + QUnit.test( testName, expected, callback, true ); + }, + + test: function( testName, expected, callback, async ) { + var test, + nameHtml = "" + escapeText( testName ) + ""; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + if ( config.currentModule ) { + nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml; + } + + test = new Test({ + nameHtml: nameHtml, + testName: testName, + expected: expected, + async: async, + callback: callback, + module: config.currentModule, + moduleTestEnvironment: config.currentModuleTestEnvironment, + stack: sourceFromStacktrace( 2 ) + }); + + if ( !validTest( test ) ) { + return; + } + + test.queue(); + }, + + // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. + expect: function( asserts ) { + if (arguments.length === 1) { + config.current.expected = asserts; + } else { + return config.current.expected; + } + }, + + start: function( count ) { + // QUnit hasn't been initialized yet. + // Note: RequireJS (et al) may delay onLoad + if ( config.semaphore === undefined ) { + QUnit.begin(function() { + // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first + setTimeout(function() { + QUnit.start( count ); + }); + }); + return; + } + + config.semaphore -= count || 1; + // don't start until equal number of stop-calls + if ( config.semaphore > 0 ) { + return; + } + // ignore if start is called more often then stop + if ( config.semaphore < 0 ) { + config.semaphore = 0; + QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) ); + return; + } + // A slight delay, to avoid any current callbacks + if ( defined.setTimeout ) { + window.setTimeout(function() { + if ( config.semaphore > 0 ) { + return; + } + if ( config.timeout ) { + clearTimeout( config.timeout ); + } + + config.blocking = false; + process( true ); + }, 13); + } else { + config.blocking = false; + process( true ); + } + }, + + stop: function( count ) { + config.semaphore += count || 1; + config.blocking = true; + + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout( config.timeout ); + config.timeout = window.setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + config.semaphore = 1; + QUnit.start(); + }, config.testTimeout ); + } + } +}; + +// `assert` initialized at top of scope +// Asssert helpers +// All of these must either call QUnit.push() or manually do: +// - runLoggingCallbacks( "log", .. ); +// - config.current.assertions.push({ .. }); +// We attach it to the QUnit object *after* we expose the public API, +// otherwise `assert` will become a global variable in browsers (#341). +assert = { + /** + * Asserts rough true-ish result. + * @name ok + * @function + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function( result, msg ) { + if ( !config.current ) { + throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + result = !!result; + + var source, + details = { + module: config.current.module, + name: config.current.testName, + result: result, + message: msg + }; + + msg = escapeText( msg || (result ? "okay" : "failed" ) ); + msg = "" + msg + ""; + + if ( !result ) { + source = sourceFromStacktrace( 2 ); + if ( source ) { + details.source = source; + msg += "
                  Source:
                  " + escapeText( source ) + "
                  "; + } + } + runLoggingCallbacks( "log", QUnit, details ); + config.current.assertions.push({ + result: result, + message: msg + }); + }, + + /** + * Assert that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * @name equal + * @function + * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); + */ + equal: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + QUnit.push( expected == actual, actual, expected, message ); + }, + + /** + * @name notEqual + * @function + */ + notEqual: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + QUnit.push( expected != actual, actual, expected, message ); + }, + + /** + * @name propEqual + * @function + */ + propEqual: function( actual, expected, message ) { + actual = objectValues(actual); + expected = objectValues(expected); + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name notPropEqual + * @function + */ + notPropEqual: function( actual, expected, message ) { + actual = objectValues(actual); + expected = objectValues(expected); + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name deepEqual + * @function + */ + deepEqual: function( actual, expected, message ) { + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name notDeepEqual + * @function + */ + notDeepEqual: function( actual, expected, message ) { + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name strictEqual + * @function + */ + strictEqual: function( actual, expected, message ) { + QUnit.push( expected === actual, actual, expected, message ); + }, + + /** + * @name notStrictEqual + * @function + */ + notStrictEqual: function( actual, expected, message ) { + QUnit.push( expected !== actual, actual, expected, message ); + }, + + "throws": function( block, expected, message ) { + var actual, + expectedOutput = expected, + ok = false; + + // 'expected' is optional + if ( typeof expected === "string" ) { + message = expected; + expected = null; + } + + config.current.ignoreGlobalErrors = true; + try { + block.call( config.current.testEnvironment ); + } catch (e) { + actual = e; + } + config.current.ignoreGlobalErrors = false; + + if ( actual ) { + // we don't want to validate thrown error + if ( !expected ) { + ok = true; + expectedOutput = null; + // expected is a regexp + } else if ( QUnit.objectType( expected ) === "regexp" ) { + ok = expected.test( errorString( actual ) ); + // expected is a constructor + } else if ( actual instanceof expected ) { + ok = true; + // expected is a validation function which returns true is validation passed + } else if ( expected.call( {}, actual ) === true ) { + expectedOutput = null; + ok = true; + } + + QUnit.push( ok, actual, expectedOutput, message ); + } else { + QUnit.pushFailure( message, null, 'No exception was thrown.' ); + } + } +}; + +/** + * @deprecate since 1.8.0 + * Kept assertion helpers in root for backwards compatibility. + */ +extend( QUnit, assert ); + +/** + * @deprecated since 1.9.0 + * Kept root "raises()" for backwards compatibility. + * (Note that we don't introduce assert.raises). + */ +QUnit.raises = assert[ "throws" ]; + +/** + * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 + * Kept to avoid TypeErrors for undefined methods. + */ +QUnit.equals = function() { + QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); +}; +QUnit.same = function() { + QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); +}; + +// We want access to the constructor's prototype +(function() { + function F() {} + F.prototype = QUnit; + QUnit = new F(); + // Make F QUnit's constructor so that we can add to the prototype later + QUnit.constructor = F; +}()); + +/** + * Config object: Maintain internal state + * Later exposed as QUnit.config + * `config` initialized at top of scope + */ +config = { + // The queue of tests to run + queue: [], + + // block until document ready + blocking: true, + + // when enabled, show only failing tests + // gets persisted through sessionStorage and can be changed in UI via checkbox + hidepassed: false, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + // by default, modify document.title when suite is done + altertitle: true, + + // when enabled, all tests must call expect() + requireExpects: false, + + // add checkboxes that are persisted in the query-string + // when enabled, the id is set to `true` as a `QUnit.config` property + urlConfig: [ + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." + } + ], + + // Set of all modules. + modules: {}, + + // logging callback queues + begin: [], + done: [], + log: [], + testStart: [], + testDone: [], + moduleStart: [], + moduleDone: [] +}; + +// Export global variables, unless an 'exports' object exists, +// in that case we assume we're in CommonJS (dealt with on the bottom of the script) +if ( typeof exports === "undefined" ) { + extend( window, QUnit ); + + // Expose QUnit object + window.QUnit = QUnit; +} + +// Initialize more QUnit.config and QUnit.urlParams +(function() { + var i, + location = window.location || { search: "", protocol: "file:" }, + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}, + current; + + if ( params[ 0 ] ) { + for ( i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + urlParams[ current[ 0 ] ] = current[ 1 ]; + } + } + + QUnit.urlParams = urlParams; + + // String search anywhere in moduleName+testName + config.filter = urlParams.filter; + + // Exact match of the module name + config.module = urlParams.module; + + config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; + + // Figure out if we're running the tests from a server or not + QUnit.isLocal = location.protocol === "file:"; +}()); + +// Extend QUnit object, +// these after set here because they should not be exposed as global functions +extend( QUnit, { + assert: assert, + + config: config, + + // Initialize the configuration options + init: function() { + extend( config, { + stats: { all: 0, bad: 0 }, + moduleStats: { all: 0, bad: 0 }, + started: +new Date(), + updateRate: 1000, + blocking: false, + autostart: true, + autorun: false, + filter: "", + queue: [], + semaphore: 1 + }); + + var tests, banner, result, + qunit = id( "qunit" ); + + if ( qunit ) { + qunit.innerHTML = + "

                  " + escapeText( document.title ) + "

                  " + + "

                  " + + "
                  " + + "

                  " + + "
                    "; + } + + tests = id( "qunit-tests" ); + banner = id( "qunit-banner" ); + result = id( "qunit-testresult" ); + + if ( tests ) { + tests.innerHTML = ""; + } + + if ( banner ) { + banner.className = ""; + } + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...
                     "; + } + }, + + // Resets the test setup. Useful for tests that modify the DOM. + reset: function() { + var fixture = id( "qunit-fixture" ); + if ( fixture ) { + fixture.innerHTML = config.fixture; + } + }, + + // Trigger an event on an element. + // @example triggerEvent( document.body, "click" ); + triggerEvent: function( elem, type, event ) { + if ( document.createEvent ) { + event = document.createEvent( "MouseEvents" ); + event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + + elem.dispatchEvent( event ); + } else if ( elem.fireEvent ) { + elem.fireEvent( "on" + type ); + } + }, + + // Safe object type checking + is: function( type, obj ) { + return QUnit.objectType( obj ) === type; + }, + + objectType: function( obj ) { + if ( typeof obj === "undefined" ) { + return "undefined"; + // consider: typeof null === object + } + if ( obj === null ) { + return "null"; + } + + var match = toString.call( obj ).match(/^\[object\s(.*)\]$/), + type = match && match[1] || ""; + + switch ( type ) { + case "Number": + if ( isNaN(obj) ) { + return "nan"; + } + return "number"; + case "String": + case "Boolean": + case "Array": + case "Date": + case "RegExp": + case "Function": + return type.toLowerCase(); + } + if ( typeof obj === "object" ) { + return "object"; + } + return undefined; + }, + + push: function( result, actual, expected, message ) { + if ( !config.current ) { + throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); + } + + var output, source, + details = { + module: config.current.module, + name: config.current.testName, + result: result, + message: message, + actual: actual, + expected: expected + }; + + message = escapeText( message ) || ( result ? "okay" : "failed" ); + message = "" + message + ""; + output = message; + + if ( !result ) { + expected = escapeText( QUnit.jsDump.parse(expected) ); + actual = escapeText( QUnit.jsDump.parse(actual) ); + output += ""; + + if ( actual !== expected ) { + output += ""; + output += ""; + } + + source = sourceFromStacktrace(); + + if ( source ) { + details.source = source; + output += ""; + } + + output += "
                    Expected:
                    " + expected + "
                    Result:
                    " + actual + "
                    Diff:
                    " + QUnit.diff( expected, actual ) + "
                    Source:
                    " + escapeText( source ) + "
                    "; + } + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: !!result, + message: output + }); + }, + + pushFailure: function( message, source, actual ) { + if ( !config.current ) { + throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + + var output, + details = { + module: config.current.module, + name: config.current.testName, + result: false, + message: message + }; + + message = escapeText( message ) || "error"; + message = "" + message + ""; + output = message; + + output += ""; + + if ( actual ) { + output += ""; + } + + if ( source ) { + details.source = source; + output += ""; + } + + output += "
                    Result:
                    " + escapeText( actual ) + "
                    Source:
                    " + escapeText( source ) + "
                    "; + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: false, + message: output + }); + }, + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var key, + querystring = "?"; + + for ( key in params ) { + if ( !hasOwn.call( params, key ) ) { + continue; + } + querystring += encodeURIComponent( key ) + "=" + + encodeURIComponent( params[ key ] ) + "&"; + } + return window.location.protocol + "//" + window.location.host + + window.location.pathname + querystring.slice( 0, -1 ); + }, + + extend: extend, + id: id, + addEvent: addEvent + // load, equiv, jsDump, diff: Attached later +}); + +/** + * @deprecated: Created for backwards compatibility with test runner that set the hook function + * into QUnit.{hook}, instead of invoking it and passing the hook function. + * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. + * Doing this allows us to tell if the following methods have been overwritten on the actual + * QUnit object. + */ +extend( QUnit.constructor.prototype, { + + // Logging callbacks; all receive a single argument with the listed properties + // run test/logs.html for any related changes + begin: registerLoggingCallback( "begin" ), + + // done: { failed, passed, total, runtime } + done: registerLoggingCallback( "done" ), + + // log: { result, actual, expected, message } + log: registerLoggingCallback( "log" ), + + // testStart: { name } + testStart: registerLoggingCallback( "testStart" ), + + // testDone: { name, failed, passed, total, duration } + testDone: registerLoggingCallback( "testDone" ), + + // moduleStart: { name } + moduleStart: registerLoggingCallback( "moduleStart" ), + + // moduleDone: { name, failed, passed, total } + moduleDone: registerLoggingCallback( "moduleDone" ) +}); + +if ( typeof document === "undefined" || document.readyState === "complete" ) { + config.autorun = true; +} + +QUnit.load = function() { + runLoggingCallbacks( "begin", QUnit, {} ); + + // Initialize the config, saving the execution queue + var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, + urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter, + numModules = 0, + moduleFilterHtml = "", + urlConfigHtml = "", + oldconfig = extend( {}, config ); + + QUnit.init(); + extend(config, oldconfig); + + config.blocking = false; + + len = config.urlConfig.length; + + for ( i = 0; i < len; i++ ) { + val = config.urlConfig[i]; + if ( typeof val === "string" ) { + val = { + id: val, + label: val, + tooltip: "[no tooltip available]" + }; + } + config[ val.id ] = QUnit.urlParams[ val.id ]; + urlConfigHtml += ""; + } + + moduleFilterHtml += ""; + + // `userAgent` initialized at top of scope + userAgent = id( "qunit-userAgent" ); + if ( userAgent ) { + userAgent.innerHTML = navigator.userAgent; + } + + // `banner` initialized at top of scope + banner = id( "qunit-header" ); + if ( banner ) { + banner.innerHTML = "" + banner.innerHTML + " "; + } + + // `toolbar` initialized at top of scope + toolbar = id( "qunit-testrunner-toolbar" ); + if ( toolbar ) { + // `filter` initialized at top of scope + filter = document.createElement( "input" ); + filter.type = "checkbox"; + filter.id = "qunit-filter-pass"; + + addEvent( filter, "click", function() { + var tmp, + ol = document.getElementById( "qunit-tests" ); + + if ( filter.checked ) { + ol.className = ol.className + " hidepass"; + } else { + tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; + ol.className = tmp.replace( / hidepass /, " " ); + } + if ( defined.sessionStorage ) { + if (filter.checked) { + sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); + } else { + sessionStorage.removeItem( "qunit-filter-passed-tests" ); + } + } + }); + + if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { + filter.checked = true; + // `ol` initialized at top of scope + ol = document.getElementById( "qunit-tests" ); + ol.className = ol.className + " hidepass"; + } + toolbar.appendChild( filter ); + + // `label` initialized at top of scope + label = document.createElement( "label" ); + label.setAttribute( "for", "qunit-filter-pass" ); + label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." ); + label.innerHTML = "Hide passed tests"; + toolbar.appendChild( label ); + + urlConfigCheckboxesContainer = document.createElement("span"); + urlConfigCheckboxesContainer.innerHTML = urlConfigHtml; + urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input"); + // For oldIE support: + // * Add handlers to the individual elements instead of the container + // * Use "click" instead of "change" + // * Fallback from event.target to event.srcElement + addEvents( urlConfigCheckboxes, "click", function( event ) { + var params = {}, + target = event.target || event.srcElement; + params[ target.name ] = target.checked ? true : undefined; + window.location = QUnit.url( params ); + }); + toolbar.appendChild( urlConfigCheckboxesContainer ); + + if (numModules > 1) { + moduleFilter = document.createElement( 'span' ); + moduleFilter.setAttribute( 'id', 'qunit-modulefilter-container' ); + moduleFilter.innerHTML = moduleFilterHtml; + addEvent( moduleFilter.lastChild, "change", function() { + var selectBox = moduleFilter.getElementsByTagName("select")[0], + selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value); + + window.location = QUnit.url( { module: ( selectedModule === "" ) ? undefined : selectedModule } ); + }); + toolbar.appendChild(moduleFilter); + } + } + + // `main` initialized at top of scope + main = id( "qunit-fixture" ); + if ( main ) { + config.fixture = main.innerHTML; + } + + if ( config.autostart ) { + QUnit.start(); + } +}; + +addEvent( window, "load", QUnit.load ); + +// `onErrorFnPrev` initialized at top of scope +// Preserve other handlers +onErrorFnPrev = window.onerror; + +// Cover uncaught exceptions +// Returning true will surpress the default browser handler, +// returning false will let it run. +window.onerror = function ( error, filePath, linerNr ) { + var ret = false; + if ( onErrorFnPrev ) { + ret = onErrorFnPrev( error, filePath, linerNr ); + } + + // Treat return value as window.onerror itself does, + // Only do our handling if not surpressed. + if ( ret !== true ) { + if ( QUnit.config.current ) { + if ( QUnit.config.current.ignoreGlobalErrors ) { + return true; + } + QUnit.pushFailure( error, filePath + ":" + linerNr ); + } else { + QUnit.test( "global failure", extend( function() { + QUnit.pushFailure( error, filePath + ":" + linerNr ); + }, { validTest: validTest } ) ); + } + return false; + } + + return ret; +}; + +function done() { + config.autorun = true; + + // Log the last module results + if ( config.currentModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.currentModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + + var i, key, + banner = id( "qunit-banner" ), + tests = id( "qunit-tests" ), + runtime = +new Date() - config.started, + passed = config.stats.all - config.stats.bad, + html = [ + "Tests completed in ", + runtime, + " milliseconds.
                    ", + "", + passed, + " assertions of ", + config.stats.all, + " passed, ", + config.stats.bad, + " failed." + ].join( "" ); + + if ( banner ) { + banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); + } + + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } + + if ( config.altertitle && typeof document !== "undefined" && document.title ) { + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + ( config.stats.bad ? "\u2716" : "\u2714" ), + document.title.replace( /^[\u2714\u2716] /i, "" ) + ].join( " " ); + } + + // clear own sessionStorage items if all tests passed + if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { + // `key` & `i` initialized at top of scope + for ( i = 0; i < sessionStorage.length; i++ ) { + key = sessionStorage.key( i++ ); + if ( key.indexOf( "qunit-test-" ) === 0 ) { + sessionStorage.removeItem( key ); + } + } + } + + // scroll back to top to show results + if ( window.scrollTo ) { + window.scrollTo(0, 0); + } + + runLoggingCallbacks( "done", QUnit, { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + }); +} + +/** @return Boolean: true if this test should be ran */ +function validTest( test ) { + var include, + filter = config.filter && config.filter.toLowerCase(), + module = config.module && config.module.toLowerCase(), + fullName = (test.module + ": " + test.testName).toLowerCase(); + + // Internally-generated tests are always valid + if ( test.callback && test.callback.validTest === validTest ) { + delete test.callback.validTest; + return true; + } + + if ( config.testNumber ) { + return test.testNumber === config.testNumber; + } + + if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { + return false; + } + + if ( !filter ) { + return true; + } + + include = filter.charAt( 0 ) !== "!"; + if ( !include ) { + filter = filter.slice( 1 ); + } + + // If the filter matches, we need to honour include + if ( fullName.indexOf( filter ) !== -1 ) { + return include; + } + + // Otherwise, do the opposite + return !include; +} + +// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) +// Later Safari and IE10 are supposed to support error.stack as well +// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack +function extractStacktrace( e, offset ) { + offset = offset === undefined ? 3 : offset; + + var stack, include, i; + + if ( e.stacktrace ) { + // Opera + return e.stacktrace.split( "\n" )[ offset + 3 ]; + } else if ( e.stack ) { + // Firefox, Chrome + stack = e.stack.split( "\n" ); + if (/^error$/i.test( stack[0] ) ) { + stack.shift(); + } + if ( fileName ) { + include = []; + for ( i = offset; i < stack.length; i++ ) { + if ( stack[ i ].indexOf( fileName ) !== -1 ) { + break; + } + include.push( stack[ i ] ); + } + if ( include.length ) { + return include.join( "\n" ); + } + } + return stack[ offset ]; + } else if ( e.sourceURL ) { + // Safari, PhantomJS + // hopefully one day Safari provides actual stacktraces + // exclude useless self-reference for generated Error objects + if ( /qunit.js$/.test( e.sourceURL ) ) { + return; + } + // for actual exceptions, this is useful + return e.sourceURL + ":" + e.line; + } +} +function sourceFromStacktrace( offset ) { + try { + throw new Error(); + } catch ( e ) { + return extractStacktrace( e, offset ); + } +} + +/** + * Escape text for attribute or text content. + */ +function escapeText( s ) { + if ( !s ) { + return ""; + } + s = s + ""; + // Both single quotes and double quotes (for attributes) + return s.replace( /['"<>&]/g, function( s ) { + switch( s ) { + case '\'': + return '''; + case '"': + return '"'; + case '<': + return '<'; + case '>': + return '>'; + case '&': + return '&'; + } + }); +} + +function synchronize( callback, last ) { + config.queue.push( callback ); + + if ( config.autorun && !config.blocking ) { + process( last ); + } +} + +function process( last ) { + function next() { + process( last ); + } + var start = new Date().getTime(); + config.depth = config.depth ? config.depth + 1 : 1; + + while ( config.queue.length && !config.blocking ) { + if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { + config.queue.shift()(); + } else { + window.setTimeout( next, 13 ); + break; + } + } + config.depth--; + if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { + done(); + } +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in window ) { + // in Opera sometimes DOM element ids show up here, ignore them + if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) { + continue; + } + config.pollution.push( key ); + } + } +} + +function checkPollution() { + var newGlobals, + deletedGlobals, + old = config.pollution; + + saveGlobal(); + + newGlobals = diff( config.pollution, old ); + if ( newGlobals.length > 0 ) { + QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); + } + + deletedGlobals = diff( old, config.pollution ); + if ( deletedGlobals.length > 0 ) { + QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); + } +} + +// returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var i, j, + result = a.slice(); + + for ( i = 0; i < result.length; i++ ) { + for ( j = 0; j < b.length; j++ ) { + if ( result[i] === b[j] ) { + result.splice( i, 1 ); + i--; + break; + } + } + } + return result; +} + +function extend( a, b ) { + for ( var prop in b ) { + if ( b[ prop ] === undefined ) { + delete a[ prop ]; + + // Avoid "Member not found" error in IE8 caused by setting window.constructor + } else if ( prop !== "constructor" || a !== window ) { + a[ prop ] = b[ prop ]; + } + } + + return a; +} + +/** + * @param {HTMLElement} elem + * @param {string} type + * @param {Function} fn + */ +function addEvent( elem, type, fn ) { + // Standards-based browsers + if ( elem.addEventListener ) { + elem.addEventListener( type, fn, false ); + // IE + } else { + elem.attachEvent( "on" + type, fn ); + } +} + +/** + * @param {Array|NodeList} elems + * @param {string} type + * @param {Function} fn + */ +function addEvents( elems, type, fn ) { + var i = elems.length; + while ( i-- ) { + addEvent( elems[i], type, fn ); + } +} + +function hasClass( elem, name ) { + return (" " + elem.className + " ").indexOf(" " + name + " ") > -1; +} + +function addClass( elem, name ) { + if ( !hasClass( elem, name ) ) { + elem.className += (elem.className ? " " : "") + name; + } +} + +function removeClass( elem, name ) { + var set = " " + elem.className + " "; + // Class name may appear multiple times + while ( set.indexOf(" " + name + " ") > -1 ) { + set = set.replace(" " + name + " " , " "); + } + // If possible, trim it for prettiness, but not neccecarily + elem.className = window.jQuery ? jQuery.trim( set ) : ( set.trim ? set.trim() : set ); +} + +function id( name ) { + return !!( typeof document !== "undefined" && document && document.getElementById ) && + document.getElementById( name ); +} + +function registerLoggingCallback( key ) { + return function( callback ) { + config[key].push( callback ); + }; +} + +// Supports deprecated method of completely overwriting logging callbacks +function runLoggingCallbacks( key, scope, args ) { + var i, callbacks; + if ( QUnit.hasOwnProperty( key ) ) { + QUnit[ key ].call(scope, args ); + } else { + callbacks = config[ key ]; + for ( i = 0; i < callbacks.length; i++ ) { + callbacks[ i ].call( scope, args ); + } + } +} + +// Test for equality any JavaScript type. +// Author: Philippe Rathé +QUnit.equiv = (function() { + + // Call the o related callback with the given arguments. + function bindCallbacks( o, callbacks, args ) { + var prop = QUnit.objectType( o ); + if ( prop ) { + if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { + return callbacks[ prop ].apply( callbacks, args ); + } else { + return callbacks[ prop ]; // or undefined + } + } + } + + // the real equiv function + var innerEquiv, + // stack to decide between skip/abort functions + callers = [], + // stack to avoiding loops from circular referencing + parents = [], + + getProto = Object.getPrototypeOf || function ( obj ) { + return obj.__proto__; + }, + callbacks = (function () { + + // for string, boolean, number and null + function useStrictEquality( b, a ) { + /*jshint eqeqeq:false */ + if ( b instanceof a.constructor || a instanceof b.constructor ) { + // to catch short annotaion VS 'new' annotation of a + // declaration + // e.g. var i = 1; + // var j = new Number(1); + return a == b; + } else { + return a === b; + } + } + + return { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + + "nan": function( b ) { + return isNaN( b ); + }, + + "date": function( b, a ) { + return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function( b, a ) { + return QUnit.objectType( b ) === "regexp" && + // the regex itself + a.source === b.source && + // and its modifers + a.global === b.global && + // (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline && + a.sticky === b.sticky; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function() { + var caller = callers[callers.length - 1]; + return caller !== Object && typeof caller !== "undefined"; + }, + + "array": function( b, a ) { + var i, j, len, loop; + + // b could be an object literal here + if ( QUnit.objectType( b ) !== "array" ) { + return false; + } + + len = a.length; + if ( len !== b.length ) { + // safe and faster + return false; + } + + // track reference to avoid circular references + parents.push( a ); + for ( i = 0; i < len; i++ ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + if ( parents[j] === a[i] ) { + loop = true;// dont rewalk array + } + } + if ( !loop && !innerEquiv(a[i], b[i]) ) { + parents.pop(); + return false; + } + } + parents.pop(); + return true; + }, + + "object": function( b, a ) { + var i, j, loop, + // Default to true + eq = true, + aProperties = [], + bProperties = []; + + // comparing constructors is more strict than using + // instanceof + if ( a.constructor !== b.constructor ) { + // Allow objects with no prototype to be equivalent to + // objects with Object as their constructor. + if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || + ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { + return false; + } + } + + // stack constructor before traversing properties + callers.push( a.constructor ); + // track reference to avoid circular references + parents.push( a ); + + for ( i in a ) { // be strict: don't ensures hasOwnProperty + // and go deep + loop = false; + for ( j = 0; j < parents.length; j++ ) { + if ( parents[j] === a[i] ) { + // don't go down the same path twice + loop = true; + } + } + aProperties.push(i); // collect a's properties + + if (!loop && !innerEquiv( a[i], b[i] ) ) { + eq = false; + break; + } + } + + callers.pop(); // unstack, we are done + parents.pop(); + + for ( i in b ) { + bProperties.push( i ); // collect b's properties + } + + // Ensures identical properties name + return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); + } + }; + }()); + + innerEquiv = function() { // can take multiple arguments + var args = [].slice.apply( arguments ); + if ( args.length < 2 ) { + return true; // end transition + } + + return (function( a, b ) { + if ( a === b ) { + return true; // catch the most you can + } else if ( a === null || b === null || typeof a === "undefined" || + typeof b === "undefined" || + QUnit.objectType(a) !== QUnit.objectType(b) ) { + return false; // don't lose time with error prone cases + } else { + return bindCallbacks(a, callbacks, [ b, a ]); + } + + // apply transition with (1..n) arguments + }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) ); + }; + + return innerEquiv; +}()); + +/** + * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | + * http://flesler.blogspot.com Licensed under BSD + * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 + * + * @projectDescription Advanced and extensible data dumping for Javascript. + * @version 1.0.0 + * @author Ariel Flesler + * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} + */ +QUnit.jsDump = (function() { + function quote( str ) { + return '"' + str.toString().replace( /"/g, '\\"' ) + '"'; + } + function literal( o ) { + return o + ""; + } + function join( pre, arr, post ) { + var s = jsDump.separator(), + base = jsDump.indent(), + inner = jsDump.indent(1); + if ( arr.join ) { + arr = arr.join( "," + s + inner ); + } + if ( !arr ) { + return pre + post; + } + return [ pre, inner + arr, base + post ].join(s); + } + function array( arr, stack ) { + var i = arr.length, ret = new Array(i); + this.up(); + while ( i-- ) { + ret[i] = this.parse( arr[i] , undefined , stack); + } + this.down(); + return join( "[", ret, "]" ); + } + + var reName = /^function (\w+)/, + jsDump = { + // type is used mostly internally, you can fix a (custom)type in advance + parse: function( obj, type, stack ) { + stack = stack || [ ]; + var inStack, res, + parser = this.parsers[ type || this.typeOf(obj) ]; + + type = typeof parser; + inStack = inArray( obj, stack ); + + if ( inStack !== -1 ) { + return "recursion(" + (inStack - stack.length) + ")"; + } + if ( type === "function" ) { + stack.push( obj ); + res = parser.call( this, obj, stack ); + stack.pop(); + return res; + } + return ( type === "string" ) ? parser : this.parsers.error; + }, + typeOf: function( obj ) { + var type; + if ( obj === null ) { + type = "null"; + } else if ( typeof obj === "undefined" ) { + type = "undefined"; + } else if ( QUnit.is( "regexp", obj) ) { + type = "regexp"; + } else if ( QUnit.is( "date", obj) ) { + type = "date"; + } else if ( QUnit.is( "function", obj) ) { + type = "function"; + } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { + type = "window"; + } else if ( obj.nodeType === 9 ) { + type = "document"; + } else if ( obj.nodeType ) { + type = "node"; + } else if ( + // native arrays + toString.call( obj ) === "[object Array]" || + // NodeList objects + ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) + ) { + type = "array"; + } else if ( obj.constructor === Error.prototype.constructor ) { + type = "error"; + } else { + type = typeof obj; + } + return type; + }, + separator: function() { + return this.multiline ? this.HTML ? "
                    " : "\n" : this.HTML ? " " : " "; + }, + // extra can be a number, shortcut for increasing-calling-decreasing + indent: function( extra ) { + if ( !this.multiline ) { + return ""; + } + var chr = this.indentChar; + if ( this.HTML ) { + chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); + } + return new Array( this._depth_ + (extra||0) ).join(chr); + }, + up: function( a ) { + this._depth_ += a || 1; + }, + down: function( a ) { + this._depth_ -= a || 1; + }, + setParser: function( name, parser ) { + this.parsers[name] = parser; + }, + // The next 3 are exposed so you can use them + quote: quote, + literal: literal, + join: join, + // + _depth_: 1, + // This is the list of parsers, to modify them, use jsDump.setParser + parsers: { + window: "[Window]", + document: "[Document]", + error: function(error) { + return "Error(\"" + error.message + "\")"; + }, + unknown: "[Unknown]", + "null": "null", + "undefined": "undefined", + "function": function( fn ) { + var ret = "function", + // functions never have name in IE + name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1]; + + if ( name ) { + ret += " " + name; + } + ret += "( "; + + ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); + return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); + }, + array: array, + nodelist: array, + "arguments": array, + object: function( map, stack ) { + var ret = [ ], keys, key, val, i; + QUnit.jsDump.up(); + keys = []; + for ( key in map ) { + keys.push( key ); + } + keys.sort(); + for ( i = 0; i < keys.length; i++ ) { + key = keys[ i ]; + val = map[ key ]; + ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); + } + QUnit.jsDump.down(); + return join( "{", ret, "}" ); + }, + node: function( node ) { + var len, i, val, + open = QUnit.jsDump.HTML ? "<" : "<", + close = QUnit.jsDump.HTML ? ">" : ">", + tag = node.nodeName.toLowerCase(), + ret = open + tag, + attrs = node.attributes; + + if ( attrs ) { + for ( i = 0, len = attrs.length; i < len; i++ ) { + val = attrs[i].nodeValue; + // IE6 includes all attributes in .attributes, even ones not explicitly set. + // Those have values like undefined, null, 0, false, "" or "inherit". + if ( val && val !== "inherit" ) { + ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" ); + } + } + } + ret += close; + + // Show content of TextNode or CDATASection + if ( node.nodeType === 3 || node.nodeType === 4 ) { + ret += node.nodeValue; + } + + return ret + open + "/" + tag + close; + }, + // function calls it internally, it's the arguments part of the function + functionArgs: function( fn ) { + var args, + l = fn.length; + + if ( !l ) { + return ""; + } + + args = new Array(l); + while ( l-- ) { + // 97 is 'a' + args[l] = String.fromCharCode(97+l); + } + return " " + args.join( ", " ) + " "; + }, + // object calls it internally, the key part of an item in a map + key: quote, + // function calls it internally, it's the content of the function + functionCode: "[code]", + // node calls it internally, it's an html attribute value + attribute: quote, + string: quote, + date: quote, + regexp: literal, + number: literal, + "boolean": literal + }, + // if true, entities are escaped ( <, >, \t, space and \n ) + HTML: false, + // indentation unit + indentChar: " ", + // if true, items in a collection, are separated by a \n, else just a space. + multiline: true + }; + + return jsDump; +}()); + +// from jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; +} + +/* + * Javascript Diff Algorithm + * By John Resig (http://ejohn.org/) + * Modified by Chu Alan "sprite" + * + * Released under the MIT license. + * + * More Info: + * http://ejohn.org/projects/javascript-diff-algorithm/ + * + * Usage: QUnit.diff(expected, actual) + * + * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" + */ +QUnit.diff = (function() { + /*jshint eqeqeq:false, eqnull:true */ + function diff( o, n ) { + var i, + ns = {}, + os = {}; + + for ( i = 0; i < n.length; i++ ) { + if ( !hasOwn.call( ns, n[i] ) ) { + ns[ n[i] ] = { + rows: [], + o: null + }; + } + ns[ n[i] ].rows.push( i ); + } + + for ( i = 0; i < o.length; i++ ) { + if ( !hasOwn.call( os, o[i] ) ) { + os[ o[i] ] = { + rows: [], + n: null + }; + } + os[ o[i] ].rows.push( i ); + } + + for ( i in ns ) { + if ( !hasOwn.call( ns, i ) ) { + continue; + } + if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) { + n[ ns[i].rows[0] ] = { + text: n[ ns[i].rows[0] ], + row: os[i].rows[0] + }; + o[ os[i].rows[0] ] = { + text: o[ os[i].rows[0] ], + row: ns[i].rows[0] + }; + } + } + + for ( i = 0; i < n.length - 1; i++ ) { + if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && + n[ i + 1 ] == o[ n[i].row + 1 ] ) { + + n[ i + 1 ] = { + text: n[ i + 1 ], + row: n[i].row + 1 + }; + o[ n[i].row + 1 ] = { + text: o[ n[i].row + 1 ], + row: i + 1 + }; + } + } + + for ( i = n.length - 1; i > 0; i-- ) { + if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && + n[ i - 1 ] == o[ n[i].row - 1 ]) { + + n[ i - 1 ] = { + text: n[ i - 1 ], + row: n[i].row - 1 + }; + o[ n[i].row - 1 ] = { + text: o[ n[i].row - 1 ], + row: i - 1 + }; + } + } + + return { + o: o, + n: n + }; + } + + return function( o, n ) { + o = o.replace( /\s+$/, "" ); + n = n.replace( /\s+$/, "" ); + + var i, pre, + str = "", + out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), + oSpace = o.match(/\s+/g), + nSpace = n.match(/\s+/g); + + if ( oSpace == null ) { + oSpace = [ " " ]; + } + else { + oSpace.push( " " ); + } + + if ( nSpace == null ) { + nSpace = [ " " ]; + } + else { + nSpace.push( " " ); + } + + if ( out.n.length === 0 ) { + for ( i = 0; i < out.o.length; i++ ) { + str += "" + out.o[i] + oSpace[i] + ""; + } + } + else { + if ( out.n[0].text == null ) { + for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { + str += "" + out.o[n] + oSpace[n] + ""; + } + } + + for ( i = 0; i < out.n.length; i++ ) { + if (out.n[i].text == null) { + str += "" + out.n[i] + nSpace[i] + ""; + } + else { + // `pre` initialized at top of scope + pre = ""; + + for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { + pre += "" + out.o[n] + oSpace[n] + ""; + } + str += " " + out.n[i].text + nSpace[i] + pre; + } + } + } + + return str; + }; +}()); + +// for CommonJS enviroments, export everything +if ( typeof exports !== "undefined" ) { + extend( exports, QUnit ); +} + +// get at whatever the global object is, like window in browsers +}( (function() {return this;}.call()) )); \ No newline at end of file diff --git a/vendor/jquery-mask/test/sinon-1.10.3.js b/vendor/jquery-mask/test/sinon-1.10.3.js new file mode 100755 index 0000000000..703414dd49 --- /dev/null +++ b/vendor/jquery-mask/test/sinon-1.10.3.js @@ -0,0 +1,5073 @@ +/** + * Sinon.JS 1.10.3, 2014/07/11 + * + * @author Christian Johansen (christian@cjohansen.no) + * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS + * + * (The BSD License) + * + * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Christian Johansen nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +this.sinon = (function () { +var samsam, formatio; +function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else if (typeof fn === "function") { formatio = fn(samsam); } } +define.amd = {}; +((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) || + (typeof module === "object" && + function (m) { module.exports = m(); }) || // Node + function (m) { this.samsam = m(); } // Browser globals +)(function () { + var o = Object.prototype; + var div = typeof document !== "undefined" && document.createElement("div"); + + function isNaN(value) { + // Unlike global isNaN, this avoids type coercion + // typeof check avoids IE host object issues, hat tip to + // lodash + var val = value; // JsLint thinks value !== value is "weird" + return typeof value === "number" && value !== val; + } + + function getClass(value) { + // Returns the internal [[Class]] by calling Object.prototype.toString + // with the provided value as this. Return value is a string, naming the + // internal class, e.g. "Array" + return o.toString.call(value).split(/[ \]]/)[1]; + } + + /** + * @name samsam.isArguments + * @param Object object + * + * Returns ``true`` if ``object`` is an ``arguments`` object, + * ``false`` otherwise. + */ + function isArguments(object) { + if (typeof object !== "object" || typeof object.length !== "number" || + getClass(object) === "Array") { + return false; + } + if (typeof object.callee == "function") { return true; } + try { + object[object.length] = 6; + delete object[object.length]; + } catch (e) { + return true; + } + return false; + } + + /** + * @name samsam.isElement + * @param Object object + * + * Returns ``true`` if ``object`` is a DOM element node. Unlike + * Underscore.js/lodash, this function will return ``false`` if ``object`` + * is an *element-like* object, i.e. a regular object with a ``nodeType`` + * property that holds the value ``1``. + */ + function isElement(object) { + if (!object || object.nodeType !== 1 || !div) { return false; } + try { + object.appendChild(div); + object.removeChild(div); + } catch (e) { + return false; + } + return true; + } + + /** + * @name samsam.keys + * @param Object object + * + * Return an array of own property names. + */ + function keys(object) { + var ks = [], prop; + for (prop in object) { + if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); } + } + return ks; + } + + /** + * @name samsam.isDate + * @param Object value + * + * Returns true if the object is a ``Date``, or *date-like*. Duck typing + * of date objects work by checking that the object has a ``getTime`` + * function whose return value equals the return value from the object's + * ``valueOf``. + */ + function isDate(value) { + return typeof value.getTime == "function" && + value.getTime() == value.valueOf(); + } + + /** + * @name samsam.isNegZero + * @param Object value + * + * Returns ``true`` if ``value`` is ``-0``. + */ + function isNegZero(value) { + return value === 0 && 1 / value === -Infinity; + } + + /** + * @name samsam.equal + * @param Object obj1 + * @param Object obj2 + * + * Returns ``true`` if two objects are strictly equal. Compared to + * ``===`` there are two exceptions: + * + * - NaN is considered equal to NaN + * - -0 and +0 are not considered equal + */ + function identical(obj1, obj2) { + if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) { + return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2); + } + } + + + /** + * @name samsam.deepEqual + * @param Object obj1 + * @param Object obj2 + * + * Deep equal comparison. Two values are "deep equal" if: + * + * - They are equal, according to samsam.identical + * - They are both date objects representing the same time + * - They are both arrays containing elements that are all deepEqual + * - They are objects with the same set of properties, and each property + * in ``obj1`` is deepEqual to the corresponding property in ``obj2`` + * + * Supports cyclic objects. + */ + function deepEqualCyclic(obj1, obj2) { + + // used for cyclic comparison + // contain already visited objects + var objects1 = [], + objects2 = [], + // contain pathes (position in the object structure) + // of the already visited objects + // indexes same as in objects arrays + paths1 = [], + paths2 = [], + // contains combinations of already compared objects + // in the manner: { "$1['ref']$2['ref']": true } + compared = {}; + + /** + * used to check, if the value of a property is an object + * (cyclic logic is only needed for objects) + * only needed for cyclic logic + */ + function isObject(value) { + + if (typeof value === 'object' && value !== null && + !(value instanceof Boolean) && + !(value instanceof Date) && + !(value instanceof Number) && + !(value instanceof RegExp) && + !(value instanceof String)) { + + return true; + } + + return false; + } + + /** + * returns the index of the given object in the + * given objects array, -1 if not contained + * only needed for cyclic logic + */ + function getIndex(objects, obj) { + + var i; + for (i = 0; i < objects.length; i++) { + if (objects[i] === obj) { + return i; + } + } + + return -1; + } + + // does the recursion for the deep equal check + return (function deepEqual(obj1, obj2, path1, path2) { + var type1 = typeof obj1; + var type2 = typeof obj2; + + // == null also matches undefined + if (obj1 === obj2 || + isNaN(obj1) || isNaN(obj2) || + obj1 == null || obj2 == null || + type1 !== "object" || type2 !== "object") { + + return identical(obj1, obj2); + } + + // Elements are only equal if identical(expected, actual) + if (isElement(obj1) || isElement(obj2)) { return false; } + + var isDate1 = isDate(obj1), isDate2 = isDate(obj2); + if (isDate1 || isDate2) { + if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) { + return false; + } + } + + if (obj1 instanceof RegExp && obj2 instanceof RegExp) { + if (obj1.toString() !== obj2.toString()) { return false; } + } + + var class1 = getClass(obj1); + var class2 = getClass(obj2); + var keys1 = keys(obj1); + var keys2 = keys(obj2); + + if (isArguments(obj1) || isArguments(obj2)) { + if (obj1.length !== obj2.length) { return false; } + } else { + if (type1 !== type2 || class1 !== class2 || + keys1.length !== keys2.length) { + return false; + } + } + + var key, i, l, + // following vars are used for the cyclic logic + value1, value2, + isObject1, isObject2, + index1, index2, + newPath1, newPath2; + + for (i = 0, l = keys1.length; i < l; i++) { + key = keys1[i]; + if (!o.hasOwnProperty.call(obj2, key)) { + return false; + } + + // Start of the cyclic logic + + value1 = obj1[key]; + value2 = obj2[key]; + + isObject1 = isObject(value1); + isObject2 = isObject(value2); + + // determine, if the objects were already visited + // (it's faster to check for isObject first, than to + // get -1 from getIndex for non objects) + index1 = isObject1 ? getIndex(objects1, value1) : -1; + index2 = isObject2 ? getIndex(objects2, value2) : -1; + + // determine the new pathes of the objects + // - for non cyclic objects the current path will be extended + // by current property name + // - for cyclic objects the stored path is taken + newPath1 = index1 !== -1 + ? paths1[index1] + : path1 + '[' + JSON.stringify(key) + ']'; + newPath2 = index2 !== -1 + ? paths2[index2] + : path2 + '[' + JSON.stringify(key) + ']'; + + // stop recursion if current objects are already compared + if (compared[newPath1 + newPath2]) { + return true; + } + + // remember the current objects and their pathes + if (index1 === -1 && isObject1) { + objects1.push(value1); + paths1.push(newPath1); + } + if (index2 === -1 && isObject2) { + objects2.push(value2); + paths2.push(newPath2); + } + + // remember that the current objects are already compared + if (isObject1 && isObject2) { + compared[newPath1 + newPath2] = true; + } + + // End of cyclic logic + + // neither value1 nor value2 is a cycle + // continue with next level + if (!deepEqual(value1, value2, newPath1, newPath2)) { + return false; + } + } + + return true; + + }(obj1, obj2, '$1', '$2')); + } + + var match; + + function arrayContains(array, subset) { + if (subset.length === 0) { return true; } + var i, l, j, k; + for (i = 0, l = array.length; i < l; ++i) { + if (match(array[i], subset[0])) { + for (j = 0, k = subset.length; j < k; ++j) { + if (!match(array[i + j], subset[j])) { return false; } + } + return true; + } + } + return false; + } + + /** + * @name samsam.match + * @param Object object + * @param Object matcher + * + * Compare arbitrary value ``object`` with matcher. + */ + match = function match(object, matcher) { + if (matcher && typeof matcher.test === "function") { + return matcher.test(object); + } + + if (typeof matcher === "function") { + return matcher(object) === true; + } + + if (typeof matcher === "string") { + matcher = matcher.toLowerCase(); + var notNull = typeof object === "string" || !!object; + return notNull && + (String(object)).toLowerCase().indexOf(matcher) >= 0; + } + + if (typeof matcher === "number") { + return matcher === object; + } + + if (typeof matcher === "boolean") { + return matcher === object; + } + + if (getClass(object) === "Array" && getClass(matcher) === "Array") { + return arrayContains(object, matcher); + } + + if (matcher && typeof matcher === "object") { + var prop; + for (prop in matcher) { + if (!match(object[prop], matcher[prop])) { + return false; + } + } + return true; + } + + throw new Error("Matcher was not a string, a number, a " + + "function, a boolean or an object"); + }; + + return { + isArguments: isArguments, + isElement: isElement, + isDate: isDate, + isNegZero: isNegZero, + identical: identical, + deepEqual: deepEqualCyclic, + match: match, + keys: keys + }; +}); +((typeof define === "function" && define.amd && function (m) { + define("formatio", ["samsam"], m); +}) || (typeof module === "object" && function (m) { + module.exports = m(require("samsam")); +}) || function (m) { this.formatio = m(this.samsam); } +)(function (samsam) { + + var formatio = { + excludeConstructors: ["Object", /^.$/], + quoteStrings: true + }; + + var hasOwn = Object.prototype.hasOwnProperty; + + var specialObjects = []; + if (typeof global !== "undefined") { + specialObjects.push({ object: global, value: "[object global]" }); + } + if (typeof document !== "undefined") { + specialObjects.push({ + object: document, + value: "[object HTMLDocument]" + }); + } + if (typeof window !== "undefined") { + specialObjects.push({ object: window, value: "[object Window]" }); + } + + function functionName(func) { + if (!func) { return ""; } + if (func.displayName) { return func.displayName; } + if (func.name) { return func.name; } + var matches = func.toString().match(/function\s+([^\(]+)/m); + return (matches && matches[1]) || ""; + } + + function constructorName(f, object) { + var name = functionName(object && object.constructor); + var excludes = f.excludeConstructors || + formatio.excludeConstructors || []; + + var i, l; + for (i = 0, l = excludes.length; i < l; ++i) { + if (typeof excludes[i] === "string" && excludes[i] === name) { + return ""; + } else if (excludes[i].test && excludes[i].test(name)) { + return ""; + } + } + + return name; + } + + function isCircular(object, objects) { + if (typeof object !== "object") { return false; } + var i, l; + for (i = 0, l = objects.length; i < l; ++i) { + if (objects[i] === object) { return true; } + } + return false; + } + + function ascii(f, object, processed, indent) { + if (typeof object === "string") { + var qs = f.quoteStrings; + var quote = typeof qs !== "boolean" || qs; + return processed || quote ? '"' + object + '"' : object; + } + + if (typeof object === "function" && !(object instanceof RegExp)) { + return ascii.func(object); + } + + processed = processed || []; + + if (isCircular(object, processed)) { return "[Circular]"; } + + if (Object.prototype.toString.call(object) === "[object Array]") { + return ascii.array.call(f, object, processed); + } + + if (!object) { return String((1/object) === -Infinity ? "-0" : object); } + if (samsam.isElement(object)) { return ascii.element(object); } + + if (typeof object.toString === "function" && + object.toString !== Object.prototype.toString) { + return object.toString(); + } + + var i, l; + for (i = 0, l = specialObjects.length; i < l; i++) { + if (object === specialObjects[i].object) { + return specialObjects[i].value; + } + } + + return ascii.object.call(f, object, processed, indent); + } + + ascii.func = function (func) { + return "function " + functionName(func) + "() {}"; + }; + + ascii.array = function (array, processed) { + processed = processed || []; + processed.push(array); + var i, l, pieces = []; + for (i = 0, l = array.length; i < l; ++i) { + pieces.push(ascii(this, array[i], processed)); + } + return "[" + pieces.join(", ") + "]"; + }; + + ascii.object = function (object, processed, indent) { + processed = processed || []; + processed.push(object); + indent = indent || 0; + var pieces = [], properties = samsam.keys(object).sort(); + var length = 3; + var prop, str, obj, i, l; + + for (i = 0, l = properties.length; i < l; ++i) { + prop = properties[i]; + obj = object[prop]; + + if (isCircular(obj, processed)) { + str = "[Circular]"; + } else { + str = ascii(this, obj, processed, indent + 2); + } + + str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str; + length += str.length; + pieces.push(str); + } + + var cons = constructorName(this, object); + var prefix = cons ? "[" + cons + "] " : ""; + var is = ""; + for (i = 0, l = indent; i < l; ++i) { is += " "; } + + if (length + indent > 80) { + return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + + is + "}"; + } + return prefix + "{ " + pieces.join(", ") + " }"; + }; + + ascii.element = function (element) { + var tagName = element.tagName.toLowerCase(); + var attrs = element.attributes, attr, pairs = [], attrName, i, l, val; + + for (i = 0, l = attrs.length; i < l; ++i) { + attr = attrs.item(i); + attrName = attr.nodeName.toLowerCase().replace("html:", ""); + val = attr.nodeValue; + if (attrName !== "contenteditable" || val !== "inherit") { + if (!!val) { pairs.push(attrName + "=\"" + val + "\""); } + } + } + + var formatted = "<" + tagName + (pairs.length > 0 ? " " : ""); + var content = element.innerHTML; + + if (content.length > 20) { + content = content.substr(0, 20) + "[...]"; + } + + var res = formatted + pairs.join(" ") + ">" + content + + ""; + + return res.replace(/ contentEditable="inherit"/, ""); + }; + + function Formatio(options) { + for (var opt in options) { + this[opt] = options[opt]; + } + } + + Formatio.prototype = { + functionName: functionName, + + configure: function (options) { + return new Formatio(options); + }, + + constructorName: function (object) { + return constructorName(this, object); + }, + + ascii: function (object, processed, indent) { + return ascii(this, object, processed, indent); + } + }; + + return Formatio.prototype; +}); +/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/ +/*global module, require, __dirname, document*/ +/** + * Sinon core utilities. For internal use only. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +var sinon = (function (formatio) { + var div = typeof document != "undefined" && document.createElement("div"); + var hasOwn = Object.prototype.hasOwnProperty; + + function isDOMNode(obj) { + var success = false; + + try { + obj.appendChild(div); + success = div.parentNode == obj; + } catch (e) { + return false; + } finally { + try { + obj.removeChild(div); + } catch (e) { + // Remove failed, not much we can do about that + } + } + + return success; + } + + function isElement(obj) { + return div && obj && obj.nodeType === 1 && isDOMNode(obj); + } + + function isFunction(obj) { + return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply); + } + + function isReallyNaN(val) { + return typeof val === 'number' && isNaN(val); + } + + function mirrorProperties(target, source) { + for (var prop in source) { + if (!hasOwn.call(target, prop)) { + target[prop] = source[prop]; + } + } + } + + function isRestorable (obj) { + return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon; + } + + var sinon = { + wrapMethod: function wrapMethod(object, property, method) { + if (!object) { + throw new TypeError("Should wrap property of object"); + } + + if (typeof method != "function") { + throw new TypeError("Method wrapper should be function"); + } + + var wrappedMethod = object[property], + error; + + if (!isFunction(wrappedMethod)) { + error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + + property + " as function"); + } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) { + error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); + } else if (wrappedMethod.calledBefore) { + var verb = !!wrappedMethod.returns ? "stubbed" : "spied on"; + error = new TypeError("Attempted to wrap " + property + " which is already " + verb); + } + + if (error) { + if (wrappedMethod && wrappedMethod._stack) { + error.stack += '\n--------------\n' + wrappedMethod._stack; + } + throw error; + } + + // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem + // when using hasOwn.call on objects from other frames. + var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property); + object[property] = method; + method.displayName = property; + // Set up a stack trace which can be used later to find what line of + // code the original method was created on. + method._stack = (new Error('Stack Trace for original')).stack; + + method.restore = function () { + // For prototype properties try to reset by delete first. + // If this fails (ex: localStorage on mobile safari) then force a reset + // via direct assignment. + if (!owned) { + delete object[property]; + } + if (object[property] === method) { + object[property] = wrappedMethod; + } + }; + + method.restore.sinon = true; + mirrorProperties(method, wrappedMethod); + + return method; + }, + + extend: function extend(target) { + for (var i = 1, l = arguments.length; i < l; i += 1) { + for (var prop in arguments[i]) { + if (arguments[i].hasOwnProperty(prop)) { + target[prop] = arguments[i][prop]; + } + + // DONT ENUM bug, only care about toString + if (arguments[i].hasOwnProperty("toString") && + arguments[i].toString != target.toString) { + target.toString = arguments[i].toString; + } + } + } + + return target; + }, + + create: function create(proto) { + var F = function () {}; + F.prototype = proto; + return new F(); + }, + + deepEqual: function deepEqual(a, b) { + if (sinon.match && sinon.match.isMatcher(a)) { + return a.test(b); + } + + if (typeof a != 'object' || typeof b != 'object') { + if (isReallyNaN(a) && isReallyNaN(b)) { + return true; + } else { + return a === b; + } + } + + if (isElement(a) || isElement(b)) { + return a === b; + } + + if (a === b) { + return true; + } + + if ((a === null && b !== null) || (a !== null && b === null)) { + return false; + } + + if (a instanceof RegExp && b instanceof RegExp) { + return (a.source === b.source) && (a.global === b.global) && + (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline); + } + + var aString = Object.prototype.toString.call(a); + if (aString != Object.prototype.toString.call(b)) { + return false; + } + + if (aString == "[object Date]") { + return a.valueOf() === b.valueOf(); + } + + var prop, aLength = 0, bLength = 0; + + if (aString == "[object Array]" && a.length !== b.length) { + return false; + } + + for (prop in a) { + aLength += 1; + + if (!(prop in b)) { + return false; + } + + if (!deepEqual(a[prop], b[prop])) { + return false; + } + } + + for (prop in b) { + bLength += 1; + } + + return aLength == bLength; + }, + + functionName: function functionName(func) { + var name = func.displayName || func.name; + + // Use function decomposition as a last resort to get function + // name. Does not rely on function decomposition to work - if it + // doesn't debugging will be slightly less informative + // (i.e. toString will say 'spy' rather than 'myFunc'). + if (!name) { + var matches = func.toString().match(/function ([^\s\(]+)/); + name = matches && matches[1]; + } + + return name; + }, + + functionToString: function toString() { + if (this.getCall && this.callCount) { + var thisValue, prop, i = this.callCount; + + while (i--) { + thisValue = this.getCall(i).thisValue; + + for (prop in thisValue) { + if (thisValue[prop] === this) { + return prop; + } + } + } + } + + return this.displayName || "sinon fake"; + }, + + getConfig: function (custom) { + var config = {}; + custom = custom || {}; + var defaults = sinon.defaultConfig; + + for (var prop in defaults) { + if (defaults.hasOwnProperty(prop)) { + config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop]; + } + } + + return config; + }, + + format: function (val) { + return "" + val; + }, + + defaultConfig: { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "server", "requests"], + useFakeTimers: true, + useFakeServer: true + }, + + timesInWords: function timesInWords(count) { + return count == 1 && "once" || + count == 2 && "twice" || + count == 3 && "thrice" || + (count || 0) + " times"; + }, + + calledInOrder: function (spies) { + for (var i = 1, l = spies.length; i < l; i++) { + if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) { + return false; + } + } + + return true; + }, + + orderByFirstCall: function (spies) { + return spies.sort(function (a, b) { + // uuid, won't ever be equal + var aCall = a.getCall(0); + var bCall = b.getCall(0); + var aId = aCall && aCall.callId || -1; + var bId = bCall && bCall.callId || -1; + + return aId < bId ? -1 : 1; + }); + }, + + log: function () {}, + + logError: function (label, err) { + var msg = label + " threw exception: "; + sinon.log(msg + "[" + err.name + "] " + err.message); + if (err.stack) { sinon.log(err.stack); } + + setTimeout(function () { + err.message = msg + err.message; + throw err; + }, 0); + }, + + typeOf: function (value) { + if (value === null) { + return "null"; + } + else if (value === undefined) { + return "undefined"; + } + var string = Object.prototype.toString.call(value); + return string.substring(8, string.length - 1).toLowerCase(); + }, + + createStubInstance: function (constructor) { + if (typeof constructor !== "function") { + throw new TypeError("The constructor should be a function."); + } + return sinon.stub(sinon.create(constructor.prototype)); + }, + + restore: function (object) { + if (object !== null && typeof object === "object") { + for (var prop in object) { + if (isRestorable(object[prop])) { + object[prop].restore(); + } + } + } + else if (isRestorable(object)) { + object.restore(); + } + } + }; + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd; + + function makePublicAPI(require, exports, module) { + module.exports = sinon; + sinon.spy = require("./sinon/spy"); + sinon.spyCall = require("./sinon/call"); + sinon.behavior = require("./sinon/behavior"); + sinon.stub = require("./sinon/stub"); + sinon.mock = require("./sinon/mock"); + sinon.collection = require("./sinon/collection"); + sinon.assert = require("./sinon/assert"); + sinon.sandbox = require("./sinon/sandbox"); + sinon.test = require("./sinon/test"); + sinon.testCase = require("./sinon/test_case"); + sinon.match = require("./sinon/match"); + } + + if (isAMD) { + define(makePublicAPI); + } else if (isNode) { + try { + formatio = require("formatio"); + } catch (e) {} + makePublicAPI(require, exports, module); + } + + if (formatio) { + var formatter = formatio.configure({ quoteStrings: false }); + sinon.format = function () { + return formatter.ascii.apply(formatter, arguments); + }; + } else if (isNode) { + try { + var util = require("util"); + sinon.format = function (value) { + return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value; + }; + } catch (e) { + /* Node, but no util module - would be very old, but better safe than + sorry */ + } + } + + return sinon; +}(typeof formatio == "object" && formatio)); + +/* @depend ../sinon.js */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Match functions + * + * @author Maximilian Antoni (mail@maxantoni.de) + * @license BSD + * + * Copyright (c) 2012 Maximilian Antoni + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function assertType(value, type, name) { + var actual = sinon.typeOf(value); + if (actual !== type) { + throw new TypeError("Expected type of " + name + " to be " + + type + ", but was " + actual); + } + } + + var matcher = { + toString: function () { + return this.message; + } + }; + + function isMatcher(object) { + return matcher.isPrototypeOf(object); + } + + function matchObject(expectation, actual) { + if (actual === null || actual === undefined) { + return false; + } + for (var key in expectation) { + if (expectation.hasOwnProperty(key)) { + var exp = expectation[key]; + var act = actual[key]; + if (match.isMatcher(exp)) { + if (!exp.test(act)) { + return false; + } + } else if (sinon.typeOf(exp) === "object") { + if (!matchObject(exp, act)) { + return false; + } + } else if (!sinon.deepEqual(exp, act)) { + return false; + } + } + } + return true; + } + + matcher.or = function (m2) { + if (!arguments.length) { + throw new TypeError("Matcher expected"); + } else if (!isMatcher(m2)) { + m2 = match(m2); + } + var m1 = this; + var or = sinon.create(matcher); + or.test = function (actual) { + return m1.test(actual) || m2.test(actual); + }; + or.message = m1.message + ".or(" + m2.message + ")"; + return or; + }; + + matcher.and = function (m2) { + if (!arguments.length) { + throw new TypeError("Matcher expected"); + } else if (!isMatcher(m2)) { + m2 = match(m2); + } + var m1 = this; + var and = sinon.create(matcher); + and.test = function (actual) { + return m1.test(actual) && m2.test(actual); + }; + and.message = m1.message + ".and(" + m2.message + ")"; + return and; + }; + + var match = function (expectation, message) { + var m = sinon.create(matcher); + var type = sinon.typeOf(expectation); + switch (type) { + case "object": + if (typeof expectation.test === "function") { + m.test = function (actual) { + return expectation.test(actual) === true; + }; + m.message = "match(" + sinon.functionName(expectation.test) + ")"; + return m; + } + var str = []; + for (var key in expectation) { + if (expectation.hasOwnProperty(key)) { + str.push(key + ": " + expectation[key]); + } + } + m.test = function (actual) { + return matchObject(expectation, actual); + }; + m.message = "match(" + str.join(", ") + ")"; + break; + case "number": + m.test = function (actual) { + return expectation == actual; + }; + break; + case "string": + m.test = function (actual) { + if (typeof actual !== "string") { + return false; + } + return actual.indexOf(expectation) !== -1; + }; + m.message = "match(\"" + expectation + "\")"; + break; + case "regexp": + m.test = function (actual) { + if (typeof actual !== "string") { + return false; + } + return expectation.test(actual); + }; + break; + case "function": + m.test = expectation; + if (message) { + m.message = message; + } else { + m.message = "match(" + sinon.functionName(expectation) + ")"; + } + break; + default: + m.test = function (actual) { + return sinon.deepEqual(expectation, actual); + }; + } + if (!m.message) { + m.message = "match(" + expectation + ")"; + } + return m; + }; + + match.isMatcher = isMatcher; + + match.any = match(function () { + return true; + }, "any"); + + match.defined = match(function (actual) { + return actual !== null && actual !== undefined; + }, "defined"); + + match.truthy = match(function (actual) { + return !!actual; + }, "truthy"); + + match.falsy = match(function (actual) { + return !actual; + }, "falsy"); + + match.same = function (expectation) { + return match(function (actual) { + return expectation === actual; + }, "same(" + expectation + ")"); + }; + + match.typeOf = function (type) { + assertType(type, "string", "type"); + return match(function (actual) { + return sinon.typeOf(actual) === type; + }, "typeOf(\"" + type + "\")"); + }; + + match.instanceOf = function (type) { + assertType(type, "function", "type"); + return match(function (actual) { + return actual instanceof type; + }, "instanceOf(" + sinon.functionName(type) + ")"); + }; + + function createPropertyMatcher(propertyTest, messagePrefix) { + return function (property, value) { + assertType(property, "string", "property"); + var onlyProperty = arguments.length === 1; + var message = messagePrefix + "(\"" + property + "\""; + if (!onlyProperty) { + message += ", " + value; + } + message += ")"; + return match(function (actual) { + if (actual === undefined || actual === null || + !propertyTest(actual, property)) { + return false; + } + return onlyProperty || sinon.deepEqual(value, actual[property]); + }, message); + }; + } + + match.has = createPropertyMatcher(function (actual, property) { + if (typeof actual === "object") { + return property in actual; + } + return actual[property] !== undefined; + }, "has"); + + match.hasOwn = createPropertyMatcher(function (actual, property) { + return actual.hasOwnProperty(property); + }, "hasOwn"); + + match.bool = match.typeOf("boolean"); + match.number = match.typeOf("number"); + match.string = match.typeOf("string"); + match.object = match.typeOf("object"); + match.func = match.typeOf("function"); + match.array = match.typeOf("array"); + match.regexp = match.typeOf("regexp"); + match.date = match.typeOf("date"); + + sinon.match = match; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = match; }); + } else if (commonJSModule) { + module.exports = match; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend match.js + */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Spy calls + * + * @author Christian Johansen (christian@cjohansen.no) + * @author Maximilian Antoni (mail@maxantoni.de) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + * Copyright (c) 2013 Maximilian Antoni + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function throwYieldError(proxy, text, args) { + var msg = sinon.functionName(proxy) + text; + if (args.length) { + msg += " Received [" + slice.call(args).join(", ") + "]"; + } + throw new Error(msg); + } + + var slice = Array.prototype.slice; + + var callProto = { + calledOn: function calledOn(thisValue) { + if (sinon.match && sinon.match.isMatcher(thisValue)) { + return thisValue.test(this.thisValue); + } + return this.thisValue === thisValue; + }, + + calledWith: function calledWith() { + for (var i = 0, l = arguments.length; i < l; i += 1) { + if (!sinon.deepEqual(arguments[i], this.args[i])) { + return false; + } + } + + return true; + }, + + calledWithMatch: function calledWithMatch() { + for (var i = 0, l = arguments.length; i < l; i += 1) { + var actual = this.args[i]; + var expectation = arguments[i]; + if (!sinon.match || !sinon.match(expectation).test(actual)) { + return false; + } + } + return true; + }, + + calledWithExactly: function calledWithExactly() { + return arguments.length == this.args.length && + this.calledWith.apply(this, arguments); + }, + + notCalledWith: function notCalledWith() { + return !this.calledWith.apply(this, arguments); + }, + + notCalledWithMatch: function notCalledWithMatch() { + return !this.calledWithMatch.apply(this, arguments); + }, + + returned: function returned(value) { + return sinon.deepEqual(value, this.returnValue); + }, + + threw: function threw(error) { + if (typeof error === "undefined" || !this.exception) { + return !!this.exception; + } + + return this.exception === error || this.exception.name === error; + }, + + calledWithNew: function calledWithNew() { + return this.proxy.prototype && this.thisValue instanceof this.proxy; + }, + + calledBefore: function (other) { + return this.callId < other.callId; + }, + + calledAfter: function (other) { + return this.callId > other.callId; + }, + + callArg: function (pos) { + this.args[pos](); + }, + + callArgOn: function (pos, thisValue) { + this.args[pos].apply(thisValue); + }, + + callArgWith: function (pos) { + this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1))); + }, + + callArgOnWith: function (pos, thisValue) { + var args = slice.call(arguments, 2); + this.args[pos].apply(thisValue, args); + }, + + "yield": function () { + this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0))); + }, + + yieldOn: function (thisValue) { + var args = this.args; + for (var i = 0, l = args.length; i < l; ++i) { + if (typeof args[i] === "function") { + args[i].apply(thisValue, slice.call(arguments, 1)); + return; + } + } + throwYieldError(this.proxy, " cannot yield since no callback was passed.", args); + }, + + yieldTo: function (prop) { + this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1))); + }, + + yieldToOn: function (prop, thisValue) { + var args = this.args; + for (var i = 0, l = args.length; i < l; ++i) { + if (args[i] && typeof args[i][prop] === "function") { + args[i][prop].apply(thisValue, slice.call(arguments, 2)); + return; + } + } + throwYieldError(this.proxy, " cannot yield to '" + prop + + "' since no callback was passed.", args); + }, + + toString: function () { + var callStr = this.proxy.toString() + "("; + var args = []; + + for (var i = 0, l = this.args.length; i < l; ++i) { + args.push(sinon.format(this.args[i])); + } + + callStr = callStr + args.join(", ") + ")"; + + if (typeof this.returnValue != "undefined") { + callStr += " => " + sinon.format(this.returnValue); + } + + if (this.exception) { + callStr += " !" + this.exception.name; + + if (this.exception.message) { + callStr += "(" + this.exception.message + ")"; + } + } + + return callStr; + } + }; + + callProto.invokeCallback = callProto.yield; + + function createSpyCall(spy, thisValue, args, returnValue, exception, id) { + if (typeof id !== "number") { + throw new TypeError("Call id is not a number"); + } + var proxyCall = sinon.create(callProto); + proxyCall.proxy = spy; + proxyCall.thisValue = thisValue; + proxyCall.args = args; + proxyCall.returnValue = returnValue; + proxyCall.exception = exception; + proxyCall.callId = id; + + return proxyCall; + } + createSpyCall.toString = callProto.toString; // used by mocks + + sinon.spyCall = createSpyCall; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = createSpyCall; }); + } else if (commonJSModule) { + module.exports = createSpyCall; + } +}(typeof sinon == "object" && sinon || null)); + + +/** + * @depend ../sinon.js + * @depend call.js + */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Spy functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + var push = Array.prototype.push; + var slice = Array.prototype.slice; + var callId = 0; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function spy(object, property) { + if (!property && typeof object == "function") { + return spy.create(object); + } + + if (!object && !property) { + return spy.create(function () { }); + } + + var method = object[property]; + return sinon.wrapMethod(object, property, spy.create(method)); + } + + function matchingFake(fakes, args, strict) { + if (!fakes) { + return; + } + + for (var i = 0, l = fakes.length; i < l; i++) { + if (fakes[i].matches(args, strict)) { + return fakes[i]; + } + } + } + + function incrementCallCount() { + this.called = true; + this.callCount += 1; + this.notCalled = false; + this.calledOnce = this.callCount == 1; + this.calledTwice = this.callCount == 2; + this.calledThrice = this.callCount == 3; + } + + function createCallProperties() { + this.firstCall = this.getCall(0); + this.secondCall = this.getCall(1); + this.thirdCall = this.getCall(2); + this.lastCall = this.getCall(this.callCount - 1); + } + + var vars = "a,b,c,d,e,f,g,h,i,j,k,l"; + function createProxy(func) { + // Retain the function length: + var p; + if (func.length) { + eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) + + ") { return p.invoke(func, this, slice.call(arguments)); });"); + } + else { + p = function proxy() { + return p.invoke(func, this, slice.call(arguments)); + }; + } + return p; + } + + var uuid = 0; + + // Public API + var spyApi = { + reset: function () { + this.called = false; + this.notCalled = true; + this.calledOnce = false; + this.calledTwice = false; + this.calledThrice = false; + this.callCount = 0; + this.firstCall = null; + this.secondCall = null; + this.thirdCall = null; + this.lastCall = null; + this.args = []; + this.returnValues = []; + this.thisValues = []; + this.exceptions = []; + this.callIds = []; + if (this.fakes) { + for (var i = 0; i < this.fakes.length; i++) { + this.fakes[i].reset(); + } + } + }, + + create: function create(func) { + var name; + + if (typeof func != "function") { + func = function () { }; + } else { + name = sinon.functionName(func); + } + + var proxy = createProxy(func); + + sinon.extend(proxy, spy); + delete proxy.create; + sinon.extend(proxy, func); + + proxy.reset(); + proxy.prototype = func.prototype; + proxy.displayName = name || "spy"; + proxy.toString = sinon.functionToString; + proxy._create = sinon.spy.create; + proxy.id = "spy#" + uuid++; + + return proxy; + }, + + invoke: function invoke(func, thisValue, args) { + var matching = matchingFake(this.fakes, args); + var exception, returnValue; + + incrementCallCount.call(this); + push.call(this.thisValues, thisValue); + push.call(this.args, args); + push.call(this.callIds, callId++); + + // Make call properties available from within the spied function: + createCallProperties.call(this); + + try { + if (matching) { + returnValue = matching.invoke(func, thisValue, args); + } else { + returnValue = (this.func || func).apply(thisValue, args); + } + + var thisCall = this.getCall(this.callCount - 1); + if (thisCall.calledWithNew() && typeof returnValue !== 'object') { + returnValue = thisValue; + } + } catch (e) { + exception = e; + } + + push.call(this.exceptions, exception); + push.call(this.returnValues, returnValue); + + // Make return value and exception available in the calls: + createCallProperties.call(this); + + if (exception !== undefined) { + throw exception; + } + + return returnValue; + }, + + named: function named(name) { + this.displayName = name; + return this; + }, + + getCall: function getCall(i) { + if (i < 0 || i >= this.callCount) { + return null; + } + + return sinon.spyCall(this, this.thisValues[i], this.args[i], + this.returnValues[i], this.exceptions[i], + this.callIds[i]); + }, + + getCalls: function () { + var calls = []; + var i; + + for (i = 0; i < this.callCount; i++) { + calls.push(this.getCall(i)); + } + + return calls; + }, + + calledBefore: function calledBefore(spyFn) { + if (!this.called) { + return false; + } + + if (!spyFn.called) { + return true; + } + + return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1]; + }, + + calledAfter: function calledAfter(spyFn) { + if (!this.called || !spyFn.called) { + return false; + } + + return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1]; + }, + + withArgs: function () { + var args = slice.call(arguments); + + if (this.fakes) { + var match = matchingFake(this.fakes, args, true); + + if (match) { + return match; + } + } else { + this.fakes = []; + } + + var original = this; + var fake = this._create(); + fake.matchingAguments = args; + fake.parent = this; + push.call(this.fakes, fake); + + fake.withArgs = function () { + return original.withArgs.apply(original, arguments); + }; + + for (var i = 0; i < this.args.length; i++) { + if (fake.matches(this.args[i])) { + incrementCallCount.call(fake); + push.call(fake.thisValues, this.thisValues[i]); + push.call(fake.args, this.args[i]); + push.call(fake.returnValues, this.returnValues[i]); + push.call(fake.exceptions, this.exceptions[i]); + push.call(fake.callIds, this.callIds[i]); + } + } + createCallProperties.call(fake); + + return fake; + }, + + matches: function (args, strict) { + var margs = this.matchingAguments; + + if (margs.length <= args.length && + sinon.deepEqual(margs, args.slice(0, margs.length))) { + return !strict || margs.length == args.length; + } + }, + + printf: function (format) { + var spy = this; + var args = slice.call(arguments, 1); + var formatter; + + return (format || "").replace(/%(.)/g, function (match, specifyer) { + formatter = spyApi.formatters[specifyer]; + + if (typeof formatter == "function") { + return formatter.call(null, spy, args); + } else if (!isNaN(parseInt(specifyer, 10))) { + return sinon.format(args[specifyer - 1]); + } + + return "%" + specifyer; + }); + } + }; + + function delegateToCalls(method, matchAny, actual, notCalled) { + spyApi[method] = function () { + if (!this.called) { + if (notCalled) { + return notCalled.apply(this, arguments); + } + return false; + } + + var currentCall; + var matches = 0; + + for (var i = 0, l = this.callCount; i < l; i += 1) { + currentCall = this.getCall(i); + + if (currentCall[actual || method].apply(currentCall, arguments)) { + matches += 1; + + if (matchAny) { + return true; + } + } + } + + return matches === this.callCount; + }; + } + + delegateToCalls("calledOn", true); + delegateToCalls("alwaysCalledOn", false, "calledOn"); + delegateToCalls("calledWith", true); + delegateToCalls("calledWithMatch", true); + delegateToCalls("alwaysCalledWith", false, "calledWith"); + delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch"); + delegateToCalls("calledWithExactly", true); + delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly"); + delegateToCalls("neverCalledWith", false, "notCalledWith", + function () { return true; }); + delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch", + function () { return true; }); + delegateToCalls("threw", true); + delegateToCalls("alwaysThrew", false, "threw"); + delegateToCalls("returned", true); + delegateToCalls("alwaysReturned", false, "returned"); + delegateToCalls("calledWithNew", true); + delegateToCalls("alwaysCalledWithNew", false, "calledWithNew"); + delegateToCalls("callArg", false, "callArgWith", function () { + throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); + }); + spyApi.callArgWith = spyApi.callArg; + delegateToCalls("callArgOn", false, "callArgOnWith", function () { + throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); + }); + spyApi.callArgOnWith = spyApi.callArgOn; + delegateToCalls("yield", false, "yield", function () { + throw new Error(this.toString() + " cannot yield since it was not yet invoked."); + }); + // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode. + spyApi.invokeCallback = spyApi.yield; + delegateToCalls("yieldOn", false, "yieldOn", function () { + throw new Error(this.toString() + " cannot yield since it was not yet invoked."); + }); + delegateToCalls("yieldTo", false, "yieldTo", function (property) { + throw new Error(this.toString() + " cannot yield to '" + property + + "' since it was not yet invoked."); + }); + delegateToCalls("yieldToOn", false, "yieldToOn", function (property) { + throw new Error(this.toString() + " cannot yield to '" + property + + "' since it was not yet invoked."); + }); + + spyApi.formatters = { + "c": function (spy) { + return sinon.timesInWords(spy.callCount); + }, + + "n": function (spy) { + return spy.toString(); + }, + + "C": function (spy) { + var calls = []; + + for (var i = 0, l = spy.callCount; i < l; ++i) { + var stringifiedCall = " " + spy.getCall(i).toString(); + if (/\n/.test(calls[i - 1])) { + stringifiedCall = "\n" + stringifiedCall; + } + push.call(calls, stringifiedCall); + } + + return calls.length > 0 ? "\n" + calls.join("\n") : ""; + }, + + "t": function (spy) { + var objects = []; + + for (var i = 0, l = spy.callCount; i < l; ++i) { + push.call(objects, sinon.format(spy.thisValues[i])); + } + + return objects.join(", "); + }, + + "*": function (spy, args) { + var formatted = []; + + for (var i = 0, l = args.length; i < l; ++i) { + push.call(formatted, sinon.format(args[i])); + } + + return formatted.join(", "); + } + }; + + sinon.extend(spy, spyApi); + + spy.spyCall = sinon.spyCall; + sinon.spy = spy; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = spy; }); + } else if (commonJSModule) { + module.exports = spy; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + */ +/*jslint eqeqeq: false, onevar: false*/ +/*global module, require, sinon, process, setImmediate, setTimeout*/ +/** + * Stub behavior + * + * @author Christian Johansen (christian@cjohansen.no) + * @author Tim Fischbach (mail@timfischbach.de) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + var slice = Array.prototype.slice; + var join = Array.prototype.join; + var proto; + + var nextTick = (function () { + if (typeof process === "object" && typeof process.nextTick === "function") { + return process.nextTick; + } else if (typeof setImmediate === "function") { + return setImmediate; + } else { + return function (callback) { + setTimeout(callback, 0); + }; + } + })(); + + function throwsException(error, message) { + if (typeof error == "string") { + this.exception = new Error(message || ""); + this.exception.name = error; + } else if (!error) { + this.exception = new Error("Error"); + } else { + this.exception = error; + } + + return this; + } + + function getCallback(behavior, args) { + var callArgAt = behavior.callArgAt; + + if (callArgAt < 0) { + var callArgProp = behavior.callArgProp; + + for (var i = 0, l = args.length; i < l; ++i) { + if (!callArgProp && typeof args[i] == "function") { + return args[i]; + } + + if (callArgProp && args[i] && + typeof args[i][callArgProp] == "function") { + return args[i][callArgProp]; + } + } + + return null; + } + + return args[callArgAt]; + } + + function getCallbackError(behavior, func, args) { + if (behavior.callArgAt < 0) { + var msg; + + if (behavior.callArgProp) { + msg = sinon.functionName(behavior.stub) + + " expected to yield to '" + behavior.callArgProp + + "', but no object with such a property was passed."; + } else { + msg = sinon.functionName(behavior.stub) + + " expected to yield, but no callback was passed."; + } + + if (args.length > 0) { + msg += " Received [" + join.call(args, ", ") + "]"; + } + + return msg; + } + + return "argument at index " + behavior.callArgAt + " is not a function: " + func; + } + + function callCallback(behavior, args) { + if (typeof behavior.callArgAt == "number") { + var func = getCallback(behavior, args); + + if (typeof func != "function") { + throw new TypeError(getCallbackError(behavior, func, args)); + } + + if (behavior.callbackAsync) { + nextTick(function() { + func.apply(behavior.callbackContext, behavior.callbackArguments); + }); + } else { + func.apply(behavior.callbackContext, behavior.callbackArguments); + } + } + } + + proto = { + create: function(stub) { + var behavior = sinon.extend({}, sinon.behavior); + delete behavior.create; + behavior.stub = stub; + + return behavior; + }, + + isPresent: function() { + return (typeof this.callArgAt == 'number' || + this.exception || + typeof this.returnArgAt == 'number' || + this.returnThis || + this.returnValueDefined); + }, + + invoke: function(context, args) { + callCallback(this, args); + + if (this.exception) { + throw this.exception; + } else if (typeof this.returnArgAt == 'number') { + return args[this.returnArgAt]; + } else if (this.returnThis) { + return context; + } + + return this.returnValue; + }, + + onCall: function(index) { + return this.stub.onCall(index); + }, + + onFirstCall: function() { + return this.stub.onFirstCall(); + }, + + onSecondCall: function() { + return this.stub.onSecondCall(); + }, + + onThirdCall: function() { + return this.stub.onThirdCall(); + }, + + withArgs: function(/* arguments */) { + throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' + + 'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.'); + }, + + callsArg: function callsArg(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.callArgAt = pos; + this.callbackArguments = []; + this.callbackContext = undefined; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + callsArgOn: function callsArgOn(pos, context) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = pos; + this.callbackArguments = []; + this.callbackContext = context; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + callsArgWith: function callsArgWith(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.callArgAt = pos; + this.callbackArguments = slice.call(arguments, 1); + this.callbackContext = undefined; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + callsArgOnWith: function callsArgWith(pos, context) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = pos; + this.callbackArguments = slice.call(arguments, 2); + this.callbackContext = context; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + yields: function () { + this.callArgAt = -1; + this.callbackArguments = slice.call(arguments, 0); + this.callbackContext = undefined; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + yieldsOn: function (context) { + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = -1; + this.callbackArguments = slice.call(arguments, 1); + this.callbackContext = context; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + yieldsTo: function (prop) { + this.callArgAt = -1; + this.callbackArguments = slice.call(arguments, 1); + this.callbackContext = undefined; + this.callArgProp = prop; + this.callbackAsync = false; + + return this; + }, + + yieldsToOn: function (prop, context) { + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = -1; + this.callbackArguments = slice.call(arguments, 2); + this.callbackContext = context; + this.callArgProp = prop; + this.callbackAsync = false; + + return this; + }, + + + "throws": throwsException, + throwsException: throwsException, + + returns: function returns(value) { + this.returnValue = value; + this.returnValueDefined = true; + + return this; + }, + + returnsArg: function returnsArg(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.returnArgAt = pos; + + return this; + }, + + returnsThis: function returnsThis() { + this.returnThis = true; + + return this; + } + }; + + // create asynchronous versions of callsArg* and yields* methods + for (var method in proto) { + // need to avoid creating anotherasync versions of the newly added async methods + if (proto.hasOwnProperty(method) && + method.match(/^(callsArg|yields)/) && + !method.match(/Async/)) { + proto[method + 'Async'] = (function (syncFnName) { + return function () { + var result = this[syncFnName].apply(this, arguments); + this.callbackAsync = true; + return result; + }; + })(method); + } + } + + sinon.behavior = proto; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = proto; }); + } else if (commonJSModule) { + module.exports = proto; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend spy.js + * @depend behavior.js + */ +/*jslint eqeqeq: false, onevar: false*/ +/*global module, require, sinon*/ +/** + * Stub functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function stub(object, property, func) { + if (!!func && typeof func != "function") { + throw new TypeError("Custom stub should be function"); + } + + var wrapper; + + if (func) { + wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; + } else { + wrapper = stub.create(); + } + + if (!object && typeof property === "undefined") { + return sinon.stub.create(); + } + + if (typeof property === "undefined" && typeof object == "object") { + for (var prop in object) { + if (typeof object[prop] === "function") { + stub(object, prop); + } + } + + return object; + } + + return sinon.wrapMethod(object, property, wrapper); + } + + function getDefaultBehavior(stub) { + return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub); + } + + function getParentBehaviour(stub) { + return (stub.parent && getCurrentBehavior(stub.parent)); + } + + function getCurrentBehavior(stub) { + var behavior = stub.behaviors[stub.callCount - 1]; + return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub); + } + + var uuid = 0; + + sinon.extend(stub, (function () { + var proto = { + create: function create() { + var functionStub = function () { + return getCurrentBehavior(functionStub).invoke(this, arguments); + }; + + functionStub.id = "stub#" + uuid++; + var orig = functionStub; + functionStub = sinon.spy.create(functionStub); + functionStub.func = orig; + + sinon.extend(functionStub, stub); + functionStub._create = sinon.stub.create; + functionStub.displayName = "stub"; + functionStub.toString = sinon.functionToString; + + functionStub.defaultBehavior = null; + functionStub.behaviors = []; + + return functionStub; + }, + + resetBehavior: function () { + var i; + + this.defaultBehavior = null; + this.behaviors = []; + + delete this.returnValue; + delete this.returnArgAt; + this.returnThis = false; + + if (this.fakes) { + for (i = 0; i < this.fakes.length; i++) { + this.fakes[i].resetBehavior(); + } + } + }, + + onCall: function(index) { + if (!this.behaviors[index]) { + this.behaviors[index] = sinon.behavior.create(this); + } + + return this.behaviors[index]; + }, + + onFirstCall: function() { + return this.onCall(0); + }, + + onSecondCall: function() { + return this.onCall(1); + }, + + onThirdCall: function() { + return this.onCall(2); + } + }; + + for (var method in sinon.behavior) { + if (sinon.behavior.hasOwnProperty(method) && + !proto.hasOwnProperty(method) && + method != 'create' && + method != 'withArgs' && + method != 'invoke') { + proto[method] = (function(behaviorMethod) { + return function() { + this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this); + this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments); + return this; + }; + }(method)); + } + } + + return proto; + }())); + + sinon.stub = stub; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = stub; }); + } else if (commonJSModule) { + module.exports = stub; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend stub.js + */ +/*jslint eqeqeq: false, onevar: false, nomen: false*/ +/*global module, require, sinon*/ +/** + * Mock functions. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + var push = [].push; + var match; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + match = sinon.match; + + if (!match && commonJSModule) { + match = require("./match"); + } + + function mock(object) { + if (!object) { + return sinon.expectation.create("Anonymous mock"); + } + + return mock.create(object); + } + + sinon.mock = mock; + + sinon.extend(mock, (function () { + function each(collection, callback) { + if (!collection) { + return; + } + + for (var i = 0, l = collection.length; i < l; i += 1) { + callback(collection[i]); + } + } + + return { + create: function create(object) { + if (!object) { + throw new TypeError("object is null"); + } + + var mockObject = sinon.extend({}, mock); + mockObject.object = object; + delete mockObject.create; + + return mockObject; + }, + + expects: function expects(method) { + if (!method) { + throw new TypeError("method is falsy"); + } + + if (!this.expectations) { + this.expectations = {}; + this.proxies = []; + } + + if (!this.expectations[method]) { + this.expectations[method] = []; + var mockObject = this; + + sinon.wrapMethod(this.object, method, function () { + return mockObject.invokeMethod(method, this, arguments); + }); + + push.call(this.proxies, method); + } + + var expectation = sinon.expectation.create(method); + push.call(this.expectations[method], expectation); + + return expectation; + }, + + restore: function restore() { + var object = this.object; + + each(this.proxies, function (proxy) { + if (typeof object[proxy].restore == "function") { + object[proxy].restore(); + } + }); + }, + + verify: function verify() { + var expectations = this.expectations || {}; + var messages = [], met = []; + + each(this.proxies, function (proxy) { + each(expectations[proxy], function (expectation) { + if (!expectation.met()) { + push.call(messages, expectation.toString()); + } else { + push.call(met, expectation.toString()); + } + }); + }); + + this.restore(); + + if (messages.length > 0) { + sinon.expectation.fail(messages.concat(met).join("\n")); + } else { + sinon.expectation.pass(messages.concat(met).join("\n")); + } + + return true; + }, + + invokeMethod: function invokeMethod(method, thisValue, args) { + var expectations = this.expectations && this.expectations[method]; + var length = expectations && expectations.length || 0, i; + + for (i = 0; i < length; i += 1) { + if (!expectations[i].met() && + expectations[i].allowsCall(thisValue, args)) { + return expectations[i].apply(thisValue, args); + } + } + + var messages = [], available, exhausted = 0; + + for (i = 0; i < length; i += 1) { + if (expectations[i].allowsCall(thisValue, args)) { + available = available || expectations[i]; + } else { + exhausted += 1; + } + push.call(messages, " " + expectations[i].toString()); + } + + if (exhausted === 0) { + return available.apply(thisValue, args); + } + + messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ + proxy: method, + args: args + })); + + sinon.expectation.fail(messages.join("\n")); + } + }; + }())); + + var times = sinon.timesInWords; + + sinon.expectation = (function () { + var slice = Array.prototype.slice; + var _invoke = sinon.spy.invoke; + + function callCountInWords(callCount) { + if (callCount == 0) { + return "never called"; + } else { + return "called " + times(callCount); + } + } + + function expectedCallCountInWords(expectation) { + var min = expectation.minCalls; + var max = expectation.maxCalls; + + if (typeof min == "number" && typeof max == "number") { + var str = times(min); + + if (min != max) { + str = "at least " + str + " and at most " + times(max); + } + + return str; + } + + if (typeof min == "number") { + return "at least " + times(min); + } + + return "at most " + times(max); + } + + function receivedMinCalls(expectation) { + var hasMinLimit = typeof expectation.minCalls == "number"; + return !hasMinLimit || expectation.callCount >= expectation.minCalls; + } + + function receivedMaxCalls(expectation) { + if (typeof expectation.maxCalls != "number") { + return false; + } + + return expectation.callCount == expectation.maxCalls; + } + + function verifyMatcher(possibleMatcher, arg){ + if (match && match.isMatcher(possibleMatcher)) { + return possibleMatcher.test(arg); + } else { + return true; + } + } + + return { + minCalls: 1, + maxCalls: 1, + + create: function create(methodName) { + var expectation = sinon.extend(sinon.stub.create(), sinon.expectation); + delete expectation.create; + expectation.method = methodName; + + return expectation; + }, + + invoke: function invoke(func, thisValue, args) { + this.verifyCallAllowed(thisValue, args); + + return _invoke.apply(this, arguments); + }, + + atLeast: function atLeast(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not number"); + } + + if (!this.limitsSet) { + this.maxCalls = null; + this.limitsSet = true; + } + + this.minCalls = num; + + return this; + }, + + atMost: function atMost(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not number"); + } + + if (!this.limitsSet) { + this.minCalls = null; + this.limitsSet = true; + } + + this.maxCalls = num; + + return this; + }, + + never: function never() { + return this.exactly(0); + }, + + once: function once() { + return this.exactly(1); + }, + + twice: function twice() { + return this.exactly(2); + }, + + thrice: function thrice() { + return this.exactly(3); + }, + + exactly: function exactly(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not a number"); + } + + this.atLeast(num); + return this.atMost(num); + }, + + met: function met() { + return !this.failed && receivedMinCalls(this); + }, + + verifyCallAllowed: function verifyCallAllowed(thisValue, args) { + if (receivedMaxCalls(this)) { + this.failed = true; + sinon.expectation.fail(this.method + " already called " + times(this.maxCalls)); + } + + if ("expectedThis" in this && this.expectedThis !== thisValue) { + sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " + + this.expectedThis); + } + + if (!("expectedArguments" in this)) { + return; + } + + if (!args) { + sinon.expectation.fail(this.method + " received no arguments, expected " + + sinon.format(this.expectedArguments)); + } + + if (args.length < this.expectedArguments.length) { + sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) + + "), expected " + sinon.format(this.expectedArguments)); + } + + if (this.expectsExactArgCount && + args.length != this.expectedArguments.length) { + sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) + + "), expected " + sinon.format(this.expectedArguments)); + } + + for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { + + if (!verifyMatcher(this.expectedArguments[i],args[i])) { + sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + + ", didn't match " + this.expectedArguments.toString()); + } + + if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { + sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + + ", expected " + sinon.format(this.expectedArguments)); + } + } + }, + + allowsCall: function allowsCall(thisValue, args) { + if (this.met() && receivedMaxCalls(this)) { + return false; + } + + if ("expectedThis" in this && this.expectedThis !== thisValue) { + return false; + } + + if (!("expectedArguments" in this)) { + return true; + } + + args = args || []; + + if (args.length < this.expectedArguments.length) { + return false; + } + + if (this.expectsExactArgCount && + args.length != this.expectedArguments.length) { + return false; + } + + for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { + if (!verifyMatcher(this.expectedArguments[i],args[i])) { + return false; + } + + if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { + return false; + } + } + + return true; + }, + + withArgs: function withArgs() { + this.expectedArguments = slice.call(arguments); + return this; + }, + + withExactArgs: function withExactArgs() { + this.withArgs.apply(this, arguments); + this.expectsExactArgCount = true; + return this; + }, + + on: function on(thisValue) { + this.expectedThis = thisValue; + return this; + }, + + toString: function () { + var args = (this.expectedArguments || []).slice(); + + if (!this.expectsExactArgCount) { + push.call(args, "[...]"); + } + + var callStr = sinon.spyCall.toString.call({ + proxy: this.method || "anonymous mock expectation", + args: args + }); + + var message = callStr.replace(", [...", "[, ...") + " " + + expectedCallCountInWords(this); + + if (this.met()) { + return "Expectation met: " + message; + } + + return "Expected " + message + " (" + + callCountInWords(this.callCount) + ")"; + }, + + verify: function verify() { + if (!this.met()) { + sinon.expectation.fail(this.toString()); + } else { + sinon.expectation.pass(this.toString()); + } + + return true; + }, + + pass: function(message) { + sinon.assert.pass(message); + }, + fail: function (message) { + var exception = new Error(message); + exception.name = "ExpectationError"; + + throw exception; + } + }; + }()); + + sinon.mock = mock; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = mock; }); + } else if (commonJSModule) { + module.exports = mock; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend stub.js + * @depend mock.js + */ +/*jslint eqeqeq: false, onevar: false, forin: true*/ +/*global module, require, sinon*/ +/** + * Collections of stubs, spies and mocks. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + var push = [].push; + var hasOwnProperty = Object.prototype.hasOwnProperty; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function getFakes(fakeCollection) { + if (!fakeCollection.fakes) { + fakeCollection.fakes = []; + } + + return fakeCollection.fakes; + } + + function each(fakeCollection, method) { + var fakes = getFakes(fakeCollection); + + for (var i = 0, l = fakes.length; i < l; i += 1) { + if (typeof fakes[i][method] == "function") { + fakes[i][method](); + } + } + } + + function compact(fakeCollection) { + var fakes = getFakes(fakeCollection); + var i = 0; + while (i < fakes.length) { + fakes.splice(i, 1); + } + } + + var collection = { + verify: function resolve() { + each(this, "verify"); + }, + + restore: function restore() { + each(this, "restore"); + compact(this); + }, + + verifyAndRestore: function verifyAndRestore() { + var exception; + + try { + this.verify(); + } catch (e) { + exception = e; + } + + this.restore(); + + if (exception) { + throw exception; + } + }, + + add: function add(fake) { + push.call(getFakes(this), fake); + return fake; + }, + + spy: function spy() { + return this.add(sinon.spy.apply(sinon, arguments)); + }, + + stub: function stub(object, property, value) { + if (property) { + var original = object[property]; + + if (typeof original != "function") { + if (!hasOwnProperty.call(object, property)) { + throw new TypeError("Cannot stub non-existent own property " + property); + } + + object[property] = value; + + return this.add({ + restore: function () { + object[property] = original; + } + }); + } + } + if (!property && !!object && typeof object == "object") { + var stubbedObj = sinon.stub.apply(sinon, arguments); + + for (var prop in stubbedObj) { + if (typeof stubbedObj[prop] === "function") { + this.add(stubbedObj[prop]); + } + } + + return stubbedObj; + } + + return this.add(sinon.stub.apply(sinon, arguments)); + }, + + mock: function mock() { + return this.add(sinon.mock.apply(sinon, arguments)); + }, + + inject: function inject(obj) { + var col = this; + + obj.spy = function () { + return col.spy.apply(col, arguments); + }; + + obj.stub = function () { + return col.stub.apply(col, arguments); + }; + + obj.mock = function () { + return col.mock.apply(col, arguments); + }; + + return obj; + } + }; + + sinon.collection = collection; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = collection; }); + } else if (commonJSModule) { + module.exports = collection; + } +}(typeof sinon == "object" && sinon || null)); + +/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/ +/*global module, require, window*/ +/** + * Fake timer API + * setTimeout + * setInterval + * clearTimeout + * clearInterval + * tick + * reset + * Date + * + * Inspired by jsUnitMockTimeOut from JsUnit + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof sinon == "undefined") { + var sinon = {}; +} + +(function (global) { + // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref() + // browsers, a number. + // see https://github.com/cjohansen/Sinon.JS/pull/436 + var timeoutResult = setTimeout(function() {}, 0); + var addTimerReturnsObject = typeof timeoutResult === 'object'; + clearTimeout(timeoutResult); + + var id = 1; + + function addTimer(args, recurring) { + if (args.length === 0) { + throw new Error("Function requires at least 1 parameter"); + } + + if (typeof args[0] === "undefined") { + throw new Error("Callback must be provided to timer calls"); + } + + var toId = id++; + var delay = args[1] || 0; + + if (!this.timeouts) { + this.timeouts = {}; + } + + this.timeouts[toId] = { + id: toId, + func: args[0], + callAt: this.now + delay, + invokeArgs: Array.prototype.slice.call(args, 2) + }; + + if (recurring === true) { + this.timeouts[toId].interval = delay; + } + + if (addTimerReturnsObject) { + return { + id: toId, + ref: function() {}, + unref: function() {} + }; + } + else { + return toId; + } + } + + function parseTime(str) { + if (!str) { + return 0; + } + + var strings = str.split(":"); + var l = strings.length, i = l; + var ms = 0, parsed; + + if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { + throw new Error("tick only understands numbers and 'h:m:s'"); + } + + while (i--) { + parsed = parseInt(strings[i], 10); + + if (parsed >= 60) { + throw new Error("Invalid time " + str); + } + + ms += parsed * Math.pow(60, (l - i - 1)); + } + + return ms * 1000; + } + + function createObject(object) { + var newObject; + + if (Object.create) { + newObject = Object.create(object); + } else { + var F = function () {}; + F.prototype = object; + newObject = new F(); + } + + newObject.Date.clock = newObject; + return newObject; + } + + sinon.clock = { + now: 0, + + create: function create(now) { + var clock = createObject(this); + + if (typeof now == "number") { + clock.now = now; + } + + if (!!now && typeof now == "object") { + throw new TypeError("now should be milliseconds since UNIX epoch"); + } + + return clock; + }, + + setTimeout: function setTimeout(callback, timeout) { + return addTimer.call(this, arguments, false); + }, + + clearTimeout: function clearTimeout(timerId) { + if (!timerId) { + // null appears to be allowed in most browsers, and appears to be relied upon by some libraries, like Bootstrap carousel + return; + } + if (!this.timeouts) { + this.timeouts = []; + } + // in Node, timerId is an object with .ref()/.unref(), and + // its .id field is the actual timer id. + if (typeof timerId === 'object') { + timerId = timerId.id + } + if (timerId in this.timeouts) { + delete this.timeouts[timerId]; + } + }, + + setInterval: function setInterval(callback, timeout) { + return addTimer.call(this, arguments, true); + }, + + clearInterval: function clearInterval(timerId) { + this.clearTimeout(timerId); + }, + + setImmediate: function setImmediate(callback) { + var passThruArgs = Array.prototype.slice.call(arguments, 1); + + return addTimer.call(this, [callback, 0].concat(passThruArgs), false); + }, + + clearImmediate: function clearImmediate(timerId) { + this.clearTimeout(timerId); + }, + + tick: function tick(ms) { + ms = typeof ms == "number" ? ms : parseTime(ms); + var tickFrom = this.now, tickTo = this.now + ms, previous = this.now; + var timer = this.firstTimerInRange(tickFrom, tickTo); + + var firstException; + while (timer && tickFrom <= tickTo) { + if (this.timeouts[timer.id]) { + tickFrom = this.now = timer.callAt; + try { + this.callTimer(timer); + } catch (e) { + firstException = firstException || e; + } + } + + timer = this.firstTimerInRange(previous, tickTo); + previous = tickFrom; + } + + this.now = tickTo; + + if (firstException) { + throw firstException; + } + + return this.now; + }, + + firstTimerInRange: function (from, to) { + var timer, smallest = null, originalTimer; + + for (var id in this.timeouts) { + if (this.timeouts.hasOwnProperty(id)) { + if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) { + continue; + } + + if (smallest === null || this.timeouts[id].callAt < smallest) { + originalTimer = this.timeouts[id]; + smallest = this.timeouts[id].callAt; + + timer = { + func: this.timeouts[id].func, + callAt: this.timeouts[id].callAt, + interval: this.timeouts[id].interval, + id: this.timeouts[id].id, + invokeArgs: this.timeouts[id].invokeArgs + }; + } + } + } + + return timer || null; + }, + + callTimer: function (timer) { + if (typeof timer.interval == "number") { + this.timeouts[timer.id].callAt += timer.interval; + } else { + delete this.timeouts[timer.id]; + } + + try { + if (typeof timer.func == "function") { + timer.func.apply(null, timer.invokeArgs); + } else { + eval(timer.func); + } + } catch (e) { + var exception = e; + } + + if (!this.timeouts[timer.id]) { + if (exception) { + throw exception; + } + return; + } + + if (exception) { + throw exception; + } + }, + + reset: function reset() { + this.timeouts = {}; + }, + + Date: (function () { + var NativeDate = Date; + + function ClockDate(year, month, date, hour, minute, second, ms) { + // Defensive and verbose to avoid potential harm in passing + // explicit undefined when user does not pass argument + switch (arguments.length) { + case 0: + return new NativeDate(ClockDate.clock.now); + case 1: + return new NativeDate(year); + case 2: + return new NativeDate(year, month); + case 3: + return new NativeDate(year, month, date); + case 4: + return new NativeDate(year, month, date, hour); + case 5: + return new NativeDate(year, month, date, hour, minute); + case 6: + return new NativeDate(year, month, date, hour, minute, second); + default: + return new NativeDate(year, month, date, hour, minute, second, ms); + } + } + + return mirrorDateProperties(ClockDate, NativeDate); + }()) + }; + + function mirrorDateProperties(target, source) { + if (source.now) { + target.now = function now() { + return target.clock.now; + }; + } else { + delete target.now; + } + + if (source.toSource) { + target.toSource = function toSource() { + return source.toSource(); + }; + } else { + delete target.toSource; + } + + target.toString = function toString() { + return source.toString(); + }; + + target.prototype = source.prototype; + target.parse = source.parse; + target.UTC = source.UTC; + target.prototype.toUTCString = source.prototype.toUTCString; + + for (var prop in source) { + if (source.hasOwnProperty(prop)) { + target[prop] = source[prop]; + } + } + + return target; + } + + var methods = ["Date", "setTimeout", "setInterval", + "clearTimeout", "clearInterval"]; + + if (typeof global.setImmediate !== "undefined") { + methods.push("setImmediate"); + } + + if (typeof global.clearImmediate !== "undefined") { + methods.push("clearImmediate"); + } + + function restore() { + var method; + + for (var i = 0, l = this.methods.length; i < l; i++) { + method = this.methods[i]; + + if (global[method].hadOwnProperty) { + global[method] = this["_" + method]; + } else { + try { + delete global[method]; + } catch (e) {} + } + } + + // Prevent multiple executions which will completely remove these props + this.methods = []; + } + + function stubGlobal(method, clock) { + clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method); + clock["_" + method] = global[method]; + + if (method == "Date") { + var date = mirrorDateProperties(clock[method], global[method]); + global[method] = date; + } else { + global[method] = function () { + return clock[method].apply(clock, arguments); + }; + + for (var prop in clock[method]) { + if (clock[method].hasOwnProperty(prop)) { + global[method][prop] = clock[method][prop]; + } + } + } + + global[method].clock = clock; + } + + sinon.useFakeTimers = function useFakeTimers(now) { + var clock = sinon.clock.create(now); + clock.restore = restore; + clock.methods = Array.prototype.slice.call(arguments, + typeof now == "number" ? 1 : 0); + + if (clock.methods.length === 0) { + clock.methods = methods; + } + + for (var i = 0, l = clock.methods.length; i < l; i++) { + stubGlobal(clock.methods[i], clock); + } + + return clock; + }; +}(typeof global != "undefined" && typeof global !== "function" ? global : this)); + +sinon.timers = { + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), + clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined), + setInterval: setInterval, + clearInterval: clearInterval, + Date: Date +}; + +if (typeof module !== 'undefined' && module.exports) { + module.exports = sinon; +} + +/*jslint eqeqeq: false, onevar: false*/ +/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ +/** + * Minimal Event interface implementation + * + * Original implementation by Sven Fuchs: https://gist.github.com/995028 + * Modifications and tests by Christian Johansen. + * + * @author Sven Fuchs (svenfuchs@artweb-design.de) + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2011 Sven Fuchs, Christian Johansen + */ + +if (typeof sinon == "undefined") { + this.sinon = {}; +} + +(function () { + var push = [].push; + + sinon.Event = function Event(type, bubbles, cancelable, target) { + this.initEvent(type, bubbles, cancelable, target); + }; + + sinon.Event.prototype = { + initEvent: function(type, bubbles, cancelable, target) { + this.type = type; + this.bubbles = bubbles; + this.cancelable = cancelable; + this.target = target; + }, + + stopPropagation: function () {}, + + preventDefault: function () { + this.defaultPrevented = true; + } + }; + + sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) { + this.initEvent(type, false, false, target); + this.loaded = progressEventRaw.loaded || null; + this.total = progressEventRaw.total || null; + }; + + sinon.ProgressEvent.prototype = new sinon.Event(); + + sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent; + + sinon.CustomEvent = function CustomEvent(type, customData, target) { + this.initEvent(type, false, false, target); + this.detail = customData.detail || null; + }; + + sinon.CustomEvent.prototype = new sinon.Event(); + + sinon.CustomEvent.prototype.constructor = sinon.CustomEvent; + + sinon.EventTarget = { + addEventListener: function addEventListener(event, listener) { + this.eventListeners = this.eventListeners || {}; + this.eventListeners[event] = this.eventListeners[event] || []; + push.call(this.eventListeners[event], listener); + }, + + removeEventListener: function removeEventListener(event, listener) { + var listeners = this.eventListeners && this.eventListeners[event] || []; + + for (var i = 0, l = listeners.length; i < l; ++i) { + if (listeners[i] == listener) { + return listeners.splice(i, 1); + } + } + }, + + dispatchEvent: function dispatchEvent(event) { + var type = event.type; + var listeners = this.eventListeners && this.eventListeners[type] || []; + + for (var i = 0; i < listeners.length; i++) { + if (typeof listeners[i] == "function") { + listeners[i].call(this, event); + } else { + listeners[i].handleEvent(event); + } + } + + return !!event.defaultPrevented; + } + }; +}()); + +/** + * @depend ../../sinon.js + * @depend event.js + */ +/*jslint eqeqeq: false, onevar: false*/ +/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ +/** + * Fake XMLHttpRequest object + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +// wrapper for global +(function(global) { + if (typeof sinon === "undefined") { + global.sinon = {}; + } + + var supportsProgress = typeof ProgressEvent !== "undefined"; + var supportsCustomEvent = typeof CustomEvent !== "undefined"; + sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest }; + var xhr = sinon.xhr; + xhr.GlobalXMLHttpRequest = global.XMLHttpRequest; + xhr.GlobalActiveXObject = global.ActiveXObject; + xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined"; + xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined"; + xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX + ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false; + xhr.supportsCORS = xhr.supportsXHR && 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest()); + + /*jsl:ignore*/ + var unsafeHeaders = { + "Accept-Charset": true, + "Accept-Encoding": true, + "Connection": true, + "Content-Length": true, + "Cookie": true, + "Cookie2": true, + "Content-Transfer-Encoding": true, + "Date": true, + "Expect": true, + "Host": true, + "Keep-Alive": true, + "Referer": true, + "TE": true, + "Trailer": true, + "Transfer-Encoding": true, + "Upgrade": true, + "User-Agent": true, + "Via": true + }; + /*jsl:end*/ + + function FakeXMLHttpRequest() { + this.readyState = FakeXMLHttpRequest.UNSENT; + this.requestHeaders = {}; + this.requestBody = null; + this.status = 0; + this.statusText = ""; + this.upload = new UploadProgress(); + if (sinon.xhr.supportsCORS) { + this.withCredentials = false; + } + + + var xhr = this; + var events = ["loadstart", "load", "abort", "loadend"]; + + function addEventListener(eventName) { + xhr.addEventListener(eventName, function (event) { + var listener = xhr["on" + eventName]; + + if (listener && typeof listener == "function") { + listener.call(this, event); + } + }); + } + + for (var i = events.length - 1; i >= 0; i--) { + addEventListener(events[i]); + } + + if (typeof FakeXMLHttpRequest.onCreate == "function") { + FakeXMLHttpRequest.onCreate(this); + } + } + + // An upload object is created for each + // FakeXMLHttpRequest and allows upload + // events to be simulated using uploadProgress + // and uploadError. + function UploadProgress() { + this.eventListeners = { + "progress": [], + "load": [], + "abort": [], + "error": [] + } + } + + UploadProgress.prototype.addEventListener = function(event, listener) { + this.eventListeners[event].push(listener); + }; + + UploadProgress.prototype.removeEventListener = function(event, listener) { + var listeners = this.eventListeners[event] || []; + + for (var i = 0, l = listeners.length; i < l; ++i) { + if (listeners[i] == listener) { + return listeners.splice(i, 1); + } + } + }; + + UploadProgress.prototype.dispatchEvent = function(event) { + var listeners = this.eventListeners[event.type] || []; + + for (var i = 0, listener; (listener = listeners[i]) != null; i++) { + listener(event); + } + }; + + function verifyState(xhr) { + if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { + throw new Error("INVALID_STATE_ERR"); + } + + if (xhr.sendFlag) { + throw new Error("INVALID_STATE_ERR"); + } + } + + // filtering to enable a white-list version of Sinon FakeXhr, + // where whitelisted requests are passed through to real XHR + function each(collection, callback) { + if (!collection) return; + for (var i = 0, l = collection.length; i < l; i += 1) { + callback(collection[i]); + } + } + function some(collection, callback) { + for (var index = 0; index < collection.length; index++) { + if(callback(collection[index]) === true) return true; + } + return false; + } + // largest arity in XHR is 5 - XHR#open + var apply = function(obj,method,args) { + switch(args.length) { + case 0: return obj[method](); + case 1: return obj[method](args[0]); + case 2: return obj[method](args[0],args[1]); + case 3: return obj[method](args[0],args[1],args[2]); + case 4: return obj[method](args[0],args[1],args[2],args[3]); + case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]); + } + }; + + FakeXMLHttpRequest.filters = []; + FakeXMLHttpRequest.addFilter = function(fn) { + this.filters.push(fn) + }; + var IE6Re = /MSIE 6/; + FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) { + var xhr = new sinon.xhr.workingXHR(); + each(["open","setRequestHeader","send","abort","getResponseHeader", + "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"], + function(method) { + fakeXhr[method] = function() { + return apply(xhr,method,arguments); + }; + }); + + var copyAttrs = function(args) { + each(args, function(attr) { + try { + fakeXhr[attr] = xhr[attr] + } catch(e) { + if(!IE6Re.test(navigator.userAgent)) throw e; + } + }); + }; + + var stateChange = function() { + fakeXhr.readyState = xhr.readyState; + if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) { + copyAttrs(["status","statusText"]); + } + if(xhr.readyState >= FakeXMLHttpRequest.LOADING) { + copyAttrs(["responseText"]); + } + if(xhr.readyState === FakeXMLHttpRequest.DONE) { + copyAttrs(["responseXML"]); + } + if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr }); + }; + if(xhr.addEventListener) { + for(var event in fakeXhr.eventListeners) { + if(fakeXhr.eventListeners.hasOwnProperty(event)) { + each(fakeXhr.eventListeners[event],function(handler) { + xhr.addEventListener(event, handler); + }); + } + } + xhr.addEventListener("readystatechange",stateChange); + } else { + xhr.onreadystatechange = stateChange; + } + apply(xhr,"open",xhrArgs); + }; + FakeXMLHttpRequest.useFilters = false; + + function verifyRequestOpened(xhr) { + if (xhr.readyState != FakeXMLHttpRequest.OPENED) { + throw new Error("INVALID_STATE_ERR - " + xhr.readyState); + } + } + + function verifyRequestSent(xhr) { + if (xhr.readyState == FakeXMLHttpRequest.DONE) { + throw new Error("Request done"); + } + } + + function verifyHeadersReceived(xhr) { + if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) { + throw new Error("No headers received"); + } + } + + function verifyResponseBodyType(body) { + if (typeof body != "string") { + var error = new Error("Attempted to respond to fake XMLHttpRequest with " + + body + ", which is not a string."); + error.name = "InvalidBodyException"; + throw error; + } + } + + sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, { + async: true, + + open: function open(method, url, async, username, password) { + this.method = method; + this.url = url; + this.async = typeof async == "boolean" ? async : true; + this.username = username; + this.password = password; + this.responseText = null; + this.responseXML = null; + this.requestHeaders = {}; + this.sendFlag = false; + if(sinon.FakeXMLHttpRequest.useFilters === true) { + var xhrArgs = arguments; + var defake = some(FakeXMLHttpRequest.filters,function(filter) { + return filter.apply(this,xhrArgs) + }); + if (defake) { + return sinon.FakeXMLHttpRequest.defake(this,arguments); + } + } + this.readyStateChange(FakeXMLHttpRequest.OPENED); + }, + + readyStateChange: function readyStateChange(state) { + this.readyState = state; + + if (typeof this.onreadystatechange == "function") { + try { + this.onreadystatechange(); + } catch (e) { + sinon.logError("Fake XHR onreadystatechange handler", e); + } + } + + this.dispatchEvent(new sinon.Event("readystatechange")); + + switch (this.readyState) { + case FakeXMLHttpRequest.DONE: + this.dispatchEvent(new sinon.Event("load", false, false, this)); + this.dispatchEvent(new sinon.Event("loadend", false, false, this)); + this.upload.dispatchEvent(new sinon.Event("load", false, false, this)); + if (supportsProgress) { + this.upload.dispatchEvent(new sinon.ProgressEvent('progress', {loaded: 100, total: 100})); + } + break; + } + }, + + setRequestHeader: function setRequestHeader(header, value) { + verifyState(this); + + if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) { + throw new Error("Refused to set unsafe header \"" + header + "\""); + } + + if (this.requestHeaders[header]) { + this.requestHeaders[header] += "," + value; + } else { + this.requestHeaders[header] = value; + } + }, + + // Helps testing + setResponseHeaders: function setResponseHeaders(headers) { + verifyRequestOpened(this); + this.responseHeaders = {}; + + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + this.responseHeaders[header] = headers[header]; + } + } + + if (this.async) { + this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED); + } else { + this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED; + } + }, + + // Currently treats ALL data as a DOMString (i.e. no Document) + send: function send(data) { + verifyState(this); + + if (!/^(get|head)$/i.test(this.method)) { + if (this.requestHeaders["Content-Type"]) { + var value = this.requestHeaders["Content-Type"].split(";"); + this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8"; + } else { + this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; + } + + this.requestBody = data; + } + + this.errorFlag = false; + this.sendFlag = this.async; + this.readyStateChange(FakeXMLHttpRequest.OPENED); + + if (typeof this.onSend == "function") { + this.onSend(this); + } + + this.dispatchEvent(new sinon.Event("loadstart", false, false, this)); + }, + + abort: function abort() { + this.aborted = true; + this.responseText = null; + this.errorFlag = true; + this.requestHeaders = {}; + + if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) { + this.readyStateChange(sinon.FakeXMLHttpRequest.DONE); + this.sendFlag = false; + } + + this.readyState = sinon.FakeXMLHttpRequest.UNSENT; + + this.dispatchEvent(new sinon.Event("abort", false, false, this)); + + this.upload.dispatchEvent(new sinon.Event("abort", false, false, this)); + + if (typeof this.onerror === "function") { + this.onerror(); + } + }, + + getResponseHeader: function getResponseHeader(header) { + if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { + return null; + } + + if (/^Set-Cookie2?$/i.test(header)) { + return null; + } + + header = header.toLowerCase(); + + for (var h in this.responseHeaders) { + if (h.toLowerCase() == header) { + return this.responseHeaders[h]; + } + } + + return null; + }, + + getAllResponseHeaders: function getAllResponseHeaders() { + if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { + return ""; + } + + var headers = ""; + + for (var header in this.responseHeaders) { + if (this.responseHeaders.hasOwnProperty(header) && + !/^Set-Cookie2?$/i.test(header)) { + headers += header + ": " + this.responseHeaders[header] + "\r\n"; + } + } + + return headers; + }, + + setResponseBody: function setResponseBody(body) { + verifyRequestSent(this); + verifyHeadersReceived(this); + verifyResponseBodyType(body); + + var chunkSize = this.chunkSize || 10; + var index = 0; + this.responseText = ""; + + do { + if (this.async) { + this.readyStateChange(FakeXMLHttpRequest.LOADING); + } + + this.responseText += body.substring(index, index + chunkSize); + index += chunkSize; + } while (index < body.length); + + var type = this.getResponseHeader("Content-Type"); + + if (this.responseText && + (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) { + try { + this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); + } catch (e) { + // Unable to parse XML - no biggie + } + } + + if (this.async) { + this.readyStateChange(FakeXMLHttpRequest.DONE); + } else { + this.readyState = FakeXMLHttpRequest.DONE; + } + }, + + respond: function respond(status, headers, body) { + this.status = typeof status == "number" ? status : 200; + this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; + this.setResponseHeaders(headers || {}); + this.setResponseBody(body || ""); + }, + + uploadProgress: function uploadProgress(progressEventRaw) { + if (supportsProgress) { + this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); + } + }, + + uploadError: function uploadError(error) { + if (supportsCustomEvent) { + this.upload.dispatchEvent(new sinon.CustomEvent("error", {"detail": error})); + } + } + }); + + sinon.extend(FakeXMLHttpRequest, { + UNSENT: 0, + OPENED: 1, + HEADERS_RECEIVED: 2, + LOADING: 3, + DONE: 4 + }); + + // Borrowed from JSpec + FakeXMLHttpRequest.parseXML = function parseXML(text) { + var xmlDoc; + + if (typeof DOMParser != "undefined") { + var parser = new DOMParser(); + xmlDoc = parser.parseFromString(text, "text/xml"); + } else { + xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); + xmlDoc.async = "false"; + xmlDoc.loadXML(text); + } + + return xmlDoc; + }; + + FakeXMLHttpRequest.statusCodes = { + 100: "Continue", + 101: "Switching Protocols", + 200: "OK", + 201: "Created", + 202: "Accepted", + 203: "Non-Authoritative Information", + 204: "No Content", + 205: "Reset Content", + 206: "Partial Content", + 300: "Multiple Choice", + 301: "Moved Permanently", + 302: "Found", + 303: "See Other", + 304: "Not Modified", + 305: "Use Proxy", + 307: "Temporary Redirect", + 400: "Bad Request", + 401: "Unauthorized", + 402: "Payment Required", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 406: "Not Acceptable", + 407: "Proxy Authentication Required", + 408: "Request Timeout", + 409: "Conflict", + 410: "Gone", + 411: "Length Required", + 412: "Precondition Failed", + 413: "Request Entity Too Large", + 414: "Request-URI Too Long", + 415: "Unsupported Media Type", + 416: "Requested Range Not Satisfiable", + 417: "Expectation Failed", + 422: "Unprocessable Entity", + 500: "Internal Server Error", + 501: "Not Implemented", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", + 505: "HTTP Version Not Supported" + }; + + sinon.useFakeXMLHttpRequest = function () { + sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) { + if (xhr.supportsXHR) { + global.XMLHttpRequest = xhr.GlobalXMLHttpRequest; + } + + if (xhr.supportsActiveX) { + global.ActiveXObject = xhr.GlobalActiveXObject; + } + + delete sinon.FakeXMLHttpRequest.restore; + + if (keepOnCreate !== true) { + delete sinon.FakeXMLHttpRequest.onCreate; + } + }; + if (xhr.supportsXHR) { + global.XMLHttpRequest = sinon.FakeXMLHttpRequest; + } + + if (xhr.supportsActiveX) { + global.ActiveXObject = function ActiveXObject(objId) { + if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { + + return new sinon.FakeXMLHttpRequest(); + } + + return new xhr.GlobalActiveXObject(objId); + }; + } + + return sinon.FakeXMLHttpRequest; + }; + + sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; + +})((function(){ return typeof global === "object" ? global : this; })()); + +if (typeof module !== 'undefined' && module.exports) { + module.exports = sinon; +} + +/** + * @depend fake_xml_http_request.js + */ +/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/ +/*global module, require, window*/ +/** + * The Sinon "server" mimics a web server that receives requests from + * sinon.FakeXMLHttpRequest and provides an API to respond to those requests, + * both synchronously and asynchronously. To respond synchronuously, canned + * answers have to be provided upfront. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof sinon == "undefined") { + var sinon = {}; +} + +sinon.fakeServer = (function () { + var push = [].push; + function F() {} + + function create(proto) { + F.prototype = proto; + return new F(); + } + + function responseArray(handler) { + var response = handler; + + if (Object.prototype.toString.call(handler) != "[object Array]") { + response = [200, {}, handler]; + } + + if (typeof response[2] != "string") { + throw new TypeError("Fake server response body should be string, but was " + + typeof response[2]); + } + + return response; + } + + var wloc = typeof window !== "undefined" ? window.location : {}; + var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); + + function matchOne(response, reqMethod, reqUrl) { + var rmeth = response.method; + var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase(); + var url = response.url; + var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl)); + + return matchMethod && matchUrl; + } + + function match(response, request) { + var requestUrl = request.url; + + if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) { + requestUrl = requestUrl.replace(rCurrLoc, ""); + } + + if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { + if (typeof response.response == "function") { + var ru = response.url; + var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []); + return response.response.apply(response, args); + } + + return true; + } + + return false; + } + + return { + create: function () { + var server = create(this); + this.xhr = sinon.useFakeXMLHttpRequest(); + server.requests = []; + + this.xhr.onCreate = function (xhrObj) { + server.addRequest(xhrObj); + }; + + return server; + }, + + addRequest: function addRequest(xhrObj) { + var server = this; + push.call(this.requests, xhrObj); + + xhrObj.onSend = function () { + server.handleRequest(this); + + if (server.autoRespond && !server.responding) { + setTimeout(function () { + server.responding = false; + server.respond(); + }, server.autoRespondAfter || 10); + + server.responding = true; + } + }; + }, + + getHTTPMethod: function getHTTPMethod(request) { + if (this.fakeHTTPMethods && /post/i.test(request.method)) { + var matches = (request.requestBody || "").match(/_method=([^\b;]+)/); + return !!matches ? matches[1] : request.method; + } + + return request.method; + }, + + handleRequest: function handleRequest(xhr) { + if (xhr.async) { + if (!this.queue) { + this.queue = []; + } + + push.call(this.queue, xhr); + } else { + this.processRequest(xhr); + } + }, + + log: function(response, request) { + var str; + + str = "Request:\n" + sinon.format(request) + "\n\n"; + str += "Response:\n" + sinon.format(response) + "\n\n"; + + sinon.log(str); + }, + + respondWith: function respondWith(method, url, body) { + if (arguments.length == 1 && typeof method != "function") { + this.response = responseArray(method); + return; + } + + if (!this.responses) { this.responses = []; } + + if (arguments.length == 1) { + body = method; + url = method = null; + } + + if (arguments.length == 2) { + body = url; + url = method; + method = null; + } + + push.call(this.responses, { + method: method, + url: url, + response: typeof body == "function" ? body : responseArray(body) + }); + }, + + respond: function respond() { + if (arguments.length > 0) this.respondWith.apply(this, arguments); + var queue = this.queue || []; + var requests = queue.splice(0, queue.length); + var request; + + while(request = requests.shift()) { + this.processRequest(request); + } + }, + + processRequest: function processRequest(request) { + try { + if (request.aborted) { + return; + } + + var response = this.response || [404, {}, ""]; + + if (this.responses) { + for (var l = this.responses.length, i = l - 1; i >= 0; i--) { + if (match.call(this, this.responses[i], request)) { + response = this.responses[i].response; + break; + } + } + } + + if (request.readyState != 4) { + sinon.fakeServer.log(response, request); + + request.respond(response[0], response[1], response[2]); + } + } catch (e) { + sinon.logError("Fake server request processing", e); + } + }, + + restore: function restore() { + return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments); + } + }; +}()); + +if (typeof module !== 'undefined' && module.exports) { + module.exports = sinon; +} + +/** + * @depend fake_server.js + * @depend fake_timers.js + */ +/*jslint browser: true, eqeqeq: false, onevar: false*/ +/*global sinon*/ +/** + * Add-on for sinon.fakeServer that automatically handles a fake timer along with + * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery + * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead, + * it polls the object for completion with setInterval. Dispite the direct + * motivation, there is nothing jQuery-specific in this file, so it can be used + * in any environment where the ajax implementation depends on setInterval or + * setTimeout. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function () { + function Server() {} + Server.prototype = sinon.fakeServer; + + sinon.fakeServerWithClock = new Server(); + + sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { + if (xhr.async) { + if (typeof setTimeout.clock == "object") { + this.clock = setTimeout.clock; + } else { + this.clock = sinon.useFakeTimers(); + this.resetClock = true; + } + + if (!this.longestTimeout) { + var clockSetTimeout = this.clock.setTimeout; + var clockSetInterval = this.clock.setInterval; + var server = this; + + this.clock.setTimeout = function (fn, timeout) { + server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); + + return clockSetTimeout.apply(this, arguments); + }; + + this.clock.setInterval = function (fn, timeout) { + server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); + + return clockSetInterval.apply(this, arguments); + }; + } + } + + return sinon.fakeServer.addRequest.call(this, xhr); + }; + + sinon.fakeServerWithClock.respond = function respond() { + var returnVal = sinon.fakeServer.respond.apply(this, arguments); + + if (this.clock) { + this.clock.tick(this.longestTimeout || 0); + this.longestTimeout = 0; + + if (this.resetClock) { + this.clock.restore(); + this.resetClock = false; + } + } + + return returnVal; + }; + + sinon.fakeServerWithClock.restore = function restore() { + if (this.clock) { + this.clock.restore(); + } + + return sinon.fakeServer.restore.apply(this, arguments); + }; +}()); + +/** + * @depend ../sinon.js + * @depend collection.js + * @depend util/fake_timers.js + * @depend util/fake_server_with_clock.js + */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global require, module*/ +/** + * Manages fake collections as well as fake utilities such as Sinon's + * timers and fake XHR implementation in one convenient object. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof module !== "undefined" && module.exports && typeof require == "function") { + var sinon = require("../sinon"); + sinon.extend(sinon, require("./util/fake_timers")); +} + +(function () { + var push = [].push; + + function exposeValue(sandbox, config, key, value) { + if (!value) { + return; + } + + if (config.injectInto && !(key in config.injectInto)) { + config.injectInto[key] = value; + sandbox.injectedKeys.push(key); + } else { + push.call(sandbox.args, value); + } + } + + function prepareSandboxFromConfig(config) { + var sandbox = sinon.create(sinon.sandbox); + + if (config.useFakeServer) { + if (typeof config.useFakeServer == "object") { + sandbox.serverPrototype = config.useFakeServer; + } + + sandbox.useFakeServer(); + } + + if (config.useFakeTimers) { + if (typeof config.useFakeTimers == "object") { + sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); + } else { + sandbox.useFakeTimers(); + } + } + + return sandbox; + } + + sinon.sandbox = sinon.extend(sinon.create(sinon.collection), { + useFakeTimers: function useFakeTimers() { + this.clock = sinon.useFakeTimers.apply(sinon, arguments); + + return this.add(this.clock); + }, + + serverPrototype: sinon.fakeServer, + + useFakeServer: function useFakeServer() { + var proto = this.serverPrototype || sinon.fakeServer; + + if (!proto || !proto.create) { + return null; + } + + this.server = proto.create(); + return this.add(this.server); + }, + + inject: function (obj) { + sinon.collection.inject.call(this, obj); + + if (this.clock) { + obj.clock = this.clock; + } + + if (this.server) { + obj.server = this.server; + obj.requests = this.server.requests; + } + + return obj; + }, + + restore: function () { + sinon.collection.restore.apply(this, arguments); + this.restoreContext(); + }, + + restoreContext: function () { + if (this.injectedKeys) { + for (var i = 0, j = this.injectedKeys.length; i < j; i++) { + delete this.injectInto[this.injectedKeys[i]]; + } + this.injectedKeys = []; + } + }, + + create: function (config) { + if (!config) { + return sinon.create(sinon.sandbox); + } + + var sandbox = prepareSandboxFromConfig(config); + sandbox.args = sandbox.args || []; + sandbox.injectedKeys = []; + sandbox.injectInto = config.injectInto; + var prop, value, exposed = sandbox.inject({}); + + if (config.properties) { + for (var i = 0, l = config.properties.length; i < l; i++) { + prop = config.properties[i]; + value = exposed[prop] || prop == "sandbox" && sandbox; + exposeValue(sandbox, config, prop, value); + } + } else { + exposeValue(sandbox, config, "sandbox", value); + } + + return sandbox; + } + }); + + sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = sinon.sandbox; }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = sinon.sandbox; + } +}()); + +/** + * @depend ../sinon.js + * @depend stub.js + * @depend mock.js + * @depend sandbox.js + */ +/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Test function, sandboxes fakes + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function test(callback) { + var type = typeof callback; + + if (type != "function") { + throw new TypeError("sinon.test needs to wrap a test function, got " + type); + } + + function sinonSandboxedTest() { + var config = sinon.getConfig(sinon.config); + config.injectInto = config.injectIntoThis && this || config.injectInto; + var sandbox = sinon.sandbox.create(config); + var exception, result; + var args = Array.prototype.slice.call(arguments).concat(sandbox.args); + + try { + result = callback.apply(this, args); + } catch (e) { + exception = e; + } + + if (typeof exception !== "undefined") { + sandbox.restore(); + throw exception; + } + else { + sandbox.verifyAndRestore(); + } + + return result; + }; + + if (callback.length) { + return function sinonAsyncSandboxedTest(callback) { + return sinonSandboxedTest.apply(this, arguments); + }; + } + + return sinonSandboxedTest; + } + + test.config = { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "server", "requests"], + useFakeTimers: true, + useFakeServer: true + }; + + sinon.test = test; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = test; }); + } else if (commonJSModule) { + module.exports = test; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend test.js + */ +/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/ +/*global module, require, sinon*/ +/** + * Test case, sandboxes all test functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon || !Object.prototype.hasOwnProperty) { + return; + } + + function createTest(property, setUp, tearDown) { + return function () { + if (setUp) { + setUp.apply(this, arguments); + } + + var exception, result; + + try { + result = property.apply(this, arguments); + } catch (e) { + exception = e; + } + + if (tearDown) { + tearDown.apply(this, arguments); + } + + if (exception) { + throw exception; + } + + return result; + }; + } + + function testCase(tests, prefix) { + /*jsl:ignore*/ + if (!tests || typeof tests != "object") { + throw new TypeError("sinon.testCase needs an object with test functions"); + } + /*jsl:end*/ + + prefix = prefix || "test"; + var rPrefix = new RegExp("^" + prefix); + var methods = {}, testName, property, method; + var setUp = tests.setUp; + var tearDown = tests.tearDown; + + for (testName in tests) { + if (tests.hasOwnProperty(testName)) { + property = tests[testName]; + + if (/^(setUp|tearDown)$/.test(testName)) { + continue; + } + + if (typeof property == "function" && rPrefix.test(testName)) { + method = property; + + if (setUp || tearDown) { + method = createTest(property, setUp, tearDown); + } + + methods[testName] = sinon.test(method); + } else { + methods[testName] = tests[testName]; + } + } + } + + return methods; + } + + sinon.testCase = testCase; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = testCase; }); + } else if (commonJSModule) { + module.exports = testCase; + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend ../sinon.js + * @depend stub.js + */ +/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Assertions matching the test spy retrieval interface. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon, global) { + var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; + var slice = Array.prototype.slice; + var assert; + + if (!sinon && commonJSModule) { + sinon = require("../sinon"); + } + + if (!sinon) { + return; + } + + function verifyIsStub() { + var method; + + for (var i = 0, l = arguments.length; i < l; ++i) { + method = arguments[i]; + + if (!method) { + assert.fail("fake is not a spy"); + } + + if (typeof method != "function") { + assert.fail(method + " is not a function"); + } + + if (typeof method.getCall != "function") { + assert.fail(method + " is not stubbed"); + } + } + } + + function failAssertion(object, msg) { + object = object || global; + var failMethod = object.fail || assert.fail; + failMethod.call(object, msg); + } + + function mirrorPropAsAssertion(name, method, message) { + if (arguments.length == 2) { + message = method; + method = name; + } + + assert[name] = function (fake) { + verifyIsStub(fake); + + var args = slice.call(arguments, 1); + var failed = false; + + if (typeof method == "function") { + failed = !method(fake); + } else { + failed = typeof fake[method] == "function" ? + !fake[method].apply(fake, args) : !fake[method]; + } + + if (failed) { + failAssertion(this, fake.printf.apply(fake, [message].concat(args))); + } else { + assert.pass(name); + } + }; + } + + function exposedName(prefix, prop) { + return !prefix || /^fail/.test(prop) ? prop : + prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1); + } + + assert = { + failException: "AssertError", + + fail: function fail(message) { + var error = new Error(message); + error.name = this.failException || assert.failException; + + throw error; + }, + + pass: function pass(assertion) {}, + + callOrder: function assertCallOrder() { + verifyIsStub.apply(null, arguments); + var expected = "", actual = ""; + + if (!sinon.calledInOrder(arguments)) { + try { + expected = [].join.call(arguments, ", "); + var calls = slice.call(arguments); + var i = calls.length; + while (i) { + if (!calls[--i].called) { + calls.splice(i, 1); + } + } + actual = sinon.orderByFirstCall(calls).join(", "); + } catch (e) { + // If this fails, we'll just fall back to the blank string + } + + failAssertion(this, "expected " + expected + " to be " + + "called in order but were called as " + actual); + } else { + assert.pass("callOrder"); + } + }, + + callCount: function assertCallCount(method, count) { + verifyIsStub(method); + + if (method.callCount != count) { + var msg = "expected %n to be called " + sinon.timesInWords(count) + + " but was called %c%C"; + failAssertion(this, method.printf(msg)); + } else { + assert.pass("callCount"); + } + }, + + expose: function expose(target, options) { + if (!target) { + throw new TypeError("target is null or undefined"); + } + + var o = options || {}; + var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix; + var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail; + + for (var method in this) { + if (method != "export" && (includeFail || !/^(fail)/.test(method))) { + target[exposedName(prefix, method)] = this[method]; + } + } + + return target; + }, + + match: function match(actual, expectation) { + var matcher = sinon.match(expectation); + if (matcher.test(actual)) { + assert.pass("match"); + } else { + var formatted = [ + "expected value to match", + " expected = " + sinon.format(expectation), + " actual = " + sinon.format(actual) + ] + failAssertion(this, formatted.join("\n")); + } + } + }; + + mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called"); + mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; }, + "expected %n to not have been called but was called %c%C"); + mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C"); + mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C"); + mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C"); + mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t"); + mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t"); + mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new"); + mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new"); + mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C"); + mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C"); + mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C"); + mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C"); + mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C"); + mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C"); + mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C"); + mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C"); + mirrorPropAsAssertion("threw", "%n did not throw exception%C"); + mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C"); + + sinon.assert = assert; + + if (typeof define === "function" && define.amd) { + define(["module"], function(module) { module.exports = assert; }); + } else if (commonJSModule) { + module.exports = assert; + } +}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global)); + +/** + * @depend ../../sinon.js + * @depend event.js + */ +/*jslint eqeqeq: false, onevar: false*/ +/*global sinon, module, require, XDomainRequest*/ +/** + * Fake XDomainRequest object + */ + +if (typeof sinon == "undefined") { + this.sinon = {}; +} +sinon.xdr = { XDomainRequest: this.XDomainRequest }; + +// wrapper for global +(function (global) { + var xdr = sinon.xdr; + xdr.GlobalXDomainRequest = global.XDomainRequest; + xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined"; + xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false; + + function FakeXDomainRequest() { + this.readyState = FakeXDomainRequest.UNSENT; + this.requestBody = null; + this.requestHeaders = {}; + this.status = 0; + this.timeout = null; + + if (typeof FakeXDomainRequest.onCreate == "function") { + FakeXDomainRequest.onCreate(this); + } + } + + function verifyState(xdr) { + if (xdr.readyState !== FakeXDomainRequest.OPENED) { + throw new Error("INVALID_STATE_ERR"); + } + + if (xdr.sendFlag) { + throw new Error("INVALID_STATE_ERR"); + } + } + + function verifyRequestSent(xdr) { + if (xdr.readyState == FakeXDomainRequest.UNSENT) { + throw new Error("Request not sent"); + } + if (xdr.readyState == FakeXDomainRequest.DONE) { + throw new Error("Request done"); + } + } + + function verifyResponseBodyType(body) { + if (typeof body != "string") { + var error = new Error("Attempted to respond to fake XDomainRequest with " + + body + ", which is not a string."); + error.name = "InvalidBodyException"; + throw error; + } + } + + sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, { + open: function open(method, url) { + this.method = method; + this.url = url; + + this.responseText = null; + this.sendFlag = false; + + this.readyStateChange(FakeXDomainRequest.OPENED); + }, + + readyStateChange: function readyStateChange(state) { + this.readyState = state; + var eventName = ''; + switch (this.readyState) { + case FakeXDomainRequest.UNSENT: + break; + case FakeXDomainRequest.OPENED: + break; + case FakeXDomainRequest.LOADING: + if (this.sendFlag){ + //raise the progress event + eventName = 'onprogress'; + } + break; + case FakeXDomainRequest.DONE: + if (this.isTimeout){ + eventName = 'ontimeout' + } + else if (this.errorFlag || (this.status < 200 || this.status > 299)) { + eventName = 'onerror'; + } + else { + eventName = 'onload' + } + break; + } + + // raising event (if defined) + if (eventName) { + if (typeof this[eventName] == "function") { + try { + this[eventName](); + } catch (e) { + sinon.logError("Fake XHR " + eventName + " handler", e); + } + } + } + }, + + send: function send(data) { + verifyState(this); + + if (!/^(get|head)$/i.test(this.method)) { + this.requestBody = data; + } + this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; + + this.errorFlag = false; + this.sendFlag = true; + this.readyStateChange(FakeXDomainRequest.OPENED); + + if (typeof this.onSend == "function") { + this.onSend(this); + } + }, + + abort: function abort() { + this.aborted = true; + this.responseText = null; + this.errorFlag = true; + + if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) { + this.readyStateChange(sinon.FakeXDomainRequest.DONE); + this.sendFlag = false; + } + }, + + setResponseBody: function setResponseBody(body) { + verifyRequestSent(this); + verifyResponseBodyType(body); + + var chunkSize = this.chunkSize || 10; + var index = 0; + this.responseText = ""; + + do { + this.readyStateChange(FakeXDomainRequest.LOADING); + this.responseText += body.substring(index, index + chunkSize); + index += chunkSize; + } while (index < body.length); + + this.readyStateChange(FakeXDomainRequest.DONE); + }, + + respond: function respond(status, contentType, body) { + // content-type ignored, since XDomainRequest does not carry this + // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease + // test integration across browsers + this.status = typeof status == "number" ? status : 200; + this.setResponseBody(body || ""); + }, + + simulatetimeout: function(){ + this.status = 0; + this.isTimeout = true; + // Access to this should actually throw an error + this.responseText = undefined; + this.readyStateChange(FakeXDomainRequest.DONE); + } + }); + + sinon.extend(FakeXDomainRequest, { + UNSENT: 0, + OPENED: 1, + LOADING: 3, + DONE: 4 + }); + + sinon.useFakeXDomainRequest = function () { + sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) { + if (xdr.supportsXDR) { + global.XDomainRequest = xdr.GlobalXDomainRequest; + } + + delete sinon.FakeXDomainRequest.restore; + + if (keepOnCreate !== true) { + delete sinon.FakeXDomainRequest.onCreate; + } + }; + if (xdr.supportsXDR) { + global.XDomainRequest = sinon.FakeXDomainRequest; + } + return sinon.FakeXDomainRequest; + }; + + sinon.FakeXDomainRequest = FakeXDomainRequest; +})(this); + +if (typeof module == "object" && typeof require == "function") { + module.exports = sinon; +} + +return sinon;}.call(typeof window != 'undefined' && window || {})); diff --git a/vendor/jquery-mask/test/sinon-qunit-1.0.0.js b/vendor/jquery-mask/test/sinon-qunit-1.0.0.js new file mode 100755 index 0000000000..c26232fae7 --- /dev/null +++ b/vendor/jquery-mask/test/sinon-qunit-1.0.0.js @@ -0,0 +1,62 @@ +/** + * sinon-qunit 1.0.0, 2010/12/09 + * + * @author Christian Johansen (christian@cjohansen.no) + * + * (The BSD License) + * + * Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Christian Johansen nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*global sinon, QUnit, test*/ +sinon.assert.fail = function (msg) { + QUnit.ok(false, msg); +}; + +sinon.assert.pass = function (assertion) { + QUnit.ok(true, assertion); +}; + +sinon.config = { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "sandbox"], + useFakeTimers: true, + useFakeServer: false +}; + +(function (global) { + var qTest = QUnit.test; + + QUnit.test = global.test = function (testName, expected, callback, async) { + if (arguments.length === 2) { + callback = expected; + expected = null; + } + + return qTest(testName, expected, sinon.test(callback), async); + }; +}(this)); diff --git a/vendor/jquery-mask/test/sinon-qunit.js b/vendor/jquery-mask/test/sinon-qunit.js new file mode 100755 index 0000000000..c26232fae7 --- /dev/null +++ b/vendor/jquery-mask/test/sinon-qunit.js @@ -0,0 +1,62 @@ +/** + * sinon-qunit 1.0.0, 2010/12/09 + * + * @author Christian Johansen (christian@cjohansen.no) + * + * (The BSD License) + * + * Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Christian Johansen nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*global sinon, QUnit, test*/ +sinon.assert.fail = function (msg) { + QUnit.ok(false, msg); +}; + +sinon.assert.pass = function (assertion) { + QUnit.ok(true, assertion); +}; + +sinon.config = { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "sandbox"], + useFakeTimers: true, + useFakeServer: false +}; + +(function (global) { + var qTest = QUnit.test; + + QUnit.test = global.test = function (testName, expected, callback, async) { + if (arguments.length === 2) { + callback = expected; + expected = null; + } + + return qTest(testName, expected, sinon.test(callback), async); + }; +}(this)); diff --git a/vendor/jquery-mask/test/test-for-jquery-1.11.1.html b/vendor/jquery-mask/test/test-for-jquery-1.11.1.html new file mode 100755 index 0000000000..23de894934 --- /dev/null +++ b/vendor/jquery-mask/test/test-for-jquery-1.11.1.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

                    jQuery-Mask-Plugin QUnit Tests

                    +

                    +
                    +

                    +
                      +
                      test markup, will be hidden
                      + + + + + + + + +
                      +
                      + + + + + + + + + + + + diff --git a/vendor/jquery-mask/test/test-for-jquery-1.7.2.html b/vendor/jquery-mask/test/test-for-jquery-1.7.2.html new file mode 100755 index 0000000000..e50d43ae4e --- /dev/null +++ b/vendor/jquery-mask/test/test-for-jquery-1.7.2.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

                      jQuery-Mask-Plugin QUnit Tests

                      +

                      +
                      +

                      +
                        +
                        test markup, will be hidden
                        + + + + + + + + +
                        +
                        + + + + + + + + + + + + diff --git a/vendor/jquery-mask/test/test-for-jquery-1.8.3.html b/vendor/jquery-mask/test/test-for-jquery-1.8.3.html new file mode 100755 index 0000000000..c037820ad0 --- /dev/null +++ b/vendor/jquery-mask/test/test-for-jquery-1.8.3.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

                        jQuery-Mask-Plugin QUnit Tests

                        +

                        +
                        +

                        +
                          +
                          test markup, will be hidden
                          + + + + + + + + +
                          +
                          + + + + + + + + + + + + diff --git a/vendor/jquery-mask/test/test-for-jquery-1.9.1.html b/vendor/jquery-mask/test/test-for-jquery-1.9.1.html new file mode 100755 index 0000000000..65765858b2 --- /dev/null +++ b/vendor/jquery-mask/test/test-for-jquery-1.9.1.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

                          jQuery-Mask-Plugin QUnit Tests

                          +

                          +
                          +

                          +
                            +
                            test markup, will be hidden
                            + + + + + + + + +
                            +
                            + + + + + + + + + + + + diff --git a/vendor/jquery-mask/test/test-for-jquery-2.1.1.html b/vendor/jquery-mask/test/test-for-jquery-2.1.1.html new file mode 100755 index 0000000000..052517a829 --- /dev/null +++ b/vendor/jquery-mask/test/test-for-jquery-2.1.1.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

                            jQuery-Mask-Plugin QUnit Tests

                            +

                            +
                            +

                            +
                              +
                              test markup, will be hidden
                              + + + + + + + + +
                              +
                              + + + + + + + + + + + + diff --git a/vendor/jquery-mask/test/test-for-jquery-3.0.0.html b/vendor/jquery-mask/test/test-for-jquery-3.0.0.html new file mode 100755 index 0000000000..283b5cdf4a --- /dev/null +++ b/vendor/jquery-mask/test/test-for-jquery-3.0.0.html @@ -0,0 +1,35 @@ + + + jQuery-Mask-Plugin UnitTesting + + + + +

                              jQuery-Mask-Plugin QUnit Tests

                              +

                              +
                              +

                              +
                                +
                                test markup, will be hidden
                                + + + + + + + + +
                                +
                                + + + + + + + + + + + + diff --git a/vendor/jquery-mask/test/test-for-zepto.html b/vendor/jquery-mask/test/test-for-zepto.html new file mode 100755 index 0000000000..abb593232f --- /dev/null +++ b/vendor/jquery-mask/test/test-for-zepto.html @@ -0,0 +1,36 @@ + + + Zepto-Mask-Plugin UnitTesting + + + + +

                                Zepto-Mask-Plugin QUnit Tests

                                +

                                +
                                +

                                +
                                  +
                                  test markup, will be hidden
                                  + + + + + + + + +
                                  +
                                  + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/jquery-mask/test/zepto/data.js b/vendor/jquery-mask/test/zepto/data.js new file mode 100755 index 0000000000..8a9f9db3a2 --- /dev/null +++ b/vendor/jquery-mask/test/zepto/data.js @@ -0,0 +1,80 @@ +// Zepto.js +// (c) 2010-2014 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +// The following code is heavily inspired by jQuery's $.fn.data() + +;(function($){ + var data = {}, dataAttr = $.fn.data, camelize = $.camelCase, + exp = $.expando = 'Zepto' + (+new Date()), emptyArray = [] + + // Get value from node: + // 1. first try key as given, + // 2. then try camelized key, + // 3. fall back to reading "data-*" attribute. + function getData(node, name) { + var id = node[exp], store = id && data[id] + if (name === undefined) return store || setData(node) + else { + if (store) { + if (name in store) return store[name] + var camelName = camelize(name) + if (camelName in store) return store[camelName] + } + return dataAttr.call($(node), name) + } + } + + // Store value under camelized key on node + function setData(node, name, value) { + var id = node[exp] || (node[exp] = ++$.uuid), + store = data[id] || (data[id] = attributeData(node)) + if (name !== undefined) store[camelize(name)] = value + return store + } + + // Read all "data-*" attributes from a node + function attributeData(node) { + var store = {} + $.each(node.attributes || emptyArray, function(i, attr){ + if (attr.name.indexOf('data-') == 0) + store[camelize(attr.name.replace('data-', ''))] = + $.zepto.deserializeValue(attr.value) + }) + return store + } + + $.fn.data = function(name, value) { + return value === undefined ? + // set multiple values via object + $.isPlainObject(name) ? + this.each(function(i, node){ + $.each(name, function(key, value){ setData(node, key, value) }) + }) : + // get value from first element + (0 in this ? getData(this[0], name) : undefined) : + // set value on all elements + this.each(function(){ setData(this, name, value) }) + } + + $.fn.removeData = function(names) { + if (typeof names == 'string') names = names.split(/\s+/) + return this.each(function(){ + var id = this[exp], store = id && data[id] + if (store) $.each(names || store, function(key){ + delete store[names ? camelize(this) : key] + }) + }) + } + + // Generate extended `remove` and `empty` functions + ;['remove', 'empty'].forEach(function(methodName){ + var origFn = $.fn[methodName] + $.fn[methodName] = function() { + var elements = this.find('*') + if (methodName === 'remove') elements = elements.add(this) + elements.removeData() + return origFn.call(this) + } + }) +})(Zepto) diff --git a/vendor/jquery-mask/test/zepto/event.js b/vendor/jquery-mask/test/zepto/event.js new file mode 100755 index 0000000000..a7d2ec1a70 --- /dev/null +++ b/vendor/jquery-mask/test/zepto/event.js @@ -0,0 +1,282 @@ +// Zepto.js +// (c) 2010-2014 Thomas Fuchs +// Zepto.js may be freely distributed under the MIT license. + +;(function($){ + var _zid = 1, undefined, + slice = Array.prototype.slice, + isFunction = $.isFunction, + isString = function(obj){ return typeof obj == 'string' }, + handlers = {}, + specialEvents={}, + focusinSupported = 'onfocusin' in window, + focus = { focus: 'focusin', blur: 'focusout' }, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } + + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' + + function zid(element) { + return element._zid || (element._zid = _zid++) + } + function findHandlers(element, event, fn, selector) { + event = parse(event) + if (event.ns) var matcher = matcherFor(event.ns) + return (handlers[zid(element)] || []).filter(function(handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector) + }) + } + function parse(event) { + var parts = ('' + event).split('.') + return {e: parts[0], ns: parts.slice(1).sort().join(' ')} + } + function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') + } + + function eventCapture(handler, captureSetting) { + return handler.del && + (!focusinSupported && (handler.e in focus)) || + !!captureSetting + } + + function realEvent(type) { + return hover[type] || (focusinSupported && focus[type]) || type + } + + function add(element, events, fn, data, selector, delegator, capture){ + var id = zid(element), set = (handlers[id] || (handlers[id] = [])) + events.split(/\s/).forEach(function(event){ + if (event == 'ready') return $(document).ready(fn) + var handler = parse(event) + handler.fn = fn + handler.sel = selector + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function(e){ + var related = e.relatedTarget + if (!related || (related !== this && !$.contains(this, related))) + return handler.fn.apply(this, arguments) + } + handler.del = delegator + var callback = delegator || fn + handler.proxy = function(e){ + e = compatible(e) + if (e.isImmediatePropagationStopped()) return + e.data = data + var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)) + if (result === false) e.preventDefault(), e.stopPropagation() + return result + } + handler.i = set.length + set.push(handler) + if ('addEventListener' in element) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + } + function remove(element, events, fn, selector, capture){ + var id = zid(element) + ;(events || '').split(/\s/).forEach(function(event){ + findHandlers(element, event, fn, selector).forEach(function(handler){ + delete handlers[id][handler.i] + if ('removeEventListener' in element) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + }) + } + + $.event = { add: add, remove: remove } + + $.proxy = function(fn, context) { + var args = (2 in arguments) && slice.call(arguments, 2) + if (isFunction(fn)) { + var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) } + proxyFn._zid = zid(fn) + return proxyFn + } else if (isString(context)) { + if (args) { + args.unshift(fn[context], fn) + return $.proxy.apply(null, args) + } else { + return $.proxy(fn[context], fn) + } + } else { + throw new TypeError("expected function") + } + } + + $.fn.bind = function(event, data, callback){ + return this.on(event, data, callback) + } + $.fn.unbind = function(event, callback){ + return this.off(event, callback) + } + $.fn.one = function(event, selector, data, callback){ + return this.on(event, selector, data, callback, 1) + } + + var returnTrue = function(){return true}, + returnFalse = function(){return false}, + ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + } + + function compatible(event, source) { + if (source || !event.isDefaultPrevented) { + source || (source = event) + + $.each(eventMethods, function(name, predicate) { + var sourceMethod = source[name] + event[name] = function(){ + this[predicate] = returnTrue + return sourceMethod && sourceMethod.apply(source, arguments) + } + event[predicate] = returnFalse + }) + + if (source.defaultPrevented !== undefined ? source.defaultPrevented : + 'returnValue' in source ? source.returnValue === false : + source.getPreventDefault && source.getPreventDefault()) + event.isDefaultPrevented = returnTrue + } + return event + } + + function createProxy(event) { + var key, proxy = { originalEvent: event } + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] + + return compatible(proxy, event) + } + + $.fn.delegate = function(selector, event, callback){ + return this.on(event, selector, callback) + } + $.fn.undelegate = function(selector, event, callback){ + return this.off(event, selector, callback) + } + + $.fn.live = function(event, callback){ + $(document.body).delegate(this.selector, event, callback) + return this + } + $.fn.die = function(event, callback){ + $(document.body).undelegate(this.selector, event, callback) + return this + } + + $.fn.on = function(event, selector, data, callback, one){ + var autoRemove, delegator, $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.on(type, selector, data, fn, one) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = data, data = selector, selector = undefined + if (isFunction(data) || data === false) + callback = data, data = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(_, element){ + if (one) autoRemove = function(e){ + remove(element, e.type, callback) + return callback.apply(this, arguments) + } + + if (selector) delegator = function(e){ + var evt, match = $(e.target).closest(selector, element).get(0) + if (match && match !== element) { + evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) + return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))) + } + } + + add(element, event, callback, data, selector, delegator || autoRemove) + }) + } + $.fn.off = function(event, selector, callback){ + var $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.off(type, selector, fn) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = selector, selector = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(){ + remove(this, event, callback, selector) + }) + } + + $.fn.trigger = function(event, args){ + event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event) + event._args = args + return this.each(function(){ + // items in the collection might not be DOM elements + if('dispatchEvent' in this) this.dispatchEvent(event) + else $(this).triggerHandler(event, args) + }) + } + + // triggers event handlers on current element just as if an event occurred, + // doesn't trigger an actual event, doesn't bubble + $.fn.triggerHandler = function(event, args){ + var e, result + this.each(function(i, element){ + e = createProxy(isString(event) ? $.Event(event) : event) + e._args = args + e.target = element + $.each(findHandlers(element, event.type || event), function(i, handler){ + result = handler.proxy(e) + if (e.isImmediatePropagationStopped()) return false + }) + }) + return result + } + + // shortcut methods for `.bind(event, fn)` for each event type + ;('focusin focusout load resize scroll unload click dblclick '+ + 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ + 'change select keydown keypress keyup error').split(' ').forEach(function(event) { + $.fn[event] = function(callback) { + return callback ? + this.bind(event, callback) : + this.trigger(event) + } + }) + + ;['focus', 'blur'].forEach(function(name) { + $.fn[name] = function(callback) { + if (callback) this.bind(name, callback) + else this.each(function(){ + try { this[name]() } + catch(e) {} + }) + return this + } + }) + + $.Event = function(type, props) { + if (!isString(type)) props = type, type = props.type + var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true + if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) + event.initEvent(type, bubbles, true) + return compatible(event) + } + +})(Zepto) diff --git a/vendor/jquery-mask/test/zepto/zepto.min.js b/vendor/jquery-mask/test/zepto/zepto.min.js new file mode 100755 index 0000000000..99949a36cd --- /dev/null +++ b/vendor/jquery-mask/test/zepto/zepto.min.js @@ -0,0 +1,1580 @@ +/* Zepto v1.1.4 - zepto event ajax form ie - zeptojs.com/license */ + +var Zepto = (function() { + var undefined, key, $, classList, emptyArray = [], slice = emptyArray.slice, filter = emptyArray.filter, + document = window.document, + elementDisplay = {}, classCache = {}, + cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 }, + fragmentRE = /^\s*<(\w+|!)[^>]*>/, + singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + capitalRE = /([A-Z])/g, + + // special attributes that should be get/set via method calls + methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], + + adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ], + table = document.createElement('table'), + tableRow = document.createElement('tr'), + containers = { + 'tr': document.createElement('tbody'), + 'tbody': table, 'thead': table, 'tfoot': table, + 'td': tableRow, 'th': tableRow, + '*': document.createElement('div') + }, + readyRE = /complete|loaded|interactive/, + simpleSelectorRE = /^[\w-]*$/, + class2type = {}, + toString = class2type.toString, + zepto = {}, + camelize, uniq, + tempParent = document.createElement('div'), + propMap = { + 'tabindex': 'tabIndex', + 'readonly': 'readOnly', + 'for': 'htmlFor', + 'class': 'className', + 'maxlength': 'maxLength', + 'cellspacing': 'cellSpacing', + 'cellpadding': 'cellPadding', + 'rowspan': 'rowSpan', + 'colspan': 'colSpan', + 'usemap': 'useMap', + 'frameborder': 'frameBorder', + 'contenteditable': 'contentEditable' + }, + isArray = Array.isArray || + function(object){ return object instanceof Array } + + zepto.matches = function(element, selector) { + if (!selector || !element || element.nodeType !== 1) return false + var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector || + element.oMatchesSelector || element.matchesSelector + if (matchesSelector) return matchesSelector.call(element, selector) + // fall back to performing a selector: + var match, parent = element.parentNode, temp = !parent + if (temp) (parent = tempParent).appendChild(element) + match = ~zepto.qsa(parent, selector).indexOf(element) + temp && tempParent.removeChild(element) + return match + } + + function type(obj) { + return obj == null ? String(obj) : + class2type[toString.call(obj)] || "object" + } + + function isFunction(value) { return type(value) == "function" } + function isWindow(obj) { return obj != null && obj == obj.window } + function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } + function isObject(obj) { return type(obj) == "object" } + function isPlainObject(obj) { + return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype + } + function likeArray(obj) { return typeof obj.length == 'number' } + + function compact(array) { return filter.call(array, function(item){ return item != null }) } + function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array } + camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) } + function dasherize(str) { + return str.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/_/g, '-') + .toLowerCase() + } + uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) } + + function classRE(name) { + return name in classCache ? + classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')) + } + + function maybeAddPx(name, value) { + return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value + } + + function defaultDisplay(nodeName) { + var element, display + if (!elementDisplay[nodeName]) { + element = document.createElement(nodeName) + document.body.appendChild(element) + display = getComputedStyle(element, '').getPropertyValue("display") + element.parentNode.removeChild(element) + display == "none" && (display = "block") + elementDisplay[nodeName] = display + } + return elementDisplay[nodeName] + } + + function children(element) { + return 'children' in element ? + slice.call(element.children) : + $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node }) + } + + // `$.zepto.fragment` takes a html string and an optional tag name + // to generate DOM nodes nodes from the given html string. + // The generated DOM nodes are returned as an array. + // This function can be overriden in plugins for example to make + // it compatible with browsers that don't support the DOM fully. + zepto.fragment = function(html, name, properties) { + var dom, nodes, container + + // A special case optimization for a single tag + if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1)) + + if (!dom) { + if (html.replace) html = html.replace(tagExpanderRE, "<$1>") + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 + if (!(name in containers)) name = '*' + + container = containers[name] + container.innerHTML = '' + html + dom = $.each(slice.call(container.childNodes), function(){ + container.removeChild(this) + }) + } + + if (isPlainObject(properties)) { + nodes = $(dom) + $.each(properties, function(key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value) + else nodes.attr(key, value) + }) + } + + return dom + } + + // `$.zepto.Z` swaps out the prototype of the given `dom` array + // of nodes with `$.fn` and thus supplying all the Zepto functions + // to the array. Note that `__proto__` is not supported on Internet + // Explorer. This method can be overriden in plugins. + zepto.Z = function(dom, selector) { + dom = dom || [] + dom.__proto__ = $.fn + dom.selector = selector || '' + return dom + } + + // `$.zepto.isZ` should return `true` if the given object is a Zepto + // collection. This method can be overriden in plugins. + zepto.isZ = function(object) { + return object instanceof zepto.Z + } + + // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and + // takes a CSS selector and an optional context (and handles various + // special cases). + // This method can be overriden in plugins. + zepto.init = function(selector, context) { + var dom + // If nothing given, return an empty Zepto collection + if (!selector) return zepto.Z() + // Optimize for string selectors + else if (typeof selector == 'string') { + selector = selector.trim() + // If it's a html fragment, create nodes from it + // Note: In both Chrome 21 and Firefox 15, DOM error 12 + // is thrown if the fragment doesn't begin with < + if (selector[0] == '<' && fragmentRE.test(selector)) + dom = zepto.fragment(selector, RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // If it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) return $(document).ready(selector) + // If a Zepto collection is given, just return it + else if (zepto.isZ(selector)) return selector + else { + // normalize array if an array of nodes is given + if (isArray(selector)) dom = compact(selector) + // Wrap DOM nodes. + else if (isObject(selector)) + dom = [selector], selector = null + // If it's a html fragment, create nodes from it + else if (fragmentRE.test(selector)) + dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // And last but no least, if it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // create a new Zepto collection from the nodes found + return zepto.Z(dom, selector) + } + + // `$` will be the base `Zepto` object. When calling this + // function just call `$.zepto.init, which makes the implementation + // details of selecting nodes and creating Zepto collections + // patchable in plugins. + $ = function(selector, context){ + return zepto.init(selector, context) + } + + function extend(target, source, deep) { + for (key in source) + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) + target[key] = {} + if (isArray(source[key]) && !isArray(target[key])) + target[key] = [] + extend(target[key], source[key], deep) + } + else if (source[key] !== undefined) target[key] = source[key] + } + + // Copy all but undefined properties from one or more + // objects to the `target` object. + $.extend = function(target){ + var deep, args = slice.call(arguments, 1) + if (typeof target == 'boolean') { + deep = target + target = args.shift() + } + args.forEach(function(arg){ extend(target, arg, deep) }) + return target + } + + // `$.zepto.qsa` is Zepto's CSS selector implementation which + // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`. + // This method can be overriden in plugins. + zepto.qsa = function(element, selector){ + var found, + maybeID = selector[0] == '#', + maybeClass = !maybeID && selector[0] == '.', + nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked + isSimple = simpleSelectorRE.test(nameOnly) + return (isDocument(element) && isSimple && maybeID) ? + ( (found = element.getElementById(nameOnly)) ? [found] : [] ) : + (element.nodeType !== 1 && element.nodeType !== 9) ? [] : + slice.call( + isSimple && !maybeID ? + maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class + element.getElementsByTagName(selector) : // Or a tag + element.querySelectorAll(selector) // Or it's not simple, and we need to query all + ) + } + + function filtered(nodes, selector) { + return selector == null ? $(nodes) : $(nodes).filter(selector) + } + + $.contains = document.documentElement.contains ? + function(parent, node) { + return parent !== node && parent.contains(node) + } : + function(parent, node) { + while (node && (node = node.parentNode)) + if (node === parent) return true + return false + } + + function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg + } + + function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value) + } + + // access className property while respecting SVGAnimatedString + function className(node, value){ + var klass = node.className, + svg = klass && klass.baseVal !== undefined + + if (value === undefined) return svg ? klass.baseVal : klass + svg ? (klass.baseVal = value) : (node.className = value) + } + + // "true" => true + // "false" => false + // "null" => null + // "42" => 42 + // "42.5" => 42.5 + // "08" => "08" + // JSON => parse if valid + // String => self + function deserializeValue(value) { + var num + try { + return value ? + value == "true" || + ( value == "false" ? false : + value == "null" ? null : + !/^0/.test(value) && !isNaN(num = Number(value)) ? num : + /^[\[\{]/.test(value) ? $.parseJSON(value) : + value ) + : value + } catch(e) { + return value + } + } + + $.type = type + $.isFunction = isFunction + $.isWindow = isWindow + $.isArray = isArray + $.isPlainObject = isPlainObject + + $.isEmptyObject = function(obj) { + var name + for (name in obj) return false + return true + } + + $.inArray = function(elem, array, i){ + return emptyArray.indexOf.call(array, elem, i) + } + + $.camelCase = camelize + $.trim = function(str) { + return str == null ? "" : String.prototype.trim.call(str) + } + + // plugin compatibility + $.uuid = 0 + $.support = { } + $.expr = { } + + $.map = function(elements, callback){ + var value, values = [], i, key + if (likeArray(elements)) + for (i = 0; i < elements.length; i++) { + value = callback(elements[i], i) + if (value != null) values.push(value) + } + else + for (key in elements) { + value = callback(elements[key], key) + if (value != null) values.push(value) + } + return flatten(values) + } + + $.each = function(elements, callback){ + var i, key + if (likeArray(elements)) { + for (i = 0; i < elements.length; i++) + if (callback.call(elements[i], i, elements[i]) === false) return elements + } else { + for (key in elements) + if (callback.call(elements[key], key, elements[key]) === false) return elements + } + + return elements + } + + $.grep = function(elements, callback){ + return filter.call(elements, callback) + } + + if (window.JSON) $.parseJSON = JSON.parse + + // Populate the class2type map + $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase() + }) + + // Define methods that will be available on all + // Zepto collections + $.fn = { + // Because a collection acts like an array + // copy over these useful array functions. + forEach: emptyArray.forEach, + reduce: emptyArray.reduce, + push: emptyArray.push, + sort: emptyArray.sort, + indexOf: emptyArray.indexOf, + concat: emptyArray.concat, + + // `map` and `slice` in the jQuery API work differently + // from their array counterparts + map: function(fn){ + return $($.map(this, function(el, i){ return fn.call(el, i, el) })) + }, + slice: function(){ + return $(slice.apply(this, arguments)) + }, + + ready: function(callback){ + // need to check if document.body exists for IE as that browser reports + // document ready when it hasn't yet created the body element + if (readyRE.test(document.readyState) && document.body) callback($) + else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false) + return this + }, + get: function(idx){ + return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length] + }, + toArray: function(){ return this.get() }, + size: function(){ + return this.length + }, + remove: function(){ + return this.each(function(){ + if (this.parentNode != null) + this.parentNode.removeChild(this) + }) + }, + each: function(callback){ + emptyArray.every.call(this, function(el, idx){ + return callback.call(el, idx, el) !== false + }) + return this + }, + filter: function(selector){ + if (isFunction(selector)) return this.not(this.not(selector)) + return $(filter.call(this, function(element){ + return zepto.matches(element, selector) + })) + }, + add: function(selector,context){ + return $(uniq(this.concat($(selector,context)))) + }, + is: function(selector){ + return this.length > 0 && zepto.matches(this[0], selector) + }, + not: function(selector){ + var nodes=[] + if (isFunction(selector) && selector.call !== undefined) + this.each(function(idx){ + if (!selector.call(this,idx)) nodes.push(this) + }) + else { + var excludes = typeof selector == 'string' ? this.filter(selector) : + (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector) + this.forEach(function(el){ + if (excludes.indexOf(el) < 0) nodes.push(el) + }) + } + return $(nodes) + }, + has: function(selector){ + return this.filter(function(){ + return isObject(selector) ? + $.contains(this, selector) : + $(this).find(selector).size() + }) + }, + eq: function(idx){ + return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1) + }, + first: function(){ + var el = this[0] + return el && !isObject(el) ? el : $(el) + }, + last: function(){ + var el = this[this.length - 1] + return el && !isObject(el) ? el : $(el) + }, + find: function(selector){ + var result, $this = this + if (!selector) result = [] + else if (typeof selector == 'object') + result = $(selector).filter(function(){ + var node = this + return emptyArray.some.call($this, function(parent){ + return $.contains(parent, node) + }) + }) + else if (this.length == 1) result = $(zepto.qsa(this[0], selector)) + else result = this.map(function(){ return zepto.qsa(this, selector) }) + return result + }, + closest: function(selector, context){ + var node = this[0], collection = false + if (typeof selector == 'object') collection = $(selector) + while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector))) + node = node !== context && !isDocument(node) && node.parentNode + return $(node) + }, + parents: function(selector){ + var ancestors = [], nodes = this + while (nodes.length > 0) + nodes = $.map(nodes, function(node){ + if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) { + ancestors.push(node) + return node + } + }) + return filtered(ancestors, selector) + }, + parent: function(selector){ + return filtered(uniq(this.pluck('parentNode')), selector) + }, + children: function(selector){ + return filtered(this.map(function(){ return children(this) }), selector) + }, + contents: function() { + return this.map(function() { return slice.call(this.childNodes) }) + }, + siblings: function(selector){ + return filtered(this.map(function(i, el){ + return filter.call(children(el.parentNode), function(child){ return child!==el }) + }), selector) + }, + empty: function(){ + return this.each(function(){ this.innerHTML = '' }) + }, + // `pluck` is borrowed from Prototype.js + pluck: function(property){ + return $.map(this, function(el){ return el[property] }) + }, + show: function(){ + return this.each(function(){ + this.style.display == "none" && (this.style.display = '') + if (getComputedStyle(this, '').getPropertyValue("display") == "none") + this.style.display = defaultDisplay(this.nodeName) + }) + }, + replaceWith: function(newContent){ + return this.before(newContent).remove() + }, + wrap: function(structure){ + var func = isFunction(structure) + if (this[0] && !func) + var dom = $(structure).get(0), + clone = dom.parentNode || this.length > 1 + + return this.each(function(index){ + $(this).wrapAll( + func ? structure.call(this, index) : + clone ? dom.cloneNode(true) : dom + ) + }) + }, + wrapAll: function(structure){ + if (this[0]) { + $(this[0]).before(structure = $(structure)) + var children + // drill down to the inmost element + while ((children = structure.children()).length) structure = children.first() + $(structure).append(this) + } + return this + }, + wrapInner: function(structure){ + var func = isFunction(structure) + return this.each(function(index){ + var self = $(this), contents = self.contents(), + dom = func ? structure.call(this, index) : structure + contents.length ? contents.wrapAll(dom) : self.append(dom) + }) + }, + unwrap: function(){ + this.parent().each(function(){ + $(this).replaceWith($(this).children()) + }) + return this + }, + clone: function(){ + return this.map(function(){ return this.cloneNode(true) }) + }, + hide: function(){ + return this.css("display", "none") + }, + toggle: function(setting){ + return this.each(function(){ + var el = $(this) + ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide() + }) + }, + prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') }, + next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') }, + html: function(html){ + return 0 in arguments ? + this.each(function(idx){ + var originHtml = this.innerHTML + $(this).empty().append( funcArg(this, html, idx, originHtml) ) + }) : + (0 in this ? this[0].innerHTML : null) + }, + text: function(text){ + return 0 in arguments ? + this.each(function(idx){ + var newText = funcArg(this, text, idx, this.textContent) + this.textContent = newText == null ? '' : ''+newText + }) : + (0 in this ? this[0].textContent : null) + }, + attr: function(name, value){ + var result + return (typeof name == 'string' && !(1 in arguments)) ? + (!this.length || this[0].nodeType !== 1 ? undefined : + (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result + ) : + this.each(function(idx){ + if (this.nodeType !== 1) return + if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) + else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) + }) + }, + removeAttr: function(name){ + return this.each(function(){ this.nodeType === 1 && setAttribute(this, name) }) + }, + prop: function(name, value){ + name = propMap[name] || name + return (1 in arguments) ? + this.each(function(idx){ + this[name] = funcArg(this, value, idx, this[name]) + }) : + (this[0] && this[0][name]) + }, + data: function(name, value){ + var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase() + + var data = (1 in arguments) ? + this.attr(attrName, value) : + this.attr(attrName) + + return data !== null ? deserializeValue(data) : undefined + }, + val: function(value){ + return 0 in arguments ? + this.each(function(idx){ + this.value = funcArg(this, value, idx, this.value) + }) : + (this[0] && (this[0].multiple ? + $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') : + this[0].value) + ) + }, + offset: function(coordinates){ + if (coordinates) return this.each(function(index){ + var $this = $(this), + coords = funcArg(this, coordinates, index, $this.offset()), + parentOffset = $this.offsetParent().offset(), + props = { + top: coords.top - parentOffset.top, + left: coords.left - parentOffset.left + } + + if ($this.css('position') == 'static') props['position'] = 'relative' + $this.css(props) + }) + if (!this.length) return null + var obj = this[0].getBoundingClientRect() + return { + left: obj.left + window.pageXOffset, + top: obj.top + window.pageYOffset, + width: Math.round(obj.width), + height: Math.round(obj.height) + } + }, + css: function(property, value){ + if (arguments.length < 2) { + var element = this[0], computedStyle = getComputedStyle(element, '') + if(!element) return + if (typeof property == 'string') + return element.style[camelize(property)] || computedStyle.getPropertyValue(property) + else if (isArray(property)) { + var props = {} + $.each(isArray(property) ? property: [property], function(_, prop){ + props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop)) + }) + return props + } + } + + var css = '' + if (type(property) == 'string') { + if (!value && value !== 0) + this.each(function(){ this.style.removeProperty(dasherize(property)) }) + else + css = dasherize(property) + ":" + maybeAddPx(property, value) + } else { + for (key in property) + if (!property[key] && property[key] !== 0) + this.each(function(){ this.style.removeProperty(dasherize(key)) }) + else + css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' + } + + return this.each(function(){ this.style.cssText += ';' + css }) + }, + index: function(element){ + return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]) + }, + hasClass: function(name){ + if (!name) return false + return emptyArray.some.call(this, function(el){ + return this.test(className(el)) + }, classRE(name)) + }, + addClass: function(name){ + if (!name) return this + return this.each(function(idx){ + classList = [] + var cls = className(this), newName = funcArg(this, name, idx, cls) + newName.split(/\s+/g).forEach(function(klass){ + if (!$(this).hasClass(klass)) classList.push(klass) + }, this) + classList.length && className(this, cls + (cls ? " " : "") + classList.join(" ")) + }) + }, + removeClass: function(name){ + return this.each(function(idx){ + if (name === undefined) return className(this, '') + classList = className(this) + funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){ + classList = classList.replace(classRE(klass), " ") + }) + className(this, classList.trim()) + }) + }, + toggleClass: function(name, when){ + if (!name) return this + return this.each(function(idx){ + var $this = $(this), names = funcArg(this, name, idx, className(this)) + names.split(/\s+/g).forEach(function(klass){ + (when === undefined ? !$this.hasClass(klass) : when) ? + $this.addClass(klass) : $this.removeClass(klass) + }) + }) + }, + scrollTop: function(value){ + if (!this.length) return + var hasScrollTop = 'scrollTop' in this[0] + if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset + return this.each(hasScrollTop ? + function(){ this.scrollTop = value } : + function(){ this.scrollTo(this.scrollX, value) }) + }, + scrollLeft: function(value){ + if (!this.length) return + var hasScrollLeft = 'scrollLeft' in this[0] + if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset + return this.each(hasScrollLeft ? + function(){ this.scrollLeft = value } : + function(){ this.scrollTo(value, this.scrollY) }) + }, + position: function() { + if (!this.length) return + + var elem = this[0], + // Get *real* offsetParent + offsetParent = this.offsetParent(), + // Get correct offsets + offset = this.offset(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset() + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( $(elem).css('margin-top') ) || 0 + offset.left -= parseFloat( $(elem).css('margin-left') ) || 0 + + // Add offsetParent borders + parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0 + parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0 + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + } + }, + offsetParent: function() { + return this.map(function(){ + var parent = this.offsetParent || document.body + while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static") + parent = parent.offsetParent + return parent + }) + } + } + + // for now + $.fn.detach = $.fn.remove + + // Generate the `width` and `height` functions + ;['width', 'height'].forEach(function(dimension){ + var dimensionProperty = + dimension.replace(/./, function(m){ return m[0].toUpperCase() }) + + $.fn[dimension] = function(value){ + var offset, el = this[0] + if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] : + isDocument(el) ? el.documentElement['scroll' + dimensionProperty] : + (offset = this.offset()) && offset[dimension] + else return this.each(function(idx){ + el = $(this) + el.css(dimension, funcArg(this, value, idx, el[dimension]())) + }) + } + }) + + function traverseNode(node, fun) { + fun(node) + for (var i = 0, len = node.childNodes.length; i < len; i++) + traverseNode(node.childNodes[i], fun) + } + + // Generate the `after`, `prepend`, `before`, `append`, + // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods. + adjacencyOperators.forEach(function(operator, operatorIndex) { + var inside = operatorIndex % 2 //=> prepend, append + + $.fn[operator] = function(){ + // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings + var argType, nodes = $.map(arguments, function(arg) { + argType = type(arg) + return argType == "object" || argType == "array" || arg == null ? + arg : zepto.fragment(arg) + }), + parent, copyByClone = this.length > 1 + if (nodes.length < 1) return this + + return this.each(function(_, target){ + parent = inside ? target : target.parentNode + + // convert all methods to a "before" operation + target = operatorIndex == 0 ? target.nextSibling : + operatorIndex == 1 ? target.firstChild : + operatorIndex == 2 ? target : + null + + var parentInDocument = $.contains(document.documentElement, parent) + + nodes.forEach(function(node){ + if (copyByClone) node = node.cloneNode(true) + else if (!parent) return $(node).remove() + + parent.insertBefore(node, target) + if (parentInDocument) traverseNode(node, function(el){ + if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && + (!el.type || el.type === 'text/javascript') && !el.src) + window['eval'].call(window, el.innerHTML) + }) + }) + }) + } + + // after => insertAfter + // prepend => prependTo + // before => insertBefore + // append => appendTo + $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){ + $(html)[operator](this) + return this + } + }) + + zepto.Z.prototype = $.fn + + // Export internal API functions in the `$.zepto` namespace + zepto.uniq = uniq + zepto.deserializeValue = deserializeValue + $.zepto = zepto + + return $ +})() + +window.Zepto = Zepto +window.$ === undefined && (window.$ = Zepto) + +;(function($){ + var _zid = 1, undefined, + slice = Array.prototype.slice, + isFunction = $.isFunction, + isString = function(obj){ return typeof obj == 'string' }, + handlers = {}, + specialEvents={}, + focusinSupported = 'onfocusin' in window, + focus = { focus: 'focusin', blur: 'focusout' }, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } + + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' + + function zid(element) { + return element._zid || (element._zid = _zid++) + } + function findHandlers(element, event, fn, selector) { + event = parse(event) + if (event.ns) var matcher = matcherFor(event.ns) + return (handlers[zid(element)] || []).filter(function(handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector) + }) + } + function parse(event) { + var parts = ('' + event).split('.') + return {e: parts[0], ns: parts.slice(1).sort().join(' ')} + } + function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') + } + + function eventCapture(handler, captureSetting) { + return handler.del && + (!focusinSupported && (handler.e in focus)) || + !!captureSetting + } + + function realEvent(type) { + return hover[type] || (focusinSupported && focus[type]) || type + } + + function add(element, events, fn, data, selector, delegator, capture){ + var id = zid(element), set = (handlers[id] || (handlers[id] = [])) + events.split(/\s/).forEach(function(event){ + if (event == 'ready') return $(document).ready(fn) + var handler = parse(event) + handler.fn = fn + handler.sel = selector + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function(e){ + var related = e.relatedTarget + if (!related || (related !== this && !$.contains(this, related))) + return handler.fn.apply(this, arguments) + } + handler.del = delegator + var callback = delegator || fn + handler.proxy = function(e){ + e = compatible(e) + if (e.isImmediatePropagationStopped()) return + e.data = data + var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)) + if (result === false) e.preventDefault(), e.stopPropagation() + return result + } + handler.i = set.length + set.push(handler) + if ('addEventListener' in element) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + } + function remove(element, events, fn, selector, capture){ + var id = zid(element) + ;(events || '').split(/\s/).forEach(function(event){ + findHandlers(element, event, fn, selector).forEach(function(handler){ + delete handlers[id][handler.i] + if ('removeEventListener' in element) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + }) + } + + $.event = { add: add, remove: remove } + + $.proxy = function(fn, context) { + var args = (2 in arguments) && slice.call(arguments, 2) + if (isFunction(fn)) { + var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) } + proxyFn._zid = zid(fn) + return proxyFn + } else if (isString(context)) { + if (args) { + args.unshift(fn[context], fn) + return $.proxy.apply(null, args) + } else { + return $.proxy(fn[context], fn) + } + } else { + throw new TypeError("expected function") + } + } + + $.fn.bind = function(event, data, callback){ + return this.on(event, data, callback) + } + $.fn.unbind = function(event, callback){ + return this.off(event, callback) + } + $.fn.one = function(event, selector, data, callback){ + return this.on(event, selector, data, callback, 1) + } + + var returnTrue = function(){return true}, + returnFalse = function(){return false}, + ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + } + + function compatible(event, source) { + if (source || !event.isDefaultPrevented) { + source || (source = event) + + $.each(eventMethods, function(name, predicate) { + var sourceMethod = source[name] + event[name] = function(){ + this[predicate] = returnTrue + return sourceMethod && sourceMethod.apply(source, arguments) + } + event[predicate] = returnFalse + }) + + if (source.defaultPrevented !== undefined ? source.defaultPrevented : + 'returnValue' in source ? source.returnValue === false : + source.getPreventDefault && source.getPreventDefault()) + event.isDefaultPrevented = returnTrue + } + return event + } + + function createProxy(event) { + var key, proxy = { originalEvent: event } + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] + + return compatible(proxy, event) + } + + $.fn.delegate = function(selector, event, callback){ + return this.on(event, selector, callback) + } + $.fn.undelegate = function(selector, event, callback){ + return this.off(event, selector, callback) + } + + $.fn.live = function(event, callback){ + $(document.body).delegate(this.selector, event, callback) + return this + } + $.fn.die = function(event, callback){ + $(document.body).undelegate(this.selector, event, callback) + return this + } + + $.fn.on = function(event, selector, data, callback, one){ + var autoRemove, delegator, $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.on(type, selector, data, fn, one) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = data, data = selector, selector = undefined + if (isFunction(data) || data === false) + callback = data, data = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(_, element){ + if (one) autoRemove = function(e){ + remove(element, e.type, callback) + return callback.apply(this, arguments) + } + + if (selector) delegator = function(e){ + var evt, match = $(e.target).closest(selector, element).get(0) + if (match && match !== element) { + evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) + return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))) + } + } + + add(element, event, callback, data, selector, delegator || autoRemove) + }) + } + $.fn.off = function(event, selector, callback){ + var $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.off(type, selector, fn) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = selector, selector = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(){ + remove(this, event, callback, selector) + }) + } + + $.fn.trigger = function(event, args){ + event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event) + event._args = args + return this.each(function(){ + // items in the collection might not be DOM elements + if('dispatchEvent' in this) this.dispatchEvent(event) + else $(this).triggerHandler(event, args) + }) + } + + // triggers event handlers on current element just as if an event occurred, + // doesn't trigger an actual event, doesn't bubble + $.fn.triggerHandler = function(event, args){ + var e, result + this.each(function(i, element){ + e = createProxy(isString(event) ? $.Event(event) : event) + e._args = args + e.target = element + $.each(findHandlers(element, event.type || event), function(i, handler){ + result = handler.proxy(e) + if (e.isImmediatePropagationStopped()) return false + }) + }) + return result + } + + // shortcut methods for `.bind(event, fn)` for each event type + ;('focusin focusout load resize scroll unload click dblclick '+ + 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ + 'change select keydown keypress keyup error').split(' ').forEach(function(event) { + $.fn[event] = function(callback) { + return callback ? + this.bind(event, callback) : + this.trigger(event) + } + }) + + ;['focus', 'blur'].forEach(function(name) { + $.fn[name] = function(callback) { + if (callback) this.bind(name, callback) + else this.each(function(){ + try { this[name]() } + catch(e) {} + }) + return this + } + }) + + $.Event = function(type, props) { + if (!isString(type)) props = type, type = props.type + var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true + if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) + event.initEvent(type, bubbles, true) + return compatible(event) + } + +})(Zepto) + +;(function($){ + var jsonpID = 0, + document = window.document, + key, + name, + rscript = /)<[^<]*)*<\/script>/gi, + scriptTypeRE = /^(?:text|application)\/javascript/i, + xmlTypeRE = /^(?:text|application)\/xml/i, + jsonType = 'application/json', + htmlType = 'text/html', + blankRE = /^\s*$/ + + // trigger a custom event and return false if it was cancelled + function triggerAndReturn(context, eventName, data) { + var event = $.Event(eventName) + $(context).trigger(event, data) + return !event.isDefaultPrevented() + } + + // trigger an Ajax "global" event + function triggerGlobal(settings, context, eventName, data) { + if (settings.global) return triggerAndReturn(context || document, eventName, data) + } + + // Number of active Ajax requests + $.active = 0 + + function ajaxStart(settings) { + if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart') + } + function ajaxStop(settings) { + if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop') + } + + // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable + function ajaxBeforeSend(xhr, settings) { + var context = settings.context + if (settings.beforeSend.call(context, xhr, settings) === false || + triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false) + return false + + triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]) + } + function ajaxSuccess(data, xhr, settings, deferred) { + var context = settings.context, status = 'success' + settings.success.call(context, data, status, xhr) + if (deferred) deferred.resolveWith(context, [data, status, xhr]) + triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]) + ajaxComplete(status, xhr, settings) + } + // type: "timeout", "error", "abort", "parsererror" + function ajaxError(error, type, xhr, settings, deferred) { + var context = settings.context + settings.error.call(context, xhr, type, error) + if (deferred) deferred.rejectWith(context, [xhr, type, error]) + triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error || type]) + ajaxComplete(type, xhr, settings) + } + // status: "success", "notmodified", "error", "timeout", "abort", "parsererror" + function ajaxComplete(status, xhr, settings) { + var context = settings.context + settings.complete.call(context, xhr, status) + triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]) + ajaxStop(settings) + } + + // Empty function, used as default callback + function empty() {} + + $.ajaxJSONP = function(options, deferred){ + if (!('type' in options)) return $.ajax(options) + + var _callbackName = options.jsonpCallback, + callbackName = ($.isFunction(_callbackName) ? + _callbackName() : _callbackName) || ('jsonp' + (++jsonpID)), + script = document.createElement('script'), + originalCallback = window[callbackName], + responseData, + abort = function(errorType) { + $(script).triggerHandler('error', errorType || 'abort') + }, + xhr = { abort: abort }, abortTimeout + + if (deferred) deferred.promise(xhr) + + $(script).on('load error', function(e, errorType){ + clearTimeout(abortTimeout) + $(script).off().remove() + + if (e.type == 'error' || !responseData) { + ajaxError(null, errorType || 'error', xhr, options, deferred) + } else { + ajaxSuccess(responseData[0], xhr, options, deferred) + } + + window[callbackName] = originalCallback + if (responseData && $.isFunction(originalCallback)) + originalCallback(responseData[0]) + + originalCallback = responseData = undefined + }) + + if (ajaxBeforeSend(xhr, options) === false) { + abort('abort') + return xhr + } + + window[callbackName] = function(){ + responseData = arguments + } + + script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName) + document.head.appendChild(script) + + if (options.timeout > 0) abortTimeout = setTimeout(function(){ + abort('timeout') + }, options.timeout) + + return xhr + } + + $.ajaxSettings = { + // Default type of request + type: 'GET', + // Callback that is executed before request + beforeSend: empty, + // Callback that is executed if the request succeeds + success: empty, + // Callback that is executed the the server drops error + error: empty, + // Callback that is executed on request complete (both: error and success) + complete: empty, + // The context for the callbacks + context: null, + // Whether to trigger "global" Ajax events + global: true, + // Transport + xhr: function () { + return new window.XMLHttpRequest() + }, + // MIME types mapping + // IIS returns Javascript as "application/x-javascript" + accepts: { + script: 'text/javascript, application/javascript, application/x-javascript', + json: jsonType, + xml: 'application/xml, text/xml', + html: htmlType, + text: 'text/plain' + }, + // Whether the request is to another domain + crossDomain: false, + // Default timeout + timeout: 0, + // Whether data should be serialized to string + processData: true, + // Whether the browser should be allowed to cache GET responses + cache: true + } + + function mimeToDataType(mime) { + if (mime) mime = mime.split(';', 2)[0] + return mime && ( mime == htmlType ? 'html' : + mime == jsonType ? 'json' : + scriptTypeRE.test(mime) ? 'script' : + xmlTypeRE.test(mime) && 'xml' ) || 'text' + } + + function appendQuery(url, query) { + if (query == '') return url + return (url + '&' + query).replace(/[&?]{1,2}/, '?') + } + + // serialize payload and append it to the URL for GET requests + function serializeData(options) { + if (options.processData && options.data && $.type(options.data) != "string") + options.data = $.param(options.data, options.traditional) + if (options.data && (!options.type || options.type.toUpperCase() == 'GET')) + options.url = appendQuery(options.url, options.data), options.data = undefined + } + + $.ajax = function(options){ + var settings = $.extend({}, options || {}), + deferred = $.Deferred && $.Deferred() + for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key] + + ajaxStart(settings) + + if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && + RegExp.$2 != window.location.host + + if (!settings.url) settings.url = window.location.toString() + serializeData(settings) + + var dataType = settings.dataType, hasPlaceholder = /\?.+=\?/.test(settings.url) + if (hasPlaceholder) dataType = 'jsonp' + + if (settings.cache === false || ( + (!options || options.cache !== true) && + ('script' == dataType || 'jsonp' == dataType) + )) + settings.url = appendQuery(settings.url, '_=' + Date.now()) + + if ('jsonp' == dataType) { + if (!hasPlaceholder) + settings.url = appendQuery(settings.url, + settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?') + return $.ajaxJSONP(settings, deferred) + } + + var mime = settings.accepts[dataType], + headers = { }, + setHeader = function(name, value) { headers[name.toLowerCase()] = [name, value] }, + protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol, + xhr = settings.xhr(), + nativeSetHeader = xhr.setRequestHeader, + abortTimeout + + if (deferred) deferred.promise(xhr) + + if (!settings.crossDomain) setHeader('X-Requested-With', 'XMLHttpRequest') + setHeader('Accept', mime || '*/*') + if (mime = settings.mimeType || mime) { + if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0] + xhr.overrideMimeType && xhr.overrideMimeType(mime) + } + if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) + setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded') + + if (settings.headers) for (name in settings.headers) setHeader(name, settings.headers[name]) + xhr.setRequestHeader = setHeader + + xhr.onreadystatechange = function(){ + if (xhr.readyState == 4) { + xhr.onreadystatechange = empty + clearTimeout(abortTimeout) + var result, error = false + if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) { + dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type')) + result = xhr.responseText + + try { + // http://perfectionkills.com/global-eval-what-are-the-options/ + if (dataType == 'script') (1,eval)(result) + else if (dataType == 'xml') result = xhr.responseXML + else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result) + } catch (e) { error = e } + + if (error) ajaxError(error, 'parsererror', xhr, settings, deferred) + else ajaxSuccess(result, xhr, settings, deferred) + } else { + ajaxError(xhr.statusText || null, xhr.status ? 'error' : 'abort', xhr, settings, deferred) + } + } + } + + if (ajaxBeforeSend(xhr, settings) === false) { + xhr.abort() + ajaxError(null, 'abort', xhr, settings, deferred) + return xhr + } + + if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name] + + var async = 'async' in settings ? settings.async : true + xhr.open(settings.type, settings.url, async, settings.username, settings.password) + + for (name in headers) nativeSetHeader.apply(xhr, headers[name]) + + if (settings.timeout > 0) abortTimeout = setTimeout(function(){ + xhr.onreadystatechange = empty + xhr.abort() + ajaxError(null, 'timeout', xhr, settings, deferred) + }, settings.timeout) + + // avoid sending empty string (#319) + xhr.send(settings.data ? settings.data : null) + return xhr + } + + // handle optional data/success arguments + function parseArguments(url, data, success, dataType) { + if ($.isFunction(data)) dataType = success, success = data, data = undefined + if (!$.isFunction(success)) dataType = success, success = undefined + return { + url: url + , data: data + , success: success + , dataType: dataType + } + } + + $.get = function(/* url, data, success, dataType */){ + return $.ajax(parseArguments.apply(null, arguments)) + } + + $.post = function(/* url, data, success, dataType */){ + var options = parseArguments.apply(null, arguments) + options.type = 'POST' + return $.ajax(options) + } + + $.getJSON = function(/* url, data, success */){ + var options = parseArguments.apply(null, arguments) + options.dataType = 'json' + return $.ajax(options) + } + + $.fn.load = function(url, data, success){ + if (!this.length) return this + var self = this, parts = url.split(/\s/), selector, + options = parseArguments(url, data, success), + callback = options.success + if (parts.length > 1) options.url = parts[0], selector = parts[1] + options.success = function(response){ + self.html(selector ? + $('
                                  ').html(response.replace(rscript, "")).find(selector) + : response) + callback && callback.apply(self, arguments) + } + $.ajax(options) + return this + } + + var escape = encodeURIComponent + + function serialize(params, obj, traditional, scope){ + var type, array = $.isArray(obj), hash = $.isPlainObject(obj) + $.each(obj, function(key, value) { + type = $.type(value) + if (scope) key = traditional ? scope : + scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']' + // handle data in serializeArray() format + if (!scope && array) params.add(value.name, value.value) + // recurse into nested objects + else if (type == "array" || (!traditional && type == "object")) + serialize(params, value, traditional, key) + else params.add(key, value) + }) + } + + $.param = function(obj, traditional){ + var params = [] + params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) } + serialize(params, obj, traditional) + return params.join('&').replace(/%20/g, '+') + } +})(Zepto) + +;(function($){ + $.fn.serializeArray = function() { + var result = [], el + $([].slice.call(this.get(0).elements)).each(function(){ + el = $(this) + var type = el.attr('type') + if (this.nodeName.toLowerCase() != 'fieldset' && + !this.disabled && type != 'submit' && type != 'reset' && type != 'button' && + ((type != 'radio' && type != 'checkbox') || this.checked)) + result.push({ + name: el.attr('name'), + value: el.val() + }) + }) + return result + } + + $.fn.serialize = function(){ + var result = [] + this.serializeArray().forEach(function(elm){ + result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value)) + }) + return result.join('&') + } + + $.fn.submit = function(callback) { + if (callback) this.bind('submit', callback) + else if (this.length) { + var event = $.Event('submit') + this.eq(0).trigger(event) + if (!event.isDefaultPrevented()) this.get(0).submit() + } + return this + } + +})(Zepto) + +;(function($){ + // __proto__ doesn't exist on IE<11, so redefine + // the Z function to use object extension instead + if (!('__proto__' in {})) { + $.extend($.zepto, { + Z: function(dom, selector){ + dom = dom || [] + $.extend(dom, $.fn) + dom.selector = selector || '' + dom.__Z = true + return dom + }, + // this is a kludge but works + isZ: function(object){ + return $.type(object) === 'array' && '__Z' in object + } + }) + } + + // getComputedStyle shouldn't freak out when called + // without a valid element as argument + try { + getComputedStyle(undefined) + } catch(e) { + var nativeGetComputedStyle = getComputedStyle; + window.getComputedStyle = function(element){ + try { + return nativeGetComputedStyle(element) + } catch(e) { + return null + } + } + } +})(Zepto) diff --git a/version.php b/version.php old mode 100644 new mode 100755