├── .gitignore ├── README.md ├── css ├── jquery.mobile.simpledialog.css ├── jquery.swipeButton-1.0.1.css └── style.css ├── img ├── ajax_loader.gif ├── apple-touch-icon-114x114-precomposed.png ├── apple-touch-icon-72x72-precomposed.png ├── apple-touch-icon-precomposed.png ├── circle_green.png ├── circle_red.png ├── error_facebook.png ├── error_twitter.png ├── facebook_icon.png ├── favicon.png ├── google_article.png ├── google_icon.png ├── google_photo.png ├── google_video.png ├── ok_facebook.png ├── ok_twitter.png ├── people_icon.png ├── posts_icon.png ├── twitter_favourite.png ├── twitter_icon.png ├── twitter_reply.png ├── twitter_retweet.png └── twitter_verified.png ├── index.html ├── js ├── amplify.store.min.js ├── handlebars-1.0.0.beta.6.js ├── jquery.ba-serializeobject.js ├── jquery.cookie.js ├── jquery.deserialize.js ├── jquery.mobile.simpledialog2.js ├── jquery.oauthpopup.js ├── jquery.prettydate.js ├── jquery.swipeButton-1.1.js ├── json2.js └── scripts.js └── php ├── EpiCurl.php ├── EpiOAuth.php ├── EpiTwitter.php ├── facebook_auth.php ├── facebook_keys.php ├── facebook_sign_out.php ├── twitter_auth.php ├── twitter_keys.php ├── twitter_search_people.php └── twitter_sign_out.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | social-web-search 2 | ================= 3 | 4 | Search the social web... Find people & posts on Twitter, Facebook and Google+. 5 | 6 | Live Demo: http://sws.jensdriller.com 7 | -------------------------------------------------------------------------------- /css/jquery.mobile.simpledialog.css: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Mobile Framework : plugin to provide a simple Dialog widget. 3 | * Copyright (c) JTSage 4 | * CC 3.0 Attribution. May be relicensed without permission/notifcation. 5 | * https://github.com/jtsage/jquery-mobile-simpledialog 6 | */ 7 | 8 | /* Shared Styles */ 9 | 10 | .ui-simpledialog-header h4 { margin-top: 5px; margin-bottom: 5px; text-align: center; } 11 | .ui-simpledialog-container { border: 5px solid #111 !important; width:85%; max-width:500px;} 12 | .ui-simpledialog-screen { position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; } 13 | .ui-simpledialog-hidden { display: none; } 14 | .ui-simpledialog-input { width: 85% !important; display: block !important; margin-left: auto; margin-right: auto;} 15 | .ui-simpledialog-screen-modal { background-color: black; -moz-opacity: 0.8; opacity:.80; filter: alpha(opacity=80); } 16 | .ui-simpledialog-subtitle { text-align: center; } 17 | .ui-simpledialog-controls .buttons-separator {min-height: .6em;} 18 | .ui-simpledialog-controls .button-hidden { display:none; } 19 | 20 | .ui-dialog .ui-simpledialog-container { border: none !important; } 21 | .ui-dialog-simpledialog .ui-content { padding: 5px !important;} -------------------------------------------------------------------------------- /css/jquery.swipeButton-1.0.1.css: -------------------------------------------------------------------------------- 1 | /* 2 | Name: jquery.swipeButton.css 3 | Author: Andy andyMatthews 4 | Website: http://andyMatthews.net 5 | Packed With: http://jsutility.pjoneil.net/ 6 | Version: 1.0.1 7 | */ 8 | li[data-swipeurl] .ui-btn { 9 | margin: 30px; 10 | float: right; 11 | font-size: 12px; 12 | margin: 4px 4px 0 0 !important; 13 | padding: 0; 14 | z-index: 100; 15 | border-radius: .5em; 16 | } 17 | li[data-swipeurl] .ui-btn .ui-btn-inner { 18 | padding: 0.6em .9em !important; 19 | } 20 | li[data-swipeurl] .ui-btn .ui-btn-corner-all { 21 | border-radius: .5em; 22 | } -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | /*******************/ 2 | /* GENERAL STUFF */ 3 | /*******************/ 4 | body { 5 | text-align: center; 6 | } 7 | 8 | .ui-header { 9 | background: #3B5998; 10 | } 11 | 12 | a.ui-mini.ui-input-clear { 13 | right: 0 !important; 14 | } 15 | 16 | a.profileLink, a.profileLink:visited { 17 | color: #2489CE; 18 | font-weight: bold; 19 | } 20 | 21 | li.loadingAnimation img { 22 | margin: 25% 50%; 23 | } 24 | 25 | .ui-header .ui-title { 26 | margin-left: 0; 27 | margin-right: 0; 28 | white-space: normal; 29 | } 30 | 31 | .ui-li .ui-btn-text a { 32 | white-space: normal !important; 33 | overflow: visible !important; 34 | } 35 | 36 | 37 | 38 | /***************/ 39 | /* HOME PAGE */ 40 | /***************/ 41 | form#searchFormHome, form#searchForm { 42 | padding: 0 20px 15px 20px; 43 | } 44 | 45 | #btnAuthFacebook img, #btnAuthTwitter img { 46 | padding-right: 0.4em; 47 | } 48 | 49 | form#searchFormHome #lblPosts, form#searchFormHome #lblPeople { 50 | display: block; 51 | } 52 | 53 | #formFirstRow { 54 | width: 300px; 55 | margin: 0 auto; 56 | } 57 | 58 | #formFirstRow #searchPlatforms { 59 | float: left; 60 | margin-right: 1em; 61 | } 62 | 63 | #formSecondRow .ui-block-b .ui-btn { 64 | display: block !important; 65 | } 66 | 67 | #formSecondRow .ui-block-b .ui-mini { 68 | margin: .25em 5px; 69 | } 70 | 71 | span#facebookUser img, span#twitterUser img { 72 | margin-right: 0.5em; 73 | -webkit-border-radius: 5px; 74 | -moz-border-radius: 5px; 75 | border-radius: 5px; 76 | border: 1px solid #CCCCCC; 77 | } 78 | 79 | div#home a[href='#preferences'] { 80 | margin: 0; 81 | } 82 | span#facebookUser img, span#facebookUser span, span#twitterUser img, span#twitterUser span { 83 | vertical-align: middle; 84 | } 85 | 86 | div#authTwitter { 87 | margin-top: 1em; 88 | } 89 | 90 | div#authFacebook { 91 | margin-top: 0.5em; 92 | } 93 | img.socialNetworkImg { 94 | display: block; 95 | } 96 | 97 | 98 | /*********************/ 99 | /* TRENDING TOPICS */ 100 | /*********************/ 101 | ul#trendingTopicsList img.twitterThumbnail { 102 | float: left; 103 | margin: 0 0.5em; 104 | padding-top: 10px; 105 | } 106 | 107 | div#trendingTopicsWrapper span.ui-btn-inner { 108 | text-align: center; 109 | } 110 | 111 | 112 | 113 | /********************/ 114 | /* RECENT QUERIES */ 115 | /********************/ 116 | ul#recentQueries { 117 | display: none; 118 | } 119 | 120 | ul#recentQueries .ui-bar-b { 121 | border: none; 122 | } 123 | 124 | ul#recentQueries img { 125 | float: left; 126 | margin-left: 0.5em; 127 | padding-top: 0.6em; 128 | } 129 | 130 | ul#recentQueries div.type { 131 | float: left; 132 | } 133 | 134 | ul#recentQueries div.arrow { 135 | float: left; 136 | padding-top: 0.6em; 137 | padding-left: 0.6em; 138 | } 139 | 140 | ul#recentQueries div.platforms img:last-child { 141 | margin-right: 0.7em; 142 | } 143 | 144 | 145 | 146 | /******************/ 147 | /* SEARCH PAGE */ 148 | /******************/ 149 | span#searchType { 150 | font-style: italic; 151 | } 152 | 153 | span#searchPlatform img { 154 | margin-right: 5px; 155 | } 156 | 157 | div#search a.linkAuthFacebook, div#search a.linkAuthTwitter { 158 | color: #2489CE; 159 | font-weight: bold; 160 | } 161 | 162 | div#search a.linkAuthFacebook:visited, div#search a.linkAuthTwitter:visited { 163 | color: #2489CE; 164 | } 165 | 166 | div#search a.linkAuthFacebook:hover, div#search a.linkAuthTwitter:hover { 167 | cursor: pointer; 168 | } 169 | 170 | div#search div.ui-block-b .ui-btn { 171 | display: block; 172 | } 173 | 174 | div#search div.ui-block-b .ui-mini { 175 | margin: 0.25em 5px; 176 | } 177 | 178 | @media (max-width: 450px) { 179 | span#searchPlatform { 180 | display: block; 181 | margin-top: 0.2em; 182 | } 183 | } 184 | 185 | 186 | 187 | /**************************/ 188 | /* RESULT LISTS GENERAL */ 189 | /**************************/ 190 | .ui-content .ui-listview { 191 | margin-bottom: 15px; 192 | } 193 | 194 | ul.resultList a { 195 | text-decoration: none; 196 | color: #333; 197 | } 198 | 199 | ul.resultList a:hover { 200 | text-decoration: underline; 201 | } 202 | 203 | ul.resultList p.post a { 204 | color: #666666; 205 | text-decoration: underline; 206 | } 207 | 208 | ul.resultList img.thumbnail { 209 | -webkit-border-radius: 5px; 210 | -moz-border-radius: 5px; 211 | border-radius: 5px; 212 | border: 1px solid #CCCCCC; 213 | } 214 | 215 | ul.resultList li.loadMore { 216 | background: #FADB4E; 217 | background-image: -webkit-linear-gradient(#FFEFAA,#FFE155); 218 | background-image: -moz-linear-gradient(#FFEFAA,#FFE155); 219 | background-image: -o-linear-gradient(#FFEFAA,#FFE155); 220 | background-image: -ms-linear-gradient(#FFEFAA,#FFE155); 221 | background-image: linear-gradient(#FFEFAA,#FFE155); 222 | } 223 | 224 | ul.resultList p.img_wrapper { 225 | float: left; 226 | margin-right: 1em; 227 | margin-bottom: 0; 228 | } 229 | 230 | ul.resultList li.loadMore div { 231 | text-align: center !important; 232 | } 233 | 234 | ul.resultList .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li { 235 | padding: 1.2em 15px 0.8em 15px; 236 | } 237 | 238 | ul.resultList li.divider img { 239 | padding-left: 0.6em; 240 | padding-top: 0.5em; 241 | } 242 | 243 | ul.resultList li.divider { 244 | padding: 0.7em 0 0.7em 2.6em !important; 245 | } 246 | 247 | ul.resultList li.loadMore a.ui-link-inherit { 248 | padding: 0.7em 15px 0.7em 15px !important; 249 | } 250 | 251 | ul.resultList li.error { 252 | padding-top: 1.3em; 253 | padding-bottom: 0.9em !important; 254 | } 255 | 256 | ul.resultList li.error p { 257 | margin-bottom: 0; 258 | } 259 | 260 | ul.resultList .ui-li-aside { 261 | width: auto; 262 | } 263 | 264 | ul.resultList span.name { 265 | font-size: 16px; 266 | font-weight: bold; 267 | display: block; 268 | margin-top: 0.2em; 269 | margin-left: 0.6em; 270 | } 271 | 272 | ul.resultList li.ui-li-has-count { 273 | padding-right: 80px; 274 | } 275 | 276 | ul.resultList li.posts span.name { 277 | padding-right: 80px; 278 | } 279 | 280 | ul.resultList li.posts span.text-only { 281 | display: block; 282 | margin-bottom: 0.5em; 283 | } 284 | 285 | ul.resultList li.posts span.attachment { 286 | display:block; 287 | clear: both; 288 | padding-top: 0.5em; 289 | } 290 | 291 | ul.resultList .ui-li .ui-li-heading a, .ui-li-desc { 292 | white-space: normal !important; 293 | } 294 | 295 | ul.resultList li.posts span.attachment img.preview { 296 | margin-top: 0.4em; 297 | } 298 | 299 | 300 | 301 | /******************/ 302 | /* TWITTER LIST */ 303 | /******************/ 304 | ul#twitterList a.twitterLink { 305 | color: #2489CE; 306 | font-weight: bold; 307 | } 308 | 309 | ul#twitterList span.screenName { 310 | color: #777; 311 | font-size: 0.9em; 312 | display: block; 313 | } 314 | 315 | ul.resultList span.post { 316 | font-size: 12px; 317 | font-weight: normal; 318 | display: block; 319 | margin-top: 0.2em; 320 | } 321 | 322 | ul#twitterList li.people span.latestTweet a.timestamp { 323 | color: #666; 324 | } 325 | 326 | ul.resultList li.people span.name { 327 | margin-top: -0.4em; 328 | margin-left: 3.9em; 329 | } 330 | 331 | ul#twitterList li.people span.description { 332 | font-size: 12px; 333 | font-weight: normal; 334 | font-style: italic; 335 | margin-top: 0.35em; 336 | display: block; 337 | } 338 | 339 | ul#twitterList li.people span.description { 340 | font-size: 12px; 341 | font-weight: normal; 342 | font-style: italic; 343 | margin-top: 0.35em; 344 | display: block; 345 | } 346 | 347 | ul#twitterList li.people span.latestTweet { 348 | font-size: 12px; 349 | font-weight: normal; 350 | display: block; 351 | clear: both; 352 | margin-top: 1em; 353 | } 354 | 355 | ul#twitterList li.people span.latestTweetLabel { 356 | font-weight: bold; 357 | } 358 | 359 | ul#twitterList li.posts span.name { 360 | margin-top: 0; 361 | } 362 | 363 | ul#twitterList li.posts span.replyLinks { 364 | font-size: 12px; 365 | font-weight: normal; 366 | display: block; 367 | margin-top: 0.25em; 368 | } 369 | 370 | ul#twitterList li.posts span.replyLinks a { 371 | margin-right: 1em; 372 | } 373 | 374 | 375 | 376 | /*******************/ 377 | /* FACEBOOK LIST */ 378 | /*******************/ 379 | ul#facebookList li.people.ui-li-static.ui-li { 380 | padding-bottom: 2.1em; 381 | } 382 | 383 | ul#facebookList li.people span.name { 384 | margin-top: 0.6em; 385 | } 386 | 387 | ul#facebookList li.posts span.post img { 388 | margin-right: 0.5em; 389 | } 390 | 391 | 392 | 393 | /*****************/ 394 | /* GOOGLE LIST */ 395 | /*****************/ 396 | ul#googleList li.people.ui-li-static.ui-li { 397 | padding-bottom: 2.1em; 398 | } 399 | 400 | ul#googleList li.people span.name { 401 | margin-top: 0.6em; 402 | } 403 | 404 | ul#googleList li.posts span.attachment img { 405 | margin-right: 0.2em; 406 | } 407 | 408 | 409 | 410 | /**********************/ 411 | /* PREFERENCES PAGE */ 412 | /**********************/ 413 | @media (min-width: 450px) { 414 | .ui-field-contain .ui-controlgroup-controls { 415 | width: 35%; 416 | } 417 | } 418 | 419 | @media (max-width: 450px) { 420 | .controlsWrapper { 421 | margin: 0 auto; 422 | width: 250px; 423 | } 424 | } 425 | 426 | 427 | 428 | /*************************/ 429 | /* AUTHENTICATION PAGE */ 430 | /*************************/ 431 | div.authError { 432 | display: none; 433 | } 434 | p.user img { 435 | margin-right: 0.5em; 436 | -webkit-border-radius: 5px; 437 | -moz-border-radius: 5px; 438 | border-radius: 5px; 439 | border: 1px solid #CCCCCC; 440 | } 441 | p.user img, p.user span { 442 | vertical-align: middle; 443 | font-weight: bold; 444 | } 445 | 446 | 447 | 448 | /***************/ 449 | /* INFO PAGE */ 450 | /***************/ 451 | div#info div.row { 452 | margin-top: 0.8em; 453 | } 454 | div#info div#networks { 455 | width: 115px; 456 | text-align: left; 457 | margin: 0 auto; 458 | margin-bottom: 2em; 459 | } 460 | div#info div.row img { 461 | vertical-align: middle; 462 | margin-right: 0.2em; 463 | } 464 | div#info div#about p { 465 | margin-bottom: 2em; 466 | } 467 | div#info div#about span { 468 | margin-bottom: 0.3em; 469 | display: block; 470 | font-weight: bold; 471 | } 472 | div#info p#author { 473 | margin-bottom: 0 !important; 474 | } 475 | div#info p#contact img { 476 | margin-right: 0.5em; 477 | } 478 | 479 | 480 | 481 | /***************/ 482 | /* COPYRIGHT */ 483 | /***************/ 484 | div.copyright { 485 | color: #CCCCCC; 486 | font-weight: bold; 487 | } -------------------------------------------------------------------------------- /img/ajax_loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/ajax_loader.gif -------------------------------------------------------------------------------- /img/apple-touch-icon-114x114-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/apple-touch-icon-114x114-precomposed.png -------------------------------------------------------------------------------- /img/apple-touch-icon-72x72-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/apple-touch-icon-72x72-precomposed.png -------------------------------------------------------------------------------- /img/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /img/circle_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/circle_green.png -------------------------------------------------------------------------------- /img/circle_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/circle_red.png -------------------------------------------------------------------------------- /img/error_facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/error_facebook.png -------------------------------------------------------------------------------- /img/error_twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/error_twitter.png -------------------------------------------------------------------------------- /img/facebook_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/facebook_icon.png -------------------------------------------------------------------------------- /img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/favicon.png -------------------------------------------------------------------------------- /img/google_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/google_article.png -------------------------------------------------------------------------------- /img/google_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/google_icon.png -------------------------------------------------------------------------------- /img/google_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/google_photo.png -------------------------------------------------------------------------------- /img/google_video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/google_video.png -------------------------------------------------------------------------------- /img/ok_facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/ok_facebook.png -------------------------------------------------------------------------------- /img/ok_twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/ok_twitter.png -------------------------------------------------------------------------------- /img/people_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/people_icon.png -------------------------------------------------------------------------------- /img/posts_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/posts_icon.png -------------------------------------------------------------------------------- /img/twitter_favourite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/twitter_favourite.png -------------------------------------------------------------------------------- /img/twitter_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/twitter_icon.png -------------------------------------------------------------------------------- /img/twitter_reply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/twitter_reply.png -------------------------------------------------------------------------------- /img/twitter_retweet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/twitter_retweet.png -------------------------------------------------------------------------------- /img/twitter_verified.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenzz/social-web-search/75b62b947a13857bddc194109f19dfa958ee0d36/img/twitter_verified.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Social Web Search 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
47 | 48 |
49 | 50 | Info 51 |

Social Web Search

52 | 53 |
54 | 55 |
56 | 57 |
58 | 59 | 60 | 64 | 65 | 66 | 70 | 71 | 72 | 76 | 77 |
78 | 79 |
80 | 81 | 82 | 86 | 87 | 88 | 92 | 93 | 94 |
95 | 96 |
97 | 98 |
99 | 100 |
101 | 102 |
103 | 104 |
105 | 106 |
107 | 108 |
109 | 110 |
111 | 112 |
113 | 114 |
115 | 116 |
117 |

Trending Topics

118 |

Trending topics are currently only supported by Twitter.

119 |
    120 |
    121 | 122 | 125 | 126 | Preferences 127 | 128 |
    129 | 130 | TwitterAuth with Twitter 131 |
    132 | 133 |
    134 | 135 | FacebookAuth with Facebook 136 |
    137 | 138 |
    139 | 140 | 143 | 144 |
    145 | 146 | 147 | 148 | 149 | 150 | 181 | 182 | 183 | 184 | 185 | 186 |
    187 | 188 |
    189 | 190 |

    Preferences

    191 | Back 192 | 193 |
    194 | 195 |
    196 | 197 |
    198 |
    199 | 200 | Number of recent queries shown 201 | 202 |
    203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 |
    215 | 216 |
    217 |
    218 | 219 |
    220 |
    221 | 222 | Recent search queries delete mode 223 | 224 |
    225 | 226 | 227 | 228 | 229 |
    230 | 231 |
    232 |
    233 | 234 |
    235 |
    236 | 237 | Post results shown per social network per page 238 | 239 |
    240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 |
    252 | 253 |
    254 |
    255 | 256 |
    257 |
    258 | 259 | People results shown per social network per page 260 | 261 |
    262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 |
    274 | 275 |
    276 |
    277 | 278 |
    279 |
    280 | 281 | Trending topics by default 282 | 283 |
    284 | 285 | 286 | 287 | 288 | 289 |
    290 | 291 |
    292 |
    293 | 294 | 295 | 296 |
    297 |
    298 | 299 | Search results display mode 300 | 301 |
    302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 |
    310 | 311 |
    312 |
    313 | 314 |
    315 | 316 |
    317 | Back to home screen 318 | 319 |
    320 | 321 | 324 | 325 |
    326 | 327 | 328 | 329 | 330 | 331 |
    332 | 333 |
    334 | 335 |

    Social Web Search

    336 | Home 337 | 338 |
    339 | 340 |
    341 | 342 |

    This mobile web app allows you to search for people and posts
    on the three main social networks:

    343 | 344 |
    345 | 346 |
    347 | Twitter 348 | Twitter 349 |
    350 |
    351 | Facebook 352 | Facebook 353 |
    354 |
    355 | Google 356 | Google+ 357 |
    358 | 359 |
    360 | 361 |
    362 | 363 |

    364 | Based on: 365 | jQuery 1.7.1 and 366 | jQuery Mobile 1.1.0 367 |

    368 |

    369 | A project by: 370 | Jens Driller
    371 | University of Kent
    372 | jd428 [at] kent.ac.uk 373 |

    374 |

    375 | Twitter 376 | Facebook 377 | Google 378 |

    379 | 380 |
    381 | 382 | Back to home screen 383 | 384 |
    385 | 386 | 389 | 390 |
    391 | 392 | 393 | 394 | 395 | 396 |
    397 | 398 |
    399 | 400 |

    Social Web Search

    401 | Home 402 | 403 |
    404 | 405 |
    406 | 407 |
    408 | OK 409 |

    410 |

    You have been authorised successfully.

    411 |

    You can now start searching for people on Twitter.

    412 |
    413 | 414 |
    415 | Error 416 |

    You have cancelled the authentication or an error occurred.

    417 |
    418 | 419 |
    Back to home screen 420 | 421 |
    422 | 423 | 426 | 427 |
    428 | 429 | 430 | 431 | 432 | 433 |
    434 | 435 |
    436 | 437 |

    Social Web Search

    438 | Home 439 | 440 |
    441 | 442 |
    443 | 444 |
    445 | OK 446 |

    447 |

    You have been authorised successfully.

    448 |

    You can now start searching for people on Facebook.

    449 |
    450 | 451 |
    452 | OK 453 |

    You have cancelled the authentication or an error occurred.

    454 |
    455 | 456 |
    Back to home screen 457 | 458 |
    459 | 460 | 463 | 464 |
    465 | 466 | 467 | 468 | 469 | 470 |
    471 | 472 |
    473 | 474 |

    Social Web Search

    475 | Home 476 | 477 |
    478 | 479 |
    480 | 481 |

    482 |

    You were successfully logged out from Twitter.

    483 | 484 |
    Back to home screen 485 | 486 |
    487 | 488 | 491 | 492 |
    493 | 494 | 495 | 496 | 497 | 498 |
    499 | 500 |
    501 | 502 |

    Social Web Search

    503 | Home 504 | 505 |
    506 | 507 |
    508 | 509 |

    510 |

    You were successfully logged out from Facebook.

    511 | 512 |
    Back to home screen 513 | 514 |
    515 | 516 | 519 | 520 |
    521 | 522 | 523 | 524 | 525 | 526 | 557 | 558 | 582 | 583 | 603 | 604 | 618 | 619 | 639 | 640 | 654 | 655 | 656 | -------------------------------------------------------------------------------- /js/amplify.store.min.js: -------------------------------------------------------------------------------- 1 | (function(a,b){function e(a,e){c.addType(a,function(f,g,h){var i,j,k,l,m=g,n=(new Date).getTime();if(!f){m={},l=[],k=0;try{f=e.length;while(f=e.key(k++))d.test(f)&&(j=JSON.parse(e.getItem(f)),j.expires&&j.expires<=n?l.push(f):m[f.replace(d,"")]=j.data);while(f=l.pop())e.removeItem(f)}catch(o){}return m}f="__amplify__"+f;if(g===b){i=e.getItem(f),j=i?JSON.parse(i):{expires:-1};if(j.expires&&j.expires<=n)e.removeItem(f);else return j.data}else if(g===null)e.removeItem(f);else{j=JSON.stringify({data:g,expires:h.expires?n+h.expires:null});try{e.setItem(f,j)}catch(o){c[a]();try{e.setItem(f,j)}catch(o){throw c.error()}}}return m})}var c=a.store=function(a,b,d,e){var e=c.type;d&&d.type&&d.type in c.types&&(e=d.type);return c.types[e](a,b,d||{})};c.types={},c.type=null,c.addType=function(a,b){c.type||(c.type=a),c.types[a]=b,c[a]=function(b,d,e){e=e||{},e.type=a;return c(b,d,e)}},c.error=function(){return"amplify.store quota exceeded"};var d=/^__amplify__/;for(var f in{localStorage:1,sessionStorage:1})try{window[f].getItem&&e(f,window[f])}catch(g){}if(window.globalStorage)try{e("globalStorage",window.globalStorage[window.location.hostname]),c.type==="sessionStorage"&&(c.type="globalStorage")}catch(g){}(function(){if(!c.types.localStorage){var a=document.createElement("div"),d="amplify";a.style.display="none",document.getElementsByTagName("head")[0].appendChild(a);try{a.addBehavior("#default#userdata"),a.load(d)}catch(e){a.parentNode.removeChild(a);return}c.addType("userData",function(e,f,g){a.load(d);var h,i,j,k,l,m=f,n=(new Date).getTime();if(!e){m={},l=[],k=0;while(h=a.XMLDocument.documentElement.attributes[k++])i=JSON.parse(h.value),i.expires&&i.expires<=n?l.push(h.name):m[h.name]=i.data;while(e=l.pop())a.removeAttribute(e);a.save(d);return m}e=e.replace(/[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/g,"-");if(f===b){h=a.getAttribute(e),i=h?JSON.parse(h):{expires:-1};if(i.expires&&i.expires<=n)a.removeAttribute(e);else return i.data}else f===null?a.removeAttribute(e):(j=a.getAttribute(e),i=JSON.stringify({data:f,expires:g.expires?n+g.expires:null}),a.setAttribute(e,i));try{a.save(d)}catch(o){j===null?a.removeAttribute(e):a.setAttribute(e,j),c.userData();try{a.setAttribute(e,i),a.save(d)}catch(o){j===null?a.removeAttribute(e):a.setAttribute(e,j);throw c.error()}}return m})}})(),function(){function e(a){return a===b?b:JSON.parse(JSON.stringify(a))}var a={},d={};c.addType("memory",function(c,f,g){if(!c)return e(a);if(f===b)return e(a[c]);d[c]&&(clearTimeout(d[c]),delete d[c]);if(f===null){delete a[c];return null}a[c]=f,g.expires&&(d[c]=setTimeout(function(){delete a[c],delete d[c]},g.expires));return f})}()})(this.amplify=this.amplify||{}); -------------------------------------------------------------------------------- /js/handlebars-1.0.0.beta.6.js: -------------------------------------------------------------------------------- 1 | // lib/handlebars/base.js 2 | var Handlebars = {}; 3 | 4 | Handlebars.VERSION = "1.0.beta.6"; 5 | 6 | Handlebars.helpers = {}; 7 | Handlebars.partials = {}; 8 | 9 | Handlebars.registerHelper = function(name, fn, inverse) { 10 | if(inverse) { fn.not = inverse; } 11 | this.helpers[name] = fn; 12 | }; 13 | 14 | Handlebars.registerPartial = function(name, str) { 15 | this.partials[name] = str; 16 | }; 17 | 18 | Handlebars.registerHelper('helperMissing', function(arg) { 19 | if(arguments.length === 2) { 20 | return undefined; 21 | } else { 22 | throw new Error("Could not find property '" + arg + "'"); 23 | } 24 | }); 25 | 26 | var toString = Object.prototype.toString, functionType = "[object Function]"; 27 | 28 | Handlebars.registerHelper('blockHelperMissing', function(context, options) { 29 | var inverse = options.inverse || function() {}, fn = options.fn; 30 | 31 | 32 | var ret = ""; 33 | var type = toString.call(context); 34 | 35 | if(type === functionType) { context = context.call(this); } 36 | 37 | if(context === true) { 38 | return fn(this); 39 | } else if(context === false || context == null) { 40 | return inverse(this); 41 | } else if(type === "[object Array]") { 42 | if(context.length > 0) { 43 | for(var i=0, j=context.length; i 0) { 60 | for(var i=0, j=context.length; i 2) { 235 | expected.push("'" + this.terminals_[p] + "'"); 236 | } 237 | var errStr = ""; 238 | if (this.lexer.showPosition) { 239 | errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + this.terminals_[symbol] + "'"; 240 | } else { 241 | errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'"); 242 | } 243 | this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); 244 | } 245 | } 246 | if (action[0] instanceof Array && action.length > 1) { 247 | throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); 248 | } 249 | switch (action[0]) { 250 | case 1: 251 | stack.push(symbol); 252 | vstack.push(this.lexer.yytext); 253 | lstack.push(this.lexer.yylloc); 254 | stack.push(action[1]); 255 | symbol = null; 256 | if (!preErrorSymbol) { 257 | yyleng = this.lexer.yyleng; 258 | yytext = this.lexer.yytext; 259 | yylineno = this.lexer.yylineno; 260 | yyloc = this.lexer.yylloc; 261 | if (recovering > 0) 262 | recovering--; 263 | } else { 264 | symbol = preErrorSymbol; 265 | preErrorSymbol = null; 266 | } 267 | break; 268 | case 2: 269 | len = this.productions_[action[1]][1]; 270 | yyval.$ = vstack[vstack.length - len]; 271 | yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column}; 272 | r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); 273 | if (typeof r !== "undefined") { 274 | return r; 275 | } 276 | if (len) { 277 | stack = stack.slice(0, -1 * len * 2); 278 | vstack = vstack.slice(0, -1 * len); 279 | lstack = lstack.slice(0, -1 * len); 280 | } 281 | stack.push(this.productions_[action[1]][0]); 282 | vstack.push(yyval.$); 283 | lstack.push(yyval._$); 284 | newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; 285 | stack.push(newState); 286 | break; 287 | case 3: 288 | return true; 289 | } 290 | } 291 | return true; 292 | } 293 | };/* Jison generated lexer */ 294 | var lexer = (function(){ 295 | 296 | var lexer = ({EOF:1, 297 | parseError:function parseError(str, hash) { 298 | if (this.yy.parseError) { 299 | this.yy.parseError(str, hash); 300 | } else { 301 | throw new Error(str); 302 | } 303 | }, 304 | setInput:function (input) { 305 | this._input = input; 306 | this._more = this._less = this.done = false; 307 | this.yylineno = this.yyleng = 0; 308 | this.yytext = this.matched = this.match = ''; 309 | this.conditionStack = ['INITIAL']; 310 | this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0}; 311 | return this; 312 | }, 313 | input:function () { 314 | var ch = this._input[0]; 315 | this.yytext+=ch; 316 | this.yyleng++; 317 | this.match+=ch; 318 | this.matched+=ch; 319 | var lines = ch.match(/\n/); 320 | if (lines) this.yylineno++; 321 | this._input = this._input.slice(1); 322 | return ch; 323 | }, 324 | unput:function (ch) { 325 | this._input = ch + this._input; 326 | return this; 327 | }, 328 | more:function () { 329 | this._more = true; 330 | return this; 331 | }, 332 | pastInput:function () { 333 | var past = this.matched.substr(0, this.matched.length - this.match.length); 334 | return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); 335 | }, 336 | upcomingInput:function () { 337 | var next = this.match; 338 | if (next.length < 20) { 339 | next += this._input.substr(0, 20-next.length); 340 | } 341 | return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, ""); 342 | }, 343 | showPosition:function () { 344 | var pre = this.pastInput(); 345 | var c = new Array(pre.length + 1).join("-"); 346 | return pre + this.upcomingInput() + "\n" + c+"^"; 347 | }, 348 | next:function () { 349 | if (this.done) { 350 | return this.EOF; 351 | } 352 | if (!this._input) this.done = true; 353 | 354 | var token, 355 | match, 356 | col, 357 | lines; 358 | if (!this._more) { 359 | this.yytext = ''; 360 | this.match = ''; 361 | } 362 | var rules = this._currentRules(); 363 | for (var i=0;i < rules.length; i++) { 364 | match = this._input.match(this.rules[rules[i]]); 365 | if (match) { 366 | lines = match[0].match(/\n.*/g); 367 | if (lines) this.yylineno += lines.length; 368 | this.yylloc = {first_line: this.yylloc.last_line, 369 | last_line: this.yylineno+1, 370 | first_column: this.yylloc.last_column, 371 | last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length} 372 | this.yytext += match[0]; 373 | this.match += match[0]; 374 | this.matches = match; 375 | this.yyleng = this.yytext.length; 376 | this._more = false; 377 | this._input = this._input.slice(match[0].length); 378 | this.matched += match[0]; 379 | token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]); 380 | if (token) return token; 381 | else return; 382 | } 383 | } 384 | if (this._input === "") { 385 | return this.EOF; 386 | } else { 387 | this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), 388 | {text: "", token: null, line: this.yylineno}); 389 | } 390 | }, 391 | lex:function lex() { 392 | var r = this.next(); 393 | if (typeof r !== 'undefined') { 394 | return r; 395 | } else { 396 | return this.lex(); 397 | } 398 | }, 399 | begin:function begin(condition) { 400 | this.conditionStack.push(condition); 401 | }, 402 | popState:function popState() { 403 | return this.conditionStack.pop(); 404 | }, 405 | _currentRules:function _currentRules() { 406 | return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules; 407 | }, 408 | topState:function () { 409 | return this.conditionStack[this.conditionStack.length-2]; 410 | }, 411 | pushState:function begin(condition) { 412 | this.begin(condition); 413 | }}); 414 | lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { 415 | 416 | var YYSTATE=YY_START 417 | switch($avoiding_name_collisions) { 418 | case 0: 419 | if(yy_.yytext.slice(-1) !== "\\") this.begin("mu"); 420 | if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu"); 421 | if(yy_.yytext) return 14; 422 | 423 | break; 424 | case 1: return 14; 425 | break; 426 | case 2: this.popState(); return 14; 427 | break; 428 | case 3: return 24; 429 | break; 430 | case 4: return 16; 431 | break; 432 | case 5: return 20; 433 | break; 434 | case 6: return 19; 435 | break; 436 | case 7: return 19; 437 | break; 438 | case 8: return 23; 439 | break; 440 | case 9: return 23; 441 | break; 442 | case 10: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15; 443 | break; 444 | case 11: return 22; 445 | break; 446 | case 12: return 34; 447 | break; 448 | case 13: return 33; 449 | break; 450 | case 14: return 33; 451 | break; 452 | case 15: return 36; 453 | break; 454 | case 16: /*ignore whitespace*/ 455 | break; 456 | case 17: this.popState(); return 18; 457 | break; 458 | case 18: this.popState(); return 18; 459 | break; 460 | case 19: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 28; 461 | break; 462 | case 20: return 30; 463 | break; 464 | case 21: return 30; 465 | break; 466 | case 22: return 29; 467 | break; 468 | case 23: return 33; 469 | break; 470 | case 24: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 33; 471 | break; 472 | case 25: return 'INVALID'; 473 | break; 474 | case 26: return 5; 475 | break; 476 | } 477 | }; 478 | lexer.rules = [/^[^\x00]*?(?=(\{\{))/,/^[^\x00]+/,/^[^\x00]{2,}?(?=(\{\{))/,/^\{\{>/,/^\{\{#/,/^\{\{\//,/^\{\{\^/,/^\{\{\s*else\b/,/^\{\{\{/,/^\{\{&/,/^\{\{![\s\S]*?\}\}/,/^\{\{/,/^=/,/^\.(?=[} ])/,/^\.\./,/^[\/.]/,/^\s+/,/^\}\}\}/,/^\}\}/,/^"(\\["]|[^"])*"/,/^true(?=[}\s])/,/^false(?=[}\s])/,/^[0-9]+(?=[}\s])/,/^[a-zA-Z0-9_$-]+(?=[=}\s\/.])/,/^\[[^\]]*\]/,/^./,/^$/]; 479 | lexer.conditions = {"mu":{"rules":[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"INITIAL":{"rules":[0,1,26],"inclusive":true}};return lexer;})() 480 | parser.lexer = lexer; 481 | return parser; 482 | })(); 483 | if (typeof require !== 'undefined' && typeof exports !== 'undefined') { 484 | exports.parser = handlebars; 485 | exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); } 486 | exports.main = function commonjsMain(args) { 487 | if (!args[1]) 488 | throw new Error('Usage: '+args[0]+' FILE'); 489 | if (typeof process !== 'undefined') { 490 | var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8"); 491 | } else { 492 | var cwd = require("file").path(require("file").cwd()); 493 | var source = cwd.join(args[1]).read({charset: "utf-8"}); 494 | } 495 | return exports.parser.parse(source); 496 | } 497 | if (typeof module !== 'undefined' && require.main === module) { 498 | exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args); 499 | } 500 | }; 501 | ; 502 | // lib/handlebars/compiler/base.js 503 | Handlebars.Parser = handlebars; 504 | 505 | Handlebars.parse = function(string) { 506 | Handlebars.Parser.yy = Handlebars.AST; 507 | return Handlebars.Parser.parse(string); 508 | }; 509 | 510 | Handlebars.print = function(ast) { 511 | return new Handlebars.PrintVisitor().accept(ast); 512 | }; 513 | 514 | Handlebars.logger = { 515 | DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, 516 | 517 | // override in the host environment 518 | log: function(level, str) {} 519 | }; 520 | 521 | Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); }; 522 | ; 523 | // lib/handlebars/compiler/ast.js 524 | (function() { 525 | 526 | Handlebars.AST = {}; 527 | 528 | Handlebars.AST.ProgramNode = function(statements, inverse) { 529 | this.type = "program"; 530 | this.statements = statements; 531 | if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); } 532 | }; 533 | 534 | Handlebars.AST.MustacheNode = function(params, hash, unescaped) { 535 | this.type = "mustache"; 536 | this.id = params[0]; 537 | this.params = params.slice(1); 538 | this.hash = hash; 539 | this.escaped = !unescaped; 540 | }; 541 | 542 | Handlebars.AST.PartialNode = function(id, context) { 543 | this.type = "partial"; 544 | 545 | // TODO: disallow complex IDs 546 | 547 | this.id = id; 548 | this.context = context; 549 | }; 550 | 551 | var verifyMatch = function(open, close) { 552 | if(open.original !== close.original) { 553 | throw new Handlebars.Exception(open.original + " doesn't match " + close.original); 554 | } 555 | }; 556 | 557 | Handlebars.AST.BlockNode = function(mustache, program, close) { 558 | verifyMatch(mustache.id, close); 559 | this.type = "block"; 560 | this.mustache = mustache; 561 | this.program = program; 562 | }; 563 | 564 | Handlebars.AST.InverseNode = function(mustache, program, close) { 565 | verifyMatch(mustache.id, close); 566 | this.type = "inverse"; 567 | this.mustache = mustache; 568 | this.program = program; 569 | }; 570 | 571 | Handlebars.AST.ContentNode = function(string) { 572 | this.type = "content"; 573 | this.string = string; 574 | }; 575 | 576 | Handlebars.AST.HashNode = function(pairs) { 577 | this.type = "hash"; 578 | this.pairs = pairs; 579 | }; 580 | 581 | Handlebars.AST.IdNode = function(parts) { 582 | this.type = "ID"; 583 | this.original = parts.join("."); 584 | 585 | var dig = [], depth = 0; 586 | 587 | for(var i=0,l=parts.length; i": ">", 646 | '"': """, 647 | "'": "'", 648 | "`": "`" 649 | }; 650 | 651 | var badChars = /&(?!\w+;)|[<>"'`]/g; 652 | var possible = /[&<>"'`]/; 653 | 654 | var escapeChar = function(chr) { 655 | return escape[chr] || "&"; 656 | }; 657 | 658 | Handlebars.Utils = { 659 | escapeExpression: function(string) { 660 | // don't escape SafeStrings, since they're already safe 661 | if (string instanceof Handlebars.SafeString) { 662 | return string.toString(); 663 | } else if (string == null || string === false) { 664 | return ""; 665 | } 666 | 667 | if(!possible.test(string)) { return string; } 668 | return string.replace(badChars, escapeChar); 669 | }, 670 | 671 | isEmpty: function(value) { 672 | if (typeof value === "undefined") { 673 | return true; 674 | } else if (value === null) { 675 | return true; 676 | } else if (value === false) { 677 | return true; 678 | } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) { 679 | return true; 680 | } else { 681 | return false; 682 | } 683 | } 684 | }; 685 | })();; 686 | // lib/handlebars/compiler/compiler.js 687 | Handlebars.Compiler = function() {}; 688 | Handlebars.JavaScriptCompiler = function() {}; 689 | 690 | (function(Compiler, JavaScriptCompiler) { 691 | Compiler.OPCODE_MAP = { 692 | appendContent: 1, 693 | getContext: 2, 694 | lookupWithHelpers: 3, 695 | lookup: 4, 696 | append: 5, 697 | invokeMustache: 6, 698 | appendEscaped: 7, 699 | pushString: 8, 700 | truthyOrFallback: 9, 701 | functionOrFallback: 10, 702 | invokeProgram: 11, 703 | invokePartial: 12, 704 | push: 13, 705 | assignToHash: 15, 706 | pushStringParam: 16 707 | }; 708 | 709 | Compiler.MULTI_PARAM_OPCODES = { 710 | appendContent: 1, 711 | getContext: 1, 712 | lookupWithHelpers: 2, 713 | lookup: 1, 714 | invokeMustache: 3, 715 | pushString: 1, 716 | truthyOrFallback: 1, 717 | functionOrFallback: 1, 718 | invokeProgram: 3, 719 | invokePartial: 1, 720 | push: 1, 721 | assignToHash: 1, 722 | pushStringParam: 1 723 | }; 724 | 725 | Compiler.DISASSEMBLE_MAP = {}; 726 | 727 | for(var prop in Compiler.OPCODE_MAP) { 728 | var value = Compiler.OPCODE_MAP[prop]; 729 | Compiler.DISASSEMBLE_MAP[value] = prop; 730 | } 731 | 732 | Compiler.multiParamSize = function(code) { 733 | return Compiler.MULTI_PARAM_OPCODES[Compiler.DISASSEMBLE_MAP[code]]; 734 | }; 735 | 736 | Compiler.prototype = { 737 | compiler: Compiler, 738 | 739 | disassemble: function() { 740 | var opcodes = this.opcodes, opcode, nextCode; 741 | var out = [], str, name, value; 742 | 743 | for(var i=0, l=opcodes.length; i 0) { 1128 | this.source[1] = this.source[1] + ", " + locals.join(", "); 1129 | } 1130 | 1131 | // Generate minimizer alias mappings 1132 | if (!this.isChild) { 1133 | var aliases = [] 1134 | for (var alias in this.context.aliases) { 1135 | this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias]; 1136 | } 1137 | } 1138 | 1139 | if (this.source[1]) { 1140 | this.source[1] = "var " + this.source[1].substring(2) + ";"; 1141 | } 1142 | 1143 | // Merge children 1144 | if (!this.isChild) { 1145 | this.source[1] += '\n' + this.context.programs.join('\n') + '\n'; 1146 | } 1147 | 1148 | if (!this.environment.isSimple) { 1149 | this.source.push("return buffer;"); 1150 | } 1151 | 1152 | var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"]; 1153 | 1154 | for(var i=0, l=this.environment.depths.list.length; i this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } 1406 | return "stack" + this.stackSlot; 1407 | }, 1408 | 1409 | popStack: function() { 1410 | return "stack" + this.stackSlot--; 1411 | }, 1412 | 1413 | topStack: function() { 1414 | return "stack" + this.stackSlot; 1415 | }, 1416 | 1417 | quotedString: function(str) { 1418 | return '"' + str 1419 | .replace(/\\/g, '\\\\') 1420 | .replace(/"/g, '\\"') 1421 | .replace(/\n/g, '\\n') 1422 | .replace(/\r/g, '\\r') + '"'; 1423 | } 1424 | }; 1425 | 1426 | var reservedWords = ( 1427 | "break else new var" + 1428 | " case finally return void" + 1429 | " catch for switch while" + 1430 | " continue function this with" + 1431 | " default if throw" + 1432 | " delete in try" + 1433 | " do instanceof typeof" + 1434 | " abstract enum int short" + 1435 | " boolean export interface static" + 1436 | " byte extends long super" + 1437 | " char final native synchronized" + 1438 | " class float package throws" + 1439 | " const goto private transient" + 1440 | " debugger implements protected volatile" + 1441 | " double import public let yield" 1442 | ).split(" "); 1443 | 1444 | var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; 1445 | 1446 | for(var i=0, l=reservedWords.length; i 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value === null || value === undefined)) { 6 | options = $.extend({}, options); 7 | 8 | if (value === null || value === undefined) { 9 | options.expires = -1; 10 | } 11 | 12 | if (typeof options.expires === 'number') { 13 | var days = options.expires, t = options.expires = new Date(); 14 | t.setDate(t.getDate() + days); 15 | } 16 | 17 | value = String(value); 18 | 19 | return (document.cookie = [ 20 | encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value), 21 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 22 | options.path ? '; path=' + options.path : '', 23 | options.domain ? '; domain=' + options.domain : '', 24 | options.secure ? '; secure' : '' 25 | ].join('')); 26 | } 27 | 28 | // key and possibly options given, get cookie... 29 | options = value || {}; 30 | var decode = options.raw ? function(s) { return s; } : decodeURIComponent; 31 | 32 | var pairs = document.cookie.split('; '); 33 | for (var i = 0, pair; pair = pairs[i] && pairs[i].split('='); i++) { 34 | if (decode(pair[0]) === key) return decode(pair[1] || ''); // IE saves cookies with empty string as "c; ", e.g. without "=" as opposed to EOMB, thus pair[1] may be undefined 35 | } 36 | return null; 37 | }; 38 | })(jQuery); -------------------------------------------------------------------------------- /js/jquery.deserialize.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | $.deserialize = function (str, options) { 3 | var pairs = str.split(/&|&/i), 4 | h = {}, 5 | options = options || {}; 6 | for(var i = 0; i < pairs.length; i++) { 7 | var kv = pairs[i].split('='); 8 | kv[0] = decodeURIComponent(kv[0]); 9 | if(!options.except || options.except.indexOf(kv[0]) == -1) { 10 | if((/^\w+\[\w+\]$/).test(kv[0])) { 11 | var matches = kv[0].match(/^(\w+)\[(\w+)\]$/); 12 | if(typeof h[matches[1]] === 'undefined') { 13 | h[matches[1]] = {}; 14 | } 15 | h[matches[1]][matches[2]] = decodeURIComponent(kv[1]); 16 | } else { 17 | h[kv[0]] = decodeURIComponent(kv[1]); 18 | } 19 | } 20 | } 21 | return h; 22 | }; 23 | 24 | $.fn.deserialize = function (options) { 25 | return $.deserialize($(this).serialize(), options); 26 | }; 27 | })(jQuery); -------------------------------------------------------------------------------- /js/jquery.mobile.simpledialog2.js: -------------------------------------------------------------------------------- 1 | (function($, undefined ) { 2 | $.widget( "mobile.simpledialog2", $.mobile.widget, { 3 | options: { 4 | version: '1.0.1-2012022700', // jQueryMobile-YrMoDaySerial 5 | mode: 'blank', // or 'button' 6 | themeDialog: 'b', 7 | themeInput: false, 8 | themeButtonDefault: false, 9 | themeHeader: 'a', 10 | 11 | fullScreen: false, 12 | fullScreenForce: false, 13 | dialogAllow: false, 14 | dialogForce: false, 15 | 16 | headerText: false, 17 | headerClose: false, 18 | buttonPrompt: false, 19 | buttonInput: false, 20 | buttonPassword: false, 21 | blankContent: false, 22 | 23 | resizeListener: true, 24 | safeNuke: true, 25 | forceInput: true, 26 | showModal: true, 27 | animate: true, 28 | transition: 'pop', 29 | clickEvent: 'click', 30 | zindex: '500', 31 | width: '280px', 32 | left: false, 33 | top: false, 34 | 35 | callbackOpen: false, 36 | callbackOpenArgs: [], 37 | callbackClose: false, 38 | callbackCloseArgs: [] 39 | }, 40 | _eventHandler: function(e,p) { 41 | // Handle the triggers 42 | var self = e.data.widget, 43 | o = e.data.widget.options; 44 | 45 | if ( ! e.isPropagationStopped() ) { 46 | switch (p.method) { 47 | case 'close': 48 | self.close(); 49 | break; 50 | case 'html': 51 | self.updateBlank(p.source); 52 | break; 53 | } 54 | } 55 | }, 56 | _create: function () { 57 | var self = this, 58 | o = $.extend(this.options, this.element.jqmData('options')), 59 | initDate = new Date(), 60 | content = $("
    "); 62 | 63 | if ( o.themeButtonDefault === false ) { o.themeButtonDefault = o.themeDialog; } 64 | if ( o.themeInput === false ) { o.themeInput = o.themeDialog; } 65 | $.mobile.sdCurrentDialog = self; 66 | if ( typeof $.mobile.sdLastInput !== 'undefined' ) { delete $.mobile.sdLastInput; } 67 | self.internalID = initDate.getTime(); 68 | self.displayAnchor = $.mobile.activePage.children('.ui-content').first(); 69 | 70 | self.dialogPage = $("
    "); 71 | self.sdAllContent = self.dialogPage.find('[data-role=content]'); 72 | 73 | content.appendTo(self.sdAllContent); 74 | 75 | self.sdIntContent = self.sdAllContent.find('.ui-simpledialog-container'); 76 | self.sdIntContent.css('width', o.width); 77 | 78 | if ( o.headerText !== false || o.headerClose !== false ) { 79 | self.sdHeader = $('
    '); 80 | if ( o.headerClose === true ) { 81 | $("Close").appendTo(self.sdHeader).buttonMarkup({ theme : o.themeHeader, icon : 'delete', iconpos: 'notext', corners: true, shadow : true }); 82 | } 83 | $('

    '+((o.headerText !== false)?o.headerText:'')+'

    ').appendTo(self.sdHeader); 84 | self.sdHeader.appendTo(self.sdIntContent); 85 | } 86 | 87 | if ( o.mode === 'blank' ) { 88 | if ( o.blankContent === true ) { 89 | o.blankContent = self.element.html(); 90 | } 91 | $(o.blankContent).appendTo(self.sdIntContent); 92 | } else if ( o.mode === 'button' ) { 93 | self._makeButtons().appendTo(self.sdIntContent); 94 | } 95 | 96 | self.sdIntContent.appendTo(self.displayAnchor.parent()); 97 | 98 | self.dialogPage.appendTo( $.mobile.pageContainer ) 99 | .page().css('minHeight', '0px').css('zIndex', o.zindex); 100 | 101 | if ( o.animate === true ) { self.dialogPage.addClass(o.transition); } 102 | 103 | self.screen = $("
    ", {'class':'ui-simpledialog-screen ui-simpledialog-hidden'}) 104 | .css('z-index', (o.zindex-1)) 105 | .appendTo(self.displayAnchor.parent()) 106 | .bind(o.clickEvent, function(event){ 107 | if ( !o.forceInput ) { 108 | self.close(); 109 | } 110 | event.preventDefault(); 111 | }); 112 | 113 | if ( o.showModal ) { self.screen.addClass('ui-simpledialog-screen-modal'); } 114 | 115 | $(document).bind('simpledialog.'+self.internalID, {widget:self}, function(e,p) { self._eventHandler(e,p); }); 116 | }, 117 | _makeButtons: function () { 118 | var self = this, 119 | o = self.options, 120 | buttonHTML = $('
    '), 121 | pickerInput = $("
    "), 122 | pickerChoice = $("
    ", { "class":'ui-simpledialog-controls' }); 123 | 124 | 125 | if ( o.buttonPrompt !== false ) { 126 | self.buttonPromptText = $("

    "+o.buttonPrompt+"

    ").appendTo(buttonHTML); 127 | } 128 | 129 | if ( o.buttonInput !== false ) { 130 | $.mobile.sdLastInput = ""; 131 | pickerInput.appendTo(buttonHTML); 132 | pickerInput.find('input').bind('change', function () { 133 | $.mobile.sdLastInput = pickerInput.find('input').first().val(); 134 | self.thisInput = pickerInput.find('input').first().val(); 135 | }); 136 | } 137 | 138 | pickerChoice.appendTo(buttonHTML); 139 | 140 | self.butObj = []; 141 | 142 | $.each(o.buttons, function(name, props) { 143 | props = $.isFunction( props ) ? { click: props } : props; 144 | props = $.extend({ 145 | text : name, 146 | id : name + self.internalID, 147 | theme : o.themeButtonDefault, 148 | icon : 'check', 149 | iconpos: 'left', 150 | corners: 'true', 151 | shadow : 'true', 152 | args : [], 153 | close : true 154 | }, props); 155 | 156 | self.butObj.push($(""+name+"") 157 | .appendTo(pickerChoice) 158 | .attr('id', props.id) 159 | .buttonMarkup({ 160 | theme : props.theme, 161 | icon : props.icon, 162 | iconpos: props.iconpos, 163 | corners: props.corners, 164 | shadow : props.shadow 165 | }).unbind("vclick click") 166 | .bind(o.clickEvent, function() { 167 | if ( o.buttonInput ) { self.sdIntContent.find('input [name=pickin]').trigger('change'); } 168 | //var returnValue = props.click.apply(self.element[0], arguments); 169 | var returnValue = props.click.apply(self, $.merge(arguments, props.args)); 170 | if ( returnValue !== false && props.close === true ) { 171 | self.close(); 172 | } 173 | }) 174 | ); 175 | }); 176 | 177 | return buttonHTML; 178 | }, 179 | _getCoords: function(widget) { 180 | var self = widget, 181 | docWinWidth = $.mobile.activePage.width(), 182 | docWinHighOff = $(window).scrollTop(), 183 | docWinHigh = $(window).height(), 184 | diaWinWidth = widget.sdIntContent.innerWidth(), 185 | diaWinHigh = widget.sdIntContent.outerHeight(), 186 | 187 | coords = { 188 | 'high' : $(window).height(), 189 | 'width' : $.mobile.activePage.width(), 190 | 'fullTop' : $(window).scrollTop(), 191 | 'fullLeft': $(window).scrollLeft(), 192 | 'winTop' : docWinHighOff + ((widget.options.top !== false) ? widget.options.top : (( docWinHigh / 2 ) - ( diaWinHigh / 2 ) )), 193 | 'winLeft' : ((widget.options.left !== false) ? widget.options.left : (( docWinWidth / 2 ) - ( diaWinWidth / 2 ) )) 194 | }; 195 | 196 | if ( coords.winTop < 45 ) { coords.winTop = 45; } 197 | 198 | return coords; 199 | }, 200 | _orientChange: function(e) { 201 | var self = e.data.widget, 202 | o = e.data.widget.options, 203 | coords = e.data.widget._getCoords(e.data.widget); 204 | 205 | e.stopPropagation(); 206 | 207 | if ( self.isDialog === true ) { 208 | return true; 209 | } else { 210 | if ( o.fullScreen === true && ( coords.width < 400 || o.fullScreenForce === true ) ) { 211 | self.sdIntContent.css({'border': 'none', 'position': 'absolute', 'top': coords.fullTop, 'left': coords.fullLeft, 'height': coords.high, 'width': coords.width, 'maxWidth': coords.width }).removeClass('ui-simpledialog-hidden'); 212 | } else { 213 | self.sdIntContent.css({'position': 'absolute', 'top': coords.winTop, 'left': coords.winLeft}).removeClass('ui-simpledialog-hidden'); 214 | } 215 | } 216 | }, 217 | repos: function() { 218 | var bsEvent = { data: {widget:this}, stopPropagation: function () { return true; }}; 219 | this._orientChange(bsEvent); 220 | }, 221 | open: function() { 222 | var self = this, 223 | o = this.options, 224 | coords = this._getCoords(this); 225 | 226 | self.sdAllContent.find('.ui-btn-active').removeClass('ui-btn-active'); 227 | self.sdIntContent.delegate('[rel=close]', o.clickEvent, function (e) { e.preventDefault(); self.close(); }); 228 | 229 | if ( ( o.dialogAllow === true && coords.width < 400 ) || o.dialogForce ) { 230 | self.isDialog = true; 231 | 232 | if ( o.mode === 'blank' ) { // Custom selects do not play well with dialog mode - so, we turn them off. 233 | self.sdIntContent.find('select').each(function () { 234 | $(this).jqmData('nativeMenu', true); 235 | }); 236 | } 237 | 238 | self.displayAnchor.parent().unbind("pagehide.remove"); 239 | self.sdAllContent.append(self.sdIntContent); 240 | self.sdAllContent.trigger('create'); 241 | if ( o.headerText !== false ) { 242 | self.sdHeader.find('h1').appendTo(self.dialogPage.find('[data-role=header]')); 243 | self.sdIntContent.find('.ui-header').empty().removeClass(); 244 | } 245 | if ( o.headerClose === true ) { 246 | self.dialogPage.find('.ui-header a').bind('click', function () { 247 | setTimeout("$.mobile.sdCurrentDialog.destroy();", 1000); 248 | }); 249 | } else { 250 | self.dialogPage.find('.ui-header a').remove(); 251 | } 252 | 253 | self.sdIntContent.removeClass().css({'top': 'auto', 'width': 'auto', 'left': 'auto', 'marginLeft': 'auto', 'marginRight': 'auto', 'zIndex': o.zindex}); 254 | $.mobile.changePage(self.dialogPage, {'transition': (o.animate === true) ? o.transition : 'none'}); 255 | } else { 256 | self.isDialog = false; 257 | self.selects = []; 258 | 259 | if ( o.fullScreen === false ) { 260 | if ( o.showModal === true && o.animate === true ) { self.screen.fadeIn('slow'); } 261 | else { self.screen.removeClass('ui-simpledialog-hidden'); } 262 | } 263 | 264 | self.sdIntContent.addClass('ui-overlay-shadow in').css('zIndex', o.zindex).trigger('create'); 265 | 266 | if ( o.fullScreen === true && ( coords.width < 400 || o.fullScreenForce === true ) ) { 267 | self.sdIntContent.removeClass('ui-simpledialog-container').css({'border': 'none', 'position': 'absolute', 'top': coords.fullTop, 'left': coords.fullLeft, 'height': coords.high, 'width': coords.width, 'maxWidth': coords.width }).removeClass('ui-simpledialog-hidden'); 268 | } else { 269 | self.sdIntContent.css({'position': 'absolute', 'top': coords.winTop, 'left': coords.winLeft}).removeClass('ui-simpledialog-hidden'); 270 | } 271 | 272 | $(document).bind('orientationchange.simpledialog', {widget:self}, function(e) { self._orientChange(e); }); 273 | if ( o.resizeListener === true ) { 274 | $(window).bind('resize.simpledialog', {widget:self}, function (e) { self._orientChange(e); }); 275 | } 276 | } 277 | if ( $.isFunction(o.callbackOpen) ) { 278 | o.callbackOpen.apply(self, o.callbackOpenArgs); 279 | } 280 | }, 281 | close: function() { 282 | var self = this, retty; 283 | 284 | if ( $.isFunction(self.options.callbackClose) ) { 285 | retty = self.options.callbackClose.apply(self, self.options.callbackCloseArgs); 286 | if ( retty === false ) { return false; } 287 | } 288 | 289 | if ( self.isDialog ) { 290 | $(self.dialogPage).dialog('close'); 291 | self.sdIntContent.addClass('ui-simpledialog-hidden'); 292 | self.sdIntContent.appendTo(self.displayAnchor.parent()); 293 | if ( $.mobile.activePage.jqmData("page").options.domCache != true ) { 294 | $.mobile.activePage.bind("pagehide.remove", function () { 295 | $(this).remove(); 296 | }); 297 | } 298 | } else { 299 | if ( self.options.showModal === true && self.options.animate === true ) { 300 | self.screen.fadeOut('slow'); 301 | } else { 302 | self.screen.addClass('ui-simpledialog-hidden'); 303 | } 304 | self.sdIntContent.addClass('ui-simpledialog-hidden').removeClass('in'); 305 | $(document).unbind('orientationchange.simpledialog'); 306 | if ( self.options.resizeListener === true ) { $(window).unbind('resize.simpledialog'); } 307 | } 308 | 309 | //$.mobile.activePage.find('.ui-btn-active').removeClass('ui-btn-active'); 310 | 311 | if ( self.isDialog === true || self.options.animate === true ) { 312 | setTimeout("$.mobile.sdCurrentDialog.destroy();", 1000); 313 | } else { 314 | self.destroy(); 315 | } 316 | }, 317 | destroy: function() { 318 | var self = this, 319 | ele = self.element; 320 | 321 | if ( self.options.mode === 'blank' ) { 322 | $.mobile.sdCurrentDialog.sdIntContent.find('select').each(function() { 323 | if ( $(this).data('nativeMenu') == false ) { 324 | $(this).data('selectmenu').menuPage.remove(); 325 | $(this).data('selectmenu').screen.remove(); 326 | $(this).data('selectmenu').listbox.remove(); 327 | } 328 | }); 329 | } 330 | 331 | $(self.sdIntContent).remove(); 332 | $(self.dialogPage).remove(); 333 | $(self.screen).remove(); 334 | $(document).unbind('simpledialog.'+self.internalID); 335 | delete $.mobile.sdCurrentDialog; 336 | $.Widget.prototype.destroy.call(self); 337 | if ( self.options.safeNuke === true && $(ele).parents().length === 0 && $(ele).contents().length === 0 ) { 338 | ele.remove(); 339 | } 340 | }, 341 | updateBlank: function (newHTML) { 342 | var self = this, 343 | o = this.options; 344 | 345 | self.sdIntContent.empty(); 346 | 347 | if ( o.headerText !== false || o.headerClose !== false ) { 348 | self.sdHeader = $('
    '); 349 | if ( o.headerClose === true ) { 350 | $("Close").appendTo(self.sdHeader).buttonMarkup({ theme : o.themeHeader, icon : 'delete', iconpos: 'notext', corners: true, shadow : true }); 351 | } 352 | $('

    '+((o.headerText !== false)?o.headerText:'')+'

    ').appendTo(self.sdHeader); 353 | self.sdHeader.appendTo(self.sdIntContent); 354 | } 355 | 356 | $(newHTML).appendTo(self.sdIntContent); 357 | self.sdIntContent.trigger('create'); 358 | $(document).trigger('orientationchange.simpledialog'); 359 | }, 360 | _init: function() { 361 | this.open(); 362 | } 363 | }); 364 | })( jQuery ); -------------------------------------------------------------------------------- /js/jquery.oauthpopup.js: -------------------------------------------------------------------------------- 1 | (function(jQuery){ 2 | var width = 800; 3 | var height = 400; 4 | var left = (screen.width/2)-(width/2); 5 | var top = (screen.height/2)-(height/2); 6 | // inspired by DISQUS 7 | jQuery.oauthpopup = function(options) { 8 | options.windowName = options.windowName || 'ConnectWithOAuth'; // should not include space for IE 9 | options.windowOptions = options.windowOptions || 'location=0,status=0,width='+width+',height='+height+',top='+top+',left='+left; 10 | options.callback = options.callback || function(){ window.location.reload(); }; 11 | var that = this; 12 | 13 | that._oauthWindow = window.open(options.path, options.windowName, options.windowOptions); 14 | 15 | that._oauthInterval = window.setInterval(function() { 16 | if (that._oauthWindow.closed) { 17 | window.clearInterval(that._oauthInterval); 18 | options.callback(); 19 | } 20 | }, 200); 21 | }; 22 | })(jQuery); -------------------------------------------------------------------------------- /js/jquery.prettydate.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 3 | $.prettyDate = { 4 | 5 | template: function(source, params) { 6 | if ( arguments.length == 1 ) 7 | return function() { 8 | var args = $.makeArray(arguments); 9 | args.unshift(source); 10 | return $.prettyDate.template.apply( this, args ); 11 | }; 12 | if ( arguments.length > 2 && params.constructor != Array ) { 13 | params = $.makeArray(arguments).slice(1); 14 | } 15 | if ( params.constructor != Array ) { 16 | params = [ params ]; 17 | } 18 | $.each(params, function(i, n) { 19 | source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n); 20 | }); 21 | return source; 22 | }, 23 | 24 | now: function() { 25 | return new Date(); 26 | }, 27 | 28 | fromUTC: function (utcDate, isUTC) { 29 | if (!isUTC) { 30 | return utcDate; 31 | } else { 32 | var date = new Date(); 33 | date.setUTCDate(utcDate.getDate()); 34 | date.setUTCHours(utcDate.getHours()); 35 | date.setUTCMonth(utcDate.getMonth()); 36 | date.setUTCFullYear(utcDate.getFullYear()); 37 | date.setUTCMinutes(utcDate.getMinutes()); 38 | date.setUTCSeconds(utcDate.getSeconds()); 39 | date.setUTCMilliseconds(utcDate.getMilliseconds()); 40 | return date; 41 | } 42 | }, 43 | 44 | // Takes an ISO time and returns a string representing how 45 | // long ago the date represents. 46 | format: function(time, isUTC) { 47 | var date = $.prettyDate.fromUTC(new Date((time || "").replace(/-/g,"/").replace(/[TZ]/g," ")), isUTC), 48 | diff = ($.prettyDate.now().getTime() - date.getTime()) / 1000, 49 | day_diff = Math.floor(diff / 86400); 50 | 51 | if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 ) 52 | return; 53 | 54 | var messages = $.prettyDate.messages; 55 | return day_diff == 0 && ( 56 | diff < 60 && messages.now || 57 | diff < 120 && messages.minute || 58 | diff < 3600 && messages.minutes(Math.floor( diff / 60 )) || 59 | diff < 7200 && messages.hour || 60 | diff < 86400 && messages.hours(Math.floor( diff / 3600 ))) || 61 | day_diff == 1 && messages.yesterday || 62 | day_diff < 7 && messages.days(day_diff) || 63 | day_diff < 31 && messages.weeks(Math.ceil( day_diff / 7 )); 64 | } 65 | 66 | }; 67 | 68 | $.prettyDate.messages = { 69 | now: "just now", 70 | minute: "1 minute ago", 71 | minutes: $.prettyDate.template("{0} minutes ago"), 72 | hour: "1 hour ago", 73 | hours: $.prettyDate.template("{0} hours ago"), 74 | yesterday: "Yesterday", 75 | days: $.prettyDate.template("{0} days ago"), 76 | weeks: $.prettyDate.template("{0} weeks ago") 77 | }; 78 | 79 | $.fn.prettyDate = function(options) { 80 | options = $.extend({ 81 | value: function() { 82 | return $(this).attr(options.attribute); 83 | }, 84 | interval: 10000, 85 | attribute: "title", 86 | isUTC: false 87 | }, options); 88 | var elements = this; 89 | function format() { 90 | elements.each(function() { 91 | var date = $.prettyDate.format(options.value.apply(this), options.isUTC); 92 | if ( date && $(this).text() != date ) 93 | $(this).text( date ); 94 | }); 95 | } 96 | format(); 97 | if (options.interval) 98 | setInterval(format, options.interval); 99 | return this; 100 | }; 101 | 102 | })(jQuery); -------------------------------------------------------------------------------- /js/jquery.swipeButton-1.1.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | 3 | $.fn.swipeDelete = function(o){ 4 | 5 | o = $.extend( {}, $.fn.swipeDelete.defaults, o ); 6 | 7 | return this.filter('[data-swipeurl]').each(function(i, el){ 8 | 9 | var $e = $(el); 10 | var $parent = $(el).parent('ul'); 11 | 12 | $e.bind(o.direction, function ( e ) { 13 | 14 | // reference the current item 15 | var $li = $(this); 16 | var cnt = $('div.ui-btn', $li).length; 17 | 18 | // remove all currently displayed buttons 19 | $('div.ui-btn, .' + o.btnClass, $parent).animate({ width: 'toggle' }, 200, function(e) { 20 | $(this).remove(); 21 | }); 22 | 23 | // if there's an existing button we simply delete it, then stop 24 | if (!cnt) { 25 | // create button 26 | var $swipeBtn = $('' + o.btnLabel + '').attr({ 27 | 'data-role': 'button', 28 | 'data-inline': 'true', 29 | 'class': o.btnClass, 30 | 'data-theme': o.btnTheme, 31 | 'href': $li.data('swipeurl') 32 | }) 33 | .bind('click tap', o.click); 34 | 35 | // slide insert button into list item 36 | $swipeBtn.prependTo($li).button(); 37 | $li.find('.ui-btn').hide().animate({ width: 'toggle' }, 200); 38 | 39 | // override row click 40 | $('div a:not(' + o.btnClass + ')', $li).bind('click.swipe', function(e){ 41 | e.stopPropagation(); 42 | e.preventDefault(); 43 | $(this).unbind('click.swipe'); 44 | $li.removeClass('ui-btn-active').find('div.ui-btn').remove(); 45 | }); 46 | } 47 | 48 | 49 | }); 50 | 51 | }); 52 | 53 | } 54 | 55 | $.fn.swipeDelete.defaults = { 56 | direction: 'swiperight', 57 | btnLabel: 'Delete', 58 | btnTheme: 'e', 59 | btnClass: 'aSwipeBtn', 60 | click: function(e){ 61 | e.preventDefault(); 62 | $(this).parents('li').slideUp(); 63 | } 64 | }; 65 | 66 | })(jQuery); -------------------------------------------------------------------------------- /js/json2.js: -------------------------------------------------------------------------------- 1 | var JSON; 2 | if (!JSON) { 3 | JSON = {}; 4 | } 5 | 6 | (function () { 7 | 'use strict'; 8 | 9 | function f(n) { 10 | // Format integers to have at least two digits. 11 | return n < 10 ? '0' + n : n; 12 | } 13 | 14 | if (typeof Date.prototype.toJSON !== 'function') { 15 | 16 | Date.prototype.toJSON = function (key) { 17 | 18 | return isFinite(this.valueOf()) 19 | ? this.getUTCFullYear() + '-' + 20 | f(this.getUTCMonth() + 1) + '-' + 21 | f(this.getUTCDate()) + 'T' + 22 | f(this.getUTCHours()) + ':' + 23 | f(this.getUTCMinutes()) + ':' + 24 | f(this.getUTCSeconds()) + 'Z' 25 | : null; 26 | }; 27 | 28 | String.prototype.toJSON = 29 | Number.prototype.toJSON = 30 | Boolean.prototype.toJSON = function (key) { 31 | return this.valueOf(); 32 | }; 33 | } 34 | 35 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 36 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 37 | gap, 38 | indent, 39 | meta = { // table of character substitutions 40 | '\b': '\\b', 41 | '\t': '\\t', 42 | '\n': '\\n', 43 | '\f': '\\f', 44 | '\r': '\\r', 45 | '"' : '\\"', 46 | '\\': '\\\\' 47 | }, 48 | rep; 49 | 50 | 51 | function quote(string) { 52 | 53 | // If the string contains no control characters, no quote characters, and no 54 | // backslash characters, then we can safely slap some quotes around it. 55 | // Otherwise we must also replace the offending characters with safe escape 56 | // sequences. 57 | 58 | escapable.lastIndex = 0; 59 | return escapable.test(string) ? '"' + string.replace(escapable, function (a) { 60 | var c = meta[a]; 61 | return typeof c === 'string' 62 | ? c 63 | : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 64 | }) + '"' : '"' + string + '"'; 65 | } 66 | 67 | 68 | function str(key, holder) { 69 | 70 | // Produce a string from holder[key]. 71 | 72 | var i, // The loop counter. 73 | k, // The member key. 74 | v, // The member value. 75 | length, 76 | mind = gap, 77 | partial, 78 | value = holder[key]; 79 | 80 | // If the value has a toJSON method, call it to obtain a replacement value. 81 | 82 | if (value && typeof value === 'object' && 83 | typeof value.toJSON === 'function') { 84 | value = value.toJSON(key); 85 | } 86 | 87 | // If we were called with a replacer function, then call the replacer to 88 | // obtain a replacement value. 89 | 90 | if (typeof rep === 'function') { 91 | value = rep.call(holder, key, value); 92 | } 93 | 94 | // What happens next depends on the value's type. 95 | 96 | switch (typeof value) { 97 | case 'string': 98 | return quote(value); 99 | 100 | case 'number': 101 | 102 | // JSON numbers must be finite. Encode non-finite numbers as null. 103 | 104 | return isFinite(value) ? String(value) : 'null'; 105 | 106 | case 'boolean': 107 | case 'null': 108 | 109 | // If the value is a boolean or null, convert it to a string. Note: 110 | // typeof null does not produce 'null'. The case is included here in 111 | // the remote chance that this gets fixed someday. 112 | 113 | return String(value); 114 | 115 | // If the type is 'object', we might be dealing with an object or an array or 116 | // null. 117 | 118 | case 'object': 119 | 120 | // Due to a specification blunder in ECMAScript, typeof null is 'object', 121 | // so watch out for that case. 122 | 123 | if (!value) { 124 | return 'null'; 125 | } 126 | 127 | // Make an array to hold the partial results of stringifying this object value. 128 | 129 | gap += indent; 130 | partial = []; 131 | 132 | // Is the value an array? 133 | 134 | if (Object.prototype.toString.apply(value) === '[object Array]') { 135 | 136 | // The value is an array. Stringify every element. Use null as a placeholder 137 | // for non-JSON values. 138 | 139 | length = value.length; 140 | for (i = 0; i < length; i += 1) { 141 | partial[i] = str(i, value) || 'null'; 142 | } 143 | 144 | // Join all of the elements together, separated with commas, and wrap them in 145 | // brackets. 146 | 147 | v = partial.length === 0 148 | ? '[]' 149 | : gap 150 | ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' 151 | : '[' + partial.join(',') + ']'; 152 | gap = mind; 153 | return v; 154 | } 155 | 156 | // If the replacer is an array, use it to select the members to be stringified. 157 | 158 | if (rep && typeof rep === 'object') { 159 | length = rep.length; 160 | for (i = 0; i < length; i += 1) { 161 | if (typeof rep[i] === 'string') { 162 | k = rep[i]; 163 | v = str(k, value); 164 | if (v) { 165 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 166 | } 167 | } 168 | } 169 | } else { 170 | 171 | // Otherwise, iterate through all of the keys in the object. 172 | 173 | for (k in value) { 174 | if (Object.prototype.hasOwnProperty.call(value, k)) { 175 | v = str(k, value); 176 | if (v) { 177 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 178 | } 179 | } 180 | } 181 | } 182 | 183 | // Join all of the member texts together, separated with commas, 184 | // and wrap them in braces. 185 | 186 | v = partial.length === 0 187 | ? '{}' 188 | : gap 189 | ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' 190 | : '{' + partial.join(',') + '}'; 191 | gap = mind; 192 | return v; 193 | } 194 | } 195 | 196 | // If the JSON object does not yet have a stringify method, give it one. 197 | 198 | if (typeof JSON.stringify !== 'function') { 199 | JSON.stringify = function (value, replacer, space) { 200 | 201 | // The stringify method takes a value and an optional replacer, and an optional 202 | // space parameter, and returns a JSON text. The replacer can be a function 203 | // that can replace values, or an array of strings that will select the keys. 204 | // A default replacer method can be provided. Use of the space parameter can 205 | // produce text that is more easily readable. 206 | 207 | var i; 208 | gap = ''; 209 | indent = ''; 210 | 211 | // If the space parameter is a number, make an indent string containing that 212 | // many spaces. 213 | 214 | if (typeof space === 'number') { 215 | for (i = 0; i < space; i += 1) { 216 | indent += ' '; 217 | } 218 | 219 | // If the space parameter is a string, it will be used as the indent string. 220 | 221 | } else if (typeof space === 'string') { 222 | indent = space; 223 | } 224 | 225 | // If there is a replacer, it must be a function or an array. 226 | // Otherwise, throw an error. 227 | 228 | rep = replacer; 229 | if (replacer && typeof replacer !== 'function' && 230 | (typeof replacer !== 'object' || 231 | typeof replacer.length !== 'number')) { 232 | throw new Error('JSON.stringify'); 233 | } 234 | 235 | // Make a fake root object containing our value under the key of ''. 236 | // Return the result of stringifying the value. 237 | 238 | return str('', {'': value}); 239 | }; 240 | } 241 | 242 | 243 | // If the JSON object does not yet have a parse method, give it one. 244 | 245 | if (typeof JSON.parse !== 'function') { 246 | JSON.parse = function (text, reviver) { 247 | 248 | // The parse method takes a text and an optional reviver function, and returns 249 | // a JavaScript value if the text is a valid JSON text. 250 | 251 | var j; 252 | 253 | function walk(holder, key) { 254 | 255 | // The walk method is used to recursively walk the resulting structure so 256 | // that modifications can be made. 257 | 258 | var k, v, value = holder[key]; 259 | if (value && typeof value === 'object') { 260 | for (k in value) { 261 | if (Object.prototype.hasOwnProperty.call(value, k)) { 262 | v = walk(value, k); 263 | if (v !== undefined) { 264 | value[k] = v; 265 | } else { 266 | delete value[k]; 267 | } 268 | } 269 | } 270 | } 271 | return reviver.call(holder, key, value); 272 | } 273 | 274 | 275 | // Parsing happens in four stages. In the first stage, we replace certain 276 | // Unicode characters with escape sequences. JavaScript handles many characters 277 | // incorrectly, either silently deleting them, or treating them as line endings. 278 | 279 | text = String(text); 280 | cx.lastIndex = 0; 281 | if (cx.test(text)) { 282 | text = text.replace(cx, function (a) { 283 | return '\\u' + 284 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 285 | }); 286 | } 287 | 288 | // In the second stage, we run the text against regular expressions that look 289 | // for non-JSON patterns. We are especially concerned with '()' and 'new' 290 | // because they can cause invocation, and '=' because it can cause mutation. 291 | // But just to be safe, we want to reject all unexpected forms. 292 | 293 | // We split the second stage into 4 regexp operations in order to work around 294 | // crippling inefficiencies in IE's and Safari's regexp engines. First we 295 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we 296 | // replace all simple value tokens with ']' characters. Third, we delete all 297 | // open brackets that follow a colon or comma or that begin the text. Finally, 298 | // we look to see that the remaining characters are only whitespace or ']' or 299 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. 300 | 301 | if (/^[\],:{}\s]*$/ 302 | .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') 303 | .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') 304 | .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { 305 | 306 | // In the third stage we use the eval function to compile the text into a 307 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity 308 | // in JavaScript: it can begin a block or an object literal. We wrap the text 309 | // in parens to eliminate the ambiguity. 310 | 311 | j = eval('(' + text + ')'); 312 | 313 | // In the optional fourth stage, we recursively walk the new structure, passing 314 | // each name/value pair to a reviver function for possible transformation. 315 | 316 | return typeof reviver === 'function' 317 | ? walk({'': j}, '') 318 | : j; 319 | } 320 | 321 | // If the text is not JSON parseable, then a SyntaxError is thrown. 322 | 323 | throw new SyntaxError('JSON.parse'); 324 | }; 325 | } 326 | }()); -------------------------------------------------------------------------------- /php/EpiCurl.php: -------------------------------------------------------------------------------- 1 | mc = curl_multi_init(); 26 | $this->properties = array( 27 | 'code' => CURLINFO_HTTP_CODE, 28 | 'time' => CURLINFO_TOTAL_TIME, 29 | 'length'=> CURLINFO_CONTENT_LENGTH_DOWNLOAD, 30 | 'type' => CURLINFO_CONTENT_TYPE, 31 | 'url' => CURLINFO_EFFECTIVE_URL 32 | ); 33 | } 34 | 35 | public function addEasyCurl($ch) 36 | { 37 | $key = $this->getKey($ch); 38 | $this->requests[$key] = $ch; 39 | curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, 'headerCallback')); 40 | $done = array('handle' => $ch); 41 | $this->storeResponse($done, false); 42 | $this->startTimer($key); 43 | return new EpiCurlManager($key); 44 | } 45 | 46 | public function addCurl($ch) 47 | { 48 | $key = $this->getKey($ch); 49 | $this->requests[$key] = $ch; 50 | curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, 'headerCallback')); 51 | 52 | $code = curl_multi_add_handle($this->mc, $ch); 53 | $this->startTimer($key); 54 | 55 | // (1) 56 | if($code === CURLM_OK || $code === CURLM_CALL_MULTI_PERFORM) 57 | { 58 | do { 59 | $code = $this->execStatus = curl_multi_exec($this->mc, $this->running); 60 | } while ($this->execStatus === CURLM_CALL_MULTI_PERFORM); 61 | 62 | return new EpiCurlManager($key); 63 | } 64 | else 65 | { 66 | return $code; 67 | } 68 | } 69 | 70 | public function getResult($key = null) 71 | { 72 | if($key != null) 73 | { 74 | if(isset($this->responses[$key])) 75 | { 76 | return $this->responses[$key]; 77 | } 78 | 79 | $innerSleepInt = $outerSleepInt = 1; 80 | while($this->running && ($this->execStatus == CURLM_OK || $this->execStatus == CURLM_CALL_MULTI_PERFORM)) 81 | { 82 | usleep(intval($outerSleepInt)); 83 | $outerSleepInt = intval(max(1, ($outerSleepInt*$this->sleepIncrement))); 84 | $ms=curl_multi_select($this->mc, 0); 85 | if($ms > 0) 86 | { 87 | do{ 88 | $this->execStatus = curl_multi_exec($this->mc, $this->running); 89 | usleep(intval($innerSleepInt)); 90 | $innerSleepInt = intval(max(1, ($innerSleepInt*$this->sleepIncrement))); 91 | }while($this->execStatus==CURLM_CALL_MULTI_PERFORM); 92 | $innerSleepInt = 1; 93 | } 94 | $this->storeResponses(); 95 | if(isset($this->responses[$key]['data'])) 96 | { 97 | return $this->responses[$key]; 98 | } 99 | $runningCurrent = $this->running; 100 | } 101 | return null; 102 | } 103 | return false; 104 | } 105 | 106 | public static function getSequence() 107 | { 108 | return new EpiSequence(self::$timers); 109 | } 110 | 111 | public static function getTimers() 112 | { 113 | return self::$timers; 114 | } 115 | 116 | private function getKey($ch) 117 | { 118 | return (string)$ch; 119 | } 120 | 121 | private function headerCallback($ch, $header) 122 | { 123 | $_header = trim($header); 124 | $colonPos= strpos($_header, ':'); 125 | if($colonPos > 0) 126 | { 127 | $key = substr($_header, 0, $colonPos); 128 | $val = preg_replace('/^\W+/','',substr($_header, $colonPos)); 129 | $this->responses[$this->getKey($ch)]['headers'][$key] = $val; 130 | } 131 | return strlen($header); 132 | } 133 | 134 | private function storeResponses() 135 | { 136 | while($done = curl_multi_info_read($this->mc)) 137 | { 138 | $this->storeResponse($done); 139 | } 140 | } 141 | 142 | private function storeResponse($done, $isAsynchronous = true) 143 | { 144 | $key = $this->getKey($done['handle']); 145 | $this->stopTimer($key, $done); 146 | if($isAsynchronous) 147 | $this->responses[$key]['data'] = curl_multi_getcontent($done['handle']); 148 | else 149 | $this->responses[$key]['data'] = curl_exec($done['handle']); 150 | 151 | foreach($this->properties as $name => $const) 152 | { 153 | $this->responses[$key][$name] = curl_getinfo($done['handle'], $const); 154 | } 155 | if($isAsynchronous) 156 | curl_multi_remove_handle($this->mc, $done['handle']); 157 | curl_close($done['handle']); 158 | } 159 | 160 | private function startTimer($key) 161 | { 162 | self::$timers[$key]['start'] = microtime(true); 163 | } 164 | 165 | private function stopTimer($key, $done) 166 | { 167 | self::$timers[$key]['end'] = microtime(true); 168 | self::$timers[$key]['api'] = curl_getinfo($done['handle'], CURLINFO_EFFECTIVE_URL); 169 | self::$timers[$key]['time'] = curl_getinfo($done['handle'], CURLINFO_TOTAL_TIME); 170 | self::$timers[$key]['code'] = curl_getinfo($done['handle'], CURLINFO_HTTP_CODE); 171 | } 172 | 173 | static function getInstance() 174 | { 175 | if(self::$inst == null) 176 | { 177 | self::$singleton = 1; 178 | self::$inst = new EpiCurl(); 179 | } 180 | 181 | return self::$inst; 182 | } 183 | } 184 | 185 | class EpiCurlManager 186 | { 187 | private $key; 188 | private $epiCurl; 189 | 190 | public function __construct($key) 191 | { 192 | $this->key = $key; 193 | $this->epiCurl = EpiCurl::getInstance(); 194 | } 195 | 196 | public function __get($name) 197 | { 198 | $responses = $this->epiCurl->getResult($this->key); 199 | return isset($responses[$name]) ? $responses[$name] : null; 200 | } 201 | 202 | public function __isset($name) 203 | { 204 | $val = self::__get($name); 205 | return empty($val); 206 | } 207 | } 208 | 209 | /* 210 | * Credits: 211 | * - (1) Alistair pointed out that curl_multi_add_handle can return CURLM_CALL_MULTI_PERFORM on success. 212 | */ 213 | ?> -------------------------------------------------------------------------------- /php/EpiOAuth.php: -------------------------------------------------------------------------------- 1 | headers = array_merge($this->headers, $header); 28 | elseif(!empty($header)) 29 | $this->headers[] = $header; 30 | } 31 | 32 | public function getAccessToken($params = null) 33 | { 34 | if (isset($_GET['oauth_verifier']) && !isset($params['oauth_verifier'])) 35 | { 36 | $params['oauth_verifier'] = $_GET['oauth_verifier']; 37 | } 38 | $resp = $this->httpRequest('POST', $this->getUrl($this->accessTokenUrl), $params); 39 | return new EpiOAuthResponse($resp); 40 | } 41 | 42 | public function getAuthenticateUrl($token = null, $params = null) 43 | { 44 | $token = $token ? $token : $this->getRequestToken($params); 45 | if (is_object($token)) $token = $token->oauth_token; 46 | $addlParams = empty($params) ? '' : '&'.http_build_query($params, '', '&'); 47 | return $this->getUrl($this->authenticateUrl) . '?oauth_token=' . $token . $addlParams; 48 | } 49 | 50 | public function getAuthorizeUrl($token = null, $params = null) 51 | { 52 | $token = $token ? $token : $this->getRequestToken($params); 53 | if (is_object($token)) $token = $token->oauth_token; 54 | return $this->getUrl($this->authorizeUrl) . '?oauth_token=' . $token; 55 | } 56 | 57 | // DEPRECATED in favor of getAuthorizeUrl() 58 | public function getAuthorizationUrl($token = null) 59 | { 60 | return $this->getAuthorizeUrl($token); 61 | } 62 | 63 | public function getRequestToken($params = null) 64 | { 65 | if (isset($this->callback) && !isset($params['oauth_callback'])) 66 | { 67 | $params['oauth_callback'] = $this->callback; 68 | } 69 | $resp = $this->httpRequest('POST', $this->getUrl($this->requestTokenUrl), $params); 70 | return new EpiOAuthResponse($resp); 71 | } 72 | 73 | public function getUrl($url) 74 | { 75 | if($this->useSSL === true) 76 | return preg_replace('/^http:/', 'https:', $url); 77 | 78 | return $url; 79 | } 80 | 81 | public function httpRequest($method = null, $url = null, $params = null, $isMultipart = false) 82 | { 83 | if(empty($method) || empty($url)) 84 | return false; 85 | 86 | if(empty($params['oauth_signature'])) 87 | $params = $this->prepareParameters($method, $url, $params); 88 | 89 | switch($method) 90 | { 91 | case 'GET': 92 | return $this->httpGet($url, $params); 93 | break; 94 | case 'POST': 95 | return $this->httpPost($url, $params, $isMultipart); 96 | break; 97 | case 'DELETE': 98 | return $this->httpDelete($url, $params); 99 | break; 100 | 101 | } 102 | } 103 | 104 | public function setDebug($bool=false) 105 | { 106 | $this->debug = (bool)$bool; 107 | } 108 | 109 | public function setFollowLocation($bool) 110 | { 111 | $this->followLocation = (bool)$bool; 112 | } 113 | 114 | public function setTimeout($requestTimeout = null, $connectionTimeout = null) 115 | { 116 | if($requestTimeout !== null) 117 | $this->requestTimeout = floatval($requestTimeout); 118 | if($connectionTimeout !== null) 119 | $this->connectionTimeout = floatval($connectionTimeout); 120 | } 121 | 122 | public function setToken($token = null, $secret = null) 123 | { 124 | $this->token = $token; 125 | $this->tokenSecret = $secret; 126 | } 127 | 128 | public function setCallback($callback = null) 129 | { 130 | $this->callback = $callback; 131 | } 132 | 133 | public function useSSL($use = false) 134 | { 135 | $this->useSSL = (bool)$use; 136 | } 137 | 138 | protected function addDefaultHeaders($url, $oauthHeaders) 139 | { 140 | $_h = array('Expect:'); 141 | $urlParts = parse_url($url); 142 | $oauth = 'Authorization: OAuth realm="' . $urlParts['scheme'] . '://' . $urlParts['host'] . $urlParts['path'] . '",'; 143 | foreach($oauthHeaders as $name => $value) 144 | { 145 | $oauth .= "{$name}=\"{$value}\","; 146 | } 147 | $_h[] = substr($oauth, 0, -1); 148 | $_h[] = "User-Agent: {$this->userAgent}"; 149 | $this->addHeader($_h); 150 | } 151 | 152 | protected function buildHttpQueryRaw($params) 153 | { 154 | $retval = ''; 155 | foreach((array)$params as $key => $value) 156 | $retval .= "{$key}={$value}&"; 157 | $retval = substr($retval, 0, -1); 158 | return $retval; 159 | } 160 | 161 | protected function curlInit($url) 162 | { 163 | $ch = curl_init($url); 164 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 165 | curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers); 166 | curl_setopt($ch, CURLOPT_TIMEOUT, $this->requestTimeout); 167 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectionTimeout); 168 | curl_setopt($ch, CURLOPT_ENCODING, ''); 169 | if($this->followLocation) 170 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 171 | if(isset($_SERVER ['SERVER_ADDR']) && !empty($_SERVER['SERVER_ADDR']) && $_SERVER['SERVER_ADDR'] != '127.0.0.1') 172 | curl_setopt($ch, CURLOPT_INTERFACE, $_SERVER ['SERVER_ADDR']); 173 | 174 | // if the certificate exists then use it, else bypass ssl checks 175 | if(file_exists($cert = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'ca-bundle.crt')) 176 | { 177 | curl_setopt($ch, CURLOPT_CAINFO, $cert); 178 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 179 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); 180 | } 181 | else 182 | { 183 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 184 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 185 | } 186 | return $ch; 187 | } 188 | 189 | protected function emptyHeaders() 190 | { 191 | $this->headers = array(); 192 | } 193 | 194 | protected function encode_rfc3986($string) 195 | { 196 | return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode(($string)))); 197 | } 198 | 199 | protected function generateNonce() 200 | { 201 | if(isset($this->nonce)) // for unit testing 202 | return $this->nonce; 203 | 204 | return md5(uniqid(rand(), true)); 205 | } 206 | 207 | // parameters should already have been passed through prepareParameters 208 | // no need to double encode 209 | protected function generateSignature($method = null, $url = null, $params = null) 210 | { 211 | if(empty($method) || empty($url)) 212 | return false; 213 | 214 | // concatenating and encode 215 | $concatenatedParams = $this->encode_rfc3986($this->buildHttpQueryRaw($params)); 216 | 217 | // normalize url 218 | $normalizedUrl = $this->encode_rfc3986($this->normalizeUrl($url)); 219 | $method = $this->encode_rfc3986($method); // don't need this but why not? 220 | 221 | $signatureBaseString = "{$method}&{$normalizedUrl}&{$concatenatedParams}"; 222 | return $this->signString($signatureBaseString); 223 | } 224 | 225 | protected function executeCurl($ch) 226 | { 227 | if($this->isAsynchronous) 228 | return $this->curl->addCurl($ch); 229 | else 230 | return $this->curl->addEasyCurl($ch); 231 | } 232 | 233 | protected function httpDelete($url, $params) { 234 | $this->addDefaultHeaders($url, $params['oauth']); 235 | $ch = $this->curlInit($url); 236 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); 237 | curl_setopt($ch, CURLOPT_POSTFIELDS, $this->buildHttpQueryRaw($params['request'])); 238 | $resp = $this->executeCurl($ch); 239 | $this->emptyHeaders(); 240 | return $resp; 241 | } 242 | 243 | protected function httpGet($url, $params = null) 244 | { 245 | if(count($params['request']) > 0) 246 | { 247 | $url .= '?'; 248 | foreach($params['request'] as $k => $v) 249 | { 250 | $url .= "{$k}={$v}&"; 251 | } 252 | $url = substr($url, 0, -1); 253 | } 254 | $this->addDefaultHeaders($url, $params['oauth']); 255 | $ch = $this->curlInit($url); 256 | $resp = $this->executeCurl($ch); 257 | $this->emptyHeaders(); 258 | 259 | return $resp; 260 | } 261 | 262 | protected function httpPost($url, $params = null, $isMultipart) 263 | { 264 | $this->addDefaultHeaders($url, $params['oauth']); 265 | $ch = $this->curlInit($url); 266 | curl_setopt($ch, CURLOPT_POST, 1); 267 | // php's curl extension automatically sets the content type 268 | // based on whether the params are in string or array form 269 | if($isMultipart) 270 | curl_setopt($ch, CURLOPT_POSTFIELDS, $params['request']); 271 | else 272 | curl_setopt($ch, CURLOPT_POSTFIELDS, $this->buildHttpQueryRaw($params['request'])); 273 | $resp = $this->executeCurl($ch); 274 | $this->emptyHeaders(); 275 | 276 | return $resp; 277 | } 278 | 279 | protected function normalizeUrl($url = null) 280 | { 281 | $urlParts = parse_url($url); 282 | $scheme = strtolower($urlParts['scheme']); 283 | $host = strtolower($urlParts['host']); 284 | $port = isset($urlParts['port']) ? intval($urlParts['port']) : 0; 285 | 286 | $retval = strtolower($scheme) . '://' . strtolower($host); 287 | 288 | if(!empty($port) && (($scheme === 'http' && $port != 80) || ($scheme === 'https' && $port != 443))) 289 | $retval .= ":{$port}"; 290 | 291 | $retval .= $urlParts['path']; 292 | if(!empty($urlParts['query'])) 293 | { 294 | $retval .= "?{$urlParts['query']}"; 295 | } 296 | 297 | return $retval; 298 | } 299 | 300 | protected function isMultipart($params = null) 301 | { 302 | if($params) 303 | { 304 | foreach($params as $k => $v) 305 | { 306 | if(strncmp('@',$k,1) === 0) 307 | return true; 308 | } 309 | } 310 | return false; 311 | } 312 | 313 | protected function prepareParameters($method = null, $url = null, $params = null) 314 | { 315 | if(empty($method) || empty($url)) 316 | return false; 317 | 318 | $oauth['oauth_consumer_key'] = $this->consumerKey; 319 | $oauth['oauth_token'] = $this->token; 320 | $oauth['oauth_nonce'] = $this->generateNonce(); 321 | $oauth['oauth_timestamp'] = !isset($this->timestamp) ? time() : $this->timestamp; // for unit test 322 | $oauth['oauth_signature_method'] = $this->signatureMethod; 323 | if(isset($params['oauth_verifier'])) 324 | { 325 | $oauth['oauth_verifier'] = $params['oauth_verifier']; 326 | unset($params['oauth_verifier']); 327 | } 328 | $oauth['oauth_version'] = $this->version; 329 | // encode all oauth values 330 | foreach($oauth as $k => $v) 331 | $oauth[$k] = $this->encode_rfc3986($v); 332 | // encode all non '@' params 333 | // keep sigParams for signature generation (exclude '@' params) 334 | // rename '@key' to 'key' 335 | $sigParams = array(); 336 | $hasFile = false; 337 | if(is_array($params)) 338 | { 339 | foreach($params as $k => $v) 340 | { 341 | if(strncmp('@',$k,1) !== 0) 342 | { 343 | $sigParams[$k] = $this->encode_rfc3986($v); 344 | $params[$k] = $this->encode_rfc3986($v); 345 | } 346 | else 347 | { 348 | $params[substr($k, 1)] = $v; 349 | unset($params[$k]); 350 | $hasFile = true; 351 | } 352 | } 353 | 354 | if($hasFile === true) 355 | $sigParams = array(); 356 | } 357 | 358 | $sigParams = array_merge($oauth, (array)$sigParams); 359 | 360 | // sorting 361 | ksort($sigParams); 362 | 363 | // signing 364 | $oauth['oauth_signature'] = $this->encode_rfc3986($this->generateSignature($method, $url, $sigParams)); 365 | return array('request' => $params, 'oauth' => $oauth); 366 | } 367 | 368 | protected function signString($string = null) 369 | { 370 | $retval = false; 371 | switch($this->signatureMethod) 372 | { 373 | case 'HMAC-SHA1': 374 | $key = $this->encode_rfc3986($this->consumerSecret) . '&' . $this->encode_rfc3986($this->tokenSecret); 375 | $retval = base64_encode(hash_hmac('sha1', $string, $key, true)); 376 | break; 377 | } 378 | 379 | return $retval; 380 | } 381 | 382 | public function __construct($consumerKey, $consumerSecret, $signatureMethod='HMAC-SHA1') 383 | { 384 | $this->consumerKey = $consumerKey; 385 | $this->consumerSecret = $consumerSecret; 386 | $this->signatureMethod = $signatureMethod; 387 | $this->curl = EpiCurl::getInstance(); 388 | } 389 | } 390 | 391 | class EpiOAuthResponse 392 | { 393 | private $__resp; 394 | protected $debug = false; 395 | 396 | public function __construct($resp) 397 | { 398 | $this->__resp = $resp; 399 | } 400 | 401 | public function __get($name) 402 | { 403 | if($this->__resp->code != 200) 404 | EpiOAuthException::raise($this->__resp, $this->debug); 405 | 406 | parse_str($this->__resp->data, $result); 407 | foreach($result as $k => $v) 408 | { 409 | $this->$k = $v; 410 | } 411 | 412 | return isset($result[$name]) ? $result[$name] : null; 413 | } 414 | 415 | public function __toString() 416 | { 417 | return $this->__resp->data; 418 | } 419 | } 420 | 421 | class EpiOAuthException extends Exception 422 | { 423 | public static function raise($response, $debug) 424 | { 425 | $message = $response->responseText; 426 | 427 | switch($response->code) 428 | { 429 | case 400: 430 | throw new EpiOAuthBadRequestException($message, $response->code); 431 | case 401: 432 | throw new EpiOAuthUnauthorizedException($message, $response->code); 433 | default: 434 | throw new EpiOAuthException($message, $response->code); 435 | } 436 | } 437 | } 438 | class EpiOAuthBadRequestException extends EpiOAuthException{} 439 | class EpiOAuthUnauthorizedException extends EpiOAuthException{} 440 | ?> -------------------------------------------------------------------------------- /php/EpiTwitter.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class EpiTwitter extends EpiOAuth 13 | { 14 | const EPITWITTER_SIGNATURE_METHOD = 'HMAC-SHA1'; 15 | const EPITWITTER_AUTH_OAUTH = 'oauth'; 16 | const EPITWITTER_AUTH_BASIC = 'basic'; 17 | protected $requestTokenUrl= 'https://api.twitter.com/oauth/request_token'; 18 | protected $accessTokenUrl = 'https://api.twitter.com/oauth/access_token'; 19 | protected $authorizeUrl = 'https://api.twitter.com/oauth/authorize'; 20 | protected $authenticateUrl= 'https://api.twitter.com/oauth/authenticate'; 21 | protected $apiUrl = 'http://api.twitter.com'; 22 | protected $apiVersionedUrl= 'http://api.twitter.com'; 23 | protected $searchUrl = 'http://search.twitter.com'; 24 | protected $userAgent = 'EpiTwitter (http://github.com/jmathai/twitter-async/tree/)'; 25 | protected $apiVersion = '1'; 26 | protected $isAsynchronous = false; 27 | 28 | /* OAuth methods */ 29 | public function delete($endpoint, $params = null) 30 | { 31 | return $this->request('DELETE', $endpoint, $params); 32 | } 33 | 34 | public function get($endpoint, $params = null) 35 | { 36 | return $this->request('GET', $endpoint, $params); 37 | } 38 | 39 | public function post($endpoint, $params = null) 40 | { 41 | return $this->request('POST', $endpoint, $params); 42 | } 43 | 44 | /* Basic auth methods */ 45 | public function delete_basic($endpoint, $params = null, $username = null, $password = null) 46 | { 47 | return $this->request_basic('DELETE', $endpoint, $params, $username, $password); 48 | } 49 | 50 | public function get_basic($endpoint, $params = null, $username = null, $password = null) 51 | { 52 | return $this->request_basic('GET', $endpoint, $params, $username, $password); 53 | } 54 | 55 | public function post_basic($endpoint, $params = null, $username = null, $password = null) 56 | { 57 | return $this->request_basic('POST', $endpoint, $params, $username, $password); 58 | } 59 | 60 | public function useApiVersion($version = null) 61 | { 62 | $this->apiVersion = $version; 63 | } 64 | 65 | public function useAsynchronous($async = true) 66 | { 67 | $this->isAsynchronous = (bool)$async; 68 | } 69 | 70 | public function __construct($consumerKey = null, $consumerSecret = null, $oauthToken = null, $oauthTokenSecret = null) 71 | { 72 | parent::__construct($consumerKey, $consumerSecret, self::EPITWITTER_SIGNATURE_METHOD); 73 | $this->setToken($oauthToken, $oauthTokenSecret); 74 | } 75 | 76 | public function __call($name, $params = null/*, $username, $password*/) 77 | { 78 | $parts = explode('_', $name); 79 | $method = strtoupper(array_shift($parts)); 80 | $parts = implode('_', $parts); 81 | $endpoint = '/' . preg_replace('/[A-Z]|[0-9]+/e', "'/'.strtolower('\\0')", $parts) . '.json'; 82 | /* HACK: this is required for list support that starts with a user id */ 83 | $endpoint = str_replace('//','/',$endpoint); 84 | $args = !empty($params) ? array_shift($params) : null; 85 | 86 | // calls which do not have a consumerKey are assumed to not require authentication 87 | if($this->consumerKey === null) 88 | { 89 | $username = null; 90 | $password = null; 91 | 92 | if(!empty($params)) 93 | { 94 | $username = array_shift($params); 95 | $password = !empty($params) ? array_shift($params) : null; 96 | } 97 | 98 | return $this->request_basic($method, $endpoint, $args, $username, $password); 99 | } 100 | 101 | return $this->request($method, $endpoint, $args); 102 | } 103 | 104 | private function getApiUrl($endpoint) 105 | { 106 | if(preg_match('@^/search[./]?(?=(json|daily|current|weekly))@', $endpoint)) 107 | return "{$this->searchUrl}{$endpoint}"; 108 | elseif(!empty($this->apiVersion)) 109 | return "{$this->apiVersionedUrl}/{$this->apiVersion}{$endpoint}"; 110 | else 111 | return "{$this->apiUrl}{$endpoint}"; 112 | } 113 | 114 | private function request($method, $endpoint, $params = null) 115 | { 116 | $url = $this->getUrl($this->getApiUrl($endpoint)); 117 | $resp= new EpiTwitterJson(call_user_func(array($this, 'httpRequest'), $method, $url, $params, $this->isMultipart($params)), $this->debug); 118 | if(!$this->isAsynchronous) 119 | $resp->response; 120 | 121 | return $resp; 122 | } 123 | 124 | private function request_basic($method, $endpoint, $params = null, $username = null, $password = null) 125 | { 126 | $url = $this->getApiUrl($endpoint); 127 | if($method === 'GET') 128 | $url .= is_null($params) ? '' : '?'.http_build_query($params, '', '&'); 129 | $ch = curl_init($url); 130 | curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); 131 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 132 | curl_setopt($ch, CURLOPT_TIMEOUT, $this->requestTimeout); 133 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); 134 | if($method === 'POST' && $params !== null) 135 | { 136 | if($this->isMultipart($params)) 137 | curl_setopt($ch, CURLOPT_POSTFIELDS, $params); 138 | else 139 | curl_setopt($ch, CURLOPT_POSTFIELDS, $this->buildHttpQueryRaw($params)); 140 | } 141 | if(!empty($username) && !empty($password)) 142 | curl_setopt($ch, CURLOPT_USERPWD, "{$username}:{$password}"); 143 | 144 | $resp = new EpiTwitterJson(EpiCurl::getInstance()->addCurl($ch), $this->debug); 145 | if(!$this->isAsynchronous) 146 | $resp->response; 147 | 148 | return $resp; 149 | } 150 | } 151 | 152 | class EpiTwitterJson implements ArrayAccess, Countable, IteratorAggregate 153 | { 154 | private $debug; 155 | private $__resp; 156 | public function __construct($response, $debug = false) 157 | { 158 | $this->__resp = $response; 159 | $this->debug = $debug; 160 | } 161 | 162 | // ensure that calls complete by blocking for results, NOOP if already returned 163 | public function __destruct() 164 | { 165 | $this->responseText; 166 | } 167 | 168 | // Implementation of the IteratorAggregate::getIterator() to support foreach ($this as $...) 169 | public function getIterator () 170 | { 171 | if ($this->__obj) { 172 | return new ArrayIterator($this->__obj); 173 | } else { 174 | return new ArrayIterator($this->response); 175 | } 176 | } 177 | 178 | // Implementation of Countable::count() to support count($this) 179 | public function count () 180 | { 181 | return count($this->response); 182 | } 183 | 184 | // Next four functions are to support ArrayAccess interface 185 | // 1 186 | public function offsetSet($offset, $value) 187 | { 188 | $this->response[$offset] = $value; 189 | } 190 | 191 | // 2 192 | public function offsetExists($offset) 193 | { 194 | return isset($this->response[$offset]); 195 | } 196 | 197 | // 3 198 | public function offsetUnset($offset) 199 | { 200 | unset($this->response[$offset]); 201 | } 202 | 203 | // 4 204 | public function offsetGet($offset) 205 | { 206 | return isset($this->response[$offset]) ? $this->response[$offset] : null; 207 | } 208 | 209 | public function __get($name) 210 | { 211 | $accessible = array('responseText'=>1,'headers'=>1,'code'=>1); 212 | $this->responseText = $this->__resp->data; 213 | $this->headers = $this->__resp->headers; 214 | $this->code = $this->__resp->code; 215 | if(isset($accessible[$name]) && $accessible[$name]) 216 | return $this->$name; 217 | elseif(($this->code < 200 || $this->code >= 400) && !isset($accessible[$name])) 218 | EpiTwitterException::raise($this->__resp, $this->debug); 219 | 220 | // Call appears ok so we can fill in the response 221 | $this->response = json_decode($this->responseText, 1); 222 | $this->__obj = json_decode($this->responseText); 223 | 224 | if(gettype($this->__obj) === 'object') 225 | { 226 | foreach($this->__obj as $k => $v) 227 | { 228 | $this->$k = $v; 229 | } 230 | } 231 | 232 | if (property_exists($this, $name)) { 233 | return $this->$name; 234 | } 235 | return null; 236 | } 237 | 238 | public function __isset($name) 239 | { 240 | $value = self::__get($name); 241 | return !empty($name); 242 | } 243 | } 244 | 245 | class EpiTwitterException extends Exception 246 | { 247 | public static function raise($response, $debug) 248 | { 249 | $message = $response->data; 250 | switch($response->code) 251 | { 252 | case 400: 253 | throw new EpiTwitterBadRequestException($message, $response->code); 254 | case 401: 255 | throw new EpiTwitterNotAuthorizedException($message, $response->code); 256 | case 403: 257 | throw new EpiTwitterForbiddenException($message, $response->code); 258 | case 404: 259 | throw new EpiTwitterNotFoundException($message, $response->code); 260 | case 406: 261 | throw new EpiTwitterNotAcceptableException($message, $response->code); 262 | case 420: 263 | throw new EpiTwitterEnhanceYourCalmException($message, $response->code); 264 | case 500: 265 | throw new EpiTwitterInternalServerException($message, $response->code); 266 | case 502: 267 | throw new EpiTwitterBadGatewayException($message, $response->code); 268 | case 503: 269 | throw new EpiTwitterServiceUnavailableException($message, $response->code); 270 | default: 271 | throw new EpiTwitterException($message, $response->code); 272 | } 273 | } 274 | } 275 | class EpiTwitterBadRequestException extends EpiTwitterException{} 276 | class EpiTwitterNotAuthorizedException extends EpiTwitterException{} 277 | class EpiTwitterForbiddenException extends EpiTwitterException{} 278 | class EpiTwitterNotFoundException extends EpiTwitterException{} 279 | class EpiTwitterNotAcceptableException extends EpiTwitterException{} 280 | class EpiTwitterEnhanceYourCalmException extends EpiTwitterException{} 281 | class EpiTwitterInternalServerException extends EpiTwitterException{} 282 | class EpiTwitterBadGatewayException extends EpiTwitterException{} 283 | class EpiTwitterServiceUnavailableException extends EpiTwitterException{} 284 | ?> -------------------------------------------------------------------------------- /php/facebook_auth.php: -------------------------------------------------------------------------------- 1 | top.location.href='" . $dialog_url . "'"); 16 | 17 | } 18 | 19 | if($_REQUEST['state'] == $_SESSION['state']) { 20 | 21 | $token_url = "https://graph.facebook.com/oauth/access_token?" 22 | . "client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url) 23 | . "&client_secret=" . $app_secret . "&code=" . $code; 24 | 25 | $response = file_get_contents($token_url); 26 | $params = null; 27 | parse_str($response, $params); 28 | 29 | $graph_url = "https://graph.facebook.com/me?access_token=" . $params['access_token']; 30 | $user = json_decode(file_get_contents($graph_url)); 31 | 32 | setcookie('fb_access_token', $params['access_token'], null, '/'); 33 | setcookie('fb_user_id', $user->id, null, '/'); 34 | setcookie('fb_user_name', $user->name, null, '/'); 35 | 36 | echo(""); 37 | 38 | } 39 | 40 | ?> -------------------------------------------------------------------------------- /php/facebook_keys.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /php/facebook_sign_out.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /php/twitter_auth.php: -------------------------------------------------------------------------------- 1 | window.close();"); 13 | exit; 14 | 15 | } 16 | 17 | 18 | if( !isset( $_GET['oauth_token'] ) ) { 19 | 20 | $url = $Twitter->getAuthenticateUrl(); 21 | header( 'Location: ' . $url ); 22 | exit; 23 | 24 | } 25 | 26 | 27 | if( isset( $_GET['oauth_token'] ) || (isset( $_COOKIE['oauth_token'] ) && isset( $_COOKIE['oauth_token_secret'] ) ) ) { 28 | 29 | // user accepted access 30 | if( !isset( $_COOKIE['oauth_token'] ) || !isset( $_COOKIE['oauth_token_secret'] ) ) { 31 | 32 | // user comes from twitter 33 | $Twitter->setToken( $_GET['oauth_token'] ); 34 | $token = $Twitter->getAccessToken(); 35 | $Twitter->setToken($token->oauth_token, $token->oauth_token_secret); 36 | 37 | setcookie('twitter_oauth_token', $token->oauth_token, null, '/'); 38 | setcookie('twitter_oauth_token_secret', $token->oauth_token_secret, null, '/'); 39 | 40 | } else { 41 | 42 | // user switched pages and came back or got here directly, stilled logged in 43 | $Twitter->setToken( $_COOKIE['oauth_token'], $_COOKIE['oauth_token_secret'] ); 44 | } 45 | 46 | $result = $Twitter->get_accountVerify_credentials(); 47 | setcookie('twitter_user_name', $result->screen_name, null, '/'); 48 | setcookie('twitter_user_image_url', $result->profile_image_url, null, '/'); 49 | 50 | echo(""); 51 | 52 | } 53 | 54 | ?> -------------------------------------------------------------------------------- /php/twitter_keys.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /php/twitter_search_people.php: -------------------------------------------------------------------------------- 1 | array( 'message' => "You have to authenticate with Twitter to search for people. Let's Do It!" ) ) ); 11 | exit; 12 | 13 | } 14 | 15 | try { 16 | 17 | $Twitter = new EpiTwitter( TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET ); 18 | $Twitter->setToken( $_GET['oauth_token'], $_GET['oauth_token_secret'] ); 19 | unset($_GET['oauth_token']); 20 | unset($_GET['oauth_token_secret']); 21 | $result = $Twitter->get_usersSearch( $_GET ); 22 | 23 | } catch (Exception $e) { 24 | 25 | echo 'api_error'; 26 | exit; 27 | 28 | } 29 | 30 | $data = array( 'results' => $result->response ); 31 | echo json_encode($data); 32 | 33 | ?> -------------------------------------------------------------------------------- /php/twitter_sign_out.php: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------