45
|
1 // https://fonts.google.com/icons
|
|
2
|
51
|
3 function ajax(url,postData,context) {
|
|
4 let request = new XMLHttpRequest();
|
|
5 let method = postData ? 'POST' : 'GET';
|
|
6 request.open( method, url );
|
|
7 if( postData )
|
|
8 request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
|
|
9 request.onload = function() {
|
|
10 if( request.status !== 200 ) {
|
|
11 window.console && console.log( 'ajax failed: ' + request.status );
|
|
12 if( request.responseText )
|
|
13 document.write('<pre>'+request.responseText+'</pre>');
|
|
14 return;
|
|
15 }
|
|
16 eval( request.responseText );
|
|
17 };
|
|
18 request.send(postData);
|
|
19 }
|
|
20
|
48
|
21 function upload(input,callback) {
|
44
|
22 let file = input.files[0];
|
|
23 input.value = null;
|
|
24 let request = new XMLHttpRequest();
|
|
25 let url = 'https://upload.uploadcare.com/base/';
|
|
26 request.open( 'POST', url );
|
|
27 request.onload = function() {
|
|
28 if( request.status !== 200 ) {
|
|
29 let err = 'ajax failed: ' + request.status;
|
|
30 if( request.responseText ) {
|
|
31 err += '\n' + request.responseText;
|
|
32 document.write('<pre>'+request.responseText+'</pre>');
|
|
33 }
|
|
34 console.log(err);
|
|
35 ajax( '/error_log.js', 'err='+encodeURIComponent(err) );
|
|
36 return;
|
|
37 }
|
|
38 let response = JSON.parse(request.responseText);
|
|
39 let filename = file.name;
|
|
40 let url = 'https://ucarecdn.com/' + response.file + '/' + filename;
|
|
41 callback(input,url,filename);
|
|
42 };
|
|
43 let formData = new FormData();
|
|
44 formData.append( 'UPLOADCARE_PUB_KEY', 'fe3d30f3088a50941d45' );
|
|
45 formData.append( 'file', file );
|
|
46 request.send(formData);
|
|
47 }
|
|
48
|
|
49 function bbcodeCreate(div,options) {
|
46
|
50 if( typeof(div) === 'string' ) {
|
44
|
51 div = document.querySelector(div);
|
46
|
52 if(!div) throw 'selector not found';
|
|
53 }
|
|
54 options = options || {};
|
44
|
55 let content = options.content || '';
|
|
56 let save = options.save;
|
|
57 let cancel = options.cancel;
|
|
58 let html = `\
|
50
|
59 <div bbcode_editor>
|
48
|
60 <textarea name=bbcode>${content}</textarea>
|
51
|
61 <div preview from_bbcode></div>
|
45
|
62 <div buttons>
|
48
|
63 <button type=button bold title="Bold"><img src="/bbcode/icons/format_bold.svg"></button>
|
|
64 <button type=button italic title="Italic"><img src="/bbcode/icons/format_italic.svg"></button>
|
|
65 <button type=button underline title="Underline"><img src="/bbcode/icons/format_underlined.svg"></button>
|
|
66 <button type=button strikethrough title="Strikethrough"><img src="/bbcode/icons/format_strikethrough.svg"></button>
|
|
67 <button type=button sub title="Subscript"><img src="/bbcode/icons/subscript.svg"></button>
|
|
68 <button type=button sup title="Superscript"><img src="/bbcode/icons/superscript.svg"></button>
|
|
69 <button type=button ul title="Bullet list"><img src="/bbcode/icons/format_list_bulleted.svg"></button>
|
|
70 <button type=button ol title="Numbered list"><img src="/bbcode/icons/format_list_numbered.svg"></button>
|
49
|
71 <button type=button code_block title="Code block"><img src="/bbcode/icons/code_blocks.svg"></button>
|
|
72 <button type=button code_inline title="Inline code"><img src="/bbcode/icons/code.svg"></button>
|
52
|
73 <button type=button convert_urls checked title="Convert URLs"><img src="/bbcode/icons/media_link.svg"></button>
|
|
74 <input type=hidden name=convert_urls value=true>
|
48
|
75 <button type=button more checked title="More..."><img src="/bbcode/icons/more_horiz.svg"></button>
|
|
76 <input type=file>
|
|
77 <button type=button upload title="Upload File"><img src="/bbcode/icons/file_upload.svg"></button>
|
51
|
78 <button type=button preview title="Preview"><img src="/bbcode/icons/preview.svg"></button>
|
44
|
79 ` ;
|
|
80 if(save) {
|
|
81 html += `\
|
45
|
82 <button type=button save title="Send message"><img src="/bbcode/icons/send.svg"></button>
|
44
|
83 ` ;
|
|
84 }
|
|
85 if(cancel) {
|
|
86 html += `\
|
45
|
87 <button type=button cancel title="Cancel"><img src="/bbcode/icons/cancel.svg"></button>
|
44
|
88 ` ;
|
|
89 }
|
|
90 html += `\
|
45
|
91 </div>
|
44
|
92 </div>
|
|
93 ` ;
|
|
94 div.innerHTML = html;
|
48
|
95
|
51
|
96 let enabledInPreview = [];
|
52
|
97 let convertUrls = true;
|
51
|
98
|
|
99 if(save) {
|
|
100 let button = div.querySelector('button[save]');
|
52
|
101 button.onclick = function(event) {
|
|
102 event.convertUrls = convertUrls;
|
|
103 save(event);
|
|
104 };
|
51
|
105 enabledInPreview.push(button);
|
|
106 }
|
|
107 if(cancel) {
|
|
108 let button = div.querySelector('button[cancel]');
|
|
109 button.onclick = cancel;
|
|
110 enabledInPreview.push(button);
|
|
111 }
|
48
|
112
|
|
113 let textarea = div.querySelector('textarea');
|
|
114 function fixTextarea() {
|
|
115 let height = textarea.scrollHeight;
|
|
116 if( height > textarea.clientHeight ) {
|
|
117 textarea.style.height = (height+2) + "px";
|
|
118 }
|
|
119 };
|
|
120 textarea.oninput = fixTextarea;
|
|
121 fixTextarea();
|
|
122
|
52
|
123 function toggle(button) {
|
|
124 let checked = button.getAttribute('checked') !== null;
|
|
125 checked = !checked; // toggle
|
|
126 if( checked ) {
|
|
127 button.setAttribute('checked','');
|
|
128 } else {
|
|
129 button.removeAttribute('checked');
|
|
130 }
|
|
131 return checked;
|
|
132 }
|
|
133
|
48
|
134 let moreButton = div.querySelector('button[more]');
|
|
135 function more() {
|
52
|
136 let checked = toggle(moreButton);
|
|
137 let buttons = moreButton.parentNode.querySelectorAll('button');
|
48
|
138 if( checked ) {
|
|
139 for( let b of buttons ) {
|
52
|
140 if( b === moreButton )
|
|
141 break;
|
|
142 b.removeAttribute('hidden');
|
|
143 }
|
|
144 } else {
|
|
145 for( let b of buttons ) {
|
|
146 if( b === moreButton )
|
48
|
147 break;
|
|
148 b.setAttribute('hidden','');
|
|
149 }
|
|
150 }
|
|
151 };
|
|
152 moreButton.onclick = more;
|
|
153 more();
|
51
|
154 enabledInPreview.push(moreButton);
|
|
155
|
|
156 let divPreview = div.querySelector('div[preview]');
|
52
|
157 function contextPreview(bbcode,html) {
|
|
158 textarea.value = bbcode;
|
51
|
159 divPreview.innerHTML = html;
|
|
160 }
|
|
161 let previewButton = div.querySelector('button[preview]');
|
|
162 function preview() {
|
52
|
163 let checked = toggle(previewButton);
|
|
164 let buttons = previewButton.parentNode.querySelectorAll('button');
|
51
|
165 if( checked ) {
|
52
|
166 for( let b of buttons ) {
|
|
167 if( !enabledInPreview.includes(b) )
|
|
168 b.disabled = true;
|
|
169 }
|
|
170 textarea.style.display = 'none';
|
|
171 divPreview.style.display = 'block';
|
|
172 let url = '/bbcode/preview.js?text=' + encodeURIComponent(textarea.value) + '&convert_urls=' + convertUrls;
|
|
173 ajax( url, null, {preview: contextPreview} );
|
|
174 } else {
|
51
|
175 for( let b of buttons ) {
|
|
176 b.disabled = false;
|
|
177 }
|
|
178 textarea.style.display = 'initial';
|
|
179 divPreview.style.display = 'none';
|
|
180 textarea.focus();
|
|
181 }
|
|
182 }
|
|
183 previewButton.onclick = preview;
|
|
184 enabledInPreview.push(previewButton);
|
48
|
185
|
52
|
186 let convertUrlsButton = div.querySelector('button[convert_urls]');
|
|
187 let convertUrlsInput = div.querySelector('input[name="convert_urls"]');
|
|
188 function toggleConvertUrls() {
|
|
189 convertUrls = toggle(convertUrlsButton);
|
|
190 convertUrlsInput.value = convertUrls;
|
|
191 }
|
|
192 convertUrlsButton.onclick = toggleConvertUrls;
|
|
193
|
48
|
194 function add(tag,openTag,closeTag) {
|
|
195 let button = div.querySelector('button['+tag+']');
|
|
196 button.onclick = function() {
|
|
197 let start = textarea.selectionStart;
|
|
198 let end = textarea.selectionEnd;
|
|
199 textarea.setRangeText(closeTag,end,end);
|
|
200 textarea.setRangeText(openTag,start,start);
|
|
201 let len = openTag.length;
|
|
202 textarea.setSelectionRange(start+len,end+len);
|
|
203 fixTextarea();
|
|
204 textarea.focus();
|
|
205 };
|
|
206 }
|
|
207 add('bold','[b]','[/b]');
|
|
208 add('italic','[i]','[/i]');
|
|
209 add('underline','[u]','[/u]');
|
|
210 add('strikethrough','[s]','[/s]');
|
|
211 add('sub','[sub]','[/sub]');
|
|
212 add('sup','[sup]','[/sup]');
|
|
213 add('ul','[list]\n[item]','[/item]\n[/list]');
|
|
214 add('ol','[list=1]\n[item]','[/item]\n[/list]');
|
49
|
215 add('code_block','[code]','[/code]');
|
|
216 add('code_inline','[code=inline]','[/code]');
|
48
|
217
|
|
218 let fileInput = div.querySelector('input[type="file"]');
|
|
219 div.querySelector('button[upload]').onclick = function(){ fileInput.click(); };
|
|
220 function uploaded(input,url,filename) {
|
|
221 textarea.setRangeText(url,textarea.selectionStart,textarea.selectionEnd,'select');
|
|
222 textarea.focus();
|
|
223 }
|
|
224 fileInput.onchange = function() { upload(fileInput,uploaded); };
|
44
|
225 }
|