mirror of
https://github.com/lubuntu-team/lubuntu.me.git
synced 2025-02-23 08:11:08 +00:00
1591 lines
53 KiB
JavaScript
1591 lines
53 KiB
JavaScript
"use strict";
|
|
|
|
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; })();
|
|
|
|
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
|
|
|
|
function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; }
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
/**
|
|
* A Twitter library in JavaScript
|
|
*
|
|
* @package codebird
|
|
* @version 3.0.0-dev
|
|
* @author Jublo Solutions <support@jublo.net>
|
|
* @copyright 2010-2016 Jublo Solutions <support@jublo.net>
|
|
* @license http://opensource.org/licenses/GPL-3.0 GNU Public License 3.0
|
|
* @link https://github.com/jublonet/codebird-php
|
|
*/
|
|
|
|
/* global window,
|
|
document,
|
|
navigator,
|
|
Ti,
|
|
ActiveXObject,
|
|
module,
|
|
define,
|
|
require */
|
|
|
|
(function () {
|
|
/**
|
|
* A Twitter library in JavaScript
|
|
*
|
|
* @package codebird
|
|
* @subpackage codebird-js
|
|
*/
|
|
|
|
var Codebird = (function () {
|
|
function Codebird() {
|
|
_classCallCheck(this, Codebird);
|
|
|
|
/**
|
|
* The OAuth consumer key of your registered app
|
|
*/
|
|
this._oauth_consumer_key = null;
|
|
|
|
/**
|
|
* The corresponding consumer secret
|
|
*/
|
|
this._oauth_consumer_secret = null;
|
|
|
|
/**
|
|
* The app-only bearer token. Used to authorize app-only requests
|
|
*/
|
|
this._oauth_bearer_token = null;
|
|
|
|
/**
|
|
* The API endpoint base to use
|
|
*/
|
|
this._endpoint_base = "https://api.twitter.com/";
|
|
|
|
/**
|
|
* The media API endpoint base to use
|
|
*/
|
|
this._endpoint_base_media = "https://upload.twitter.com/";
|
|
|
|
/**
|
|
* The API endpoint to use
|
|
*/
|
|
this._endpoint = this._endpoint_base + "1.1/";
|
|
|
|
/**
|
|
* The media API endpoint to use
|
|
*/
|
|
this._endpoint_media = this._endpoint_base_media + "1.1/";
|
|
|
|
/**
|
|
* The publish API endpoint to use
|
|
*/
|
|
this._endpoint_publish = "https://publish.twitter.com/";
|
|
|
|
/**
|
|
* The API endpoint base to use
|
|
*/
|
|
this._endpoint_oauth = this._endpoint_base;
|
|
|
|
/**
|
|
* API proxy endpoint
|
|
*/
|
|
this._endpoint_proxy = "https://api.jublo.net/codebird/";
|
|
|
|
/**
|
|
* Whether to access the API via a proxy that is allowed by CORS
|
|
* Assume that CORS is only necessary in browsers
|
|
*/
|
|
this._use_proxy = typeof navigator !== "undefined" && typeof navigator.userAgent !== "undefined";
|
|
|
|
/**
|
|
* The Request or access token. Used to sign requests
|
|
*/
|
|
this._oauth_token = null;
|
|
|
|
/**
|
|
* The corresponding request or access token secret
|
|
*/
|
|
this._oauth_token_secret = null;
|
|
|
|
/**
|
|
* The current Codebird version
|
|
*/
|
|
this._version = "3.0.0-dev";
|
|
|
|
this.b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
|
}
|
|
|
|
/**
|
|
* Sets the OAuth consumer key and secret (App key)
|
|
*
|
|
* @param string key OAuth consumer key
|
|
* @param string secret OAuth consumer secret
|
|
*
|
|
* @return void
|
|
*/
|
|
|
|
_createClass(Codebird, [{
|
|
key: "setConsumerKey",
|
|
value: function setConsumerKey(key, secret) {
|
|
this._oauth_consumer_key = key;
|
|
this._oauth_consumer_secret = secret;
|
|
}
|
|
|
|
/**
|
|
* Sets the OAuth2 app-only auth bearer token
|
|
*
|
|
* @param string token OAuth2 bearer token
|
|
*
|
|
* @return void
|
|
*/
|
|
|
|
}, {
|
|
key: "setBearerToken",
|
|
value: function setBearerToken(token) {
|
|
this._oauth_bearer_token = token;
|
|
}
|
|
|
|
/**
|
|
* Gets the current Codebird version
|
|
*
|
|
* @return string The version number
|
|
*/
|
|
|
|
}, {
|
|
key: "getVersion",
|
|
value: function getVersion() {
|
|
return this._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
|
|
*/
|
|
|
|
}, {
|
|
key: "setToken",
|
|
value: function setToken(token, secret) {
|
|
this._oauth_token = token;
|
|
this._oauth_token_secret = secret;
|
|
}
|
|
|
|
/**
|
|
* Forgets the OAuth request or access token and secret (User key)
|
|
*
|
|
* @return bool
|
|
*/
|
|
|
|
}, {
|
|
key: "logout",
|
|
value: function logout() {
|
|
this._oauth_token = this._oauth_token_secret = null;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Enables or disables CORS proxy
|
|
*
|
|
* @param bool use_proxy Whether to use CORS proxy or not
|
|
*
|
|
* @return void
|
|
*/
|
|
|
|
}, {
|
|
key: "setUseProxy",
|
|
value: function setUseProxy(use_proxy) {
|
|
this._use_proxy = !!use_proxy;
|
|
}
|
|
|
|
/**
|
|
* Sets custom CORS proxy server
|
|
*
|
|
* @param string proxy Address of proxy server to use
|
|
*
|
|
* @return void
|
|
*/
|
|
|
|
}, {
|
|
key: "setProxy",
|
|
value: function setProxy(proxy) {
|
|
// add trailing slash if missing
|
|
if (!proxy.match(/\/$/)) {
|
|
proxy += "/";
|
|
}
|
|
this._endpoint_proxy = proxy;
|
|
}
|
|
|
|
/**
|
|
* Signing helpers
|
|
*/
|
|
|
|
/**
|
|
* URL-encodes the given data
|
|
*
|
|
* @param mixed data
|
|
*
|
|
* @return mixed The encoded data
|
|
*/
|
|
|
|
}, {
|
|
key: "_url",
|
|
value: function _url(data) {
|
|
if (/boolean|number|string/.test(typeof data === "undefined" ? "undefined" : _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
|
|
*/
|
|
|
|
}, {
|
|
key: "_sha1",
|
|
value: function _sha1(e) {
|
|
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 = undefined;
|
|
|
|
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;
|
|
|
|
var b = this._oauth_consumer_secret + "&" + (null !== this._oauth_token_secret ? this._oauth_token_secret : "");
|
|
if (this._oauth_consumer_secret === null) {
|
|
throw "To generate a hash, the consumer secret must be set.";
|
|
}
|
|
var c = q(b);
|
|
if (c.length > 16) {
|
|
c = n(c, b.length * g);
|
|
}
|
|
var bb = new Array(16);
|
|
for (var a = new Array(16), d = 0; d < 16; d++) {
|
|
a[d] = c[d] ^ 909522486;
|
|
bb[d] = c[d] ^ 1549556828;
|
|
}
|
|
c = n(a.concat(q(e)), 512 + e.length * g);
|
|
bb = n(bb.concat(c), 672);
|
|
b = "";
|
|
for (g = 0; g < 4 * bb.length; g += 3) {
|
|
for (d = (bb[g >> 2] >> 8 * (3 - g % 4) & 255) << 16 | (bb[g + 1 >> 2] >> 8 * (3 - (g + 1) % 4) & 255) << 8 | bb[g + 2 >> 2] >> 8 * (3 - (g + 2) % 4) & 255, e = 0; 4 > e; e++) {
|
|
b = 8 * g + 6 * e > 32 * bb.length ? b + "=" : b + this.b64_alphabet.charAt(d >> 6 * (3 - e) & 63);
|
|
}
|
|
}
|
|
return b;
|
|
}
|
|
|
|
/*
|
|
* 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
|
|
*/
|
|
|
|
}, {
|
|
key: "_base64_encode",
|
|
value: function _base64_encode(a) {
|
|
var d = undefined,
|
|
e = undefined,
|
|
f = undefined,
|
|
b = undefined,
|
|
g = 0,
|
|
h = 0,
|
|
i = this.b64_alphabet,
|
|
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);
|
|
i = c.join("");
|
|
a = a.length % 3;
|
|
return (a ? i.slice(0, a - 3) : i) + "===".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
|
|
*/
|
|
|
|
}, {
|
|
key: "_http_build_query",
|
|
value: function _http_build_query(e, f, b) {
|
|
function g(c, a, d) {
|
|
var b = undefined,
|
|
e = [];
|
|
if (a === true) {
|
|
a = "1";
|
|
} else if (a === false) {
|
|
a = "0";
|
|
}
|
|
if (null !== a) {
|
|
if ((typeof a === "undefined" ? "undefined" : _typeof(a)) === "object") {
|
|
for (b in a) {
|
|
if (a.hasOwnProperty(b) && a[b] !== null) {
|
|
e.push(g.call(this, c + "[" + b + "]", a[b], d));
|
|
}
|
|
}
|
|
return e.join(d);
|
|
}
|
|
if (typeof a !== "function") {
|
|
return this._url(c) + "=" + this._url(a);
|
|
}
|
|
throw "There was an error processing for http_build_query().";
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
var d,
|
|
c,
|
|
h = [];
|
|
if (!b) {
|
|
b = "&";
|
|
}
|
|
for (c in e) {
|
|
if (!e.hasOwnProperty(c)) {
|
|
continue;
|
|
}
|
|
d = e[c];
|
|
if (f && !isNaN(c)) {
|
|
c = String(f) + c;
|
|
}
|
|
d = g.call(this, 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
|
|
*/
|
|
|
|
}, {
|
|
key: "_nonce",
|
|
value: function _nonce() {
|
|
var length = arguments.length <= 0 || arguments[0] === undefined ? 8 : arguments[0];
|
|
|
|
if (length < 1) {
|
|
throw "Invalid nonce length.";
|
|
}
|
|
var nonce = "";
|
|
for (var i = 0; i < length; i++) {
|
|
var character = Math.floor(Math.random() * 61);
|
|
nonce += this.b64_alphabet.substring(character, character + 1);
|
|
}
|
|
return nonce;
|
|
}
|
|
|
|
/**
|
|
* Sort array elements by key
|
|
*
|
|
* @param array input_arr The array to sort
|
|
*
|
|
* @return array The sorted keys
|
|
*/
|
|
|
|
}, {
|
|
key: "_ksort",
|
|
value: function _ksort(input_arr) {
|
|
var keys = [],
|
|
sorter = undefined,
|
|
k = undefined;
|
|
|
|
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
|
|
*/
|
|
|
|
}, {
|
|
key: "_clone",
|
|
value: function _clone(obj) {
|
|
var clone = {};
|
|
for (var i in obj) {
|
|
if (_typeof(obj[i]) === "object") {
|
|
clone[i] = this._clone(obj[i]);
|
|
} else {
|
|
clone[i] = obj[i];
|
|
}
|
|
}
|
|
return clone;
|
|
}
|
|
|
|
/**
|
|
* Gets the XML HTTP Request object, trying to load it in various ways
|
|
*
|
|
* @return object The XMLHttpRequest object instance
|
|
*/
|
|
|
|
}, {
|
|
key: "_getXmlRequestObject",
|
|
value: function _getXmlRequestObject() {
|
|
var xml = null;
|
|
// first, try the W3-standard object
|
|
if ((typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" && window && typeof window.XMLHttpRequest !== "undefined") {
|
|
xml = new window.XMLHttpRequest();
|
|
// then, try Titanium framework object
|
|
} else if ((typeof Ti === "undefined" ? "undefined" : _typeof(Ti)) === "object" && Ti && typeof Ti.Network.createHTTPClient !== "undefined") {
|
|
xml = Ti.Network.createHTTPClient();
|
|
// are we in an old Internet Explorer?
|
|
} else if (typeof ActiveXObject !== "undefined") {
|
|
try {
|
|
xml = new ActiveXObject("Microsoft.XMLHTTP");
|
|
} catch (e) {
|
|
throw "ActiveXObject object not defined.";
|
|
}
|
|
// now, consider RequireJS and/or Node.js objects
|
|
} else if (typeof require === "function") {
|
|
var XMLHttpRequest;
|
|
// look for xmlhttprequest module
|
|
try {
|
|
XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
|
|
xml = new XMLHttpRequest();
|
|
} catch (e1) {
|
|
// or maybe the user is using xhr2
|
|
try {
|
|
XMLHttpRequest = require("xhr2");
|
|
xml = new XMLHttpRequest();
|
|
} catch (e2) {
|
|
throw "xhr2 object not defined, cancelling.";
|
|
}
|
|
}
|
|
}
|
|
return xml;
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
|
|
}, {
|
|
key: "_parse_str",
|
|
value: function _parse_str(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 fixStr(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;
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get allowed API methods, sorted by GET or POST
|
|
* Watch out for multiple-method "account/settings"!
|
|
*
|
|
* @return array $apimethods
|
|
*/
|
|
|
|
}, {
|
|
key: "getApiMethods",
|
|
value: function getApiMethods() {
|
|
var httpmethods = {
|
|
GET: ["account/settings", "account/verify_credentials", "application/rate_limit_status", "blocks/ids", "blocks/list", "collections/entries", "collections/list", "collections/show", "direct_messages", "direct_messages/sent", "direct_messages/show", "favorites/list", "followers/ids", "followers/list", "friends/ids", "friends/list", "friendships/incoming", "friendships/lookup", "friendships/lookup", "friendships/no_retweets/ids", "friendships/outgoing", "friendships/show", "geo/id/:place_id", "geo/reverse_geocode", "geo/search", "geo/similar_places", "help/configuration", "help/languages", "help/privacy", "help/tos", "lists/list", "lists/members", "lists/members/show", "lists/memberships", "lists/ownerships", "lists/show", "lists/statuses", "lists/subscribers", "lists/subscribers/show", "lists/subscriptions", "mutes/users/ids", "mutes/users/list", "oauth/authenticate", "oauth/authorize", "saved_searches/list", "saved_searches/show/:id", "search/tweets", "site", "statuses/firehose", "statuses/home_timeline", "statuses/mentions_timeline", "statuses/oembed", "statuses/retweeters/ids", "statuses/retweets/:id", "statuses/retweets_of_me", "statuses/sample", "statuses/show/:id", "statuses/user_timeline", "trends/available", "trends/closest", "trends/place", "user", "users/contributees", "users/contributors", "users/profile_banner", "users/search", "users/show", "users/suggestions", "users/suggestions/:slug", "users/suggestions/:slug/members"],
|
|
POST: ["account/remove_profile_banner", "account/settings__post", "account/update_delivery_device", "account/update_profile", "account/update_profile_background_image", "account/update_profile_banner", "account/update_profile_colors", "account/update_profile_image", "blocks/create", "blocks/destroy", "collections/create", "collections/destroy", "collections/entries/add", "collections/entries/curate", "collections/entries/move", "collections/entries/remove", "collections/update", "direct_messages/destroy", "direct_messages/new", "favorites/create", "favorites/destroy", "friendships/create", "friendships/destroy", "friendships/update", "lists/create", "lists/destroy", "lists/members/create", "lists/members/create_all", "lists/members/destroy", "lists/members/destroy_all", "lists/subscribers/create", "lists/subscribers/destroy", "lists/update", "media/upload", "mutes/users/create", "mutes/users/destroy", "oauth/access_token", "oauth/request_token", "oauth2/invalidate_token", "oauth2/token", "saved_searches/create", "saved_searches/destroy/:id", "statuses/destroy/:id", "statuses/filter", "statuses/lookup", "statuses/retweet/:id", "statuses/unretweet/:id", "statuses/update", "statuses/update_with_media", // deprecated, use media/upload
|
|
"users/lookup", "users/report_spam"]
|
|
};
|
|
return httpmethods;
|
|
}
|
|
|
|
/**
|
|
* Promise helpers
|
|
*/
|
|
|
|
/**
|
|
* Get a deferred object
|
|
*/
|
|
|
|
}, {
|
|
key: "_getDfd",
|
|
value: function _getDfd() {
|
|
if (typeof window !== "undefined") {
|
|
if (typeof window.jQuery !== "undefined" && window.jQuery.Deferred) {
|
|
return window.jQuery.Deferred();
|
|
}
|
|
if (typeof window.Q !== "undefined" && window.Q.defer) {
|
|
return window.Q.defer();
|
|
}
|
|
if (typeof window.RSVP !== "undefined" && window.RSVP.defer) {
|
|
return window.RSVP.defer();
|
|
}
|
|
if (typeof window.when !== "undefined" && window.when.defer) {
|
|
return window.when.defer();
|
|
}
|
|
}
|
|
if (typeof require !== "undefined") {
|
|
var promise_class = false;
|
|
try {
|
|
promise_class = require("jquery");
|
|
} catch (e) {}
|
|
if (promise_class) {
|
|
return promise_class.Deferred();
|
|
}
|
|
try {
|
|
promise_class = require("q");
|
|
} catch (e) {}
|
|
if (!promise_class) {
|
|
try {
|
|
promise_class = require("rsvp");
|
|
} catch (e) {}
|
|
}
|
|
if (!promise_class) {
|
|
try {
|
|
promise_class = require("when");
|
|
} catch (e) {}
|
|
}
|
|
if (promise_class) {
|
|
try {
|
|
return promise_class.defer();
|
|
} catch (e) {}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get a promise from the dfd object
|
|
*/
|
|
|
|
}, {
|
|
key: "_getPromise",
|
|
value: function _getPromise(dfd) {
|
|
if (typeof dfd.promise === "function") {
|
|
return dfd.promise();
|
|
}
|
|
return dfd.promise; // object
|
|
}
|
|
|
|
/**
|
|
* __call() helpers
|
|
*/
|
|
|
|
/**
|
|
* Parse given params, detect query-style params
|
|
*
|
|
* @param array|string params Parameters to parse
|
|
*
|
|
* @return array apiparams
|
|
*/
|
|
|
|
}, {
|
|
key: "_parseApiParams",
|
|
value: function _parseApiParams(params) {
|
|
var apiparams = {};
|
|
if ((typeof params === "undefined" ? "undefined" : _typeof(params)) === "object") {
|
|
apiparams = params;
|
|
} else {
|
|
this._parse_str(params, apiparams); //TODO
|
|
}
|
|
|
|
return apiparams;
|
|
}
|
|
|
|
/**
|
|
* Replace null and boolean parameters with their string representations
|
|
*
|
|
* @param array apiparams Parameter array to replace in
|
|
*
|
|
* @return array apiparams
|
|
*/
|
|
|
|
}, {
|
|
key: "_stringifyNullBoolParams",
|
|
value: function _stringifyNullBoolParams(apiparams) {
|
|
for (var key in apiparams) {
|
|
if (!apiparams.hasOwnProperty(key)) {
|
|
continue;
|
|
}
|
|
var value = apiparams[key];
|
|
if (value === null) {
|
|
apiparams[key] = "null";
|
|
} else if (value === true || value === false) {
|
|
apiparams[key] = value ? "true" : "false";
|
|
}
|
|
}
|
|
|
|
return apiparams;
|
|
}
|
|
|
|
/**
|
|
* API method mapping: Replaces _ with / character
|
|
*
|
|
* @param string fn Function called
|
|
*
|
|
* @return string API method to call
|
|
*/
|
|
|
|
}, {
|
|
key: "_mapFnInsertSlashes",
|
|
value: function _mapFnInsertSlashes(fn) {
|
|
return fn.split("_").join("/");
|
|
}
|
|
|
|
/**
|
|
* API method mapping: Restore _ character in named parameters
|
|
*
|
|
* @param string method API method to call
|
|
*
|
|
* @return string API method with restored underscores
|
|
*/
|
|
|
|
}, {
|
|
key: "_mapFnRestoreParamUnderscores",
|
|
value: function _mapFnRestoreParamUnderscores(method) {
|
|
var url_parameters_with_underscore = ["screen_name", "place_id"];
|
|
var i = undefined,
|
|
param = undefined,
|
|
replacement_was = undefined;
|
|
for (i = 0; i < url_parameters_with_underscore.length; i++) {
|
|
param = url_parameters_with_underscore[i].toUpperCase();
|
|
replacement_was = param.split("_").join("/");
|
|
method = method.split(replacement_was).join(param);
|
|
}
|
|
|
|
return method;
|
|
}
|
|
|
|
/**
|
|
* Maps called PHP magic method name to Twitter API method
|
|
*
|
|
* @param string $fn Function called
|
|
* @param array $apiparams byref API parameters
|
|
*
|
|
* @return string[] (string method, string method_template)
|
|
*/
|
|
|
|
}, {
|
|
key: "_mapFnToApiMethod",
|
|
value: function _mapFnToApiMethod(fn, apiparams) {
|
|
var method = "",
|
|
param = undefined,
|
|
i = undefined,
|
|
j = undefined;
|
|
|
|
// replace _ by /
|
|
method = this._mapFnInsertSlashes(fn);
|
|
|
|
// undo replacement for URL parameters
|
|
method = this._mapFnRestoreParamUnderscores(method);
|
|
|
|
// 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));
|
|
}
|
|
throw "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));
|
|
}
|
|
|
|
return [method, method_template];
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
|
|
}, {
|
|
key: "_detectMethod",
|
|
value: function _detectMethod(method, params) {
|
|
if (typeof params.httpmethod !== "undefined") {
|
|
var httpmethod = params.httpmethod;
|
|
delete params.httpmethod;
|
|
return httpmethod;
|
|
}
|
|
|
|
// multi-HTTP method endpoints
|
|
switch (method) {
|
|
case "account/settings":
|
|
case "account/login_verification_enrollment":
|
|
case "account/login_verification_request":
|
|
method = Object.keys(params).length ? method + "__post" : method;
|
|
break;
|
|
}
|
|
|
|
var apimethods = this.getApiMethods();
|
|
for (var httpmethod in apimethods) {
|
|
if (apimethods.hasOwnProperty(httpmethod) && apimethods[httpmethod].indexOf(method) > -1) {
|
|
return httpmethod;
|
|
}
|
|
}
|
|
throw "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
|
|
*/
|
|
|
|
}, {
|
|
key: "_detectMultipart",
|
|
value: function _detectMultipart(method) {
|
|
var multiparts = [
|
|
// Tweets
|
|
"statuses/update_with_media", "media/upload",
|
|
|
|
// Users
|
|
"account/update_profile_background_image", "account/update_profile_image", "account/update_profile_banner"];
|
|
return multiparts.indexOf(method) > -1;
|
|
}
|
|
|
|
/**
|
|
* Signature helper
|
|
*
|
|
* @param string httpmethod Usually either 'GET' or 'POST' or 'DELETE'
|
|
* @param string method The API method to call
|
|
* @param array base_params The signature base parameters
|
|
*
|
|
* @return string signature
|
|
*/
|
|
|
|
}, {
|
|
key: "_getSignature",
|
|
value: function _getSignature(httpmethod, method, keys, base_params) {
|
|
// convert params to string
|
|
var base_string = "",
|
|
key = undefined,
|
|
value = undefined;
|
|
for (var i = 0; i < keys.length; i++) {
|
|
key = keys[i];
|
|
value = base_params[key];
|
|
base_string += key + "=" + this._url(value) + "&";
|
|
}
|
|
base_string = base_string.substring(0, base_string.length - 1);
|
|
return this._sha1(httpmethod + "&" + this._url(method) + "&" + this._url(base_string));
|
|
}
|
|
|
|
/**
|
|
* Generates the UNIX timestamp
|
|
*/
|
|
|
|
}, {
|
|
key: "_time",
|
|
value: function _time() {
|
|
return Math.round(new Date().getTime() / 1000);
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*
|
|
* @return string Authorization HTTP header
|
|
*/
|
|
|
|
}, {
|
|
key: "_sign",
|
|
value: function _sign(httpmethod, method) {
|
|
var params = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
|
|
|
|
if (this._oauth_consumer_key === null) {
|
|
throw "To generate a signature, the consumer key must be set.";
|
|
}
|
|
var sign_params = {
|
|
consumer_key: this._oauth_consumer_key,
|
|
version: "1.0",
|
|
timestamp: this._time(),
|
|
nonce: this._nonce(),
|
|
signature_method: "HMAC-SHA1"
|
|
};
|
|
var sign_base_params = {};
|
|
for (var key in sign_params) {
|
|
if (!sign_params.hasOwnProperty(key)) {
|
|
continue;
|
|
}
|
|
var value = sign_params[key];
|
|
sign_base_params["oauth_" + key] = this._url(value);
|
|
}
|
|
if (this._oauth_token !== null) {
|
|
sign_base_params.oauth_token = this._url(this._oauth_token);
|
|
}
|
|
var oauth_params = this._clone(sign_base_params);
|
|
for (key in params) {
|
|
if (!params.hasOwnProperty(key)) {
|
|
continue;
|
|
}
|
|
sign_base_params[key] = params[key];
|
|
}
|
|
var keys = this._ksort(sign_base_params);
|
|
|
|
var signature = this._getSignature(httpmethod, method, keys, sign_base_params);
|
|
|
|
params = oauth_params;
|
|
params.oauth_signature = signature;
|
|
keys = this._ksort(params);
|
|
var authorization = "OAuth ";
|
|
for (var i = 0; i < keys.length; i++) {
|
|
key = keys[i];
|
|
authorization += key + "=\"" + this._url(params[key]) + "\", ";
|
|
}
|
|
return authorization.substring(0, authorization.length - 2);
|
|
}
|
|
|
|
/**
|
|
* Build multipart request from upload params
|
|
*
|
|
* @param string method The API method to call
|
|
* @param array params The parameters to send along
|
|
*
|
|
* @return null|string The built multipart request body
|
|
*/
|
|
|
|
}, {
|
|
key: "_buildMultipart",
|
|
value: function _buildMultipart(method, params) {
|
|
// well, files will only work in multipart methods
|
|
if (!this._detectMultipart(method)) {
|
|
return;
|
|
}
|
|
|
|
// only check specific parameters
|
|
var possible_methods = [
|
|
// Tweets
|
|
"media/upload", "statuses/update_with_media",
|
|
// Accounts
|
|
"account/update_profile_background_image", "account/update_profile_image", "account/update_profile_banner"];
|
|
var possible_files = {
|
|
// Tweets
|
|
"media/upload": "media",
|
|
"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 = "--------------------" + this._nonce();
|
|
var multipart_request = "";
|
|
for (var key in params) {
|
|
if (!params.hasOwnProperty(key)) {
|
|
continue;
|
|
}
|
|
multipart_request += "--" + multipart_border + "\r\nContent-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 should use media endpoint
|
|
*
|
|
* @param string method The API method to call
|
|
*
|
|
* @return bool Whether the method is defined in media API
|
|
*/
|
|
|
|
}, {
|
|
key: "_detectMedia",
|
|
value: function _detectMedia(method) {
|
|
var medias = ["media/upload"];
|
|
return medias.indexOf(method) > -1;
|
|
}
|
|
|
|
/**
|
|
* Detects if API call should use JSON body
|
|
*
|
|
* @param string method The API method to call
|
|
*
|
|
* @return bool Whether the method is defined as accepting JSON body
|
|
*/
|
|
|
|
}, {
|
|
key: "_detectJsonBody",
|
|
value: function _detectJsonBody(method) {
|
|
var json_bodies = ["collections/entries/curate"];
|
|
return json_bodies.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
|
|
*/
|
|
|
|
}, {
|
|
key: "_getEndpoint",
|
|
value: function _getEndpoint(method) {
|
|
var url = undefined;
|
|
if (method.substring(0, 5) === "oauth") {
|
|
url = this._endpoint_oauth + method;
|
|
} else if (this._detectMedia(method)) {
|
|
url = this._endpoint_media + method + ".json";
|
|
} else if (method === "statuses/oembed") {
|
|
url = this._endpoint_publish + "oembed";
|
|
} else {
|
|
url = this._endpoint + method + ".json";
|
|
}
|
|
return url;
|
|
}
|
|
|
|
/**
|
|
* Parses the API reply to encode it in the set return_format
|
|
*
|
|
* @param string reply The actual reply, JSON-encoded or URL-encoded
|
|
*
|
|
* @return array|object The parsed reply
|
|
*/
|
|
|
|
}, {
|
|
key: "_parseApiReply",
|
|
value: function _parseApiReply(reply) {
|
|
if (typeof reply !== "string" || reply === "") {
|
|
return {};
|
|
}
|
|
if (reply === "[]") {
|
|
return [];
|
|
}
|
|
var parsed = undefined;
|
|
try {
|
|
parsed = JSON.parse(reply);
|
|
} catch (e) {
|
|
parsed = {};
|
|
// 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;
|
|
}
|
|
|
|
/**
|
|
* Uncommon API methods
|
|
*/
|
|
|
|
/**
|
|
* Gets the OAuth authenticate URL for the current request token
|
|
*
|
|
* @return object Promise
|
|
*/
|
|
|
|
}, {
|
|
key: "oauth_authenticate",
|
|
value: function oauth_authenticate() {
|
|
var params = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
|
|
var callback = arguments.length <= 1 || arguments[1] === undefined ? undefined : arguments[1];
|
|
var type = arguments.length <= 2 || arguments[2] === undefined ? "authenticate" : arguments[2];
|
|
|
|
var dfd = this._getDfd();
|
|
if (typeof params.force_login === "undefined") {
|
|
params.force_login = null;
|
|
}
|
|
if (typeof params.screen_name === "undefined") {
|
|
params.screen_name = null;
|
|
}
|
|
if (["authenticate", "authorize"].indexOf(type) === -1) {
|
|
type = "authenticate";
|
|
}
|
|
if (this._oauth_token === null) {
|
|
var error = "To get the " + type + " URL, the OAuth token must be set.";
|
|
if (dfd) {
|
|
dfd.reject({ error: error });
|
|
return this._getPromise(dfd);
|
|
}
|
|
throw error;
|
|
}
|
|
var url = this._endpoint_oauth + "oauth/" + type + "?oauth_token=" + this._url(this._oauth_token);
|
|
if (params.force_login === true) {
|
|
url += "&force_login=1";
|
|
}
|
|
if (params.screen_name !== null) {
|
|
url += "&screen_name=" + params.screen_name;
|
|
}
|
|
if (typeof callback === "function") {
|
|
callback(url);
|
|
}
|
|
if (dfd) {
|
|
dfd.resolve({ reply: url });
|
|
return this._getPromise(dfd);
|
|
}
|
|
// no promises
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Gets the OAuth authorize URL for the current request token
|
|
*
|
|
* @return string The OAuth authorize URL
|
|
*/
|
|
|
|
}, {
|
|
key: "oauth_authorize",
|
|
value: function oauth_authorize(params, callback) {
|
|
return this.oauth_authenticate(params, callback, "authorize");
|
|
}
|
|
|
|
/**
|
|
* Gets the OAuth bearer token
|
|
*
|
|
* @return object Promise
|
|
*/
|
|
|
|
}, {
|
|
key: "oauth2_token",
|
|
value: function oauth2_token(callback) {
|
|
var _this = this;
|
|
|
|
var dfd = this._getDfd();
|
|
|
|
if (this._oauth_consumer_key === null) {
|
|
var error = "To obtain a bearer token, the consumer key must be set.";
|
|
if (dfd) {
|
|
dfd.reject({ error: error });
|
|
return this._getPromise(dfd);
|
|
}
|
|
throw error;
|
|
}
|
|
|
|
if (!dfd && typeof callback === "undefined") {
|
|
callback = function () {};
|
|
}
|
|
|
|
var post_fields = "grant_type=client_credentials";
|
|
var url = this._endpoint_oauth + "oauth2/token";
|
|
|
|
if (this._use_proxy) {
|
|
url = url.replace(this._endpoint_base, this._endpoint_proxy);
|
|
}
|
|
|
|
var xml = this._getXmlRequestObject();
|
|
if (xml === null) {
|
|
return;
|
|
}
|
|
xml.open("POST", url, true);
|
|
xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
xml.setRequestHeader((this._use_proxy ? "X-" : "") + "Authorization", "Basic " + this._base64_encode(this._oauth_consumer_key + ":" + this._oauth_consumer_secret));
|
|
|
|
xml.onreadystatechange = function () {
|
|
if (xml.readyState >= 4) {
|
|
var httpstatus = 12027;
|
|
try {
|
|
httpstatus = xml.status;
|
|
} catch (e) {}
|
|
var response = "";
|
|
try {
|
|
response = xml.responseText;
|
|
} catch (e) {}
|
|
var reply = _this._parseApiReply(response);
|
|
reply.httpstatus = httpstatus;
|
|
if (httpstatus === 200) {
|
|
_this.setBearerToken(reply.access_token);
|
|
}
|
|
if (typeof callback === "function") {
|
|
callback(reply);
|
|
}
|
|
if (dfd) {
|
|
dfd.resolve({ reply: reply });
|
|
}
|
|
}
|
|
};
|
|
// function called when an error occurs, including a timeout
|
|
xml.onerror = function (e) {
|
|
if (typeof callback === "function") {
|
|
callback(null, e);
|
|
}
|
|
if (dfd) {
|
|
dfd.reject(e);
|
|
}
|
|
};
|
|
xml.timeout = 30000; // in milliseconds
|
|
|
|
xml.send(post_fields);
|
|
if (dfd) {
|
|
return this._getPromise(dfd);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 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 function callback The function to call with the API call result
|
|
*
|
|
* @return mixed The API reply, encoded in the set return_format
|
|
*/
|
|
|
|
}, {
|
|
key: "_callApi",
|
|
value: function _callApi(httpmethod, method) {
|
|
var params = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
|
|
var multipart = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
|
|
|
|
var _this2 = this;
|
|
|
|
var app_only_auth = arguments.length <= 4 || arguments[4] === undefined ? false : arguments[4];
|
|
var callback = arguments.length <= 5 || arguments[5] === undefined ? function () {} : arguments[5];
|
|
|
|
var dfd = this._getDfd();
|
|
|
|
var url = this._getEndpoint(method),
|
|
authorization = null;
|
|
|
|
var xml = this._getXmlRequestObject();
|
|
if (xml === null) {
|
|
return;
|
|
}
|
|
var post_fields = undefined;
|
|
|
|
if (httpmethod === "GET") {
|
|
var url_with_params = url;
|
|
if (JSON.stringify(params) !== "{}") {
|
|
url_with_params += "?" + this._http_build_query(params);
|
|
}
|
|
if (!app_only_auth) {
|
|
authorization = this._sign(httpmethod, url, params);
|
|
}
|
|
|
|
if (this._use_proxy) {
|
|
url_with_params = url_with_params.replace(this._endpoint_base, this._endpoint_proxy).replace(this._endpoint_base_media, this._endpoint_proxy);
|
|
}
|
|
xml.open(httpmethod, url_with_params, true);
|
|
} else {
|
|
if (multipart) {
|
|
if (!app_only_auth) {
|
|
authorization = this._sign(httpmethod, url, {});
|
|
}
|
|
params = this._buildMultipart(method, params);
|
|
} else if (this._detectJsonBody(method)) {
|
|
authorization = this._sign(httpmethod, url, {});
|
|
params = JSON.stringify(params);
|
|
} else {
|
|
if (!app_only_auth) {
|
|
authorization = this._sign(httpmethod, url, params);
|
|
}
|
|
params = this._http_build_query(params);
|
|
}
|
|
post_fields = params;
|
|
if (this._use_proxy || multipart) {
|
|
// force proxy for multipart base64
|
|
url = url.replace(this._endpoint_base, this._endpoint_proxy).replace(this._endpoint_base_media, this._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 if (this._detectJsonBody(method)) {
|
|
xml.setRequestHeader("Content-Type", "application/json");
|
|
} else {
|
|
xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
}
|
|
}
|
|
if (app_only_auth) {
|
|
if (this._oauth_consumer_key === null && this._oauth_bearer_token === null) {
|
|
var error = "To make an app-only auth API request, consumer key or bearer token must be set.";
|
|
if (dfd) {
|
|
dfd.reject({ error: error });
|
|
return this._getPromise(dfd);
|
|
}
|
|
throw error;
|
|
}
|
|
// automatically fetch bearer token, if necessary
|
|
if (this._oauth_bearer_token === null) {
|
|
if (dfd) {
|
|
return this.oauth2_token().then(function () {
|
|
return _this2._callApi(httpmethod, method, params, multipart, app_only_auth, callback);
|
|
});
|
|
}
|
|
this.oauth2_token(function () {
|
|
_this2._callApi(httpmethod, method, params, multipart, app_only_auth, callback);
|
|
});
|
|
return;
|
|
}
|
|
authorization = "Bearer " + this._oauth_bearer_token;
|
|
}
|
|
if (authorization !== null) {
|
|
xml.setRequestHeader((this._use_proxy ? "X-" : "") + "Authorization", authorization);
|
|
}
|
|
xml.onreadystatechange = function () {
|
|
if (xml.readyState >= 4) {
|
|
var httpstatus = 12027;
|
|
try {
|
|
httpstatus = xml.status;
|
|
} catch (e) {}
|
|
var response = "";
|
|
try {
|
|
response = xml.responseText;
|
|
} catch (e) {}
|
|
var reply = _this2._parseApiReply(response);
|
|
reply.httpstatus = httpstatus;
|
|
var rate = null;
|
|
if (typeof xml.getResponseHeader !== "undefined" && xml.getResponseHeader("x-rate-limit-limit") !== "") {
|
|
rate = {
|
|
limit: xml.getResponseHeader("x-rate-limit-limit"),
|
|
remaining: xml.getResponseHeader("x-rate-limit-remaining"),
|
|
reset: xml.getResponseHeader("x-rate-limit-reset")
|
|
};
|
|
}
|
|
if (typeof callback === "function") {
|
|
callback(reply, rate);
|
|
}
|
|
if (dfd) {
|
|
dfd.resolve({ reply: reply, rate: rate });
|
|
}
|
|
}
|
|
};
|
|
// function called when an error occurs, including a timeout
|
|
xml.onerror = function (e) {
|
|
if (typeof callback === "function") {
|
|
callback(null, null, e);
|
|
}
|
|
if (dfd) {
|
|
dfd.reject(e);
|
|
}
|
|
};
|
|
xml.timeout = 30000; // in milliseconds
|
|
|
|
xml.send(httpmethod === "GET" ? null : post_fields);
|
|
if (dfd) {
|
|
return this._getPromise(dfd);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 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 object Promise
|
|
*/
|
|
|
|
}, {
|
|
key: "__call",
|
|
value: function __call(fn) {
|
|
var params = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
|
|
var callback = arguments[2];
|
|
var app_only_auth = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
|
|
|
|
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);
|
|
}
|
|
|
|
// parse parameters
|
|
var apiparams = this._parseApiParams(params);
|
|
|
|
// stringify null and boolean parameters
|
|
apiparams = this._stringifyNullBoolParams(apiparams);
|
|
|
|
// reset token when requesting a new token (causes 401 for signature error on 2nd+ requests)
|
|
if (fn === "oauth_requestToken") {
|
|
this.setToken(null, null);
|
|
}
|
|
|
|
// map function name to API method
|
|
|
|
var _mapFnToApiMethod2 = this._mapFnToApiMethod(fn, apiparams);
|
|
|
|
var _mapFnToApiMethod3 = _slicedToArray(_mapFnToApiMethod2, 2);
|
|
|
|
var method = _mapFnToApiMethod3[0];
|
|
var method_template = _mapFnToApiMethod3[1];
|
|
var httpmethod = this._detectMethod(method_template, apiparams);
|
|
var multipart = this._detectMultipart(method_template);
|
|
|
|
return this._callApi(httpmethod, method, apiparams, multipart, app_only_auth, callback);
|
|
}
|
|
}]);
|
|
|
|
return Codebird;
|
|
})();
|
|
|
|
;
|
|
|
|
if ((typeof module === "undefined" ? "undefined" : _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 === "undefined" ? "undefined" : _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;
|
|
});
|
|
}
|
|
}
|
|
})(); |