get rid of some IE 6/7/8 code.
fixes: CNVS-12363 this is all just old crufty stuff that since we don't support IE <= 8 we don't need. the only noticeable difference is that if you try to go to canvas in IE 8 it will give you that "this browser is not supported" screen. I don't think it did that before Change-Id: I9e11eb0925502d1862616a971ce88126c7d5eb67 Reviewed-on: https://gerrit.instructure.com/30409 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Ryan Florence <ryanf@instructure.com> QA-Review: Nathan Rogowski <nathan@instructure.com> Product-Review: Ryan Shaw <ryan@instructure.com>
This commit is contained in:
parent
95faa5fb36
commit
6dda1b53a6
|
@ -25,10 +25,6 @@ require [
|
|||
'compiled/behaviors/admin-links'
|
||||
'compiled/behaviors/activate'
|
||||
'compiled/behaviors/elementToggler'
|
||||
# uncomment these to turn on collection pinning and voting
|
||||
# 'compiled/behaviors/upvote-item'
|
||||
# 'compiled/behaviors/repin-item'
|
||||
# 'compiled/behaviors/follow'
|
||||
'compiled/behaviors/tooltip'
|
||||
'compiled/behaviors/instructure_inline_media_comment'
|
||||
|
||||
|
@ -54,11 +50,6 @@ require [
|
|||
helpDialog.initTriggers()
|
||||
tours.init()
|
||||
|
||||
# Make the font-based icons work in IE8,
|
||||
# it needs to be told to redraw pseudo elements on page load
|
||||
if INST.browser.ie8
|
||||
$('<style>:before,:after{content:"" !important}</style>').appendTo('head').delay(1).remove()
|
||||
|
||||
$('#skip_navigation_link').on 'click', ->
|
||||
$($(this).attr('href')).attr('tabindex', -1).focus()
|
||||
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
require ['vendor/json2']
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
<script>
|
||||
window.JSON || document.write('<%= (javascript_include_tag "#{js_base_url}/vendor/json2.js").gsub("</script>", "<\\/script>") %>');
|
||||
(''.trim && Function.prototype.bind) || document.write('<%= (javascript_include_tag "#{js_base_url}/es5_shim.js").gsub("</script>", "<\\/script>") %>');
|
||||
|
||||
INST = <%= raw(inst_env.to_json) %>;
|
||||
ENV = <%= raw Api.recursively_stringify_json_ids(js_env.clone).to_json %>;
|
||||
|
||||
|
|
|
@ -5,41 +5,35 @@
|
|||
yield :pre_html
|
||||
|
||||
-%><!DOCTYPE html>
|
||||
<!--[if IE 7 ]> <html class="ie ie7 scripts-not-loaded" lang=<%= @locale %>> <![endif]-->
|
||||
<!--[if IE 8 ]> <html class="ie ie8 scripts-not-loaded" lang=<%= @locale %>> <![endif]-->
|
||||
<!--[if gte IE 9 ]><html class="ie ie9 scripts-not-loaded" lang=<%= @locale %>> <![endif]-->
|
||||
<!--[if !(IE)]><!--> <html class="not-ie scripts-not-loaded" lang=<%= @locale %>> <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><%= yield :page_title || t('default_page_title', "Canvas LMS") %></title>
|
||||
<noscript> <h1>You need to have javascript enabled in order to access this site.</h1> </noscript>
|
||||
<!--[if lte IE 6]> <meta http-equiv=refresh content="0; URL=/ie-6-is-not-supported.html" /> <![endif]-->
|
||||
<!--[if lte IE 8]> <meta http-equiv=refresh content="0; URL=/ie-8-is-not-supported.html" /> <![endif]-->
|
||||
|
||||
<%= yield :auto_discovery %>
|
||||
<%= yield :head %>
|
||||
<%= yield :meta_tags %>
|
||||
<%= include_css_bundles %>
|
||||
<!--[if lte IE 8]> <%= javascript_include_tag "vendor/html5.js" %> <![endif]-->
|
||||
<%= yield :stylesheets %>
|
||||
<%= include_account_css %>
|
||||
<script>
|
||||
// listen for any clicks on links that have href="#" and queue them to be fired on dom ready.
|
||||
_earlyClick = function(e){
|
||||
e = e || window.event;
|
||||
function _earlyClick(e){
|
||||
var cur = e.target || e.srcElement;
|
||||
while ( cur && cur.ownerDocument ) {
|
||||
if ( cur.getAttribute('href') === '#' ) {
|
||||
e.preventDefault ? e.preventDefault() : e.returnValue = false;
|
||||
if ( cur.getAttribute('href') == '#' ) {
|
||||
e.preventDefault();
|
||||
_earlyClick.clicks = _earlyClick.clicks || [];
|
||||
_earlyClick.clicks.push(cur);
|
||||
break;
|
||||
}
|
||||
cur = cur.parentNode;
|
||||
}
|
||||
};
|
||||
document.addEventListener ?
|
||||
document.addEventListener('click', _earlyClick, false) :
|
||||
document.attachEvent('onclick', _earlyClick);
|
||||
}
|
||||
document.addEventListener('click', _earlyClick);
|
||||
</script>
|
||||
</head>
|
||||
<body class="<%= (@body_classes).uniq.join(" ") %>">
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title><%= t :title, "Facebook Page" %></title>
|
||||
<noscript> <meta http-equiv=refresh content="0; URL=/enable-javascript.html" /> </noscript>
|
||||
<!--[if lte IE 6]> <meta http-equiv=refresh content="0; URL=/ie-6-is-not-supported.html" /> <![endif]-->
|
||||
<!--[if lte IE 8]> <meta http-equiv=refresh content="0; URL=/ie-8-is-not-supported.html" /> <![endif]-->
|
||||
<%= include_common_stylesheets %>
|
||||
<%= include_stylesheets :facebook %>
|
||||
</head>
|
||||
|
@ -15,7 +15,6 @@
|
|||
</div>
|
||||
|
||||
<script>
|
||||
window.JSON || document.write('<%= (javascript_include_tag "#{js_base_url}/vendor/json2.js").gsub("</script>", "<\\/script>") %>');
|
||||
|
||||
INST = <%= raw(inst_env.to_json) %>;
|
||||
ENV = <%= raw js_env.to_json %>;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Internet Explorer 6 is not supported on this website</title>
|
||||
<title>Internet Explorer version 8 and below are not supported on this website</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Internet Explorer version 6 is so outdated it is not supported on this website.</h1>
|
||||
<h1>Internet Explorer version 8 and below are so outdated they are not supported on this website.</h1>
|
||||
<p>
|
||||
May we suggest some better, more modern browsers? <a href="http://getfirefox.com">download firefox here</a> or <a href="http://www.google.com/chrome">get Google Chrome here</a>.
|
||||
</p>
|
|
@ -1,156 +0,0 @@
|
|||
// this just grabs Function.prototype.bind and String.prototype.trim from
|
||||
// https://github.com/kriskowal/es5-shim
|
||||
|
||||
(function(){
|
||||
|
||||
var slice = Array.prototype.slice;
|
||||
|
||||
//
|
||||
// Function
|
||||
// ========
|
||||
//
|
||||
|
||||
// ES-5 15.3.4.5
|
||||
// http://es5.github.com/#x15.3.4.5
|
||||
|
||||
if (!Function.prototype.bind) {
|
||||
Function.prototype.bind = function bind(that) { // .length is 1
|
||||
// 1. Let Target be the this value.
|
||||
var target = this;
|
||||
// 2. If IsCallable(Target) is false, throw a TypeError exception.
|
||||
if (typeof target != "function") {
|
||||
throw new TypeError("Function.prototype.bind called on incompatible " + target);
|
||||
}
|
||||
// 3. Let A be a new (possibly empty) internal list of all of the
|
||||
// argument values provided after thisArg (arg1, arg2 etc), in order.
|
||||
// XXX slicedArgs will stand in for "A" if used
|
||||
var args = slice.call(arguments, 1); // for normal call
|
||||
// 4. Let F be a new native ECMAScript object.
|
||||
// 11. Set the [[Prototype]] internal property of F to the standard
|
||||
// built-in Function prototype object as specified in 15.3.3.1.
|
||||
// 12. Set the [[Call]] internal property of F as described in
|
||||
// 15.3.4.5.1.
|
||||
// 13. Set the [[Construct]] internal property of F as described in
|
||||
// 15.3.4.5.2.
|
||||
// 14. Set the [[HasInstance]] internal property of F as described in
|
||||
// 15.3.4.5.3.
|
||||
var bound = function () {
|
||||
|
||||
if (this instanceof bound) {
|
||||
// 15.3.4.5.2 [[Construct]]
|
||||
// When the [[Construct]] internal method of a function object,
|
||||
// F that was created using the bind function is called with a
|
||||
// list of arguments ExtraArgs, the following steps are taken:
|
||||
// 1. Let target be the value of F's [[TargetFunction]]
|
||||
// internal property.
|
||||
// 2. If target has no [[Construct]] internal method, a
|
||||
// TypeError exception is thrown.
|
||||
// 3. Let boundArgs be the value of F's [[BoundArgs]] internal
|
||||
// property.
|
||||
// 4. Let args be a new list containing the same values as the
|
||||
// list boundArgs in the same order followed by the same
|
||||
// values as the list ExtraArgs in the same order.
|
||||
// 5. Return the result of calling the [[Construct]] internal
|
||||
// method of target providing args as the arguments.
|
||||
|
||||
var F = function(){};
|
||||
F.prototype = target.prototype;
|
||||
var self = new F;
|
||||
|
||||
var result = target.apply(
|
||||
self,
|
||||
args.concat(slice.call(arguments))
|
||||
);
|
||||
if (Object(result) === result) {
|
||||
return result;
|
||||
}
|
||||
return self;
|
||||
|
||||
} else {
|
||||
// 15.3.4.5.1 [[Call]]
|
||||
// When the [[Call]] internal method of a function object, F,
|
||||
// which was created using the bind function is called with a
|
||||
// this value and a list of arguments ExtraArgs, the following
|
||||
// steps are taken:
|
||||
// 1. Let boundArgs be the value of F's [[BoundArgs]] internal
|
||||
// property.
|
||||
// 2. Let boundThis be the value of F's [[BoundThis]] internal
|
||||
// property.
|
||||
// 3. Let target be the value of F's [[TargetFunction]] internal
|
||||
// property.
|
||||
// 4. Let args be a new list containing the same values as the
|
||||
// list boundArgs in the same order followed by the same
|
||||
// values as the list ExtraArgs in the same order.
|
||||
// 5. Return the result of calling the [[Call]] internal method
|
||||
// of target providing boundThis as the this value and
|
||||
// providing args as the arguments.
|
||||
|
||||
// equiv: target.call(this, ...boundArgs, ...args)
|
||||
return target.apply(
|
||||
that,
|
||||
args.concat(slice.call(arguments))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
// XXX bound.length is never writable, so don't even try
|
||||
//
|
||||
// 15. If the [[Class]] internal property of Target is "Function", then
|
||||
// a. Let L be the length property of Target minus the length of A.
|
||||
// b. Set the length own property of F to either 0 or L, whichever is
|
||||
// larger.
|
||||
// 16. Else set the length own property of F to 0.
|
||||
// 17. Set the attributes of the length own property of F to the values
|
||||
// specified in 15.3.5.1.
|
||||
|
||||
// TODO
|
||||
// 18. Set the [[Extensible]] internal property of F to true.
|
||||
|
||||
// TODO
|
||||
// 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
|
||||
// 20. Call the [[DefineOwnProperty]] internal method of F with
|
||||
// arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
|
||||
// thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
|
||||
// false.
|
||||
// 21. Call the [[DefineOwnProperty]] internal method of F with
|
||||
// arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
|
||||
// [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
|
||||
// and false.
|
||||
|
||||
// TODO
|
||||
// NOTE Function objects created using Function.prototype.bind do not
|
||||
// have a prototype property or the [[Code]], [[FormalParameters]], and
|
||||
// [[Scope]] internal properties.
|
||||
// XXX can't delete prototype in pure-js.
|
||||
|
||||
// 22. Return F.
|
||||
return bound;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// String
|
||||
// ======
|
||||
//
|
||||
|
||||
// ES5 15.5.4.20
|
||||
// http://es5.github.com/#x15.5.4.20
|
||||
var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
|
||||
"\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
|
||||
"\u2029\uFEFF";
|
||||
if (!String.prototype.trim || ws.trim()) {
|
||||
// http://blog.stevenlevithan.com/archives/faster-trim-javascript
|
||||
// http://perfectionkills.com/whitespace-deviations/
|
||||
ws = "[" + ws + "]";
|
||||
var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
|
||||
trimEndRegexp = new RegExp(ws + ws + "*$");
|
||||
String.prototype.trim = function trim() {
|
||||
if (this === undefined || this === null) {
|
||||
throw new TypeError("can't convert "+this+" to object");
|
||||
}
|
||||
return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
|
||||
};
|
||||
}
|
||||
})();
|
|
@ -64,9 +64,7 @@ define([
|
|||
if (window._earlyClick) {
|
||||
|
||||
// unset the onclick handler we were using to capture the events
|
||||
document.removeEventListener ?
|
||||
document.removeEventListener('click', _earlyClick, false) :
|
||||
document.detachEvent('onclick', _earlyClick);
|
||||
document.removeEventListener('click', _earlyClick);
|
||||
|
||||
if (_earlyClick.clicks) {
|
||||
// wait to fire the "click" events till after all of the event hanlders loaded at dom ready are initialized
|
||||
|
@ -120,14 +118,6 @@ define([
|
|||
.delegate('.menu-item', 'mouseenter focusin', hoverMenuItem )
|
||||
.delegate('.menu-item', 'mouseleave focusout', unhoverMenuItem );
|
||||
|
||||
// ie7 needs some help forcing the columns to be as wide as (width_of_one_column * #_of_columns_in_this_dropdown)
|
||||
if (INST.browser.ie7) {
|
||||
$(".menu-item-drop")
|
||||
.width(function(){
|
||||
var $columns = $(this).find(".menu-item-drop-column");
|
||||
return $columns.length * $columns.css('width').replace('px', '');
|
||||
});
|
||||
}
|
||||
|
||||
// this stuff is for the ipad, it needs a little help getting the drop menus to show up
|
||||
$menu_items.live('touchstart', function(){
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
/*! HTML5 Shiv vpre3.5 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed */
|
||||
// copied from https://github.com/aFarkas/html5shiv/blob/master/src/html5shiv-printshiv.js
|
||||
(function(n,k){function t(a,c){var e=a.createElement("p"),h=a.getElementsByTagName("head")[0]||a.documentElement;e.innerHTML="x<style>"+c+"</style>";return h.insertBefore(e.lastChild,h.firstChild)}function p(){var a=l.elements;return typeof a=="string"?a.split(" "):a}function w(a){var c={},e=a.createElement,h=a.createDocumentFragment,i=h();a.createElement=function(b){l.shivMethods||e(b);var d;d=c[b]?c[b].cloneNode():x.test(b)?(c[b]=e(b)).cloneNode():e(b);return d.canHaveChildren&&!y.test(b)?i.appendChild(d):
|
||||
d};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+p().join().replace(/\w+/g,function(b){e(b);i.createElement(b);return'c("'+b+'")'})+");return n}")(l,i)}function u(a){var c;if(a.documentShived)return a;if(l.shivCSS&&!q)c=!!t(a,"article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio{display:none}canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden]{display:none}audio[controls]{display:inline-block;*display:inline;*zoom:1}mark{background:#FF0;color:#000}");
|
||||
r||(c=!w(a));if(c)a.documentShived=c;return a}function z(a){for(var c,e=a.attributes,h=e.length,i=a.ownerDocument.createElement(o+":"+a.nodeName);h--;){c=e[h];c.specified&&i.setAttribute(c.nodeName,c.nodeValue)}i.style.cssText=a.style.cssText;return i}function v(a){var c,e,h=a.namespaces,i=a.parentWindow;if(!A||a.printShived)return a;typeof h[o]=="undefined"&&h.add(o);i.attachEvent("onbeforeprint",function(){var b,d,g;g=a.styleSheets;for(var j=[],f=g.length,m=Array(f);f--;)m[f]=g[f];for(;g=m.pop();)if(!g.disabled&&
|
||||
B.test(g.media)){try{b=g.imports;d=b.length}catch(C){d=0}for(f=0;f<d;f++)m.push(b[f]);try{j.push(g.cssText)}catch(D){}}b=j.reverse().join("").split("{");d=b.length;f=RegExp("(^|[\\s,>+~])("+p().join("|")+")(?=[[\\s,>+~#.:]|$)","gi");for(m="$1"+o+"\\:$2";d--;){j=b[d]=b[d].split("}");j[j.length-1]=j[j.length-1].replace(f,m);b[d]=j.join("}")}j=b.join("{");d=a.getElementsByTagName("*");f=d.length;m=RegExp("^(?:"+p().join("|")+")$","i");for(g=[];f--;){b=d[f];m.test(b.nodeName)&&g.push(b.applyElement(z(b)))}e=
|
||||
g;c=t(a,j)});i.attachEvent("onafterprint",function(){for(var b=e,d=b.length;d--;)b[d].removeNode();c.removeNode(true)});a.printShived=true;return a}var s=n.html5||{},y=/^<|^(?:button|form|map|select|textarea|object|iframe)$/i,x=/^<|^(?:a|b|button|code|div|fieldset|form|h1|h2|h3|h4|h5|h6|i|iframe|img|input|label|li|link|ol|option|p|param|q|script|select|span|strong|style|table|tbody|td|textarea|tfoot|th|thead|tr|ul)$/i,q,r;(function(){var a=k.createElement("a");a.innerHTML="<xyz></xyz>";(q="hidden"in
|
||||
a)&&typeof injectElementWithStyles=="function"&&injectElementWithStyles("#modernizr{}",function(c){c.hidden=true;q=(n.getComputedStyle?getComputedStyle(c,null):c.currentStyle).display=="none"});r=a.childNodes.length==1||function(){try{k.createElement("a")}catch(c){return true}var e=k.createDocumentFragment();return typeof e.cloneNode=="undefined"||typeof e.createDocumentFragment=="undefined"||typeof e.createElement=="undefined"}()})();var l={elements:s.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",
|
||||
shivCSS:s.shivCSS!==false,shivMethods:s.shivMethods!==false,type:"default",shivDocument:u};n.html5=l;u(k);var B=/^$|\b(?:all|print)\b/,o="html5shiv",A=!r&&function(){var a=k.documentElement;return!(typeof k.namespaces=="undefined"||typeof k.parentWindow=="undefined"||typeof a.applyElement=="undefined"||typeof a.removeNode=="undefined"||typeof n.attachEvent=="undefined")}();l.type+=" print";l.shivPrint=v;v(k)})(this,document);
|
|
@ -1,478 +0,0 @@
|
|||
/*
|
||||
http://www.JSON.org/json2.js
|
||||
2009-04-16
|
||||
|
||||
Public Domain.
|
||||
|
||||
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||
|
||||
See http://www.JSON.org/js.html
|
||||
|
||||
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. 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' or ' '),
|
||||
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 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.
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
object. The value that is returned from your method will be
|
||||
serialized. If your method returns undefined, then the member will
|
||||
be excluded from the serialization.
|
||||
|
||||
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 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.
|
||||
|
||||
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
|
||||
the indentation will be that many spaces.
|
||||
|
||||
Example:
|
||||
|
||||
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||
// text is '["e",{"pluribus":"unum"}]'
|
||||
|
||||
|
||||
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 the structure is not modified.
|
||||
If it returns undefined then the member is deleted.
|
||||
|
||||
Example:
|
||||
|
||||
// Parse the text. Values that look like ISO date strings will
|
||||
// be converted to Date objects.
|
||||
|
||||
myData = JSON.parse(text, function (key, value) {
|
||||
var a;
|
||||
if (typeof value === 'string') {
|
||||
a =
|
||||
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||
if (a) {
|
||||
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||
+a[5], +a[6]));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
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.
|
||||
|
||||
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 evil: true */
|
||||
|
||||
/*global JSON */
|
||||
|
||||
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
|
||||
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
||||
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
||||
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
||||
test, toJSON, toString, valueOf
|
||||
*/
|
||||
|
||||
// Create a JSON object only if one does not already exist. We create the
|
||||
// methods in a closure to avoid creating global variables.
|
||||
|
||||
if (!this.JSON) {
|
||||
JSON = {};
|
||||
}
|
||||
(function () {
|
||||
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
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 = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
},
|
||||
rep;
|
||||
|
||||
|
||||
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.
|
||||
|
||||
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) {
|
||||
|
||||
// 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];
|
||||
|
||||
// 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 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);
|
||||
}
|
||||
|
||||
// What happens next depends on the value's type.
|
||||
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
return quote(value);
|
||||
|
||||
case 'number':
|
||||
|
||||
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||
|
||||
return isFinite(value) ? String(value) : '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);
|
||||
|
||||
// If the type is 'object', we might be dealing with an object or an array or
|
||||
// null.
|
||||
|
||||
case 'object':
|
||||
|
||||
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||
// so watch out for that case.
|
||||
|
||||
if (!value) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// Make an array to hold the partial results of stringifying this object value.
|
||||
|
||||
gap += indent;
|
||||
partial = [];
|
||||
|
||||
// Is the value an array?
|
||||
|
||||
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||
|
||||
// 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';
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// If the replacer is an array, use it to select the members to be stringified.
|
||||
|
||||
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 {
|
||||
|
||||
// Otherwise, iterate through all of the keys in the object.
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// If the JSON object does not yet have a stringify method, give it one.
|
||||
|
||||
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
|
||||
// that can replace values, or an array of strings that will select the keys.
|
||||
// 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 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 there is a replacer, it must be a function or an array.
|
||||
// Otherwise, throw an error.
|
||||
|
||||
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});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return reviver.call(holder, key, value);
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
});
|
||||
}
|
||||
|
||||
// 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 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(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
|
||||
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
|
||||
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||
|
||||
// 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 + ')');
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||
|
||||
throw new SyntaxError('JSON.parse');
|
||||
};
|
||||
}
|
||||
}());
|
Loading…
Reference in New Issue