-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
Copy patheditor.js
161 lines (152 loc) · 5.85 KB
/
editor.js
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
class Editor {
// default parameters:
// defaultForm - when the Editor is initialized, there needs to be a default editor form:
// 1. the main comment form in multi-comment wikis, questions, & research notes.
// 2. the only editor form on /wiki/new and /wiki/edit
// elementIDPrefixes - the ID naming conventions are different depending on context:
// 1. multi-form pages with multiple comments: #comment-preview-123
// 2. /wiki/new and /wiki/edit: #preview-main
constructor(defaultForm = "main", elementIDPrefixes = {}) {
this.commentFormID = defaultForm;
this.elementIDPrefixes = elementIDPrefixes;
this.textarea = $("#text-input-" + this.commentFormID);
// this will get deleted in the next few PRs, so collapsing into one line to pass codeclimate
this.templates = { 'blog': "## The beginning\n\n## What we did\n\n## Why it matters\n\n## How can you help", 'default': "## What I want to do\n\n## My attempt and results\n\n## Questions and next steps\n\n## Why I'm interested", 'support': "## Details about the problem\n\n## A photo or screenshot of the setup", 'event': "## Event details\n\nWhen, where, what\n\n## Background\n\nWho, why", 'question': "## What I want to do or know\n\n## Background story" };
marked.setOptions({
gfm: true,
tables: true,
breaks: true,
pedantic: false,
sanitize: false,
smartLists: true,
langPrefix: 'language-',
highlight: function(code, lang) {
if (lang === 'js') {
return highlighter.javascript(code);
}
return code;
}
});
}
setState(commentFormID) {
this.commentFormID = commentFormID;
this.textarea = $("#text-input-" + commentFormID);
$E.textarea.bind('input propertychange', $E.save);
}
get textAreaElement() {
const textAreaID = "#text-input-" + this.commentFormID;
return $(textAreaID);
}
get textAreaValue() {
return this.textAreaElement.val();
}
get previewElement() {
let previewIDPrefix = "#comment-preview-";
if (this.elementIDPrefixes.hasOwnProperty("preview")) {
// eg. on /wiki/new & /wiki/edit, the preview element is called #preview-main
previewIDPrefix = "#" + this.elementIDPrefixes["preview"] + "-";
}
const previewID = previewIDPrefix + this.commentFormID;
return $(previewID);
}
// wraps currently selected text in textarea with strings a and b
wrap(a, b, newlineDesired = false, fallback) {
const selectionStart = this.textAreaElement[0].selectionStart;
const selectionEnd = this.textAreaElement[0].selectionEnd;
const selection = fallback || this.textAreaValue.substring(selectionStart, selectionEnd); // fallback if nothing has been selected, and we're simply dealing with an insertion point
let newText = newlineDesired ? a + selection + b + "\n\n" : a + selection + b; // ie. ** + selection + ** (wrapping selection in bold)
const selectionStartsMidText = this.textAreaElement[0].selectionStart > 0;
if (newlineDesired && selectionStartsMidText) { newText = "\n" + newText; }
const textLength = this.textAreaValue.length;
const textBeforeSelection = this.textAreaValue.substring(0, selectionStart);
const textAfterSelection = this.textAreaValue.substring(selectionEnd, textLength);
this.textAreaElement.val(textBeforeSelection + newText + textAfterSelection);
}
bold() {
this.wrap('**', '**');
}
italic() {
this.wrap('_', '_');
}
link(uri) {
uri = prompt('Enter a URL');
if (!uri) { uri = ""; }
this.wrap(
'[',
'](' + uri + ')'
);
}
image(src) {
this.wrap(
'\n![',
'](' + src + ')\n'
);
}
// these header formatting functions are not used anywhere, so commenting them out for now to pass codeclimate:
// h1() {
// this.wrap('#','')
// }
h2() {
this.wrap('##', '');
}
// h3() {
// this.wrap('###','')
// }
// h4() {
// this.wrap('####','')
// }
// h5() {
// this.wrap('#####','')
// }
// h6() {
// this.wrap('######','')
// }
// h7() {
// this.wrap('#######','')
// }
// this function is dedicated to Don Blair https://github.com/donblair
save() {
localStorage.setItem('plots:lastpost', this.textAreaValue);
}
recover() {
this.textAreaElement.val(localStorage.getItem('plots:lastpost'));
}
apply_template(template) {
if(this.textAreaValue == ""){
this.textAreaElement.val(this.templates[template])
}else if((this.textAreaValue == this.templates['event']) || (this.textAreaValue == this.templates['default']) || (this.textAreaValue == this.templates['support'])){
this.textAreaElement.val(this.templates[template])
}else{
this.textAreaElement.val(this.textAreaValue+'\n\n'+this.templates[template])
}
}
generate_preview(id,text) {
$('#' + id)[0].innerHTML = marked(text)
}
toggle_preview() {
// if the element is part of a multi-comment page,
// ensure to grab the current element and not the other comment element.
const previewBtn = $("#toggle-preview-button-" + this.commentFormID);
const commentFormBody = $("#comment-form-body-" + this.commentFormID);
this.previewElement[0].innerHTML = marked(this.textAreaValue);
this.previewElement.toggle();
commentFormBody.toggle();
this.toggleButtonPreviewMode(previewBtn);
}
toggleButtonPreviewMode(previewBtn) {
let isPreviewing = previewBtn.attr('data-previewing');
// If data-previewing attribute is not present -> we are not in "preview" mode
if (!isPreviewing) {
previewBtn.attr('data-previewing', 'false');
isPreviewing = 'false';
}
if (isPreviewing === 'false') {
previewBtn.attr('data-previewing', 'true');
let previewText = previewBtn.attr('data-previewing-text');
previewBtn.text(previewText);
} else {
previewBtn.attr('data-previewing', 'false');
previewBtn.text('Preview');
}
}
}