diff options
Diffstat (limited to 'js/dojo-1.7.2/dojox/json')
| -rw-r--r-- | js/dojo-1.7.2/dojox/json/README | 42 | ||||
| -rw-r--r-- | js/dojo-1.7.2/dojox/json/query.js | 262 | ||||
| -rw-r--r-- | js/dojo-1.7.2/dojox/json/ref.js | 360 | ||||
| -rw-r--r-- | js/dojo-1.7.2/dojox/json/schema.js | 223 |
4 files changed, 887 insertions, 0 deletions
diff --git a/js/dojo-1.7.2/dojox/json/README b/js/dojo-1.7.2/dojox/json/README new file mode 100644 index 0000000..b80d139 --- /dev/null +++ b/js/dojo-1.7.2/dojox/json/README @@ -0,0 +1,42 @@ +------------------------------------------------------------------------------- +DojoX JSON Modules +------------------------------------------------------------------------------- +Version 0.1 +Release date: 07/06/2008 +------------------------------------------------------------------------------- +Project state: +beta +------------------------------------------------------------------------------- +Credits + Kris Zyp (kris@sitepen.com) +------------------------------------------------------------------------------- +Project description +JSONQuery (dojox.json.query) - A comprehensive object data query tool +JSON Schema (dojox.json.schema) - An object validation tool based on JSON Schema +JSON Referencing (dojox.json.ref) - JSON Referencing capable serializer and +deserializer. + +------------------------------------------------------------------------------- +Dependencies: + +dojox.json.ref uses dojo.date.stamp +------------------------------------------------------------------------------- +Documentation +See the Dojo API tool (http://dojotoolkit.org/api) +------------------------------------------------------------------------------- +Installation instructions + +Grab the following from the Dojo SVN Repository: +http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/json/* + +Install into the following directory structure: +/dojox/json/ + +...which should be at the same level as your Dojo checkout. + +/dojox/json/* + +Require in the dojox.data stores you wish to use. +------------------------------------------------------------------------------- +Additional Notes + diff --git a/js/dojo-1.7.2/dojox/json/query.js b/js/dojo-1.7.2/dojox/json/query.js new file mode 100644 index 0000000..0f4c914 --- /dev/null +++ b/js/dojo-1.7.2/dojox/json/query.js @@ -0,0 +1,262 @@ +//>>built +define("dojox/json/query", ["dojo/_base/kernel", "dojox", "dojo/_base/array"], function(dojo, dojox){ + + dojo.getObject("json", true, dojox); + + dojox.json._slice = function(obj,start,end,step){ + // handles slice operations: [3:6:2] + var len=obj.length,results = []; + end = end || len; + start = (start < 0) ? Math.max(0,start+len) : Math.min(len,start); + end = (end < 0) ? Math.max(0,end+len) : Math.min(len,end); + for(var i=start; i<end; i+=step){ + results.push(obj[i]); + } + return results; + } + dojox.json._find = function e(obj,name){ + // handles ..name, .*, [*], [val1,val2], [val] + // name can be a property to search for, undefined for full recursive, or an array for picking by index + var results = []; + function walk(obj){ + if(name){ + if(name===true && !(obj instanceof Array)){ + //recursive object search + results.push(obj); + }else if(obj[name]){ + // found the name, add to our results + results.push(obj[name]); + } + } + for(var i in obj){ + var val = obj[i]; + if(!name){ + // if we don't have a name we are just getting all the properties values (.* or [*]) + results.push(val); + }else if(val && typeof val == 'object'){ + + walk(val); + } + } + } + if(name instanceof Array){ + // this is called when multiple items are in the brackets: [3,4,5] + if(name.length==1){ + // this can happen as a result of the parser becoming confused about commas + // in the brackets like [@.func(4,2)]. Fixing the parser would require recursive + // analsys, very expensive, but this fixes the problem nicely. + return obj[name[0]]; + } + for(var i = 0; i < name.length; i++){ + results.push(obj[name[i]]); + } + }else{ + // otherwise we expanding + walk(obj); + } + return results; + } + + dojox.json._distinctFilter = function(array, callback){ + // does the filter with removal of duplicates in O(n) + var outArr = []; + var primitives = {}; + for(var i=0,l=array.length; i<l; ++i){ + var value = array[i]; + if(callback(value, i, array)){ + if((typeof value == 'object') && value){ + // with objects we prevent duplicates with a marker property + if(!value.__included){ + value.__included = true; + outArr.push(value); + } + }else if(!primitives[value + typeof value]){ + // with primitives we prevent duplicates by putting it in a map + primitives[value + typeof value] = true; + outArr.push(value); + } + } + } + for(i=0,l=outArr.length; i<l; ++i){ + // cleanup the marker properties + if(outArr[i]){ + delete outArr[i].__included; + } + } + return outArr; + } + return dojox.json.query = function(/*String*/query,/*Object?*/obj){ + // summary: + // Performs a JSONQuery on the provided object and returns the results. + // If no object is provided (just a query), it returns a "compiled" function that evaluates objects + // according to the provided query. + // query: + // Query string + // obj: + // Target of the JSONQuery + // + // description: + // JSONQuery provides a comprehensive set of data querying tools including filtering, + // recursive search, sorting, mapping, range selection, and powerful expressions with + // wildcard string comparisons and various operators. JSONQuery generally supersets + // JSONPath and provides syntax that matches and behaves like JavaScript where + // possible. + // + // JSONQuery evaluations begin with the provided object, which can referenced with + // $. From + // the starting object, various operators can be successively applied, each operating + // on the result of the last operation. + // + // Supported Operators: + // -------------------- + // * .property - This will return the provided property of the object, behaving exactly + // like JavaScript. + // * [expression] - This returns the property name/index defined by the evaluation of + // the provided expression, behaving exactly like JavaScript. + // * [?expression] - This will perform a filter operation on an array, returning all the + // items in an array that match the provided expression. This operator does not + // need to be in brackets, you can simply use ?expression, but since it does not + // have any containment, no operators can be used afterwards when used + // without brackets. + // * [^?expression] - This will perform a distinct filter operation on an array. This behaves + // as [?expression] except that it will remove any duplicate values/objects from the + // result set. + // * [/expression], [\expression], [/expression, /expression] - This performs a sort + // operation on an array, with sort based on the provide expression. Multiple comma delimited sort + // expressions can be provided for multiple sort orders (first being highest priority). / + // indicates ascending order and \ indicates descending order + // * [=expression] - This performs a map operation on an array, creating a new array + // with each item being the evaluation of the expression for each item in the source array. + // * [start:end:step] - This performs an array slice/range operation, returning the elements + // from the optional start index to the optional end index, stepping by the optional step number. + // * [expr,expr] - This a union operator, returning an array of all the property/index values from + // the evaluation of the comma delimited expressions. + // * .* or [*] - This returns the values of all the properties of the current object. + // * $ - This is the root object, If a JSONQuery expression does not being with a $, + // it will be auto-inserted at the beginning. + // * @ - This is the current object in filter, sort, and map expressions. This is generally + // not necessary, names are auto-converted to property references of the current object + // in expressions. + // * ..property - Performs a recursive search for the given property name, returning + // an array of all values with such a property name in the current object and any subobjects + // * expr = expr - Performs a comparison (like JS's ==). When comparing to + // a string, the comparison string may contain wildcards * (matches any number of + // characters) and ? (matches any single character). + // * expr ~ expr - Performs a string comparison with case insensitivity. + // * ..[?expression] - This will perform a deep search filter operation on all the objects and + // subobjects of the current data. Rather than only searching an array, this will search + // property values, arrays, and their children. + // * $1,$2,$3, etc. - These are references to extra parameters passed to the query + // function or the evaluator function. + // * +, -, /, *, &, |, %, (, ), <, >, <=, >=, != - These operators behave just as they do + // in JavaScript. + // + // + // + // | dojox.json.query(queryString,object) + // and + // | dojox.json.query(queryString)(object) + // always return identical results. The first one immediately evaluates, the second one returns a + // function that then evaluates the object. + // + // example: + // | dojox.json.query("foo",{foo:"bar"}) + // This will return "bar". + // + // example: + // | evaluator = dojox.json.query("?foo='bar'&rating>3"); + // This creates a function that finds all the objects in an array with a property + // foo that is equals to "bar" and with a rating property with a value greater + // than 3. + // | evaluator([{foo:"bar",rating:4},{foo:"baz",rating:2}]) + // This returns: + // | {foo:"bar",rating:4} + // + // example: + // | evaluator = dojox.json.query("$[?price<15.00][\rating][0:10]"); + // This finds objects in array with a price less than 15.00 and sorts then + // by rating, highest rated first, and returns the first ten items in from this + // filtered and sorted list. + var depth = 0; + var str = []; + query = query.replace(/"(\\.|[^"\\])*"|'(\\.|[^'\\])*'|[\[\]]/g,function(t){ + depth += t == '[' ? 1 : t == ']' ? -1 : 0; // keep track of bracket depth + return (t == ']' && depth > 0) ? '`]' : // we mark all the inner brackets as skippable + (t.charAt(0) == '"' || t.charAt(0) == "'") ? "`" + (str.push(t) - 1) :// and replace all the strings + t; + }); + var prefix = ''; + function call(name){ + // creates a function call and puts the expression so far in a parameter for a call + prefix = name + "(" + prefix; + } + function makeRegex(t,a,b,c,d,e,f,g){ + // creates a regular expression matcher for when wildcards and ignore case is used + return str[g].match(/[\*\?]/) || f == '~' ? + "/^" + str[g].substring(1,str[g].length-1).replace(/\\([btnfr\\"'])|([^\w\*\?])/g,"\\$1$2").replace(/([\*\?])/g,"[\\w\\W]$1") + (f == '~' ? '$/i' : '$/') + ".test(" + a + ")" : + t; + } + query.replace(/(\]|\)|push|pop|shift|splice|sort|reverse)\s*\(/,function(){ + throw new Error("Unsafe function call"); + }); + + query = query.replace(/([^<>=]=)([^=])/g,"$1=$2"). // change the equals to comparisons except operators ==, <=, >= + replace(/@|(\.\s*)?[a-zA-Z\$_]+(\s*:)?/g,function(t){ + return t.charAt(0) == '.' ? t : // leave .prop alone + t == '@' ? "$obj" :// the reference to the current object + (t.match(/:|^(\$|Math|true|false|null)$/) ? "" : "$obj.") + t; // plain names should be properties of root... unless they are a label in object initializer + }). + replace(/\.?\.?\[(`\]|[^\]])*\]|\?.*|\.\.([\w\$_]+)|\.\*/g,function(t,a,b){ + var oper = t.match(/^\.?\.?(\[\s*\^?\?|\^?\?|\[\s*==)(.*?)\]?$/); // [?expr] and ?expr and [=expr and =expr + if(oper){ + var prefix = ''; + if(t.match(/^\./)){ + // recursive object search + call("dojox.json._find"); + prefix = ",true)"; + } + call(oper[1].match(/\=/) ? "dojo.map" : oper[1].match(/\^/) ? "dojox.json._distinctFilter" : "dojo.filter"); + return prefix + ",function($obj){return " + oper[2] + "})"; + } + oper = t.match(/^\[\s*([\/\\].*)\]/); // [/sortexpr,\sortexpr] + if(oper){ + // make a copy of the array and then sort it using the sorting expression + return ".concat().sort(function(a,b){" + oper[1].replace(/\s*,?\s*([\/\\])\s*([^,\\\/]+)/g,function(t,a,b){ + return "var av= " + b.replace(/\$obj/,"a") + ",bv= " + b.replace(/\$obj/,"b") + // FIXME: Should check to make sure the $obj token isn't followed by characters + ";if(av>bv||bv==null){return " + (a== "/" ? 1 : -1) +";}\n" + + "if(bv>av||av==null){return " + (a== "/" ? -1 : 1) +";}\n"; + }) + "return 0;})"; + } + oper = t.match(/^\[(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)\]/); // slice [0:3] + if(oper){ + call("dojox.json._slice"); + return "," + (oper[1] || 0) + "," + (oper[2] || 0) + "," + (oper[3] || 1) + ")"; + } + if(t.match(/^\.\.|\.\*|\[\s*\*\s*\]|,/)){ // ..prop and [*] + call("dojox.json._find"); + return (t.charAt(1) == '.' ? + ",'" + b + "'" : // ..prop + t.match(/,/) ? + "," + t : // [prop1,prop2] + "") + ")"; // [*] + } + return t; + }). + replace(/(\$obj\s*((\.\s*[\w_$]+\s*)|(\[\s*`([0-9]+)\s*`\]))*)(==|~)\s*`([0-9]+)/g,makeRegex). // create regex matching + replace(/`([0-9]+)\s*(==|~)\s*(\$obj\s*((\.\s*[\w_$]+)|(\[\s*`([0-9]+)\s*`\]))*)/g,function(t,a,b,c,d,e,f,g){ // and do it for reverse = + return makeRegex(t,c,d,e,f,g,b,a); + }); + query = prefix + (query.charAt(0) == '$' ? "" : "$") + query.replace(/`([0-9]+|\])/g,function(t,a){ + //restore the strings + return a == ']' ? ']' : str[a]; + }); + // create a function within this scope (so it can use expand and slice) + + var executor = eval("1&&function($,$1,$2,$3,$4,$5,$6,$7,$8,$9){var $obj=$;return " + query + "}"); + for(var i = 0;i<arguments.length-1;i++){ + arguments[i] = arguments[i+1]; + } + return obj ? executor.apply(this,arguments) : executor; + }; + +});
\ No newline at end of file diff --git a/js/dojo-1.7.2/dojox/json/ref.js b/js/dojo-1.7.2/dojox/json/ref.js new file mode 100644 index 0000000..4da8d80 --- /dev/null +++ b/js/dojo-1.7.2/dojox/json/ref.js @@ -0,0 +1,360 @@ +//>>built +define("dojox/json/ref", ["dojo/_base/kernel", "dojox", "dojo/date/stamp", "dojo/_base/array", "dojo/_base/json"], function(dojo, dojox){ + +dojo.getObject("json", true, dojox); + +return dojox.json.ref = { + // summary: + // Adds advanced JSON {de}serialization capabilities to the base json library. + // This enhances the capabilities of dojo.toJson and dojo.fromJson, + // adding referencing support, date handling, and other extra format handling. + // On parsing, references are resolved. When references are made to + // ids/objects that have been loaded yet, the loader function will be set to + // _loadObject to denote a lazy loading (not loaded yet) object. + + + resolveJson: function(/*Object*/ root,/*Object?*/ args){ + // summary: + // Indexes and resolves references in the JSON object. + // description: + // A JSON Schema object that can be used to advise the handling of the JSON (defining ids, date properties, urls, etc) + // + // root: + // The root object of the object graph to be processed + // args: + // Object with additional arguments: + // + // The *index* parameter. + // This is the index object (map) to use to store an index of all the objects. + // If you are using inter-message referencing, you must provide the same object for each call. + // The *defaultId* parameter. + // This is the default id to use for the root object (if it doesn't define it's own id) + // The *idPrefix* parameter. + // This the prefix to use for the ids as they enter the index. This allows multiple tables + // to use ids (that might otherwise collide) that enter the same global index. + // idPrefix should be in the form "/Service/". For example, + // if the idPrefix is "/Table/", and object is encountered {id:"4",...}, this would go in the + // index as "/Table/4". + // The *idAttribute* parameter. + // This indicates what property is the identity property. This defaults to "id" + // The *assignAbsoluteIds* parameter. + // This indicates that the resolveJson should assign absolute ids (__id) as the objects are being parsed. + // + // The *schemas* parameter + // This provides a map of schemas, from which prototypes can be retrieved + // The *loader* parameter + // This is a function that is called added to the reference objects that can't be resolved (lazy objects) + // return: + // An object, the result of the processing + args = args || {}; + var idAttribute = args.idAttribute || 'id'; + var refAttribute = this.refAttribute; + var idAsRef = args.idAsRef; + var prefix = args.idPrefix || ''; + var assignAbsoluteIds = args.assignAbsoluteIds; + var index = args.index || {}; // create an index if one doesn't exist + var timeStamps = args.timeStamps; + var ref,reWalk=[]; + var pathResolveRegex = /^(.*\/)?(\w+:\/\/)|[^\/\.]+\/\.\.\/|^.*\/(\/)/; + var addProp = this._addProp; + var F = function(){}; + function walk(it, stop, defaultId, needsPrefix, schema, defaultObject){ + // this walks the new graph, resolving references and making other changes + var i, update, val, id = idAttribute in it ? it[idAttribute] : defaultId; + if(idAttribute in it || ((id !== undefined) && needsPrefix)){ + id = (prefix + id).replace(pathResolveRegex,'$2$3'); + } + var target = defaultObject || it; + if(id !== undefined){ // if there is an id available... + if(assignAbsoluteIds){ + it.__id = id; + } + if(args.schemas && (!(it instanceof Array)) && // won't try on arrays to do prototypes, plus it messes with queries + (val = id.match(/^(.+\/)[^\.\[]*$/))){ // if it has a direct table id (no paths) + schema = args.schemas[val[1]]; + } + // if the id already exists in the system, we should use the existing object, and just + // update it... as long as the object is compatible + if(index[id] && ((it instanceof Array) == (index[id] instanceof Array))){ + target = index[id]; + delete target.$ref; // remove this artifact + delete target._loadObject; + update = true; + }else{ + var proto = schema && schema.prototype; // and if has a prototype + if(proto){ + // if the schema defines a prototype, that needs to be the prototype of the object + F.prototype = proto; + target = new F(); + } + } + index[id] = target; // add the prefix, set _id, and index it + if(timeStamps){ + timeStamps[id] = args.time; + } + } + while(schema){ + var properties = schema.properties; + if(properties){ + for(i in it){ + var propertyDefinition = properties[i]; + if(propertyDefinition && propertyDefinition.format == 'date-time' && typeof it[i] == 'string'){ + it[i] = dojo.date.stamp.fromISOString(it[i]); + } + } + } + schema = schema["extends"]; + } + var length = it.length; + for(i in it){ + if(i==length){ + break; + } + if(it.hasOwnProperty(i)){ + val=it[i]; + if((typeof val =='object') && val && !(val instanceof Date) && i != '__parent'){ + ref=val[refAttribute] || (idAsRef && val[idAttribute]); + if(!ref || !val.__parent){ + if(it != reWalk){ + val.__parent = target; + } + } + if(ref){ // a reference was found + // make sure it is a safe reference + delete it[i];// remove the property so it doesn't resolve to itself in the case of id.propertyName lazy values + var path = ref.toString().replace(/(#)([^\.\[])/,'$1.$2').match(/(^([^\[]*\/)?[^#\.\[]*)#?([\.\[].*)?/); // divide along the path + if(index[(prefix + ref).replace(pathResolveRegex,'$2$3')]){ + ref = index[(prefix + ref).replace(pathResolveRegex,'$2$3')]; + }else if((ref = (path[1]=='$' || path[1]=='this' || path[1]=='') ? root : index[(prefix + path[1]).replace(pathResolveRegex,'$2$3')])){ // a $ indicates to start with the root, otherwise start with an id + // if there is a path, we will iterate through the path references + if(path[3]){ + path[3].replace(/(\[([^\]]+)\])|(\.?([^\.\[]+))/g,function(t,a,b,c,d){ + ref = ref && ref[b ? b.replace(/[\"\'\\]/,'') : d]; + }); + } + } + if(ref){ + val = ref; + }else{ + // otherwise, no starting point was found (id not found), if stop is set, it does not exist, we have + // unloaded reference, if stop is not set, it may be in a part of the graph not walked yet, + // we will wait for the second loop + if(!stop){ + var rewalking; + if(!rewalking){ + reWalk.push(target); // we need to rewalk it to resolve references + } + rewalking = true; // we only want to add it once + val = walk(val, false, val[refAttribute], true, propertyDefinition); + // create a lazy loaded object + val._loadObject = args.loader; + } + } + }else{ + if(!stop){ // if we are in stop, that means we are in the second loop, and we only need to check this current one, + // further walking may lead down circular loops + val = walk( + val, + reWalk==it, + id === undefined ? undefined : addProp(id, i), // the default id to use + false, + propertyDefinition, + // if we have an existing object child, we want to + // maintain it's identity, so we pass it as the default object + target != it && typeof target[i] == 'object' && target[i] + ); + } + } + } + it[i] = val; + if(target!=it && !target.__isDirty){// do updates if we are updating an existing object and it's not dirty + var old = target[i]; + target[i] = val; // only update if it changed + if(update && val !== old && // see if it is different + !target._loadObject && // no updates if we are just lazy loading + !(i.charAt(0) == '_' && i.charAt(1) == '_') && i != "$ref" && + !(val instanceof Date && old instanceof Date && val.getTime() == old.getTime()) && // make sure it isn't an identical date + !(typeof val == 'function' && typeof old == 'function' && val.toString() == old.toString()) && // make sure it isn't an indentical function + index.onUpdate){ + index.onUpdate(target,i,old,val); // call the listener for each update + } + } + } + } + + if(update && (idAttribute in it || target instanceof Array)){ + // this means we are updating with a full representation of the object, we need to remove deleted + for(i in target){ + if(!target.__isDirty && target.hasOwnProperty(i) && !it.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_') && !(target instanceof Array && isNaN(i))){ + if(index.onUpdate && i != "_loadObject" && i != "_idAttr"){ + index.onUpdate(target,i,target[i],undefined); // call the listener for each update + } + delete target[i]; + while(target instanceof Array && target.length && target[target.length-1] === undefined){ + // shorten the target if necessary + target.length--; + } + } + } + }else{ + if(index.onLoad){ + index.onLoad(target); + } + } + return target; + } + if(root && typeof root == 'object'){ + root = walk(root,false,args.defaultId, true); // do the main walk through + walk(reWalk,false); // re walk any parts that were not able to resolve references on the first round + } + return root; + }, + + + fromJson: function(/*String*/ str,/*Object?*/ args){ + // summary: + // evaluates the passed string-form of a JSON object. + // + // str: + // a string literal of a JSON item, for instance: + // '{ "foo": [ "bar", 1, { "baz": "thud" } ] }' + // args: See resolveJson + // + // return: + // An object, the result of the evaluation + function ref(target){ // support call styles references as well + var refObject = {}; + refObject[this.refAttribute] = target; + return refObject; + } + try{ + var root = eval('(' + str + ')'); // do the eval + }catch(e){ + throw new SyntaxError("Invalid JSON string: " + e.message + " parsing: "+ str); + } + if(root){ + return this.resolveJson(root, args); + } + return root; + }, + + toJson: function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*Object?*/ idPrefix, /*Object?*/ indexSubObjects){ + // summary: + // Create a JSON serialization of an object. + // This has support for referencing, including circular references, duplicate references, and out-of-message references + // id and path-based referencing is supported as well and is based on http://www.json.com/2007/10/19/json-referencing-proposal-and-library/. + // + // it: + // an object to be serialized. + // + // prettyPrint: + // if true, we indent objects and arrays to make the output prettier. + // The variable dojo.toJsonIndentStr is used as the indent string + // -- to use something other than the default (tab), + // change that variable before calling dojo.toJson(). + // + // idPrefix: The prefix that has been used for the absolute ids + // + // return: + // a String representing the serialized version of the passed object. + var useRefs = this._useRefs; + var addProp = this._addProp; + var refAttribute = this.refAttribute; + idPrefix = idPrefix || ''; // the id prefix for this context + var paths={}; + var generated = {}; + function serialize(it,path,_indentStr){ + if(typeof it == 'object' && it){ + var value; + if(it instanceof Date){ // properly serialize dates + return '"' + dojo.date.stamp.toISOString(it,{zulu:true}) + '"'; + } + var id = it.__id; + if(id){ // we found an identifiable object, we will just serialize a reference to it... unless it is the root + if(path != '#' && ((useRefs && !id.match(/#/)) || paths[id])){ + var ref = id; + if(id.charAt(0)!='#'){ + if(it.__clientId == id){ + ref = "cid:" + id; + }else if(id.substring(0, idPrefix.length) == idPrefix){ // see if the reference is in the current context + // a reference with a prefix matching the current context, the prefix should be removed + ref = id.substring(idPrefix.length); + }else{ + // a reference to a different context, assume relative url based referencing + ref = id; + } + } + var refObject = {}; + refObject[refAttribute] = ref; + return serialize(refObject,'#'); + } + path = id; + }else{ + it.__id = path; // we will create path ids for other objects in case they are circular + generated[path] = it; + } + paths[path] = it;// save it here so they can be deleted at the end + _indentStr = _indentStr || ""; + var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : ""; + var newLine = prettyPrint ? "\n" : ""; + var sep = prettyPrint ? " " : ""; + + if(it instanceof Array){ + var res = dojo.map(it, function(obj,i){ + var val = serialize(obj, addProp(path, i), nextIndent); + if(typeof val != "string"){ + val = "undefined"; + } + return newLine + nextIndent + val; + }); + return "[" + res.join("," + sep) + newLine + _indentStr + "]"; + } + + var output = []; + for(var i in it){ + if(it.hasOwnProperty(i)){ + var keyStr; + if(typeof i == "number"){ + keyStr = '"' + i + '"'; + }else if(typeof i == "string" && (i.charAt(0) != '_' || i.charAt(1) != '_')){ + // we don't serialize our internal properties __id and __clientId + keyStr = dojo._escapeString(i); + }else{ + // skip non-string or number keys + continue; + } + var val = serialize(it[i],addProp(path, i),nextIndent); + if(typeof val != "string"){ + // skip non-serializable values + continue; + } + output.push(newLine + nextIndent + keyStr + ":" + sep + val); + } + } + return "{" + output.join("," + sep) + newLine + _indentStr + "}"; + }else if(typeof it == "function" && dojox.json.ref.serializeFunctions){ + return it.toString(); + } + + return dojo.toJson(it); // use the default serializer for primitives + } + var json = serialize(it,'#',''); + if(!indexSubObjects){ + for(var i in generated) {// cleanup the temporary path-generated ids + delete generated[i].__id; + } + } + return json; + }, + _addProp: function(id, prop){ + return id + (id.match(/#/) ? id.length == 1 ? '' : '.' : '#') + prop; + }, + // refAttribute: String + // This indicates what property is the reference property. This acts like the idAttribute + // except that this is used to indicate the current object is a reference or only partially + // loaded. This defaults to "$ref". + refAttribute: "$ref", + _useRefs: false, + serializeFunctions: false +}; +}); diff --git a/js/dojo-1.7.2/dojox/json/schema.js b/js/dojo-1.7.2/dojox/json/schema.js new file mode 100644 index 0000000..6659956 --- /dev/null +++ b/js/dojo-1.7.2/dojox/json/schema.js @@ -0,0 +1,223 @@ +//>>built +define("dojox/json/schema", ["dojo/_base/kernel", "dojox", "dojo/_base/array"], function(dojo, dojox){ + +dojo.getObject("json.schema", true, dojox); + + +dojox.json.schema.validate = function(/*Any*/instance,/*Object*/schema){ + // summary: + // To use the validator call this with an instance object and an optional schema object. + // If a schema is provided, it will be used to validate. If the instance object refers to a schema (self-validating), + // that schema will be used to validate and the schema parameter is not necessary (if both exist, + // both validations will occur). + // instance: + // The instance value/object to validate + // schema: + // The schema to use to validate + // description: + // The validate method will return an object with two properties: + // valid: A boolean indicating if the instance is valid by the schema + // errors: An array of validation errors. If there are no errors, then an + // empty list will be returned. A validation error will have two properties: + // property: which indicates which property had the error + // message: which indicates what the error was + // + return this._validate(instance,schema,false); +}; +dojox.json.schema.checkPropertyChange = function(/*Any*/value,/*Object*/schema, /*String*/ property){ + // summary: + // The checkPropertyChange method will check to see if an value can legally be in property with the given schema + // This is slightly different than the validate method in that it will fail if the schema is readonly and it will + // not check for self-validation, it is assumed that the passed in value is already internally valid. + // The checkPropertyChange method will return the same object type as validate, see JSONSchema.validate for + // information. + // value: + // The new instance value/object to check + // schema: + // The schema to use to validate + // return: + // see dojox.validate.jsonSchema.validate + // + return this._validate(value,schema, property || "property"); +}; +dojox.json.schema.mustBeValid = function(result){ + // summary: + // This checks to ensure that the result is valid and will throw an appropriate error message if it is not + // result: the result returned from checkPropertyChange or validate + if(!result.valid){ + throw new TypeError(dojo.map(result.errors,function(error){return "for property " + error.property + ': ' + error.message;}).join(", ")); + } +} +dojox.json.schema._validate = function(/*Any*/instance,/*Object*/schema,/*Boolean*/ _changing){ + + var errors = []; + // validate a value against a property definition + function checkProp(value, schema, path,i){ + var l; + path += path ? typeof i == 'number' ? '[' + i + ']' : typeof i == 'undefined' ? '' : '.' + i : i; + function addError(message){ + errors.push({property:path,message:message}); + } + + if((typeof schema != 'object' || schema instanceof Array) && (path || typeof schema != 'function')){ + if(typeof schema == 'function'){ + if(!(Object(value) instanceof schema)){ + addError("is not an instance of the class/constructor " + schema.name); + } + }else if(schema){ + addError("Invalid schema/property definition " + schema); + } + return null; + } + if(_changing && schema.readonly){ + addError("is a readonly field, it can not be changed"); + } + if(schema['extends']){ // if it extends another schema, it must pass that schema as well + checkProp(value,schema['extends'],path,i); + } + // validate a value against a type definition + function checkType(type,value){ + if(type){ + if(typeof type == 'string' && type != 'any' && + (type == 'null' ? value !== null : typeof value != type) && + !(value instanceof Array && type == 'array') && + !(type == 'integer' && value%1===0)){ + return [{property:path,message:(typeof value) + " value found, but a " + type + " is required"}]; + } + if(type instanceof Array){ + var unionErrors=[]; + for(var j = 0; j < type.length; j++){ // a union type + if(!(unionErrors=checkType(type[j],value)).length){ + break; + } + } + if(unionErrors.length){ + return unionErrors; + } + }else if(typeof type == 'object'){ + var priorErrors = errors; + errors = []; + checkProp(value,type,path); + var theseErrors = errors; + errors = priorErrors; + return theseErrors; + } + } + return []; + } + if(value === undefined){ + if(!schema.optional){ + addError("is missing and it is not optional"); + } + }else{ + errors = errors.concat(checkType(schema.type,value)); + if(schema.disallow && !checkType(schema.disallow,value).length){ + addError(" disallowed value was matched"); + } + if(value !== null){ + if(value instanceof Array){ + if(schema.items){ + if(schema.items instanceof Array){ + for(i=0,l=value.length; i<l; i++){ + errors.concat(checkProp(value[i],schema.items[i],path,i)); + } + }else{ + for(i=0,l=value.length; i<l; i++){ + errors.concat(checkProp(value[i],schema.items,path,i)); + } + } + } + if(schema.minItems && value.length < schema.minItems){ + addError("There must be a minimum of " + schema.minItems + " in the array"); + } + if(schema.maxItems && value.length > schema.maxItems){ + addError("There must be a maximum of " + schema.maxItems + " in the array"); + } + }else if(schema.properties){ + errors.concat(checkObj(value,schema.properties,path,schema.additionalProperties)); + } + if(schema.pattern && typeof value == 'string' && !value.match(schema.pattern)){ + addError("does not match the regex pattern " + schema.pattern); + } + if(schema.maxLength && typeof value == 'string' && value.length > schema.maxLength){ + addError("may only be " + schema.maxLength + " characters long"); + } + if(schema.minLength && typeof value == 'string' && value.length < schema.minLength){ + addError("must be at least " + schema.minLength + " characters long"); + } + if(typeof schema.minimum !== undefined && typeof value == typeof schema.minimum && + schema.minimum > value){ + addError("must have a minimum value of " + schema.minimum); + } + if(typeof schema.maximum !== undefined && typeof value == typeof schema.maximum && + schema.maximum < value){ + addError("must have a maximum value of " + schema.maximum); + } + if(schema['enum']){ + var enumer = schema['enum']; + l = enumer.length; + var found; + for(var j = 0; j < l; j++){ + if(enumer[j]===value){ + found=1; + break; + } + } + if(!found){ + addError("does not have a value in the enumeration " + enumer.join(", ")); + } + } + if(typeof schema.maxDecimal == 'number' && + (value.toString().match(new RegExp("\\.[0-9]{" + (schema.maxDecimal + 1) + ",}")))){ + addError("may only have " + schema.maxDecimal + " digits of decimal places"); + } + } + } + return null; + } + // validate an object against a schema + function checkObj(instance,objTypeDef,path,additionalProp){ + + if(typeof objTypeDef =='object'){ + if(typeof instance != 'object' || instance instanceof Array){ + errors.push({property:path,message:"an object is required"}); + } + + for(var i in objTypeDef){ + if(objTypeDef.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_')){ + var value = instance[i]; + var propDef = objTypeDef[i]; + checkProp(value,propDef,path,i); + } + } + } + for(i in instance){ + if(instance.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_') && objTypeDef && !objTypeDef[i] && additionalProp===false){ + errors.push({property:path,message:(typeof value) + "The property " + i + + " is not defined in the schema and the schema does not allow additional properties"}); + } + var requires = objTypeDef && objTypeDef[i] && objTypeDef[i].requires; + if(requires && !(requires in instance)){ + errors.push({property:path,message:"the presence of the property " + i + " requires that " + requires + " also be present"}); + } + value = instance[i]; + if(objTypeDef && typeof objTypeDef == 'object' && !(i in objTypeDef)){ + checkProp(value,additionalProp,path,i); + } + if(!_changing && value && value.$schema){ + errors = errors.concat(checkProp(value,value.$schema,path,i)); + } + } + return errors; + } + if(schema){ + checkProp(instance,schema,'',_changing || ''); + } + if(!_changing && instance && instance.$schema){ + checkProp(instance,instance.$schema,'',''); + } + return {valid:!errors.length,errors:errors}; +}; + +return dojox.json.schema; +}); |
