├── .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 |
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 |
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 |
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 |
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 |
--------------------------------------------------------------------------------