Skip to content

Commit f565bbf

Browse files
committed
convert to TypeScript
1 parent cc469a5 commit f565bbf

21 files changed

Lines changed: 337 additions & 257 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
.build/
12
.DS_Store
23
node_modules/
34
npm-debug.log

Makefile

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11

22
NAME=createlink
3-
EXTDIR=extension
43
VERSION=$(shell plutil -convert json -r -o - ./extension/manifest.json | "grep" '"version"' | "egrep" -o '\w(\.\w+)+')
5-
DIRNAME=$(shell pwd)
4+
CWD=$(shell pwd)
65
SRC="extension/js/popup.js"
7-
EXTENSIONDIR=extension
6+
EXT_DIRNAME=extension
7+
EXT_DIR=$(CWD)/$(EXT_DIRNAME)
88

9-
CRXMAKE_DIR=./crxmake
10-
TMPFILELIST=/tmp/filelist
9+
BUILD_DIR=$(CWD)/.build
10+
TMPFILELIST=$(BUILD_DIR)/filelist
1111

1212
$(NAME)-$(VERSION).zip: $(SRC)
13-
find "$(EXTENSIONDIR)" | sed 's/$(EXTENSIONDIR)/./' | grep -v .js.map > $(TMPFILELIST)
14-
cd $(EXTENSIONDIR); cat $(TMPFILELIST) | zip -q $(DIRNAME)/$@ -@
13+
'rm' $(BUILD_DIR)/$@
14+
mkdir -p $(BUILD_DIR)
15+
find "$(EXT_DIRNAME)" | sed 's/$(EXT_DIRNAME)/./' | grep -v .js.map > $(TMPFILELIST)
16+
cd $(EXT_DIR); cat $(TMPFILELIST) | zip -q $(BUILD_DIR)/$@ -@
1517

1618
$(SRC):
1719
./node_modules/.bin/webpack --mode=production
@@ -20,4 +22,4 @@ watch:
2022
./node_modules/.bin/webpack -w --mode=development
2123

2224
clean:
23-
rm $(NAME).crx $(NAME).zip
25+
rm -rf .build/

extension/background.html

Lines changed: 0 additions & 11 deletions
This file was deleted.

extension/content.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
33
switch (request.type) {
44
case 'ping':
5-
return sendResponse('pong')
5+
return sendResponse({type: 'pong'})
66
case 'showInputDialog':
77
const text = window.prompt("CreateLink needs your input");
8-
return sendResponse(text);
8+
return sendResponse({type: request.type, text});
99
case 'selectedText':
1010
const s = document.getSelection()
11-
return sendResponse(s ? s.toString() : '')
11+
return sendResponse({ type: request.type, text: (s ? s.toString() : '')})
1212
case 'evaluateFilter':
1313
const f = new Function('s', request.code)
14-
return sendResponse(f.call(null, request.string))
14+
return sendResponse({ type: request.type, text: f.call(null, request.string)})
1515
case 'copyToClipboard':
16-
copyToClipboard(request.link)
16+
return sendResponse({ type: request.type, text: copyToClipboard(request.link) })
1717
}
1818
});
1919

@@ -34,4 +34,5 @@ function copyToClipboard(text) {
3434
textarea.select()
3535
document.execCommand("copy");
3636
textarea.parentNode.removeChild(textarea)
37+
return text
3738
}

extension/manifest.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"name": "Create Link",
3-
"version": "0.5.0",
3+
"version": "0.5.1",
44
"manifest_version": 3,
55
"background": {
6-
"service_worker": "js/background.js"
6+
"service_worker": "js/service-worker.js"
77
},
88
"action": {
99
"default_icon": "icon64.png",
@@ -36,5 +36,5 @@
3636
"http://*/*",
3737
"https://*/*"
3838
],
39-
"permissions": [ "tabs", "contextMenus", "storage", "clipboardWrite" ]
39+
"permissions": [ "contextMenus", "storage", "clipboardWrite" ]
4040
}

extension/options.html

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<script src="./js/options.js"></script>
99
</head>
1010
<body>
11-
<div id="about">
11+
<section id="about">
1212
<div>
1313
<img src="icon128.png" class="icon" width="128" height="128" />
1414
</div>
@@ -22,19 +22,19 @@ <h1>Create Link</h1><h2 id="version"></h2>
2222
<li>Icons by <a href="http://icontoaster.com/?free-icons-for-all">icontoaster.com</a></li>
2323
</ul>
2424
</div>
25-
</div>
25+
</section>
2626

27-
<div>
27+
<section>
2828
<h2>Default Format</h2>
2929
<p>Select the format from the table below that should be used when the keyboard shortcut is activated.</p>
3030
<!-- when table row is selected, show selection below -->
3131
<p>Default is currently <select id="current-default-format"></select></p>
3232
<p>
3333
<a href="#" id="configure-shortcut">Configure shortcut</a>
3434
</p>
35-
</div>
35+
</section>
3636

37-
<div id="configuration">
37+
<section id="configuration">
3838
<h2>Formats</h2>
3939
<table id="cocoatable" class="cocoatable">
4040
<thead>
@@ -52,9 +52,9 @@ <h2>Formats</h2>
5252
<div id="cocoatable-button-minus" class="button minus">-</div>
5353
<div style="clear:both"><!-- --></div>
5454
</div>
55-
</div>
55+
</section>
5656

57-
<div>
57+
<section>
5858
<h2>Variables</h2>
5959
<div>
6060
Create Link recognizes some <a href="https://addons.mozilla.org/en/firefox/addon/142">Make Link</a> compatible variables.
@@ -77,15 +77,30 @@ <h2>Variables</h2>
7777
<dt>%input%</dt>
7878
<dd>Shows a dialog to input text.</dd>
7979
</dl>
80-
</div>
80+
</section>
8181

82-
<div>
82+
<section>
83+
<h2>Meta Characters</h2>
84+
<div>
85+
CreateLink supports following meta characters to put special characters.
86+
</div>
87+
<dl id="metachars">
88+
<dt>\t</dt>
89+
<dd>Tab character.</dd>
90+
<dt>\n</dt>
91+
<dd>New line. 0x0A Line Feed.</dd>
92+
<dt>\r</dt>
93+
<dd>0x0D Carriage Return.</dd>
94+
</dl>
95+
</section>
96+
97+
<section>
8398
<h2>Filter</h2>
8499
<div>
85100
<p>Filter must be specified in the following format (perl-like substitution operator): <code>s/<i>&lt;pattern&gt;</i>/<i>&lt;replacement&gt;</i>/<i>[&lt;flags&gt;]</i></code><br>
86101
Pattern is regular expression and flags are either "g", "i", "m" or "y".</p>
87102
<p>For example, <code>s/\[at\]/@/gi</code> will replace all occurrences (g) of "[at]/[AT]/[At]/[aT]" case-insensitively (i) into "@".</p>
88103
</div>
89-
</div>
104+
</section>
90105
</body>
91106
</html>

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
{
22
"devDependencies": {
3+
"@types/chrome": "0.0.171",
34
"gutil": "^1.6.4",
5+
"ts-loader": "^9.2.6",
6+
"typescript": "^4.5.4",
47
"webpack": "^5.0.0",
58
"webpack-cli": "^4.9.1"
69
}
Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,40 @@
1-
const CreateLink = require('./createlink')
2-
const utils = require('./utils')
3-
const fmt = require('./formats')
1+
import fmt, { FormatDefinition } from "./formats";
2+
import { MessageBroker } from './message-broker'
3+
import {CreateLink } from './createlink'
4+
import { sendMessageToTab } from './utils'
45

56
// run in service worker context.
6-
module.exports = class ContextMenuHandler {
7-
constructor(broker) {
8-
this.contextMenuIdList = {};
7+
export class ContextMenuHandler {
8+
broker: MessageBroker
9+
contextMenuIdList: { [name: string]: number }
10+
11+
constructor(broker: MessageBroker) {
912
this.broker = broker
13+
this.contextMenuIdList = {};
1014
}
1115

12-
initialize(formats) {
16+
initialize(formats: FormatDefinition[]) {
1317
this.updateContextMenus(formats)
1418

1519
chrome.contextMenus.onClicked.addListener(this.onMenuItemClicked.bind(this))
1620
chrome.runtime.onMessage.addListener(this.onMessage.bind(this))
1721
}
1822

19-
onMessage(request, sender, sendResponse) {
23+
onMessage(request: any, sender: chrome.runtime.MessageSender, sendResponse: ((response?: any) => void)) {
2024
if (request.request == 'updateFormats') {
2125
// options page requests updating the items
2226
this.updateContextMenus(request.formats)
2327
}
2428
}
2529

26-
formatIndexOfMenuItemId(menuItemId) {
27-
return this.contextMenuIdList[menuItemId]
30+
formatIndexOfMenuItemId(menuItemId: string|number): number {
31+
return this.contextMenuIdList[String(menuItemId)]
2832
}
2933

3034
// callback function for contextMenus.onClicked cannot be an async function.
31-
onMenuItemClicked(info, tab) {
32-
utils.sendMessageToTab(tab.id, { type: 'ping' }).then(async (response) => {
33-
if (response !== "pong") {
35+
onMenuItemClicked(info: chrome.contextMenus.OnClickData, tab: chrome.tabs.Tab) {
36+
sendMessageToTab(tab.id, { type: 'ping' }).then(async (response) => {
37+
if (response && response.type !== "pong") {
3438
// Reload the tab. The tab might be opened before this extension is installed.
3539
// It should respond once it is reloaded.
3640
chrome.tabs.reload(tab.id)
@@ -41,12 +45,12 @@ module.exports = class ContextMenuHandler {
4145
const def = fmt.format(formatIndex)
4246
const cl = new CreateLink()
4347
cl.formatInTab(def, info, tab).then(link => {
44-
utils.sendMessageToTab(tab.id, { type: 'copyToClipboard', link })
48+
sendMessageToTab(tab.id, { type: 'copyToClipboard', link })
4549
})
4650
})
4751
}
4852

49-
updateContextMenus(formats) {
53+
updateContextMenus(formats: FormatDefinition[]) {
5054
chrome.contextMenus.removeAll();
5155

5256
if (formats.length == 1) {
Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
11

2-
const utils = require('./utils')
3-
const fmt = require('./formats')
2+
import {showInputDialog, sendMessageToTab} from './utils'
3+
import fmt, { FormatDefinition } from './formats'
44

5-
class CreateLink {
5+
interface ClickContext {
6+
selectionText?: string
7+
pageUrl: string
8+
linkUrl?: string
9+
srcUrl?: string
10+
mediaType?: string
11+
}
12+
13+
14+
export class CreateLink {
615
constructor() {
716
}
817

9-
applyFilter(tabId, def, data) {
18+
applyFilter(tabId: number, def: FormatDefinition, data: string): Promise<string> {
1019
if (def.filter) {
1120
var m = def.filter.match(/^s\/(.+?)\/(.*?)\/(\w*)$/);
1221
if (m) {
1322
var r = new RegExp(m[1], m[3]);
1423
data = data.replace(r, m[2]);
1524
} else {
16-
return utils.sendMessageToTab(tabId, {type: 'evaluateFilter', code: def.filter, string: data})
25+
return sendMessageToTab(tabId, { type: 'evaluateFilter', code: def.filter, string: data }).then( response => response.text )
1726
}
1827
}
1928
return Promise.resolve(data);
2029
}
2130

22-
formatLinkText(def, url, text, title, inputs) {
31+
formatLinkText(def: FormatDefinition, url: string, text: string, title: string, inputs: string[]): string {
2332
text = text || ''
2433

2534
var data = def.format.
@@ -41,18 +50,18 @@ class CreateLink {
4150
})
4251
}
4352

44-
getInputs(def, tabId) {
53+
getInputs(def: FormatDefinition, tabId: number): Promise<string[]> {
4554
const m = def.format.match(/%input%/g)
4655
if (m) {
47-
return Promise.all( m.map( () => {
48-
return utils.showInputDialog(tabId)
49-
}) )
56+
return Promise.all(m.map(() => {
57+
return showInputDialog(tabId).then(response => response.text)
58+
}))
5059
} else {
5160
return Promise.resolve([])
5261
}
5362
}
5463

55-
async formatInTab(def, info, tab) {
64+
async formatInTab(def: FormatDefinition, info: ClickContext, tab: chrome.tabs.Tab): Promise<string> {
5665
var url;
5766
if (info.mediaType === 'image') {
5867
url = info.srcUrl;
@@ -65,13 +74,13 @@ class CreateLink {
6574
return this.formatString(tab.id, def, url, text, title)
6675
}
6776

68-
async formatString(tabId, def, url, text, title) {
77+
async formatString(tabId: number, def: FormatDefinition, url: string, text: string, title: string): Promise<string> {
6978
const inputs = await this.getInputs(def, tabId)
7079
const linkText = this.formatLinkText(def, url, text, title, inputs)
7180
return this.applyFilter(tabId, def, linkText)
7281
}
7382

74-
indexOfFormatByLabel(label) {
83+
indexOfFormatByLabel(label: string): number {
7584
const formats = fmt.getFormats();
7685
for (var i = 0, len = formats.length; i < len; i++) {
7786
var item = formats[i];
@@ -84,21 +93,14 @@ class CreateLink {
8493
};
8594
}
8695

87-
function escapeHTML(text) {
96+
function escapeHTML(text: string): string {
8897
return text ? text.replace(/[&<>'"]/g, convertHTMLChar) : text;
8998
}
90-
function convertHTMLChar(c) { return charMap[c]; }
91-
var charMap = {
99+
function convertHTMLChar(c: string): string { return charMap[c]; }
100+
const charMap: { [name: string]: string } = {
92101
'&': '&amp;',
93102
'<': '&lt;',
94103
'>': '&gt;',
95104
"'": '&apos;',
96105
'"': '&quot;'
97106
};
98-
function showPrompt(text, pos, subject) {
99-
var msg = "Please enter the input text for \n" + subject;
100-
var s = window.prompt(msg);
101-
return (s === null) ? "" : s;
102-
}
103-
104-
module.exports = CreateLink

0 commit comments

Comments
 (0)