This repository was archived by the owner on Dec 27, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
164 lines (143 loc) · 6.31 KB
/
Copy pathscript.js
File metadata and controls
164 lines (143 loc) · 6.31 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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//enable html design mode for editor
editor.document.designMode = "On";
//declare dropdowns
let styleDropdown, fontDropdown, emojiDropdown;
//to maintain active option state
let activeProperties = {
bold: false,
italic: false,
strikeThrough: false,
underline: false,
insertOrderedList: false,
insertUnorderedList: false,
codeBlock: false,
};
//initialize everything when the window loads
window.onload = function () {
//since the editor is an iframe, it doesn't contain any script or css.
//following code add prism.css & editor.css to the editor
let head = editor.document.getElementsByTagName('head')[0];
let prismCss = editor.document.createElement('link');
prismCss.rel = 'stylesheet';
prismCss.type = 'text/css';
prismCss.href = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism.min.css';
head.appendChild(prismCss);
let editorCss = editor.document.createElement('link');
editorCss.rel = 'stylesheet';
editorCss.type = 'text/css';
editorCss.href = 'editor/editor.css';
head.appendChild(editorCss);
//following code add prism.js to editor
let body = editor.document.getElementsByTagName('body')[0];
let script = editor.document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/prism.min.js';
body.appendChild(script);
//set the default fontName of the editor to Verdana
transform('fontName', 'Verdana');
//initializes the dropdown for text-style button
styleDropdown = new Dropdown(document.querySelector("#btn-style"), intialValue = 'Normal');
styleDropdown.init();
//initializes the dropdown for font-family button
fontDropdown = new Dropdown(document.querySelector("#btn-font"), intialValue = 'Verdana');
fontDropdown.init();
//initializes the dropdown for emoji button
emojiDropdown = new EmojiDropdown(document.querySelector("#btn-emoji"));
emojiDropdown.init((emoji) => {
//to append emoji at end of current text
//more on selection & range at: https://javascript.info/selection-range#selection-events
editor.document.body.focus();
let selection = editor.window.getSelection();
let range = selection.getRangeAt(0);
let selectedText = range.extractContents();
selectedText.append(emoji);
range.insertNode(selectedText);
range.collapse();
});
//to hide the dropdowns of the use clicks on outside the dropdown
document.querySelector('body').addEventListener('click', (e) => {
if (e.target != styleDropdown.element) styleDropdown.hide();
if (e.target != fontDropdown.element) fontDropdown.hide();
if (e.target != emojiDropdown.element && !emojiDropdown.element.contains(e.target))
emojiDropdown.hide();
});
//listen to all change events on editor to change properties accordingly
addMultipleEventListener(editor.document.body, ['keydown', 'click', 'focus'], () => {
onEditorChange();
});
}
//whenever anything changes on editor this should be called
function onEditorChange() {
//TODO:add debounce to this
let currentElement = editor.window.getSelection().getRangeAt(0).commonAncestorContainer;
if (currentElement.tagName == 'BODY') return;
activeProperties.bold = isDescendantOf(currentElement, 'B');
activeProperties.italic = isDescendantOf(currentElement, 'I');
activeProperties.strikeThrough = isDescendantOf(currentElement, 'STRIKE');
activeProperties.underline = isDescendantOf(currentElement, 'U');
activeProperties.insertOrderedList = isDescendantOf(currentElement, 'OL');
activeProperties.insertUnorderedList = isDescendantOf(currentElement, 'UL');
activeProperties.codeBlock = isDescendantOf(currentElement, 'PRE');
updateOptionsState();
hideAllDropdown();
}
//update the UI base on activeProperties
function updateOptionsState() {
setElementActiveState(document.querySelector('#btn-bold'), activeProperties.bold);
setElementActiveState(document.querySelector('#btn-italic'), activeProperties.italic);
setElementActiveState(document.querySelector('#btn-strikethrough'), activeProperties.strikeThrough);
setElementActiveState(document.querySelector('#btn-underline'), activeProperties.underline);
setElementActiveState(document.querySelector('#btn-ordered-list'), activeProperties.insertOrderedList);
setElementActiveState(document.querySelector('#btn-unordered-list'), activeProperties.insertUnorderedList);
setElementActiveState(document.querySelector('#btn-code-block'), activeProperties.codeBlock);
}
function setElementActiveState(element, isActive) {
if (isActive) element.classList.add('active');
else element.classList.remove('active');
}
function hideAllDropdown() {
styleDropdown.hide();
fontDropdown.hide();
emojiDropdown.hide();
}
//to execute commands on editor
function transform(option, argument) {
editor.document.body.focus();
editor.document.execCommand(option, false, argument);
}
function onOptionClick(element, option) {
transform(option, null);
setElementActiveState(element, activeProperties[option] = !activeProperties[option]);
}
function onCreateLinkClick() {
var link = window.prompt('Enter link URL');
if (link != null) transform('createLink', link);
}
function onInsertImageClick() {
var link = window.prompt('Enter image URL');
if (link != null) transform('insertImage', link);
}
function onAddCodeBlockClick(element) {
//get current selection & range
//more on selection & range at: https://javascript.info/selection-range#selection-events
let selection = editor.window.getSelection();
let range = selection.getRangeAt(0);
//code tag needs to be inside pre tag
//both tags need to have language class
//selected text should be inside code tag
console.log(range.commonAncestorContainer);
//create pre tag and code tag and add content to code tag, add css
if (!isDescendantOf(range.commonAncestorContainer, 'PRE')) {
let preTag = editor.document.createElement('pre');
let codeTag = editor.document.createElement('code');
let selectedText = range.extractContents();
codeTag.classList.add('language-css');
preTag.classList.add('language-css');
codeTag.appendChild(selectedText);
preTag.appendChild(codeTag);
range.insertNode(editor.document.createElement('br'));
range.insertNode(preTag);
setElementActiveState(element, true);
}
//TODO: fix issue - when a empty code block is created the code is entered inside pre tag not code tag
}