UNPKG

angular-jsv

Version:

JSV (JSON+CSV) httpParamSerializer for AngularJS

489 lines (435 loc) 16.8 kB
angular.module("JSV", []) .service("JsvHttpParamSerializer", function () { function isWindow(obj) { return obj && obj.window === obj; } function isScope(obj) { return obj && obj.$evalAsync && obj.$watch; } function toJsvReplacer(key, value) { var val = value; if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') { val = undefined; } else if (isWindow(value)) { val = '$WINDOW'; } else if (value && document === value) { val = '$DOCUMENT'; } else if (isScope(value)) { val = '$SCOPE'; } return val; } function toJsv(obj, pretty) { if (typeof obj === 'undefined') return undefined; if (!angular.isNumber(pretty)) { pretty = pretty ? 2 : null; } return JSV.stringify(obj, toJsvReplacer, pretty); } function serializeValue(v) { if (angular.isObject(v)) { return angular.isDate(v) ? v.toISOString() : toJsv(v); } return v; } function forEachSorted(obj, iterator, context) { var keys = Object.keys(obj).sort(); for (var i = 0; i < keys.length; i++) { iterator.call(context, obj[keys[i]], keys[i]); } return keys; } function encodeUriQuery(val, pctEncodeSpaces) { return encodeURIComponent(val). replace(/%40/gi, '@'). replace(/%3A/gi, ':'). replace(/%24/g, '$'). replace(/%2C/gi, ','). replace(/%3B/gi, ';'). replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); } return function (params) { if (!params) return ''; var parts = []; forEachSorted(params, function (value, key) { if (value === null || angular.isUndefined(value)) return; if (angular.isArray(value)) { angular.forEach(value, function (v, k) { parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(v))); }); } else { parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value))); } }); return parts.join('&'); } }); /** * Created by IntelliJ IDEA. * User: mythz * Date: 16-Jun-2010 * Time: 00:51:17 * To change this template use File | Settings | File Templates. */ (function () { if (typeof window !== "undefined" && window !== null) { window.JSV = JSV = {}; } else if (typeof module !== "undefined" && module !== null) { module.exports = JSV = {}; } /** * parses JSV text into a JavaScript type * @param str */ JSV.parse = function (str) { if (!str) return str; if (str[0] == '{') { return JSV.parseObject_(str); } else if (str[0] == '[') { return JSV.parseArray_(str); } else { return JSV.parseString(str); } } JSV.ESCAPE_CHARS = ['"', ',', '{', '}', '[', ']']; JSV.parseArray_ = function (str) { var to = [], value = JSV.stripList_(str); if (!value) return to; if (value[0] == '{') { var ref = { i: 0 }; do { var itemValue = JSV.eatMapValue_(value, ref); to.push(JSV.parse(itemValue)); } while (++ref.i < value.length); } else { for (var ref = { i: 0 }; ref.i < value.length; ref.i++) { var elementValue = JSV.eatElementValue_(value, ref); to.push(JSV.parse(elementValue)); } } return to; }; JSV.parseObject_ = function (str) { if (str[0] != '{') { throw "Type definitions should start with a '{', got string starting with: " + str.substr(0, str.length < 50 ? str.length : 50); } var name, obj = {}; if (str == '{}') return null; for (var ref = { i: 1 }, strTypeLength = str.length; ref.i < strTypeLength; ref.i++) { name = JSV.eatMapKey_(str, ref); ref.i++; var value = JSV.eatMapValue_(str, ref); obj[name] = JSV.parse(value); } return obj; } JSV.eatElementValue_ = function (value, ref) { return JSV.eatUntilCharFound_(value, ref, ','); } JSV.containsAny_ = function (str, tests) { if (!is.String(str)) return; for (var i = 0, len = tests.length; i < len; i++) { if (str.indexOf(tests[i]) != -1) return true; } return false; }; JSV.toCsvField = function (text) { return !text || JSV.containsAny_(JSV.ESCAPE_CHARS) ? text : '"' + text.replace(/"/g, '""') + '"'; } JSV.parseString = JSV.fromCsvField = function (text) { return !text || text[0] != '"' ? text : text.substr(1, text.length - 2).replace(/""/g, '"'); } JSV.stripList_ = function (value) { if (!value) return null; return value[0] == '[' ? value.substr(1, value.length - 2) : value; }; /** * @param value {string} * @param ref {ref int} * @param findChar {char} */ JSV.eatUntilCharFound_ = function (value, ref, findChar) { var tokenStartPos = ref.i; var valueLength = value.length; if (value[tokenStartPos] != '"') { ref.i = value.indexOf(findChar, tokenStartPos); if (ref.i == -1) ref.i = valueLength; return value.substr(tokenStartPos, ref.i - tokenStartPos); } while (++ref.i < valueLength) { if (value[ref.i] == '"') { if (ref.i + 1 >= valueLength) { return value.substr(tokenStartPos, ++ref.i - tokenStartPos); } if (value[ref.i + 1] == '"') { ref.i++; } else if (value[ref.i + 1] == findChar) { return value.substr(tokenStartPos, ++ref.i - tokenStartPos); } } } throw "Could not find ending quote"; } /** * * @param value {string} * @param i {ref int} */ JSV.eatMapKey_ = function (value, ref) { var tokenStartPos = ref.i; while (value[++ref.i] != ':' && ref.i < value.length) { } return value.substr(tokenStartPos, ref.i - tokenStartPos); } /** * * @param value {string} * @param ref {ref int} */ JSV.eatMapValue_ = function (value, ref) { var tokenStartPos = ref.i; var valueLength = value.length; if (ref.i == valueLength) return null; var valueChar = value[ref.i]; //If we are at the end, return. if (valueChar == ',' || valueChar == '}') { return null; } //Is List, i.e. [...] var withinQuotes = false; if (valueChar == '[') { var endsToEat = 1; while (++ref.i < valueLength && endsToEat > 0) { valueChar = value[ref.i]; if (valueChar == '"') withinQuotes = !withinQuotes; if (withinQuotes) continue; if (valueChar == '[') endsToEat++; if (valueChar == ']') endsToEat--; } return value.substr(tokenStartPos, ref.i - tokenStartPos); } //Is Type/Map, i.e. {...} if (valueChar == '{') { var endsToEat = 1; while (++ref.i < valueLength && endsToEat > 0) { valueChar = value[ref.i]; if (valueChar == '"') withinQuotes = !withinQuotes; if (withinQuotes) continue; if (valueChar == '{') endsToEat++; if (valueChar == '}') endsToEat--; } return value.substr(tokenStartPos, ref.i - tokenStartPos); } //Is Within Quotes, i.e. "..." if (valueChar == '"') { while (++ref.i < valueLength) { valueChar = value[ref.i]; if (valueChar != '"') continue; var isLiteralQuote = ref.i + 1 < valueLength && value[ref.i + 1] == '"'; ref.i++; //skip quote if (!isLiteralQuote) break; } return value.substr(tokenStartPos, ref.i - tokenStartPos); } //Is Value while (++ref.i < valueLength) { valueChar = value[ref.i]; if (valueChar == ',' || valueChar == '}') break; } return value.substr(tokenStartPos, ref.i - tokenStartPos); } JSV.isEmpty_ = function (a) { return (a === null || a === undefined || a === ""); } JSV.isFunction_ = function (a) { return (typeof (a) === 'function') ? a.constructor.toString().match(/Function/) !== null : false; }; JSV.isString_ = function (a) { if (a === null || a === undefined) return false; return (typeof (a) === 'string') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/string/i) !== null : false; }; JSV.isDate_ = function (a) { if (JSV.isEmpty_(a)) return false; return (typeof (a) === 'date') ? true : (typeof (a) === 'object') ? a.constructor.toString().match(/date/i) !== null : false; }; JSV.isArray_ = function (a) { if (a === null || a === undefined || a === "") return false; return (typeof (a) === 'object') ? a.constructor.toString().match(/array/i) !== null || a.length !== undefined : false; }; JSV.toXsdDateTime = function (date) { function pad(n) { var s = n.toString(); return s.length < 2 ? '0' + s : s; }; var yyyy = date.getUTCFullYear(); var MM = pad(date.getUTCMonth() + 1); var dd = pad(date.getUTCDate()); var hh = pad(date.getUTCHours()); var mm = pad(date.getUTCMinutes()); var ss = pad(date.getUTCSeconds()); var ms = pad(date.getUTCMilliseconds()); return yyyy + '-' + MM + '-' + dd + 'T' + hh + ':' + mm + ':' + ss + '.' + ms + 'Z'; } JSV.serialize = JSV.stringify = function (obj) { if (obj === null || obj === undefined) return null; var typeOf = typeof (obj); if (obj === 'function') return null; if (typeOf === 'object') { var ctorStr = obj.constructor.toString().toLowerCase(); if (ctorStr.indexOf('string') != -1) return JSV.escapeString(obj); if (ctorStr.indexOf('boolean') != -1) return obj ? "True" : "False"; if (ctorStr.indexOf('number') != -1) return obj; if (ctorStr.indexOf('date') != -1) return JSV.escapeString(JSV.toXsdDateTime(obj)); if (ctorStr.indexOf('array') != -1) return JSV.serializeArray(obj); return JSV.serializeObject(obj); } else { switch (typeOf) { case 'string': return JSV.escapeString(obj); break; case 'boolean': return obj ? "True" : "False"; break; case 'date': return JSV.escapeString(JSV.toXsdDateTime(obj)); break; case 'array': return JSV.serializeArray(obj); break; case 'number': default: return obj; } } }; JSV.serializeObject = function (obj) { var value, sb = new StringBuffer(); for (var key in obj) { value = obj[key]; if (!obj.hasOwnProperty(key) || JSV.isEmpty_(value) || JSV.isFunction_(value)) continue; if (sb.getLength() > 0) sb.append(','); sb.append(JSV.escapeString(key)); sb.append(':'); sb.append(JSV.serialize(value)); } return '{' + sb.toString() + '}'; }; JSV.serializeArray = function (array) { var value, sb = new StringBuffer(); for (var i = 0, len = array.length; i < len; i++) { value = array[i]; if (JSV.isEmpty_(value) || JSV.isFunction_(value)) continue; if (sb.getLength() > 0) sb.append(','); sb.append(JSV.serialize(value)); } return '[' + sb.toString() + ']'; }; JSV.escapeString = function (str) { if (str === undefined || str === null) return null; if (str === '') return '""'; if (str.indexOf('"')) { str = str.replace(/"/g, '""'); } if (JSV.containsAny_(str, JSV.ESCAPE_CHARS)) { return '"' + str + '"'; } return str; }; JSV.containsAny_ = function (str, tests) { if (!JSV.isString_(str)) return; for (var i = 0, len = tests.length; i < len; i++) { if (str.indexOf(tests[i]) != -1) return true; } return false; }; /* Closure Library StringBuffer for efficient string concatenation */ var hasScriptEngine = 'ScriptEngine' in window; var HAS_JSCRIPT = hasScriptEngine && window['ScriptEngine']() == 'JScript'; StringBuffer = function (opt_a1, var_args) { this.buffer_ = HAS_JSCRIPT ? [] : ''; if (opt_a1 != null) { this.append.apply(this, arguments); } }; StringBuffer.prototype.set = function (s) { this.clear(); this.append(s); }; if (HAS_JSCRIPT) { StringBuffer.prototype.bufferLength_ = 0; StringBuffer.prototype.append = function (a1, opt_a2, var_args) { // IE version. if (opt_a2 == null) { // second argument is undefined (null == undefined) // Array assignment is 2x faster than Array push. Also, use a1 // directly to avoid arguments instantiation, another 2x improvement. this.buffer_[this.bufferLength_++] = a1; } else { this.buffer_.push.apply(/** @type {Array} */(this.buffer_), arguments); this.bufferLength_ = this.buffer_.length; } return this; }; } else { StringBuffer.prototype.append = function (a1, opt_a2, var_args) { // W3 version. this.buffer_ += a1; if (opt_a2 != null) { // second argument is undefined (null == undefined) for (var i = 1; i < arguments.length; i++) { this.buffer_ += arguments[i]; } } return this; }; } StringBuffer.prototype.clear = function () { if (HAS_JSCRIPT) { this.buffer_.length = 0; // Reuse the array to avoid creating new object. this.bufferLength_ = 0; } else { this.buffer_ = ''; } }; StringBuffer.prototype.getLength = function () { return this.toString().length; }; StringBuffer.prototype.toString = function () { if (HAS_JSCRIPT) { var str = this.buffer_.join(''); this.clear(); if (str) { this.append(str); } return str; } else { return /** @type {string} */ (this.buffer_); } }; })();