mirror of
https://github.com/jcreek/Assassins-Mission-Control.git
synced 2026-07-13 02:53:44 +00:00
0a7943162d
This version works and has been tested in a full game with over 50 players however there isn’t as yet a proper admin backend and many activities require the admin to fiddle with html or SQL at the moment.
1475 lines
47 KiB
JavaScript
1475 lines
47 KiB
JavaScript
/**
|
|
* A Twitter library in JavaScript
|
|
*
|
|
* @package codebird
|
|
* @version 2.5.0-alpha.1.1
|
|
* @author Jublo IT Solutions <support@jublo.net>
|
|
* @copyright 2010-2014 Jublo IT Solutions <support@jublo.net>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/* jshint curly: true,
|
|
eqeqeq: true,
|
|
latedef: true,
|
|
quotmark: double,
|
|
undef: true,
|
|
unused: true,
|
|
trailing: true,
|
|
laxbreak: true */
|
|
/* global window,
|
|
document,
|
|
navigator,
|
|
console,
|
|
ActiveXObject,
|
|
module,
|
|
define,
|
|
require */
|
|
"use strict";
|
|
|
|
/**
|
|
* Array.indexOf polyfill
|
|
*/
|
|
if (! Array.prototype.indexOf) {
|
|
Array.prototype.indexOf = function (obj, start) {
|
|
for (var i = (start || 0); i < this.length; i++) {
|
|
if (this[i] === obj) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
};
|
|
}
|
|
|
|
(function (undefined) {
|
|
/**
|
|
* A Twitter library in JavaScript
|
|
*
|
|
* @package codebird
|
|
* @subpackage codebird-js
|
|
*/
|
|
/* jshint -W098 */
|
|
var Codebird = function () {
|
|
/* jshint +W098 */
|
|
|
|
/**
|
|
* The OAuth consumer key of your registered app
|
|
*/
|
|
var _oauth_consumer_key = null;
|
|
|
|
/**
|
|
* The corresponding consumer secret
|
|
*/
|
|
var _oauth_consumer_secret = null;
|
|
|
|
/**
|
|
* The app-only bearer token. Used to authorize app-only requests
|
|
*/
|
|
var _oauth_bearer_token = null;
|
|
|
|
/**
|
|
* The API endpoint base to use
|
|
*/
|
|
var _endpoint_base = "https://api.twitter.com/";
|
|
|
|
/**
|
|
* The API endpoint to use
|
|
*/
|
|
var _endpoint = _endpoint_base + "1.1/";
|
|
|
|
/**
|
|
* The API endpoint base to use
|
|
*/
|
|
var _endpoint_oauth = _endpoint_base;
|
|
|
|
/**
|
|
* API proxy endpoint
|
|
*/
|
|
var _endpoint_proxy = "https://api.jublo.net/codebird/";
|
|
|
|
/**
|
|
* The API endpoint to use for old requests
|
|
*/
|
|
var _endpoint_old = _endpoint_base + "1/";
|
|
|
|
/**
|
|
* Use JSONP for GET requests in IE7-9
|
|
*/
|
|
var _use_jsonp = (typeof navigator !== "undefined"
|
|
&& typeof navigator.userAgent !== "undefined"
|
|
&& (navigator.userAgent.indexOf("Trident/4") > -1
|
|
|| navigator.userAgent.indexOf("Trident/5") > -1
|
|
|| navigator.userAgent.indexOf("MSIE 7.0") > -1
|
|
)
|
|
);
|
|
|
|
/**
|
|
* Whether to access the API via a proxy that is allowed by CORS
|
|
* Assume that CORS is only necessary in browsers
|
|
*/
|
|
var _use_proxy = (typeof navigator !== "undefined"
|
|
&& typeof navigator.userAgent !== "undefined"
|
|
);
|
|
|
|
/**
|
|
* The Request or access token. Used to sign requests
|
|
*/
|
|
var _oauth_token = null;
|
|
|
|
/**
|
|
* The corresponding request or access token secret
|
|
*/
|
|
var _oauth_token_secret = null;
|
|
|
|
/**
|
|
* The current Codebird version
|
|
*/
|
|
var _version = "2.5.0-alpha.1.1";
|
|
|
|
/**
|
|
* Sets the OAuth consumer key and secret (App key)
|
|
*
|
|
* @param string key OAuth consumer key
|
|
* @param string secret OAuth consumer secret
|
|
*
|
|
* @return void
|
|
*/
|
|
var setConsumerKey = function (key, secret) {
|
|
_oauth_consumer_key = key;
|
|
_oauth_consumer_secret = secret;
|
|
};
|
|
|
|
/**
|
|
* Sets the OAuth2 app-only auth bearer token
|
|
*
|
|
* @param string token OAuth2 bearer token
|
|
*
|
|
* @return void
|
|
*/
|
|
var setBearerToken = function (token) {
|
|
_oauth_bearer_token = token;
|
|
};
|
|
|
|
/**
|
|
* Gets the current Codebird version
|
|
*
|
|
* @return string The version number
|
|
*/
|
|
var getVersion = function () {
|
|
return _version;
|
|
};
|
|
|
|
/**
|
|
* Sets the OAuth request or access token and secret (User key)
|
|
*
|
|
* @param string token OAuth request or access token
|
|
* @param string secret OAuth request or access token secret
|
|
*
|
|
* @return void
|
|
*/
|
|
var setToken = function (token, secret) {
|
|
_oauth_token = token;
|
|
_oauth_token_secret = secret;
|
|
};
|
|
|
|
/**
|
|
* Enables or disables CORS proxy
|
|
*
|
|
* @param bool use_proxy Whether to use CORS proxy or not
|
|
*
|
|
* @return void
|
|
*/
|
|
var setUseProxy = function (use_proxy) {
|
|
_use_proxy = !! use_proxy;
|
|
};
|
|
|
|
/**
|
|
* Sets custom CORS proxy server
|
|
*
|
|
* @param string proxy Address of proxy server to use
|
|
*
|
|
* @return void
|
|
*/
|
|
var setProxy = function (proxy) {
|
|
// add trailing slash if missing
|
|
if (! proxy.match(/\/$/)) {
|
|
proxy += "/";
|
|
}
|
|
_endpoint_proxy = proxy;
|
|
};
|
|
|
|
/**
|
|
* Parse URL-style parameters into object
|
|
*
|
|
* version: 1109.2015
|
|
* discuss at: http://phpjs.org/functions/parse_str
|
|
* + original by: Cagri Ekin
|
|
* + improved by: Michael White (http://getsprink.com)
|
|
* + tweaked by: Jack
|
|
* + bugfixed by: Onno Marsman
|
|
* + reimplemented by: stag019
|
|
* + bugfixed by: Brett Zamir (http://brett-zamir.me)
|
|
* + bugfixed by: stag019
|
|
* - depends on: urldecode
|
|
* + input by: Dreamer
|
|
* + bugfixed by: Brett Zamir (http://brett-zamir.me)
|
|
* % note 1: When no argument is specified, will put variables in global scope.
|
|
*
|
|
* @param string str String to parse
|
|
* @param array array to load data into
|
|
*
|
|
* @return object
|
|
*/
|
|
var _parse_str = function (str, array) {
|
|
var glue1 = "=",
|
|
glue2 = "&",
|
|
array2 = String(str).replace(/^&?([\s\S]*?)&?$/, "$1").split(glue2),
|
|
i, j, chr, tmp, key, value, bracket, keys, evalStr,
|
|
fixStr = function (str) {
|
|
return decodeURIComponent(str).replace(/([\\"'])/g, "\\$1").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
};
|
|
if (! array) {
|
|
array = this.window;
|
|
}
|
|
|
|
for (i = 0; i < array2.length; i++) {
|
|
tmp = array2[i].split(glue1);
|
|
if (tmp.length < 2) {
|
|
tmp = [tmp, ""];
|
|
}
|
|
key = fixStr(tmp[0]);
|
|
value = fixStr(tmp[1]);
|
|
while (key.charAt(0) === " ") {
|
|
key = key.substr(1);
|
|
}
|
|
if (key.indexOf("\0") !== -1) {
|
|
key = key.substr(0, key.indexOf("\0"));
|
|
}
|
|
if (key && key.charAt(0) !== "[") {
|
|
keys = [];
|
|
bracket = 0;
|
|
for (j = 0; j < key.length; j++) {
|
|
if (key.charAt(j) === "[" && !bracket) {
|
|
bracket = j + 1;
|
|
} else if (key.charAt(j) === "]") {
|
|
if (bracket) {
|
|
if (!keys.length) {
|
|
keys.push(key.substr(0, bracket - 1));
|
|
}
|
|
keys.push(key.substr(bracket, j - bracket));
|
|
bracket = 0;
|
|
if (key.charAt(j + 1) !== "[") {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!keys.length) {
|
|
keys = [key];
|
|
}
|
|
for (j = 0; j < keys[0].length; j++) {
|
|
chr = keys[0].charAt(j);
|
|
if (chr === " " || chr === "." || chr === "[") {
|
|
keys[0] = keys[0].substr(0, j) + "_" + keys[0].substr(j + 1);
|
|
}
|
|
if (chr === "[") {
|
|
break;
|
|
}
|
|
}
|
|
/* jshint -W061 */
|
|
evalStr = "array";
|
|
for (j = 0; j < keys.length; j++) {
|
|
key = keys[j];
|
|
if ((key !== "" && key !== " ") || j === 0) {
|
|
key = "'" + key + "'";
|
|
} else {
|
|
key = eval(evalStr + ".push([]);") - 1;
|
|
}
|
|
evalStr += "[" + key + "]";
|
|
if (j !== keys.length - 1 && eval("typeof " + evalStr) === "undefined") {
|
|
eval(evalStr + " = [];");
|
|
}
|
|
}
|
|
evalStr += " = '" + value + "';\n";
|
|
eval(evalStr);
|
|
/* jshint +W061 */
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Main API handler working on any requests you issue
|
|
*
|
|
* @param string fn The member function you called
|
|
* @param array params The parameters you sent along
|
|
* @param function callback The callback to call with the reply
|
|
* @param bool app_only_auth Whether to use app-only auth
|
|
*
|
|
* @return mixed The API reply encoded in the set return_format
|
|
*/
|
|
|
|
var __call = function (fn, params, callback, app_only_auth) {
|
|
if (typeof params === "undefined") {
|
|
params = {};
|
|
}
|
|
if (typeof app_only_auth === "undefined") {
|
|
app_only_auth = false;
|
|
}
|
|
if (typeof callback !== "function" && typeof params === "function") {
|
|
callback = params;
|
|
params = {};
|
|
if (typeof callback === "boolean") {
|
|
app_only_auth = callback;
|
|
}
|
|
} else if (typeof callback === "undefined") {
|
|
callback = function () {};
|
|
}
|
|
switch (fn) {
|
|
case "oauth_authenticate":
|
|
case "oauth_authorize":
|
|
return this[fn](params, callback);
|
|
|
|
case "oauth2_token":
|
|
return this[fn](callback);
|
|
}
|
|
// reset token when requesting a new token (causes 401 for signature error on 2nd+ requests)
|
|
if (fn === "oauth_requestToken") {
|
|
setToken(null, null);
|
|
}
|
|
// parse parameters
|
|
var apiparams = {};
|
|
if (typeof params === "object") {
|
|
apiparams = params;
|
|
} else {
|
|
_parse_str(params, apiparams); //TODO
|
|
}
|
|
|
|
// map function name to API method
|
|
var method = "";
|
|
var param, i, j;
|
|
|
|
// replace _ by /
|
|
var path = fn.split("_");
|
|
for (i = 0; i < path.length; i++) {
|
|
if (i > 0) {
|
|
method += "/";
|
|
}
|
|
method += path[i];
|
|
}
|
|
|
|
// undo replacement for URL parameters
|
|
var url_parameters_with_underscore = ["screen_name", "place_id"];
|
|
for (i = 0; i < url_parameters_with_underscore.length; i++) {
|
|
param = url_parameters_with_underscore[i].toUpperCase();
|
|
var replacement_was = param.split("_").join("/");
|
|
method = method.split(replacement_was).join(param);
|
|
}
|
|
|
|
// replace AA by URL parameters
|
|
var method_template = method;
|
|
var match = method.match(/[A-Z_]{2,}/);
|
|
if (match) {
|
|
for (i = 0; i < match.length; i++) {
|
|
param = match[i];
|
|
var param_l = param.toLowerCase();
|
|
method_template = method_template.split(param).join(":" + param_l);
|
|
if (typeof apiparams[param_l] === "undefined") {
|
|
for (j = 0; j < 26; j++) {
|
|
method_template = method_template.split(String.fromCharCode(65 + j)).join("_" + String.fromCharCode(97 + j));
|
|
}
|
|
console.warn("To call the templated method \"" + method_template + "\", specify the parameter value for \"" + param_l + "\".");
|
|
}
|
|
method = method.split(param).join(apiparams[param_l]);
|
|
delete apiparams[param_l];
|
|
}
|
|
}
|
|
|
|
// replace A-Z by _a-z
|
|
for (i = 0; i < 26; i++) {
|
|
method = method.split(String.fromCharCode(65 + i)).join("_" + String.fromCharCode(97 + i));
|
|
method_template = method_template.split(String.fromCharCode(65 + i)).join("_" + String.fromCharCode(97 + i));
|
|
}
|
|
|
|
var httpmethod = _detectMethod(method_template, apiparams);
|
|
var multipart = _detectMultipart(method_template);
|
|
var internal = _detectInternal(method_template);
|
|
|
|
return _callApi(
|
|
httpmethod,
|
|
method,
|
|
method_template,
|
|
apiparams,
|
|
multipart,
|
|
app_only_auth,
|
|
internal,
|
|
callback
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Gets the OAuth authenticate URL for the current request token
|
|
*
|
|
* @return string The OAuth authenticate URL
|
|
*/
|
|
var oauth_authenticate = function (params, callback) {
|
|
if (typeof params.force_login === "undefined") {
|
|
params.force_login = null;
|
|
}
|
|
if (typeof params.screen_name === "undefined") {
|
|
params.screen_name = null;
|
|
}
|
|
if (_oauth_token === null) {
|
|
console.warn("To get the authenticate URL, the OAuth token must be set.");
|
|
}
|
|
var url = _endpoint_oauth + "oauth/authenticate?oauth_token=" + _url(_oauth_token);
|
|
if (params.force_login === true) {
|
|
url += "?force_login=1";
|
|
if (params.screen_name !== null) {
|
|
url += "&screen_name=" + params.screen_name;
|
|
}
|
|
}
|
|
callback(url);
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Gets the OAuth authorize URL for the current request token
|
|
*
|
|
* @return string The OAuth authorize URL
|
|
*/
|
|
var oauth_authorize = function (params, callback) {
|
|
if (typeof params.force_login === "undefined") {
|
|
params.force_login = null;
|
|
}
|
|
if (typeof params.screen_name === "undefined") {
|
|
params.screen_name = null;
|
|
}
|
|
if (_oauth_token === null) {
|
|
console.warn("To get the authorize URL, the OAuth token must be set.");
|
|
}
|
|
var url = _endpoint_oauth + "oauth/authorize?oauth_token=" + _url(_oauth_token);
|
|
if (params.force_login === true) {
|
|
url += "?force_login=1";
|
|
if (params.screen_name !== null) {
|
|
url += "&screen_name=" + params.screen_name;
|
|
}
|
|
}
|
|
callback(url);
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Gets the OAuth bearer token
|
|
*
|
|
* @return string The OAuth bearer token
|
|
*/
|
|
|
|
var oauth2_token = function (callback) {
|
|
if (_oauth_consumer_key === null) {
|
|
console.warn("To obtain a bearer token, the consumer key must be set.");
|
|
}
|
|
|
|
if (typeof callback === "undefined") {
|
|
callback = function () {};
|
|
}
|
|
|
|
var post_fields = "grant_type=client_credentials";
|
|
var url = _endpoint_oauth + "oauth2/token";
|
|
|
|
if (_use_proxy) {
|
|
url = url.replace(
|
|
_endpoint_base,
|
|
_endpoint_proxy
|
|
);
|
|
}
|
|
|
|
var xml = _getXmlRequestObject();
|
|
if (xml === null) {
|
|
return;
|
|
}
|
|
xml.open("POST", url, true);
|
|
xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
xml.setRequestHeader(
|
|
(_use_proxy ? "X-" : "") + "Authorization",
|
|
"Basic " + _base64_encode(_oauth_consumer_key + ":" + _oauth_consumer_secret)
|
|
);
|
|
|
|
xml.onreadystatechange = function () {
|
|
if (xml.readyState >= 4) {
|
|
var httpstatus = 12027;
|
|
try {
|
|
httpstatus = xml.status;
|
|
} catch (e) {}
|
|
var reply = _parseApiReply("oauth2/token", xml.responseText);
|
|
reply.httpstatus = httpstatus;
|
|
if (httpstatus === 200) {
|
|
setBearerToken(reply.access_token);
|
|
}
|
|
callback(reply);
|
|
}
|
|
};
|
|
xml.send(post_fields);
|
|
|
|
};
|
|
|
|
/**
|
|
* Signing helpers
|
|
*/
|
|
|
|
/**
|
|
* URL-encodes the given data
|
|
*
|
|
* @param mixed data
|
|
*
|
|
* @return mixed The encoded data
|
|
*/
|
|
var _url = function (data) {
|
|
if ((/boolean|number|string/).test(typeof data)) {
|
|
return encodeURIComponent(data).replace(/!/g, "%21").replace(/'/g, "%27").replace(/\(/g, "%28").replace(/\)/g, "%29").replace(/\*/g, "%2A");
|
|
} else {
|
|
return "";
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Gets the base64-encoded SHA1 hash for the given data
|
|
*
|
|
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
|
|
* in FIPS PUB 180-1
|
|
* Based on version 2.1 Copyright Paul Johnston 2000 - 2002.
|
|
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
|
* Distributed under the BSD License
|
|
* See http://pajhome.org.uk/crypt/md5 for details.
|
|
*
|
|
* @param string data The data to calculate the hash from
|
|
*
|
|
* @return string The hash
|
|
*/
|
|
var _sha1 = function () {
|
|
function n(e, b) {
|
|
e[b >> 5] |= 128 << 24 - b % 32;
|
|
e[(b + 64 >> 9 << 4) + 15] = b;
|
|
for (var c = new Array(80), a = 1732584193, d = -271733879, h = -1732584194,
|
|
k = 271733878, g = -1009589776, p = 0; p < e.length; p += 16) {
|
|
for (var o = a, q = d, r = h, s = k, t = g, f = 0; 80 > f; f++) {
|
|
var m;
|
|
|
|
if (f < 16) {
|
|
m = e[p + f];
|
|
} else {
|
|
m = c[f - 3] ^ c[f - 8] ^ c[f - 14] ^ c[f - 16];
|
|
m = m << 1 | m >>> 31;
|
|
}
|
|
|
|
c[f] = m;
|
|
m = l(l(a << 5 | a >>> 27, 20 > f ? d & h | ~d & k : 40 > f ? d ^
|
|
h ^ k : 60 > f ? d & h | d & k | h & k : d ^ h ^ k), l(
|
|
l(g, c[f]), 20 > f ? 1518500249 : 40 > f ? 1859775393 :
|
|
60 > f ? -1894007588 : -899497514));
|
|
g = k;
|
|
k = h;
|
|
h = d << 30 | d >>> 2;
|
|
d = a;
|
|
a = m;
|
|
}
|
|
a = l(a, o);
|
|
d = l(d, q);
|
|
h = l(h, r);
|
|
k = l(k, s);
|
|
g = l(g, t);
|
|
}
|
|
return [a, d, h, k, g];
|
|
}
|
|
|
|
function l(e, b) {
|
|
var c = (e & 65535) + (b & 65535);
|
|
return (e >> 16) + (b >> 16) + (c >> 16) << 16 | c & 65535;
|
|
}
|
|
|
|
function q(e) {
|
|
for (var b = [], c = (1 << g) - 1, a = 0; a < e.length * g; a += g) {
|
|
b[a >> 5] |= (e.charCodeAt(a / g) & c) << 24 - a % 32;
|
|
}
|
|
return b;
|
|
}
|
|
var g = 8;
|
|
return function (e) {
|
|
var b = _oauth_consumer_secret + "&" + (null !== _oauth_token_secret ?
|
|
_oauth_token_secret : "");
|
|
if (_oauth_consumer_secret === null) {
|
|
console.warn("To generate a hash, the consumer secret must be set.");
|
|
}
|
|
var c = q(b);
|
|
if (c.length > 16) {
|
|
c = n(c, b.length * g);
|
|
}
|
|
b = new Array(16);
|
|
for (var a = new Array(16), d = 0; d < 16; d++) {
|
|
a[d] = c[d] ^ 909522486;
|
|
b[d] = c[d] ^ 1549556828;
|
|
}
|
|
c = n(a.concat(q(e)), 512 + e.length * g);
|
|
b = n(b.concat(c), 672);
|
|
c = "";
|
|
for (a = 0; a < 4 * b.length; a += 3) {
|
|
for (d = (b[a >> 2] >> 8 * (3 - a % 4) & 255) << 16 | (b[a + 1 >> 2] >>
|
|
8 * (3 - (a + 1) % 4) & 255) << 8 | b[a + 2 >> 2] >> 8 * (3 -
|
|
(a + 2) % 4) & 255, e = 0; 4 > e; e++) {
|
|
c = 8 * a + 6 * e > 32 * b.length ? c + "=" : c +
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
.charAt(d >> 6 * (3 - e) & 63);
|
|
}
|
|
}
|
|
return c;
|
|
};
|
|
}();
|
|
|
|
/*
|
|
* Gets the base64 representation for the given data
|
|
*
|
|
* http://phpjs.org
|
|
* + original by: Tyler Akins (http://rumkin.com)
|
|
* + improved by: Bayron Guevara
|
|
* + improved by: Thunder.m
|
|
* + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
|
* + bugfixed by: Pellentesque Malesuada
|
|
* + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
|
* + improved by: Rafał Kukawski (http://kukawski.pl)
|
|
*
|
|
* @param string data The data to calculate the base64 representation from
|
|
*
|
|
* @return string The base64 representation
|
|
*/
|
|
var _base64_encode = function (a) {
|
|
var d, e, f, b, g = 0,
|
|
h = 0,
|
|
i = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
|
|
c = [];
|
|
if (!a) {
|
|
return a;
|
|
}
|
|
do {
|
|
d = a.charCodeAt(g++);
|
|
e = a.charCodeAt(g++);
|
|
f = a.charCodeAt(g++);
|
|
b = d << 16 | e << 8 | f;
|
|
d = b >> 18 & 63;
|
|
e = b >> 12 & 63;
|
|
f = b >> 6 & 63;
|
|
b &= 63;
|
|
c[h++] = i.charAt(d) + i.charAt(e) + i.charAt(f) + i.charAt(b);
|
|
} while (g < a.length);
|
|
c = c.join("");
|
|
a = a.length % 3;
|
|
return (a ? c.slice(0, a - 3) : c) + "===".slice(a || 3);
|
|
};
|
|
|
|
/*
|
|
* Builds a HTTP query string from the given data
|
|
*
|
|
* http://phpjs.org
|
|
* + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
|
* + improved by: Legaev Andrey
|
|
* + improved by: Michael White (http://getsprink.com)
|
|
* + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
|
|
* + improved by: Brett Zamir (http://brett-zamir.me)
|
|
* + revised by: stag019
|
|
* + input by: Dreamer
|
|
* + bugfixed by: Brett Zamir (http://brett-zamir.me)
|
|
* + bugfixed by: MIO_KODUKI (http://mio-koduki.blogspot.com/)
|
|
*
|
|
* @param string data The data to concatenate
|
|
*
|
|
* @return string The HTTP query
|
|
*/
|
|
var _http_build_query = function (e, f, b) {
|
|
function g(c, a, d) {
|
|
var b, e = [];
|
|
if (a === true) {
|
|
a = "1";
|
|
} else if (a === false) {
|
|
a = "0";
|
|
}
|
|
if (null !== a) {
|
|
if (typeof a === "object") {
|
|
for (b in a) {
|
|
if (a[b] !== null) {
|
|
e.push(g(c + "[" + b + "]", a[b], d));
|
|
}
|
|
}
|
|
return e.join(d);
|
|
}
|
|
if (typeof a !== "function") {
|
|
return _url(c) + "=" + _url(a);
|
|
}
|
|
console.warn("There was an error processing for http_build_query().");
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
var d, c, h = [];
|
|
if (! b) {
|
|
b = "&";
|
|
}
|
|
for (c in e) {
|
|
d = e[c];
|
|
if (f && ! isNaN(c)) {
|
|
c = String(f) + c;
|
|
}
|
|
d = g(c, d, b);
|
|
if (d !== "") {
|
|
h.push(d);
|
|
}
|
|
}
|
|
return h.join(b);
|
|
};
|
|
|
|
/**
|
|
* Generates a (hopefully) unique random string
|
|
*
|
|
* @param int optional length The length of the string to generate
|
|
*
|
|
* @return string The random string
|
|
*/
|
|
var _nonce = function (length) {
|
|
if (typeof length === "undefined") {
|
|
length = 8;
|
|
}
|
|
if (length < 1) {
|
|
console.warn("Invalid nonce length.");
|
|
}
|
|
var nonce = "";
|
|
for (var i = 0; i < length; i++) {
|
|
var character = Math.floor(Math.random() * 61);
|
|
nonce += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz".substring(character, character + 1);
|
|
}
|
|
return nonce;
|
|
};
|
|
|
|
/**
|
|
* Sort array elements by key
|
|
*
|
|
* @param array input_arr The array to sort
|
|
*
|
|
* @return array The sorted keys
|
|
*/
|
|
var _ksort = function (input_arr) {
|
|
var keys = [], sorter, k;
|
|
|
|
sorter = function (a, b) {
|
|
var a_float = parseFloat(a),
|
|
b_float = parseFloat(b),
|
|
a_numeric = a_float + "" === a,
|
|
b_numeric = b_float + "" === b;
|
|
if (a_numeric && b_numeric) {
|
|
return a_float > b_float ? 1 : a_float < b_float ? -1 : 0;
|
|
} else if (a_numeric && !b_numeric) {
|
|
return 1;
|
|
} else if (!a_numeric && b_numeric) {
|
|
return -1;
|
|
}
|
|
return a > b ? 1 : a < b ? -1 : 0;
|
|
};
|
|
|
|
// Make a list of key names
|
|
for (k in input_arr) {
|
|
if (input_arr.hasOwnProperty(k)) {
|
|
keys.push(k);
|
|
}
|
|
}
|
|
keys.sort(sorter);
|
|
return keys;
|
|
};
|
|
|
|
/**
|
|
* Clone objects
|
|
*
|
|
* @param object obj The object to clone
|
|
*
|
|
* @return object clone The cloned object
|
|
*/
|
|
var _clone = function (obj) {
|
|
var clone = {};
|
|
for (var i in obj) {
|
|
if (typeof(obj[i]) === "object") {
|
|
clone[i] = clone(obj[i]);
|
|
} else {
|
|
clone[i] = obj[i];
|
|
}
|
|
}
|
|
return clone;
|
|
};
|
|
|
|
/**
|
|
* Generates an OAuth signature
|
|
*
|
|
* @param string httpmethod Usually either 'GET' or 'POST' or 'DELETE'
|
|
* @param string method The API method to call
|
|
* @param array optional params The API call parameters, associative
|
|
* @param bool optional append_to_get Whether to append the OAuth params to GET
|
|
*
|
|
* @return string Authorization HTTP header
|
|
*/
|
|
var _sign = function (httpmethod, method, params, append_to_get) {
|
|
if (typeof params === "undefined") {
|
|
params = {};
|
|
}
|
|
if (typeof append_to_get === "undefined") {
|
|
append_to_get = false;
|
|
}
|
|
if (_oauth_consumer_key === null) {
|
|
console.warn("To generate a signature, the consumer key must be set.");
|
|
}
|
|
var sign_params = {
|
|
consumer_key: _oauth_consumer_key,
|
|
version: "1.0",
|
|
timestamp: Math.round(new Date().getTime() / 1000),
|
|
nonce: _nonce(),
|
|
signature_method: "HMAC-SHA1"
|
|
};
|
|
var sign_base_params = {};
|
|
var value;
|
|
for (var key in sign_params) {
|
|
value = sign_params[key];
|
|
sign_base_params["oauth_" + key] = _url(value);
|
|
}
|
|
if (_oauth_token !== null) {
|
|
sign_base_params.oauth_token = _url(_oauth_token);
|
|
}
|
|
var oauth_params = _clone(sign_base_params);
|
|
for (key in params) {
|
|
value = params[key];
|
|
sign_base_params[key] = value;
|
|
}
|
|
var keys = _ksort(sign_base_params);
|
|
var sign_base_string = "";
|
|
for (var i = 0; i < keys.length; i++) {
|
|
key = keys[i];
|
|
value = sign_base_params[key];
|
|
sign_base_string += key + "=" + _url(value) + "&";
|
|
}
|
|
sign_base_string = sign_base_string.substring(0, sign_base_string.length - 1);
|
|
var signature = _sha1(httpmethod + "&" + _url(method) + "&" + _url(sign_base_string));
|
|
|
|
params = append_to_get ? sign_base_params : oauth_params;
|
|
params.oauth_signature = signature;
|
|
keys = _ksort(params);
|
|
var authorization = "";
|
|
if (append_to_get) {
|
|
for(i = 0; i < keys.length; i++) {
|
|
key = keys[i];
|
|
value = params[key];
|
|
authorization += key + "=" + _url(value) + "&";
|
|
}
|
|
return authorization.substring(0, authorization.length - 1);
|
|
}
|
|
authorization = "OAuth ";
|
|
for (i = 0; i < keys.length; i++) {
|
|
key = keys[i];
|
|
value = params[key];
|
|
authorization += key + "=\"" + _url(value) + "\", ";
|
|
}
|
|
return authorization.substring(0, authorization.length - 2);
|
|
};
|
|
|
|
/**
|
|
* Detects HTTP method to use for API call
|
|
*
|
|
* @param string method The API method to call
|
|
* @param array params The parameters to send along
|
|
*
|
|
* @return string The HTTP method that should be used
|
|
*/
|
|
var _detectMethod = function (method, params) {
|
|
// multi-HTTP method endpoints
|
|
switch(method) {
|
|
case "account/settings":
|
|
case "account/login_verification_enrollment":
|
|
case "account/login_verification_request":
|
|
method = params.length ? method + "__post" : method;
|
|
break;
|
|
}
|
|
|
|
var httpmethods = {};
|
|
httpmethods.GET = [
|
|
// Timelines
|
|
"statuses/mentions_timeline",
|
|
"statuses/user_timeline",
|
|
"statuses/home_timeline",
|
|
"statuses/retweets_of_me",
|
|
|
|
// Tweets
|
|
"statuses/retweets/:id",
|
|
"statuses/show/:id",
|
|
"statuses/oembed",
|
|
|
|
// Search
|
|
"search/tweets",
|
|
|
|
// Direct Messages
|
|
"direct_messages",
|
|
"direct_messages/sent",
|
|
"direct_messages/show",
|
|
|
|
// Friends & Followers
|
|
"friendships/no_retweets/ids",
|
|
"friends/ids",
|
|
"followers/ids",
|
|
"friendships/lookup",
|
|
"friendships/incoming",
|
|
"friendships/outgoing",
|
|
"friendships/show",
|
|
"friends/list",
|
|
"followers/list",
|
|
|
|
// Users
|
|
"account/settings",
|
|
"account/verify_credentials",
|
|
"blocks/list",
|
|
"blocks/ids",
|
|
"users/lookup",
|
|
"users/show",
|
|
"users/search",
|
|
"users/contributees",
|
|
"users/contributors",
|
|
"users/profile_banner",
|
|
|
|
// Suggested Users
|
|
"users/suggestions/:slug",
|
|
"users/suggestions",
|
|
"users/suggestions/:slug/members",
|
|
|
|
// Favorites
|
|
"favorites/list",
|
|
|
|
// Lists
|
|
"lists/list",
|
|
"lists/statuses",
|
|
"lists/memberships",
|
|
"lists/subscribers",
|
|
"lists/subscribers/show",
|
|
"lists/members/show",
|
|
"lists/members",
|
|
"lists/show",
|
|
"lists/subscriptions",
|
|
|
|
// Saved searches
|
|
"saved_searches/list",
|
|
"saved_searches/show/:id",
|
|
|
|
// Places & Geo
|
|
"geo/id/:place_id",
|
|
"geo/reverse_geocode",
|
|
"geo/search",
|
|
"geo/similar_places",
|
|
|
|
// Trends
|
|
"trends/place",
|
|
"trends/available",
|
|
"trends/closest",
|
|
|
|
// OAuth
|
|
"oauth/authenticate",
|
|
"oauth/authorize",
|
|
|
|
// Help
|
|
"help/configuration",
|
|
"help/languages",
|
|
"help/privacy",
|
|
"help/tos",
|
|
"application/rate_limit_status",
|
|
|
|
// Internal
|
|
"users/recommendations",
|
|
"account/push_destinations/device",
|
|
"activity/about_me",
|
|
"activity/by_friends",
|
|
"statuses/media_timeline",
|
|
"timeline/home",
|
|
"help/experiments",
|
|
"search/typeahead",
|
|
"search/universal",
|
|
"discover/universal",
|
|
"conversation/show",
|
|
"statuses/:id/activity/summary",
|
|
"account/login_verification_enrollment",
|
|
"account/login_verification_request",
|
|
"prompts/suggest",
|
|
|
|
"beta/timelines/custom/list",
|
|
"beta/timelines/timeline",
|
|
"beta/timelines/custom/show"
|
|
];
|
|
httpmethods.POST = [
|
|
// Tweets
|
|
"statuses/destroy/:id",
|
|
"statuses/update",
|
|
"statuses/retweet/:id",
|
|
"statuses/update_with_media",
|
|
|
|
// Direct Messages
|
|
"direct_messages/destroy",
|
|
"direct_messages/new",
|
|
|
|
// Friends & Followers
|
|
"friendships/create",
|
|
"friendships/destroy",
|
|
"friendships/update",
|
|
|
|
// Users
|
|
"account/settings__post",
|
|
"account/update_delivery_device",
|
|
"account/update_profile",
|
|
"account/update_profile_background_image",
|
|
"account/update_profile_colors",
|
|
"account/update_profile_image",
|
|
"blocks/create",
|
|
"blocks/destroy",
|
|
"account/update_profile_banner",
|
|
"account/remove_profile_banner",
|
|
|
|
// Favorites
|
|
"favorites/destroy",
|
|
"favorites/create",
|
|
|
|
// Lists
|
|
"lists/members/destroy",
|
|
"lists/subscribers/create",
|
|
"lists/subscribers/destroy",
|
|
"lists/members/create_all",
|
|
"lists/members/create",
|
|
"lists/destroy",
|
|
"lists/update",
|
|
"lists/create",
|
|
"lists/members/destroy_all",
|
|
|
|
// Saved Searches
|
|
"saved_searches/create",
|
|
"saved_searches/destroy/:id",
|
|
|
|
// Spam Reporting
|
|
"users/report_spam",
|
|
|
|
// OAuth
|
|
"oauth/access_token",
|
|
"oauth/request_token",
|
|
"oauth2/token",
|
|
"oauth2/invalidate_token",
|
|
|
|
// Internal
|
|
"direct_messages/read",
|
|
"account/login_verification_enrollment__post",
|
|
"push_destinations/enable_login_verification",
|
|
"account/login_verification_request__post",
|
|
|
|
"beta/timelines/custom/create",
|
|
"beta/timelines/custom/update",
|
|
"beta/timelines/custom/destroy",
|
|
"beta/timelines/custom/add",
|
|
"beta/timelines/custom/remove"
|
|
];
|
|
for (var httpmethod in httpmethods) {
|
|
if (httpmethods[httpmethod].indexOf(method) > -1) {
|
|
return httpmethod;
|
|
}
|
|
}
|
|
console.warn("Can't find HTTP method to use for \"" + method + "\".");
|
|
};
|
|
|
|
/**
|
|
* Detects if API call should use multipart/form-data
|
|
*
|
|
* @param string method The API method to call
|
|
*
|
|
* @return bool Whether the method should be sent as multipart
|
|
*/
|
|
var _detectMultipart = function (method) {
|
|
var multiparts = [
|
|
// Tweets
|
|
"statuses/update_with_media",
|
|
|
|
// Users
|
|
"account/update_profile_background_image",
|
|
"account/update_profile_image",
|
|
"account/update_profile_banner"
|
|
];
|
|
return multiparts.indexOf(method) > -1;
|
|
};
|
|
|
|
/**
|
|
* Build multipart request from upload params
|
|
*
|
|
* @param string method The API method to call
|
|
* @param array params The parameters to send along
|
|
*
|
|
* @return string The built multipart request body
|
|
*/
|
|
var _buildMultipart = function (method, params) {
|
|
// well, files will only work in multipart methods
|
|
if (! _detectMultipart(method)) {
|
|
return;
|
|
}
|
|
|
|
// only check specific parameters
|
|
var possible_methods = [
|
|
// Tweets
|
|
"statuses/update_with_media",
|
|
// Accounts
|
|
"account/update_profile_background_image",
|
|
"account/update_profile_image",
|
|
"account/update_profile_banner"
|
|
];
|
|
var possible_files = {
|
|
// Tweets
|
|
"statuses/update_with_media": "media[]",
|
|
// Accounts
|
|
"account/update_profile_background_image": "image",
|
|
"account/update_profile_image": "image",
|
|
"account/update_profile_banner": "banner"
|
|
};
|
|
// method might have files?
|
|
if (possible_methods.indexOf(method) === -1) {
|
|
return;
|
|
}
|
|
|
|
// check for filenames
|
|
possible_files = possible_files[method].split(" ");
|
|
|
|
var multipart_border = "--------------------" + _nonce();
|
|
var multipart_request = "";
|
|
for (var key in params) {
|
|
multipart_request +=
|
|
"--" + multipart_border + "\r\n"
|
|
+ "Content-Disposition: form-data; name=\"" + key + "\"";
|
|
if (possible_files.indexOf(key) > -1) {
|
|
multipart_request +=
|
|
"\r\nContent-Transfer-Encoding: base64";
|
|
}
|
|
multipart_request +=
|
|
"\r\n\r\n" + params[key] + "\r\n";
|
|
}
|
|
multipart_request += "--" + multipart_border + "--";
|
|
return multipart_request;
|
|
};
|
|
|
|
/**
|
|
* Detects if API call is internal
|
|
*
|
|
* @param string method The API method to call
|
|
*
|
|
* @return bool Whether the method is defined in internal API
|
|
*/
|
|
var _detectInternal = function (method) {
|
|
var internals = [
|
|
"users/recommendations"
|
|
];
|
|
return internals.join(" ").indexOf(method) > -1;
|
|
};
|
|
|
|
/**
|
|
* Detects if API call should use old endpoint
|
|
*
|
|
* @param string method The API method to call
|
|
*
|
|
* @return bool Whether the method is defined in old API
|
|
*/
|
|
var _detectOld = function (method) {
|
|
var olds = [
|
|
"account/push_destinations/device"
|
|
];
|
|
return olds.join(" ").indexOf(method) > -1;
|
|
};
|
|
|
|
/**
|
|
* Builds the complete API endpoint url
|
|
*
|
|
* @param string method The API method to call
|
|
*
|
|
* @return string The URL to send the request to
|
|
*/
|
|
var _getEndpoint = function (method) {
|
|
var url;
|
|
if (method.substring(0, 5) === "oauth") {
|
|
url = _endpoint_oauth + method;
|
|
} else if (_detectOld(method)) {
|
|
url = _endpoint_old + method + ".json";
|
|
} else {
|
|
url = _endpoint + method + ".json";
|
|
}
|
|
return url;
|
|
};
|
|
|
|
/**
|
|
* Gets the XML HTTP Request object, trying to load it in various ways
|
|
*
|
|
* @return object The XMLHttpRequest object instance
|
|
*/
|
|
var _getXmlRequestObject = function () {
|
|
var xml = null;
|
|
if (typeof window === "object"
|
|
&& window
|
|
&& typeof window.XMLHttpRequest === "function"
|
|
) {
|
|
xml = new window.XMLHttpRequest();
|
|
} else if (typeof require === "function"
|
|
&& require
|
|
) {
|
|
try {
|
|
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
|
|
xml = new XMLHttpRequest();
|
|
} catch (e1) {
|
|
try {
|
|
var XMLHttpRequest = require("xhr2");
|
|
xml = new XMLHttpRequest();
|
|
} catch (e2) {
|
|
console.error("xhr2 object not defined, trying ActiveXObject.");
|
|
try {
|
|
xml = new ActiveXObject("Microsoft.XMLHTTP");
|
|
} catch (e3) {
|
|
console.error("ActiveXObject object not defined, cancelling.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return xml;
|
|
};
|
|
|
|
/**
|
|
* Calls the API using cURL
|
|
*
|
|
* @param string httpmethod The HTTP method to use for making the request
|
|
* @param string method The API method to call
|
|
* @param string method_template The templated API method to call
|
|
* @param array optional params The parameters to send along
|
|
* @param bool optional multipart Whether to use multipart/form-data
|
|
* @param bool optional $app_only_auth Whether to use app-only bearer authentication
|
|
* @param bool optional $internal Whether to use internal call
|
|
* @param function callback The function to call with the API call result
|
|
*
|
|
* @return mixed The API reply, encoded in the set return_format
|
|
*/
|
|
|
|
var _callApi = function (httpmethod, method, method_template, params, multipart, app_only_auth, internal, callback) {
|
|
if (typeof params === "undefined") {
|
|
params = {};
|
|
}
|
|
if (typeof multipart === "undefined") {
|
|
multipart = false;
|
|
}
|
|
if (typeof app_only_auth === "undefined") {
|
|
app_only_auth = false;
|
|
}
|
|
if (typeof callback !== "function") {
|
|
callback = function () {};
|
|
}
|
|
if (internal) {
|
|
params.adc = "phone";
|
|
params.application_id = 333903271;
|
|
}
|
|
|
|
var url = _getEndpoint(method);
|
|
var authorization = null;
|
|
|
|
var xml = _getXmlRequestObject();
|
|
if (xml === null) {
|
|
return;
|
|
}
|
|
var post_fields;
|
|
|
|
if (httpmethod === "GET") {
|
|
var url_with_params = url;
|
|
if (JSON.stringify(params) !== "{}") {
|
|
url_with_params += "?" + _http_build_query(params);
|
|
}
|
|
authorization = _sign(httpmethod, url, params);
|
|
|
|
// append auth params to GET url for IE7-9, to send via JSONP
|
|
if (_use_jsonp) {
|
|
if (JSON.stringify(params) !== "{}") {
|
|
url_with_params += "&";
|
|
} else {
|
|
url_with_params += "?";
|
|
}
|
|
var callback_name = _nonce();
|
|
window[callback_name] = function (reply) {
|
|
reply.httpstatus = 200;
|
|
|
|
var rate = {
|
|
limit: xml.getResponseHeader("x-rate-limit-limit"),
|
|
remaining: xml.getResponseHeader("x-rate-limit-remaining"),
|
|
reset: xml.getResponseHeader("x-rate-limit-reset")
|
|
};
|
|
callback(reply, rate);
|
|
};
|
|
params.callback = callback_name;
|
|
url_with_params = url + "?" + _sign(httpmethod, url, params, true);
|
|
var tag = document.createElement("script");
|
|
tag.type = "text/javascript";
|
|
tag.src = url_with_params;
|
|
var body = document.getElementsByTagName("body")[0];
|
|
body.appendChild(tag);
|
|
return;
|
|
|
|
} else if (_use_proxy) {
|
|
url_with_params = url_with_params.replace(
|
|
_endpoint_base,
|
|
_endpoint_proxy
|
|
);
|
|
}
|
|
xml.open(httpmethod, url_with_params, true);
|
|
} else {
|
|
if (_use_jsonp) {
|
|
console.warn("Sending POST requests is not supported for IE7-9.");
|
|
return;
|
|
}
|
|
if (multipart) {
|
|
authorization = _sign(httpmethod, url, {});
|
|
params = _buildMultipart(method, params);
|
|
} else {
|
|
authorization = _sign(httpmethod, url, params);
|
|
params = _http_build_query(params);
|
|
}
|
|
post_fields = params;
|
|
if (_use_proxy || multipart) { // force proxy for multipart base64
|
|
url = url.replace(
|
|
_endpoint_base,
|
|
_endpoint_proxy
|
|
);
|
|
}
|
|
xml.open(httpmethod, url, true);
|
|
if (multipart) {
|
|
xml.setRequestHeader("Content-Type", "multipart/form-data; boundary="
|
|
+ post_fields.split("\r\n")[0].substring(2));
|
|
} else {
|
|
xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
}
|
|
}
|
|
if (app_only_auth) {
|
|
if (_oauth_consumer_key === null) {
|
|
console.warn("To make an app-only auth API request, the consumer key must be set.");
|
|
}
|
|
// automatically fetch bearer token, if necessary
|
|
if (_oauth_bearer_token === null) {
|
|
return oauth2_token(function () {
|
|
_callApi(httpmethod, method, method_template, params, multipart, app_only_auth, false, callback);
|
|
});
|
|
}
|
|
authorization = "Bearer " + _oauth_bearer_token;
|
|
}
|
|
if (authorization !== null) {
|
|
xml.setRequestHeader((_use_proxy ? "X-" : "") + "Authorization", authorization);
|
|
}
|
|
xml.onreadystatechange = function () {
|
|
if (xml.readyState >= 4) {
|
|
var httpstatus = 12027;
|
|
try {
|
|
httpstatus = xml.status;
|
|
} catch (e) {}
|
|
var reply = _parseApiReply(method_template, xml.responseText);
|
|
reply.httpstatus = httpstatus;
|
|
var rate = {
|
|
limit: xml.getResponseHeader("x-rate-limit-limit"),
|
|
remaining: xml.getResponseHeader("x-rate-limit-remaining"),
|
|
reset: xml.getResponseHeader("x-rate-limit-reset")
|
|
};
|
|
callback(reply, rate);
|
|
}
|
|
};
|
|
xml.send(httpmethod === "GET" ? null : post_fields);
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Parses the API reply to encode it in the set return_format
|
|
*
|
|
* @param string method The method that has been called
|
|
* @param string reply The actual reply, JSON-encoded or URL-encoded
|
|
*
|
|
* @return array|object The parsed reply
|
|
*/
|
|
var _parseApiReply = function (method, reply) {
|
|
if (reply === "[]") {
|
|
return [];
|
|
}
|
|
var parsed = false;
|
|
try {
|
|
parsed = JSON.parse(reply);
|
|
} catch (e) {
|
|
parsed = {};
|
|
if (reply.indexOf("<" + "?xml version=\"1.0\" encoding=\"UTF-8\"?" + ">") === 0) {
|
|
// we received XML...
|
|
// since this only happens for errors,
|
|
// don't perform a full decoding
|
|
parsed.request = reply.match(/<request>(.*)<\/request>/)[1];
|
|
parsed.error = reply.match(/<error>(.*)<\/error>/)[1];
|
|
} else {
|
|
// assume query format
|
|
var elements = reply.split("&");
|
|
for (var i = 0; i < elements.length; i++) {
|
|
var element = elements[i].split("=", 2);
|
|
if (element.length > 1) {
|
|
parsed[element[0]] = decodeURIComponent(element[1]);
|
|
} else {
|
|
parsed[element[0]] = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return parsed;
|
|
};
|
|
|
|
return {
|
|
setConsumerKey: setConsumerKey,
|
|
getVersion: getVersion,
|
|
setToken: setToken,
|
|
setBearerToken: setBearerToken,
|
|
setUseProxy: setUseProxy,
|
|
setProxy: setProxy,
|
|
__call: __call,
|
|
oauth_authenticate: oauth_authenticate,
|
|
oauth_authorize: oauth_authorize,
|
|
oauth2_token: oauth2_token
|
|
};
|
|
};
|
|
|
|
if (typeof module === "object"
|
|
&& module
|
|
&& typeof module.exports === "object"
|
|
) {
|
|
// Expose codebird as module.exports in loaders that implement the Node
|
|
// module pattern (including browserify). Do not create the global, since
|
|
// the user will be storing it themselves locally, and globals are frowned
|
|
// upon in the Node module world.
|
|
module.exports = Codebird;
|
|
} else {
|
|
// Otherwise expose codebird to the global object as usual
|
|
if (typeof window === "object"
|
|
&& window) {
|
|
window.Codebird = Codebird;
|
|
}
|
|
|
|
// Register as a named AMD module, since codebird can be concatenated with other
|
|
// files that may use define, but not via a proper concatenation script that
|
|
// understands anonymous AMD modules. A named AMD is safest and most robust
|
|
// way to register. Lowercase codebird is used because AMD module names are
|
|
// derived from file names, and codebird is normally delivered in a lowercase
|
|
// file name. Do this after creating the global so that if an AMD module wants
|
|
// to call noConflict to hide this version of codebird, it will work.
|
|
if (typeof define === "function" && define.amd) {
|
|
define("codebird", [], function () { return Codebird; });
|
|
}
|
|
}
|
|
|
|
})();
|