diff --git a/Makefile b/Makefile index cf8f061..3ee9521 100644 --- a/Makefile +++ b/Makefile @@ -2,4 +2,7 @@ clean: rm -rf dist/* install: - npm run build \ No newline at end of file + npm run build + +sneed: clean install + cat dist/4chan-XT.user.js | xclip -selection clipboard diff --git a/src/Menu/CopyTextLink.ts b/src/Menu/CopyTextLink.ts new file mode 100644 index 0000000..27e4a91 --- /dev/null +++ b/src/Menu/CopyTextLink.ts @@ -0,0 +1,47 @@ +import { g, Conf, d } from '../globals/globals' +import $ from '../platform/$' +import Menu from './Menu' +import type Post from '../classes/Post' + +var CopyTextLink = { + text: '', + init(): void { + if ( + !['index', 'thread'].includes(g.VIEW) || + !Conf['Menu'] || + !Conf['Copy Text Link'] + ) { + return + } + + const a: HTMLAnchorElement = $.el('a', { + className: 'copy-text-link', + href: 'javascript:;', + textContent: 'Copy Text', + }) + $.on(a, 'click', CopyTextLink.copy) + + return Menu.menu.addEntry({ + el: a, + order: 12, + open(post: Post): boolean { + CopyTextLink.text = (post.origin || post).commentOrig() + return true + }, + }) + }, + + copy() { + const el: HTMLTextAreaElement = $.el('textarea', { + className: 'copy-text-element', + value: CopyTextLink.text, + }) + $.add(d.body, el) + el.select() + try { + d.execCommand('copy') + } catch (error) {} + return $.rm(el) + }, +} +export default CopyTextLink diff --git a/src/Menu/DownloadLink.js b/src/Menu/DownloadLink.ts similarity index 75% rename from src/Menu/DownloadLink.js rename to src/Menu/DownloadLink.ts index 78736f1..b7d138c 100644 --- a/src/Menu/DownloadLink.js +++ b/src/Menu/DownloadLink.ts @@ -3,13 +3,8 @@ import ImageCommon from '../Images/ImageCommon' import $ from '../platform/$' import Menu from './Menu' -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md - */ const DownloadLink = { - init() { + init(): void { if ( !['index', 'thread'].includes(g.VIEW) || !Conf['Menu'] || @@ -18,7 +13,7 @@ const DownloadLink = { return } - const a = $.el('a', { + const a: HTMLAnchorElement = $.el('a', { className: 'download-link', textContent: 'Download file', }) @@ -29,7 +24,7 @@ const DownloadLink = { return Menu.menu.addEntry({ el: a, order: 100, - open({ file }) { + open({file}) { if (!file) { return false } diff --git a/src/Menu/Menu.ts b/src/Menu/Menu.ts new file mode 100644 index 0000000..0fd8d87 --- /dev/null +++ b/src/Menu/Menu.ts @@ -0,0 +1,71 @@ +import Callbacks from '../classes/Callbacks'; +import UI from '../General/UI'; +import { g, Conf } from '../globals/globals'; +import $ from '../platform/$'; + +interface Post { + isClone?: boolean; + nodes: { + info: HTMLElement; + icons: HTMLElement; + }; + thread?: { + OP: Post; + }; +} + +const Menu = { + button: document.createElement('a'), + menu: new UI.Menu('post'), + + init(): void | ReturnType { + if (!['index', 'thread'].includes(g.VIEW) || !Conf['Menu']) { + return; + } + + this.button = $.el('a', { + className: 'menu-button', + href: 'javascript:;', + }); + + $.extend(this.button, { innerHTML: '' }); + + this.menu = new UI.Menu('post'); + Callbacks.Post.push({ + name: 'Menu', + cb: this.node, + }); + + return Callbacks.CatalogThread.push({ + name: 'Menu', + cb: this.catalogNode, + }); + }, + + node(this: Post): void | HTMLElement { + if (this.isClone) { + const button = $('.menu-button', this.nodes.info); + $.rmClass(button, 'active'); + $.rm($('.dialog', this.nodes.info)); + Menu.makeButton(this, button); + return; + } + return $.add(this.nodes.info, Menu.makeButton(this)); + }, + + catalogNode(this: Post): void { + return $.after(this.nodes.icons, Menu.makeButton(this.thread!.OP)); + }, + + makeButton(post: Post, button?: HTMLElement): HTMLElement { + if (!button) { + button = Menu.button.cloneNode(true) as HTMLElement; + } + $.on(button, 'click', function (this: HTMLElement, e: Event) { + return Menu.menu.toggle(e, this, post); + }); + return button; + }, +}; + +export default Menu; diff --git a/src/Menu/ReportLink.js b/src/Menu/ReportLink.js index d36668a..a19dbb6 100644 --- a/src/Menu/ReportLink.js +++ b/src/Menu/ReportLink.js @@ -2,11 +2,6 @@ import { g, Conf, d } from '../globals/globals' import $ from '../platform/$' import Menu from './Menu' -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md - */ var ReportLink = { init() { if ( diff --git a/src/site/Site.js b/src/site/Site.ts similarity index 86% rename from src/site/Site.js rename to src/site/Site.ts index fb9cb72..8a029ad 100644 --- a/src/site/Site.js +++ b/src/site/Site.ts @@ -4,11 +4,6 @@ import $ from '../platform/$' import { dict } from '../platform/helpers' import SW from './SW' -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md - */ var Site = { defaultProperties: { '4chan.org': { software: 'yotsuba' }, @@ -19,7 +14,7 @@ var Site = { 'smug.nepu.moe': { canonical: 'smuglo.li' }, }, - init(cb) { + init(cb: () => void): void { $.extend(Conf['siteProperties'], Site.defaultProperties) let hostname = Site.resolve() if (hostname && $.hasOwn(SW, Conf['siteProperties'][hostname].software)) { @@ -28,7 +23,7 @@ var Site = { } return $.onExists(doc, 'body', () => { for (var software in SW) { - var changes + var changes = null if ((changes = SW[software].detect?.())) { changes.software = software hostname = location.hostname.replace(/^www\./, '') @@ -55,13 +50,13 @@ var Site = { }) }, - resolve(url = location) { - let { hostname } = url + resolve(url = location.href): string { + let { hostname: hostname } = new URL(url) while (hostname && !$.hasOwn(Conf['siteProperties'], hostname)) { hostname = hostname.replace(/^[^.]*\.?/, '') } if (hostname) { - let canonical + let canonical: string if ((canonical = Conf['siteProperties'][hostname].canonical)) { hostname = canonical } @@ -69,14 +64,13 @@ var Site = { return hostname }, - parseURL(url) { + parseURL(url: any): any { const siteID = Site.resolve(url) return Main.parseURL(g.sites[siteID], url) }, - - set(hostname) { + set(hostname: string) { for (var ID in Conf['siteProperties']) { - var site + var site: HTMLElement var properties = Conf['siteProperties'][ID] if (properties.canonical) { continue