-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
executable file
·144 lines (130 loc) · 4.57 KB
/
script.js
File metadata and controls
executable file
·144 lines (130 loc) · 4.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
var md = document.getElementById("md");
var mdd = document.getElementById("mdd");
var ht = document.getElementById("ht");
var infos = document.getElementById("infos");
async function markedIniAndRender() { // add source pos tags for headings to marked.js
await import(chrome.runtime.getURL("marked.min.js"));
// this stores original tokenizer stuff which can be called. Otherwise, rules are not initialized.
var origlexer = new marked.Lexer({ ...marked.defaults, tokenizer: new marked.Tokenizer() });
const tokenizer = { // add source position tag
heading(src) {
var res = origlexer.tokenizer.heading(src);
if (res) {
res.tokens = this.lexer.inline(res.text);
res.charno = md.value.length - src.length;
return res;
}
},
paragraph(src) {
var res = origlexer.tokenizer.paragraph(src);
if (res) {
res.tokens = this.lexer.inline(res.text);
res.charno = md.value.length - src.length;
return res;
}
},
};
marked.use({ tokenizer });
const walkTokens = (token) => {
if (token.charno) { // append charno!
var ct = { type: 'html', text: '<div hidden class="tag" data-charno=' + token.charno + '></div>' };
if (token.tokens) { token.tokens.push(ct); } else { token.tokens = [ct]; }
}
};
marked.use({ walkTokens });
renderit();
}
function renderit() {
ht.innerHTML = marked.parse(md.value);
}
function updateht() {
if (typeof marked === "undefined") { // dynamically load marked
markedIniAndRender();
} else
renderit();
};
function updatemd(s) {
md.value = s;
updateht();
};
function toggleEditor(showonly = false) {
if (!showonly && !mdd.classList.contains("hidden")) { // close editor, save
localStorage.setItem('notes', md.value);
localStorage.setItem('notes-html', ht.innerHTML);
mdd.classList.add("hidden")
infos.classList.add("hidden")
} else { // edit
mdd.classList.remove("hidden")
md.focus();
infos.classList.remove("hidden")
}
};
// startup: load saved or README.md
var iniht = localStorage.getItem('notes-html');
var inimd = localStorage.getItem('notes');
if (iniht != null && inimd != null) {
md.value = inimd;
ht.innerHTML = iniht;
} else {
var url = chrome.runtime.getURL("README.md");
fetch(url).then((response) => response.text().then((text) => updatemd(text)));
}
mdd.onkeyup = () => { // update html on edit
updateht();
};
ht.addEventListener('click', function (e) {
if (e.detail === 3) { // triple click
var curr = e.target;
var pos = 0;
if ( !(curr != ht && ht.contains(curr)) ) { // not a child of ht clicked? find closest element!
mindy = 1e10;
curr = null;
for (child of ht.children) {
dy = Math.abs(e.clientY - (child.getBoundingClientRect().top + child.getBoundingClientRect().height / 2))
if (mindy > dy) {
mindy = dy;
curr = child;
}
}
}
if (curr) {
while (curr) {
if (curr.className === 'tag') {
pos = curr.dataset.charno;
break;
} else if (child = curr.querySelector('.tag')) {
pos = child.dataset.charno;
break;
}
curr = curr.nextElementSibling || curr.parentNode; // try next node or go up
}
}
toggleEditor(true);
md.focus();
md.setSelectionRange(pos, pos);
md.blur();
md.focus();
}
});
window.onstorage = (event) => { // Inter Tab Synchronization
if (event.key === "notes") md.value = event.newValue
else if (event.key === "notes-html") ht.innerHTML = event.newValue;
};
// Key Events
document.onkeydown = (event) => {
if (event.code === 'Tab') { // Change Tab to Spaces
event.preventDefault();
const spaces = ' ';
document.execCommand('insertText', false, spaces);
} else if (event.code === 'Escape') { // toggle editor
toggleEditor();
} else if ((event.metaKey || event.ctrlKey) && event.key === 's') { // backup
event.preventDefault();
var elem = window.document.createElement('a');
elem.download = "chrome-newtabmarkdown-backup-" + new Date().toISOString() + (event.shiftKey ? ".html" : ".md");
elem.href = window.URL.createObjectURL(new Blob([event.shiftKey ? document.documentElement.outerHTML : md.value], { type: (event.shiftKey ? "text/html" : "text/plain") }));
document.body.appendChild(elem);
elem.click();
document.body.removeChild(elem);
}
};