Changeset 38410 for lang/javascript
- Timestamp:
- 09/04/10 04:25:04 (3 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
lang/javascript/vimperator-plugins/trunk/twittperator.js
r38378 r38410 26 26 let PLUGIN_INFO = 27 27 <VimperatorPlugin> 28 <name> twittperator</name>28 <name>Twittperator</name> 29 29 <description>Twitter Client using ChirpStream</description> 30 30 <description lang="ja">OAuth対応Twitterクライアント</description> 31 <version>1.4.2 </version>31 <version>1.4.2.3.4.5.6.7.8.9.10.11.12.13</version> 32 32 <minVersion>2.3</minVersion> 33 33 <maxVersion>2.4</maxVersion> … … 41 41 - Use completion for comfort. 42 42 :tw[ittperator] -getPIN 43 Opens the page to authorize twittperator and get your PIN from Twitter43 Opens the page to authorize Twittperator and get your PIN from Twitter. 44 44 :tw[ittperator] -setPIN {PINcode} 45 45 Allows Twittperator to access Twitter by signifying your PIN. 46 46 47 47 :tw[ittperator] 48 Shows recent your timeline. ( The timeline will be cashed and expired 90 seconds after Twittperator get from Twitter.)48 Shows recent your timeline. (The timeline will be cashed and expired 90 seconds after Twittperator get from Twitter.) 49 49 :tw[ittperator]! 50 50 Gets recent your timeline from Twitter and shows it. … … 73 73 ||< 74 74 and you will get the page to authorize Twittperator to access Twitter in a new tab. 75 If you allow and you will get the PIN ( 7 digits numbers), then yank it.75 If you allow and you will get the PIN (7 digit numbers), then yank it. 76 76 77 77 Secondarily, authorize Twittperator with your PIN. … … 280 280 } 281 281 return into; 282 } 282 }; 283 283 284 284 OAuth.setProperties(OAuth, // utility functions … … 307 307 s = s.replace(/\)/g, "%29"); 308 308 return s; 309 } 310 , 309 }, 311 310 decodePercent: function decodePercent(s) { 312 311 if (s != null) { … … 316 315 } 317 316 return decodeURIComponent(s); 318 } 319 , 317 }, 320 318 /** Convert the given parameters to an Array of name-value pairs. */ 321 319 getParameterList: function getParameterList(parameters) { … … 334 332 } 335 333 return list; 336 } 337 , 334 }, 338 335 /** Convert the given parameters to a map from name to value. */ 339 336 getParameterMap: function getParameterMap(parameters) { … … 355 352 } 356 353 return parameters; 357 } 358 , 354 }, 359 355 getParameter: function getParameter(parameters, name) { 360 356 if (!parameters instanceof Array) { … … 367 363 } 368 364 return null; 369 } 370 , 365 }, 371 366 formEncode: function formEncode(parameters) { 372 367 var form = ""; … … 380 375 } 381 376 return form; 382 } 383 , 377 }, 384 378 decodeForm: function decodeForm(form) { 385 379 var list = []; … … 403 397 } 404 398 return list; 405 } 406 , 399 }, 407 400 setParameter: function setParameter(message, name, value) { 408 401 var parameters = message.parameters; … … 426 419 message.parameters = parameters; 427 420 } 428 } 429 , 421 }, 430 422 setParameters: function setParameters(message, parameters) { 431 423 var list = OAuth.getParameterList(parameters); … … 433 425 OAuth.setParameter(message, list[i][0], list[i][1]); 434 426 } 435 } 436 , 427 }, 437 428 /** Fill in parameters to help construct a request message. 438 429 This function doesn't fill in every parameter. 439 430 The accessor object should be like: 440 {consumerKey:"foo", consumerSecret:"bar", accessorSecret:"nurn", token:"krelm", tokenSecret:"blah"} 431 { consumerKey: "foo", consumerSecret: "bar", accessorSecret: "nurn", 432 token: "krelm", tokenSecret: "blah" } 441 433 The accessorSecret property is optional. 442 434 */ … … 462 454 } 463 455 OAuth.SignatureMethod.sign(message, accessor); 464 } 465 , 456 }, 466 457 setTimestampAndNonce: function setTimestampAndNonce(message) { 467 458 OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp()); 468 459 OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6)); 469 } 470 , 460 }, 471 461 addToURL: function addToURL(url, parameters) { 472 462 newURL = url; … … 481 471 } 482 472 return newURL; 483 } 484 , 473 }, 485 474 /** Construct the value of the Authorization header for an HTTP request. */ 486 475 getAuthorizationHeader: function getAuthorizationHeader(realm, parameters) { … … 495 484 } 496 485 return header; 497 } 498 , 486 }, 499 487 /** Correct the time using a parameter from the URL from which the last script was loaded. */ 500 488 correctTimestampFromSrc: function correctTimestampFromSrc(parameterName) { … … 510 498 if (t == null) return; 511 499 OAuth.correctTimestamp(t); 512 } 513 , 500 }, 514 501 /** Generate timestamps starting with the given value. */ 515 502 correctTimestamp: function correctTimestamp(timestamp) { 516 503 OAuth.timeCorrectionMsec = (timestamp * 1000) - (new Date()).getTime(); 517 } 518 , 504 }, 519 505 /** The difference between the correct time and my clock. */ 520 timeCorrectionMsec: 0 521 , 506 timeCorrectionMsec: 0, 522 507 timestamp: function timestamp() { 523 508 var t = (new Date()).getTime() + OAuth.timeCorrectionMsec; 524 509 return Math.floor(t / 1000); 525 } 526 , 510 }, 527 511 nonce: function nonce(length) { 528 512 var chars = OAuth.nonce.CHARS; … … 567 551 OAuth.setParameter(message, "oauth_signature", signature); 568 552 return signature; // just in case someone's interested 569 } 570 , 553 }, 571 554 /** Set the key string for signing. */ 572 555 initialize: function initialize(name, accessor) { … … 586 569 587 570 /* SignatureMethod expects an accessor object to be like this: 588 {tokenSecret: "lakjsdflkj...", consumerSecret: "QOUEWRI..", accessorSecret: "xcmvzc..."} 571 { tokenSecret: "lakjsdflkj...", consumerSecret: "QOUEWRI..", 572 accessorSecret: "xcmvzc..." } 589 573 The accessorSecret property is optional. 590 574 */ … … 599 583 } 600 584 OAuth.SignatureMethod.newMethod(name, accessor).sign(message); 601 } 602 , 585 }, 603 586 /** Instantiate a SignatureMethod for the given method name. */ 604 587 newMethod: function newMethod(name, accessor) { … … 617 600 err.oauth_acceptable_signature_methods = acceptable; 618 601 throw err; 619 } 620 , 602 }, 621 603 /** A map from signature method name to constructor. */ 622 REGISTERED : {} 623 , 604 REGISTERED: {}, 624 605 /** Subsequently, the given constructor will be used for the named methods. 625 606 The constructor will be called with no parameters. … … 631 612 OAuth.SignatureMethod.REGISTERED[names[n]] = classConstructor; 632 613 } 633 } 634 , 614 }, 635 615 /** Create a subclass of OAuth.SignatureMethod, with the given getSignature function. */ 636 616 makeSubclass: function makeSubclass(getSignatureFunction) { … … 645 625 subClass.prototype.constructor = subClass; 646 626 return subClass; 647 } 648 , 627 }, 649 628 getBaseString: function getBaseString(message) { 650 629 var URL = message.action; … … 664 643 +"&"+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeUrl(URL)) 665 644 +"&"+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeParameters(parameters)); 666 } 667 , 645 }, 668 646 normalizeUrl: function normalizeUrl(url) { 669 647 var uri = OAuth.SignatureMethod.parseUri(url); … … 673 651 || (scheme == "https" && uri.port == 443); 674 652 if (dropPort) { 675 // find the last :in the authority653 // find the last ":" in the authority 676 654 var index = authority.lastIndexOf(":"); 677 655 if (index >= 0) { … … 685 663 // we know that there is no query and no fragment here. 686 664 return scheme + "://" + authority + path; 687 } 688 , 665 }, 689 666 parseUri: function parseUri(str) { 690 667 /* This function was adapted from parseUri 1.2.1 691 668 http://stevenlevithan.com/demo/parseuri/js/assets/parseuri.js 692 669 */ 693 var o = {key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], 694 parser: {strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ }}; 670 var o = { 671 key: ["source", "protocol", "authority", "userInfo", "user", 672 "password", "host", "port", "relative", "path", "directory", 673 "file", "query", "anchor"], 674 parser: { strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ } 675 }; 695 676 var m = o.parser.strict.exec(str); 696 677 var uri = {}; … … 698 679 while (i--) uri[o.key[i]] = m[i] || ""; 699 680 return uri; 700 } 701 , 681 }, 702 682 normalizeParameters: function normalizeParameters(parameters) { 703 683 if (parameters == null) { … … 711 691 sortable.push([ OAuth.percentEncode(nvp[0]) 712 692 + " " // because it comes before any character that can appear in a percentEncoded string. 713 + OAuth.percentEncode(nvp[1]) 714 ,nvp]);693 + OAuth.percentEncode(nvp[1]), 694 nvp]); 715 695 } 716 696 } 717 sortable.sort(function(a, b) {697 sortable.sort(function(a, b) { 718 698 if (a[0] < b[0]) return -1; 719 699 if (a[0] > b[0]) return 1; … … 729 709 730 710 OAuth.SignatureMethod.registerMethodClass(["PLAINTEXT", "PLAINTEXT-Accessor"], 731 OAuth.SignatureMethod.makeSubclass( 732 function getSignature(baseString) { 733 return this.key; 734 } 735 )); 711 OAuth.SignatureMethod.makeSubclass(function getSignature(baseString) this.key)); 736 712 737 713 OAuth.SignatureMethod.registerMethodClass(["HMAC-SHA1", "HMAC-SHA1-Accessor"], 738 OAuth.SignatureMethod.makeSubclass( 739 function getSignature(baseString) { 740 b64pad = "="; 741 var signature = b64_hmac_sha1(this.key, baseString); 742 return signature; 743 } 744 )); 714 OAuth.SignatureMethod.makeSubclass(function getSignature(baseString) { 715 b64pad = "="; 716 var signature = b64_hmac_sha1(this.key, baseString); 717 return signature; 718 })); 745 719 746 720 // oauth.js 2}}} … … 961 935 }, 962 936 // temp for request 963 request : {964 token :"", // response oauth_token937 request: { 938 token :"", // response oauth_token 965 939 tokenSecret: ""// response oauth_token_secret 966 940 }, 967 941 // トークンが取得済みかの真偽値を返す 968 isAuthorize : function() {942 isAuthorize: function() { 969 943 let accessor = this.getAccessor(); 970 944 if (accessor.consumerKey && accessor.consumerSecret && … … 976 950 getAccessor: function() { 977 951 return { 978 consumerKey: this.accessor.get("consumerKey", ""),979 consumerSecret: this.accessor.get("consumerSecret", ""),980 token: this.accessor.get("token", ""),981 tokenSecret: this.accessor.get("tokenSecret", "")952 consumerKey: this.accessor.get("consumerKey", ""), 953 consumerSecret: this.accessor.get("consumerSecret", ""), 954 token: this.accessor.get("token", ""), 955 tokenSecret: this.accessor.get("tokenSecret", "") 982 956 }; 983 957 }, 984 deleteAccessor : function() {958 deleteAccessor: function() { 985 959 var clientInfo = { 986 960 clientName: this.accessor.get("clientName", ""), 987 consumerKey: this.accessor.get("consumerKey", ""),988 consumerSecret: this.accessor.get("consumerSecret", ""),961 consumerKey: this.accessor.get("consumerKey", ""), 962 consumerSecret: this.accessor.get("consumerSecret", ""), 989 963 }; 990 964 this.accessor.clear(); … … 994 968 }, 995 969 // 認証ページのURLを取得 996 getRequestToken : function(callback) {970 getRequestToken: function(callback) { 997 971 let message = { 998 972 method: "GET", … … 1000 974 parameters: { 1001 975 oauth_signature_method: "HMAC-SHA1", 1002 oauth_consumer_key: this.accessor.get("consumerKey", "")976 oauth_consumer_key: this.accessor.get("consumerKey", "") 1003 977 } 1004 978 }; … … 1035 1009 }); 1036 1010 }, 1037 // pinを元にAccess Tokenを取得して保存、callbackにはaccessorオブジェクトを渡す1011 // PINを元にaccess tokenを取得して保存、callbackにはaccessorオブジェクトを渡す 1038 1012 getAccessToken: function(pin, callback) { 1039 1013 var message = { … … 1042 1016 parameters: { 1043 1017 oauth_signature_method: "HMAC-SHA1", 1044 oauth_consumer_key: this.accessor.get("consumerKey", ""),1018 oauth_consumer_key: this.accessor.get("consumerKey", ""), 1045 1019 oauth_token: this.request.token, // Request Token 1046 1020 oauth_verifier: pin … … 1056 1030 onload: function(d) { 1057 1031 if (d.status == 200) { 1058 /* 返り値から Access Token/Access Token Secretを取り出す */1032 /* 返り値からaccess token/access token secretを取り出す */ 1059 1033 var res = d.responseText; 1060 1034 var parameter = self.getParameter(res); … … 1076 1050 // api+?+query にアクセスした結果をcallbackに渡す 1077 1051 get: function(api, query, callback) { 1078 var btquery = (query)? "?"+this.buildQuery(query) : "";1052 var btquery = query ? "?" + this.buildQuery(query) : ""; 1079 1053 var message = { 1080 1054 method: "GET", 1081 action: api + btquery,1055 action: setting.apiURLBase + api + btquery, 1082 1056 parameters: { 1083 1057 oauth_signature_method: "HMAC-SHA1", 1084 oauth_consumer_key: this.accessor.get("consumerKey", ""),// queryの構築1085 oauth_token: this.accessor.get("token", "") // Access Token1058 oauth_consumer_key: this.accessor.get("consumerKey", ""), // Queryの構築 1059 oauth_token: this.accessor.get("token", "") // Access token 1086 1060 } 1087 1061 }; … … 1107 1081 var message = { 1108 1082 method: "POST", 1109 action: api,1083 action: setting.apiURLBase + api, 1110 1084 parameters: { 1111 1085 oauth_signature_method: "HMAC-SHA1", 1112 oauth_consumer_key: this.accessor.get("consumerKey", ""),1113 oauth_token: this.accessor.get("token", "") // Access Token1086 oauth_consumer_key: this.accessor.get("consumerKey", ""), 1087 oauth_token: this.accessor.get("token", "") // Access token 1114 1088 } 1115 1089 }; 1116 1090 // 送信するデータをパラメータに追加する 1117 for ( var key in content) {1091 for (var key in content) { 1118 1092 message.parameters[key] = content[key]; 1119 1093 } … … 1137 1111 Utils.xmlhttpRequest(options); // 送信 1138 1112 }, 1113 put: function(api, content, callback) { 1114 var message = { 1115 method: "PUT", 1116 action: setting.apiURLBase + api, 1117 parameters: { 1118 oauth_signature_method: "HMAC-SHA1", 1119 oauth_consumer_key: this.accessor.get("consumerKey", ""), 1120 oauth_token: this.accessor.get("token", "") // Access token 1121 } 1122 }; 1123 // 送信するデータをパラメータに追加する 1124 for (var key in content) { 1125 message.parameters[key] = content[key]; 1126 } 1127 OAuth.setTimestampAndNonce(message); 1128 OAuth.SignatureMethod.sign(message, this.getAccessor()); 1129 var target = OAuth.addToURL(message.action, message.parameters); 1130 var options = { 1131 method: message.method, 1132 url: target, 1133 onload: function(d) { 1134 if (d.status == 200) { 1135 if (callback) { 1136 callback(d.responseText); 1137 } 1138 } else { 1139 callback(d); 1140 } 1141 } 1142 }; 1143 Utils.xmlhttpRequest(options); // 送信 1144 }, 1145 delete: function(api, content, callback) { 1146 var btquery = query ? "?" + this.buildQuery(query) : ""; 1147 var message = { 1148 method: "DELETE", 1149 action: setting.apiURLBase + api + btquery, 1150 parameters: { 1151 oauth_signature_method: "HMAC-SHA1", 1152 oauth_consumer_key: this.accessor.get("consumerKey", ""), // Queryの構築 1153 oauth_token: this.accessor.get("token", "") // Access token 1154 } 1155 }; 1156 OAuth.setTimestampAndNonce(message); 1157 OAuth.SignatureMethod.sign(message, this.getAccessor()); 1158 var target = OAuth.addToURL(message.action, message.parameters); 1159 var options = { 1160 method: message.method, 1161 url: target, 1162 onload: function(d) { 1163 if (d.status == 200) { 1164 if (callback) { 1165 callback(d.responseText); 1166 } 1167 }else{ 1168 callback(d.statusText); 1169 } 1170 }, 1171 }; 1172 Utils.xmlhttpRequest(options); // 送信 1173 }, 1139 1174 getAuthorizationHeader: function(api) { 1140 1175 var message = { … … 1143 1178 parameters: { 1144 1179 oauth_signature_method: "HMAC-SHA1", 1145 oauth_consumer_key: this.accessor.get("consumerKey", ""),// queryの構築1146 oauth_token: this.accessor.get("token", ""), // Access Token1180 oauth_consumer_key: this.accessor.get("consumerKey", ""), // Queryの構築 1181 oauth_token: this.accessor.get("token", ""), // Access token 1147 1182 oauth_version: "1.0" 1148 1183 } … … 1152 1187 return OAuth.getAuthorizationHeader("Twitter", message.parameters); 1153 1188 }, 1154 // utility関数1189 // Utility関数 1155 1190 // http://kevin.vanzonneveld.net 1156 urlEncode : function(str) {1191 urlEncode: function(str) { 1157 1192 str = (str+"").toString(); 1158 1193 return encodeURIComponent(str).replace(/!/g, "%21").replace(/"/g, "%27").replace(/\(/g, "%28") … … 1160 1195 }, 1161 1196 // オブジェクトからクエリを生成 1162 buildQuery : function(formdata, numeric_prefix, arg_separator) {1163 // * example 1: http_build_query({ foo: "bar", php: "hypertext processor", baz: "boom", cow: "milk"}, "", "&");1164 // * returns 1: "foo=bar&php= hypertext+processor&baz=boom&cow=milk"1165 // * example 2: http_build_query({ "php": "hypertext processor", 0: "foo", 1: "bar", 2: "baz", 3: "boom", "cow": "milk"}, "myvar_");1166 // * returns 2: " php=hypertext+processor&myvar_0=foo&myvar_1=bar&myvar_2=baz&myvar_3=boom&cow=milk"1197 buildQuery: function(formdata, numeric_prefix, arg_separator) { 1198 // * example 1: http_build_query({ foo: "bar", php: "Hypertext Processor", baz: "boom", cow: "milk" }, "", "&"); 1199 // * returns 1: "foo=bar&php=Hypertext+Processor&baz=boom&cow=milk" 1200 // * example 2: http_build_query({ "PHP": "Hypertext Processor", 0: "foo", 1: "bar", 2: "baz", 3: "boom", "cow": "milk" }, "myvar_"); 1201 // * returns 2: "PHP=Hypertext+Processor&myvar_0=foo&myvar_1=bar&myvar_2=baz&myvar_3=boom&cow=milk" 1167 1202 var value, key, tmp = []; 1168 1203 var self = this; … … 1201 1236 return tmp.join(arg_separator); 1202 1237 }, 1203 // Query String から 連想配列を返す1238 // Query string から 連想配列を返す 1204 1239 getParameter: function(str) { 1205 var dec = decodeURIComponent; 1206 var par = {}, itm; 1207 if (typeof str == "undefined") return par; 1208 if (str.indexOf("?", 0) > -1) str = str.split("?")[1]; 1209 str = str.split("&"); 1210 for (var i = 0; str.length > i; i++) { 1211 itm = str[i].split("="); 1212 if (itm[0] != "") { 1213 par[itm[0]] = typeof itm[1] == "undefined" ? true : dec(itm[1]); 1214 } 1215 } 1216 return par; 1217 } 1218 }; 1219 return p; 1240 if (typeof str == "undefined") return {}; 1241 var itm; 1242 if (str.indexOf("?", 0) > -1) str = str.split("?", 2)[1]; 1243 var regex = str.indexOf("&") > str.indexOf(";") ? /;+/ : /&+/; 1244 return str.split(regex).reduce(function(r, v) { 1245 var kv = v.split("=", 2); 1246 if (kv[0] != "") { 1247 r[kv[0]] = typeof kv[1] == "undefined" ? true : decodeURIComponent(kv[1]); 1248 } 1249 return r; 1250 }, {}); 1251 } 1252 }; 1253 return p; 1220 1254 })(); 1221 1255 // }}} 1222 1256 1223 1257 // Twittperator 1224 function Stream({ host, path}) { // {{{1258 function Stream({ host, path }) { // {{{ 1225 1259 function extractURL(s) 1226 1260 let (m = s.match(/https?:\/\/\S+/)) … … 1235 1269 1236 1270 if (restartCount > 13) 1237 return liberator.echoerr( 'Twittperator: Gave up to connect to ChirpUserStream...');1238 1239 liberator.echoerr( 'Twittperator: ChirpUserStream will be restared...');1271 return liberator.echoerr("Twittperator: Gave up to connect to ChirpUserStream..."); 1272 1273 liberator.echoerr("Twittperator: ChirpUserStream will be restared..."); 1240 1274 1241 1275 // 試行済み回数^2 秒後にリトライ … … 1290 1324 null, 0, 1291 1325 useProxy ? setting.proxyHost : host, 1292 useProxy ? parseInt(setting.proxyPort || '3128', 10) : 80,1326 useProxy ? parseInt(setting.proxyPort || "3128", 10) : 80, 1293 1327 null); 1294 1328 let os = transport.openOutputStream(0, 0, 0); … … 1320 1354 for (let [, line] in Iterator(lines.slice(0, -1))) { 1321 1355 try { 1322 if (/^ \s*\{/(line))1356 if (/^[ \n\r\t]*\{/(line)) 1323 1357 onMsg(Utils.fixStatusObject(JSON.parse(line)), line); 1324 1358 } catch (e) { liberator.log(e); } … … 1328 1362 buf += data; 1329 1363 } 1330 } catch (e if /^ (?:NS_ERROR_NET_RESET|NS_BASE_STREAM_CLOSED)$/(e)) {1331 liberator.echoerr( 'Twittperator: ChirpStream was stopped by ' + e.name + '.');1364 } catch (e if /^NS_(?:ERROR_NET_RESET|BASE_STREAM_CLOSED)$/(e)) { 1365 liberator.echoerr("Twittperator: ChirpStream was stopped by " + e.name + "."); 1332 1366 restart(); 1333 1367 } catch (e) { 1334 liberator.echoerr( 'Twittperator: Unknown error on ChirpStream connection: '+ e.name);1368 liberator.echoerr("Twittperator: Unknown error on ChirpStream connection: " + e.name); 1335 1369 restart(); 1336 1370 } … … 1368 1402 }; 1369 1403 }; // }}} 1370 let ChirpUserStream = Stream({ host: "chirpstream.twitter.com", path: "/2b/user.json"});1404 let ChirpUserStream = Stream({ host: "chirpstream.twitter.com", path: "/2b/user.json" }); 1371 1405 let Twitter = { // {{{ 1372 1406 destroy: function(id) { // {{{ 1373 tw. post("http://api.twitter.com/1/statuses/destroy/" + id + ".json", null, function(text) {1407 tw.delete("statuses/destroy/" + id + ".json", null, function(text) { 1374 1408 let res = Utils.fixStatusObject(JSON.parse(text)); 1375 1409 Twittperator.echo("delete: " + res.user.name + " " + res.text) … … 1377 1411 }, // }}} 1378 1412 favorite: function(id) { // {{{ 1379 tw.post(" http://api.twitter.com/1/favorites/create/" + id + ".json", null, function(text) {1413 tw.post("favorites/create/" + id + ".json", null, function(text) { 1380 1414 let res = Utils.fixStatusObject(JSON.parse(text)); 1381 1415 Twittperator.echo("fav: " + res.user.name + " " + res.text) … … 1393 1427 onload(history); 1394 1428 } else { 1395 let api = " http://api.twitter.com/1/statuses/home_timeline.json", query = {};1429 let api = "statuses/home_timeline.json", query = {}; 1396 1430 1397 1431 if (target) { 1398 api = " http://api.twitter.com/1/statuses/user_timeline.json";1432 api = "statuses/user_timeline.json"; 1399 1433 query.screen_name = target; 1400 1434 } else { … … 1430 1464 let sendData = {}; 1431 1465 let prefix, replyUser, replyID, postfix; 1432 if (stat.match(/^(.*)@( [^\s#]+)(?:#(\d+))(.*)$/)) {1466 if (stat.match(/^(.*)@(\w{1,15})#(\d+)(.*)$/)) { 1433 1467 [prefix, replyUser, replyID, postfix] = [RegExp.$1, RegExp.$2, RegExp.$3, RegExp.$4]; 1434 1468 if (stat.indexOf("RT @" + replyUser + "#" + replyID) == 0) { 1435 1469 Twittperator.withProtectedUserConfirmation( 1436 { screenName: replyUser, statusId: replyID},1437 'retweet',1438 function() Twitter.re Tweet(replyID)1470 { screenName: replyUser, statusId: replyID }, 1471 "retweet", 1472 function() Twitter.retweet(replyID) 1439 1473 ); 1440 1474 return; … … 1445 1479 } 1446 1480 Twittperator.withProtectedUserConfirmation( 1447 { screenName: replyUser, statusId: replyID},1448 'reply',1481 { screenName: replyUser, statusId: replyID }, 1482 "reply", 1449 1483 function() { 1450 1484 sendData.status = stat; 1451 1485 sendData.source = "Twittperator"; 1452 tw.post(" http://api.twitter.com/1/statuses/update.json", sendData, function(text) {1486 tw.post("statuses/update.json", sendData, function(text) { 1453 1487 let t = Utils.fixStatusObject(JSON.parse(text || "{}")).text; 1454 1488 Twittperator.echo("Your post " + '"' + t + '" (' + t.length + " characters) was sent."); … … 1457 1491 ); 1458 1492 }, // }}} 1459 re Tweet: function(id) { // {{{1460 let url = " http://api.twitter.com/1/statuses/retweet/" + id + ".json";1461 tw.p ost(url, null, function(text) {1493 retweet: function(id) { // {{{ 1494 let url = "statuses/retweet/" + id + ".json"; 1495 tw.put(url, null, function(text) { 1462 1496 let res = Utils.fixStatusObject(JSON.parse(text)); 1463 Twittperator.echo("Re Tweet: " + res.retweeted_status.text);1497 Twittperator.echo("Retweet: " + res.retweeted_status.text); 1464 1498 }); 1465 1499 }, // }}} 1466 1500 unfavorite: function(id) { // {{{ 1467 tw. post("http://api.twitter.com/1/favorites/destroy/" + id + ".json", null, function(text) {1501 tw.delete("favorites/destroy/" + id + ".json", null, function(text) { 1468 1502 let res = Utils.fixStatusObject(JSON.parse(text)); 1469 1503 Twittperator.echo("unfav: " + res.user.name + " " + res.text, true); … … 1480 1514 let [head, tail] = [center[0], center.slice(1)]; 1481 1515 let right = str.substring(m.index + m[0].length); 1482 let content = head === "@" ? <a highlight="URL" href={ "http://twitter.com/" + tail}> {center} </a>1483 : <a highlight="URL" href={center}> {center} </a> 1516 let content = head === "@" ? <a highlight="URL" href={setting.showTLURLScheme + "://twitter.com/" + tail}> {center} </a> 1517 : <a highlight="URL" href={center}> {center} </a>; 1484 1518 return <>{Utils.anchorLink(left)}{content}{Utils.anchorLink(right)}</>; 1485 1519 } … … 1487 1521 }, // }}} 1488 1522 fixStatusObject: function(st) { // {{{ 1489 const Amps= {1523 const ENTITIY_PAIRS = { 1490 1524 lt: "<", 1491 1525 gt: ">", 1492 quot: "\"",1526 quot: '"' 1493 1527 hellip: "\u2026", 1494 1528 }; 1495 1529 1496 function unescapeAmps(str) 1497 str.replace(/&([^;]+);/g, function(m, n) Amps[n] || m); 1530 function unescapeSpecificEntities(str) 1531 str.replace(/&([a-z\d]+);/g, function(m, n) ENTITIY_PAIRS[n] || m); 1532 1533 function unescapeBrakets(str) 1534 str.replace(/</g, "<").replace(/>/g, ">"); 1498 1535 1499 1536 let result = {}; 1500 1537 for (let [n, v] in Iterator(st)) { 1501 result[n] = v && typeof v === 'object'? Utils.fixStatusObject(v) :1502 n === 'text' ? unescapeAmps(v) :1538 result[n] = v && typeof v === "object" ? Utils.fixStatusObject(v) : 1539 n === "text" ? unescapeBrakets(v) : 1503 1540 v; 1504 1541 } … … 1520 1557 liberator.echo("[Twittperator] " + msg); 1521 1558 }, // }}} 1522 isProtected: function({statusId, userId, screenName}) { // {{{ 1559 isProtected: function({ statusId, userId, screenName }) { // {{{ 1560 if (screenName && isp(function(st) st.user && st.user.screen_name == screenName)) 1561 return true; 1562 1563 if (statusId && isp(function(st) st.user && st.id == statusId)) 1564 return true; 1565 1566 if (userId && find(function(st) st.user && st.user.id == userId)) 1567 return true; 1568 1569 return false; 1570 1523 1571 function isp(f) { 1524 1572 let r; 1525 1573 history.some(function(st) f(st) && (r = st)); 1526 return r && r.user.protected && r.user.screen_name;1574 return (r && r.user.protected && r.user.screen_name) ? true : false; 1527 1575 } 1528 1529 if (screenName && isp(function(st) st.user && st.user.screen_name == screenName))1530 return true;1531 1532 if (statusId && isp(function(st) st.user && st.id == statusId))1533 return true;1534 1535 if (userId && find(function(st) st.user && st.user.id == userId))1536 return true;1537 1538 return false;1539 1576 }, // }}} 1540 1577 loadPlugins: function() { // {{{ … … 1637 1674 }, // }}} 1638 1675 showTwitterMentions: function(arg) { // {{{ 1639 tw.get(" http://api.twitter.com/1/statuses/mentions.json", null, function(text) {1676 tw.get("statuses/mentions.json", null, function(text) { 1640 1677 Twittperator.showTL(JSON.parse(text).map(Utils.fixStatusObject)); 1641 1678 }); … … 1679 1716 withProtectedUserConfirmation: function(check, actionName, action) { // {{{ 1680 1717 function canceled() 1681 Twittperator.echo( 'Canceled.');1718 Twittperator.echo("Canceled."); 1682 1719 1683 1720 let protectedUserName = Twittperator.isProtected(check); 1684 1721 if (protectedUserName) { 1685 1722 commandline.input( 1686 protectedUserName + ' is protected user! Do you really want to '+ actionName + '? Input "yes" if you want. => ',1687 function(s) (s === 'yes'? action : canceled)(),1723 protectedUserName + " is protected user! Do you really want to " + actionName + '? Input "yes" if you want. => ', 1724 function(s) (s === "yes" ? action : canceled)(), 1688 1725 { 1689 1726 onCancel: canceled … … 1734 1771 get expr() { 1735 1772 return RegExp( 1736 '^'+1773 "^" + 1737 1774 this.command.map(function(c) 1738 1775 let (r = util.escapeRegex(c)) 1739 (/^\W$/(c) ? r : r + ' ')1740 ).join("|" /* /|/ */)1776 (/^\W$/(c) ? r : r + " ") 1777 ).join("|") 1741 1778 ); 1742 1779 }, 1743 1780 match: function(s) s.match(this.expr), 1744 action: function(args) init.action(args.literalArg.replace(this.expr, '').trim())1781 action: function(args) init.action(args.literalArg.replace(this.expr, "").trim()) 1745 1782 }; 1746 1783 }; … … 1771 1808 description: "Show mentions or follower tweets", 1772 1809 action: function(arg) { 1773 if (arg. match(/^.+/)) {1810 if (arg.length > 0) { 1774 1811 Twittperator.showFollowersStatus(arg, true); 1775 1812 } else { … … 1904 1941 return; 1905 1942 context.title = ["Sub command", "Description"]; 1906 context.completions = SubCommands.map(function({ command, description}) [command[0], description]);1943 context.completions = SubCommands.map(function({ command, description }) [command[0], description]); 1907 1944 } // }}} 1908 1945 … … 1987 2024 proxyHost: gv.twittperator_proxy_host, 1988 2025 proxyPort: gv.twittperator_proxy_port, 1989 screenName: gv.twittperator_screen_name 2026 screenName: gv.twittperator_screen_name, 2027 apiURLBase: "http" + (!!gv.twittperator_use_ssl_connection_for_api_ep ? "s" : "") + 2028 "://api.twitter.com/" + (gv.twittperator_twitter_api_version || 1) + "/", 1990 2029 }); 1991 2030
![(please configure the [header_logo] section in trac.ini)](/share/chrome/site/your_project_logo.png)