1591 lines
53 KiB
JavaScript
Raw Normal View History

2018-01-26 15:50:15 +01:00
"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;
});
}
}
})();