Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge remote-tracking branch 'robertkrimen/master'

Conflicts:
	MANIFEST
	ToDo
  • Loading branch information...
commit 4484210468e7f85fe2571c2a03b02326c295945d 2 parents e9c6201 + 5390bec
@ingydotnet authored
Showing with 1,958 additions and 1,175 deletions.
  1. +8 −0 .gitignore
  2. +72 −0 Changes
  3. +147 −0 MANIFEST
  4. +5 −0 MANIFEST.SKIP
  5. +7 −0 Makefile.PL
  6. +13 −3 README
  7. +4 −0 ToDo
  8. +539 −452 bin/jemplate
  9. +1 −0  js
  10. +22 −7 lib/Jemplate.pm
  11. +35 −1 lib/Jemplate/Directive.pm
  12. +1 −1  lib/Jemplate/Grammar.pm
  13. +494 −443 lib/Jemplate/Runtime.pm
  14. +3 −3 lib/Jemplate/Runtime/Compact.pm
  15. +1 −1  src/js/json2.compact.js
  16. +239 −223 src/js/json2.js
  17. +1 −1  src/js/kernel.compact.js
  18. +22 −3 src/js/kernel.js
  19. +1 −1  src/parser/Parser.yp
  20. +34 −0 t/9bug/37539-intermediate-instantiation.t
  21. +35 −0 t/9bug/37540-iterate-over-empty-object.t
  22. +32 −0 t/9bug/37570-list-for-lists.t
  23. +12 −0 t/9bug/37895-inconsistent-jemplate-version.t
  24. +34 −0 t/9bug/43809-capture-implementation.t
  25. +51 −0 t/9bug/53453-make-Jemplate-slice-like-TT-slice.t
  26. +52 −0 t/9bug/53454-array-range-operator.t
  27. +12 −0 t/9bug/53967-compiler-double-dot-path-fail.t
  28. +36 −0 t/9bug/56965-DIV-operator-broken.t
  29. 0  t/assets/jt/a/.hidden/apple
  30. 0  t/assets/jt/a/b/c/.hidden
  31. +3 −0  t/assets/jt/a/b/cherry
  32. +38 −0 t/pairs.t
  33. +0 −32 tests/index.html
  34. +1 −1  tests/t/list.t.js
  35. +3 −3 tests/t/string.t.js
View
8 .gitignore
@@ -0,0 +1,8 @@
+tests/tjs/var
+Makefile
+Makefile.old
+Makefile.js
+t/a.js
+t/b.js
+t/check.js
+t?
View
72 Changes
@@ -1,4 +1,76 @@
---
+version: 0.261
+date: Tuesday April 27 09:35:06 PDT 2010
+changes:
+- Fixed rt56956 with test case - DIV operator broken (Agent Zhang)
+
+---
+version: 0.260
+date: Monday April 26 12:03:40 PDT 2010
+
+---
+version: 0.25_2
+date: Saturday April 24 18:48:53 PDT 2010
+changes:
+- Implemented rt4308 - Capture implementation (Tom Molesworth)
+- Added test for rt37570 - List method for lists (fixed in 5eaf340da...)
+
+---
+version: 0.25_1
+date: Thursday April 22 17:58:53 PDT 2010
+changes:
+- Fixed rt53454 with test case - Support rudimentary array range operator
+- Fixed rt53453 with test case - Make Jemplate slice like TT slice
+- Fixed rt53967 with test case - Compiler double-dot path fail
+- Added test case for rt37539 - Intermediate instantiation
+- Added test case for rt37540 - Iterate over empty object
+- Added test case for rt37895 - Inconsistent jemplate version
+
+---
+version: 0.25
+date: Wednesday April 21 13:44:19 PDT 2010
+changes:
+- release
+
+---
+version: 0.24_4
+date: Saturday January 09 17:06:40 PST 2010
+changes:
+- added .pairs (VMethod) functionality with tests
+- fixed quoted.t failing test
+
+---
+version: 0.24_3
+date: Mon Jun 8 2009
+changes:
+- fixed bug, related to empty template body (http://rt.cpan.org/Public/Bug/Display.html?id=37061)
+- fixed bug in Parser.yp, which produced compilation error for macroses
+- fixed "intermediate instantiation" issue (http://rt.cpan.org/Public/Bug/Display.html?id=37539)
+- fixed "iteration over empty object" issue (http://rt.cpan.org/Public/Bug/Display.html?id=37540)
+- added and tested MACRO directive
+- added PRE_PROCESS and POST_PROCESS configuration options
+- added and tested global scope access via GLOBAL modifier (GLOBAL.jQeuery etc)
+- added dummy LOCAL modifier, for symmetry
+- added "init" method for Jemplate singleton
+- added experimental RAW directive (RAW jQuery, equivalent of jQuery = GLOBAL.jQuery)
+
+VMethods:
+- added "list" for lists (http://rt.cpan.org/Public/Bug/Display.html?id=37570)
+- added "item" for hashes
+- fixed "import" for hashes
+
+Test suite:
+- combined back to a single copy
+
+Patches:
+- Integrated patch from RT#37895
+
+version: 0.24_2
+date: Monday June 08 10:37:54 PDT 2009
+changes:
+- Fix to get tests working on MSWin32 (rt23883)
+
+---
version: 0.24
date: Fri Sep 19 15:09:35 PDT 2008
changes:
View
147 MANIFEST
@@ -0,0 +1,147 @@
+bin/jemplate
+bin/README
+Changes
+ToDo
+DESIGN
+doc/html/Jemplate.html
+doc/Makefile
+doc/text/Jemplate.text
+examples/ajax/data.json
+examples/ajax/index.html
+examples/ajax/template/body.html
+examples/features/index.html
+examples/features/templates/body.html
+examples/features/templates/footer.html
+examples/features/templates/hacker.html
+examples/features/templates/header.html
+examples/features/templates/wrapper.html
+examples/features/templates/wrapper2.html
+examples/hello/index.html
+examples/hello/templates/hello.html
+examples/index.html
+examples/js/ajax.js
+examples/js/features.js
+examples/js/hello.js
+examples/Makefile
+inc/Module/Install.pm
+inc/Module/Install/Base.pm
+inc/Module/Install/Can.pm
+inc/Module/Install/Fetch.pm
+inc/Module/Install/Include.pm
+inc/Module/Install/Makefile.pm
+inc/Module/Install/Metadata.pm
+inc/Module/Install/TestBase.pm
+inc/Module/Install/Win32.pm
+inc/Module/Install/WriteAll.pm
+inc/Module/Install/Scripts.pm
+inc/Spiffy.pm
+inc/Test/Base.pm
+inc/Test/Base/Filter.pm
+inc/Test/Builder.pm
+inc/Test/Builder/Module.pm
+inc/Test/More.pm
+jemplate
+lib/Jemplate.pm
+lib/Jemplate/Directive.pm
+lib/Jemplate/Grammar.pm
+lib/Jemplate/Parser.pm
+lib/Jemplate/Runtime.pm
+lib/Jemplate/Runtime/Compact.pm
+LICENSE
+Makefile.PL
+MANIFEST This list of files
+META.yml
+README
+t/a.js
+t/assets/jt/hello
+t/assets/jt/a/.hidden/apple
+t/assets/jt/a/b/c/.hidden
+t/assets/jt/a/b/cherry
+t/b.js
+t/block.t
+t/call.t
+t/check.js
+t/clear.t
+t/for.t
+t/get-set.t
+t/hello.t
+t/if-else.t
+t/if-variations.t
+t/javascript.t
+t/list.t
+t/list/bar/one
+t/list/bar/two
+t/list/foo/one
+t/list/foo/two
+t/list/one
+t/list/three
+t/list/two
+t/macro.t
+t/process.t
+t/quoted.t
+t/runtime.t
+t/stash.t
+t/switch.t
+t/tags.t
+t/test.t
+t/TestJemplate.pm
+t/throw.t
+t/while.t
+t/wrapper.t
+t/pairs.t
+t/9bug/37539-intermediate-instantiation.t
+t/9bug/37540-iterate-over-empty-object.t
+t/9bug/37895-inconsistent-jemplate-version.t
+t/9bug/53967-compiler-double-dot-path-fail.t
+t/9bug/53453-make-Jemplate-slice-like-TT-slice.t
+t/9bug/53454-array-range-operator.t
+t/9bug/37570-list-for-lists.t
+t/9bug/43809-capture-implementation.t
+t/9bug/56965-DIV-operator-broken.t
+tests/Makefile
+tests/README
+tests/bin/daemon
+tests/bin/prepare-var-jt
+tests/bin/pull-jemplates
+tests/bin/render-template
+tests/bin/test-run
+tests/config.yaml
+tests/jemplate2/greeting/english
+tests/jemplate2/greeting/spanish
+tests/jemplate2/greetings
+tests/jemplate2/hello
+tests/js/Subclass.js
+tests/js/Test/Base.js
+tests/js/Test/Builder.js
+tests/js/Test/Harness/Browser.js
+tests/js/Test/Harness.js
+tests/js/Test/Jemplate.js
+tests/js/jemplate_dummy_plugin.js
+tests/js/jquery-1.2.3.js
+tests/old/Makefile
+tests/old/mangler/README
+tests/old/mangler/ctx.tst
+tests/old/mangler/mangle.pl
+tests/old/mangler/test-data.tmpl.tt
+tests/t/basics.t.js
+tests/t/bugs.t.js
+tests/t/default.t.js
+tests/t/directives.t.js
+tests/t/filters.t.js
+tests/t/greetings.t.js
+tests/t/hash.t.js
+tests/t/hello.t.js
+tests/t/join.t.js
+tests/t/list.t.js
+tests/t/localise.t.js
+tests/t/loop.t.js
+tests/t/objects.t.js
+tests/t/plugins.t.js
+tests/t/set.t.js
+tests/t/stash.t.js
+tests/t/string.t.js
+tests/t/test.html
+tests/template/index.html
+tests/template/test.html
+tests/tjs/Makefile
+tests/tjs/config.yaml
View
5 MANIFEST.SKIP
@@ -7,3 +7,8 @@
^t/Jemplate.js$
^src/
^tests/tjs/var/
+^tmp.*
+^tests/
+Makefile.old
+t[0-9]
+Template-TT3
View
7 Makefile.PL
@@ -18,11 +18,18 @@ all_from 'lib/Jemplate.pm';
#build_requires 'Directory::Scratch';
+if (-e 'inc/.author') {
+ my $all_from = join '/', 'lib', split m/-/, name . '.pm';
+ `perldoc -tF $all_from > README` if ! -e 'README' || (stat $all_from)[9] > (stat 'README')[9];
+}
+
requires 'Template' => '2.19';
requires 'File::Find::Rule' => '0.30';
use_test_base;
+tests_recursive;
+
no_index directory => 'examples';
clean_files 't/Jemplate.js t/a.js t/b.js t/check.js';
View
16 README
@@ -1,3 +1,6 @@
+VERSION
+ Version 0.261
+
NAME
Jemplate - JavaScript Templating with Template Toolkit
@@ -22,6 +25,10 @@ SYNOPSIS
Jemplate.process('my-template.html', data, '#some-div');
});
+ From the commandline:
+
+ jemplate --runtime --compile path/to/jemplate/directory/ > jemplate.js
+
DESCRIPTION
Jemplate is a templating framework for JavaScript that is built over
Perl's Template Toolkit (TT2).
@@ -161,12 +168,13 @@ CURRENT SUPPORT
* [% LAST %]
* [% CLEAR %]
* [%# this is a comment %]
+ * [% MACRO name(param1, param2) BLOCK %] ... [% END %]
ALL of the string virtual functions are supported.
ALL of the array virtual functions are supported:
- ALL of the hash virtual functions are supported (except for import):
+ ALL of the hash virtual functions are supported:
MANY of the standard filters are implemented.
@@ -185,8 +193,8 @@ BROWSER SUPPORT
All tests run 100% successful in the above browsers.
DEVELOPMENT
- The bleeding edge code is available via Subversion at
- http://svn.jemplate.net/repo/trunk/
+ The bleeding edge code is available via Git at
+ git://github.com/ingydotnet/jemplate.git
You can run the runtime tests directly from
http://svn.jemplate.net/repo/trunk/tests/run/index.html or from the
@@ -229,6 +237,8 @@ AUTHORS
Robert Krimen <robertkrimen@gmail.com>
+ Nickolay Platonov <nickolay8@gmail.com>
+
COPYRIGHT
Copyright (c) 2006-2008. Ingy döt Net.
View
4 ToDo
@@ -9,6 +9,10 @@
=== 0.23
+Add note about commit 3c4d9 referring to wrong rt, should refer to 23883
+
+TODO: Does use_test_base not work? make test compains that Test::Base is not installed -rokr
+
FUTURE:
09:55 < nkuttler_> apparently firefox sets the accept header to request xml rather than json, which obviously is incompatible with later JSON.parse calls. I have added a
View
991 bin/jemplate
539 additions, 452 deletions not shown
View
1  js
View
29 lib/Jemplate.pm
@@ -5,7 +5,13 @@ use warnings;
use Template 2.14;
use Getopt::Long;
-our $VERSION = '0.23_1';
+=head1 VERSION
+
+Version 0.261
+
+=cut
+
+our $VERSION = '0.261';
use Jemplate::Parser;
@@ -219,8 +225,10 @@ sub recurse_dir {
my $dir = shift;
my @files;
foreach ( File::Find::Rule->file->in( $dir ) ) {
- # don't include .hidden files
- unless ($_ =~ '\/\.') { push(@files, $_); }
+ if ( m{/\.[^\.]+} ) {} # Skip ".hidden" files or directories
+ else {
+ push @files, $_;
+ }
}
return @files;
}
@@ -232,7 +240,7 @@ sub make_file_list {
foreach my $arg (@args) {
unless (-e $arg) { next; } # file exists
- unless (-s $arg) { next; } # file size > 0
+ unless (-s $arg or -d $arg) { next; } # file size > 0 or directory (for Win platform)
if (-d $arg) {
foreach my $full ( recurse_dir($arg) ) {
@@ -422,6 +430,10 @@ or, with jQuery.js:
Jemplate.process('my-template.html', data, '#some-div');
});
+From the commandline:
+
+ jemplate --runtime --compile path/to/jemplate/directory/ > jemplate.js
+
=head1 DESCRIPTION
Jemplate is a templating framework for JavaScript that is built over
@@ -587,12 +599,13 @@ Jemplate now supports almost all the TT directives, including:
* [% LAST %]
* [% CLEAR %]
* [%# this is a comment %]
+ * [% MACRO name(param1, param2) BLOCK %] ... [% END %]
ALL of the string virtual functions are supported.
ALL of the array virtual functions are supported:
-ALL of the hash virtual functions are supported (except for import):
+ALL of the hash virtual functions are supported:
MANY of the standard filters are implemented.
@@ -613,8 +626,8 @@ All tests run 100% successful in the above browsers.
=head1 DEVELOPMENT
-The bleeding edge code is available via Subversion at
-http://svn.jemplate.net/repo/trunk/
+The bleeding edge code is available via Git at
+git://github.com/ingydotnet/jemplate.git
You can run the runtime tests directly from
http://svn.jemplate.net/repo/trunk/tests/run/index.html or from the
@@ -657,6 +670,8 @@ David A. Coffey <dacoffey@cogsmith.com>
Robert Krimen <robertkrimen@gmail.com>
+Nickolay Platonov <nickolay8@gmail.com>
+
=head1 COPYRIGHT
Copyright (c) 2006-2008. Ingy döt Net.
View
36 lib/Jemplate/Directive.pm
@@ -33,6 +33,17 @@ $block
...
}
+# Try to do 1 .. 10 expansions
+sub _attempt_range_expand_val ($) {
+ my $val = shift;
+ return $val unless
+ my ( $from, $to ) = $val =~ m/\s*\[\s*(\S+)\s*\.\.\s*(\S+)\s*\]/;
+
+ die "Range expansion is current supported for positive/negative integer values only (e.g. [ 1 .. 10 ])\nCannot expand: $val" unless $from =~ m/^-?\d+$/ && $to =~ m/^-?\d+$/;
+
+ return join '', '[', join( ',', $from .. $to ), ']';
+}
+
#------------------------------------------------------------------------
# textblock($text)
#------------------------------------------------------------------------
@@ -101,6 +112,7 @@ sub assign {
$var = '[' . join(', ', @$var) . ']';
}
}
+ $val = _attempt_range_expand_val $val;
$val .= ', 1' if $default;
return "stash.set($var, $val)";
}
@@ -277,6 +289,8 @@ sub foreach {
$loop_restore = 'stash = context.delocalise()';
}
+ $list = _attempt_range_expand_val $list;
+
return <<EOF;
// FOREACH
@@ -652,7 +666,27 @@ EOF
}
sub capture {
- return "throw('CAPTURE not yet supported in Jemplate');";
+ my ($class, $name, $block) = @_;
+
+ if (ref $name) {
+ if (scalar @$name == 2 && ! $name->[1]) {
+ $name = $name->[0];
+ }
+ else {
+ $name = '[' . join(', ', @$name) . ']';
+ }
+ }
+
+ return <<EOF;
+
+// CAPTURE
+(function() {
+ var output = '';
+ $block
+ stash.set($name, output);
+})();
+EOF
+
}
BEGIN {
View
2  lib/Jemplate/Grammar.pm
@@ -6010,7 +6010,7 @@ sub
'expr', 3,
sub
#line 358 "Parser.yp"
-{ "int($_[1] / $_[3])" }
+{ "Math.floor($_[1] / $_[3])" }
],
[#Rule 138
'expr', 3,
View
937 lib/Jemplate/Runtime.pm
@@ -658,7 +658,7 @@ proto.string_functions.list = function(string) {
// match(re) get list of matches
proto.string_functions.match = function(string, re, modifiers) {
- var regexp = new RegExp(re, modifiers);
+ var regexp = new RegExp(re, modifiers == undefined ? 'g' : modifiers);
var list = string.match(regexp);
return list;
}
@@ -675,7 +675,7 @@ proto.string_functions.repeat = function(string, args) {
// replace(re, sub, global) replace instances of re with sub
proto.string_functions.replace = function(string, re, sub, modifiers) {
- var regexp = new RegExp(re,modifiers);
+ var regexp = new RegExp(re, modifiers == undefined ? 'g' : modifiers);
if (! sub) sub = '';
return string.replace(regexp, sub);
@@ -792,7 +792,12 @@ proto.list_functions.merge = function(list /*, ... args */) {
}
proto.list_functions.slice = function(list, start, end) {
- return list.slice(start, end);
+ // To make it like slice in TT
+ // See rt53453
+ if ( end == -1 ) {
+ return list.slice( start );
+ }
+ return list.slice( start, end + 1 );
}
proto.list_functions.splice = function(list /*, ... args */ ) {
@@ -935,6 +940,20 @@ proto.hash_functions.values = function(hash) {
return list;
}
+proto.hash_functions.pairs = function(hash) {
+ var list = new Array();
+ var keys = new Array();
+ for ( var key in hash ) {
+ keys.push( key );
+ }
+ keys.sort();
+ for ( var key in keys ) {
+ key = keys[key]
+ list.push( { 'key': key, 'value': hash[key] } );
+ }
+ return list;
+}
+
// delete
proto.hash_functions.remove = function(hash, key) {
return delete hash[key];
@@ -1184,8 +1203,8 @@ sub json_json2_internal {
var JSON;
/*
- json2.js
- 2008-03-24
+ http://www.JSON.org/json2.js
+ 2009-04-16
Public Domain.
@@ -1193,44 +1212,48 @@ var JSON;
See http://www.JSON.org/js.html
- This file creates a global JSON object containing three methods: stringify,
- parse, and quote.
-
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
- values are stringified for objects without a toJSON
- method. It can be a function or an array.
+ values are stringified for objects. It can be a
+ function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
- level. If it is a string (such as '\t'), it contains the
- characters used to indent at each level.
+ level. If it is a string (such as '\t' or '&nbsp;'),
+ it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
- method, its toJSON method with be called and the result will be
+ method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
- or undefined if nothing should be serialized. The toJSON method will
- be passed the key associated with the value, and this will be bound
- to the object holding the key.
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the object holding the key.
- This is the toJSON method added to Dates:
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
- function toJSON(key) {
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
- }
+ };
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
@@ -1238,35 +1261,24 @@ var JSON;
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
- If no replacer parameter is provided, then a default replacer
- will be used:
-
- function replacer(key, value) {
- return Object.hasOwnProperty.call(this, key) ?
- value : undefined;
- }
-
- The default replacer is passed the key and value for each item in
- the structure. It excludes inherited members.
-
- If the replacer parameter is an array, then it will be used to
- select the members to be serialized. It filters the results such
- that only members with keys listed in the replacer array are
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
stringified.
- Values that do not have JSON representaions, such as undefined or
+ Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
- The optional space parameter produces a stringification of the value
- that is filled with line breaks and indentation to make it easier to
- read.
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
- then indentation will be that many spaces.
+ the indentation will be that many spaces.
Example:
@@ -1277,16 +1289,22 @@ var JSON;
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
- transform the results. It receives each of the keys and values, and
- its return value is used instead of the original value. If it
- returns what it received, then structure is not modified. If it
- returns undefined then the member is deleted.
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
Example:
@@ -1306,45 +1324,57 @@ var JSON;
return value;
});
-
- JSON.quote(text)
- This method wraps a string in quotes, escaping some characters
- as needed.
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
This is a reference implementation. You are free to copy, modify, or
redistribute.
- USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD THIRD PARTY
- CODE INTO YOUR PAGES.
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
*/
-/*jslint regexp: true, forin: true, evil: true */
+/*jslint evil: true */
/*global JSON */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
- call, charCodeAt, floor, getUTCDate, getUTCFullYear, getUTCHours,
- getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, length,
- parse, propertyIsEnumerable, prototype, push, quote, replace, stringify,
- test, toJSON, toString
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
*/
-if (!JSON) var JSON;
-if (!JSON) {
-
// Create a JSON object only if one does not already exist. We create the
-// object in a closure to avoid global variables.
+// methods in a closure to avoid creating global variables.
- JSON = function () {
+if (!this.JSON) {
+ this.JSON = {};
+}
+(function () {
- function f(n) { // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
- Date.prototype.toJSON = function () {
+ if (typeof Date.prototype.toJSON !== 'function') {
-// Eventually, this method will be based on the date.toISOString method.
+ Date.prototype.toJSON = function (key) {
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
@@ -1354,175 +1384,179 @@ if (!JSON) {
f(this.getUTCSeconds()) + 'Z';
};
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
- var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g,
- gap,
- indent,
- meta = { // table of character substitutions
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- },
- rep;
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
- function quote(string) {
+ function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
- return escapeable.test(string) ?
- '"' + string.replace(escapeable, function (a) {
- var c = meta[a];
- if (typeof c === 'string') {
- return c;
- }
- c = a.charCodeAt();
- return '\\u00' + Math.floor(c / 16).toString(16) +
- (c % 16).toString(16);
- }) + '"' :
- '"' + string + '"';
- }
+ escapable.lastIndex = 0;
+ return escapable.test(string) ?
+ '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' :
+ '"' + string + '"';
+ }
- function str(key, holder) {
+ function str(key, holder) {
// Produce a string from holder[key].
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length,
- mind = gap,
- partial,
- value = holder[key];
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
- if (value && typeof value === 'object' &&
- typeof value.toJSON === 'function') {
- value = value.toJSON(key);
- }
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
- }
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
// What happens next depends on the value's type.
- switch (typeof value) {
- case 'string':
- return quote(value);
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
- case 'number':
+ case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
- return isFinite(value) ? String(value) : 'null';
+ return isFinite(value) ? String(value) : 'null';
- case 'boolean':
- case 'null':
+ case 'boolean':
+ case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
- return String(value);
+ return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
- case 'object':
+ case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
- if (!value) {
- return 'null';
- }
+ if (!value) {
+ return 'null';
+ }
// Make an array to hold the partial results of stringifying this object value.
- gap += indent;
- partial = [];
+ gap += indent;
+ partial = [];
-// If the object has a dontEnum length property, we'll treat it as an array.
+// Is the value an array?
- if (typeof value.length === 'number' &&
- !(value.propertyIsEnumerable('length'))) {
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
-// The object is an array. Stringify every element. Use null as a placeholder
+// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = str(i, value) || 'null';
- }
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
- v = partial.length === 0 ? '[]' :
- gap ? '[\n' + gap + partial.join(',\n' + gap) +
- '\n' + mind + ']' :
- '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
+ v = partial.length === 0 ? '[]' :
+ gap ? '[\n' + gap +
+ partial.join(',\n' + gap) + '\n' +
+ mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
// If the replacer is an array, use it to select the members to be stringified.
- if (typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- k = rep[i];
- if (typeof k === 'string') {
- v = str(k, value, rep);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ k = rep[i];
+ if (typeof k === 'string') {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
- } else {
+ }
+ } else {
// Otherwise, iterate through all of the keys in the object.
- for (k in value) {
- v = str(k, value, rep);
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
+ }
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
- v = partial.length === 0 ? '{}' :
- gap ? '{\n' + gap + partial.join(',\n' + gap) +
- '\n' + mind + '}' :
- '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
-
- return null;
+ v = partial.length === 0 ? '{}' :
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+ mind + '}' : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
}
+ return '';
+ }
-// Return the JSON object containing the stringify, parse, and quote methods.
+// If the JSON object does not yet have a stringify method, give it one.
- return {
- stringify: function (value, replacer, space) {
+ if (typeof JSON.stringify !== 'function') {
+ JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
@@ -1530,123 +1564,124 @@ if (!JSON) {
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
- var i;
- gap = '';
- indent = '';
- if (space) {
+ var i;
+ gap = '';
+ indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
-
-// If the space parameter is a string, it will be used as the indent string.
-
- } else if (typeof space === 'string') {
- indent = space;
- }
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
}
-// If there is no replacer parameter, use the default replacer.
+// If the space parameter is a string, it will be used as the indent string.
- if (!replacer) {
- rep = function (key, value) {
- if (!Object.hasOwnProperty.call(this, key)) {
- return undefined;
- }
- return value;
- };
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
-// The replacer can be a function or an array. Otherwise, throw an error.
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
- } else if (typeof replacer === 'function' ||
- (typeof replacer === 'object' &&
- typeof replacer.length === 'number')) {
- rep = replacer;
- } else {
- throw new Error('JSON.stringify');
- }
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
- return str('', {'': value});
- },
+ return str('', {'': value});
+ };
+ }
- parse: function (text, reviver) {
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
- var j;
+ var j;
- function walk(holder, key) {
+ function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
- var k, v, value = holder[key];
- if (value && typeof value === 'object') {
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = walk(value, k);
- if (v !== undefined) {
- value[k] = v;
- } else {
- delete value[k];
- }
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
}
}
}
- return reviver.call(holder, key, value);
}
+ return reviver.call(holder, key, value);
+ }
-// Parsing happens in three stages. In the first stage, we run the text against
-// regular expressions that look for non-JSON patterns. We are especially
-// concerned with '()' and 'new' because they can cause invocation, and '='
-// because it can cause mutation. But just to be safe, we want to reject all
-// unexpected forms.
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
-// We split the first stage into 4 regexp operations in order to work around
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
-// replace all backslash pairs with '@' (a non-JSON character). Second, we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
- if (/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g, '@').
+ if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
-// In the second stage we use the eval function to compile the text into a
+// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
- j = eval('(' + text + ')');
+ j = eval('(' + text + ')');
-// In the optional third stage, we recursively walk the new structure, passing
+// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
- return typeof reviver === 'function' ?
- walk({'': j}, '') : j;
- }
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
// If the text is not JSON parseable, then a SyntaxError is thrown.
- throw new SyntaxError('JSON.parse');
- },
-
- quote: quote
+ throw new SyntaxError('JSON.parse');
};
- }();
-}
+ }
+}());
Jemplate.JSON = {
@@ -1690,8 +1725,8 @@ Jemplate.JSON = {
sub json2 {
<<'...';
/*
- json2.js
- 2008-03-24
+ http://www.JSON.org/json2.js
+ 2009-04-16
Public Domain.
@@ -1699,44 +1734,48 @@ sub json2 {
See http://www.JSON.org/js.html
- This file creates a global JSON object containing three methods: stringify,
- parse, and quote.
-
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
- values are stringified for objects without a toJSON
- method. It can be a function or an array.
+ values are stringified for objects. It can be a
+ function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
- level. If it is a string (such as '\t'), it contains the
- characters used to indent at each level.
+ level. If it is a string (such as '\t' or '&nbsp;'),
+ it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
- method, its toJSON method with be called and the result will be
+ method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
- or undefined if nothing should be serialized. The toJSON method will
- be passed the key associated with the value, and this will be bound
- to the object holding the key.
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the object holding the key.
+
+ For example, this would serialize Dates as ISO strings.
- This is the toJSON method added to Dates:
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
- function toJSON(key) {
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
- }
+ };
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
@@ -1744,35 +1783,24 @@ sub json2 {
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
- If no replacer parameter is provided, then a default replacer
- will be used:
-
- function replacer(key, value) {
- return Object.hasOwnProperty.call(this, key) ?
- value : undefined;
- }
-
- The default replacer is passed the key and value for each item in
- the structure. It excludes inherited members.
-
- If the replacer parameter is an array, then it will be used to
- select the members to be serialized. It filters the results such
- that only members with keys listed in the replacer array are
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
stringified.
- Values that do not have JSON representaions, such as undefined or
+ Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
- The optional space parameter produces a stringification of the value
- that is filled with line breaks and indentation to make it easier to
- read.
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
- then indentation will be that many spaces.
+ the indentation will be that many spaces.
Example:
@@ -1783,16 +1811,22 @@ sub json2 {
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
- transform the results. It receives each of the keys and values, and
- its return value is used instead of the original value. If it
- returns what it received, then structure is not modified. If it
- returns undefined then the member is deleted.
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
Example:
@@ -1812,45 +1846,57 @@ sub json2 {
return value;
});
-
- JSON.quote(text)
- This method wraps a string in quotes, escaping some characters
- as needed.
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
This is a reference implementation. You are free to copy, modify, or
redistribute.
- USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD THIRD PARTY
- CODE INTO YOUR PAGES.
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
*/
-/*jslint regexp: true, forin: true, evil: true */
+/*jslint evil: true */
/*global JSON */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
- call, charCodeAt, floor, getUTCDate, getUTCFullYear, getUTCHours,
- getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, length,
- parse, propertyIsEnumerable, prototype, push, quote, replace, stringify,
- test, toJSON, toString
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
*/
-if (!JSON) var JSON;
-if (!JSON) {
-
// Create a JSON object only if one does not already exist. We create the
-// object in a closure to avoid global variables.
+// methods in a closure to avoid creating global variables.
- JSON = function () {
+if (!this.JSON) {
+ this.JSON = {};
+}
+(function () {
- function f(n) { // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
- Date.prototype.toJSON = function () {
+ if (typeof Date.prototype.toJSON !== 'function') {
-// Eventually, this method will be based on the date.toISOString method.
+ Date.prototype.toJSON = function (key) {
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
@@ -1860,175 +1906,179 @@ if (!JSON) {
f(this.getUTCSeconds()) + 'Z';
};
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
- var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g,
- gap,
- indent,
- meta = { // table of character substitutions
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- },
- rep;
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
- function quote(string) {
+ function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
- return escapeable.test(string) ?
- '"' + string.replace(escapeable, function (a) {
- var c = meta[a];
- if (typeof c === 'string') {
- return c;
- }
- c = a.charCodeAt();
- return '\\u00' + Math.floor(c / 16).toString(16) +
- (c % 16).toString(16);
- }) + '"' :
- '"' + string + '"';
- }
+ escapable.lastIndex = 0;
+ return escapable.test(string) ?
+ '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' :
+ '"' + string + '"';
+ }
- function str(key, holder) {
+ function str(key, holder) {
// Produce a string from holder[key].
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length,
- mind = gap,
- partial,
- value = holder[key];
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
- if (value && typeof value === 'object' &&
- typeof value.toJSON === 'function') {
- value = value.toJSON(key);
- }
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
- }
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
// What happens next depends on the value's type.
- switch (typeof value) {
- case 'string':
- return quote(value);
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
- case 'number':
+ case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
- return isFinite(value) ? String(value) : 'null';
+ return isFinite(value) ? String(value) : 'null';
- case 'boolean':
- case 'null':
+ case 'boolean':
+ case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
- return String(value);
+ return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
- case 'object':
+ case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
- if (!value) {
- return 'null';
- }
+ if (!value) {
+ return 'null';
+ }
// Make an array to hold the partial results of stringifying this object value.
- gap += indent;
- partial = [];
+ gap += indent;
+ partial = [];
-// If the object has a dontEnum length property, we'll treat it as an array.
+// Is the value an array?
- if (typeof value.length === 'number' &&
- !(value.propertyIsEnumerable('length'))) {
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
-// The object is an array. Stringify every element. Use null as a placeholder
+// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = str(i, value) || 'null';
- }
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
- v = partial.length === 0 ? '[]' :
- gap ? '[\n' + gap + partial.join(',\n' + gap) +
- '\n' + mind + ']' :
- '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
+ v = partial.length === 0 ? '[]' :
+ gap ? '[\n' + gap +
+ partial.join(',\n' + gap) + '\n' +
+ mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
// If the replacer is an array, use it to select the members to be stringified.
- if (typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- k = rep[i];
- if (typeof k === 'string') {
- v = str(k, value, rep);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ k = rep[i];
+ if (typeof k === 'string') {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
- } else {
+ }
+ } else {
// Otherwise, iterate through all of the keys in the object.
- for (k in value) {
- v = str(k, value, rep);
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
+ }
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
- v = partial.length === 0 ? '{}' :
- gap ? '{\n' + gap + partial.join(',\n' + gap) +
- '\n' + mind + '}' :
- '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
-
- return null;
+ v = partial.length === 0 ? '{}' :
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+ mind + '}' : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
}
+ return '';
+ }
-// Return the JSON object containing the stringify, parse, and quote methods.
+// If the JSON object does not yet have a stringify method, give it one.
- return {
- stringify: function (value, replacer, space) {
+ if (typeof JSON.stringify !== 'function') {
+ JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
@@ -2036,123 +2086,124 @@ if (!JSON) {
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
- var i;
- gap = '';
- indent = '';
- if (space) {
+ var i;
+ gap = '';
+ indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
-
-// If the space parameter is a string, it will be used as the indent string.
-
- } else if (typeof space === 'string') {
- indent = space;
- }
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
}
-// If there is no replacer parameter, use the default replacer.
+// If the space parameter is a string, it will be used as the indent string.
- if (!replacer) {
- rep = function (key, value) {
- if (!Object.hasOwnProperty.call(this, key)) {
- return undefined;
- }
- return value;
- };
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
-// The replacer can be a function or an array. Otherwise, throw an error.
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
- } else if (typeof replacer === 'function' ||
- (typeof replacer === 'object' &&
- typeof replacer.length === 'number')) {
- rep = replacer;
- } else {
- throw new Error('JSON.stringify');
- }
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
- return str('', {'': value});
- },
+ return str('', {'': value});
+ };
+ }
+
+// If the JSON object does not yet have a parse method, give it one.
- parse: function (text, reviver) {
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
- var j;
+ var j;
- function walk(holder, key) {
+ function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
- var k, v, value = holder[key];
- if (value && typeof value === 'object') {
- for (k in value) {
- if (Object.hasOwnProperty.call(value, k)) {
- v = walk(value, k);
- if (v !== undefined) {
- value[k] = v;
- } else {
- delete value[k];
- }
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
}
}
}
- return reviver.call(holder, key, value);
}
+ return reviver.call(holder, key, value);
+ }
-// Parsing happens in three stages. In the first stage, we run the text against
-// regular expressions that look for non-JSON patterns. We are especially
-// concerned with '()' and 'new' because they can cause invocation, and '='
-// because it can cause mutation. But just to be safe, we want to reject all
-// unexpected forms.
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
-// We split the first stage into 4 regexp operations in order to work around
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
-// replace all backslash pairs with '@' (a non-JSON character). Second, we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
- if (/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g, '@').
+ if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
-// In the second stage we use the eval function to compile the text into a
+// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
- j = eval('(' + text + ')');
+ j = eval('(' + text + ')');
-// In the optional third stage, we recursively walk the new structure, passing
+// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
- return typeof reviver === 'function' ?
- walk({'': j}, '') : j;
- }
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
// If the text is not JSON parseable, then a SyntaxError is thrown.
- throw new SyntaxError('JSON.parse');
- },
-
- quote: quote
+ throw new SyntaxError('JSON.parse');
};
- }();
-}
+ }
+}());
...
}
View
6 lib/Jemplate/Runtime/Compact.pm
@@ -5,7 +5,7 @@ use warnings;
sub main { return &kernel }
sub kernel {
<<'...';
-if(typeof Jemplate=="undefined"){var Jemplate=function(){this.init.apply(this,arguments)}}Jemplate.VERSION="0.22";Jemplate.process=function(){var A=new Jemplate(Jemplate.prototype.config);return A.process.apply(A,arguments)};(function(){if(!Jemplate.templateMap){Jemplate.templateMap={}}var proto=Jemplate.prototype={};proto.config={AUTO_RESET:true,BLOCKS:{},CONTEXT:null,DEBUG_UNDEF:false,DEFAULT:null,ERROR:null,EVAL_JAVASCRIPT:false,GLOBAL:true,SCOPE:this,FILTERS:{},INCLUDE_PATH:[""],INTERPOLATE:false,OUTPUT:null,PLUGINS:{},POST_PROCESS:[],PRE_PROCESS:[],PROCESS:null,RECURSION:false,STASH:null,TOLERANT:null,VARIABLES:{},WRAPPER:[]};proto.defaults={AUTO_RESET:true,BLOCKS:{},CONTEXT:null,DEBUG_UNDEF:false,DEFAULT:null,ERROR:null,EVAL_JAVASCRIPT:false,GLOBAL:true,SCOPE:this,INCLUDE_PATH:[""],INTERPOLATE:false,OUTPUT:null,PLUGINS:{},POST_PROCESS:[],PRE_PROCESS:[],PROCESS:null,RECURSION:false,STASH:null,TOLERANT:null,VARIABLES:{},WRAPPER:[]};Jemplate.init=function(config){Jemplate.prototype.config=config||{};for(var i in Jemplate.prototype.defaults){if(typeof Jemplate.prototype.config[i]=="undefined"){Jemplate.prototype.config[i]=Jemplate.prototype.defaults[i]}}};proto.init=function(config){this.config=config||{};for(var i in Jemplate.prototype.defaults){if(typeof this.config[i]=="undefined"){this.config[i]=Jemplate.prototype.defaults[i]}}};proto.process=function(template,data,output){var context=this.config.CONTEXT||new Jemplate.Context();context.config=this.config;context.stash=new Jemplate.Stash(this.config.STASH,this.config);context.__filter__=new Jemplate.Filter();context.__filter__.config=this.config;context.__plugin__=new Jemplate.Plugin();context.__plugin__.config=this.config;var result;var proc=function(input){try{if(typeof context.config.PRE_PROCESS=="string"){context.config.PRE_PROCESS=[context.config.PRE_PROCESS]}for(var i=0;i<context.config.PRE_PROCESS.length;i++){context.process(context.config.PRE_PROCESS[i])}result=context.process(template,input);if(typeof context.config.POST_PROCESS=="string"){context.config.PRE_PROCESS=[context.config.POST_PROCESS]}for(i=0;i<context.config.POST_PROCESS.length;i++){context.process(context.config.POST_PROCESS[i])}}catch(e){if(!String(e).match(/Jemplate\.STOP\n/)){throw (e)}result=e.toString().replace(/Jemplate\.STOP\n/,"")}if(typeof output=="undefined"){return result}if(typeof output=="function"){output(result);return null}if(typeof (output)=="string"||output instanceof String){if(output.match(/^#[\w\-]+$/)){var id=output.replace(/^#/,"");var element=document.getElementById(id);if(typeof element=="undefined"){throw ('No element found with id="'+id+'"')}element.innerHTML=result;return null}}else{output.innerHTML=result;return null}throw ("Invalid arguments in call to Jemplate.process");return 1};if(typeof data=="function"){data=data()}else{if(typeof data=="string"){var url=data;Jemplate.Ajax.processGet(url,function(data){proc(data)});return null}}return proc(data)};if(typeof Jemplate.Context=="undefined"){Jemplate.Context=function(){}}proto=Jemplate.Context.prototype;proto.include=function(template,args){return this.process(template,args,true)};proto.process=function(template,args,localise){if(localise){this.stash.clone(args)}else{this.stash.update(args)}var func=Jemplate.templateMap[template];if(typeof func=="undefined"){throw ('No Jemplate template named "'+template+'" available')}var output=func(this);if(localise){this.stash.declone()}return output};proto.set_error=function(error,output){this._error=[error,output];return error};proto.plugin=function(name,args){if(typeof name=="undefined"){throw"Unknown plugin name ':"+name+"'"}var func=eval(name);return new func(this,args)};proto.filter=function(text,name,args){if(name=="null"){name="null_filter"}if(typeof this.__filter__.filters[name]=="function"){return this.__filter__.filters[name](text,args,this)}else{throw"Unknown filter name ':"+name+"'"}};if(typeof Jemplate.Plugin=="undefined"){Jemplate.Plugin=function(){}}proto=Jemplate.Plugin.prototype;proto.plugins={};if(typeof Jemplate.Filter=="undefined"){Jemplate.Filter=function(){}}proto=Jemplate.Filter.prototype;proto.filters={};proto.filters.null_filter=function(text){return""};proto.filters.upper=function(text){return text.toUpperCase()};proto.filters.lower=function(text){return text.toLowerCase()};proto.filters.ucfirst=function(text){var first=text.charAt(0);var rest=text.substr(1);return first.toUpperCase()+rest};proto.filters.lcfirst=function(text){var first=text.charAt(0);var rest=text.substr(1);return first.toLowerCase()+rest};proto.filters.trim=function(text){return text.replace(/^\s+/g,"").replace(/\s+$/g,"")};proto.filters.collapse=function(text){return text.replace(/^\s+/g,"").replace(/\s+$/g,"").replace(/\s+/," ")};proto.filters.html=function(text){text=text.replace(/&/g,"&amp;");text=text.replace(/</g,"&lt;");text=text.replace(/>/g,"&gt;");text=text.replace(/"/g,"&quot;");return text};proto.filters.html_para=function(text){var lines=text.split(/(?:\r?\n){2,}/);return"<p>\n"+lines.join("\n</p>\n\n<p>\n")+"</p>\n"};proto.filters.html_break=function(text){return text.replace(/(\r?\n){2,}/g,"$1<br />$1<br />$1")};proto.filters.html_line_break=function(text){return text.replace(/(\r?\n)/g,"$1<br />$1")};proto.filters.uri=function(text){return encodeURIComponent(text)};proto.filters.url=function(text){return encodeURI(text)};proto.filters.indent=function(text,args){var pad=args[0];if(!text){return null}if(typeof pad=="undefined"){pad=4}var finalpad="";if(typeof pad=="number"||String(pad).match(/^\d$/)){for(var i=0;i<pad;i++){finalpad+=" "}}else{finalpad=pad}var output=text.replace(/^/gm,finalpad);return output};proto.filters.truncate=function(text,args){var len=args[0];if(!text){return null}if(!len){len=32}if(text.length<len){return text}var newlen=len-3;return text.substr(0,newlen)+"..."};proto.filters.repeat=function(text,iter){if(!text){return null}if(!iter||iter==0){iter=1}if(iter==1){return text}var output=text;for(var i=1;i<iter;i++){output+=text}return output};proto.filters.replace=function(text,args){if(!text){return null}var re_search=args[0];var text_replace=args[1];if(!re_search){re_search=""}if(!text_replace){text_replace=""}var re=new RegExp(re_search,"g");return text.replace(re,text_replace)};if(typeof Jemplate.Stash=="undefined"){Jemplate.Stash=function(stash,config){this.__config__=config;this.data={GLOBAL:this.__config__.SCOPE};this.LOCAL_ANCHOR={};this.data.LOCAL=this.LOCAL_ANCHOR;this.update(stash)}}proto=Jemplate.Stash.prototype;proto.clone=function(args){var data=this.data;this.data={GLOBAL:this.__config__.SCOPE};this.data.LOCAL=this.LOCAL_ANCHOR;this.update(data);this.update(args);this.data._PARENT=data};proto.declone=function(args){this.data=this.data._PARENT||this.data};proto.update=function(args){if(typeof args=="undefined"){return }for(var key in args){if(key!="GLOBAL"&&key!="LOCAL"){this.set(key,args[key])}}};proto.get=function(ident,args){var root=this.data;var value;if((ident instanceof Array)||(typeof ident=="string"&&/\./.test(ident))){if(typeof ident=="string"){ident=ident.split(".");var newIdent=[];for(var i=0;i<ident.length;i++){newIdent.push(ident.replace(/\(.*$/,""));newIdent.push(0)}ident=newIdent}for(var i=0;i<ident.length;i+=2){var dotopArgs=ident.slice(i,i+2);dotopArgs.unshift(root);value=this._dotop.apply(this,dotopArgs);if(typeof value=="undefined"){break}root=value}}else{value=this._dotop(root,ident,args)}if(typeof value=="undefined"||value==null){if(this.__config__.DEBUG_UNDEF){throw ("undefined value found while using DEBUG_UNDEF")}value=""}return value};proto.set=function(ident,value,set_default){var root,result,error;root=this.data;while(true){if((ident instanceof Array)||(typeof ident=="string"&&/\./.test(ident))){if(typeof ident=="string"){ident=ident.split(".");var newIdent=[];for(var i=0;i<ident.length;i++){newIdent.push(ident.replace(/\(.*$/,""));newIdent.push(0)}ident=newIdent}for(var i=0;i<ident.length-2;i+=2){var dotopArgs=ident.slice(i,i+2);dotopArgs.unshift(root);dotopArgs.push(1);result=this._dotop.apply(this,dotopArgs);if(typeof value=="undefined"){break}root=result}var assignArgs=ident.slice(ident.length-2,ident.length);assignArgs.unshift(root);assignArgs.push(value);assignArgs.push(set_default);result=this._assign.apply(this,assignArgs)}else{result=this._assign(root,ident,0,value,set_default)}break}return(typeof result!="undefined")?result:""};proto._dotop=function(root,item,args,lvalue){if(root==this.LOCAL_ANCHOR){root=this.data}var atroot=root==this.data;var value,result=undefined;var is_function_call=args instanceof Array;args=args||[];if(typeof root=="undefined"||typeof item=="undefined"||typeof item=="string"&&item.match(/^[\._]/)){return undefined}if(atroot||(root instanceof Object&&!(root instanceof Array))||root==this.data.GLOBAL){if(typeof root[item]!="undefined"&&root[item]!=null&&(!is_function_call||!this.hash_functions[item])){if(typeof root[item]=="function"){result=root[item].apply(root,args)}else{return root[item]}}else{if(lvalue){return root[item]={}}else{if(this.hash_functions[item]&&!atroot||item=="import"){args.unshift(root);result=this.hash_functions[item].apply(this,args)}else{if(item instanceof Array){result={};for(var i=0;i<item.length;i++){result[item[i]]=root[item[i]]}return result}}}}}else{if(root instanceof Array){if(this.list_functions[item]){args.unshift(root);result=this.list_functions[item].apply(this,args)}else{if(typeof item=="string"&&/^-?\d+$/.test(item)||typeof item=="number"){if(typeof root[item]!="function"){return root[item]}result=root[item].apply(this,args)}else{if(item instanceof Array){for(var i=0;i<item.length;i++){result.push(root[item[i]])}return result}}}}else{if(this.string_functions[item]&&!lvalue){args.unshift(root);result=this.string_functions[item].apply(this,args)}else{if(this.list_functions[item]&&!lvalue){args.unshift([root]);result=this.list_functions[item].apply(this,args)}else{result=undefined}}}}if(result instanceof Array){if(typeof result[0]=="undefined"&&typeof result[1]!="undefined"){throw result[1]}}return result};proto._assign=function(root,item,args,value,set_default){var atroot=root==this.data;var result;args=args||[];if(typeof root=="undefined"||typeof item=="undefined"||typeof item=="string"&&item.match(/^[\._]/)){return undefined}if(atroot||root.constructor==Object||root==this.data.GLOBAL){if(root==this.LOCAL_ANCHOR){root=this.data}if(!(set_default&&typeof root[item]!="undefined")){if(atroot&&item=="GLOBAL"){throw"Attempt to modify GLOBAL access modifier"}if(atroot&&item=="LOCAL"){throw"Attempt to modify LOCAL access modifier"}return root[item]=value}}else{if((root instanceof Array)&&(typeof item=="string"&&/^-?\d+$/.test(item)||typeof item=="number")){if(!(set_default&&typeof root[item]!="undefined")){return root[item]=value}}else{if((root.constructor!=Object)&&(root instanceof Object)){try{result=root[item].apply(root,args)}catch(e){}}else{throw"dont know how to assign to ["+root+"."+item+"]"}}}return undefined};proto.string_functions={};proto.string_functions["typeof"]=function(value){return typeof value};proto.string_functions.chunk=function(string,size){var list=new Array();if(!size){size=1}if(size<0){size=0-size;for(var i=string.length-size;i>=0;i=i-size){list.unshift(string.substr(i,size))}if(string.length%size){list.unshift(string.substr(0,string.length%size))}}else{for(i=0;i<string.length;i=i+size){list.push(string.substr(i,size))}}return list};proto.string_functions.defined=function(string){return 1};proto.string_functions.hash=function(string){return{"value":string}};proto.string_functions.length=function(string){return string.length};proto.string_functions.list=function(string){return[string]};proto.string_functions.match=function(string,re,modifiers){var regexp=new RegExp(re,modifiers);var list=string.match(regexp);return list};proto.string_functions.repeat=function(string,args){var n=args||1;var output="";for(var i=0;i<n;i++){output+=string}return output};proto.string_functions.replace=function(string,re,sub,modifiers){var regexp=new RegExp(re,modifiers);if(!sub){sub=""}return string.replace(regexp,sub)};proto.string_functions.search=function(string,re){var regexp=new RegExp(re);return(string.search(regexp)>=0)?1:0};proto.string_functions.size=function(string){return 1};proto.string_functions.split=function(string,re){var regexp=new RegExp(re);var list=string.split(regexp);return list};proto.list_functions={};proto.list_functions["typeof"]=function(list){return"array"};proto.list_functions.list=function(list){return list};proto.list_functions.join=function(list,str){return list.join(str)};proto.list_functions.sort=function(list,key){if(typeof (key)!="undefined"&&key!=""){return list.sort(function(a,b){if(a[key]==b[key]){return 0}else{if(a[key]>b[key]){return 1}else{return -1}}})}return list.sort()};proto.list_functions.nsort=function(list){return list.sort(function(a,b){return(a-b)})};proto.list_functions.grep=function(list,re){var regexp=new RegExp(re);var result=[];for(var i=0;i<list.length;i++){if(list[i].match(regexp)){result.push(list[i])}}return result};proto.list_functions.unique=function(list){var result=[];var seen={};for(var i=0;i<list.length;i++){var elem=list[i];if(!seen[elem]){result.push(elem)}seen[elem]=true}return result};proto.list_functions.reverse=function(list){var result=[];for(var i=list.length-1;i>=0;i--){result.push(list[i])}return result};proto.list_functions.merge=function(list){var result=[];var push_all=function(elem){if(elem instanceof Array){for(var j=0;j<elem.length;j++){result.push(elem[j])}}else{result.push(elem)}};push_all(list);for(var i=1;i<arguments.length;i++){push_all(arguments[i])}return result};proto.list_functions.slice=function(list,start,end){return list.slice(start,end)};proto.list_functions.splice=function(list){var args=Array.prototype.slice.call(arguments);args.shift();return list.splice.apply(list,args)};proto.list_functions.push=function(list,value){list.push(value);return list};proto.list_functions.pop=function(list){return list.pop()};proto.list_functions.unshift=function(list,value){list.unshift(value);return list};proto.list_functions.shift=function(list){return list.shift()};proto.list_functions.first=function(list){return list[0]};proto.list_functions.size=function(list){return list.length};proto.list_functions.max=function(list){return list.length-1};proto.list_functions.last=function(list){return list.slice(-1)};proto.hash_functions={};proto.hash_functions["typeof"]=function(hash){return"object"};proto.hash_functions.each=function(hash){var list=new Array();for(var key in hash){list.push(key,hash[key])}return list};proto.hash_functions.exists=function(hash,key){return(typeof (hash[key])=="undefined")?0:1};proto.hash_functions["import"]=function(hash,hash2){for(var key in hash2){hash[key]=hash2[key]}return""};proto.hash_functions.keys=function(hash){var list=new Array();for(var key in hash){list.push(key)}return list};proto.hash_functions.list=function(hash,what){var list=new Array();var key;if(what=="keys"){for(key in hash){list.push(key)}}else{if(what=="values"){for(key in hash){list.push(hash[key])}}else{if(what=="each"){for(key in hash){list.push(key,hash[key])}}else{for(key in hash){list.push({"key":key,"value":hash[key]})}}}}return list};proto.hash_functions.nsort=function(hash){var list=new Array();for(var key in hash){list.push(key)}return list.sort(function(a,b){return(a-b)})};proto.hash_functions.item=function(hash,key){return hash[key]};proto.hash_functions.size=function(hash){var size=0;for(var key in hash){size++}return size};proto.hash_functions.sort=function(hash){var list=new Array();for(var key in hash){list.push(key)}return list.sort()};proto.hash_functions.values=function(hash){var list=new Array();for(var key in hash){list.push(hash[key])}return list};proto.hash_functions.remove=function(hash,key){return delete hash[key]};proto.hash_functions["delete"]=proto.hash_functions.remove;if(typeof Jemplate.Iterator=="undefined"){Jemplate.Iterator=function(object){if(object instanceof Array){this.object=object;this.size=object.length;this.max=this.size-1}else{if(object instanceof Object){this.object=object;var object_keys=new Array;for(var key in object){object_keys[object_keys.length]=key}this.object_keys=object_keys.sort();this.size=object_keys.length;this.max=this.size-1}else{if(typeof object=="undefined"||object==null||object==""){this.object=null;this.max=-1}}}}}proto=Jemplate.Iterator.prototype;proto.get_first=function(){this.index=0;this.first=1;this.last=0;this.count=1;return this.get_next(1)};proto.get_next=function(should_init){var object=this.object;var index;if(typeof (should_init)!="undefined"&&should_init){index=this.index}else{index=++this.index;this.first=0;this.count=this.index+1;if(this.index==this.size-1){this.last=1}}if(typeof object=="undefined"){throw ("No object to iterate")}if(this.object_keys){if(index<this.object_keys.length){this.prev=index>0?this.object_keys[index-1]:"";this.next=index<this.max?this.object_keys[index+1]:"";return[this.object_keys[index],false]}}else{if(index<=this.max){this.prev=index>0?object[index-1]:"";this.next=index<this.max?object[index+1]:"";return[object[index],false]}}return[null,true]};var stubExplanation="stub that doesn't do anything. Try including the jQuery, YUI, or XHR option when building the runtime";Jemplate.Ajax={get:function(url,callback){throw ("This is a Jemplate.Ajax.get "+stubExplanation)},processGet:function(url,callback){throw ("This is a Jemplate.Ajax.processGet "+stubExplanation)},post:function(url,callback){throw ("This is a Jemplate.Ajax.post "+stubExplanation)}};Jemplate.JSON={parse:function(decodeValue){throw ("This is a Jemplate.JSON.parse "+stubExplanation)},stringify:function(encodeValue){throw ("This is a Jemplate.JSON.stringify "+stubExplanation)}}}())
+if(typeof Jemplate=="undefined"){var Jemplate=function(){this.init.apply(this,arguments)}}Jemplate.VERSION="0.22";Jemplate.process=function(){var A=new Jemplate(Jemplate.prototype.config);return A.process.apply(A,arguments)};(function(){if(!Jemplate.templateMap){Jemplate.templateMap={}}var proto=Jemplate.prototype={};proto.config={AUTO_RESET:true,BLOCKS:{},CONTEXT:null,DEBUG_UNDEF:false,DEFAULT:null,ERROR:null,EVAL_JAVASCRIPT:false,GLOBAL:true,SCOPE:this,FILTERS:{},INCLUDE_PATH:[""],INTERPOLATE:false,OUTPUT:null,PLUGINS:{},POST_PROCESS:[],PRE_PROCESS:[],PROCESS:null,RECURSION:false,STASH:null,TOLERANT:null,VARIABLES:{},WRAPPER:[]};proto.defaults={AUTO_RESET:true,BLOCKS:{},CONTEXT:null,DEBUG_UNDEF:false,DEFAULT:null,ERROR:null,EVAL_JAVASCRIPT:false,GLOBAL:true,SCOPE:this,INCLUDE_PATH:[""],INTERPOLATE:false,OUTPUT:null,PLUGINS:{},POST_PROCESS:[],PRE_PROCESS:[],PROCESS:null,RECURSION:false,STASH:null,TOLERANT:null,VARIABLES:{},WRAPPER:[]};Jemplate.init=function(config){Jemplate.prototype.config=config||{};for(var i in Jemplate.prototype.defaults){if(typeof Jemplate.prototype.config[i]=="undefined"){Jemplate.prototype.config[i]=Jemplate.prototype.defaults[i]}}};proto.init=function(config){this.config=config||{};for(var i in Jemplate.prototype.defaults){if(typeof this.config[i]=="undefined"){this.config[i]=Jemplate.prototype.defaults[i]}}};proto.process=function(template,data,output){var context=this.config.CONTEXT||new Jemplate.Context();context.config=this.config;context.stash=new Jemplate.Stash(this.config.STASH,this.config);context.__filter__=new Jemplate.Filter();context.__filter__.config=this.config;context.__plugin__=new Jemplate.Plugin();context.__plugin__.config=this.config;var result;var proc=function(input){try{if(typeof context.config.PRE_PROCESS=="string"){context.config.PRE_PROCESS=[context.config.PRE_PROCESS]}for(var i=0;i<context.config.PRE_PROCESS.length;i++){context.process(context.config.PRE_PROCESS[i])}result=context.process(template,input);if(typeof context.config.POST_PROCESS=="string"){context.config.PRE_PROCESS=[context.config.POST_PROCESS]}for(i=0;i<context.config.POST_PROCESS.length;i++){context.process(context.config.POST_PROCESS[i])}}catch(e){if(!String(e).match(/Jemplate\.STOP\n/)){throw (e)}result=e.toString().replace(/Jemplate\.STOP\n/,"")}if(typeof output=="undefined"){return result}if(typeof output=="function"){output(result);return null}if(typeof (output)=="string"||output instanceof String){if(output.match(/^#[\w\-]+$/)){var id=output.replace(/^#/,"");var element=document.getElementById(id);if(typeof element=="undefined"){throw ('No element found with id="'+id+'"')}element.innerHTML=result;return null}}else{output.innerHTML=result;return null}throw ("Invalid arguments in call to Jemplate.process");return 1};if(typeof data=="function"){data=data()}else{if(typeof data=="string"){var url=data;Jemplate.Ajax.processGet(url,function(data){proc(data)});return null}}return proc(data)};if(typeof Jemplate.Context=="undefined"){Jemplate.Context=function(){}}proto=Jemplate.Context.prototype;proto.include=function(template,args){return this.process(template,args,true)};proto.process=function(template,args,localise){if(localise){this.stash.clone(args)}else{this.stash.update(args)}var func=Jemplate.templateMap[template];if(typeof func=="undefined"){throw ('No Jemplate template named "'+template+'" available')}var output=func(this);if(localise){this.stash.declone()}return output};proto.set_error=function(error,output){this._error=[error,output];return error};proto.plugin=function(name,args){if(typeof name=="undefined"){throw"Unknown plugin name ':"+name+"'"}var func=eval(name);return new func(this,args)};proto.filter=function(text,name,args){if(name=="null"){name="null_filter"}if(typeof this.__filter__.filters[name]=="function"){return this.__filter__.filters[name](text,args,this)}else{throw"Unknown filter name ':"+name+"'"}};if(typeof Jemplate.Plugin=="undefined"){Jemplate.Plugin=function(){}}proto=Jemplate.Plugin.prototype;proto.plugins={};if(typeof Jemplate.Filter=="undefined"){Jemplate.Filter=function(){}}proto=Jemplate.Filter.prototype;proto.filters={};proto.filters.null_filter=function(text){return""};proto.filters.upper=function(text){return text.toUpperCase()};proto.filters.lower=function(text){return text.toLowerCase()};proto.filters.ucfirst=function(text){var first=text.charAt(0);var rest=text.substr(1);return first.toUpperCase()+rest};proto.filters.lcfirst=function(text){var first=text.charAt(0);var rest=text.substr(1);return first.toLowerCase()+rest};proto.filters.trim=function(text){return text.replace(/^\s+/g,"").replace(/\s+$/g,"")};proto.filters.collapse=function(text){return text.replace(/^\s+/g,"").replace(/\s+$/g,"").replace(/\s+/," ")};proto.filters.html=function(text){text=text.replace(/&/g,"&amp;");text=text.replace(/</g,"&lt;");text=text.replace(/>/g,"&gt;");text=text.replace(/"/g,"&quot;");return text};proto.filters.html_para=function(text){var lines=text.split(/(?:\r?\n){2,}/);return"<p>\n"+lines.join("\n</p>\n\n<p>\n")+"</p>\n"};proto.filters.html_break=function(text){return text.replace(/(\r?\n){2,}/g,"$1<br />$1<br />$1")};proto.filters.html_line_break=function(text){return text.replace(/(\r?\n)/g,"$1<br />$1")};proto.filters.uri=function(text){return encodeURIComponent(text)};proto.filters.url=function(text){return encodeURI(text)};proto.filters.indent=function(text,args){var pad=args[0];if(!text){return null}if(typeof pad=="undefined"){pad=4}var finalpad="";if(typeof pad=="number"||String(pad).match(/^\d$/)){for(var i=0;i<pad;i++){finalpad+=" "}}else{finalpad=pad}var output=text.replace(/^/gm,finalpad);return output};proto.filters.truncate=function(text,args){var len=args[0];if(!text){return null}if(!len){len=32}if(text.length<len){return text}var newlen=len-3;return text.substr(0,newlen)+"..."};proto.filters.repeat=function(text,iter){if(!text){return null}if(!iter||iter==0){iter=1}if(iter==1){return text}var output=text;for(var i=1;i<iter;i++){output+=text}return output};proto.filters.replace=function(text,args){if(!text){return null}var re_search=args[0];var text_replace=args[1];if(!re_search){re_search=""}if(!text_replace){text_replace=""}var re=new RegExp(re_search,"g");return text.replace(re,text_replace)};if(typeof Jemplate.Stash=="undefined"){Jemplate.Stash=function(stash,config){this.__config__=config;this.data={GLOBAL:this.__config__.SCOPE};this.LOCAL_ANCHOR={};this.data.LOCAL=this.LOCAL_ANCHOR;this.update(stash)}}proto=Jemplate.Stash.prototype;proto.clone=function(args){var data=this.data;this.data={GLOBAL:this.__config__.SCOPE};this.data.LOCAL=this.LOCAL_ANCHOR;this.update(data);this.update(args);this.data._PARENT=data};proto.declone=function(args){this.data=this.data._PARENT||this.data};proto.update=function(args){if(typeof args=="undefined"){return }for(var key in args){if(key!="GLOBAL"&&key!="LOCAL"){this.set(key,args[key])}}};proto.get=function(ident,args){var root=this.data;var value;if((ident instanceof Array)||(typeof ident=="string"&&/\./.test(ident))){if(typeof ident=="string"){ident=ident.split(".");var newIdent=[];for(var i=0;i<ident.length;i++){newIdent.push(ident.replace(/\(.*$/,""));newIdent.push(0)}ident=newIdent}for(var i=0;i<ident.length;i+=2){var dotopArgs=ident.slice(i,i+2);dotopArgs.unshift(root);value=this._dotop.apply(this,dotopArgs);if(typeof value=="undefined"){break}root=value}}else{value=this._dotop(root,ident,args)}if(typeof value=="undefined"||value==null){if(this.__config__.DEBUG_UNDEF){throw ("undefined value found while using DEBUG_UNDEF")}value=""}return value};proto.set=function(ident,value,set_default){var root,result,error;root=this.data;while(true){if((ident instanceof Array)||(typeof ident=="string"&&/\./.test(ident))){if(typeof ident=="string"){ident=ident.split(".");var newIdent=[];for(var i=0;i<ident.length;i++){newIdent.push(ident.replace(/\(.*$/,""));newIdent.push(0)}ident=newIdent}for(var i=0;i<ident.length-2;i+=2){var dotopArgs=ident.slice(i,i+2);dotopArgs.unshift(root);dotopArgs.push(1);result=this._dotop.apply(this,dotopArgs);if(typeof value=="undefined"){break}root=result}var assignArgs=ident.slice(ident.length-2,ident.length);assignArgs.unshift(root);assignArgs.push(value);assignArgs.push(set_default);result=this._assign.apply(this,assignArgs)}else{result=this._assign(root,ident,0,value,set_default)}break}return(typeof result!="undefined")?result:""};proto._dotop=function(root,item,args,lvalue){if(root==this.LOCAL_ANCHOR){root=this.data}var atroot=root==this.data;var value,result=undefined;var is_function_call=args instanceof Array;args=args||[];if(typeof root=="undefined"||typeof item=="undefined"||typeof item=="string"&&item.match(/^[\._]/)){return undefined}if(atroot||(root instanceof Object&&!(root instanceof Array))||root==this.data.GLOBAL){if(typeof root[item]!="undefined"&&root[item]!=null&&(!is_function_call||!this.hash_functions[item])){if(typeof root[item]=="function"){result=root[item].apply(root,args)}else{return root[item]}}else{if(lvalue){return root[item]={}}else{if(this.hash_functions[item]&&!atroot||item=="import"){args.unshift(root);result=this.hash_functions[item].apply(this,args)}else{if(item instanceof Array){result={};for(var i=0;i<item.length;i++){result[item[i]]=root[item[i]]}return result}}}}}else{if(root instanceof Array){if(this.list_functions[item]){args.unshift(root);result=this.list_functions[item].apply(this,args)}else{if(typeof item=="string"&&/^-?\d+$/.test(item)||typeof item=="number"){if(typeof root[item]!="function"){return root[item]}result=root[item].apply(this,args)}else{if(item instanceof Array){for(var i=0;i<item.length;i++){result.push(root[item[i]])}return result}}}}else{if(this.string_functions[item]&&!lvalue){args.unshift(root);result=this.string_functions[item].apply(this,args)}else{if(this.list_functions[item]&&!lvalue){args.unshift([root]);result=this.list_functions[item].apply(this,args)}else{result=undefined}}}}if(result instanceof Array){if(typeof result[0]=="undefined"&&typeof result[1]!="undefined"){throw result[1]}}return result};proto._assign=function(root,item,args,value,set_default){var atroot=root==this.data;var result;args=args||[];if(typeof root=="undefined"||typeof item=="undefined"||typeof item=="string"&&item.match(/^[\._]/)){return undefined}if(atroot||root.constructor==Object||root==this.data.GLOBAL){if(root==this.LOCAL_ANCHOR){root=this.data}if(!(set_default&&typeof root[item]!="undefined")){if(atroot&&item=="GLOBAL"){throw"Attempt to modify GLOBAL access modifier"}if(atroot&&item=="LOCAL"){throw"Attempt to modify LOCAL access modifier"}return root[item]=value}}else{if((root instanceof Array)&&(typeof item=="string"&&/^-?\d+$/.test(item)||typeof item=="number")){if(!(set_default&&typeof root[item]!="undefined")){return root[item]=value}}else{if((root.constructor!=Object)&&(root instanceof Object)){try{result=root[item].apply(root,args)}catch(e){}}else{throw"dont know how to assign to ["+root+"."+item+"]"}}}return undefined};proto.string_functions={};proto.string_functions["typeof"]=function(value){return typeof value};proto.string_functions.chunk=function(string,size){var list=new Array();if(!size){size=1}if(size<0){size=0-size;for(var i=string.length-size;i>=0;i=i-size){list.unshift(string.substr(i,size))}if(string.length%size){list.unshift(string.substr(0,string.length%size))}}else{for(i=0;i<string.length;i=i+size){list.push(string.substr(i,size))}}return list};proto.string_functions.defined=function(string){return 1};proto.string_functions.hash=function(string){return{"value":string}};proto.string_functions.length=function(string){return string.length};proto.string_functions.list=function(string){return[string]};proto.string_functions.match=function(string,re,modifiers){var regexp=new RegExp(re,modifiers==undefined?"g":modifiers);var list=string.match(regexp);return list};proto.string_functions.repeat=function(string,args){var n=args||1;var output="";for(var i=0;i<n;i++){output+=string}return output};proto.string_functions.replace=function(string,re,sub,modifiers){var regexp=new RegExp(re,modifiers==undefined?"g":modifiers);if(!sub){sub=""}return string.replace(regexp,sub)};proto.string_functions.search=function(string,re){var regexp=new RegExp(re);return(string.search(regexp)>=0)?1:0};proto.string_functions.size=function(string){return 1};proto.string_functions.split=function(string,re){var regexp=new RegExp(re);var list=string.split(regexp);return list};proto.list_functions={};proto.list_functions["typeof"]=function(list){return"array"};proto.list_functions.list=function(list){return list};proto.list_functions.join=function(list,str){return list.join(str)};proto.list_functions.sort=function(list,key){if(typeof (key)!="undefined"&&key!=""){return list.sort(function(a,b){if(a[key]==b[key]){return 0}else{if(a[key]>b[key]){return 1}else{return -1}}})}return list.sort()};proto.list_functions.nsort=function(list){return list.sort(function(a,b){return(a-b)})};proto.list_functions.grep=function(list,re){var regexp=new RegExp(re);var result=[];for(var i=0;i<list.length;i++){if(list[i].match(regexp)){result.push(list[i])}}return result};proto.list_functions.unique=function(list){var result=[];var seen={};for(var i=0;i<list.length;i++){var elem=list[i];if(!seen[elem]){result.push(elem)}seen[elem]=true}return result};proto.list_functions.reverse=function(list){var result=[];for(var i=list.length-1;i>=0;i--){result.push(list[i])}return result};proto.list_functions.merge=function(list){var result=[];var push_all=function(elem){if(elem instanceof Array){for(var j=0;j<elem.length;j++){result.push(elem[j])}}else{result.push(elem)}};push_all(list);for(var i=1;i<arguments.length;i++){push_all(arguments[i])}return result};proto.list_functions.slice=function(list,start,end){if(end==-1){return list.slice(start)}return list.slice(start,end+1)};proto.list_functions.splice=function(list){var args=Array.prototype.slice.call(arguments);args.shift();return list.splice.apply(list,args)};proto.list_functions.push=function(list,value){list.push(value);return list};proto.list_functions.pop=function(list){return list.pop()};proto.list_functions.unshift=function(list,value){list.unshift(value);return list};proto.list_functions.shift=function(list){return list.shift()};proto.list_functions.first=function(list){return list[0]};proto.list_functions.size=function(list){return list.length};proto.list_functions.max=function(list){return list.length-1};proto.list_functions.last=function(list){return list.slice(-1)};proto.hash_functions={};proto.hash_functions["typeof"]=function(hash){return"object"};proto.hash_functions.each=function(hash){var list=new Array();for(var key in hash){list.push(key,hash[key])}return list};proto.hash_functions.exists=function(hash,key){return(typeof (hash[key])=="undefined")?0:1};proto.hash_functions["import"]=function(hash,hash2){for(var key in hash2){hash[key]=hash2[key]}return""};proto.hash_functions.keys=function(hash){var list=new Array();for(var key in hash){list.push(key)}return list};proto.hash_functions.list=function(hash,what){var list=new Array();var key;if(what=="keys"){for(key in hash){list.push(key)}}else{if(what=="values"){for(key in hash){list.push(hash[key])}}else{if(what=="each"){for(key in hash){list.push(key,hash[key])}}else{for(key in hash){list.push({"key":key,"value":hash[key]})}}}}return list};proto.hash_functions.nsort=function(hash){var list=new Array();for(var key in hash){list.push(key)}return list.sort(function(a,b){return(a-b)})};proto.hash_functions.item=function(hash,key){return hash[key]};proto.hash_functions.size=function(hash){var size=0;for(var key in hash){size++}return size};proto.hash_functions.sort=function(hash){var list=new Array();for(var key in hash){list.push(key)}return list.sort()};proto.hash_functions.values=function(hash){var list=new Array();for(var key in hash){list.push(hash[key])}return list};proto.hash_functions.pairs=function(hash){var list=new Array();var keys=new Array();for(var key in hash){keys.push(key)}keys.sort();for(var key in keys){key=keys[key];list.push({"key":key,"value":hash[key]})}return list};proto.hash_functions.remove=function(hash,key){return delete hash[key]};proto.hash_functions["delete"]=proto.hash_functions.remove;if(typeof Jemplate.Iterator=="undefined"){Jemplate.Iterator=function(object){if(object instanceof Array){this.object=object;this.size=object.length;this.max=this.size-1}else{if(object instanceof Object){this.object=object;var object_keys=new Array;for(var key in object){object_keys[object_keys.length]=key}this.object_keys=object_keys.sort();this.size=object_keys.length;this.max=this.size-1}else{if(typeof object=="undefined"||object==null||object==""){this.object=null;this.max=-1}}}}}proto=Jemplate.Iterator.prototype;proto.get_first=function(){this.index=0;this.first=1;this.last=0;this.count=1;return this.get_next(1)};proto.get_next=function(should_init){var object=this.object;var index;if(typeof (should_init)!="undefined"&&should_init){index=this.index}else{index=++this.index;this.first=0;this.count=this.index+1;if(this.index==this.size-1){this.last=1}}if(typeof object=="undefined"){throw ("No object to iterate")}if(this.object_keys){if(index<this.object_keys.length){this.prev=index>0?this.object_keys[index-1]:"";this.next=index<this.max?this.object_keys[index+1]:"";return[this.object_keys[index],false]}}else{if(index<=this.max){this.prev=index>0?object[index-1]:"";this.next=index<this.max?object[index+1]:"";return[object[index],false]}}return[null,true]};var stubExplanation="stub that doesn't do anything. Try including the jQuery, YUI, or XHR option when building the runtime";Jemplate.Ajax={get:function(url,callback){throw ("This is a Jemplate.Ajax.get "+stubExplanation)},processGet:function(url,callback){throw ("This is a Jemplate.Ajax.processGet "+stubExplanation)},post:function(url,callback){throw ("This is a Jemplate.Ajax.post "+stubExplanation)}};Jemplate.JSON={parse:function(decodeValue){throw ("This is a Jemplate.JSON.parse "+stubExplanation)},stringify:function(encodeValue){throw ("This is a Jemplate.JSON.stringify "+stubExplanation)}}}())
...
}
@@ -39,7 +39,7 @@ sub json_json2_internal {
var JSON;
-if(!JSON){var JSON}if(!JSON){JSON=function(){function f(n){return n<10?"0"+n:n}Date.prototype.toJSON=function(){return this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z"};var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){return escapeable.test(string)?'"'+string.replace(escapeable,function(a){var c=meta[a];if(typeof c==="string"){return c}c=a.charCodeAt();return"\\u00"+Math.floor(c/16).toString(16)+(c%16).toString(16)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(typeof value.length==="number"&&!(value.propertyIsEnumerable("length"))){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value,rep);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){v=str(k,value,rep);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}return null}return{stringify:function(value,replacer,space){var i;gap="";indent="";if(space){if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}}if(!replacer){rep=function(key,value){if(!Object.hasOwnProperty.call(this,key)){return undefined}return value}}else{if(typeof replacer==="function"||(typeof replacer==="object"&&typeof replacer.length==="number")){rep=replacer}else{throw new Error("JSON.stringify")}}return str("",{"":value})},parse:function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}if(/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")},quote:quote}}()}
+if(!this.JSON){this.JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z"};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}return""}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}())
Jemplate.JSON={parse:function(A){return JSON.parse(A)},stringify:function(A){return JSON.stringify(A)}}
@@ -55,7 +55,7 @@ sub json_yui {
sub json2 {
<<'...';
-if(!JSON){var JSON}if(!JSON){JSON=function(){function f(n){return n<10?"0"+n:n}Date.prototype.toJSON=function(){return this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z"};var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){return escapeable.test(string)?'"'+string.replace(escapeable,function(a){var c=meta[a];if(typeof c==="string"){return c}c=a.charCodeAt();return"\\u00"+Math.floor(c/16).toString(16)+(c%16).toString(16)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(typeof value.length==="number"&&!(value.propertyIsEnumerable("length"))){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value,rep);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){v=str(k,value,rep);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}return null}return{stringify:function(value,replacer,space){var i;gap="";indent="";if(space){if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}}if(!replacer){rep=function(key,value){if(!Object.hasOwnProperty.call(this,key)){return undefined}return value}}else{if(typeof replacer==="function"||(typeof replacer==="object"&&typeof replacer.length==="number")){rep=replacer}else{throw new Error("JSON.stringify")}}return str("",{"":value})},parse:function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}if(/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")},quote:quote}}()}
+if(!this.JSON){this.JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z"};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}return""}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}())
...
}
View
2  src/js/json2.compact.js
@@ -1 +1 @@
-if(!JSON){var JSON}if(!JSON){JSON=function(){function f(n){return n<10?"0"+n:n}Date.prototype.toJSON=function(){return this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z"};var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){return escapeable.test(string)?'"'+string.replace(escapeable,function(a){var c=meta[a];if(typeof c==="string"){return c}c=a.charCodeAt();return"\\u00"+Math.floor(c/16).toString(16)+(c%16).toString(16)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(typeof value.length==="number"&&!(value.propertyIsEnumerable("length"))){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value,rep);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){v=str(k,value,rep);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}return null}return{stringify:function(value,replacer,space){var i;gap="";indent="";if(space){if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}}if(!replacer){rep=function(key,value){if(!Object.hasOwnProperty.call(this,key)){return undefined}return value}}else{if(typeof replacer==="function"||(typeof replacer==="object"&&typeof replacer.length==="number")){rep=replacer}else{throw new Error("JSON.stringify")}}return str("",{"":value})},parse:function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}if(/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")},quote:quote}}()}
+if(!this.JSON){this.JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z"};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}return""}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}())
View
462 src/js/json2.js
@@ -1,6 +1,6 @@
/*
- json2.js
- 2008-03-24
+ http://www.JSON.org/json2.js
+ 2009-04-16
Public Domain.
@@ -8,44 +8,48 @@
See http://www.JSON.org/js.html
- This file creates a global JSON object containing three methods: stringify,
- parse, and quote.
-
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
- values are stringified for objects without a toJSON
- method. It can be a function or an array.
+ values are stringified for objects. It can be a
+ function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
- level. If it is a string (such as '\t'), it contains the
- characters used to indent at each level.
+ level. If it is a string (such as '\t' or '&nbsp;'),
+ it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
- method, its toJSON method with be called and the result will be
+ method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
- or undefined if nothing should be serialized. The toJSON method will
- be passed the key associated with the value, and this will be bound
- to the object holding the key.
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the object holding the key.
+
+ For example, this would serialize Dates as ISO strings.
- This is the toJSON method added to Dates:
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
- function toJSON(key) {
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
- }
+ };
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
@@ -53,35 +57,24 @@
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
- If no replacer parameter is provided, then a default replacer
- will be used:
-
- function replacer(key, value) {
- return Object.hasOwnProperty.call(this, key) ?
- value : undefined;
- }
-
- The default replacer is passed the key and value for each item in
- the structure. It excludes inherited members.
-
- If the replacer parameter is an array, then it will be used to
- select the members to be serialized. It filters the results such
- that only members with keys listed in the replacer array are
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
stringified.
- Values that do not have JSON representaions, such as undefined or
+ Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
- The optional space parameter produces a stringification of the value
- that is filled with line breaks and indentation to make it easier to
- read.
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
- then indentation will be that many spaces.
+ the indentation will be that many spaces.
Example:
@@ -92,16 +85,22 @@
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
- transform the results. It receives each of the keys and values, and
- its return value is used instead of the original value. If it
- returns what it received, then structure is not modified. If it
- returns undefined then the member is deleted.
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
Example: