Commit eaa4ee48 authored by panpp's avatar panpp
Browse files

Merge remote-tracking branch 'origin/master'

parents 1fda008a 8e233e19
/*!
SerializeJSON jQuery plugin.
https://github.com/marioizquierdo/jquery.serializeJSON
version 2.8.1 (Dec, 2016)
Copyright (c) 2012, 2017 Mario Izquierdo
Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*/
(function (factory) {
if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') { // Node/CommonJS
var jQuery = require('jquery');
module.exports = factory(jQuery);
} else { // Browser globals (zepto supported)
factory(window.jQuery || window.Zepto || window.$); // Zepto supported on browsers as well
}
}(function ($) {
"use strict";
// jQuery('form').serializeJSON()
$.fn.serializeJSON = function (options) {
var f, $form, opts, formAsArray, serializedObject, name, value, parsedValue, _obj, nameWithNoType, type, keys, skipFalsy;
f = $.serializeJSON;
$form = this; // NOTE: the set of matched elements is most likely a form, but it could also be a group of inputs
opts = f.setupOpts(options); // calculate values for options {parseNumbers, parseBoolens, parseNulls, ...} with defaults
// Use native `serializeArray` function to get an array of {name, value} objects.
formAsArray = $form.serializeArray();
f.readCheckboxUncheckedValues(formAsArray, opts, $form); // add objects to the array from unchecked checkboxes if needed
// Convert the formAsArray into a serializedObject with nested keys
serializedObject = {};
$.each(formAsArray, function (i, obj) {
name = obj.name; // original input name
value = obj.value; // input value
_obj = f.extractTypeAndNameWithNoType(name);
nameWithNoType = _obj.nameWithNoType; // input name with no type (i.e. "foo:string" => "foo")
type = _obj.type; // type defined from the input name in :type colon notation
if (!type) type = f.attrFromInputWithName($form, name, 'data-value-type');
f.validateType(name, type, opts); // make sure that the type is one of the valid types if defined
if (type !== 'skip') { // ignore inputs with type 'skip'
keys = f.splitInputNameIntoKeysArray(nameWithNoType);
parsedValue = f.parseValue(value, name, type, opts); // convert to string, number, boolean, null or customType
skipFalsy = !parsedValue && f.shouldSkipFalsy($form, name, nameWithNoType, type, opts); // ignore falsy inputs if specified
if (!skipFalsy) {
f.deepSet(serializedObject, keys, parsedValue, opts);
}
}
});
return serializedObject;
};
// Use $.serializeJSON as namespace for the auxiliar functions
// and to define defaults
$.serializeJSON = {
defaultOptions: {
checkboxUncheckedValue: undefined, // to include that value for unchecked checkboxes (instead of ignoring them)
parseNumbers: false, // convert values like "1", "-2.33" to 1, -2.33
parseBooleans: false, // convert "true", "false" to true, false
parseNulls: false, // convert "null" to null
parseAll: false, // all of the above
parseWithFunction: null, // to use custom parser, a function like: function(val){ return parsed_val; }
skipFalsyValuesForTypes: [], // skip serialization of falsy values for listed value types
skipFalsyValuesForFields: [], // skip serialization of falsy values for listed field names
customTypes: {}, // override defaultTypes
defaultTypes: {
"string": function(str) { return String(str); },
"number": function(str) { return Number(str); },
"boolean": function(str) { var falses = ["false", "null", "undefined", "", "0"]; return falses.indexOf(str) === -1; },
"null": function(str) { var falses = ["false", "null", "undefined", "", "0"]; return falses.indexOf(str) === -1 ? str : null; },
"array": function(str) { return JSON.parse(str); },
"object": function(str) { return JSON.parse(str); },
"auto": function(str) { return $.serializeJSON.parseValue(str, null, null, {parseNumbers: true, parseBooleans: true, parseNulls: true}); }, // try again with something like "parseAll"
"skip": null // skip is a special type that makes it easy to ignore elements
},
useIntKeysAsArrayIndex: false // name="foo[2]" value="v" => {foo: [null, null, "v"]}, instead of {foo: ["2": "v"]}
},
// Merge option defaults into the options
setupOpts: function(options) {
var opt, validOpts, defaultOptions, optWithDefault, parseAll, f;
f = $.serializeJSON;
if (options == null) { options = {}; } // options ||= {}
defaultOptions = f.defaultOptions || {}; // defaultOptions
// Make sure that the user didn't misspell an option
validOpts = ['checkboxUncheckedValue', 'parseNumbers', 'parseBooleans', 'parseNulls', 'parseAll', 'parseWithFunction', 'skipFalsyValuesForTypes', 'skipFalsyValuesForFields', 'customTypes', 'defaultTypes', 'useIntKeysAsArrayIndex']; // re-define because the user may override the defaultOptions
for (opt in options) {
if (validOpts.indexOf(opt) === -1) {
throw new Error("serializeJSON ERROR: invalid option '" + opt + "'. Please use one of " + validOpts.join(', '));
}
}
// Helper to get the default value for this option if none is specified by the user
optWithDefault = function(key) { return (options[key] !== false) && (options[key] !== '') && (options[key] || defaultOptions[key]); };
// Return computed options (opts to be used in the rest of the script)
parseAll = optWithDefault('parseAll');
return {
checkboxUncheckedValue: optWithDefault('checkboxUncheckedValue'),
parseNumbers: parseAll || optWithDefault('parseNumbers'),
parseBooleans: parseAll || optWithDefault('parseBooleans'),
parseNulls: parseAll || optWithDefault('parseNulls'),
parseWithFunction: optWithDefault('parseWithFunction'),
skipFalsyValuesForTypes: optWithDefault('skipFalsyValuesForTypes'),
skipFalsyValuesForFields: optWithDefault('skipFalsyValuesForFields'),
typeFunctions: $.extend({}, optWithDefault('defaultTypes'), optWithDefault('customTypes')),
useIntKeysAsArrayIndex: optWithDefault('useIntKeysAsArrayIndex')
};
},
// Given a string, apply the type or the relevant "parse" options, to return the parsed value
parseValue: function(valStr, inputName, type, opts) {
var f, parsedVal;
f = $.serializeJSON;
parsedVal = valStr; // if no parsing is needed, the returned value will be the same
if (opts.typeFunctions && type && opts.typeFunctions[type]) { // use a type if available
parsedVal = opts.typeFunctions[type](valStr);
} else if (opts.parseNumbers && f.isNumeric(valStr)) { // auto: number
parsedVal = Number(valStr);
} else if (opts.parseBooleans && (valStr === "true" || valStr === "false")) { // auto: boolean
parsedVal = (valStr === "true");
} else if (opts.parseNulls && valStr == "null") { // auto: null
parsedVal = null;
}
if (opts.parseWithFunction && !type) { // custom parse function (apply after previous parsing options, but not if there's a specific type)
parsedVal = opts.parseWithFunction(parsedVal, inputName);
}
return parsedVal;
},
isObject: function(obj) { return obj === Object(obj); }, // is it an Object?
isUndefined: function(obj) { return obj === void 0; }, // safe check for undefined values
isValidArrayIndex: function(val) { return /^[0-9]+$/.test(String(val)); }, // 1,2,3,4 ... are valid array indexes
isNumeric: function(obj) { return obj - parseFloat(obj) >= 0; }, // taken from jQuery.isNumeric implementation. Not using jQuery.isNumeric to support old jQuery and Zepto versions
optionKeys: function(obj) { if (Object.keys) { return Object.keys(obj); } else { var key, keys = []; for(key in obj){ keys.push(key); } return keys;} }, // polyfill Object.keys to get option keys in IE<9
// Fill the formAsArray object with values for the unchecked checkbox inputs,
// using the same format as the jquery.serializeArray function.
// The value of the unchecked values is determined from the opts.checkboxUncheckedValue
// and/or the data-unchecked-value attribute of the inputs.
readCheckboxUncheckedValues: function (formAsArray, opts, $form) {
var selector, $uncheckedCheckboxes, $el, uncheckedValue, f, name;
if (opts == null) { opts = {}; }
f = $.serializeJSON;
selector = 'input[type=checkbox][name]:not(:checked):not([disabled])';
$uncheckedCheckboxes = $form.find(selector).add($form.filter(selector));
$uncheckedCheckboxes.each(function (i, el) {
// Check data attr first, then the option
$el = $(el);
uncheckedValue = $el.attr('data-unchecked-value');
if (uncheckedValue == null) {
uncheckedValue = opts.checkboxUncheckedValue;
}
// If there's an uncheckedValue, push it into the serialized formAsArray
if (uncheckedValue != null) {
if (el.name && el.name.indexOf("[][") !== -1) { // identify a non-supported
throw new Error("serializeJSON ERROR: checkbox unchecked values are not supported on nested arrays of objects like '"+el.name+"'. See https://github.com/marioizquierdo/jquery.serializeJSON/issues/67");
}
formAsArray.push({name: el.name, value: uncheckedValue});
}
});
},
// Returns and object with properties {name_without_type, type} from a given name.
// The type is null if none specified. Example:
// "foo" => {nameWithNoType: "foo", type: null}
// "foo:boolean" => {nameWithNoType: "foo", type: "boolean"}
// "foo[bar]:null" => {nameWithNoType: "foo[bar]", type: "null"}
extractTypeAndNameWithNoType: function(name) {
var match;
if (match = name.match(/(.*):([^:]+)$/)) {
return {nameWithNoType: match[1], type: match[2]};
} else {
return {nameWithNoType: name, type: null};
}
},
// Check if this input should be skipped when it has a falsy value,
// depending on the options to skip values by name or type, and the data-skip-falsy attribute.
shouldSkipFalsy: function($form, name, nameWithNoType, type, opts) {
var f = $.serializeJSON;
var skipFromDataAttr = f.attrFromInputWithName($form, name, 'data-skip-falsy');
if (skipFromDataAttr != null) {
return skipFromDataAttr !== 'false'; // any value is true, except if explicitly using 'false'
}
var optForFields = opts.skipFalsyValuesForFields;
if (optForFields && (optForFields.indexOf(nameWithNoType) !== -1 || optForFields.indexOf(name) !== -1)) {
return true;
}
var optForTypes = opts.skipFalsyValuesForTypes;
if (type == null) type = 'string'; // assume fields with no type are targeted as string
if (optForTypes && optForTypes.indexOf(type) !== -1) {
return true
}
return false;
},
// Finds the first input in $form with this name, and get the given attr from it.
// Returns undefined if no input or no attribute was found.
attrFromInputWithName: function($form, name, attrName) {
var escapedName, selector, $input, attrValue;
escapedName = name.replace(/(:|\.|\[|\]|\s)/g,'\\$1'); // every non-standard character need to be escaped by \\
selector = '[name="' + escapedName + '"]';
$input = $form.find(selector).add($form.filter(selector)); // NOTE: this returns only the first $input element if multiple are matched with the same name (i.e. an "array[]"). So, arrays with different element types specified through the data-value-type attr is not supported.
return $input.attr(attrName);
},
// Raise an error if the type is not recognized.
validateType: function(name, type, opts) {
var validTypes, f;
f = $.serializeJSON;
validTypes = f.optionKeys(opts ? opts.typeFunctions : f.defaultOptions.defaultTypes);
if (!type || validTypes.indexOf(type) !== -1) {
return true;
} else {
throw new Error("serializeJSON ERROR: Invalid type " + type + " found in input name '" + name + "', please use one of " + validTypes.join(', '));
}
},
// Split the input name in programatically readable keys.
// Examples:
// "foo" => ['foo']
// "[foo]" => ['foo']
// "foo[inn][bar]" => ['foo', 'inn', 'bar']
// "foo[inn[bar]]" => ['foo', 'inn', 'bar']
// "foo[inn][arr][0]" => ['foo', 'inn', 'arr', '0']
// "arr[][val]" => ['arr', '', 'val']
splitInputNameIntoKeysArray: function(nameWithNoType) {
var keys, f;
f = $.serializeJSON;
keys = nameWithNoType.split('['); // split string into array
keys = $.map(keys, function (key) { return key.replace(/\]/g, ''); }); // remove closing brackets
if (keys[0] === '') { keys.shift(); } // ensure no opening bracket ("[foo][inn]" should be same as "foo[inn]")
return keys;
},
// Set a value in an object or array, using multiple keys to set in a nested object or array:
//
// deepSet(obj, ['foo'], v) // obj['foo'] = v
// deepSet(obj, ['foo', 'inn'], v) // obj['foo']['inn'] = v // Create the inner obj['foo'] object, if needed
// deepSet(obj, ['foo', 'inn', '123'], v) // obj['foo']['arr']['123'] = v //
//
// deepSet(obj, ['0'], v) // obj['0'] = v
// deepSet(arr, ['0'], v, {useIntKeysAsArrayIndex: true}) // arr[0] = v
// deepSet(arr, [''], v) // arr.push(v)
// deepSet(obj, ['arr', ''], v) // obj['arr'].push(v)
//
// arr = [];
// deepSet(arr, ['', v] // arr => [v]
// deepSet(arr, ['', 'foo'], v) // arr => [v, {foo: v}]
// deepSet(arr, ['', 'bar'], v) // arr => [v, {foo: v, bar: v}]
// deepSet(arr, ['', 'bar'], v) // arr => [v, {foo: v, bar: v}, {bar: v}]
//
deepSet: function (o, keys, value, opts) {
var key, nextKey, tail, lastIdx, lastVal, f;
if (opts == null) { opts = {}; }
f = $.serializeJSON;
if (f.isUndefined(o)) { throw new Error("ArgumentError: param 'o' expected to be an object or array, found undefined"); }
if (!keys || keys.length === 0) { throw new Error("ArgumentError: param 'keys' expected to be an array with least one element"); }
key = keys[0];
// Only one key, then it's not a deepSet, just assign the value.
if (keys.length === 1) {
if (key === '') {
o.push(value); // '' is used to push values into the array (assume o is an array)
} else {
o[key] = value; // other keys can be used as object keys or array indexes
}
// With more keys is a deepSet. Apply recursively.
} else {
nextKey = keys[1];
// '' is used to push values into the array,
// with nextKey, set the value into the same object, in object[nextKey].
// Covers the case of ['', 'foo'] and ['', 'var'] to push the object {foo, var}, and the case of nested arrays.
if (key === '') {
lastIdx = o.length - 1; // asume o is array
lastVal = o[lastIdx];
if (f.isObject(lastVal) && (f.isUndefined(lastVal[nextKey]) || keys.length > 2)) { // if nextKey is not present in the last object element, or there are more keys to deep set
key = lastIdx; // then set the new value in the same object element
} else {
key = lastIdx + 1; // otherwise, point to set the next index in the array
}
}
// '' is used to push values into the array "array[]"
if (nextKey === '') {
if (f.isUndefined(o[key]) || !$.isArray(o[key])) {
o[key] = []; // define (or override) as array to push values
}
} else {
if (opts.useIntKeysAsArrayIndex && f.isValidArrayIndex(nextKey)) { // if 1, 2, 3 ... then use an array, where nextKey is the index
if (f.isUndefined(o[key]) || !$.isArray(o[key])) {
o[key] = []; // define (or override) as array, to insert values using int keys as array indexes
}
} else { // for anything else, use an object, where nextKey is going to be the attribute name
if (f.isUndefined(o[key]) || !f.isObject(o[key])) {
o[key] = {}; // define (or override) as object, to set nested properties
}
}
}
// Recursively set the inner object
tail = keys.slice(1);
f.deepSet(o[key], tail, value, opts);
}
}
};
}));
/*!
SerializeJSON jQuery plugin.
https://github.com/marioizquierdo/jquery.serializeJSON
version 2.8.1 (Dec, 2016)
Copyright (c) 2012, 2017 Mario Izquierdo
Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*/
!function(a){if("function"==typeof define&&define.amd)define(["jquery"],a);else if("object"==typeof exports){var b=require("jquery");module.exports=a(b)}else a(window.jQuery||window.Zepto||window.$)}(function(a){"use strict";a.fn.serializeJSON=function(b){var c,d,e,f,g,h,i,j,k,l,m,n,o;return c=a.serializeJSON,d=this,e=c.setupOpts(b),f=d.serializeArray(),c.readCheckboxUncheckedValues(f,e,d),g={},a.each(f,function(a,b){h=b.name,i=b.value,k=c.extractTypeAndNameWithNoType(h),l=k.nameWithNoType,m=k.type,m||(m=c.attrFromInputWithName(d,h,"data-value-type")),c.validateType(h,m,e),"skip"!==m&&(n=c.splitInputNameIntoKeysArray(l),j=c.parseValue(i,h,m,e),o=!j&&c.shouldSkipFalsy(d,h,l,m,e),o||c.deepSet(g,n,j,e))}),g},a.serializeJSON={defaultOptions:{checkboxUncheckedValue:void 0,parseNumbers:!1,parseBooleans:!1,parseNulls:!1,parseAll:!1,parseWithFunction:null,skipFalsyValuesForTypes:[],skipFalsyValuesForFields:[],customTypes:{},defaultTypes:{string:function(a){return String(a)},number:function(a){return Number(a)},boolean:function(a){var b=["false","null","undefined","","0"];return b.indexOf(a)===-1},null:function(a){var b=["false","null","undefined","","0"];return b.indexOf(a)===-1?a:null},array:function(a){return JSON.parse(a)},object:function(a){return JSON.parse(a)},auto:function(b){return a.serializeJSON.parseValue(b,null,null,{parseNumbers:!0,parseBooleans:!0,parseNulls:!0})},skip:null},useIntKeysAsArrayIndex:!1},setupOpts:function(b){var c,d,e,f,g,h;h=a.serializeJSON,null==b&&(b={}),e=h.defaultOptions||{},d=["checkboxUncheckedValue","parseNumbers","parseBooleans","parseNulls","parseAll","parseWithFunction","skipFalsyValuesForTypes","skipFalsyValuesForFields","customTypes","defaultTypes","useIntKeysAsArrayIndex"];for(c in b)if(d.indexOf(c)===-1)throw new Error("serializeJSON ERROR: invalid option '"+c+"'. Please use one of "+d.join(", "));return f=function(a){return b[a]!==!1&&""!==b[a]&&(b[a]||e[a])},g=f("parseAll"),{checkboxUncheckedValue:f("checkboxUncheckedValue"),parseNumbers:g||f("parseNumbers"),parseBooleans:g||f("parseBooleans"),parseNulls:g||f("parseNulls"),parseWithFunction:f("parseWithFunction"),skipFalsyValuesForTypes:f("skipFalsyValuesForTypes"),skipFalsyValuesForFields:f("skipFalsyValuesForFields"),typeFunctions:a.extend({},f("defaultTypes"),f("customTypes")),useIntKeysAsArrayIndex:f("useIntKeysAsArrayIndex")}},parseValue:function(b,c,d,e){var f,g;return f=a.serializeJSON,g=b,e.typeFunctions&&d&&e.typeFunctions[d]?g=e.typeFunctions[d](b):e.parseNumbers&&f.isNumeric(b)?g=Number(b):!e.parseBooleans||"true"!==b&&"false"!==b?e.parseNulls&&"null"==b&&(g=null):g="true"===b,e.parseWithFunction&&!d&&(g=e.parseWithFunction(g,c)),g},isObject:function(a){return a===Object(a)},isUndefined:function(a){return void 0===a},isValidArrayIndex:function(a){return/^[0-9]+$/.test(String(a))},isNumeric:function(a){return a-parseFloat(a)>=0},optionKeys:function(a){if(Object.keys)return Object.keys(a);var b,c=[];for(b in a)c.push(b);return c},readCheckboxUncheckedValues:function(b,c,d){var e,f,g,h,i;null==c&&(c={}),i=a.serializeJSON,e="input[type=checkbox][name]:not(:checked):not([disabled])",f=d.find(e).add(d.filter(e)),f.each(function(d,e){if(g=a(e),h=g.attr("data-unchecked-value"),null==h&&(h=c.checkboxUncheckedValue),null!=h){if(e.name&&e.name.indexOf("[][")!==-1)throw new Error("serializeJSON ERROR: checkbox unchecked values are not supported on nested arrays of objects like '"+e.name+"'. See https://github.com/marioizquierdo/jquery.serializeJSON/issues/67");b.push({name:e.name,value:h})}})},extractTypeAndNameWithNoType:function(a){var b;return(b=a.match(/(.*):([^:]+)$/))?{nameWithNoType:b[1],type:b[2]}:{nameWithNoType:a,type:null}},shouldSkipFalsy:function(b,c,d,e,f){var g=a.serializeJSON,h=g.attrFromInputWithName(b,c,"data-skip-falsy");if(null!=h)return"false"!==h;var i=f.skipFalsyValuesForFields;if(i&&(i.indexOf(d)!==-1||i.indexOf(c)!==-1))return!0;var j=f.skipFalsyValuesForTypes;return null==e&&(e="string"),!(!j||j.indexOf(e)===-1)},attrFromInputWithName:function(a,b,c){var d,e,f;return d=b.replace(/(:|\.|\[|\]|\s)/g,"\\$1"),e='[name="'+d+'"]',f=a.find(e).add(a.filter(e)),f.attr(c)},validateType:function(b,c,d){var e,f;if(f=a.serializeJSON,e=f.optionKeys(d?d.typeFunctions:f.defaultOptions.defaultTypes),c&&e.indexOf(c)===-1)throw new Error("serializeJSON ERROR: Invalid type "+c+" found in input name '"+b+"', please use one of "+e.join(", "));return!0},splitInputNameIntoKeysArray:function(b){var c,d;return d=a.serializeJSON,c=b.split("["),c=a.map(c,function(a){return a.replace(/\]/g,"")}),""===c[0]&&c.shift(),c},deepSet:function(b,c,d,e){var f,g,h,i,j,k;if(null==e&&(e={}),k=a.serializeJSON,k.isUndefined(b))throw new Error("ArgumentError: param 'o' expected to be an object or array, found undefined");if(!c||0===c.length)throw new Error("ArgumentError: param 'keys' expected to be an array with least one element");f=c[0],1===c.length?""===f?b.push(d):b[f]=d:(g=c[1],""===f&&(i=b.length-1,j=b[i],f=k.isObject(j)&&(k.isUndefined(j[g])||c.length>2)?i:i+1),""===g?!k.isUndefined(b[f])&&a.isArray(b[f])||(b[f]=[]):e.useIntKeysAsArrayIndex&&k.isValidArrayIndex(g)?!k.isUndefined(b[f])&&a.isArray(b[f])||(b[f]=[]):!k.isUndefined(b[f])&&k.isObject(b[f])||(b[f]={}),h=c.slice(1),k.deepSet(b[f],h,d,e))}}});
\ No newline at end of file
/**
* jQuery serializeObject
* @copyright 2014, macek <paulmacek@gmail.com>
* @link https://github.com/macek/jquery-serialize-object
* @license BSD
* @version 2.5.0
*/
!function(e,i){if("function"==typeof define&&define.amd)define(["exports","jquery"],function(e,r){return i(e,r)});else if("undefined"!=typeof exports){var r=require("jquery");i(exports,r)}else i(e,e.jQuery||e.Zepto||e.ender||e.$)}(this,function(e,i){function r(e,r){function n(e,i,r){return e[i]=r,e}function a(e,i){for(var r,a=e.match(t.key);void 0!==(r=a.pop());)if(t.push.test(r)){var u=s(e.replace(/\[\]$/,""));i=n([],u,i)}else t.fixed.test(r)?i=n([],r,i):t.named.test(r)&&(i=n({},r,i));return i}function s(e){return void 0===h[e]&&(h[e]=0),h[e]++}function u(e){switch(i('[name="'+e.name+'"]',r).attr("type")){case"checkbox":return"on"===e.value?!0:e.value;default:return e.value}}function f(i){if(!t.validate.test(i.name))return this;var r=a(i.name,u(i));return l=e.extend(!0,l,r),this}function d(i){if(!e.isArray(i))throw new Error("formSerializer.addPairs expects an Array");for(var r=0,t=i.length;t>r;r++)this.addPair(i[r]);return this}function o(){return l}function c(){return JSON.stringify(o())}var l={},h={};this.addPair=f,this.addPairs=d,this.serialize=o,this.serializeJSON=c}var t={validate:/^[a-z_][a-z0-9_]*(?:\[(?:\d*|[a-z0-9_]+)\])*$/i,key:/[a-z0-9_]+|(?=\[\])/gi,push:/^$/,fixed:/^\d+$/,named:/^[a-z0-9_]+$/i};return r.patterns=t,r.serializeObject=function(){return new r(i,this).addPairs(this.serializeArray()).serialize()},r.serializeJSON=function(){return new r(i,this).addPairs(this.serializeArray()).serializeJSON()},"undefined"!=typeof i.fn&&(i.fn.serializeObject=r.serializeObject,i.fn.serializeJSON=r.serializeJSON),e.FormSerializer=r,r});
/*
[Leo.C, Studio] (C)2004 - 2008
$Hanization: LeoChung $
$E-Mail: who@imll.net $
$HomePage: http://imll.net $
$Date: 2008/11/8 18:02 $
*/
/*
A simple class for displaying file information and progress
Note: This is a demonstration only and not part of SWFUpload.
Note: Some have had problems adapting this class in IE7. It may not be suitable for your application.
*/
// Constructor
// file is a SWFUpload file object
// targetID is the HTML element id attribute that the FileProgress HTML structure will be added to.
// Instantiating a new FileProgress object with an existing file will reuse/update the existing DOM elements
function FileProgress(file, targetID) {
this.fileProgressID = file.id;
this.opacity = 100;
this.height = 0;
this.fileProgressWrapper = document.getElementById(this.fileProgressID);
if (!this.fileProgressWrapper) {
this.fileProgressWrapper = document.createElement("div");
this.fileProgressWrapper.className = "progressWrapper";
this.fileProgressWrapper.id = this.fileProgressID;
this.fileProgressElement = document.createElement("div");
this.fileProgressElement.className = "progressContainer";
var progressCancel = document.createElement("a");
progressCancel.className = "progressCancel";
progressCancel.href = "#";
progressCancel.style.visibility = "hidden";
progressCancel.appendChild(document.createTextNode(" "));
var progressText = document.createElement("div");
progressText.className = "progressName";
progressText.appendChild(document.createTextNode(file.name));
var progressBar = document.createElement("div");
progressBar.className = "progressBarInProgress";
var progressStatus = document.createElement("div");
progressStatus.className = "progressBarStatus";
progressStatus.innerHTML = "&nbsp;";
this.fileProgressElement.appendChild(progressCancel);
this.fileProgressElement.appendChild(progressText);
this.fileProgressElement.appendChild(progressStatus);
this.fileProgressElement.appendChild(progressBar);
this.fileProgressWrapper.appendChild(this.fileProgressElement);
document.getElementById(targetID).appendChild(this.fileProgressWrapper);
} else {
this.fileProgressElement = this.fileProgressWrapper.firstChild;
}
this.height = this.fileProgressWrapper.offsetHeight;
}
FileProgress.prototype.setProgress = function (percentage) {
this.fileProgressElement.className = "progressContainer green";
this.fileProgressElement.childNodes[3].className = "progressBarInProgress";
this.fileProgressElement.childNodes[3].style.width = percentage + "%";
};
FileProgress.prototype.setComplete = function () {
this.fileProgressElement.className = "progressContainer blue";
this.fileProgressElement.childNodes[3].className = "progressBarComplete";
this.fileProgressElement.childNodes[3].style.width = "";
var oSelf = this;
setTimeout(function () {
oSelf.disappear();
}, 10000);
};
FileProgress.prototype.setError = function () {
this.fileProgressElement.className = "progressContainer red";
this.fileProgressElement.childNodes[3].className = "progressBarError";
this.fileProgressElement.childNodes[3].style.width = "";
var oSelf = this;
setTimeout(function () {
oSelf.disappear();
}, 5000);
};
FileProgress.prototype.setCancelled = function () {
this.fileProgressElement.className = "progressContainer";
this.fileProgressElement.childNodes[3].className = "progressBarError";
this.fileProgressElement.childNodes[3].style.width = "";
var oSelf = this;
setTimeout(function () {
oSelf.disappear();
}, 2000);
};
FileProgress.prototype.setStatus = function (status) {
this.fileProgressElement.childNodes[2].innerHTML = status;
};
// Show/Hide the cancel button
FileProgress.prototype.toggleCancel = function (show, swfUploadInstance) {
this.fileProgressElement.childNodes[0].style.visibility = show ? "visible" : "hidden";
if (swfUploadInstance) {
var fileID = this.fileProgressID;
this.fileProgressElement.childNodes[0].onclick = function () {
swfUploadInstance.cancelUpload(fileID);
return false;
};
}
};
// Fades out and clips away the FileProgress box.
FileProgress.prototype.disappear = function () {
var reduceOpacityBy = 15;
var reduceHeightBy = 4;
var rate = 30; // 15 fps
if (this.opacity > 0) {
this.opacity -= reduceOpacityBy;
if (this.opacity < 0) {
this.opacity = 0;
}
if (this.fileProgressWrapper.filters) {
try {
this.fileProgressWrapper.filters.item("DXImageTransform.Microsoft.Alpha").opacity = this.opacity;
} catch (e) {
// If it is not set initially, the browser will throw an error. This will set it if it is not set yet.
this.fileProgressWrapper.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + this.opacity + ")";
}
} else {
this.fileProgressWrapper.style.opacity = this.opacity / 100;
}
}
if (this.height > 0) {
this.height -= reduceHeightBy;
if (this.height < 0) {
this.height = 0;
}
this.fileProgressWrapper.style.height = this.height + "px";
}
if (this.height > 0 || this.opacity > 0) {
var oSelf = this;
setTimeout(function () {
oSelf.disappear();
}, rate);
} else {
this.fileProgressWrapper.style.display = "none";
}
};
\ No newline at end of file
/*
[Leo.C, Studio] (C)2004 - 2008
$Hanization: LeoChung $
$E-Mail: who@imll.net $
$HomePage: http://imll.net $
$Date: 2008/11/8 18:02 $
*/
/* Demo Note: This demo uses a FileProgress class that handles the UI for displaying the file name and percent complete.
The FileProgress class is not part of SWFUpload.
*/
/* **********************
Event Handlers
These are my custom event handlers to make my
web application behave the way I went when SWFUpload
completes different tasks. These aren't part of the SWFUpload
package. They are part of my application. Without these none
of the actions SWFUpload makes will show up in my application.
********************** */
function fileQueued(file) {
try {
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setStatus("正在等待...");
progress.toggleCancel(true, this);
} catch (ex) {
this.debug(ex);
}
}
function fileQueueError(file, errorCode, message) {
try {
if (errorCode === SWFUpload.QUEUE_ERROR.QUEUE_LIMIT_EXCEEDED) {
alert("您正在上传的文件队列过多.\n" + (message === 0 ? "您已达到上传限制" : "您最多能选择 " + (message > 1 ? "上传 " + message + " 文件." : "一个文件.")));
return;
}
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setError();
progress.toggleCancel(false);
switch (errorCode) {
case SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT:
progress.setStatus("文件尺寸过大.");
this.debug("错误代码: 文件尺寸过大, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE:
progress.setStatus("无法上传零字节文件.");
this.debug("错误代码: 零字节文件, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
case SWFUpload.QUEUE_ERROR.INVALID_FILETYPE:
progress.setStatus("不支持的文件类型.");
this.debug("错误代码: 不支持的文件类型, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
default:
if (file !== null) {
progress.setStatus("未处理的错误");
}
this.debug("错误代码: " + errorCode + ", 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
}
} catch (ex) {
this.debug(ex);
}
}
function fileDialogComplete(numFilesSelected, numFilesQueued) {
try {
if (numFilesSelected > 0) {
document.getElementById(this.customSettings.cancelButtonId).disabled = false;
}
/* I want auto start the upload and I can do that here */
this.startUpload();
} catch (ex) {
this.debug(ex);
}
}
function uploadStart(file) {
try {
/* I don't want to do any file validation or anything, I'll just update the UI and
return true to indicate that the upload should start.
It's important to update the UI here because in Linux no uploadProgress events are called. The best
we can do is say we are uploading.
*/
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setStatus("正在上传...");
progress.toggleCancel(true, this);
}
catch (ex) {}
return true;
}
function uploadProgress(file, bytesLoaded, bytesTotal) {
try {
var percent = Math.ceil((bytesLoaded / bytesTotal) * 100);
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setProgress(percent);
progress.setStatus("正在上传...");
} catch (ex) {
this.debug(ex);
}
}
function uploadSuccess(file, serverData) {
try {
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setComplete();
progress.setStatus("上传成功");
progress.toggleCancel(false);
} catch (ex) {
this.debug(ex);
}
}
function uploadError(file, errorCode, message) {
try {
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setError();
progress.toggleCancel(false);
switch (errorCode) {
case SWFUpload.UPLOAD_ERROR.HTTP_ERROR:
progress.setStatus("上传错误: " + message);
this.debug("错误代码: HTTP错误, 文件名: " + file.name + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.UPLOAD_FAILED:
progress.setStatus("上传失败");
this.debug("错误代码: 上传失败, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.IO_ERROR:
progress.setStatus("服务器 (IO) 错误");
this.debug("错误代码: IO 错误, 文件名: " + file.name + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.SECURITY_ERROR:
progress.setStatus("安全错误");
this.debug("错误代码: 安全错误, 文件名: " + file.name + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.UPLOAD_LIMIT_EXCEEDED:
progress.setStatus("超出上传限制.");
this.debug("错误代码: 超出上传限制, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.FILE_VALIDATION_FAILED:
progress.setStatus("无法验证. 跳过上传.");
this.debug("错误代码: 文件验证失败, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.FILE_CANCELLED:
// If there aren't any files left (they were all cancelled) disable the cancel button
if (this.getStats().files_queued === 0) {
document.getElementById(this.customSettings.cancelButtonId).disabled = true;
}
progress.setStatus("取消");
progress.setCancelled();
break;
case SWFUpload.UPLOAD_ERROR.UPLOAD_STOPPED:
progress.setStatus("停止");
break;
default:
progress.setStatus("未处理的错误: " + errorCode);
this.debug("错误代码: " + errorCode + ", 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
}
} catch (ex) {
this.debug(ex);
}
}
function uploadComplete(file) {
if (this.getStats().files_queued === 0) {
document.getElementById(this.customSettings.cancelButtonId).disabled = true;
}
}
// This event comes from the Queue Plugin
function queueComplete(numFilesUploaded) {
var status = document.getElementById("divStatus");
status.innerHTML = numFilesUploaded + " 个文件" + (numFilesUploaded === 1 ? "" : "s") + "已上传.";
}
/*
* SWFUpload jQuery Plugin v1.0.0
*
* Copyright (c) 2009 Adam Royle
* Licensed under the MIT license.
*
*/
(function($){
var defaultHandlers = ['swfupload_loaded_handler','file_queued_handler','file_queue_error_handler','file_dialog_start_handler','file_dialog_complete_handler','upload_start_handler','upload_progress_handler','upload_error_handler','upload_success_handler','upload_complete_handler','queue_complete_handler'];
var additionalHandlers = [];
$.fn.swfupload = function(){
var args = $.makeArray(arguments);
return this.each(function(){
var swfu;
if (args.length == 1 && typeof(args[0]) == 'object') {
swfu = $(this).data('__swfu');
if (!swfu) {
var settings = args[0];
var $magicUploadControl = $(this);
var handlers = [];
$.merge(handlers, defaultHandlers);
$.merge(handlers, additionalHandlers);
$.each(handlers, function(i, v){
var eventName = v.replace(/_handler$/, '').replace(/_([a-z])/g, function(){ return arguments[1].toUpperCase(); });
settings[v] = function() {
var event = $.Event(eventName);
$magicUploadControl.trigger(event, $.makeArray(arguments));
return !event.isDefaultPrevented();
};
});
$(this).data('__swfu', new SWFUpload(settings));
}
} else if (args.length > 0 && typeof(args[0]) == 'string') {
var methodName = args.shift();
swfu = $(this).data('__swfu');
if (swfu && swfu[methodName]) {
swfu[methodName].apply(swfu, args);
}
}
});
};
$.swfupload = {
additionalHandlers: function() {
if (arguments.length === 0) {
return additionalHandlers.slice();
} else {
$(arguments).each(function(i, v){
$.merge(additionalHandlers, $.makeArray(v));
});
}
},
defaultHandlers: function() {
return defaultHandlers.slice();
},
getInstance: function(el) {
return $(el).data('__swfu');
}
};
})(jQuery);
\ No newline at end of file
/*
[Leo.C, Studio] (C)2004 - 2008
$Hanization: LeoChung $
$E-Mail: who@imll.net $
$HomePage: http://imll.net $
$Date: 2008/11/8 18:02 $
*/
/*
Queue Plug-in
Features:
*Adds a cancelQueue() method for cancelling the entire queue.
*All queued files are uploaded when startUpload() is called.
*If false is returned from uploadComplete then the queue upload is stopped.
If false is not returned (strict comparison) then the queue upload is continued.
*Adds a QueueComplete event that is fired when all the queued files have finished uploading.
Set the event handler with the queue_complete_handler setting.
*/
var SWFUpload;
if (typeof(SWFUpload) === "function") {
SWFUpload.queue = {};
SWFUpload.prototype.initSettings = (function (oldInitSettings) {
return function () {
if (typeof(oldInitSettings) === "function") {
oldInitSettings.call(this);
}
this.customSettings.queue_cancelled_flag = false;
this.customSettings.queue_upload_count = 0;
this.settings.user_upload_complete_handler = this.settings.upload_complete_handler;
this.settings.upload_complete_handler = SWFUpload.queue.uploadCompleteHandler;
this.settings.queue_complete_handler = this.settings.queue_complete_handler || null;
};
})(SWFUpload.prototype.initSettings);
SWFUpload.prototype.startUpload = function (fileID) {
this.customSettings.queue_cancelled_flag = false;
this.callFlash("StartUpload", false, [fileID]);
};
SWFUpload.prototype.cancelQueue = function () {
this.customSettings.queue_cancelled_flag = true;
this.stopUpload();
var stats = this.getStats();
while (stats.files_queued > 0) {
this.cancelUpload();
stats = this.getStats();
}
};
SWFUpload.queue.uploadCompleteHandler = function (file) {
var user_upload_complete_handler = this.settings.user_upload_complete_handler;
var continueUpload;
if (file.filestatus === SWFUpload.FILE_STATUS.COMPLETE) {
this.customSettings.queue_upload_count++;
}
if (typeof(user_upload_complete_handler) === "function") {
continueUpload = (user_upload_complete_handler.call(this, file) === false) ? false : true;
} else {
continueUpload = true;
}
if (continueUpload) {
var stats = this.getStats();
if (stats.files_queued > 0 && this.customSettings.queue_cancelled_flag === false) {
this.startUpload();
} else if (this.customSettings.queue_cancelled_flag === false) {
this.queueEvent("queue_complete_handler", [this.customSettings.queue_upload_count]);
this.customSettings.queue_upload_count = 0;
} else {
this.customSettings.queue_cancelled_flag = false;
this.customSettings.queue_upload_count = 0;
}
}
};
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment