├── .eslintrc ├── .gitignore ├── README.md ├── index.html ├── index.js └── package.json /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "browser": true, 5 | "node": true 6 | }, 7 | "extends": "elemefe", 8 | "parser": "babel-eslint" 9 | } 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | for giraffe 2 | 3 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DisqusJS 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* global Jinkela, req */ 4 | (exports => { 5 | const api = req.create({ baseUrl: '//disqus.shijianan.com/' }); 6 | const $style = document.createElement('style'); 7 | $style.type = 'text/css'; 8 | $style.appendChild(document.createTextNode(` 9 | @keyFrames busy { 10 | 0% { content: '评论加载中.'; } 11 | 25% { content: '评论加载中..'; } 12 | 50% { content: '评论加载中...'; } 13 | 75% { content: '评论加载中..'; } 14 | 100% { content: '评论加载中.'; } 15 | } 16 | `)); 17 | document.head.appendChild($style); 18 | function sortComments(response) { 19 | response.reverse(); 20 | let idMap = response.map(record => +record.id); 21 | // 子回复用数组存到父回复下 22 | response.forEach(record => { record.children = []; }); 23 | response.forEach(record => { 24 | if (record.parent) { 25 | let parentIndex = idMap.indexOf(+record.parent); 26 | response[parentIndex].children.push(record); 27 | } 28 | }); 29 | function flatten(list) { 30 | return list 31 | .reduce((prev, current) => { 32 | prev.push(current); 33 | if (current.children.length) prev.push.apply(prev, flatten(current.children)); 34 | return prev; 35 | }, []); 36 | } 37 | return flatten(response.filter(record => !record.parent)); 38 | } 39 | 40 | class DisqusHeader extends Jinkela { 41 | get template() { 42 | return ` 43 |
44 | 51 |
52 | `; 53 | } 54 | get styleSheet() { 55 | return ` 56 | :scope { 57 | border-bottom: 2px solid #e7e9ee; 58 | margin-bottom: 24px; 59 | > nav { 60 | display: flex; 61 | align-items: center; 62 | justify-content: space-between; 63 | > .icon-comment { width: 19px; height: 19px; } 64 | > ul { 65 | > li { 66 | width: 105px; 67 | display: inline-block; 68 | text-align: center; 69 | font-weight: 500; 70 | &.count { 71 | display: inline-block; 72 | color: #2a2e2e; 73 | font-size: 15px; 74 | padding: 12px 0; 75 | margin-right: 15px; 76 | font-weight: 700; 77 | border-bottom: 2px solid #2e9fff; 78 | > span { margin-right: 5px; } 79 | } 80 | } 81 | } 82 | } 83 | } 84 | `; 85 | } 86 | } 87 | 88 | class DisqusForm extends Jinkela { // eslint-disable-line no-unused-vars 89 | get value() { 90 | return { name: this.name, email: this.email }; 91 | } 92 | get template() { 93 | return ` 94 |
95 |

访客信息

96 | 97 | 98 |

经过可爱的博主同意后你的留言就会出现在页面上了 (≧▽≦)

99 |
100 | `; 101 | } 102 | get styleSheet() { 103 | return ` 104 | :scope { 105 | float: right; 106 | display: none; 107 | &.show { display: block; } 108 | > .title { 109 | margin: 10px 0; 110 | } 111 | > .notice { 112 | margin: 10px 0; 113 | font-size: 13px; 114 | color: #7f919e; 115 | font-weight: 300; 116 | } 117 | > input { 118 | box-sizing: border-box; 119 | background-color: #fff; 120 | color: #7f919e; 121 | padding: 5px 9px; 122 | border: 2px solid #dbdfe4; 123 | display: block; 124 | border-radius: 4px; 125 | font-size: 13px; 126 | height: 32px; 127 | width: 100%; 128 | margin-bottom: 12px; 129 | &.error { border-color: #F55567; } 130 | &:focus { outline: none; } 131 | } 132 | } 133 | `; 134 | } 135 | } 136 | 137 | class DisqusCurrentUser extends Jinkela { 138 | get DisqusForm() { return DisqusForm; } 139 | showActions() { 140 | this.footer.style.opacity = 1; 141 | this.form.element.classList.add('show'); 142 | this.textarea.style.height = '100px'; 143 | } 144 | setError(target) { 145 | const { name, email } = this.form.value; 146 | [this.textarea, name, email].forEach(el => el.classList.remove('error')); 147 | if (target) target.classList.add('error'); 148 | } 149 | onSubmit() { 150 | const { name, email } = this.form.value; 151 | switch (true) { 152 | case !this.textarea.value || !this.textarea.value.trim(): 153 | this.errorMessage = '请填写评论内容'; 154 | this.setError(this.textarea); 155 | return; 156 | case !name.value || !name.value.trim(): 157 | this.errorMessage = '请填写昵称'; 158 | this.setError(name); 159 | return; 160 | case !/^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(email.value): 161 | this.errorMessage = '邮箱格式非法'; 162 | this.setError(email); 163 | return; 164 | } 165 | this.setError(null); 166 | this.errorMessage = null; 167 | const payload = { 168 | name: name.value, 169 | email: email.value, 170 | comment: this.textarea.value 171 | }; 172 | if (this.restarget) payload.parent = this.restarget; 173 | this.button.setAttribute('disabled', 'disabled'); 174 | api.post('comment', JSON.stringify(payload)).end() 175 | .then(() => { 176 | alert('评论发送成功,请耐心等候博主审核通过'); 177 | this.textarea.value = ''; 178 | }, () => { this.errorMessage = '服务器抽风了,请稍后再重试 (>﹏<)'; }) 179 | .then(() => { this.button.removeAttribute('disabled'); }); 180 | } 181 | get template() { 182 | return ` 183 |
184 |
185 | 186 |
187 | 188 |
189 | 190 | {errorMessage} 191 |
192 |
193 | 194 |
195 |
196 |
197 | 198 |
199 | `; 200 | } 201 | get styleSheet() { 202 | return ` 203 | :scope { 204 | margin-bottom: 24px; 205 | overflow: auto; 206 | > .container { 207 | display: flex; 208 | > .avatar { 209 | width: 48px; 210 | height: 48px; 211 | flex-shrink: 0; 212 | border-radius: 3px; 213 | margin-right: 10px; 214 | vertical-align: middle; 215 | } 216 | > div { 217 | width: 100%; 218 | > textarea { 219 | box-sizing: border-box; 220 | height: 48px; 221 | display: block; 222 | border: 2px solid #dbdfe4; 223 | border-radius: 4px; 224 | padding: 15px 10px; 225 | resize: none; 226 | cursor: text; 227 | color: #2a2e2e; 228 | width: 100%; 229 | font-family: "Helvetica Neue",arial,sans-serif; 230 | line-height: 1.4; 231 | word-break: break-word; 232 | font-size: 14px; 233 | &.error { border-color: #F55567; } 234 | &:focus { outline: none; } 235 | } 236 | > .errormsg { 237 | > svg { vertical-align: middle; } 238 | margin-bottom: 5px; 239 | background-color: #F55567; 240 | padding: 10px 15px; 241 | color: #fff; 242 | font-weight: 300; 243 | font-size: 13px; 244 | } 245 | > footer { 246 | box-sizing: border-box; 247 | margin-top: -5px; 248 | opacity: 0; 249 | transition: opacity linear .2s; 250 | background-color: #F6F8F9; 251 | height: 36px; 252 | width: 100%; 253 | border: 2px solid #dbdfe4; 254 | border-radius: 4px; 255 | > svg { 256 | vertical-align: middle; 257 | margin: 8px; 258 | } 259 | > button { 260 | box-sizing: border-box; 261 | float: right; 262 | background-color: #737F87; 263 | color: #fff; 264 | padding: 4px 15px; 265 | border-bottom-right-radius: 4px; 266 | margin-top: -1px; 267 | margin-right: -1px; 268 | height: 34px; 269 | border: none; 270 | cursor: pointer; 271 | outline: none; 272 | &:hover { background-color: rgba(29,47,58,.7); } 273 | &:disabled { 274 | opacity: .6; 275 | cursor: not-allowed; 276 | } 277 | } 278 | } 279 | } 280 | } 281 | } 282 | `; 283 | } 284 | } 285 | 286 | class DisqusComment extends Jinkela { 287 | get DisqusCurrentUser() { return DisqusCurrentUser; } 288 | init() { 289 | if (this.isResponse) this.element.style.marginLeft = '48px'; 290 | } 291 | toggleRespond() { 292 | this.isResponsing = !this.isResponsing; 293 | this.respond.classList.toggle('active'); 294 | } 295 | get template() { 296 | return ` 297 |
  • 298 | 299 |
    300 |
    301 | {author} 302 | {date} 303 |
    304 |

    {comment}

    305 | 321 |
    322 |
  • 323 | `; 324 | } 325 | get styleSheet() { 326 | return ` 327 | :scope { 328 | display: flex; 329 | align-items: top; 330 | margin-bottom: 24px; 331 | > .avatar { 332 | flex-shrink: 0; 333 | width: 48px; 334 | height: 48px; 335 | margin-right: 10px; 336 | border-radius: 3px; 337 | } 338 | .responseform { margin-top: 15px; } 339 | .date { 340 | color: #656c7a; 341 | font-weight: 300; 342 | font-size: 12px; 343 | } 344 | .author { 345 | color: rgb(42, 146, 189); 346 | font-weight: 700; 347 | margin-right: 5px; 348 | } 349 | .comment { 350 | font-weight: 400; 351 | margin: 0; 352 | margin-top: 10px; 353 | color: #2a2e2e; 354 | margin-bottom: 5px; 355 | } 356 | footer { 357 | > ul { 358 | > li { 359 | display: block; 360 | font-size: 13px; 361 | > a { 362 | color: #656c7a; 363 | text-decoration: none; 364 | display: inline-block; 365 | &.active { color: #2e9fff; } 366 | } 367 | } 368 | } 369 | } 370 | } 371 | `; 372 | } 373 | } 374 | 375 | class DisqusCommentList extends Jinkela { 376 | init() { 377 | this.data.forEach(comment => { 378 | const { createdAt } = comment; 379 | const date = new Date(createdAt); 380 | const { cache } = comment.author.avatar; 381 | new DisqusComment({ 382 | author: comment.author.name, 383 | comment: comment.raw_message, 384 | avatar: cache, 385 | date: date.getFullYear() + '年' + (date.getMonth() + 1) + '月' + date.getDate() + '日', 386 | isResponse: !!comment.parent, 387 | resTarget: comment.parent 388 | }).to(this); 389 | }); 390 | } 391 | get tagName() { return 'ul'; } 392 | } 393 | 394 | class DisqusFooter extends Jinkela { 395 | get template() { 396 | return ` 397 | 410 | `; 411 | } 412 | get styleSheet() { 413 | return ` 414 | :scope { 415 | padding: 24px 0; 416 | margin-top: 24px; 417 | border-top: 2px solid #e7e9ee; 418 | display: flex; 419 | justify-content: space-between; 420 | align-items: center; 421 | > ul { 422 | > li { 423 | display: inline-block; 424 | font-size: 13px; 425 | &:not(:last-child) { 426 | margin-right: 15px; 427 | } 428 | > svg { vertical-align: middle; } 429 | > a { 430 | color: #494e58; 431 | text-decoration: none; 432 | display: inline-block; 433 | vertical-align: middle; 434 | } 435 | } 436 | } 437 | } 438 | `; 439 | } 440 | } 441 | 442 | class RecentComment extends Jinkela { 443 | goComment() { location.href = this.url; } 444 | get template() { 445 | return ` 446 |
  • 447 | 448 |
    449 |
    450 | {name} 451 | {date} 452 |
    453 |

    {comment}

    454 |
    455 |
  • 456 | `; 457 | } 458 | get styleSheet() { 459 | return ` 460 | :scope { 461 | overflow: auto; 462 | margin-bottom: 10px; 463 | font-size: 13px; 464 | > .avatar { 465 | float: left; 466 | width: 42px; 467 | height: 42px; 468 | margin-right: 15px; 469 | flex-shrink: 0; 470 | border-radius: 4px; 471 | } 472 | > div { 473 | float: left; 474 | width: 70%; 475 | } 476 | .author { 477 | color: #EE6172; 478 | } 479 | .comment { 480 | width: 100%; 481 | white-space: nowrap; 482 | text-overflow: ellipsis; 483 | overflow: hidden; 484 | margin-top: 5px; 485 | cursor: pointer; 486 | &:hover { color: #6BB4F3; } 487 | } 488 | } 489 | `; 490 | } 491 | } 492 | 493 | class Loading extends Jinkela { 494 | get template() { return '

    '; } 495 | get styleSheet() { 496 | return ` 497 | :scope { 498 | &::after { 499 | content: ''; 500 | opacity: .5; 501 | font-weight: 300; 502 | animation: busy 1s linear infinite; 503 | font-size: 20px; 504 | } 505 | text-align: center; 506 | padding: 15px 0; 507 | } 508 | `; 509 | } 510 | }; 511 | 512 | class Main extends Jinkela { 513 | getArticleComments(url) { 514 | // is home page 515 | if (location.pathname === '/') return; 516 | let options = {}; 517 | const loading = new Loading().to(this); 518 | if (url && url.trim()) options = { query: { url } }; 519 | api.get('comments', options).end().then(response => { 520 | response = JSON.parse(response).response; 521 | new DisqusHeader({ data: response.length }).to(this); 522 | new DisqusCurrentUser().to(this); 523 | new DisqusCommentList({ data: sortComments(response) }).to(this); 524 | new DisqusFooter().to(this); 525 | }, () => { this.internalError = true; }) 526 | .then(() => { loading.element.parentNode.removeChild(loading.element); }); 527 | } 528 | getRecentComments(dom = document.body) { 529 | const loading = new Loading().to(dom); 530 | api.get('comments/recent').end().then(response => { 531 | response = JSON.parse(response).response; 532 | response.forEach(comment => { 533 | const { cache } = comment.author.avatar; 534 | const date = new Date(comment.createdAt); 535 | new RecentComment({ 536 | name: comment.author.name, 537 | avatar: cache, 538 | comment: comment.raw_message, 539 | date: date.getFullYear() + '年' + (date.getMonth() + 1) + '月' + date.getDate() + '日', 540 | url: comment.url 541 | }).to(dom); 542 | }); 543 | }, () => {}).then(() => { loading.element.parentNode.removeChild(loading.element); }); 544 | } 545 | get template() { 546 | return ` 547 |
    548 |

    549 |

    服务器开小差了,评论加载失败,请稍后再重试 (>﹏<)

    550 |
    551 | `; 552 | } 553 | get styleSheet() { 554 | return ` 555 | :scope { 556 | font-family: "Helvetica Neue", arial, sans-serif; 557 | transition: opacity, .5s, ease; 558 | color: #656c7a; 559 | font-weight: 700; 560 | font-size: 15px; 561 | ul, ol { 562 | list-style: none; 563 | margin: 0; 564 | padding: 0; 565 | } 566 | > .errormsg { 567 | text-align: center; 568 | padding: 15px 0; 569 | } 570 | } 571 | `; 572 | } 573 | } 574 | const main = new Main(); 575 | exports.DisqusJS = { 576 | getRecentComments(dom = document.body) { main.getRecentComments(dom); }, 577 | getArticleComments(url = location.href) { 578 | new Promise((resolve, reject) => { 579 | if (~['/about/', '/message/', '/friends/', 'reading'].indexOf(location.pathname)) window.disqus_url = location.origin + location.pathname + 'index.html'; 580 | let done = false; 581 | window.disqus_config = function() { 582 | this.page.url = location.href.replace(/^https?/, 'http'); 583 | }; 584 | const $dsq = document.createElement('script'); 585 | $dsq.src = '//giraffe0813new.disqus.com/embed.js'; 586 | $dsq.onload = () => { 587 | done = true; 588 | reject(); 589 | }; 590 | document.head.appendChild($dsq); 591 | setTimeout(() => { if (!done) resolve(); }, 2000); 592 | }).then(() => { 593 | main.to(document.querySelector('#disqus_thread') || document.body); 594 | main.getArticleComments(url); 595 | }).catch(() => {}); 596 | } 597 | }; 598 | })(window); 599 | 600 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "disqusjs", 3 | "version": "2.0.8", 4 | "description": "disqus client sdk", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/jiananshi/DisqusJS.git" 12 | }, 13 | "keywords": [ 14 | "disqus" 15 | ], 16 | "author": "jiananshi (https://shijianan.com)", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/jiananshi/DisqusJS/issues" 20 | }, 21 | "homepage": "https://github.com/jiananshi/DisqusJS#readme" 22 | } 23 | --------------------------------------------------------------------------------