blob: 2d702501e71fa6e9cef3d621230b99e9f12d10df [file] [log] [blame]
/*
* Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
JSON.LoadError = "JSONLoadError";
JSON.ParseError = "JSONParseError";
// JSON.load() may be called using the following forms:
//
// JSON.load("http://www.apple.com", function() {/* success */})
// OR
// JSON.load("http://www.apple.com", function() {/* success */}, {withCredentials: true, ...})
// OR
// JSON.load("http://www.apple.com", function() {/* success */}, function() {/* failure */})
// OR
// JSON.load("http://www.apple.com", function() {/* success */}, function() {/* failure */}, {withCredentials: true, ...})
JSON.load = function(url, successCallback, failureCallback, options)
{
console.assert(url);
if (!(successCallback instanceof Function))
return;
if (failureCallback && typeof failureCallback === "object")
options = failureCallback;
if (!(failureCallback instanceof Function))
failureCallback = function() { };
if (typeof options !== "object")
options = {};
var request = new XMLHttpRequest;
request.onreadystatechange = function() {
if (this.readyState !== 4)
return;
// Don't consider a status of 0 to be a load error for easier testing with local files.
var loadErrorOccurred = this.status !== 0 && this.status !== 200;
if (loadErrorOccurred) {
failureCallback({errorType: JSON.LoadError, error: this.statusText, errorHTTPCode: this.status});
return;
}
try {
var responseText = request.responseText;
if (options.hasOwnProperty("jsonpCallbackName"))
responseText = responseText.replace(new RegExp("^" + options.jsonpCallbackName + "\\((.*)\\);?$"), "$1");
var data = JSON.parse(responseText);
} catch (e) {
var data = {errorType: JSON.ParseError, error: e.message};
failureCallback(data);
return;
}
successCallback(data);
};
request.open("GET", url);
if (options.hasOwnProperty("withCredentials"))
request.withCredentials = options.withCredentials;
request.send();
};
function loadXML(url, callback, options) {
console.assert(url);
if (!(callback instanceof Function))
return;
var request = new XMLHttpRequest;
request.onreadystatechange = function() {
if (this.readyState !== 4)
return;
// Allow a status of 0 for easier testing with local files.
if (!this.status || this.status === 200)
callback(request.responseXML);
};
request.open("GET", url);
if ((typeof options === "object") && options.hasOwnProperty("withCredentials"))
request.withCredentials = options.withCredentials;
request.send();
};
Node.prototype.isAncestor = function(node)
{
if (!node)
return false;
var currentNode = node.parentNode;
while (currentNode) {
if (this === currentNode)
return true;
currentNode = currentNode.parentNode;
}
return false;
}
Node.prototype.isDescendant = function(descendant)
{
return !!descendant && descendant.isAncestor(this);
}
Node.prototype.isSelfOrAncestor = function(node)
{
return !!node && (node === this || this.isAncestor(node));
}
Node.prototype.isSelfOrDescendant = function(node)
{
return !!node && (node === this || this.isDescendant(node));
}
Element.prototype.removeChildren = function()
{
// This has been tested to be the fastest removal method.
if (this.firstChild)
this.textContent = "";
};
DOMTokenList.prototype.contains = function(string)
{
for (var i = 0, end = this.length; i < end; ++i) {
if (this.item(i) === string)
return true;
}
return false;
}
Array.prototype.contains = function(value)
{
return this.indexOf(value) >= 0;
};
Array.prototype.findFirst = function(predicate)
{
for (var i = 0; i < this.length; ++i) {
if (predicate(this[i]))
return this[i];
}
return null;
};
Array.prototype.average = function()
{
var sum = 0;
var count = this.length;
for (var i = 0; i < count; ++i)
sum += this[i];
return sum / count;
};
Array.prototype.median = function()
{
var array = this.slice(); // Make a copy to avoid modifying the object.
array.sort(function(a, b) { return a - b; });
var half = Math.floor(array.length / 2);
if (array.length % 2)
return array[half];
else
return (array[half - 1] + array[half]) / 2;
};
String.prototype.contains = function(substring)
{
return this.indexOf(substring) >= 0;
};
String.prototype.startsWith = function(substring)
{
return this.lastIndexOf(substring, 0) === 0;
};
function sortDictionariesByOrder(unsorted)
{
var sorted = [];
for (var key in unsorted)
sorted.push(unsorted[key]);
sorted.sort(function(a, b) {
return a.order - b.order;
});
return sorted;
};