├── .gitignore ├── PRIVACY.md ├── README.md ├── background.html ├── forms.css ├── hn.css ├── images ├── arrow-down.png ├── arrow-up.png ├── follow.png ├── icon-128.png ├── icon-48.png ├── icon.png ├── icons.png ├── karma.png ├── loading-light.gif ├── loading.gif ├── promo.png └── unfollow.png ├── js ├── background.js ├── hn.js ├── ident │ ├── ident-0.1.min.js │ ├── ident-content-0.1.min.js │ ├── ident-profile-0.1.min.js │ ├── ident-twitter-parser-0.1.min.js │ ├── ident-ufxtract-parser-0.1.min.js │ ├── ident-yql-parser-0.1.min.js │ └── web-address.min.js └── libs │ ├── jquery-1.7.1.min.js │ ├── jquery.autogrow.js │ ├── jquery.hoverIntent.js │ └── twitter.text.js └── manifest.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /PRIVACY.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | To better protect your privacy, HackerNew provides this privacy policy notice explaining the way your personal information is collected and used (It's not). 4 | 5 | ## Collection of Routine Information 6 | 7 | This extension does not collect any information. 8 | 9 | ## Cookies 10 | 11 | This extension does not set or utilize cookies. 12 | 13 | ## Advertisement and Other Third Parties 14 | 15 | This extension does not display ads or send data of any kind to third parties. 16 | 17 | ## Changes To This Privacy Policy 18 | 19 | This Privacy Policy is effective as of 2021-04-19 and will remain in effect except with respect to any changes in its provisions in the future, which will be in effect immediately after being posted on this page. 20 | 21 | ## Contact Information 22 | 23 | For any questions or concerns regarding the privacy policy, please open an Issue on GitHub. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HackerNew 2 | 3 | A chrome extension to add requested and missing functionality to hacker news including quick user profiles, inline replies, story filtering and more. 4 | 5 | 6 | ## Usage 7 | 8 | Install from the Chrome Webstore to receive automatic updates: 9 | 10 | https://chrome.google.com/webstore/detail/lgoghlndihpmbbgmbpjohilcphbfhddd 11 | 12 | 13 | ## Features 14 | 15 | * Improved readability design 16 | * User following 17 | * Retina screen support 18 | * Quick inline replies 19 | * Quick profiles with social network info when hovering over usernames 20 | * Filtering of stories based on terms and phrases / domain or username 21 | 22 | 23 | ## Development 24 | 25 | This code is old, it's not good, there are jQuery selectors all over the place and 26 | It's probably best rebuilt from scratch. You've been warned :) 27 | 28 | 29 | ## License 30 | 31 | HackerNew is released under the MIT license. It is simple and easy to understand and places almost no restrictions on what you can do with it. 32 | [More Information](http://en.wikipedia.org/wiki/MIT_License) 33 | 34 | 35 | ## Credits 36 | 37 | * Uses jQuery hover intent plugin by [Brian Cherne](http://cherne.net/brian/resources/jquery.hoverIntent.html) 38 | * Entypo pictograms by [Daniel Bruce](http://www.entypo.com) 39 | * Form styles from [Twitter Bootstrap](https://github.com/twitter/bootstrap) 40 | -------------------------------------------------------------------------------- /background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /forms.css: -------------------------------------------------------------------------------- 1 | /****** Form Styles from Twitter Bootstrap *******/ 2 | 3 | /* http://twitter.github.com/bootstrap */ 4 | 5 | form { 6 | margin: 0 0 18px; 7 | } 8 | fieldset { 9 | padding: 0; 10 | margin: 0; 11 | border: 0; 12 | } 13 | legend { 14 | display: block; 15 | width: 100%; 16 | padding: 0; 17 | margin-bottom: 27px; 18 | font-size: 19.5px; 19 | line-height: 36px; 20 | color: #333333; 21 | border: 0; 22 | border-bottom: 1px solid #eee; 23 | } 24 | legend small { 25 | font-size: 13.5px; 26 | color: #999999; 27 | } 28 | label, 29 | input, 30 | button, 31 | select, 32 | textarea { 33 | font-size: 13px; 34 | font-weight: normal; 35 | line-height: 18px; 36 | height: auto !important; 37 | } 38 | input, 39 | button, 40 | select, 41 | textarea { 42 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !important; 43 | } 44 | label { 45 | display: block; 46 | margin-bottom: 5px; 47 | color: #333333; 48 | } 49 | input, 50 | textarea, 51 | select, 52 | .uneditable-input { 53 | display: inline-block; 54 | width: 210px; 55 | height: 18px; 56 | padding: 4px; 57 | margin-bottom: 9px; 58 | font-size: 13px !important; 59 | line-height: 18px; 60 | color: #555555; 61 | border: 1px solid #ccc; 62 | -webkit-border-radius: 3px; 63 | -moz-border-radius: 3px; 64 | border-radius: 3px; 65 | } 66 | .uneditable-textarea { 67 | width: auto; 68 | height: auto; 69 | } 70 | label input, label textarea, label select { 71 | display: block; 72 | } 73 | input[type="image"], input[type="checkbox"], input[type="radio"] { 74 | width: auto; 75 | height: auto; 76 | padding: 0; 77 | margin: 3px 0; 78 | *margin-top: 0; 79 | /* IE7 */ 80 | 81 | line-height: normal; 82 | cursor: pointer; 83 | -webkit-border-radius: 0; 84 | -moz-border-radius: 0; 85 | border-radius: 0; 86 | border: 0 \9; 87 | /* IE9 and down */ 88 | 89 | } 90 | input[type="image"] { 91 | border: 0; 92 | } 93 | input[type="file"] { 94 | width: auto; 95 | padding: initial; 96 | line-height: initial; 97 | border: initial; 98 | background-color: #ffffff; 99 | background-color: initial; 100 | -webkit-box-shadow: none; 101 | -moz-box-shadow: none; 102 | box-shadow: none; 103 | } 104 | input[type="button"], input[type="reset"], input[type="submit"] { 105 | width: auto; 106 | height: auto; 107 | } 108 | select, input[type="file"] { 109 | height: 28px; 110 | /* In IE7, the height of the select element cannot be changed by height, only font-size */ 111 | 112 | *margin-top: 4px; 113 | /* For IE7, add top margin to align select with labels */ 114 | 115 | line-height: 28px; 116 | } 117 | input[type="file"] { 118 | line-height: 18px \9; 119 | } 120 | select { 121 | width: 220px; 122 | background-color: #ffffff; 123 | } 124 | select[multiple], select[size] { 125 | height: auto; 126 | } 127 | input[type="image"] { 128 | -webkit-box-shadow: none; 129 | -moz-box-shadow: none; 130 | box-shadow: none; 131 | } 132 | textarea { 133 | height: auto; 134 | } 135 | input[type="hidden"] { 136 | display: none; 137 | } 138 | .radio, .checkbox { 139 | padding-left: 18px; 140 | } 141 | .radio input[type="radio"], .checkbox input[type="checkbox"] { 142 | float: left; 143 | margin-left: -18px; 144 | } 145 | .controls > .radio:first-child, .controls > .checkbox:first-child { 146 | padding-top: 5px; 147 | } 148 | .radio.inline, .checkbox.inline { 149 | display: inline-block; 150 | padding-top: 5px; 151 | margin-bottom: 0; 152 | vertical-align: middle; 153 | } 154 | .radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { 155 | margin-left: 10px; 156 | } 157 | input, textarea { 158 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 159 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 160 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 161 | -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; 162 | -moz-transition: border linear 0.2s, box-shadow linear 0.2s; 163 | -ms-transition: border linear 0.2s, box-shadow linear 0.2s; 164 | -o-transition: border linear 0.2s, box-shadow linear 0.2s; 165 | transition: border linear 0.2s, box-shadow linear 0.2s; 166 | } 167 | input:focus, textarea:focus { 168 | border-color: rgba(82, 168, 236, 0.8); 169 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 170 | -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 171 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); 172 | outline: 0; 173 | outline: thin dotted \9; 174 | /* IE6-9 */ 175 | 176 | } 177 | input[type="file"]:focus, 178 | input[type="radio"]:focus, 179 | input[type="checkbox"]:focus, 180 | select:focus { 181 | -webkit-box-shadow: none; 182 | -moz-box-shadow: none; 183 | box-shadow: none; 184 | outline: thin dotted #333; 185 | outline: 5px auto -webkit-focus-ring-color; 186 | outline-offset: -2px; 187 | } 188 | .input-mini { 189 | width: 60px; 190 | } 191 | .input-small { 192 | width: 90px; 193 | } 194 | .input-medium { 195 | width: 150px; 196 | } 197 | .input-large { 198 | width: 210px; 199 | } 200 | .input-xlarge { 201 | width: 270px; 202 | } 203 | .input-xxlarge { 204 | width: 530px; 205 | } 206 | input[class*="span"], 207 | select[class*="span"], 208 | textarea[class*="span"], 209 | .uneditable-input { 210 | float: none; 211 | margin-left: 0; 212 | } 213 | input.span1, textarea.span1, .uneditable-input.span1 { 214 | width: 50px; 215 | } 216 | input.span2, textarea.span2, .uneditable-input.span2 { 217 | width: 130px; 218 | } 219 | input.span3, textarea.span3, .uneditable-input.span3 { 220 | width: 210px; 221 | } 222 | input.span4, textarea.span4, .uneditable-input.span4 { 223 | width: 290px; 224 | } 225 | input.span5, textarea.span5, .uneditable-input.span5 { 226 | width: 370px; 227 | } 228 | input.span6, textarea.span6, .uneditable-input.span6 { 229 | width: 450px; 230 | } 231 | input.span7, textarea.span7, .uneditable-input.span7 { 232 | width: 530px; 233 | } 234 | input.span8, textarea.span8, .uneditable-input.span8 { 235 | width: 610px; 236 | } 237 | input.span9, textarea.span9, .uneditable-input.span9 { 238 | width: 690px; 239 | } 240 | input.span10, textarea.span10, .uneditable-input.span10 { 241 | width: 770px; 242 | } 243 | input.span11, textarea.span11, .uneditable-input.span11 { 244 | width: 850px; 245 | } 246 | input.span12, textarea.span12, .uneditable-input.span12 { 247 | width: 930px; 248 | } 249 | input[disabled], 250 | select[disabled], 251 | textarea[disabled], 252 | input[readonly], 253 | select[readonly], 254 | textarea[readonly] { 255 | background-color: #f5f5f5; 256 | border-color: #ddd; 257 | cursor: not-allowed; 258 | } 259 | .control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { 260 | color: #c09853; 261 | } 262 | .control-group.warning input, .control-group.warning select, .control-group.warning textarea { 263 | color: #c09853; 264 | border-color: #c09853; 265 | } 266 | .control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { 267 | border-color: #a47e3c; 268 | -webkit-box-shadow: 0 0 6px #dbc59e; 269 | -moz-box-shadow: 0 0 6px #dbc59e; 270 | box-shadow: 0 0 6px #dbc59e; 271 | } 272 | .control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { 273 | color: #c09853; 274 | background-color: #fcf8e3; 275 | border-color: #c09853; 276 | } 277 | .control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { 278 | color: #b94a48; 279 | } 280 | .control-group.error input, .control-group.error select, .control-group.error textarea { 281 | color: #b94a48; 282 | border-color: #b94a48; 283 | } 284 | .control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { 285 | border-color: #953b39; 286 | -webkit-box-shadow: 0 0 6px #d59392; 287 | -moz-box-shadow: 0 0 6px #d59392; 288 | box-shadow: 0 0 6px #d59392; 289 | } 290 | .control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { 291 | color: #b94a48; 292 | background-color: #f2dede; 293 | border-color: #b94a48; 294 | } 295 | .control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { 296 | color: #468847; 297 | } 298 | .control-group.success input, .control-group.success select, .control-group.success textarea { 299 | color: #468847; 300 | border-color: #468847; 301 | } 302 | .control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { 303 | border-color: #356635; 304 | -webkit-box-shadow: 0 0 6px #7aba7b; 305 | -moz-box-shadow: 0 0 6px #7aba7b; 306 | box-shadow: 0 0 6px #7aba7b; 307 | } 308 | .control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { 309 | color: #468847; 310 | background-color: #dff0d8; 311 | border-color: #468847; 312 | } 313 | input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { 314 | color: #b94a48; 315 | border-color: #ee5f5b; 316 | } 317 | input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { 318 | border-color: #e9322d; 319 | -webkit-box-shadow: 0 0 6px #f8b9b7; 320 | -moz-box-shadow: 0 0 6px #f8b9b7; 321 | box-shadow: 0 0 6px #f8b9b7; 322 | } 323 | .form-actions { 324 | padding: 17px 20px 18px; 325 | margin-top: 18px; 326 | margin-bottom: 18px; 327 | background-color: #f5f5f5; 328 | border-top: 1px solid #ddd; 329 | } 330 | .uneditable-input { 331 | display: block; 332 | background-color: #ffffff; 333 | border-color: #eee; 334 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); 335 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); 336 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); 337 | cursor: not-allowed; 338 | } 339 | :-moz-placeholder { 340 | color: #999999; 341 | } 342 | ::-webkit-input-placeholder { 343 | color: #999999; 344 | } 345 | .help-block { 346 | display: block; 347 | margin-top: 5px; 348 | margin-bottom: 0; 349 | color: #999999; 350 | } 351 | .help-inline { 352 | display: inline-block; 353 | *display: inline; 354 | /* IE7 inline-block hack */ 355 | 356 | *zoom: 1; 357 | margin-bottom: 9px; 358 | vertical-align: middle; 359 | padding-left: 5px; 360 | } 361 | .input-prepend, .input-append { 362 | margin-bottom: 5px; 363 | *zoom: 1; 364 | } 365 | .input-prepend:before, 366 | .input-append:before, 367 | .input-prepend:after, 368 | .input-append:after { 369 | display: table; 370 | content: ""; 371 | } 372 | .input-prepend:after, .input-append:after { 373 | clear: both; 374 | } 375 | .input-prepend input, 376 | .input-append input, 377 | .input-prepend .uneditable-input, 378 | .input-append .uneditable-input { 379 | -webkit-border-radius: 0 3px 3px 0; 380 | -moz-border-radius: 0 3px 3px 0; 381 | border-radius: 0 3px 3px 0; 382 | } 383 | .input-prepend input:focus, 384 | .input-append input:focus, 385 | .input-prepend .uneditable-input:focus, 386 | .input-append .uneditable-input:focus { 387 | position: relative; 388 | z-index: 2; 389 | } 390 | .input-prepend .uneditable-input, .input-append .uneditable-input { 391 | border-left-color: #ccc; 392 | } 393 | .input-prepend .add-on, .input-append .add-on { 394 | float: left; 395 | display: block; 396 | width: auto; 397 | min-width: 16px; 398 | height: 18px; 399 | margin-right: -1px; 400 | padding: 4px 5px; 401 | font-weight: normal; 402 | line-height: 18px; 403 | color: #999999; 404 | text-align: center; 405 | text-shadow: 0 1px 0 #ffffff; 406 | background-color: #f5f5f5; 407 | border: 1px solid #ccc; 408 | -webkit-border-radius: 3px 0 0 3px; 409 | -moz-border-radius: 3px 0 0 3px; 410 | border-radius: 3px 0 0 3px; 411 | } 412 | .input-prepend .active, .input-append .active { 413 | background-color: #a9dba9; 414 | border-color: #46a546; 415 | } 416 | .input-prepend .add-on { 417 | *margin-top: 1px; 418 | /* IE6-7 */ 419 | 420 | } 421 | .input-append input, .input-append .uneditable-input { 422 | float: left; 423 | -webkit-border-radius: 3px 0 0 3px; 424 | -moz-border-radius: 3px 0 0 3px; 425 | border-radius: 3px 0 0 3px; 426 | } 427 | .input-append .uneditable-input { 428 | border-left-color: #eee; 429 | border-right-color: #ccc; 430 | } 431 | .input-append .add-on { 432 | margin-right: 0; 433 | margin-left: -1px; 434 | -webkit-border-radius: 0 3px 3px 0; 435 | -moz-border-radius: 0 3px 3px 0; 436 | border-radius: 0 3px 3px 0; 437 | } 438 | .input-append input:first-child { 439 | *margin-left: -160px; 440 | } 441 | .input-append input:first-child + .add-on { 442 | *margin-left: -21px; 443 | } 444 | .search-query { 445 | padding-left: 14px; 446 | padding-right: 14px; 447 | margin-bottom: 0; 448 | -webkit-border-radius: 14px; 449 | -moz-border-radius: 14px; 450 | border-radius: 14px; 451 | } 452 | .form-search input, 453 | .form-inline input, 454 | .form-horizontal input, 455 | .form-search textarea, 456 | .form-inline textarea, 457 | .form-horizontal textarea, 458 | .form-search select, 459 | .form-inline select, 460 | .form-horizontal select, 461 | .form-search .help-inline, 462 | .form-inline .help-inline, 463 | .form-horizontal .help-inline, 464 | .form-search .uneditable-input, 465 | .form-inline .uneditable-input, 466 | .form-horizontal .uneditable-input { 467 | display: inline-block; 468 | margin-bottom: 0; 469 | } 470 | .form-search .hide, .form-inline .hide, .form-horizontal .hide { 471 | display: none; 472 | } 473 | .form-search label, 474 | .form-inline label, 475 | .form-search .input-append, 476 | .form-inline .input-append, 477 | .form-search .input-prepend, 478 | .form-inline .input-prepend { 479 | display: inline-block; 480 | } 481 | .form-search .input-append .add-on, 482 | .form-inline .input-prepend .add-on, 483 | .form-search .input-append .add-on, 484 | .form-inline .input-prepend .add-on { 485 | vertical-align: middle; 486 | } 487 | .form-search .radio, 488 | .form-inline .radio, 489 | .form-search .checkbox, 490 | .form-inline .checkbox { 491 | margin-bottom: 0; 492 | vertical-align: middle; 493 | } 494 | .control-group { 495 | margin-bottom: 9px; 496 | } 497 | legend + .control-group { 498 | margin-top: 18px; 499 | -webkit-margin-top-collapse: separate; 500 | } 501 | .form-horizontal .control-group { 502 | margin-bottom: 18px; 503 | *zoom: 1; 504 | } 505 | .form-horizontal .control-group:before, .form-horizontal .control-group:after { 506 | display: table; 507 | content: ""; 508 | } 509 | .form-horizontal .control-group:after { 510 | clear: both; 511 | } 512 | .form-horizontal .control-label { 513 | float: left; 514 | width: 140px; 515 | padding-top: 5px; 516 | text-align: right; 517 | } 518 | .form-horizontal .controls { 519 | margin-left: 160px; 520 | } 521 | .form-horizontal .form-actions { 522 | padding-left: 160px; 523 | } 524 | 525 | 526 | .btn { 527 | display: inline-block; 528 | padding: 4px 10px 4px; 529 | margin-bottom: 0; 530 | font-size: 13px; 531 | line-height: 18px; 532 | color: #333333; 533 | text-align: center; 534 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); 535 | vertical-align: middle; 536 | background-color: #f5f5f5; 537 | background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); 538 | background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); 539 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); 540 | background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); 541 | background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); 542 | background-image: linear-gradient(top, #ffffff, #e6e6e6); 543 | background-repeat: repeat-x; 544 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); 545 | border-color: #e6e6e6 #e6e6e6 #bfbfbf; 546 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 547 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 548 | border: 1px solid #ccc; 549 | border-bottom-color: #bbb; 550 | -webkit-border-radius: 4px; 551 | -moz-border-radius: 4px; 552 | border-radius: 4px; 553 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 554 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 555 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); 556 | cursor: pointer; 557 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 558 | *margin-left: .3em; 559 | } 560 | 561 | .btn:hover, 562 | .btn:active, 563 | .btn.active, 564 | .btn.disabled, 565 | .btn[disabled] { 566 | background-color: #e6e6e6; 567 | } 568 | .btn:active, .btn.active { 569 | background-color: #cccccc \9; 570 | } 571 | .btn:first-child { 572 | *margin-left: 0; 573 | } 574 | .btn:hover { 575 | color: #333333; 576 | text-decoration: none; 577 | background-color: #e6e6e6; 578 | background-position: 0 -15px; 579 | -webkit-transition: background-position 0.1s linear; 580 | -moz-transition: background-position 0.1s linear; 581 | -ms-transition: background-position 0.1s linear; 582 | -o-transition: background-position 0.1s linear; 583 | transition: background-position 0.1s linear; 584 | } 585 | .btn:focus { 586 | outline: thin dotted #333; 587 | outline: 5px auto -webkit-focus-ring-color; 588 | outline-offset: -2px; 589 | } 590 | .btn.active, .btn:active { 591 | background-image: none; 592 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 593 | -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 594 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); 595 | background-color: #e6e6e6; 596 | background-color: #d9d9d9 \9; 597 | outline: 0; 598 | } 599 | .btn.disabled, .btn[disabled] { 600 | cursor: default; 601 | background-image: none; 602 | background-color: #e6e6e6; 603 | opacity: 0.65; 604 | filter: alpha(opacity=65); 605 | -webkit-box-shadow: none; 606 | -moz-box-shadow: none; 607 | box-shadow: none; 608 | } 609 | .btn-large { 610 | padding: 9px 14px; 611 | font-size: 15px; 612 | line-height: normal; 613 | -webkit-border-radius: 5px; 614 | -moz-border-radius: 5px; 615 | border-radius: 5px; 616 | } 617 | .btn-large [class^="icon-"] { 618 | margin-top: 1px; 619 | } 620 | .btn-small { 621 | padding: 5px 9px; 622 | font-size: 11px; 623 | line-height: 16px; 624 | } 625 | .btn-small [class^="icon-"] { 626 | margin-top: -1px; 627 | } 628 | .btn-mini { 629 | padding: 2px 6px; 630 | font-size: 11px; 631 | line-height: 14px; 632 | } 633 | .btn-primary, 634 | .btn-primary:hover, 635 | .btn-warning, 636 | .btn-warning:hover, 637 | .btn-danger, 638 | .btn-danger:hover, 639 | .btn-success, 640 | .btn-success:hover, 641 | .btn-info, 642 | .btn-info:hover, 643 | .btn-inverse, 644 | .btn-inverse:hover { 645 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 646 | color: #ffffff; 647 | } 648 | .btn-primary.active, 649 | .btn-warning.active, 650 | .btn-danger.active, 651 | .btn-success.active, 652 | .btn-info.active, 653 | .btn-dark.active { 654 | color: rgba(255, 255, 255, 0.75); 655 | } 656 | .btn-primary { 657 | background-color: #006dcc; 658 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc); 659 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc); 660 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); 661 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); 662 | background-image: -o-linear-gradient(top, #0088cc, #0044cc); 663 | background-image: linear-gradient(top, #0088cc, #0044cc); 664 | background-repeat: repeat-x; 665 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); 666 | border-color: #0044cc #0044cc #002a80; 667 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 668 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 669 | } 670 | .btn-primary:hover, 671 | .btn-primary:active, 672 | .btn-primary.active, 673 | .btn-primary.disabled, 674 | .btn-primary[disabled] { 675 | background-color: #0044cc; 676 | } 677 | .btn-primary:active, .btn-primary.active { 678 | background-color: #003399 \9; 679 | } 680 | .btn-warning { 681 | background-color: #faa732; 682 | background-image: -moz-linear-gradient(top, #fbb450, #f89406); 683 | background-image: -ms-linear-gradient(top, #fbb450, #f89406); 684 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); 685 | background-image: -webkit-linear-gradient(top, #fbb450, #f89406); 686 | background-image: -o-linear-gradient(top, #fbb450, #f89406); 687 | background-image: linear-gradient(top, #fbb450, #f89406); 688 | background-repeat: repeat-x; 689 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); 690 | border-color: #f89406 #f89406 #ad6704; 691 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 692 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 693 | } 694 | .btn-warning:hover, 695 | .btn-warning:active, 696 | .btn-warning.active, 697 | .btn-warning.disabled, 698 | .btn-warning[disabled] { 699 | background-color: #f89406; 700 | } 701 | .btn-warning:active, .btn-warning.active { 702 | background-color: #c67605 \9; 703 | } 704 | .btn-danger { 705 | background-color: #da4f49; 706 | background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); 707 | background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); 708 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); 709 | background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); 710 | background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); 711 | background-image: linear-gradient(top, #ee5f5b, #bd362f); 712 | background-repeat: repeat-x; 713 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); 714 | border-color: #bd362f #bd362f #802420; 715 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 716 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 717 | } 718 | .btn-danger:hover, 719 | .btn-danger:active, 720 | .btn-danger.active, 721 | .btn-danger.disabled, 722 | .btn-danger[disabled] { 723 | background-color: #bd362f; 724 | } 725 | .btn-danger:active, .btn-danger.active { 726 | background-color: #942a25 \9; 727 | } 728 | .btn-success { 729 | background-color: #5bb75b; 730 | background-image: -moz-linear-gradient(top, #62c462, #51a351); 731 | background-image: -ms-linear-gradient(top, #62c462, #51a351); 732 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); 733 | background-image: -webkit-linear-gradient(top, #62c462, #51a351); 734 | background-image: -o-linear-gradient(top, #62c462, #51a351); 735 | background-image: linear-gradient(top, #62c462, #51a351); 736 | background-repeat: repeat-x; 737 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); 738 | border-color: #51a351 #51a351 #387038; 739 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 740 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 741 | } 742 | .btn-success:hover, 743 | .btn-success:active, 744 | .btn-success.active, 745 | .btn-success.disabled, 746 | .btn-success[disabled] { 747 | background-color: #51a351; 748 | } 749 | .btn-success:active, .btn-success.active { 750 | background-color: #408140 \9; 751 | } 752 | .btn-info { 753 | background-color: #49afcd; 754 | background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); 755 | background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); 756 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); 757 | background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); 758 | background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); 759 | background-image: linear-gradient(top, #5bc0de, #2f96b4); 760 | background-repeat: repeat-x; 761 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); 762 | border-color: #2f96b4 #2f96b4 #1f6377; 763 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 764 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 765 | } 766 | .btn-info:hover, 767 | .btn-info:active, 768 | .btn-info.active, 769 | .btn-info.disabled, 770 | .btn-info[disabled] { 771 | background-color: #2f96b4; 772 | } 773 | .btn-info:active, .btn-info.active { 774 | background-color: #24748c \9; 775 | } 776 | .btn-inverse { 777 | background-color: #393939; 778 | background-image: -moz-linear-gradient(top, #454545, #262626); 779 | background-image: -ms-linear-gradient(top, #454545, #262626); 780 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626)); 781 | background-image: -webkit-linear-gradient(top, #454545, #262626); 782 | background-image: -o-linear-gradient(top, #454545, #262626); 783 | background-image: linear-gradient(top, #454545, #262626); 784 | background-repeat: repeat-x; 785 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0); 786 | border-color: #262626 #262626 #000000; 787 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 788 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 789 | } 790 | .btn-inverse:hover, 791 | .btn-inverse:active, 792 | .btn-inverse.active, 793 | .btn-inverse.disabled, 794 | .btn-inverse[disabled] { 795 | background-color: #262626; 796 | } 797 | .btn-inverse:active, .btn-inverse.active { 798 | background-color: #0c0c0c \9; 799 | } 800 | button.btn, input[type="submit"].btn { 801 | *padding-top: 2px; 802 | *padding-bottom: 2px; 803 | } 804 | button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { 805 | padding: 0; 806 | border: 0; 807 | } 808 | button.btn.large, input[type="submit"].btn.large { 809 | *padding-top: 7px; 810 | *padding-bottom: 7px; 811 | } 812 | button.btn.small, input[type="submit"].btn.small { 813 | *padding-top: 3px; 814 | *padding-bottom: 3px; 815 | } -------------------------------------------------------------------------------- /hn.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: rgba(0,0,0,0.05); 3 | margin: 0; 4 | } 5 | 6 | table td, 7 | table { 8 | background: #fff; 9 | } 10 | 11 | 12 | /*********** Fonts *******************/ 13 | 14 | body, 15 | td, 16 | .admin td, 17 | .subtext td, 18 | input[type=\"submit\"], 19 | .default, 20 | .admin, 21 | .title, 22 | .adtitle, 23 | .subtext, 24 | .yclinks, 25 | .pagetop, 26 | .comhead, 27 | .comment, 28 | .dead { 29 | font-family: Verdana, Geneva, sans-serif !important; 30 | } 31 | 32 | /*********** Header ******************/ 33 | 34 | table table a[href='http://ycombinator.com'] img { 35 | padding-left: 8px; 36 | padding-right: 4px; 37 | } 38 | 39 | .pagetop { 40 | text-transform: uppercase; 41 | font-size: 11px !important; 42 | } 43 | 44 | .pagetop b { 45 | padding-right: 10px; 46 | } 47 | 48 | .pagetop a, 49 | .pagetop a:link, 50 | .pagetop a:visited { 51 | color: #444 !important; 52 | } 53 | 54 | .pagetop .topsel a, 55 | .pagetop .topsel a:link, 56 | .pagetop .topsel a:visited { 57 | color: #000 !important; 58 | font-weight: bold; 59 | } 60 | 61 | .pagetop a:hover { 62 | color: #000 !important; 63 | } 64 | 65 | 66 | /*********** Footer ******************/ 67 | 68 | .footer { 69 | position: fixed; 70 | bottom: -70px; 71 | left: 0; 72 | width: 100%; 73 | background: rgba(255,255,255,0.95); 74 | -webkit-transition: bottom 1s; 75 | } 76 | 77 | .footer:hover { 78 | bottom: 0; 79 | } 80 | 81 | .footer td { 82 | background: transparent; 83 | width: 100%; 84 | } 85 | 86 | .footer img { 87 | display: none; 88 | } 89 | 90 | .footer form { 91 | color: transparent; 92 | font-size: 0; 93 | margin: 0; 94 | } 95 | 96 | .footer input { 97 | width: 55%; 98 | } 99 | 100 | 101 | /*********** Filters *****************/ 102 | 103 | #menu-filters { 104 | cursor: pointer; 105 | position: relative; 106 | } 107 | 108 | #menu-filters .count { 109 | position: relative; 110 | padding: 1px 3px; 111 | right: 4px; 112 | top: -1px; 113 | background: #2279B2; 114 | font-size: 10px; 115 | color: #fff; 116 | border-radius: 2px; 117 | border-bottom: 1px solid #12405E; 118 | } 119 | 120 | #filter-wrapper { 121 | position: relative; 122 | display: none; 123 | } 124 | 125 | #filter-wrapper p.empty { 126 | position: absolute; 127 | top: 46px; 128 | left: 20px; 129 | line-height: 1.2; 130 | text-shadow: 0 1px 0 #fff; 131 | margin: 0; 132 | } 133 | 134 | #filter-wrapper input { 135 | position: absolute; 136 | top: 38px; 137 | right: 20px; 138 | line-height: 1.2; 139 | } 140 | 141 | #filter-wrapper em { 142 | position: absolute; 143 | top: 10px; 144 | right: 188px; 145 | width: 0; 146 | height: 0; 147 | border-left: 10px solid transparent; 148 | border-right: 10px solid transparent; 149 | border-bottom: 10px solid #f5f5f5; 150 | } 151 | 152 | #current-filters { 153 | list-style: none; 154 | margin: 20px 0 0 0; 155 | padding: 20px 250px 10px 20px; 156 | background: #f5f5f5; 157 | border-bottom: 3px solid #ddd; 158 | min-height: 38px; 159 | } 160 | 161 | #current-filters li { 162 | display: inline; 163 | } 164 | 165 | #current-filters li a { 166 | display: inline-block; 167 | padding: 4px 6px; 168 | background: #2279B2; 169 | color: #fff; 170 | margin: 0 20px 10px 0; 171 | border-radius: 3px; 172 | border-bottom: 1px solid #12405E; 173 | cursor: pointer; 174 | } 175 | 176 | #current-filters li a:active, 177 | #current-filters li:hover a { 178 | background: #BF3838; 179 | border-bottom: 1px solid #6F2020; 180 | } 181 | 182 | 183 | /*********** Code Comments ***********/ 184 | 185 | pre { 186 | background: #f1f1f1; 187 | padding: 20px 20px 20px 0 !important; 188 | color: #333; 189 | border-radius: 3px; 190 | } 191 | 192 | 193 | /*********** News Listings ***********/ 194 | 195 | body > center > table { 196 | margin: 0 -20px; 197 | padding: 20px; 198 | } 199 | 200 | td.title { 201 | padding: 8px 0 0px; 202 | position: relative; 203 | background: none; 204 | } 205 | 206 | td.title a { 207 | font-size: 17px; 208 | letter-spacing: -1px; 209 | color: rgb(0, 105, 173); 210 | } 211 | 212 | td.title a:hover { 213 | color: #2991D6; 214 | } 215 | 216 | 217 | td.title a:visited { 218 | color: #87C1E8; 219 | } 220 | 221 | td.title .comhead a { 222 | color: #444; 223 | font-size: 8pt; 224 | } 225 | 226 | td.title:first-child { 227 | font-size: 20px; 228 | color: #bbb; 229 | min-width: 33px; 230 | } 231 | 232 | td.subtext { 233 | font-size: 10px; 234 | } 235 | 236 | td.subtext a:hover { 237 | color: #444; 238 | } 239 | 240 | 241 | /*********** Vote Arrows ****************/ 242 | 243 | tr>td { 244 | min-width: 20px; 245 | } 246 | 247 | tr>td>center>a { 248 | padding: 0; 249 | vertical-align: bottom; 250 | opacity: 0.8; 251 | position: relative; 252 | top: 4px; 253 | } 254 | 255 | tr>td>center>a>img { 256 | width: 10px; 257 | height: 10px; 258 | } 259 | 260 | tr>td>center>a:hover { 261 | opacity: 1; 262 | } 263 | 264 | /* Fix reply indentation on comments page */ 265 | html.item tr>td>center>a { 266 | padding: 0; 267 | } 268 | 269 | 270 | 271 | /*********** Story Share Menu ***********/ 272 | 273 | .share-story { 274 | cursor: pointer; 275 | } 276 | 277 | .share-story:hover { 278 | text-decoration: underline; 279 | } 280 | 281 | .sharing-options { 282 | display: none; 283 | padding: 10px 0; 284 | } 285 | 286 | .sharing-options iframe { 287 | margin-right: 10px; 288 | } 289 | 290 | 291 | /*********** Story Filter Menu **********/ 292 | 293 | td.title .filter-menu { 294 | position: absolute; 295 | top: 8px; 296 | right: 0; 297 | } 298 | 299 | td.title .filter-menu span { 300 | display: block; 301 | width: 20px; 302 | height: 20px; 303 | font-size: 18px; 304 | color: rgba(0,0,0,0.05); 305 | text-align: center; 306 | line-height: 20px; 307 | padding-right: 10px; 308 | cursor: pointer; 309 | -webkit-transition: all 0.2s ease-in-out; 310 | } 311 | 312 | td.title:hover .filter-menu span { 313 | color: rgba(0,0,0,0.5); 314 | background: #fff; 315 | } 316 | 317 | td.title .filter-menu ul { 318 | list-style: none; 319 | padding: 0; 320 | margin: 0; 321 | } 322 | 323 | td.title .filter-menu .quick-filter { 324 | position: absolute; 325 | left: -9000px; 326 | background: rgba(0,0,0,0.9); 327 | box-shadow: 0 2px 10px rgba(0,0,0,0.1); 328 | z-index: 100; 329 | width: 170px; 330 | top: 25px; 331 | } 332 | 333 | td.title .filter-menu:hover .quick-filter { 334 | left: -74px; 335 | } 336 | 337 | td.title .filter-menu .quick-filter li a { 338 | font-size: 12px; 339 | color: #fff; 340 | display: block; 341 | padding: 10px; 342 | letter-spacing: 0; 343 | cursor: pointer; 344 | border-bottom: 1px solid #222; 345 | text-decoration: none; 346 | } 347 | 348 | td.title .filter-menu .quick-filter li:hover a { 349 | background: #BF3838; 350 | border-bottom: 1px solid #6F2020; 351 | } 352 | 353 | td.title .filter-menu .quick-filter em { 354 | position: absolute; 355 | top: -6px; 356 | left: 78px; 357 | width: 0; 358 | height: 0; 359 | border-left: 6px solid transparent; 360 | border-right: 6px solid transparent; 361 | border-bottom: 6px solid rgba(0,0,0,0.9); 362 | } 363 | 364 | /*********** Endless Loading **********/ 365 | 366 | a.endless_loading { 367 | display: block; 368 | height: 0; 369 | padding-top: 38px; 370 | overflow: hidden; 371 | background: url(chrome-extension://__MSG_@@extension_id__/images/loading-light.gif) no-repeat center center; 372 | } 373 | 374 | 375 | /*********** Story Page ***************/ 376 | 377 | form textarea { 378 | width: 100%; 379 | } 380 | 381 | .item .filter-menu { 382 | display: none; 383 | } 384 | 385 | .item form textarea { 386 | margin: 0 0 -10px; 387 | } 388 | 389 | .item form { 390 | margin: 0; 391 | } 392 | 393 | .item table tr td table tr td form:first-child textarea { 394 | min-width: 600px; 395 | } 396 | 397 | a.highlighted { 398 | margin: -2px 0; 399 | padding: 2px 3px; 400 | background: #ed7233; 401 | color: #fff !important; 402 | border-radius: 2px; 403 | } 404 | 405 | font u a:link, 406 | .comment a:link { 407 | color: #2279B2; 408 | } 409 | 410 | font u a:visited, 411 | .comment a:visited { 412 | color: #87C1E8; 413 | } 414 | 415 | a.toggle-replies { 416 | cursor: pointer; 417 | } 418 | 419 | a.toggle-replies:hover { 420 | text-decoration: underline; 421 | } 422 | 423 | td.default:hover a.toggle-replies { 424 | opacity: 1; 425 | } 426 | 427 | /*********** Inline Replies ***********/ 428 | 429 | #quick-reply { 430 | width: 100%; 431 | display: none; 432 | } 433 | 434 | #quick-reply textarea { 435 | height: 80px !important; 436 | } 437 | 438 | #quick-reply input[type=submit] { 439 | margin-left: 0; 440 | margin-top: 20px; 441 | } 442 | 443 | #quick-reply .loading { 444 | min-height: 38px; 445 | background: url(chrome-extension://__MSG_@@extension_id__/images/loading-light.gif) no-repeat center center; 446 | } 447 | 448 | 449 | /*********** Profile Bubble ***********/ 450 | 451 | #profile-bubble { 452 | position: relative; 453 | display: none; 454 | background: rgba(0,0,0,0.9); 455 | padding: 10px; 456 | box-shadow: 0 2px 10px rgba(0,0,0,0.1); 457 | z-index: 100; 458 | width: 150px; 459 | } 460 | 461 | #profile-bubble em { 462 | position: absolute; 463 | top: -6px; 464 | left: 78px; 465 | width: 0; 466 | height: 0; 467 | border-left: 6px solid transparent; 468 | border-right: 6px solid transparent; 469 | border-bottom: 6px solid rgba(0,0,0,0.9); 470 | } 471 | 472 | #profile-bubble a { 473 | color: #fff; 474 | display: block; 475 | padding: 5px 0; 476 | overflow: hidden; 477 | } 478 | 479 | #profile-bubble .loading { 480 | min-height: 38px; 481 | background: url(chrome-extension://__MSG_@@extension_id__/images/loading.gif) no-repeat center center; 482 | } 483 | 484 | #profile-bubble a:hover .icon-label { 485 | text-decoration: underline; 486 | } 487 | 488 | #profile-bubble .username { 489 | color: #aaa; 490 | font-size: 11px; 491 | display: block; 492 | margin-left: 26px; 493 | } 494 | 495 | #profile-bubble ul { 496 | padding: 0; 497 | margin: 0; 498 | list-style: none; 499 | } 500 | 501 | #profile-bubble .follow-user, 502 | #profile-bubble .unfollow-user { 503 | cursor: pointer; 504 | margin: 0 -10px 5px -10px; 505 | padding: 5px 10px; 506 | } 507 | 508 | #profile-bubble .follow-user:hover, 509 | #profile-bubble .unfollow-user:hover { 510 | background: #000; 511 | } 512 | 513 | /*********** Ident Icons ***********/ 514 | 515 | .icon { 516 | width: 16px; 517 | height: 16px; 518 | display: inline-block; 519 | float: left; 520 | background-color: white; 521 | border-radius: 2px; 522 | margin-top: 2px; 523 | margin-right: 10px; 524 | background: #ffffff url(chrome-extension://__MSG_@@extension_id__/images/icons.png) no-repeat top left; 525 | border-radius: 3px; 526 | } 527 | 528 | .icon-karma { background: url(chrome-extension://__MSG_@@extension_id__/images/karma.png) no-repeat top left; background-size: 100%;} 529 | .icon-follow { background: url(chrome-extension://__MSG_@@extension_id__/images/follow.png) no-repeat top left; background-size: 100%;} 530 | .icon-unfollow { background: url(chrome-extension://__MSG_@@extension_id__/images/unfollow.png) no-repeat top left; background-size: 100%;} 531 | .icon-12secondstv { background-position: 0 0; } 532 | .icon-43people { background-position: 0 -17px; } 533 | .icon-43places { background-position: 0 -34px; } 534 | .icon-43things { background-position: 0 -51px; } 535 | .icon-backnetwork { background-position: 0 -68px; } 536 | .icon-backtype { background-position: 0 -85px; } 537 | .icon-barcampbrighton3 { background-position: 0 -102px; } 538 | .icon-barcamplondon5 { background-position: 0 -119px; } 539 | .icon-blipfm { background-position: 0 -136px; } 540 | .icon-blippr { background-position: 0 -153px; } 541 | .icon-bliptv { background-position: 0 -170px; } 542 | .icon-blogger { background-position: 0 -187px; } 543 | .icon-blogspot { background-position: 0 -204px; } 544 | .icon-brightkite { background-position: 0 -221px; } 545 | .icon-claimid { background-position: 0 -238px; } 546 | .icon-cliqset { background-position: 0 -255px; } 547 | .icon-cocomment { background-position: 0 -272px; } 548 | .icon-corkd { background-position: 0 -289px; } 549 | .icon-dconstruct08 { background-position: 0 -306px; } 550 | .icon-delicious { background-position: 0 -323px; } 551 | .icon-digg { background-position: 0 -340px; } 552 | .icon-disqus { background-position: 0 -357px; } 553 | .icon-djangopeople { background-position: 0 -374px; } 554 | .icon-dopplr { background-position: 0 -391px; } 555 | .icon-edenbee { background-position: 0 -408px; } 556 | .icon-emberapp { background-position: 0 -425px; } 557 | .icon-facebook { background-position: 0 -442px; } 558 | .icon-ffffound { background-position: 0 -459px; } 559 | .icon-flickr { background-position: 0 -476px; } 560 | .icon-fotb08 { background-position: 0 -493px; } 561 | .icon-fotolog { background-position: 0 -510px; } 562 | .icon-friendfeed { background-position: 0 -527px; } 563 | .icon-getsatisfaction { background-position: 0 -544px; } 564 | .icon-github { background-position: 0 -561px; } 565 | .icon-google { background-position: 0 -578px; } 566 | .icon-googlereader { background-position: 0 -595px; } 567 | .icon-hi5 { background-position: 0 -612px; } 568 | .icon-huffduffer { background-position: 0 -629px; } 569 | .icon-identica { background-position: 0 -646px; } 570 | .icon-jaiku { background-position: 0 -663px; } 571 | .icon-joost { background-position: 0 -680px; } 572 | .icon-jpg { background-position: 0 -697px; } 573 | .icon-krop { background-position: 0 -714px; } 574 | .icon-lastfm { background-position: 0 -731px; } 575 | .icon-linkedin { background-position: 0 -748px; } 576 | .icon-livejournal { background-position: 0 -765px; } 577 | .icon-madgexlab { background-position: 0 -782px; } 578 | .icon-mashed08 { background-position: 0 -799px; } 579 | .icon-meetup { background-position: 0 -816px; } 580 | .icon-microformatsorg { background-position: 0 -833px; } 581 | .icon-mybloglog { background-position: 0 -850px; } 582 | .icon-mynameise { background-position: 0 -867px; } 583 | .icon-myopenid { background-position: 0 -884px; } 584 | .icon-myspace { background-position: 0 -901px; } 585 | .icon-mytvshows { background-position: 0 -918px; } 586 | .icon-netvibes { background-position: 0 -935px; } 587 | .icon-newsvine { background-position: 0 -952px; } 588 | .icon-odeo { background-position: 0 -969px; } 589 | .icon-orkut { background-position: 0 -986px; } 590 | .icon-picasa { background-position: 0 -1003px; } 591 | .icon-plaxo { background-position: 0 -1020px; } 592 | .icon-plazes { background-position: 0 -1037px; } 593 | .icon-plurk { background-position: 0 -1054px; } 594 | .icon-pownce { background-position: 0 -1071px; } 595 | .icon-profilactic { background-position: 0 -1088px; } 596 | .icon-readernaut { background-position: 0 -1105px; } 597 | .icon-seesmic { background-position: 0 -1122px; } 598 | .icon-slideshare { background-position: 0 -1139px; } 599 | .icon-smugmug { background-position: 0 -1156px; } 600 | .icon-soup { background-position: 0 -1173px; } 601 | .icon-stumbleupon { background-position: 0 -1190px; } 602 | .icon-technorati { background-position: 0 -1207px; } 603 | .icon-threadless { background-position: 0 -1224px; } 604 | .icon-timespeople { background-position: 0 -1241px; } 605 | .icon-tumblr { background-position: 0 -1258px; } 606 | .icon-twitpic { background-position: 0 -1275px; } 607 | .icon-twitter { background-position: 0 -1292px; } 608 | .icon-upcoming { background-position: 0 -1309px; } 609 | .icon-ustream { background-position: 0 -1326px; } 610 | .icon-viddler { background-position: 0 -1343px; } 611 | .icon-vimeo { background-position: 0 -1360px; } 612 | .icon-vox { background-position: 0 -1377px; } 613 | .icon-website { background-position: 0 -1394px; } 614 | .icon-windowslive { background-position: 0 -1411px; } 615 | .icon-wordpress { background-position: 0 -1428px; } 616 | .icon-xing { background-position: 0 -1445px; } 617 | .icon-yahoo { background-position: 0 -1462px; } 618 | .icon-yelp { background-position: 0 -1479px; } 619 | .icon-yiid { background-position: 0 -1496px; } 620 | .icon-youtube { background-position: 0 -1513px; } 621 | 622 | 623 | 624 | /* Smaller than standard 960 (devices and browsers) */ 625 | @media only screen and (max-width: 959px) { 626 | 627 | body > center > table { 628 | margin: 0; 629 | width: 100%; 630 | } 631 | 632 | } 633 | -------------------------------------------------------------------------------- /images/arrow-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/arrow-down.png -------------------------------------------------------------------------------- /images/arrow-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/arrow-up.png -------------------------------------------------------------------------------- /images/follow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/follow.png -------------------------------------------------------------------------------- /images/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/icon-128.png -------------------------------------------------------------------------------- /images/icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/icon-48.png -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/icon.png -------------------------------------------------------------------------------- /images/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/icons.png -------------------------------------------------------------------------------- /images/karma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/karma.png -------------------------------------------------------------------------------- /images/loading-light.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/loading-light.gif -------------------------------------------------------------------------------- /images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/loading.gif -------------------------------------------------------------------------------- /images/promo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/promo.png -------------------------------------------------------------------------------- /images/unfollow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tommoor/HackerNew/ce4833d9071fc2688defdc249fa7329fc72577d5/images/unfollow.png -------------------------------------------------------------------------------- /js/background.js: -------------------------------------------------------------------------------- 1 | chrome.extension.onConnect.addListener(function(port) { 2 | port.onMessage.addListener(function(data) { 3 | // what to do when we get a response? 4 | $(document).bind('ident:update', function(){ 5 | port.postMessage(ident.identities); 6 | }); 7 | 8 | // Properties for search 9 | ident.useInwardEdges = true; 10 | ident.iconPath = "images/icons/"; 11 | ident.addPrimaryURL = true; 12 | ident.search(data.urls.join(',')); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /js/hn.js: -------------------------------------------------------------------------------- 1 | var hn = { 2 | 3 | loading: [], 4 | loaded: [], 5 | identport: null, 6 | identelem: null, 7 | endless_loading: false, 8 | endless_preload: 300, 9 | 10 | init: function(){ 11 | hn.setPage(); 12 | hn.styleElements(); 13 | hn.replaceImages(); 14 | hn.createSearchBar(); 15 | hn.createProfileBubble(); 16 | hn.augmentStories(); 17 | hn.updateHighlights(); 18 | hn.bindEvents(); 19 | }, 20 | 21 | setPage: function(){ 22 | 23 | switch(window.location.pathname) { 24 | case '/news': 25 | case '/newest': 26 | case '/over': 27 | hn.createFilterMenu(); 28 | break; 29 | case '/newcomments': 30 | $('html').addClass('comments'); 31 | break; 32 | case '/item': 33 | case '/threads': 34 | $('html').addClass('item'); 35 | hn.updateHighlights(); 36 | hn.createQuickReply(); 37 | break; 38 | default: 39 | hn.createFilterMenu(); 40 | $('html').addClass('news'); 41 | } 42 | }, 43 | 44 | styleElements: function(){ 45 | $('input[type=submit]').addClass('btn'); 46 | }, 47 | 48 | replaceImages: function(){ 49 | $("img[src='y18.gif']").attr('src', chrome.extension.getURL("/images/icon.png")); 50 | $("img[src='grayarrow.gif']").attr('src', chrome.extension.getURL("/images/arrow-up.png")).show(); 51 | $("img[src='graydown.gif']").attr('src', chrome.extension.getURL("/images/arrow-down.png")).show(); 52 | $("link[rel='shortcut icon']").attr('href', chrome.extension.getURL("/images/icon.png")); 53 | }, 54 | 55 | createProfileBubble: function(){ 56 | $('body').append('
'); 57 | }, 58 | 59 | createQuickReply: function(){ 60 | $('body').append('
'); 61 | }, 62 | 63 | createFilterMenu: function(){ 64 | $('.pagetop').last().prepend('filters | '); 65 | $('.pagetop').parents('tr').first().after('

Add a filter on the right to no longer see it on HN.

'); 66 | hn.refreshFilters(); 67 | }, 68 | 69 | createSearchBar: function() { 70 | var $footer = $('.yclinks').parents('td'); 71 | var footer = $footer.html(); 72 | $footer.remove(); 73 | 74 | $('body').append(''); 75 | $('.footer input').attr('placeholder', 'Search...'); 76 | }, 77 | 78 | refreshFilters: function(){ 79 | var filters = hn.getStorage('filters'); 80 | var $filters = ''; 81 | 82 | for (var i=0, l=filters.length; i < l; i++){ 83 | $filters += '
  • '+filters[i]+'
  • '; 84 | } 85 | 86 | // show placeholder message 87 | if (l) { 88 | $('#filter-wrapper .empty').hide(); 89 | } else { 90 | $('#filter-wrapper .empty').show(); 91 | } 92 | 93 | $('#current-filters').html($filters); 94 | hn.filterStories(); 95 | }, 96 | 97 | bindEvents: function(){ 98 | 99 | $('#menu-filters').live('click', function(){ 100 | $('#filter-wrapper').fadeToggle(); 101 | }); 102 | 103 | $('a.filter.remove').live('click', function(){ 104 | hn.removeStorage("filters", $(this).data('filter')); 105 | hn.filterStories(); 106 | hn.refreshFilters(); 107 | }); 108 | 109 | $('#add-filter').keyup(function(ev){ 110 | if (ev.keyCode == 13) { 111 | hn.addStorage("filters", $(this).val()); 112 | $(this).val(''); 113 | hn.refreshFilters(); 114 | } 115 | }); 116 | 117 | $('.add-filter').live('click', function(ev){ 118 | hn.addStorage("filters", $(this).data('filter')); 119 | hn.refreshFilters(); 120 | }); 121 | 122 | $('.follow-user').live('click', function(ev){ 123 | hn.addStorage("follows", $(this).data('username')); 124 | hn.updateHighlights(); 125 | 126 | // toggle visible button 127 | $(this).hide(); 128 | $(this).parent().find('.unfollow-user').show(); 129 | }); 130 | 131 | $('.unfollow-user').live('click', function(ev){ 132 | hn.removeStorage("follows", $(this).data('username')); 133 | hn.updateHighlights(); 134 | 135 | // toggle visible button 136 | $(this).hide(); 137 | $(this).parent().find('.follow-user').show(); 138 | }); 139 | 140 | $('textarea').first().autogrow(); 141 | 142 | // slice removes the first user, which is always ourselves 143 | $('a[href^=user]').slice(1).hoverIntent(hn.loadUserDetails, function(){}); 144 | $('a[href^=reply]').click(hn.quickReply); 145 | 146 | $(document).click(hn.closeQuickReply); 147 | $(document).scroll(hn.checkPageEnd); 148 | }, 149 | 150 | checkPageEnd: function(){ 151 | // dont do anything if we're already loading the next page 152 | if (hn.endless_loading) return; 153 | 154 | // check if we're near the end 155 | if (window.scrollY > $(document).height()-window.innerHeight-hn.endless_preload) { 156 | 157 | // awesome, lets start loading 158 | hn.loadNextPage(); 159 | } 160 | }, 161 | 162 | loadNextPage: function(){ 163 | 164 | hn.endless_loading = true; 165 | 166 | var $temp = $('
    '); 167 | 168 | // find the 'More' link and add a loading class 169 | var $more = $('td.title a[href^="/x"]').last().addClass('endless_loading'); 170 | var $morerow = $more.parent().parent(); 171 | 172 | // extract the URL for the next page 173 | var url = $more.attr('href'); 174 | 175 | // load next page 176 | $temp.load(url, function(){ 177 | // find the first news title and jump up two levels to get news table body 178 | $temp = $temp.find('td.title:first-child').parent().parent().html(); 179 | 180 | // add extra options to stories before appending to DOM 181 | $morerow.after($temp); 182 | $morerow.remove(); 183 | 184 | hn.endless_loading = false; 185 | 186 | // refilter news stories 187 | hn.filterStories(); 188 | hn.replaceImages(); 189 | hn.augmentStories(); 190 | 191 | // bind quick profiles 192 | $('a[href^=user]').hoverIntent(hn.loadUserDetails, function(){}); 193 | }); 194 | }, 195 | 196 | quickReply: function(ev){ 197 | ev.preventDefault(); 198 | 199 | var $point = $(this); 200 | var $element = $('#quick-reply').clone(); 201 | var $reply = $('.reply', $element); 202 | var $textarea = $('textarea', $reply); 203 | var $temp = $('
    '); 204 | var url = $(this).attr('href') + ' form'; 205 | 206 | $element.css('display', 'block'); 207 | $point.after($element); 208 | $point.remove(); 209 | $textarea.autogrow(); 210 | $textarea.focus(); 211 | 212 | // upon reply 213 | $('form', $element).submit(function(ev){ 214 | ev.preventDefault(); 215 | 216 | // show that we are doing something 217 | $('input', $element).val('saving...'); 218 | 219 | // load real reply form from server, modify and submit 220 | $temp.load(url, function(){ 221 | $temp.find('textarea').val($textarea.val()); 222 | var $form = $temp.find('form'); 223 | document.body.appendChild($form[0]); 224 | $form.submit(); 225 | }); 226 | }); 227 | }, 228 | 229 | loadUserDetails: function(ev){ 230 | var $temp = $('
    '); 231 | var url = $(this).attr('href') + ' table'; 232 | var username = $(this).text(); 233 | 234 | hn.identelem = $(this); 235 | hn.renderProfileBubble(); 236 | 237 | // load user profile page into temporary container 238 | $temp.load(url, function(){ 239 | 240 | // find this users karma value 241 | var karma = $temp.find("td:contains('karma')").next().text(); 242 | 243 | // twitter's library is far and away the best for extracting urls 244 | var urlsWithIndices = twttr.txt.extractUrlsWithIndices($temp.html()); 245 | var filtered = []; 246 | 247 | for (var i = 0; i < urlsWithIndices.length; i++) { 248 | // ensure urls are properly formed 249 | if(!urlsWithIndices[i].url.match(/^https?:\/\//gi)){ 250 | urlsWithIndices[i].url = 'http://' + urlsWithIndices[i].url; 251 | } 252 | 253 | // filter out any ycombinator that might have got in there 254 | if(!urlsWithIndices[i].url.match(/ycombinator/gi)){ 255 | filtered.push(urlsWithIndices[i].url); 256 | } 257 | }; 258 | 259 | if (filtered.length) { 260 | hn.renderProfileBubble([], filtered, username, karma); 261 | 262 | // clean list of profile urls through social lib 263 | hn.loadUserProfiles(filtered, function(identities){ 264 | hn.renderProfileBubble(identities, urls, username, karma); 265 | }); 266 | } else { 267 | // otherwise just render a plain profile bubble 268 | hn.renderProfileBubble([], [], username, karma); 269 | } 270 | }); 271 | }, 272 | 273 | loadUserProfiles: function(urls, callback){ 274 | var name = 'ident' + (new Date).getTime(); 275 | var port = chrome.extension.connect({name: name}); 276 | port.postMessage({urls: urls}); 277 | port.onMessage.addListener(callback); 278 | hn.identport = port; 279 | }, 280 | 281 | renderProfileBubble: function(identities, urls, username, karma){ 282 | if (identities || urls || karma) { 283 | identities = identities || []; 284 | urls = urls || []; 285 | 286 | for (var i in urls) { 287 | identities.push({ 288 | profileUrl: urls[i], 289 | spriteClass: 'icon-website', 290 | username: urls[i], 291 | name: 'Website' 292 | }); 293 | } 294 | 295 | identities.unshift({ 296 | profileUrl: '', 297 | spriteClass: 'icon-karma', 298 | username: 'Karma', 299 | name: karma 300 | }); 301 | } 302 | 303 | // reset bubble 304 | var $profile = $('#profile-bubble .profile'); 305 | $profile.empty().removeClass('loading'); 306 | 307 | // loaded 308 | if (identities && identities.length > 0){ 309 | var ul = $('
      ').appendTo($profile); 310 | 311 | for (var x = 0; x < identities.length; x++) { 312 | if (identities[x].name != '') { 313 | $('
    • ' + identities[x].name + '' + identities[x].username + '
    • ').appendTo(ul); 314 | } else { 315 | $('
    • ' + identities[x].domain + '
    • ').appendTo(ul); 316 | } 317 | } 318 | 319 | // following / highlights 320 | var follows = hn.getStorage("follows"); 321 | $profile.prepend('' + 322 | '
      Unfollow'+username+'
      '); 323 | 324 | if ($.inArray(username, follows) == -1) { 325 | $('.unfollow-user', $profile).hide(); 326 | } else { 327 | $('.follow-user', $profile).hide(); 328 | } 329 | 330 | } else { 331 | $profile.addClass('loading'); 332 | } 333 | 334 | // position correctly 335 | var left = hn.identelem.offset().left + (hn.identelem.width()/2); 336 | var width = $('#profile-bubble').outerWidth()/2; 337 | 338 | $('#profile-bubble').css({ 339 | display: 'block', 340 | position: 'absolute', 341 | top: hn.identelem.offset().top+20, 342 | left: left-width 343 | }); 344 | }, 345 | 346 | closeQuickReply: function(ev){ 347 | if (!$(ev.target).parents('#profile-bubble').length && ev.target != $('#profile-bubble')[0]) { 348 | $('#profile-bubble').fadeOut(200); 349 | } 350 | }, 351 | 352 | augmentStories: function(){ 353 | var follows = hn.getStorage("follows"); 354 | 355 | $('td.title').not('.hn-processed').each(function(){ 356 | 357 | var $link = $('a', this); 358 | var $title = $link.parent(); 359 | var $details = $title.parent().next().find('td.subtext'); 360 | var $flag = $('a', $details).eq(1); 361 | 362 | // extract story info 363 | var domain = $('.comhead', $title).text().replace(/\(|\)/g, ''); 364 | var $username = $('.hnuser', $details); 365 | var username = $username.text(); 366 | 367 | // add filtering options 368 | $link.before(''); 372 | 373 | // add sharing and cache 374 | $flag.after(' | cached'); 375 | 376 | $(this).addClass('hn-processed'); 377 | }); 378 | }, 379 | 380 | updateHighlights: function() { 381 | var follows = hn.getStorage("follows"); 382 | 383 | $('.hnuser').each(function(){ 384 | var $username = $(this); 385 | var username = $username.text(); 386 | 387 | // following 388 | if ($.inArray(username, follows) != -1) { 389 | $username.addClass('highlighted'); 390 | } else { 391 | $username.removeClass('highlighted'); 392 | } 393 | }); 394 | }, 395 | 396 | filterStories: function(){ 397 | var count = 0; 398 | 399 | $('td.title a').each(function(){ 400 | var $title = $(this).parent(); 401 | var $row = $title.parent(); 402 | var $details = $row.next(); 403 | var $divider = $details.next(); 404 | 405 | // extract story info 406 | var domain = $('.comhead', $title).text().replace(/\(|\)/g, ''); 407 | var title = $(this).text(); 408 | var username = $('a', $details).first().text(); 409 | 410 | // check personal filters 411 | if (hn.checkFiltered(title, domain, username)) { 412 | $row.hide(); 413 | $details.hide(); 414 | $divider.hide(); 415 | count++; 416 | 417 | return; 418 | } else { 419 | $row.fadeIn(); 420 | $details.fadeIn(); 421 | $divider.fadeIn(); 422 | } 423 | }); 424 | 425 | // show number of filtered stories in header 426 | if (count > 0) { 427 | $('#menu-filters .count').text(count).fadeIn(); 428 | } else { 429 | $('#menu-filters .count').text('').hide(); 430 | } 431 | }, 432 | 433 | checkFiltered: function(title, domain, username){ 434 | var filters = hn.getStorage('filters'); 435 | var filter; 436 | 437 | for (var i=0, l=filters.length; i < l; i++){ 438 | 439 | // filter domain 440 | if (filters[i].match(/^site:/)) { 441 | 442 | // domain name can be partial match 443 | var re = new RegExp(filters[i].replace(/site:/i, ''), 'gi'); 444 | if (domain.match(re)) return true; 445 | 446 | // filter user 447 | } else if (filters[i].match(/^user:/)) { 448 | 449 | // username must be exact match 450 | var re = new RegExp('^' + filters[i].replace(/user:/i, '') + '$', 'gi'); 451 | if (username.match(re)) return true; 452 | } 453 | 454 | // filter story title 455 | var re = new RegExp(filters[i],"gi"); 456 | if (title.match(re)) return true; 457 | } 458 | 459 | return false; 460 | }, 461 | 462 | getStorage: function(name){ 463 | return JSON.parse(localStorage.getItem(name)) || []; 464 | }, 465 | 466 | setStorage: function(name, data){ 467 | return localStorage.setItem(name, JSON.stringify(data)); 468 | }, 469 | 470 | addStorage: function(name, item){ 471 | var f = hn.getStorage(name); 472 | var pos = f.indexOf(item); 473 | 474 | // if the filter doesnt already exist 475 | if (pos == -1) { 476 | f.push(item); 477 | hn.setStorage(name, f); 478 | } 479 | }, 480 | 481 | removeStorage: function(name, item){ 482 | var f = hn.getStorage(name); 483 | var pos = f.indexOf(item); 484 | 485 | // if the filter exists 486 | if (pos != -1) { 487 | f.splice(pos, 1); 488 | hn.setStorage(name, f); 489 | } 490 | } 491 | }; 492 | 493 | $(hn.init); 494 | -------------------------------------------------------------------------------- /js/ident/ident-0.1.min.js: -------------------------------------------------------------------------------- 1 | ident=new function(){};ident.version="0.1.7";ident.useInwardEdges=true;ident.identities=new Array();ident.domains=new Array();ident.history=new Array();ident.ufParser=null;ident.rssParser=null;ident.atomParser=null;ident.iconPath="ident/icons/";ident.addPrimaryURL=true;ident._startUrl="";ident._apiReturnCount=0;ident._usernames=new Array();ident._primaryCalled=false;ident._secondaryCalled=false;ident._endPoints={sites:[]};ident._endPointsArray=[["12seconds tv","12seconds.tv",[["12seconds.tv/channel/{username}","hCard","Profile","h"],["12seconds.tv/followers/{username}","hCard","Friends","h"],["12seconds.tv/followers/{username}?page={pagenumber}","hCard","Friends","h"],["12seconds.tv/channel/{username}","hAtom","Video","h"]]],["43things","43things.com",[["www.43things.com/person/{username}","None","None","h"],["www.43things.com/rss/uber/author?username={username}","Rss","Activity","r"]]],["43people","43people.com",[["{username}.43people.com/","None","None","h"],["www.43people.com/rss/uber/person?person={username}","Rss","Activity","r"]]],["43places","43places.com",[["{username}.43places.com/","None","None","h"]]],["Backnetwork","backnetwork.com",[]],["Backtype","backtype.com",[["www.backtype.com/{username}/","None","Profile","h"],["feeds.backtype.com/{username}","Rss","Activity","r"]]],["BarCamp Brighton 3","barcampbrighton3.backnetwork.com",[["barcampbrighton3.backnetwork.com/people/person.aspx?personid={username}","hCard","Profile","h"],["barcampbrighton3.backnetwork.com/people/person.aspx?personid={username}","XFN-hCard","Friends","h"]]],["BarCamp London 5","barcamplondon5.backnetwork.com",[["barcamplondon5.backnetwork.com/people/person.aspx?personid={username}","hCard","Profile","h"],["barcamplondon5.backnetwork.com/people/person.aspx?personid={username}","XFN-hCard","Friends","h"]]],["Blip.fm","blip.fm",[["blip.fm/profile/{username}/","None","None","h"],["blip.fm/feed/{username}","Atom","Audio","a"]]],["Blip.tv","blip.tv",[["{username}.blip.tv/","None","Profile","h"]]],["Blippr","blippr.com",[["www.blippr.com/profiles{username}","None","Profile","h"],["www.blippr.com/profiles/{username}/feed.rss","Atom","Activity","a"]]],["BlogSpot","blogspot.com",[]],["Blogger","blogger.com",[["www.blogger.com/profile/{userid}","None","Profile","h"]]],["Brightkite","brightkite.com",[["brightkite.com/people/{username}","hCard","Profile","h"],["brightkite.com/people/{username}/friends?page={pagenumber}","None","Friends","h"],["brightkite.com/people/{username}/objects.rss","Atom","Activity","a"]]],["ClaimId","claimid.com",[["claimid.com/{username}","hCard","Profile","h"]]],["CoComment","cocomment.com",[["www.cocomment.com/comments/{username}","None","None","h"],["www.cocomment.com/webRssUser/{username}.rss","Rss","Activity","r"]]],["Corkd","corkd.com",[["corkd.com/people/{username}","hCard","Profile","h"],["corkd.com/people/{username}/buddies?page={pagenumber}","XFN","Friends","h"]]],["Cliqset","cliqset.com",[["cliqset.com/user/{username}","None","Profile","h"],["cliqset.com/feed/atom?uid={username}","Atom","Activity","a"]]],["d.construct 08","dconstruct08.backnetwork.com",[["dconstruct08.backnetwork.com/people/person.aspx?personid={username}","hCard","Profile","h"],["dconstruct08.backnetwork.com/people/person.aspx?personid={username}","XFN-hCard","Friends","h"]]],["Delicious","del.icio.us",[["feeds.delicious.com/v2/rss/{username}?count=20","Atom","Bookmarks","a"],["del.icio.us/rss/{username}","Rss","Bookmarks","r"],["del.icio.us/{username}#bundle-tags","rel-tag","Interests","h"],["del.icio.us/{username}","None","Profile","h"],["delicious.com/{username}","None","Profile","h"]]],["Digg","digg.com",[["digg.com/users/{username}","hCard","Profile","h"],["digg.com/users/{username}/friends/view/page{pagenumber}","XFN-hCard","Friends","h"]]],["Disqus","disqus.com",[["www.disqus.com/people/{username}/","None","Profile","h"],["www.disqus.com/people/{username}/comments.rss","Rss","Lifestream","r"]]],["Django People","djangopeople.net",[["djangopeople.net/{username}/","hCard","Profile","h"],["djangopeople.net/{username}/","XFN","Services","h"]]],["Dopplr","dopplr.com",[["www.dopplr.com/traveller/{username}","hCard","Profile","h"]]],["Edenbee","edenbee.com",[["www.edenbee.com/users/{username}","hCard","Profile","h"],["www.edenbee.com/users/{username}/relationships?page=(pagenumber}","hCard","Friends","h"],["www.edenbee.com/users/{username}/relationships","hCard","Friends","h"],["edenbee.com/users/{username}","None","None","h"]]],["Emberapp","emberapp.com",[["emberapp.com/{username}","None","Profile","h"],["emberapp.com/{username}/images.rss","None","Images","r"]]],["Facebook","facebook.com",[["www.facebook.com/{username}","hCard","Profile","html"],["www.facebook.com/{username}","XFN","Friends","html"]]],["FFFFound","ffffound.com",[["ffffound.com/home/{username}/found/feed","Rss","Images","r"],["ffffound.com/home/{username}/found/","None","None","h"]]],["Flickr","flickr.com",[["www.flickr.com/people/{username}/","hCard","Profile","h"],["api.flickr.com/services/feeds/photos_public.gne?id={userid}&format=rss_200","Rss","Images","r"],["api.flickr.com/services/feeds/photos_public.gne?id={userid}&format=atom","Atom","Images","a"],["www.flickr.com/photos/{username}/","None","Images","h"],["flickr.com/photos/{username}/","None","Images","h"],["www.flickr.com/people/{username}/contacts/?page={pagenumber}","None","Friends","h"]]],["FOTB 08","fotb08.backnetwork.com",[["fotb08.backnetwork.com/people/person.aspx?personid={username}","hCard","Profile","h"],["fotb08.backnetwork.com/people/person.aspx?personid={username}","XFN-hCard","Friends","h"]]],["Fotolog","fotolog.com",[["www.fotolog.com/{username}","None","Profile","h"]]],["FriendFeed","friendfeed.com",[["friendfeed.com/{username}","hCard","Profile","h"],["friendfeed.com/{username}/services","XFN","Services","h"],["friendfeed.com/{username}?format=atom","Atom","Lifestream","a"]]],["GetSatisfaction","getsatisfaction.com",[["getsatisfaction.com/people/{username}","hCard","Profile","h"],["getsatisfaction.com/people/{username}.rss","Rss","Activity","r"]]],["Github","github.com",[["github.com/{_usernames}/","hCard","Profile","h"],["github.com/{username}.atom","Atom","Activity","a"]]],["Google","google.com",[["www.google.com/profiles/{username}","hCard","Profile","h"],["www.google.com/profiles/{username}","XFN","Services","h"],["www.google.com/profiles/{userid}","XFN","Services","h"],["www.google.com/profiles/{userid}","hCard","Profile","h"]]],["Google Reader","google.com",[["www.google.com/reader/shared/{username}","None","Profile","h"]]],["hi5","hi5.com",[]],["Huffduffer","huffduffer.com",[["huffduffer.com/{username}","hCard","Profile","h"],["huffduffer.com/{username}/rss","Rss","Audio","r"],["huffduffer.com/{username}","hAtom","Audio","h"]]],["Identica","identi.ca",[["identi.ca/{username}","hCard","Profile","h"],["identi.ca/{username}/foaf","FOAF","Profile","Xml"],["identi.ca/{username}/subscriptions?page={pagenumber}","hCard","Friends","h"],["identi.ca/{username}","hAtom","Status","h"],["identi.ca/{username}","rel-tag","Interests","h"],["identi.ca/{username}/all","hAtom","Friends Status","h"]]],["Jaiku","jaiku.com",[["{username}.jaiku.com/","hCard","Profile","h"]]],["JPG","jpgmag.com",[["www.jpgmag.com/people/{username}/photos","hCard","Profile","h"],["www.jpgmag.com/people/{username}/rss","Rss","Images","r"],["www.jpgmag.com/people/{username}/stories/rss","Rss","Entries","r"],["www.jpgmag.com/people/{username}/stories","None","None","h"]]],["Joost","joost.com",[["www.joost.com/users/{username}/","None","Profile","h"],["www.joost.com/api/events/get/{username}?fmt=atom","Atom","Video","a"]]],["krop","krop.com",[["www.krop.com/{username}/resume/","None","Resume","h"],["www.krop.com/{username}/portfolio/","None","Profile","h"]]],["Last.fm","last.fm",[["www.last.fm/user/{username}","hCard","Profile","h"],["www.last.fm/user/{username}/friends?page={pagenumber}","hCard","Friends","h"],["ws.audioscrobbler.com/1.0/user/{username}/recenttracks.rss","Rss","Activity","r"],["www.last.fm/user/{username}","hCalendar","Events","h"],["ws.audioscrobbler.com/1.0/user/{username}/events.rss","Rss","Events","r"]]],["Linked-in","linkedin.com",[["www.linkedin.com/in/{username}","hCard","Profile","h"],["www.linkedin.com/in/{username}","hResume","Resume","h"],["www.linkedin.com/pub/{username}","hCard","Profile","h"],["www.linkedin.com/pub/{username}","hResume","Resume","h"]]],["Livejournal","livejournal.com",[["{username}.livejournal.com/","None","Profile","h"]]],["MadgexLab","ufapi.lab.madgex.com",[["ufapi.lab.madgex.com/profile/{username}","hCard","Profile","h"]]],["Mashed 08","mashed08.backnetwork.com",[["mashed08.backnetwork.com/people/person.aspx?personid={username}","hCard","Profile","h"],["mashed08.backnetwork.com/people/person.aspx?personid={username}","XFN-hCard","Friends","h"]]],["Meetup","meetup.com",[]],["Microformats.org","microformats.org",[["microformats.org/wiki/User:{username}","hCard","Profile",undefined]]],["Mybloglog","mybloglog.com",[["www.mybloglog.com/buzz/members/{username}/hcard","hCard","Profile","h"],["www.mybloglog.com/buzz/members/{username}/","None","None","h"],["www.mybloglog.com/buzz/members/{username}/me/rss.xml","Atom","Lifestream","a"]]],["mytvshows","mytvshows.org",[["www.mytvshows.org/user/{username}/","hCard","Profile","h"],["www.mytvshows.org/rss/user/{username}/","Rss","Activity","r"]]],["My Name is E","mynameise.com",[["www.mynameise.com/{username}","None","Profile","h"],["mynameise.com/{username}","None","Profile","h"],["mynameise.com/{username}","XFN","Services","h"]]],["MyOpenid","myopenid.com",[["{username}.myopenid.com/","None","None","h"]]],["MySpace","myspace.com",[["myspace.com/{username)","hCard","Profile","h"],["www.myspace.com/{username)","hCard","Profile","h"]]],["Netvibes","netvibes.com",[["www.netvibes.com/{username)","hCard","Profile","h"],["www.netvibes.com/{username)/activities?format=atom","Atom","Activity","a"]]],["Newsvine","newsvine.com",[["{username}.newsvine.com/","None","None","h"]]],["Odeo","odeo.com",[["odeo.com/users/{username}","None","None","h"]]],["Orkut","orkut.com",[["www.orkut.com/Profile.aspx?uid={userid}","None","None","h"]]],["Picasa","picasaweb.google.com",[["picasaweb.google.com/{username}","None","Profile","h"],["picasaweb.google.com/data/feed/base/user/{username}?alt=rss&kind=album&hl=en_US&access=public","Rss","Images","r"]]],["Plaxo","plaxo.com",[["{username}.myplaxo.com/","hCard","Profile","h"]]],["Plazes","plazes.com",[["plazes.com/whereis/{username}","hCard","Profile","h"],["plazes.com/whereis/{username}","hCalendar","Events","h"]]],["Plurk","plurk.com",[["www.plurk.com/{username}","None","Profile","h"],["www.plurk.com/{username}.xml","Atom","Events","a"]]],["Profilactic","profilactic.com",[["www.profilactic.com/profile/{username}","None","Profile","h"]]],["Readernaut","readernaut.com",[["readernaut.com/{username}","None","Profile","h"],["readernaut.com/feeds/rss/{username}","Rss","Activity","r"]]],["Seesmic","seesmic.com",[["new.seesmic.com/{username}","hCard","Profile","h"],["feeds.seesmic.com/user.{username}.atom","Atom","Video","a"]]],["Slideshare","slideshare.net",[["www.slideshare.net/rss/user/{username}","Rss","Slides","r"],["www.slideshare.net/{username}","hCard","Profile","h"],["slideshare.net/{username}","None","Profile","h"],["www.slideshare.net/{username}/followers/{pagenumber}","hCard","Friends","h"]]],["Soup.io","soup.io",[["{username}.soup.io/","hCard","Profile","h"],["{username}.soup.io/","XFN","Services","h"],["{username}.soup.io/rss","Rss","Lifestream","r"]]],["Smugmug","smugmug.com",[["{username}.smugmug.com/","None","Profile","h"],["{username}.smugmug.com/hack/feed.mg?Type=nickname&Data={username}&format=atom10","Atom","Photos","a"]]],["Stumbleupon","stumbleupon.com",[["www.stumbleupon.com/stumbler/{username}","None","Profile","h"],["rss.stumbleupon.com/user/{username}/favorites","Rss","Bookmarks","r"]]],["Technorati","technorati.com",[["technorati.com/people/technorati/{username}","hCard","Profile","h"]]],["Threadless","threadless.com",[]],["Times People","timespeople.nytimes.com",[["timespeople.nytimes.com/view/user/{username}/","None","Profile","h"],["timespeople.nytimes.com/view/user/{username}/rss.xml","Rss","Activity","r"]]],["Tumblr","tumblr.com",[["{username}.tumblr.com/","None","None","h"],["{username}.tumblr.com/rss","Rss","Lifestream","r"]]],["Twitter","twitter.com",[["twitter.com/{username}","hCard","Profile","h"],["twitter.com/{username}#people","XFN-hCard","Friends","h"],["twitter.com/{username}","hAtom","Status","h"]]],["Twitpic","twitpic.com",[["www.twitpic.com/photos/{username}","None","Profile","h"],["twitpic.com/photos/{username}/feed.rss","Rss","Photos","r"]]],["Upcoming","upcoming.yahoo.com",[["upcoming.yahoo.com/user/{userid}/","hCard","Profile","h"],["upcoming.yahoo.com/user/{userid}/","hCalendar","Events","h"],["upcoming.yahoo.com/user/{userid}/past/","hCalendar","Events","h"],["upcoming.yahoo.com/syndicate/v2/my_events/{userid}","Rss","Events","r"]]],["Ustream","ustream.tv",[["www.ustream.tv/{username}","None","Profile","h"]]],["Viddler","viddler.com",[["www.viddler.com/explore/{username}","None","Profile","h"],["www.viddler.com/explore/{username}/videos/feed/","Rss","Video","r"]]],["Vimeo","vimeo.com",[["www.vimeo.com/{username}","hCard","Profile","h"],["www.vimeo.com/{username}/contacts/sort:newest/page:{pagenumber}","None","Friends","h"],["vimeo.com/{username}/videos/rss","Atom","Video","a"]]],["Vox","vox.com",[["{username}.vimeo.com/profile/","hCard","Profile","h"]]],["Windows Live","spaces.live.com",[["{username}.spaces.live.com/","None","Profile","h"]]],["Wordpress","wordpress.com",[["{username}.wordpress.com/","None","Profile","h"],["{username}.wordpress.com/feed/atom/","Atom","Lifestream","a"]]],["Xing","xing.com",[["www.xing.com/profile/{username}","hCard","Profile","h"],["www.xing.com/profile/{username}","hResume","Friends","h"]]],["Yahoo","profiles.yahoo.com",[["profiles.yahoo.com/{username}","hCard","Profile","h"]]],["YIID","yiid.com",[["{username}.yiid.com/","hCard","Profile","h"],["{username}.yiid.com/","rel-tag","Interests","h"],["{username}.yiid.com/contacts/{pagenumber}","hCard","Friends","h"],["{username}.yiid.com/identities","XFN","Services","h"],["{username}.yiid.com/cv","hResume","Resume","h"],["{username}.yiid.com/xml/atom_user","Atom","Lifestream","a"]]],["Yelp","yelp.com",[]],["Youtube","youtube.com",[["gdata.youtube.com/feeds/base/users/{username}/uploads?alt=rss&v=2","Atom","Video","a"],["youtube.com/rss/user/{username}/videos.rss","Rss","Video","r"],["youtube.com/user/{username}","None","Profile","h"],["www.youtube.com/profile?user={username}","None","Profile","h"],["www.youtube.com/user/{username}","None","Profile","h"]]]];ident._excludeDomains=["pownce.com","ma.gnolia.com","huff-duff.com","lastfm.com.br","lastfm.com.tr","lastfm.de","lastfm.es","lastfm.fr","lastfm.it","lastfm.jp","lastfm.pl","lastfm.ru","lastfm.se","cn.last.fm","radio.aol.fr"];ident._excludeUrls=["twitter.com/#replies","twitter.com/#inbox","twitter.com/#favorites","twitter.com/following","twitter.com/followers","identi.ca/group","identi.ca/tag","identi.ca/featured","identi.ca/favorited"];ident.profile=function(a,b){this.name="";this.domain="";this.username=new Array();this.profileUrl=b;this.iconUrl="";this.spriteClass=""};ident.domain=function(a,b){this.name="";this.urls=new Array();this.domain=b;this.accounts=new Array();this.hashCard=false;this.hashResume=false};ident.account=function(f,a,b,d,e,c){this.sgn=f;this.verified=a;this.profile=b;this.resume=d;this.ident=e;this.pk=c};ident.historyItem=function(b,a){this.url=b;this.apiurl=a;this.domain="";this.name="";this.contentType="";this.schema="";this.rawJSON=""};ident.username=function(){this.name="";this.rank=0};ident.search=function(b){ident.reset();var d=new Array();if(b.indexOf(",")>-1){d=b.split(",")}else{d[0]=b}for(var a=0;a<=d.length-1;a++){if(a<49){d[a];var c=ident.convertShorthandAddress(d[a]);if(ident.isUrl(c)||ident.isEmail(c)){if(ident.isExcludedUrl(c)==false){ident._startUrl+=c+","}else{ident.error('Sorry web addresses have to represent a person like profile page or a blog i.e. "http://twitter.com/glennjones"');ident._startUrl="";break}}else{ident.error('Sorry there seem to be a problem with the format of the web address you entered: "'+b+'"');ident._startUrl="";break}}}ident.apiManager()};ident.apiManager=function(a,b){if(ident._startUrl!=""){if(a!=null){ident.parseSGN(a,b);ident.statusUpdateEvent(["data-change"])}if(ident._primaryCalled==true&&ident._secondaryCalled==true){}if(ident._primaryCalled==true&&ident._secondaryCalled==false){if(ident.useInwardEdges==true){ident._secondaryCalled=true;ident.getSocialGraphData(ident._startUrl,1)}}if(ident._primaryCalled==false){ident._primaryCalled=true;ident.getSocialGraphData(ident._startUrl,0)}}else{ident.error('Sorry web addresses have to represent a person like profile page or a blog i.e. "http://twitter.com/glennjones"')}};ident.webFingerManager=function(b,c){ident._apiReturnCount++;if(b!=null){c.rawJSON=b;if(b[0].links){for(var a=0;a<=b[0].links.length-1;a++){if(b[0].links[a].rel=="http://microformats.org/profile/hcard"||b[0].links[a].rel=="http://webfinger.net/rel/profile-page"){ident._startUrl=b[0].links[a].href;ident.apiManager();break}}}}};ident.reset=function(){ident.domains=new Array();ident.history=new Array();ident.profiles=new Array();ident._startUrl="";ident._apiReturnCount=0;ident._primaryCalled=false;ident._secondaryCalled=false;ident._usernames=new Array();ident.resetTrigger()};ident.registerParser=function(a){if((a.parseUf>0&&ident.ufParser==null)||(ident.ufParser!=null&&a.parseUf>ident.ufParser.parseUf)){ident.ufParser=a}if((a.parseRss>0&&ident.rssParser==null)||(ident.rssParser!=null&&a.parseRss>ident.rssParser.parseRss)){ident.rssParser=a}if((a.parseAtom>0&&ident.atomParser==null)||(ident.atomParser!=null&&a.parseAtom>ident.atomParser.parseAtom)){ident.atomParser=a}};ident.getSocialGraphData=function(b,d){var a="http://socialgraph.apis.google.com/lookup?q="+encodeURIComponent(b)+"&fme=1&edo=1&edi="+d+"&sgn=1&pretty=1&jme=1";var c=new ident.historyItem(b,a);c.apiName="googlesoicalgraph";ident.history[ident.history.length]=c;ident.GoogleGraphAPICall(a,c)};ident.parseSGN=function(c,g){ident._apiReturnCount++;if(c!=null){g.rawJSON=c;var b="";for(var f in c.canonical_mapping){b=f}for(var f in c.nodes){if(f.indexOf("sgn://")>-1){var e=c.nodes[f];var d="";var a="";if(e.attributes["profile"]!=null){d=e.attributes["profile"]}if(e.attributes["url"]!=null){a=e.attributes["url"]}ident.appendDomainNode(f,a,true,d);ident.processClaimedNodes(e)}}for(var f in c.nodes){if(f.indexOf("http://")>-1){var e=c.nodes[f];ident.appendDomainNode("",f,false,"");ident.processClaimedNodes(e)}}}ident.postProcessDomainNode()};ident.processClaimedNodes=function(b){if(b.claimed_nodes!=null){for(var a=0;a<=b.claimed_nodes.length-1;a++){var c=b.claimed_nodes[a];if(c.indexOf("sgn://")>-1){ident.appendDomainNode(c,"",true,"")}}for(var a=0;a<=b.claimed_nodes.length-1;a++){var c=b.claimed_nodes[a];if(c.indexOf("http://")>-1){ident.appendDomainNode("",c,true,"")}}}if(b.unverified_claiming_nodes!=null){for(var a=0;a<=b.unverified_claiming_nodes.length-1;a++){var c=b.unverified_claiming_nodes[a];if(c.indexOf("sgn://")>-1){ident.appendDomainNode(c,"",false,"")}}for(var a=0;a<=b.unverified_claiming_nodes.length-1;a++){var c=b.unverified_claiming_nodes[a];if(c.indexOf("http://")>-1){ident.appendDomainNode("",c,false,"")}}}};ident.postProcessDomainNode=function(e,d,a,c){for(var b=0;b0){found=null;for(var h=0;h1){var d=new Array();var a=ident.topUsername();for(var e=0;e<=ident.domains[c].accounts.length-1;e++){if(ident.domains[c].accounts[e].ident==a){d[d.length]=ident.domains[c].accounts[e]}if(ident.domains[c].accounts[e].pk!=""){d[d.length]=ident.domains[c].accounts[e]}}ident.domains[c].accounts=d}}}};ident.findUserNameBasedURL=function(b,c){for(var a=0;a-1){return b[a]}}return""};ident.domainNodeContains=function(b){found=false;for(var a=0;a-1){e=true}}}return e};ident.sortByName=function(e,d){var c=e.name.toLowerCase();var f=d.name.toLowerCase();return((cf)?1:0))};ident.sortByDomain=function(e,d){var c=e.domain.toLowerCase();var f=d.domain.toLowerCase();return((cf)?1:0))};ident.sortBySGN=function(e,d){var c=e.sgn.toLowerCase();var f=d.sgn.toLowerCase();return((cf)?1:0))};ident.parseUserFromSGN=function(a){var b=a.sgn.substring(6,a.sgn.length);parts=b.split("?");if(parts[1].indexOf("ident=")>-1){a.username=parts[1].replace("ident=","")}else{a.userid=parts[1].replace("pk=","")}};ident.appendUrl=function(d,b){var c=false;for(var a=0;a<=d.length-1;a++){if(d[a]==b){c=true;break}}if(c==false){d[d.length]=b}};ident.appendUsername=function(d){var c=false;for(var a=0;a<=ident._usernames.length-1;a++){if(ident._usernames[a].name==d){c=true;ident._usernames[a].rank++;break}}if(c==false){var b=new ident.username();b.name=d;ident._usernames[ident._usernames.length]=b}};ident.appendCustomSGNData=function(b){for(var a=0;a<=ident._endPoints.sites.length-1;a++){var c=ident._endPoints.sites[a].domain.replace(" ","");if(ident.compareRootDomains(b.domain,c)){b.name=ident._endPoints.sites[a].name;ident.createCustomSGN(b,ident._endPoints.sites[a])}}};ident.createCustomSGN=function(e,i){e.urlmappings=i.urlmappings;for(var g=0;g<=e.urls.length-1;g++){var b=e.urls[g];for(var h=0;h<=i.urlmappings.length-1;h++){var a=i.urlmappings[h];var j=a.urltemplate;if(j!=""&&(j.indexOf("{username}")>-1||j.indexOf("{userid}")>-1)){var c=0;if(j.indexOf("{username}")>-1){c=j.indexOf("{username}")}if(j.indexOf("{userid}")>-1){c=j.indexOf("{userid}")}var d=new Array(2);if(c!=0){d[0]=j.toLowerCase().substring(0,c);if(j.indexOf("{username}")){d[1]=j.toLowerCase().substring(c+10)}else{d[1]=j.toLowerCase().substring(c+8)}}startMatch=false;endMatch=false;user=b;if(b.indexOf(d[0])==0){startMatch=true;part=d[0];user=user.substring(part.length,user.length)}if(d.length==2){if(d[1].length>0){if(ident.endsWith(b,d[1])){endMatch=true;user=user.replace(d[1],"")}else{if(ident.endsWith(b,d[1]+"/")){endMatch=true;user=user.replace(d[1]+"/","")}}}else{endMatch=true}}if(ident.endsWith(user,"/")){user=user.substring(0,user.length-1)}if(user.indexOf("/")>-1){endMatch=false}if(user.indexOf("?")>-1){userParts=user.split("?");user=userParts[0]}if(user.indexOf("#")>-1){userParts=user.split("#");user=userParts[0]}if(startMatch&&endMatch){var f=new ident.account("","","","","","");f.verified=false;f.profile="";if(a.urltemplate.indexOf("{username}")>-1){f.ident=user;ident.appendUsername(user);f.sgn="sgn://"+e.domain+"/?ident="+user}if(a.urltemplate.indexOf("{userid}")>-1){f.pk=user;f.sgn="sgn://"+e.domain+"/?pk="+user}ident.appendProfileData(i.urlmappings,f,b,e);if(ident.domainIsExcluded(e.domain)==false){ident.appendUniqueIdentityNode(e,f)}}}}}for(var g=0;g<=e.accounts.length-1;g++){ident.appendProfileData(i.urlmappings,e.accounts[g],"",e)}};ident.appendUniqueIdentityNode=function(c,a){var b=null;for(var d=0;d<=c.accounts.length-1;d++){if(c.accounts[d].sgn==a.sgn){b=c.accounts[d];break}}if(b==null){c.accounts[c.accounts.length]=a}};ident.appendProfileData=function(d,a,b,c){a.profile=ident.getAPIEndPoint("Profile","hCard",d,a);a.resume=ident.getAPIEndPoint("Resume","hResume",d,a);if(a.profile!=""){c.hashCard=true}if(a.resume!=""){c.hashResume=true}};ident.getAPIEndPoint=function(g,d,c,f,e){var b="";if(c!=undefined){if(c.length){for(var h=0;h<=c.length-1;h++){var a=c[h];if(a.contenttype==g&&a.schema==d){var i=false;b=a.urltemplate;if(f.ident!=""&&b.indexOf("{username}")>-1){b=b.replace("{username}",f.ident);i=true}if(f.pk!=""&&b.indexOf("{userid}")>-1){b=b.replace("{userid}",f.pk);i=true}if(e!=undefined){b=b.replace("{pagenumber}",e)}if(!i){b=""}}if(b!=""){break}}}}return b};ident.topUsername=function(){var b=new ident.username();for(var a=0;a<=ident._usernames.length-1;a++){if(ident._usernames[a].rank>b.rank){b=ident._usernames[a]}}return b.name};ident.isSearching=function(){if(ident._apiReturnCount>=ident.history.length){return false}else{return true}};ident.buildExcludeUrlList=function(){for(var a=0;a<=ident._endPoints.sites.length-1;a++){ident._excludeUrls[ident._excludeUrls.length]=ident._endPoints.sites[a].domain}};ident.buildExcludeUrlList();ident.buildEndPointList=function(){var e=new Array();for(var a=0;a<=ident._endPointsArray.length-1;a++){var c=new Object();c.name=ident._endPointsArray[a][0];c.domain=ident._endPointsArray[a][1];if(c.name=="Google"){c.domain="google.com|profiles"}c.urlmappings=new Array();for(var d=0;d<=ident._endPointsArray[a][2].length-1;d++){var b=new Object();b.urltemplate=ident._endPointsArray[a][2][d][0];b.schema=ident._endPointsArray[a][2][d][1];b.contenttype=ident._endPointsArray[a][2][d][2];b.mediatype=ident._endPointsArray[a][2][d][3];c.urlmappings[c.urlmappings.length]=b;if(b.urltemplate.indexOf("//")==-1){b.urltemplate="http://"+b.urltemplate}switch(b.mediatype){case"h":b.mediatype="Html";break;case"r":b.mediatype="Rss";break;case"a":b.mediatype="Atom";break}}e[e.length]=c}ident._endPoints={sites:e}};ident.buildEndPointList();ident.isExcludedUrl=function(b){for(var a=0;a<=ident._excludeUrls.length-1;a++){if(ident.compareUrl(b,"http://"+ident._excludeUrls[a])){return true}}return false};ident.convertShorthandAddress=function(a){var c="";if(a!=""){a=a.replace("acct:","");a=ident.trim(a," ");var d=new Array();if(ident.isEmail(a)){a=ident.trim(a);var g="http://webfingerclient-dclinton.appspot.com/lookup?identifier="+encodeURIComponent(a)+"&format=json&pretty=true";var i=new ident.historyItem(a,g);i.apiName="webfinger";ident.history[ident.history.length]=i;ident.WebFingerAPICall(g,i)}if(a.match(/\//g)!=null){if(a.match(/\//g).length==1){d=a.split("\\")}}if(a.indexOf(" ")>-1){d=a.split(" ")}if(d.length==2){var f=new Object();var b=ident.trim(d[0].toLowerCase()," ");var e=ident.trim(d[1].toLowerCase()," ");f.ident=e;f.pk=e;for(var h=0;h<=ident._endPoints.sites.length-1;h++){if(b==ident._endPoints.sites[h].domain){c=ident.getAPIEndPoint("Profile","hCard",ident._endPoints.sites[h].urlmappings,f);if(c==""){c=ident.getAPIEndPoint("Profile","None",ident._endPoints.sites[h].urlmappings,f)}}if(b==ident._endPoints.sites[h].name.toLowerCase().replace(/\s/g,"")){if(c==""){c=ident.getAPIEndPoint("Profile","hCard",ident._endPoints.sites[h].urlmappings,f)}if(c==""){c=ident.getAPIEndPoint("Profile","None",ident._endPoints.sites[h].urlmappings,f)}}if(c!=""){break}}}if(c!=""){a=c}}return a};ident.compareRootDomains=function(b,a){var c=false;if(b!=""||a!=""){b=b.toLowerCase().replace("www.","");if(b==a){c=true}}return c};ident.compareUrl=function(b,a){var c=false;if(b.indexOf("#")>-1){b=b.split("#")[0]}if(a.indexOf("#")>-1){a=a.split("#")[0]}if(b!=""||a!=""){b=b.toLowerCase().replace("www.","");a=a.toLowerCase().replace("www.","");if(ident.endsWith(b,"/")==false){b=b+"/"}if(ident.endsWith(a,"/")==false){a=a+"/"}if(b.toLowerCase()==a.toLowerCase()){c=true}}return c};ident.parseDomainFromURL=function(a){var b="";if(a!=undefined&&a!=""){if(a.indexOf("//")>0){var c=a.split("/");b=c[2]}}return b};ident.parseDomainFromSGN=function(c){var a="";c=c.replace("profiles.google.com","google.com|profiles");c=c.substring(6,c.length);var b=c.split("/");if(b[0].length>-1){a=b[0]}return a};ident.endsWith=function(a,c){var b=a.lastIndexOf(c);return(b!=-1)&&(b+c.length==a.length)};ident.isObject=function(a){return(typeof a=="object")};ident.isArray=function(a){if(a.constructor.toString().indexOf("Array")==-1){return false}else{return true}};ident.isString=function(a){return typeof a=="string"};ident.contains=function(d,a){var c=false;for(var b=0;b-1){var b=k[h].split("[");var a=b[0];var e=Number(b[1].substring(0,b[1].length-1));if(d[a]!=null||d[a]!="undefined"){if(d[a][e]!=null||d[a][e]!="undefined"){d=d[a][e]}}else{currentObject=null}}else{if(d[k[h]]!=null||d[k[h]]!="undefined"){d=d[k[h]]}}}c=d}catch(f){c=null}return c};ident.GoogleGraphAPICall=function(a,b){jQuery.getJSON(a+"&callback=?",function(c){ident.apiManager(c,b)})};ident.WebFingerAPICall=function(a,b){jQuery.getJSON(a+"&callback=?",function(c){ident.webFingerManager(c,b)})};ident.resetTrigger=function(){jQuery(document).trigger("ident:reset")};ident.statusUpdateEvent=function(){if(arguments.length>-1){jQuery(document).trigger("ident:update",arguments[0])}else{jQuery(document).trigger("ident:update")}};ident.error=function(){if(arguments.length>-1){jQuery(document).trigger("ident:error",arguments[0])}else{jQuery(document).trigger("ident:error")}ident.reset()}; -------------------------------------------------------------------------------- /js/ident/ident-content-0.1.min.js: -------------------------------------------------------------------------------- 1 | ident.entries=new Array();ident.events=new Array();ident.tags=new Array();ident.resetContent=function(){ident.entries=new Array();ident.events=new Array();ident.tags=new Array()};ident.hEntry=function(){this.name="";this.domain="";this.sourceUrl="";this.author=new ident.hCard();this["entry-title"]="";this["entry-content"]=new Array();this["entry-summary"]=new Array();this.bookmark=new ident.enclosure();this.enclosure=new Array();this.published="";this.updated="";this["published-datetime"];this["updated-datetime"];this.tag=new Array()};ident.hAtom=function(){this.domain="";this.sourceUrl="";this.hentry=new Array();this.tag=new Array()};ident.enclosure=function(){this.text="";this.link="";this.type="";this.rel="";this.lenght=""};ident.findContent=function(d,h,c){var a="";var b="";for(var f=0;f-1){a["entry-title"]=a["entry-content"][0]}}if(a.updated==""){a.updated=a.published}if(a.domain=="twitter.com"){a["published-datetime"]=ident.getTwitterDate(a.published);a["updated-datetime"]=ident.getTwitterDate(a.updated)}else{a["published-datetime"]=ident.getJavaScriptDates(a.published);a["updated-datetime"]=ident.getJavaScriptDates(a.updated);a["dtstart-datetime"]=ident.getJavaScriptDates(a.dtstart);a["dtend-datetime"]=ident.getJavaScriptDates(a.dtend)}};ident.postProcesshCalendar=function(a){a["dtstart-datetime"]=ident.getJavaScriptDates(a.dtstart);a["dtend-datetime"]=ident.getJavaScriptDates(a.dtend)};ident.getJavaScriptDates=function(a){var c;if(Date.parse(a)>0){c=new Date(Date.parse(a))}if(c==undefined){var b=new ISODate(a);if(b.dY>-1&&b.dY!=undefined){if(b.tH!=null&&b.tM!=-1&&b.tS!=-1){c=new Date(parseInt(b.dY),parseInt(b.dM-1),parseInt(b.dD),parseInt(b.tH),parseInt(b.tM),parseInt(b.tS))}else{c=new Date(parseInt(b.dY),parseInt(b.dM-1),parseInt(b.dD))}}}return c};ident.getTwitterDate=function(c){var d;if(c.indexOf("minute")>-1||c.indexOf("minutes")>-1||c.indexOf("hour")>-1||c.indexOf("hours")>-1||c.indexOf("day")>-1){number=c.replace("about ","").replace(" hour ago","").replace(" hours ago","").replace(" minutes ago","").replace(" minute ago","");var b=new Date();if(c.indexOf("minute")>-1||c.indexOf("minutes")>-1){b.setTime(b.getTime()-(parseInt(number)*60*1000))}else{b.setTime(b.getTime()-(parseInt(number)*60*60*1000))}d=b}else{var e=c.split(" ");month=1;switch(e[2]){case"Jan":month=0;break;case"Feb":month=1;break;case"Mar":month=2;break;case"Apr":month=3;case"May":month=4;break;case"Jun":month=5;break;case"Jul":month=6;break;case"Aug":month=7;break;case"Sep":month=8;break;case"Oct":month=9;break;case"Nov":month=10;break;case"Dec":month=11;break}var a=e[0].split(":");e[3]=parseInt(e[3].replace("th","").replace("rd","").replace("nd","").replace("st",""));var b=new Date();d=new Date(b.getFullYear(),month,e[3],parseInt(a[0]),parseInt(a[1]),0);if(e[1]=="PM"){d.setTime(d.getTime()+(12*60*60*1000))}d.setTime(d.getTime()+(8*60*60*1000))}return d};function ISODate(){this.dY;this.dM=-1;this.dD=-1;this.z=false;this.tH;this.tM=-1;this.tS=-1;this.tD=-1;this.tzH;this.tzM=-1;this.tzPN="+";this.z=false;this.format="W3C";if(arguments[0]){this.Parse(arguments[0])}}ISODate.prototype.Parse=function(f){var b="",h;var c="",e="",g="";f=f.toUpperCase();if(f.indexOf("T")>-1){h=f.split("T");c=h[0];e=h[1];if(e.indexOf("Z")>-1||e.indexOf("+")>-1||e.indexOf("-")>-1){var d=e.split("Z");e=d[0];g=d[1];this.z=true;if(e.indexOf("+")>-1||e.indexOf("-")>-1){var a=0;if(e.indexOf("+")>-1){a=e.indexOf("+")}else{a=e.indexOf("-")}g=e.substring(a,e.length);e=e.substring(0,a)}}}else{c=f}if(c!=""){this.ParseDate(c);if(e!=""){this.ParseTime(e);if(g!=""){this.ParseTimeZone(g)}}}};ISODate.prototype.ParseDate=function(b){var a="",c;c=b.match(/(\d\d\d\d)?-?(\d\d)?-?(\d\d)?/);if(c[1]){this.dY=c[1]}if(c[2]){this.dM=c[2]}if(c[3]){this.dD=c[3]}};ISODate.prototype.ParseTime=function(a){var b="";var c=a.match(/(\d\d)?:?(\d\d)?:?(\d\d)?.?([0-9]+)?/);timeSegment=a;if(c[1]){this.tH=c[1]}if(c[2]){this.tM=c[2]}if(c[3]){this.tS=c[3]}if(c[4]){this.tD=c[4]}};ISODate.prototype.ParseTimeZone=function(a){var b="";var c=a.match(/([-+]{1})?(\d\d)?:?(\d\d)?/);if(c[1]){this.tzPN=c[1]}if(c[2]){this.tzH=c[2]}if(c[3]){this.tzM=c[3]}};ISODate.prototype.toString=function(){if(this.format=="W3C"){dsep="-";tsep=":"}if(this.format=="RFC3339"){dsep="";tsep=""}var a="";if(typeof(this.dY)!="undefined"){a=this.dY;if(this.dM>0&&this.dM<13){a+=dsep+this.dM;if(this.dD>0&&this.dD<32){a+=dsep+this.dD;if(typeof(this.tH)!="undefined"){if(this.tH>-1&&this.tH<25){a+="T"+this.tH;if(this.tM>-1&&this.tM<61){a+=tsep+this.tM;if(this.tS>-1&&this.tS<61){a+=tsep+this.tS;if(this.tD>-1){a+="."+this.tD}}}if(this.z){a+="Z"}if(typeof(this.tzH)!="undefined"){if(this.tzH>-1&&this.tzH<25){a+=this.tzPN+this.tzH;if(this.tzM>-1&&this.tzM<61){a+=tsep+this.tzM}}}}}}}}return a};ident.contentAddedEvent=function(){ident.statusUpdateEvent(["content-added"])};var doc=jQuery(document);doc.ready(function(){if(ident.ufParser!=null){doc.bind("ident:reset",ident.resetContent)}}); -------------------------------------------------------------------------------- /js/ident/ident-profile-0.1.min.js: -------------------------------------------------------------------------------- 1 | ident.combinedProfile;ident.profiles=new Array();ident.resumes=new Array();ident.mes=new Array();ident.xfn=new Array();ident._allProfileUrls=new Array();ident._explicitlyDeclaredProfileUrls=new Array();ident._formattedNames=new Array();ident.formattedName=function(){this.name="";this.rank=0};ident.resetProfiles=function(){ident.combinedProfile=new ident.hCard();ident.profiles=new Array();ident.resumes=new Array();ident.mes=new Array();ident.xfn=new Array();ident._allProfileUrls=new Array();ident._explicitlyDeclaredProfileUrls=new Array();ident._formattedNames=new Array()};ident.name=function(){this.domain="";this.sourceUrl="";this["given-name"]=new Array();this["family-name"]=new Array();this["honorific-prefix"]=new Array()};ident.adr=function(){this.name="";this.domain="";this.sourceUrl="";this.type="";this["street-address"]=new Array();this["extended-address"]=new Array();this.locality="";this.region="";this["postal-code"]="";this["country-name"]="";this["post-office-box"]=""};ident.org=function(){this.domain="";this.sourceUrl="";this["organization-name"]="";this["organization-unit"]=new Array()};ident.hCard=function(){this.domain="";this.sourceUrl="";this.isRepsentative=false;this.fn="";this.n=new ident.name();this.nickname=new Array();this.photo=new Array();this.logo=new Array();this.note=new Array();this.title=new Array();this.role="";this.org=new Array();this.adr=new Array();this.url=new Array();this.email=new Array();this.tel=new Array();this.uid=""};ident.combinedProfile=new ident.hCard();ident.hResume=function(){this.domain="";this.sourceUrl="";this.contact=new ident.hCard();this.summary;this.experience=new Array();this.education=new Array()};ident.hCalendar=function(){this.name="";this.domain="";this.sourceUrl="";this.category=new Array();this.dtend="";this.dtstart="";this.dtstamp="";this.duration="";this["dtend-datetime"]="";this["dtstart-datetime"]="";this["dtstamp-datetime"]="";this["duration-datetime"]="";this.location="";this.status="";this.summary="";this.uid="";this.url="";this["last-modified"]=""};ident.valueTypeProperty=function(){this.domain="";this.sourceUrl="";this.value="";this.type=""};ident.explicitlyDeclaredProfileUrl=function(){this.url="";this.rank=0};ident.combinedProfile=new ident.hCard();ident.rateAddress=function(a){var b=0;if(a!=undefined){if(a["extended-address"]){if(a["extended-address"].length>0){b++}}if(a["street-address"]){if(a["street-address"].length>0){b++}}if(a.locality!=""&&a.locality!=undefined){b++}if(a.region!=""&&a.region!=undefined){b++}if(a["postal-code"]!=""&&a["postal-code"]!=undefined){b++}if(a["country-name"]!=""&&a["country-name"]!=undefined){b++}}return b};ident.createCombinedhCard=function(){var d=ident.combinedProfile=new ident.hCard();for(var a=0;a<=ident.profiles.length-1;a++){var f=ident.profiles[a];var c=ident.profiles[a].domain;var e=ident.profiles[a].sourceUrl;if(f.fn){d.fn=ident.addProperties(d.fn,f.fn,e,c)}if(f.n){if(f.n["given-name"]){if(f.n["given-name"].length){d.n=ident.addPropertiesToObject(d.n,f.n,e,c)}}}if(f.role){d.role=ident.addProperties(d.role,f.role,e,c)}if(f.nickname){if(d.nickname.length){f.nickname[0]=ident.addProperties(d.nickname[0],f.nickname[0],e,c)}}if(f.title){if(f.title.length){if(f.domain!="linkedin.com"){d.title[0]=ident.addProperties(d.title[0],f.title[0],e,c)}}}if(f.org){if(f.org.length){d.org[0]=ident.addPropertiesToObject(d.org[0],f.org[0],e,c)}}if(f.photo){if(f.photo.length){if(d.photo[0]==undefined){d.photo[0]=ident.addProperties(d.photo[0],f.photo[0],e,c)}}}if(f.logo){if(f.logo.length){if(d.logo[0]==undefined){d.logo[0]=ident.addProperties(d.logo[0],f.logo[0],e,c)}}}if(f.note){if(f.note.length){if(d.note[0]==undefined){d.note[0]=ident.addProperties(d.note[0],f.note[0],e,c)}else{if(f.note[0].length>d.note[0].length){d.note[0]=ident.addProperties(d.note[0],f.note[0],e,c)}}}}if(f.adr){var b=0;if(d.adr.length>0){b=ident.rateAddress(d.adr[0])}if(ident.rateAddress(f.adr[0])>b){d.adr[0]=ident.addPropertiesToObject(d.adr[0],f.adr[0],e,c)}}if(f.url){for(var g=0;g<=f.url.length-1;g++){if(f.url[g].indexOf("http://")>-1){if(ident.containsValue(d.url,f.url[g])==false&&ident.containsValue(d.url,f.url[g]+"/")==false){d.url[d.url.length++]=ident.addProperties(null,f.url[g],e,c)}}}}if(f.email){for(var g=0;g<=f.email.length-1;g++){if(f.email[g].value!=undefined){if(f.email[g].value.indexOf("@")>-1){if(ident.containsValue(d.email,f.email[g].value)==false){d.email[d.email.length++]=ident.addPropertiesToObject(null,f.email[g],e,c)}}}}}if(f.tel){for(var g=0;g<=f.tel.length-1;g++){if(ident.containsValue(d.tel,f.tel[g].value)==false){if(f.tel[g].type){if(f.tel[g].type[0]=="work VOICE"){f.tel[g].type[0]="work"}}d.tel[d.tel.length++]=ident.addPropertiesToObject(null,f.tel[g],e,c)}}}}for(var a=0;a<=ident.profiles.length-1;a++){var f=ident.profiles[a];var c=ident.profiles[a].domain;var e=ident.profiles[a].sourceUrl;if(c="twitter.com"){if(f.note){if(f.note.length){d.note[0]=ident.addProperties(d.note[0],f.note[0],e,c)}}break}}for(var a=0;a<=ident.profiles.length-1;a++){var f=ident.profiles[a];var c=ident.profiles[a].domain;var e=ident.profiles[a].sourceUrl;if(c=="linkedin.com"){if(f.photo){if(f.photo.length){d.photo[0]=ident.addProperties(d.photo[0],f.photo[0],e,c)}}if(f.note){if(f.note.length){d.note[0]=ident.addProperties(d.note[0],f.note[0],e,c)}}break}}};ident.addProperties=function(b,e,d,a){if(b!=undefined||b!=null){if(b.value){if(e.length>b.value.length){b.value=e;b.sourceUrl=d;b.domain=a;return b}else{return b}}else{var c=new Object();c.value=e;c.sourceUrl=d;c.domain=a;return c}}else{var c=new Object();c.value=e;c.sourceUrl=d;c.domain=a;return c}};ident.addPropertiesToObject=function(b,e,d,a){if(e!=undefined){var c=e;c.sourceUrl=d;c.domain=a;return c}else{return null}};ident.sentenceTruncate=function(e,c){var a=e;if(e!=undefined){if(e!=null){if(e!=""){if(e.indexOf(".")>-1){a="";var d=e.split(". ");for(var b=0;b<=d.length-1;b++){if(b0){b=ident._explicitlyDeclaredProfileUrls[0]}for(var a=0;a<=ident._explicitlyDeclaredProfileUrls.length-1;a++){if(ident._explicitlyDeclaredProfileUrls[a].rank>b.rank){b=ident._explicitlyDeclaredProfileUrls[a]}}return b.url};ident.topFormattedName=function(){var b=new ident.formattedName();for(var a=0;a<=ident._formattedNames.length-1;a++){if(ident._formattedNames[a].rank>b.rank){b=ident._formattedNames[a]}}return b.name};ident.appendFormattedName=function(b){var c=false;if(b!=""){for(var a=0;a<=ident._formattedNames.length-1;a++){if(ident._formattedNames[a].name.toLowerCase()==b.toLowerCase()){ident._formattedNames[a].rank++;c=true;break}}if(c==false){var d=new ident.formattedName();d.name=b.replace(" "," ");ident._formattedNames[ident._formattedNames.length]=d}}};ident.containsMe=function(b){var c=false;if(b!=""){if(b.indexOf(" ")>-1){parts=b.split(" ");for(var a=0;a-1){parts=c.split("/");e=parts[parts.length-1]}var a="http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20twitter.user.profile%20where%20id%3D%27"+e+"%27&format=json&env=http%3A%2F%2Fdatatables.org%2Falltables.env";d.apiurl=a;ident.history[ident.history.length]=d;jQuery.getJSON(a+"&callback=?",function(f){ident.processEnchancedTwitterJson(f,d,c)})};ident.processEnchancedTwitterJson=function(json,historyItem,url){ident._apiReturnCount++;if(ident.isObject(json)){yql=json}else{yql=eval("("+json+")")}historyItem.rawJSON=yql;var sourceUrl="";var hcard=new ident.hCard();hcard.sourceUrl=url;hcard.domain="twitter.com";hcard.name="Twitter";if(yql!=null){if(yql.query!=null){if(yql.query.results!=null){if(yql.query.results.item!=null){if(yql.query.results.item.item!=null){if(yql.query.results.item.item.length!=null){for(var j=0;j<=yql.query.results.item.item.length-1;j++){if(yql.query.results.item.item[j].rel){if(yql.query.results.item.item[j].rel=="rel:Photo"){hcard.photo[0]=yql.query.results.item.item[j].resource}}}}}if(yql.query.results.item.meta!=null){if(yql.query.results.item.meta.length!=null){for(var j=0;j<=yql.query.results.item.meta.length-1;j++){if(yql.query.results.item.meta[j].property){if(yql.query.results.item.meta[j].property=="foaf:name"){hcard.fn=yql.query.results.item.meta[j].content}if(yql.query.results.item.meta[j].property=="foaf:nick"){hcard.nickname=yql.query.results.item.meta[j].content}if(yql.query.results.item.meta[j].property=="foaf:homepage"){hcard.url[0]=yql.query.results.item.meta[j].content}if(yql.query.results.item.meta[j].property=="dc:description"){if(yql.query.results.item.meta[j].content!=undefined){hcard.note[0]=yql.query.results.item.meta[j].content}}if(yql.query.results.item.meta[j].property=="geo:location"){var adr=new ident.adr();adr.locality=yql.query.results.item.meta[j].content;hcard.adr[0]=adr}}}}}}}}}ident.profiles[ident.profiles.length++]=hcard;ident.createCombinedhCard();ident.profileAddedEvent()}; -------------------------------------------------------------------------------- /js/ident/ident-ufxtract-parser-0.1.min.js: -------------------------------------------------------------------------------- 1 | ident.ufxtract={parserName:"ufxtract",parseUf:10,parseRss:0,parseAtom:0,findProfiles:function(){ident.ufxtract.findContent("twitter.com","Profile","hCard",true);for(var a=0;a0){for(var c=0;c0){for(var c=0;c0){for(var c=0;c1){h.tag[c].tag=parts[0]}ident.tags[ident.tags.length]=h.tag[c]}}ident.contentAddedEvent()}if(h.vcard){if(h.vcard.length>0){var g=ident.findRepresentativehCard(h.vcard,f);if(g!=null){g.sourceUrl=b;g.domain=f;g.name=a;if(g.url){for(var c=0;c0){for(var c=0;c0){var g=b.split("#");b=g[0]}var h=new ident.historyItem(b,"");h.apiName="yql";h.name=a;h.domain=f;h.schema=e;h.contentType=d;var c="microformats";if(e=="Rss"){c="rss"}if(e=="Atom"){c="atom"}query="select * from "+c+" where url='"+b+"'";apiurl="http://query.yahooapis.com/v1/public/yql?q="+encodeURIComponent(query)+"&format=json";h.apiurl=apiurl;if(f=="twitter.com"&&ident.getEnchancedTwitterProfile&&e=="hCard"){ident.getEnchancedTwitterProfile(b)}else{ident.history[ident.history.length]=h;jQuery.getJSON(apiurl+"&callback=?",function(i){ident.yql.processJson(i,f,a,d,h,c)})}},processJson:function(json,domain,name,type,historyItem,mediatype){ident._apiReturnCount++;if(ident.isObject(json)){yql=json}else{yql=eval("("+json+")")}historyItem.rawJSON=yql;if(mediatype=="rss"||mediatype=="atom"){if(yql.query){if(yql.query.results){if(yql.query.results.entry){if(yql.query.results.entry.length==null){singleEntry=yql.query.results.entry;yql.query.results.entry=new Array();yql.query.results.entry[0]=singleEntry}if(yql.query.results.entry.length){for(var x=0;x<=yql.query.results.entry.length-1;x++){hentry=ident.yql.parseAtomItem(yql.query.results.entry[x]);hentry.domain=domain;hentry.name=name;hentry.type=type;hentry.sourceUrl=historyItem.url;ident.postProcesshEntry(hentry);ident.entries[ident.entries.length]=hentry}ident.contentAddedEvent()}}if(yql.query.results.item){if(yql.query.results.item.length==null){singleItem=yql.query.results.item;yql.query.results.item=new Array();yql.query.results.item[0]=singleItem}if(yql.query.results.item.length){for(var x=0;x<=yql.query.results.item.length-1;x++){hentry=ident.yql.parseRssItem(yql.query.results.item[x]);hentry.domain=domain;hentry.name=name;hentry.type=type;hentry.sourceUrl=historyItem.url;ident.postProcesshEntry(hentry);ident.entries[ident.entries.length]=hentry}ident.contentAddedEvent()}}}}}if(mediatype=="microformats"){var UnStructuredhCards=null;var UnStructuredhResumes=null;var UnStructuredhEntry=null;var UnStructuredXFN=null;var ufCollection=new Array();var sourceUrl="";if(yql!=null){if(yql.query!=null){if(yql.query.results!=null){if(yql.query.results.result!=null){if(yql.query.results.result.url!=null){sourceUrl=yql.query.results.result.url}if(yql.query.results.result.feed!=null){if(yql.query.results.result.feed.adjunct!=null){if(yql.query.results.result.feed.adjunct.length!=null){for(var x=0;x<=yql.query.results.result.feed.adjunct.length-1;x++){var adjunct=yql.query.results.result.feed.adjunct[x];if(adjunct.id=="com.yahoo.page.uf.hcard"){UnStructuredhCards=adjunct}if(adjunct.id=="com.yahoo.page.uf.hresume"){UnStructuredhResumes=adjunct}if(adjunct.id=="com.yahoo.page.uf.hentry"){UnStructuredhEntry=adjunct}if(adjunct.id=="com.yahoo.page.uf.xfn"){UnStructuredXFN=adjunct}}}else{var adjunct=yql.query.results.result.feed.adjunct;if(adjunct.id=="com.yahoo.page.uf.hcard"){UnStructuredhCards=adjunct}if(adjunct.id=="com.yahoo.page.uf.hresume"){UnStructuredhResumes=adjunct}if(adjunct.id=="com.yahoo.page.uf.hentry"){UnStructuredhEntry=adjunct}if(adjunct.id=="com.yahoo.page.uf.xfn"){UnStructuredXFN=adjunct}}}}else{historyItem.error=true;historyItem.errorMessage="Not Found"}}}}}if(UnStructuredhCards!=null){hCards=ident.yql.parsehCards(UnStructuredhCards,domain,name,sourceUrl);ufCollection[ufCollection.length]={vcard:hCards};var hCard=null;if(hCards.length==1){hCard=hCards[0]}if(hCards.length>1){hCard=ident.findRepresentativehCard(hCards,domain)}if(hCard!=null){if(hCard.url){for(var i=0;i-1){c.type="work"}if(f.item[e].type.meta[m].content.indexOf(" : ")>0){var b=f.item[e].type.meta[m].content.split(" : ");c.value=b[1]}else{c.value=f.item[e].type.meta[m].content}h.tel[h.tel.length]=c}if(f.item[e].type.meta[m].property=="vcard:email"){var i=new ident.valueTypeProperty();i.domain=d;i.sourceUrl=g;i.valueOf=f.item[e].type.meta[m].content;h.email[h.email.length]=i}if(f.item[e].type.meta[m].property=="vcard:title"){if(f.item[e].type.meta[m].content!=undefined){h.title[h.title.length]=f.item[e].type.meta[m].content}}if(f.item[e].type.meta[m].property=="vcard:role"){if(f.item[e].type.meta[m].content!=undefined){h.title[h.title.length]=f.item[e].type.meta[m].content}}}}else{if(f.item[e].type.meta.property=="vcard:fn"){h.fn=f.item[e].type.meta.content}}}if(f.item[e].type.item!=null){if(ident.isArray(f.item[e].type.item)){for(var m=0;m<=f.item[e].type.item.length-1;m++){if(f.item[e].type.item[m].rel=="vcard:photo"){h.photo[h.photo.length]=f.item[e].type.item[m].resource}if(f.item[e].type.item[m].rel=="vcard:url"){h.url[h.url.length]=f.item[e].type.item[m].resource}if(f.item[e].type.item[m].rel=="vcard:org"){if(f.item[e].type.item[m].type!=null){if(f.item[e].type.item[m].type.meta!=null){if(f.item[e].type.item[m].type.meta.property=="vcard:organization-name"){var o=new ident.org();o["organization-name"]=f.item[e].type.item[m].type.meta.content;o.domain=d;o.sourceUrl=g;h.org[h.org.length]=o}}}}if(f.item[e].type.item[m].rel=="vcard:adr"){if(f.item[e].type.item[m].type!=null){if(f.item[e].type.item[m].type.meta!=null){var n=null;if(ident.isArray(f.item[e].type.item[m].type.meta)){h.adr[0]=new ident.adr();h.adr[0].domain=d;h.adr[0].sourceUrl=g;for(var k=0;k<=f.item[e].type.item[m].type.meta.length-1;k++){var n=f.item[e].type.item[m].type.meta[k];if(n.property=="vcard:extended-address"){h.adr[0]["extended-address"][0]=n.content}if(n.property=="vcard:street-address"){h.adr[0]["street-address"][0]=n.content}if(n.property=="vcard:locality"){h.adr[0].locality=n.content}if(n.property=="vcard:region"){h.adr[0].region=n.content}if(n.property=="vcard:postal-code"){h.adr[0]["postal-code"]=n.content}if(n.property=="vcard:country-name"){h.adr[0]["country-name"]=n.content}}}else{var n=f.item[e].type.item[m].type.meta;h.adr[0]=new ident.adr();if(n.property=="vcard:extended-address"){h.adr[0]["extended-address"][0]=n.content}if(n.property=="vcard:street-address"){h.adr[0]["street-address"][0]=n.content}if(n.property=="vcard:locality"){h.adr[0].locality=n.content}if(n.property=="vcard:region"){h.adr[0].region=n.content}if(n.property=="vcard:postal-code"){h.adr[0]["postal-code"]=n.content}if(n.property=="vcard:country-name"){h.adr[0]["country-name"]=n.content}}}}}}}else{if(f.item[e].type.item.rel=="vcard:url"){h.url[h.url.length++]=f.item[e].type.item.resource}}}}if(h.fn!=""){l[l.length]=h}}}}return l},parsehResumes:function(e,d,b,c){var a=new ident.hResume();a.domain=d;a.sourceUrl=c;if(e!=null){if(e.item!=null){if(e.item.type!=null){if(e.item.type.meta!=null){if(e.item.type.meta.property=="resume:summary"){if(e.item.type.meta.content!=undefined){a.summary=e.item.type.meta.content}}}}}}return a},parseXFN:function(e,d,b,c){for(var a=0;a<=e.item.length-1;a++){var f=new Object();f.domain=d;f.sourceUrl=c;f.name=b;if(e.item[a].rel=="xfn:me"){f.link=e.item[a].item.resource;ident.mes[ident.mes.length]=f;ident.xfn[ident.xfn.length]=f;ident.appendDeclaredProfileUrl(f.link);ident.appendDomainNode("",f.link,false,"");ident.appendAllProfileUrls(f.link)}}ident.postProcessDomainNode()},parseObjectsToString:function(a,b){if(ident.isObject(a)){for(prop in a){if(typeof a[prop]=="string"){if(prop=="content"){b+=a[prop]}}if(ident.isObject(a[prop])){b=ident.yql.parseObjectsToString(a[prop],b)}}}return b}};ident.registerParser(ident.yql); -------------------------------------------------------------------------------- /js/ident/web-address.min.js: -------------------------------------------------------------------------------- 1 | webAddress={timerId1:null,timerId2:null,animate:true,string1:"",string2:"",elt:null,prefix:"i.e.",personasUserNames:new Array(),accountMappings:new Array(),accountMapping:function(b,a){this.uritemplate=b;this.name=a},init:function(){this.personasUserNames[0]="johnsmith";this.personasUserNames[1]="janeblack";this.accountMappings[0]=new this.accountMapping("http://twitter.com/{username}","twitter");this.accountMappings[1]=new this.accountMapping("http://friendfeed.com/{username}","friendfeed");this.accountMappings[2]=new this.accountMapping("http://www.flickr.com/people/{username}/","flickr");this.accountMappings[3]=new this.accountMapping("http://huffduffer.com/{username}","huffduffer");this.accountMappings[4]=new this.accountMapping("http://digg.com/users/{username}","digg");this.accountMappings[5]=new this.accountMapping("http://www.linkedin.com/in/{username}","linkedin");this.accountMappings[6]=new this.accountMapping("{username}@gmail.com","gmail")},setWebAddress:function(){if(this.personasUserNames.length==0){this.init()}var a=Math.ceil(this.accountMappings.length*Math.random());var b=Math.ceil(this.personasUserNames.length*Math.random());var d=this.accountMappings[a-1];var c=this.personasUserNames[b-1];if(d.uritemplate.indexOf("@")>-1){this.string1=d.uritemplate.replace("{username}",c);this.string2=d.uritemplate.replace("{username}",c)}else{this.string1=d.uritemplate.replace("{username}",c);this.string2=d.name+" "+c}$(this.elt).css({opacity:0});$(this.elt).html(""+this.prefix+" "+this.string1+"").animate({opacity:1},250).animate({opacity:1},3250).animate({opacity:0},250)},setString2:function(){$(this.elt).html(""+this.prefix+" "+this.string2+"").animate({opacity:1},250).animate({opacity:1},3250).animate({opacity:0},250)},stopAnimate:function(){this.clear();animate=false},startAnimate:function(){animate=true;this.update()},update:function(){if(animate){this.clear();this.setWebAddress();this.timerId1=setTimeout("webAddress.setString2()",4000);this.timerId2=setTimeout("webAddress.update()",8000)}},clear:function(){clearTimeout(this.timerId1);clearTimeout(this.timerId2)}}; -------------------------------------------------------------------------------- /js/libs/jquery.autogrow.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | /* 3 | * Auto-growing textareas; technique ripped from Facebook 4 | */ 5 | $.fn.autogrow = function(options) { 6 | 7 | this.filter('textarea').each(function() { 8 | 9 | var $this = $(this), 10 | minHeight = $this.height(), 11 | lineHeight = $this.css('lineHeight'); 12 | 13 | var shadow = $('
      ').css({ 14 | position: 'absolute', 15 | top: -10000, 16 | left: -10000, 17 | width: $(this).width(), 18 | fontSize: $this.css('fontSize'), 19 | fontFamily: $this.css('fontFamily'), 20 | lineHeight: $this.css('lineHeight'), 21 | resize: 'none' 22 | }).appendTo(document.body); 23 | 24 | var update = function() { 25 | var val = this.value.replace(//g, '>') 27 | .replace(/&/g, '&') 28 | .replace(/\n/g, '
      '); 29 | 30 | shadow.html(val); 31 | $(this).attr('style', 'height: ' + Math.max(shadow.height() + 20, minHeight) + 'px !important'); 32 | } 33 | 34 | $(this).change(update).keyup(update).keydown(update); 35 | 36 | update.apply(this); 37 | 38 | }); 39 | 40 | return this; 41 | } 42 | })(jQuery); -------------------------------------------------------------------------------- /js/libs/jquery.hoverIntent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * hoverIntent r6 // 2011.02.26 // jQuery 1.5.1+ 3 | * 4 | * 5 | * @param f onMouseOver function || An object with configuration options 6 | * @param g onMouseOut function || Nothing (use configuration options object) 7 | * @author Brian Cherne brian(at)cherne(dot)net 8 | */ 9 | (function($){$.fn.hoverIntent=function(f,g){var cfg={sensitivity:7,interval:100,timeout:0};cfg=$.extend(cfg,g?{over:f,out:g}:f);var cX,cY,pX,pY;var track=function(ev){cX=ev.pageX;cY=ev.pageY};var compare=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);if((Math.abs(pX-cX)+Math.abs(pY-cY))': '>', 12 | '<': '<', 13 | '"': '"', 14 | "'": ''' 15 | }; 16 | 17 | // HTML escaping 18 | twttr.txt.htmlEscape = function(text) { 19 | return text && text.replace(/[&"'><]/g, function(character) { 20 | return HTML_ENTITIES[character]; 21 | }); 22 | }; 23 | 24 | // Builds a RegExp 25 | function regexSupplant(regex, flags) { 26 | flags = flags || ""; 27 | if (typeof regex !== "string") { 28 | if (regex.global && flags.indexOf("g") < 0) { 29 | flags += "g"; 30 | } 31 | if (regex.ignoreCase && flags.indexOf("i") < 0) { 32 | flags += "i"; 33 | } 34 | if (regex.multiline && flags.indexOf("m") < 0) { 35 | flags += "m"; 36 | } 37 | 38 | regex = regex.source; 39 | } 40 | 41 | return new RegExp(regex.replace(/#\{(\w+)\}/g, function(match, name) { 42 | var newRegex = twttr.txt.regexen[name] || ""; 43 | if (typeof newRegex !== "string") { 44 | newRegex = newRegex.source; 45 | } 46 | return newRegex; 47 | }), flags); 48 | } 49 | 50 | // simple string interpolation 51 | function stringSupplant(str, values) { 52 | return str.replace(/#\{(\w+)\}/g, function(match, name) { 53 | return values[name] || ""; 54 | }); 55 | } 56 | 57 | function addCharsToCharClass(charClass, start, end) { 58 | var s = String.fromCharCode(start); 59 | if (end !== start) { 60 | s += "-" + String.fromCharCode(end); 61 | } 62 | charClass.push(s); 63 | return charClass; 64 | } 65 | 66 | // Space is more than %20, U+3000 for example is the full-width space used with Kanji. Provide a short-hand 67 | // to access both the list of characters and a pattern suitible for use with String#split 68 | // Taken from: ActiveSupport::Multibyte::Handlers::UTF8Handler::UNICODE_WHITESPACE 69 | var fromCode = String.fromCharCode; 70 | var UNICODE_SPACES = [ 71 | fromCode(0x0020), // White_Space # Zs SPACE 72 | fromCode(0x0085), // White_Space # Cc 73 | fromCode(0x00A0), // White_Space # Zs NO-BREAK SPACE 74 | fromCode(0x1680), // White_Space # Zs OGHAM SPACE MARK 75 | fromCode(0x180E), // White_Space # Zs MONGOLIAN VOWEL SEPARATOR 76 | fromCode(0x2028), // White_Space # Zl LINE SEPARATOR 77 | fromCode(0x2029), // White_Space # Zp PARAGRAPH SEPARATOR 78 | fromCode(0x202F), // White_Space # Zs NARROW NO-BREAK SPACE 79 | fromCode(0x205F), // White_Space # Zs MEDIUM MATHEMATICAL SPACE 80 | fromCode(0x3000) // White_Space # Zs IDEOGRAPHIC SPACE 81 | ]; 82 | addCharsToCharClass(UNICODE_SPACES, 0x009, 0x00D); // White_Space # Cc [5] .. 83 | addCharsToCharClass(UNICODE_SPACES, 0x2000, 0x200A); // White_Space # Zs [11] EN QUAD..HAIR SPACE 84 | 85 | var INVALID_CHARS = [ 86 | fromCode(0xFFFE), 87 | fromCode(0xFEFF), // BOM 88 | fromCode(0xFFFF) // Special 89 | ]; 90 | addCharsToCharClass(INVALID_CHARS, 0x202A, 0x202E); // Directional change 91 | 92 | twttr.txt.regexen.spaces_group = regexSupplant(UNICODE_SPACES.join("")); 93 | twttr.txt.regexen.spaces = regexSupplant("[" + UNICODE_SPACES.join("") + "]"); 94 | twttr.txt.regexen.invalid_chars_group = regexSupplant(INVALID_CHARS.join("")); 95 | twttr.txt.regexen.punct = /\!'#%&'\(\)*\+,\\\-\.\/:;<=>\?@\[\]\^_{|}~/; 96 | twttr.txt.regexen.atSigns = /[@@]/; 97 | twttr.txt.regexen.extractMentions = regexSupplant(/(^|[^a-zA-Z0-9_])(#{atSigns})([a-zA-Z0-9_]{1,20})/g); 98 | twttr.txt.regexen.extractReply = regexSupplant(/^(?:#{spaces})*#{atSigns}([a-zA-Z0-9_]{1,20})/); 99 | twttr.txt.regexen.listName = /[a-zA-Z][a-zA-Z0-9_\-\u0080-\u00ff]{0,24}/; 100 | twttr.txt.regexen.extractMentionsOrLists = regexSupplant(/(^|[^a-zA-Z0-9_])(#{atSigns})([a-zA-Z0-9_]{1,20})(\/[a-zA-Z][a-zA-Z0-9_\-]{0,24})?/g); 101 | 102 | var nonLatinHashtagChars = []; 103 | // Cyrillic 104 | addCharsToCharClass(nonLatinHashtagChars, 0x0400, 0x04ff); // Cyrillic 105 | addCharsToCharClass(nonLatinHashtagChars, 0x0500, 0x0527); // Cyrillic Supplement 106 | addCharsToCharClass(nonLatinHashtagChars, 0x2de0, 0x2dff); // Cyrillic Extended A 107 | addCharsToCharClass(nonLatinHashtagChars, 0xa640, 0xa69f); // Cyrillic Extended B 108 | // Hangul (Korean) 109 | addCharsToCharClass(nonLatinHashtagChars, 0x1100, 0x11ff); // Hangul Jamo 110 | addCharsToCharClass(nonLatinHashtagChars, 0x3130, 0x3185); // Hangul Compatibility Jamo 111 | addCharsToCharClass(nonLatinHashtagChars, 0xA960, 0xA97F); // Hangul Jamo Extended-A 112 | addCharsToCharClass(nonLatinHashtagChars, 0xAC00, 0xD7AF); // Hangul Syllables 113 | addCharsToCharClass(nonLatinHashtagChars, 0xD7B0, 0xD7FF); // Hangul Jamo Extended-B 114 | addCharsToCharClass(nonLatinHashtagChars, 0xFFA1, 0xFFDC); // half-width Hangul 115 | // Japanese and Chinese 116 | addCharsToCharClass(nonLatinHashtagChars, 0x30A1, 0x30FA); // Katakana (full-width) 117 | addCharsToCharClass(nonLatinHashtagChars, 0x30FC, 0x30FE); // Katakana Chouon and iteration marks (full-width) 118 | addCharsToCharClass(nonLatinHashtagChars, 0xFF66, 0xFF9F); // Katakana (half-width) 119 | addCharsToCharClass(nonLatinHashtagChars, 0xFF70, 0xFF70); // Katakana Chouon (half-width) 120 | addCharsToCharClass(nonLatinHashtagChars, 0xFF10, 0xFF19); // \ 121 | addCharsToCharClass(nonLatinHashtagChars, 0xFF21, 0xFF3A); // - Latin (full-width) 122 | addCharsToCharClass(nonLatinHashtagChars, 0xFF41, 0xFF5A); // / 123 | addCharsToCharClass(nonLatinHashtagChars, 0x3041, 0x3096); // Hiragana 124 | addCharsToCharClass(nonLatinHashtagChars, 0x3099, 0x309E); // Hiragana voicing and iteration mark 125 | addCharsToCharClass(nonLatinHashtagChars, 0x3400, 0x4DBF); // Kanji (CJK Extension A) 126 | addCharsToCharClass(nonLatinHashtagChars, 0x4E00, 0x9FFF); // Kanji (Unified) 127 | // -- Disabled as it breaks the Regex. 128 | //addCharsToCharClass(nonLatinHashtagChars, 0x20000, 0x2A6DF); // Kanji (CJK Extension B) 129 | addCharsToCharClass(nonLatinHashtagChars, 0x2A700, 0x2B73F); // Kanji (CJK Extension C) 130 | addCharsToCharClass(nonLatinHashtagChars, 0x2B740, 0x2B81F); // Kanji (CJK Extension D) 131 | addCharsToCharClass(nonLatinHashtagChars, 0x2F800, 0x2FA1F); // Kanji (CJK supplement) 132 | addCharsToCharClass(nonLatinHashtagChars, 0x3005, 0x3005); // Kanji iteration mark 133 | addCharsToCharClass(nonLatinHashtagChars, 0x303B, 0x303B); // Han iteration mark 134 | 135 | twttr.txt.regexen.nonLatinHashtagChars = regexSupplant(nonLatinHashtagChars.join("")); 136 | // Latin accented characters (subtracted 0xD7 from the range, it's a confusable multiplication sign. Looks like "x") 137 | twttr.txt.regexen.latinAccentChars = regexSupplant("ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþş\\303\\277"); 138 | 139 | twttr.txt.regexen.endScreenNameMatch = regexSupplant(/^(?:#{atSigns}|[#{latinAccentChars}]|:\/\/)/); 140 | 141 | // A hashtag must contain characters, numbers and underscores, but not all numbers. 142 | twttr.txt.regexen.hashtagAlpha = regexSupplant(/[a-z_#{latinAccentChars}#{nonLatinHashtagChars}]/i); 143 | twttr.txt.regexen.hashtagAlphaNumeric = regexSupplant(/[a-z0-9_#{latinAccentChars}#{nonLatinHashtagChars}]/i); 144 | twttr.txt.regexen.endHashtagMatch = /^(?:[##]|:\/\/)/; 145 | twttr.txt.regexen.hashtagBoundary = regexSupplant(/(?:^|$|[^&\/a-z0-9_#{latinAccentChars}#{nonLatinHashtagChars}])/); 146 | twttr.txt.regexen.autoLinkHashtags = regexSupplant(/(#{hashtagBoundary})(#|#)(#{hashtagAlphaNumeric}*#{hashtagAlpha}#{hashtagAlphaNumeric}*)/gi); 147 | twttr.txt.regexen.autoLinkUsernamesOrLists = /(^|[^a-zA-Z0-9_]|RT:?)([@@]+)([a-zA-Z0-9_]{1,20})(\/[a-zA-Z][a-zA-Z0-9_\-]{0,24})?/g; 148 | twttr.txt.regexen.autoLinkEmoticon = /(8\-\#|8\-E|\+\-\(|\`\@|\`O|\<\|:~\(|\}:o\{|:\-\[|\>o\<|X\-\/|\[:-\]\-I\-|\/\/\/\/Ö\\\\\\\\|\(\|:\|\/\)|∑:\*\)|\( \| \))/g; 149 | 150 | // URL related hash regex collection 151 | twttr.txt.regexen.validPrecedingChars = regexSupplant(/(?:[^-\/"'!=A-Za-z0-9_@@##\.#{invalid_chars_group}]|^)/); 152 | 153 | twttr.txt.regexen.invalidDomainChars = stringSupplant("#{punct}#{spaces_group}#{invalid_chars_group}", twttr.txt.regexen); 154 | twttr.txt.regexen.validDomainChars = regexSupplant(/[^#{invalidDomainChars}]/); 155 | twttr.txt.regexen.validSubdomain = regexSupplant(/(?:(?:#{validDomainChars}(?:[_-]|#{validDomainChars})*)?#{validDomainChars}\.)/); 156 | twttr.txt.regexen.validDomainName = regexSupplant(/(?:(?:#{validDomainChars}(?:-|#{validDomainChars})*)?#{validDomainChars}\.)/); 157 | twttr.txt.regexen.validGTLD = regexSupplant(/(?:(?:aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel)(?=[^a-zA-Z]|$))/); 158 | twttr.txt.regexen.validCCTLD = regexSupplant(/(?:(?:ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|ss|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw)(?=[^a-zA-Z]|$))/); 159 | twttr.txt.regexen.validPunycode = regexSupplant(/(?:xn--[0-9a-z]+)/); 160 | twttr.txt.regexen.validDomain = regexSupplant(/(?:#{validSubdomain}*#{validDomainName}(?:#{validGTLD}|#{validCCTLD}|#{validPunycode}))/); 161 | twttr.txt.regexen.validAsciiDomain = regexSupplant(/(?:(?:[a-z0-9#{latinAccentChars}]+)\.)+(?:#{validGTLD}|#{validCCTLD}|#{validPunycode})/gi); 162 | twttr.txt.regexen.invalidShortDomain = regexSupplant(/^#{validDomainName}#{validCCTLD}$/); 163 | 164 | twttr.txt.regexen.validPortNumber = regexSupplant(/[0-9]+/); 165 | 166 | twttr.txt.regexen.validGeneralUrlPathChars = regexSupplant(/[a-z0-9!\*';:=\+,\.\$\/%#\[\]\-_~|&#{latinAccentChars}]/i); 167 | // Allow URL paths to contain balanced parens 168 | // 1. Used in Wikipedia URLs like /Primer_(film) 169 | // 2. Used in IIS sessions like /S(dfd346)/ 170 | twttr.txt.regexen.validUrlBalancedParens = regexSupplant(/\(#{validGeneralUrlPathChars}+\)/i); 171 | // Valid end-of-path chracters (so /foo. does not gobble the period). 172 | // 1. Allow =&# for empty URL parameters and other URL-join artifacts 173 | twttr.txt.regexen.validUrlPathEndingChars = regexSupplant(/[\+\-a-z0-9=_#\/#{latinAccentChars}]|(?:#{validUrlBalancedParens})/i); 174 | // Allow @ in a url, but only in the middle. Catch things like http://example.com/@user/ 175 | twttr.txt.regexen.validUrlPath = regexSupplant('(?:' + 176 | '(?:' + 177 | '#{validGeneralUrlPathChars}*' + 178 | '(?:#{validUrlBalancedParens}#{validGeneralUrlPathChars}*)*' + 179 | '#{validUrlPathEndingChars}'+ 180 | ')|(?:@#{validGeneralUrlPathChars}+\/)'+ 181 | ')', 'i'); 182 | 183 | twttr.txt.regexen.validUrlQueryChars = /[a-z0-9!?\*'\(\);:&=\+\$\/%#\[\]\-_\.,~|]/i; 184 | twttr.txt.regexen.validUrlQueryEndingChars = /[a-z0-9_&=#\/]/i; 185 | twttr.txt.regexen.extractUrl = regexSupplant( 186 | '(' + // $1 total match 187 | '(#{validPrecedingChars})' + // $2 Preceeding chracter 188 | '(' + // $3 URL 189 | '(https?:\\/\\/)?' + // $4 Protocol (optional) 190 | '(#{validDomain})' + // $5 Domain(s) 191 | '(?::(#{validPortNumber}))?' + // $6 Port number (optional) 192 | '(\\/#{validUrlPath}*)?' + // $7 URL Path 193 | '(\\?#{validUrlQueryChars}*#{validUrlQueryEndingChars})?' + // $8 Query String 194 | ')' + 195 | ')' 196 | , 'gi'); 197 | 198 | // These URL validation pattern strings are based on the ABNF from RFC 3986 199 | twttr.txt.regexen.validateUrlUnreserved = /[a-z0-9\-._~]/i; 200 | twttr.txt.regexen.validateUrlPctEncoded = /(?:%[0-9a-f]{2})/i; 201 | twttr.txt.regexen.validateUrlSubDelims = /[!$&'()*+,;=]/i; 202 | twttr.txt.regexen.validateUrlPchar = regexSupplant('(?:' + 203 | '#{validateUrlUnreserved}|' + 204 | '#{validateUrlPctEncoded}|' + 205 | '#{validateUrlSubDelims}|' + 206 | '[:|@]' + 207 | ')', 'i'); 208 | 209 | twttr.txt.regexen.validateUrlScheme = /(?:[a-z][a-z0-9+\-.]*)/i; 210 | twttr.txt.regexen.validateUrlUserinfo = regexSupplant('(?:' + 211 | '#{validateUrlUnreserved}|' + 212 | '#{validateUrlPctEncoded}|' + 213 | '#{validateUrlSubDelims}|' + 214 | ':' + 215 | ')*', 'i'); 216 | 217 | twttr.txt.regexen.validateUrlDecOctet = /(?:[0-9]|(?:[1-9][0-9])|(?:1[0-9]{2})|(?:2[0-4][0-9])|(?:25[0-5]))/i; 218 | twttr.txt.regexen.validateUrlIpv4 = regexSupplant(/(?:#{validateUrlDecOctet}(?:\.#{validateUrlDecOctet}){3})/i); 219 | 220 | // Punting on real IPv6 validation for now 221 | twttr.txt.regexen.validateUrlIpv6 = /(?:\[[a-f0-9:\.]+\])/i; 222 | 223 | // Also punting on IPvFuture for now 224 | twttr.txt.regexen.validateUrlIp = regexSupplant('(?:' + 225 | '#{validateUrlIpv4}|' + 226 | '#{validateUrlIpv6}' + 227 | ')', 'i'); 228 | 229 | // This is more strict than the rfc specifies 230 | twttr.txt.regexen.validateUrlSubDomainSegment = /(?:[a-z0-9](?:[a-z0-9_\-]*[a-z0-9])?)/i; 231 | twttr.txt.regexen.validateUrlDomainSegment = /(?:[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?)/i; 232 | twttr.txt.regexen.validateUrlDomainTld = /(?:[a-z](?:[a-z0-9\-]*[a-z0-9])?)/i; 233 | twttr.txt.regexen.validateUrlDomain = regexSupplant(/(?:(?:#{validateUrlSubDomainSegment]}\.)*(?:#{validateUrlDomainSegment]}\.)#{validateUrlDomainTld})/i); 234 | 235 | twttr.txt.regexen.validateUrlHost = regexSupplant('(?:' + 236 | '#{validateUrlIp}|' + 237 | '#{validateUrlDomain}' + 238 | ')', 'i'); 239 | 240 | // Unencoded internationalized domains - this doesn't check for invalid UTF-8 sequences 241 | twttr.txt.regexen.validateUrlUnicodeSubDomainSegment = /(?:(?:[a-z0-9]|[^\u0000-\u007f])(?:(?:[a-z0-9_\-]|[^\u0000-\u007f])*(?:[a-z0-9]|[^\u0000-\u007f]))?)/i; 242 | twttr.txt.regexen.validateUrlUnicodeDomainSegment = /(?:(?:[a-z0-9]|[^\u0000-\u007f])(?:(?:[a-z0-9\-]|[^\u0000-\u007f])*(?:[a-z0-9]|[^\u0000-\u007f]))?)/i; 243 | twttr.txt.regexen.validateUrlUnicodeDomainTld = /(?:(?:[a-z]|[^\u0000-\u007f])(?:(?:[a-z0-9\-]|[^\u0000-\u007f])*(?:[a-z0-9]|[^\u0000-\u007f]))?)/i; 244 | twttr.txt.regexen.validateUrlUnicodeDomain = regexSupplant(/(?:(?:#{validateUrlUnicodeSubDomainSegment}\.)*(?:#{validateUrlUnicodeDomainSegment}\.)#{validateUrlUnicodeDomainTld})/i); 245 | 246 | twttr.txt.regexen.validateUrlUnicodeHost = regexSupplant('(?:' + 247 | '#{validateUrlIp}|' + 248 | '#{validateUrlUnicodeDomain}' + 249 | ')', 'i'); 250 | 251 | twttr.txt.regexen.validateUrlPort = /[0-9]{1,5}/; 252 | 253 | twttr.txt.regexen.validateUrlUnicodeAuthority = regexSupplant( 254 | '(?:(#{validateUrlUserinfo})@)?' + // $1 userinfo 255 | '(#{validateUrlUnicodeHost})' + // $2 host 256 | '(?::(#{validateUrlPort}))?' //$3 port 257 | , "i"); 258 | 259 | twttr.txt.regexen.validateUrlAuthority = regexSupplant( 260 | '(?:(#{validateUrlUserinfo})@)?' + // $1 userinfo 261 | '(#{validateUrlHost})' + // $2 host 262 | '(?::(#{validateUrlPort}))?' // $3 port 263 | , "i"); 264 | 265 | twttr.txt.regexen.validateUrlPath = regexSupplant(/(\/#{validateUrlPchar}*)*/i); 266 | twttr.txt.regexen.validateUrlQuery = regexSupplant(/(#{validateUrlPchar}|\/|\?)*/i); 267 | twttr.txt.regexen.validateUrlFragment = regexSupplant(/(#{validateUrlPchar}|\/|\?)*/i); 268 | 269 | // Modified version of RFC 3986 Appendix B 270 | twttr.txt.regexen.validateUrlUnencoded = regexSupplant( 271 | '^' + // Full URL 272 | '(?:' + 273 | '([^:/?#]+):\\/\\/' + // $1 Scheme 274 | ')?' + 275 | '([^/?#]*)' + // $2 Authority 276 | '([^?#]*)' + // $3 Path 277 | '(?:' + 278 | '\\?([^#]*)' + // $4 Query 279 | ')?' + 280 | '(?:' + 281 | '#(.*)' + // $5 Fragment 282 | ')?$' 283 | , "i"); 284 | 285 | 286 | // Default CSS class for auto-linked URLs 287 | var DEFAULT_URL_CLASS = "tweet-url"; 288 | // Default CSS class for auto-linked lists (along with the url class) 289 | var DEFAULT_LIST_CLASS = "list-slug"; 290 | // Default CSS class for auto-linked usernames (along with the url class) 291 | var DEFAULT_USERNAME_CLASS = "username"; 292 | // Default CSS class for auto-linked hashtags (along with the url class) 293 | var DEFAULT_HASHTAG_CLASS = "hashtag"; 294 | // HTML attribute for robot nofollow behavior (default) 295 | var HTML_ATTR_NO_FOLLOW = " rel=\"nofollow\""; 296 | 297 | // Simple object cloning function for simple objects 298 | function clone(o) { 299 | var r = {}; 300 | for (var k in o) { 301 | if (o.hasOwnProperty(k)) { 302 | r[k] = o[k]; 303 | } 304 | } 305 | 306 | return r; 307 | } 308 | 309 | twttr.txt.autoLink = function(text, options) { 310 | options = clone(options || {}); 311 | return twttr.txt.autoLinkUsernamesOrLists( 312 | twttr.txt.autoLinkUrlsCustom( 313 | twttr.txt.autoLinkHashtags(text, options), 314 | options), 315 | options); 316 | }; 317 | 318 | 319 | twttr.txt.autoLinkUsernamesOrLists = function(text, options) { 320 | options = clone(options || {}); 321 | 322 | options.urlClass = options.urlClass || DEFAULT_URL_CLASS; 323 | options.listClass = options.listClass || DEFAULT_LIST_CLASS; 324 | options.usernameClass = options.usernameClass || DEFAULT_USERNAME_CLASS; 325 | options.usernameUrlBase = options.usernameUrlBase || "http://twitter.com/"; 326 | options.listUrlBase = options.listUrlBase || "http://twitter.com/"; 327 | if (!options.suppressNoFollow) { 328 | var extraHtml = HTML_ATTR_NO_FOLLOW; 329 | } 330 | 331 | var newText = "", 332 | splitText = twttr.txt.splitTags(text); 333 | 334 | for (var index = 0; index < splitText.length; index++) { 335 | var chunk = splitText[index]; 336 | 337 | if (index !== 0) { 338 | newText += ((index % 2 === 0) ? ">" : "<"); 339 | } 340 | 341 | if (index % 4 !== 0) { 342 | newText += chunk; 343 | } else { 344 | newText += chunk.replace(twttr.txt.regexen.autoLinkUsernamesOrLists, function(match, before, at, user, slashListname, offset, chunk) { 345 | var after = chunk.slice(offset + match.length); 346 | 347 | var d = { 348 | before: before, 349 | at: at, 350 | user: twttr.txt.htmlEscape(user), 351 | slashListname: twttr.txt.htmlEscape(slashListname), 352 | extraHtml: extraHtml, 353 | preChunk: "", 354 | chunk: twttr.txt.htmlEscape(chunk), 355 | postChunk: "" 356 | }; 357 | for (var k in options) { 358 | if (options.hasOwnProperty(k)) { 359 | d[k] = options[k]; 360 | } 361 | } 362 | 363 | if (slashListname && !options.suppressLists) { 364 | // the link is a list 365 | var list = d.chunk = stringSupplant("#{user}#{slashListname}", d); 366 | d.list = twttr.txt.htmlEscape(list.toLowerCase()); 367 | return stringSupplant("#{before}#{at}#{preChunk}#{chunk}#{postChunk}", d); 368 | } else { 369 | if (after && after.match(twttr.txt.regexen.endScreenNameMatch)) { 370 | // Followed by something that means we don't autolink 371 | return match; 372 | } else { 373 | // this is a screen name 374 | d.chunk = twttr.txt.htmlEscape(user); 375 | d.dataScreenName = !options.suppressDataScreenName ? stringSupplant("data-screen-name=\"#{chunk}\" ", d) : ""; 376 | return stringSupplant("#{before}#{at}#{preChunk}#{chunk}#{postChunk}", d); 377 | } 378 | } 379 | }); 380 | } 381 | } 382 | 383 | return newText; 384 | }; 385 | 386 | twttr.txt.autoLinkHashtags = function(text, options) { 387 | options = clone(options || {}); 388 | options.urlClass = options.urlClass || DEFAULT_URL_CLASS; 389 | options.hashtagClass = options.hashtagClass || DEFAULT_HASHTAG_CLASS; 390 | options.hashtagUrlBase = options.hashtagUrlBase || "http://twitter.com/search?q=%23"; 391 | if (!options.suppressNoFollow) { 392 | var extraHtml = HTML_ATTR_NO_FOLLOW; 393 | } 394 | 395 | return text.replace(twttr.txt.regexen.autoLinkHashtags, function(match, before, hash, text, offset, chunk) { 396 | var after = chunk.slice(offset + match.length); 397 | if (after.match(twttr.txt.regexen.endHashtagMatch)) 398 | return match; 399 | 400 | var d = { 401 | before: before, 402 | hash: twttr.txt.htmlEscape(hash), 403 | preText: "", 404 | text: twttr.txt.htmlEscape(text), 405 | postText: "", 406 | extraHtml: extraHtml 407 | }; 408 | 409 | for (var k in options) { 410 | if (options.hasOwnProperty(k)) { 411 | d[k] = options[k]; 412 | } 413 | } 414 | 415 | return stringSupplant("#{before}#{hash}#{preText}#{text}#{postText}", d); 416 | }); 417 | }; 418 | 419 | 420 | twttr.txt.autoLinkUrlsCustom = function(text, options) { 421 | options = clone(options || {}); 422 | if (!options.suppressNoFollow) { 423 | options.rel = "nofollow"; 424 | } 425 | if (options.urlClass) { 426 | options["class"] = options.urlClass; 427 | delete options.urlClass; 428 | } 429 | 430 | // remap url entities to hash 431 | var urlEntities, i, len; 432 | if(options.urlEntities) { 433 | urlEntities = {}; 434 | for(i = 0, len = options.urlEntities.length; i < len; i++) { 435 | urlEntities[options.urlEntities[i].url] = options.urlEntities[i]; 436 | } 437 | } 438 | 439 | delete options.suppressNoFollow; 440 | delete options.suppressDataScreenName; 441 | delete options.listClass; 442 | delete options.usernameClass; 443 | delete options.usernameUrlBase; 444 | delete options.listUrlBase; 445 | 446 | return text.replace(twttr.txt.regexen.extractUrl, function(match, all, before, url, protocol, port, domain, path, queryString) { 447 | var tldComponents; 448 | 449 | if (protocol) { 450 | var htmlAttrs = ""; 451 | for (var k in options) { 452 | htmlAttrs += stringSupplant(" #{k}=\"#{v}\" ", {k: k, v: options[k].toString().replace(/"/, """).replace(//, ">")}); 453 | } 454 | 455 | var d = { 456 | before: before, 457 | htmlAttrs: htmlAttrs, 458 | url: twttr.txt.htmlEscape(url) 459 | }; 460 | if (urlEntities && urlEntities[url] && urlEntities[url].display_url) { 461 | d.displayUrl = twttr.txt.htmlEscape(urlEntities[url].display_url); 462 | } else { 463 | d.displayUrl = d.url; 464 | } 465 | 466 | return stringSupplant("#{before}#{displayUrl}", d); 467 | } else { 468 | return all; 469 | } 470 | }); 471 | }; 472 | 473 | twttr.txt.extractMentions = function(text) { 474 | var screenNamesOnly = [], 475 | screenNamesWithIndices = twttr.txt.extractMentionsWithIndices(text); 476 | 477 | for (var i = 0; i < screenNamesWithIndices.length; i++) { 478 | var screenName = screenNamesWithIndices[i].screenName; 479 | screenNamesOnly.push(screenName); 480 | } 481 | 482 | return screenNamesOnly; 483 | }; 484 | 485 | twttr.txt.extractMentionsWithIndices = function(text) { 486 | if (!text) { 487 | return []; 488 | } 489 | 490 | var possibleScreenNames = [], 491 | position = 0; 492 | 493 | text.replace(twttr.txt.regexen.extractMentions, function(match, before, atSign, screenName, offset, chunk) { 494 | var after = chunk.slice(offset + match.length); 495 | if (!after.match(twttr.txt.regexen.endScreenNameMatch)) { 496 | var startPosition = text.indexOf(atSign + screenName, position); 497 | position = startPosition + screenName.length + 1; 498 | possibleScreenNames.push({ 499 | screenName: screenName, 500 | indices: [startPosition, position] 501 | }); 502 | } 503 | }); 504 | 505 | return possibleScreenNames; 506 | }; 507 | 508 | /** 509 | * Extract list or user mentions. 510 | * (Presence of listSlug indicates a list) 511 | */ 512 | twttr.txt.extractMentionsOrListsWithIndices = function(text) { 513 | if (!text) { 514 | return []; 515 | } 516 | 517 | var possibleNames = [], 518 | position = 0; 519 | 520 | text.replace(twttr.txt.regexen.extractMentionsOrLists, function(match, before, atSign, screenName, slashListname, offset, chunk) { 521 | var after = chunk.slice(offset + match.length); 522 | if (!after.match(twttr.txt.regexen.endScreenNameMatch)) { 523 | slashListname = slashListname || ''; 524 | var startPosition = text.indexOf(atSign + screenName + slashListname, position); 525 | position = startPosition + screenName.length + slashListname.length + 1; 526 | possibleNames.push({ 527 | screenName: screenName, 528 | listSlug: slashListname, 529 | indices: [startPosition, position] 530 | }); 531 | } 532 | }); 533 | 534 | return possibleNames; 535 | }; 536 | 537 | 538 | twttr.txt.extractReplies = function(text) { 539 | if (!text) { 540 | return null; 541 | } 542 | 543 | var possibleScreenName = text.match(twttr.txt.regexen.extractReply); 544 | if (!possibleScreenName || 545 | RegExp.rightContext.match(twttr.txt.regexen.endScreenNameMatch)) { 546 | return null; 547 | } 548 | 549 | return possibleScreenName[1]; 550 | }; 551 | 552 | twttr.txt.extractUrls = function(text) { 553 | var urlsOnly = [], 554 | urlsWithIndices = twttr.txt.extractUrlsWithIndices(text); 555 | 556 | for (var i = 0; i < urlsWithIndices.length; i++) { 557 | urlsOnly.push(urlsWithIndices[i].url); 558 | } 559 | 560 | return urlsOnly; 561 | }; 562 | 563 | twttr.txt.extractUrlsWithIndices = function(text) { 564 | if (!text) { 565 | return []; 566 | } 567 | 568 | var urls = [], 569 | position = 0; 570 | 571 | text.replace(twttr.txt.regexen.extractUrl, function(match, all, before, url, protocol, domain, port, path, query) { 572 | var startPosition = text.indexOf(url, position), 573 | endPosition = startPosition + url.length; 574 | 575 | // if protocol is missing and domain contains non-ASCII characters, 576 | // extract ASCII-only domains. 577 | if (!protocol) { 578 | var lastUrl = null, 579 | lastUrlInvalidMatch = false, 580 | asciiEndPosition = 0; 581 | domain.replace(twttr.txt.regexen.validAsciiDomain, function(asciiDomain) { 582 | var asciiStartPosition = domain.indexOf(asciiDomain, asciiEndPosition); 583 | asciiEndPosition = asciiStartPosition + asciiDomain.length 584 | lastUrl = { 585 | url: asciiDomain, 586 | indices: [startPosition + asciiStartPosition, startPosition + asciiEndPosition] 587 | } 588 | lastUrlInvalidMatch = asciiDomain.match(twttr.txt.regexen.invalidShortDomain); 589 | if (!lastUrlInvalidMatch) { 590 | urls.push(lastUrl); 591 | } 592 | }); 593 | 594 | // no ASCII-only domain found. Skip the entire URL. 595 | if (lastUrl == null) { 596 | return; 597 | } 598 | 599 | // lastUrl only contains domain. Need to add path and query if they exist. 600 | if (path) { 601 | if (lastUrlInvalidMatch) { 602 | urls.push(lastUrl); 603 | } 604 | lastUrl.url = url.replace(domain, lastUrl.url); 605 | lastUrl.indices[1] = endPosition; 606 | } 607 | } else { 608 | urls.push({ 609 | url: url, 610 | indices: [startPosition, endPosition] 611 | }); 612 | } 613 | }); 614 | 615 | return urls; 616 | }; 617 | 618 | twttr.txt.extractHashtags = function(text) { 619 | var hashtagsOnly = [], 620 | hashtagsWithIndices = twttr.txt.extractHashtagsWithIndices(text); 621 | 622 | for (var i = 0; i < hashtagsWithIndices.length; i++) { 623 | hashtagsOnly.push(hashtagsWithIndices[i].hashtag); 624 | } 625 | 626 | return hashtagsOnly; 627 | }; 628 | 629 | twttr.txt.extractHashtagsWithIndices = function(text) { 630 | if (!text) { 631 | return []; 632 | } 633 | 634 | var tags = [], 635 | position = 0; 636 | 637 | text.replace(twttr.txt.regexen.autoLinkHashtags, function(match, before, hash, hashText, offset, chunk) { 638 | var after = chunk.slice(offset + match.length); 639 | if (after.match(twttr.txt.regexen.endHashtagMatch)) 640 | return; 641 | var startPosition = text.indexOf(hash + hashText, position); 642 | position = startPosition + hashText.length + 1; 643 | tags.push({ 644 | hashtag: hashText, 645 | indices: [startPosition, position] 646 | }); 647 | }); 648 | 649 | return tags; 650 | }; 651 | 652 | // this essentially does text.split(/<|>/) 653 | // except that won't work in IE, where empty strings are ommitted 654 | // so "<>".split(/<|>/) => [] in IE, but is ["", "", ""] in all others 655 | // but "<<".split("<") => ["", "", ""] 656 | twttr.txt.splitTags = function(text) { 657 | var firstSplits = text.split("<"), 658 | secondSplits, 659 | allSplits = [], 660 | split; 661 | 662 | for (var i = 0; i < firstSplits.length; i += 1) { 663 | split = firstSplits[i]; 664 | if (!split) { 665 | allSplits.push(""); 666 | } else { 667 | secondSplits = split.split(">"); 668 | for (var j = 0; j < secondSplits.length; j += 1) { 669 | allSplits.push(secondSplits[j]); 670 | } 671 | } 672 | } 673 | 674 | return allSplits; 675 | }; 676 | 677 | twttr.txt.hitHighlight = function(text, hits, options) { 678 | var defaultHighlightTag = "em"; 679 | 680 | hits = hits || []; 681 | options = options || {}; 682 | 683 | if (hits.length === 0) { 684 | return text; 685 | } 686 | 687 | var tagName = options.tag || defaultHighlightTag, 688 | tags = ["<" + tagName + ">", ""], 689 | chunks = twttr.txt.splitTags(text), 690 | split, 691 | i, 692 | j, 693 | result = "", 694 | chunkIndex = 0, 695 | chunk = chunks[0], 696 | prevChunksLen = 0, 697 | chunkCursor = 0, 698 | startInChunk = false, 699 | chunkChars = chunk, 700 | flatHits = [], 701 | index, 702 | hit, 703 | tag, 704 | placed, 705 | hitSpot; 706 | 707 | for (i = 0; i < hits.length; i += 1) { 708 | for (j = 0; j < hits[i].length; j += 1) { 709 | flatHits.push(hits[i][j]); 710 | } 711 | } 712 | 713 | for (index = 0; index < flatHits.length; index += 1) { 714 | hit = flatHits[index]; 715 | tag = tags[index % 2]; 716 | placed = false; 717 | 718 | while (chunk != null && hit >= prevChunksLen + chunk.length) { 719 | result += chunkChars.slice(chunkCursor); 720 | if (startInChunk && hit === prevChunksLen + chunkChars.length) { 721 | result += tag; 722 | placed = true; 723 | } 724 | 725 | if (chunks[chunkIndex + 1]) { 726 | result += "<" + chunks[chunkIndex + 1] + ">"; 727 | } 728 | 729 | prevChunksLen += chunkChars.length; 730 | chunkCursor = 0; 731 | chunkIndex += 2; 732 | chunk = chunks[chunkIndex]; 733 | chunkChars = chunk; 734 | startInChunk = false; 735 | } 736 | 737 | if (!placed && chunk != null) { 738 | hitSpot = hit - prevChunksLen; 739 | result += chunkChars.slice(chunkCursor, hitSpot) + tag; 740 | chunkCursor = hitSpot; 741 | if (index % 2 === 0) { 742 | startInChunk = true; 743 | } else { 744 | startInChunk = false; 745 | } 746 | } else if(!placed) { 747 | placed = true; 748 | result += tag; 749 | } 750 | } 751 | 752 | if (chunk != null) { 753 | if (chunkCursor < chunkChars.length) { 754 | result += chunkChars.slice(chunkCursor); 755 | } 756 | for (index = chunkIndex + 1; index < chunks.length; index += 1) { 757 | result += (index % 2 === 0 ? chunks[index] : "<" + chunks[index] + ">"); 758 | } 759 | } 760 | 761 | return result; 762 | }; 763 | 764 | var MAX_LENGTH = 140; 765 | 766 | // Characters not allowed in Tweets 767 | var INVALID_CHARACTERS = [ 768 | // BOM 769 | fromCode(0xFFFE), 770 | fromCode(0xFEFF), 771 | 772 | // Special 773 | fromCode(0xFFFF), 774 | 775 | // Directional Change 776 | fromCode(0x202A), 777 | fromCode(0x202B), 778 | fromCode(0x202C), 779 | fromCode(0x202D), 780 | fromCode(0x202E) 781 | ]; 782 | 783 | // Check the text for any reason that it may not be valid as a Tweet. This is meant as a pre-validation 784 | // before posting to api.twitter.com. There are several server-side reasons for Tweets to fail but this pre-validation 785 | // will allow quicker feedback. 786 | // 787 | // Returns false if this text is valid. Otherwise one of the following strings will be returned: 788 | // 789 | // "too_long": if the text is too long 790 | // "empty": if the text is nil or empty 791 | // "invalid_characters": if the text contains non-Unicode or any of the disallowed Unicode characters 792 | twttr.txt.isInvalidTweet = function(text) { 793 | if (!text) { 794 | return "empty"; 795 | } 796 | 797 | if (text.length > MAX_LENGTH) { 798 | return "too_long"; 799 | } 800 | 801 | for (var i = 0; i < INVALID_CHARACTERS.length; i++) { 802 | if (text.indexOf(INVALID_CHARACTERS[i]) >= 0) { 803 | return "invalid_characters"; 804 | } 805 | } 806 | 807 | return false; 808 | }; 809 | 810 | twttr.txt.isValidTweetText = function(text) { 811 | return !twttr.txt.isInvalidTweet(text); 812 | }; 813 | 814 | twttr.txt.isValidUsername = function(username) { 815 | if (!username) { 816 | return false; 817 | } 818 | 819 | var extracted = twttr.txt.extractMentions(username); 820 | 821 | // Should extract the username minus the @ sign, hence the .slice(1) 822 | return extracted.length === 1 && extracted[0] === username.slice(1); 823 | }; 824 | 825 | var VALID_LIST_RE = regexSupplant(/^#{autoLinkUsernamesOrLists}$/); 826 | 827 | twttr.txt.isValidList = function(usernameList) { 828 | var match = usernameList.match(VALID_LIST_RE); 829 | 830 | // Must have matched and had nothing before or after 831 | return !!(match && match[1] == "" && match[4]); 832 | }; 833 | 834 | twttr.txt.isValidHashtag = function(hashtag) { 835 | if (!hashtag) { 836 | return false; 837 | } 838 | 839 | var extracted = twttr.txt.extractHashtags(hashtag); 840 | 841 | // Should extract the hashtag minus the # sign, hence the .slice(1) 842 | return extracted.length === 1 && extracted[0] === hashtag.slice(1); 843 | }; 844 | 845 | twttr.txt.isValidUrl = function(url, unicodeDomains, requireProtocol) { 846 | if (unicodeDomains == null) { 847 | unicodeDomains = true; 848 | } 849 | 850 | if (requireProtocol == null) { 851 | requireProtocol = true; 852 | } 853 | 854 | if (!url) { 855 | return false; 856 | } 857 | 858 | var urlParts = url.match(twttr.txt.regexen.validateUrlUnencoded); 859 | 860 | if (!urlParts || urlParts[0] !== url) { 861 | return false; 862 | } 863 | 864 | var scheme = urlParts[1], 865 | authority = urlParts[2], 866 | path = urlParts[3], 867 | query = urlParts[4], 868 | fragment = urlParts[5]; 869 | 870 | if (!( 871 | (!requireProtocol || (isValidMatch(scheme, twttr.txt.regexen.validateUrlScheme) && scheme.match(/^https?$/i))) && 872 | isValidMatch(path, twttr.txt.regexen.validateUrlPath) && 873 | isValidMatch(query, twttr.txt.regexen.validateUrlQuery, true) && 874 | isValidMatch(fragment, twttr.txt.regexen.validateUrlFragment, true) 875 | )) { 876 | return false; 877 | } 878 | 879 | return (unicodeDomains && isValidMatch(authority, twttr.txt.regexen.validateUrlUnicodeAuthority)) || 880 | (!unicodeDomains && isValidMatch(authority, twttr.txt.regexen.validateUrlAuthority)); 881 | }; 882 | 883 | function isValidMatch(string, regex, optional) { 884 | if (!optional) { 885 | // RegExp["$&"] is the text of the last match 886 | // blank strings are ok, but are falsy, so we check stringiness instead of truthiness 887 | return ((typeof string === "string") && string.match(regex) && RegExp["$&"] === string); 888 | } 889 | 890 | // RegExp["$&"] is the text of the last match 891 | return (!string || (string.match(regex) && RegExp["$&"] === string)); 892 | } 893 | 894 | if (typeof module != 'undefined' && module.exports) { 895 | module.exports = twttr.txt; 896 | } 897 | 898 | }()); -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "HackerNew", 3 | "version": "1.3.2", 4 | "description": "The best Hacker News extension, making HN quicker and more useful since 2012.", 5 | "background": { 6 | "page": "background.html" 7 | }, 8 | "icons": { 9 | "48": "images/icon-48.png", 10 | "128": "images/icon-128.png" 11 | }, 12 | "manifest_version": 2, 13 | "web_accessible_resources": [ 14 | "images/karma.png", 15 | "images/follow.png", 16 | "images/unfollow.png", 17 | "images/loading.gif", 18 | "images/loading-light.gif", 19 | "images/icons.png", 20 | "images/icon.png", 21 | "images/arrow-up.png", 22 | "images/arrow-down.png" 23 | ], 24 | "content_scripts": [ 25 | { 26 | "matches": [ 27 | "http://news.ycombinator.com/*", 28 | "http://news.ycombinator.org/*", 29 | "http://hackerne.ws/*", 30 | "https://news.ycombinator.com/*" 31 | ], 32 | "css": [ 33 | "forms.css", 34 | "hn.css" 35 | ], 36 | "js": [ 37 | "js/libs/jquery-1.7.1.min.js", 38 | "js/libs/jquery.hoverIntent.js", 39 | "js/libs/jquery.autogrow.js", 40 | "js/libs/twitter.text.js", 41 | "js/hn.js" 42 | ] 43 | } 44 | ] 45 | } 46 | --------------------------------------------------------------------------------