##// END OF EJS Templates
Added form reset
neko259 -
r2034:53ea2770 default
parent child Browse files
Show More
@@ -1,302 +1,329 b''
1 1 var ITEM_FILE_SOURCE = 'fileSource';
2 2 var URL_STICKERS = '/api/stickers';
3 3 var MIN_INPUT_LENGTH = 3;
4 4 var URL_DELIMITER = '\n';
5 5 // TODO This needs to be the same for attachment download time limit.
6 6 var POST_AJAX_TIMEOUT = 30000;
7 var REPLY_TO_MSG = '.reply-to-message';
7 8
8 9 var pastedImages = [];
9 10
10 11 $('input[name=image]').wrap($('<div class="file_wrap"></div>'));
11 12
12 13 $('body').on('change', 'input[name=image]', function(event) {
13 14 var file = event.target.files[0];
14 15
15 16 if(file.type.match('image.*')) {
16 17 var fileReader = new FileReader();
17 18
18 19 fileReader.addEventListener("load", function(event) {
19 20 var wrapper = $('.file_wrap');
20 21
21 22 wrapper.find('.file-thumb').remove();
22 23 wrapper.append(
23 24 $('<div class="file-thumb" style="background-image: url('+event.target.result+')"></div>')
24 25 );
25 26 });
26 27
27 28 fileReader.readAsDataURL(file);
28 29 }
29 30 });
30 31
31 32 var form = $('#form');
32 33 $('textarea').keypress(function(event) {
33 34 if ((event.which == 10 || event.which == 13) && event.ctrlKey) {
34 35 form.find('input[type=submit]').click();
35 36 }
36 37 });
37 38
38 39 $('#preview-button').click(function() {
39 40 var data = {
40 41 raw_text: $('textarea#id_text').val()
41 42 }
42 43
43 44 var diffUrl = '/api/preview/';
44 45
45 46 $.post(diffUrl,
46 47 data,
47 48 function(data) {
48 49 var previewTextBlock = $('#preview-text');
49 50 previewTextBlock.html(data);
50 51 previewTextBlock.show();
51 52
52 53 addScriptsToPost(previewTextBlock);
53 54 })
54 55 });
55 56
56 57 /**
57 58 * Show text in the errors row of the form.
58 59 * @param form
59 60 * @param text
60 61 */
61 62 function showAsErrors(form, text) {
62 63 form.children('.form-errors').remove();
63 64
64 65 if (text.length > 0) {
65 66 var errorList = $('<div class="form-errors">' + text + '<div>');
66 67 errorList.appendTo(form);
67 68 }
68 69 }
69 70
70 71 function addHiddenInput(form, name, value) {
71 72 form.find('input[name=' + name + ']').val(value);
72 73 }
73 74
74 75 function selectFileChoice() {
75 76 var file_input = $('#id_file');
76 77 var url_input = $('#id_file_url');
77 78
78 79 var file_input_row = file_input.parent().parent();
79 80 var url_input_row = url_input.parent().parent();
80 81
81 82 file_input_row.toggle();
82 83 url_input_row.toggle();
83 84 url_input.val('');
84 85 file_input.val('');
85 86
86 87 var source;
87 88 if (file_input_row.is(':visible')) {
88 89 source = 'file';
89 90 } else {
90 91 source = 'url';
91 92 }
92 93 localStorage.setItem(ITEM_FILE_SOURCE, source);
93 94 }
94 95
95 96 function getPostTextarea() {
96 97 return $('textarea#id_text');
97 98 }
98 99
99 100 function addOnImagePaste() {
100 101 $('#id_file_1').on('paste', function(event) {
101 102 var items = (event.clipboardData || event.originalEvent.clipboardData).items;
102 103 for (index in items) {
103 104 var item = items[index];
104 105 if (item.kind === 'file') {
105 106 var blob = item.getAsFile();
106 107
107 108 pastedImages.push(blob);
108 109
109 110 var pastedImagesList = $('#pasted-images');
110 111 if (pastedImagesList.length === 0) {
111 112 pastedImagesList = $('<div id="pasted-images" />');
112 113 $('#id_file_1').parent().append(pastedImagesList);
113 114 }
114 115
115 116 var fr = new FileReader();
116 117 fr.onload = function () {
117 118 var img = $('<img class="image-preview" />');
118 119 img.attr('src', fr.result);
119 120 pastedImagesList.append(img);
120 121 img.on("click", function() {
121 122 // Remove the image from all lists
122 123 var itemIndex = $(this).index();
123 124 pastedImages.splice(itemIndex, 1);
124 125 $(this).remove();
125 126 });
126 127 };
127 128 fr.readAsDataURL(blob);
128 129 }
129 130 }
130 131 });
131 132 }
132 133
133 134 /**
134 135 * When the form is posted, this method will be run as a callback
135 136 */
136 137 function updateOnPost(response, statusText, xhr, form) {
137 138 var json = $.parseJSON(response);
138 139 var status = json.status;
139 140 var url = json.url;
140 141
141 142 showAsErrors(form, '');
142 143 $('.post-form-w').unblock();
143 144
144 145 if (status === 'ok') {
145 146 if (url) {
146 147 document.location = url;
147 148 } else {
148 149 resetForm();
149 150 getThreadDiff();
150 151 scrollToBottom();
151 152 }
152 153 } else {
153 154 var errors = json.errors;
154 155 for (var i = 0; i < errors.length; i++) {
155 156 var fieldErrors = errors[i];
156 157
157 158 var error = fieldErrors.errors;
158 159
159 160 showAsErrors(form, error);
160 161 }
161 162 }
162 163 }
163 164
164 165 function initAjaxForm(openingPostId) {
165 166 var form = $('#form');
166 167
167 168 var url = '/api/add_post/';
168 169 if (openingPostId) {
169 170 url += openingPostId + '/';
170 171 }
171 172
172 173 if (form.length > 0) {
173 174 var options = {
174 175 beforeSubmit: function(arr, form, options) {
175 176 $('.post-form-w').block({ message: gettext('Sending message...') });
176 177
177 178 $.each(pastedImages, function(i, blob) {
178 179 arr.push({
179 180 name: "file_0",
180 181 value: blob
181 182 });
182 183 });
183 184 },
184 185 success: updateOnPost,
185 186 error: function(xhr, textStatus, errorString) {
186 187 var errorText = gettext('Server error: ') + textStatus;
187 188 if (errorString) {
188 189 errorText += ' / ' + errorString;
189 190 }
190 191 showAsErrors(form, errorText);
191 192 $('.post-form-w').unblock();
192 193 },
193 194 url: url,
194 195 timeout: POST_AJAX_TIMEOUT
195 196 };
196 197
197 198 form.ajaxForm(options);
198 199 }
199 200 }
200 201
202 function getForm() {
203 return $('.post-form-w');
204 }
205
206 /**
207 * Clear all entered values in the form fields
208 */
209 function resetForm() {
210 var form = getForm();
211
212 form.find('input:text, input:password, input:file, textarea').val('');
213 form.find('input:radio, input:checkbox').removeAttr('checked').removeAttr('selected');
214 pastedImages = [];
215 $('#pasted-images').remove();
216 $('.file_wrap').find('.file-thumb').remove();
217 $('#preview-text').hide();
218
219 resetFormPosition(form);
220 }
221
222 function resetFormPosition(form) {
223 form.insertBefore($('footer'));
224
225 $(REPLY_TO_MSG).hide();
226 }
227
201 228 $(document).ready(function() {
202 229 var powDifficulty = parseInt($('body').attr('data-pow-difficulty'));
203 230 if (powDifficulty > 0 && typeof SharedWorker != 'undefined') {
204 231 var worker = new SharedWorker($('.post-form').attr('data-pow-script'));
205 232 worker.port.onmessage = function(e) {
206 233 var form = $('#form');
207 234 addHiddenInput(form, 'timestamp', e.data.timestamp);
208 235 addHiddenInput(form, 'iteration', e.data.iteration);
209 236 addHiddenInput(form, 'guess', e.data.guess);
210 237
211 238 form.submit();
212 239 $('.post-form-w').unblock();
213 240 };
214 241 worker.onerror = function(event){
215 242 throw new Error(event.message + " (" + event.filename + ":" + event.lineno + ")");
216 243 };
217 244 worker.port.start();
218 245
219 246 var form = $('#form');
220 247 var submitButton = form.find('input[type=submit]');
221 248 submitButton.click(function() {
222 249 showAsErrors(form, gettext('Computing PoW...'));
223 250 $('.post-form-w').block({ message: gettext('Computing PoW...') })
224 251
225 252 var msg = $('textarea#id_text').val().trim();
226 253
227 254 var data = {
228 255 msg: msg,
229 256 difficulty: parseInt($('body').attr('data-pow-difficulty')),
230 257 hasher: $('.post-form').attr('data-hasher')
231 258 };
232 259 worker.port.postMessage(data);
233 260
234 261 return false;
235 262 });
236 263 }
237 264
238 265 var $fileSourceButton = $('#file-source-button');
239 266 if (window.localStorage) {
240 267 var source = localStorage.getItem(ITEM_FILE_SOURCE);
241 268 if (source == null) {
242 269 source = 'file';
243 270 }
244 271 if (source == 'file') {
245 272 $('#id_file_url').parent().parent().hide();
246 273 } else {
247 274 $('#id_file').parent().parent().hide();
248 275 }
249 276
250 277 $fileSourceButton.click(function() {
251 278 selectFileChoice();
252 279 });
253 280 } else {
254 281 $fileSourceButton.hide();
255 282 }
256 283
257 284 addOnImagePaste();
258 285
259 286 // Stickers autocomplete
260 287 function split( val ) {
261 288 return val.split(URL_DELIMITER);
262 289 }
263 290
264 291 function extractLast( term ) {
265 292 return split(term).pop();
266 293 }
267 294
268 295 $('#id_file_1').autocomplete({
269 296 source: function( request, response ) {
270 297 $.getJSON(URL_STICKERS, {
271 298 term: extractLast( request.term )
272 299 }, response);
273 300 },
274 301 search: function() {
275 302 // custom minLength
276 303 var term = extractLast( this.value );
277 304 if (term.length < MIN_INPUT_LENGTH) {
278 305 return false;
279 306 }
280 307 },
281 308 focus: function() {
282 309 // prevent value inserted on focus
283 310 return false;
284 311 },
285 312 select: function( event, ui ) {
286 313 var terms = split( this.value );
287 314 // remove the current input
288 315 terms.pop();
289 316 // add the selected item
290 317 terms.push( ui.item.alias );
291 318 // add placeholder to get the comma-and-space at the end
292 319 terms.push("");
293 320 this.value = terms.join(URL_DELIMITER);
294 321 return false;
295 322 }
296 323 })
297 324 .autocomplete( "instance" )._renderItem = function( ul, item ) {
298 325 return $( "<li>" )
299 326 .append( "<div>" + '<img src="' + item.thumb + '">' + '<br />' + item.alias + "</div>" )
300 327 .appendTo( ul );
301 328 };
302 329 });
@@ -1,167 +1,142 b''
1 1 /*
2 2 @licstart The following is the entire license notice for the
3 3 JavaScript code in this page.
4 4
5 5
6 6 Copyright (C) 2013 neko259
7 7
8 8 The JavaScript code in this page is free software: you can
9 9 redistribute it and/or modify it under the terms of the GNU
10 10 General Public License (GNU GPL) as published by the Free Software
11 11 Foundation, either version 3 of the License, or (at your option)
12 12 any later version. The code is distributed WITHOUT ANY WARRANTY;
13 13 without even the implied warranty of MERCHANTABILITY or FITNESS
14 14 FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
15 15
16 16 As additional permission under GNU GPL version 3 section 7, you
17 17 may distribute non-source (e.g., minimized or compacted) forms of
18 18 that code without the copy of the GNU GPL normally required by
19 19 section 4, provided you include this license notice and a URL
20 20 through which recipients can access the Corresponding Source.
21 21
22 22 @licend The above is the entire license notice
23 23 for the JavaScript code in this page.
24 24 */
25 25
26 26 var REPLY_TO_MSG = '.reply-to-message';
27 27 var REPLY_TO_MSG_ID = '#reply-to-message-id';
28 28
29 29 var $html = $("html, body");
30 30
31 31 function moveCaretToEnd(el) {
32 32 var newPos = el.val().length;
33 33 el[0].setSelectionRange(newPos, newPos);
34 34 }
35 35
36 function getForm() {
37 return $('.post-form-w');
38 }
39
40 /**
41 * Clear all entered values in the form fields
42 */
43 function resetForm() {
44 var form = getForm();
45
46 form.find('input:text, input:password, input:file, textarea').val('');
47 form.find('input:radio, input:checkbox').removeAttr('checked').removeAttr('selected');
48 pastedImages = [];
49 $('#pasted-images').remove();
50 $('.file_wrap').find('.file-thumb').remove();
51 $('#preview-text').hide();
52
53 resetFormPosition(form);
54 }
55
56 function resetFormPosition(form) {
57 form.insertAfter($('.thread'));
58
59 $(REPLY_TO_MSG).hide();
60 }
61 36
62 37 function showFormAfter(blockToInsertAfter) {
63 38 var form = getForm();
64 39 form.insertAfter(blockToInsertAfter);
65 40
66 41 form.show();
67 42 $(REPLY_TO_MSG_ID).text(blockToInsertAfter.attr('id'));
68 43 $(REPLY_TO_MSG).show();
69 44 }
70 45
71 46 function addQuickReply(postId) {
72 47 var blockToInsert = null;
73 48 var textAreaJq = getPostTextarea();
74 49 var postLinkRaw = '[post]' + postId + '[/post]'
75 50 var textToAdd = '';
76 51
77 52 if (postId != null) {
78 53 var post = $('#' + postId);
79 54
80 55 // If this is not OP, add reflink to the post. If there already is
81 56 // the same reflink, don't add it again.
82 57 var postText = textAreaJq.val();
83 58 if (!post.is(':first-child') && postText.indexOf(postLinkRaw) < 0) {
84 59 // Insert line break if none is present.
85 60 if (postText.length > 0 && !postText.endsWith('\n') && !postText.endsWith('\r')) {
86 61 textToAdd += '\n';
87 62 }
88 63 textToAdd += postLinkRaw + '\n';
89 64 }
90 65
91 66 textAreaJq.val(textAreaJq.val()+ textToAdd);
92 67 blockToInsert = post;
93 68 } else {
94 69 blockToInsert = $('.thread');
95 70 }
96 71 showFormAfter(blockToInsert);
97 72
98 73 textAreaJq.focus();
99 74
100 75 moveCaretToEnd(textAreaJq);
101 76 }
102 77
103 78 function addQuickQuote() {
104 79 var textAreaJq = getPostTextarea();
105 80
106 81 var quoteButton = $("#quote-button");
107 82 var postId = quoteButton.attr('data-post-id');
108 83 if (postId != null) {
109 84 addQuickReply(postId);
110 85 }
111 86
112 87 var textToAdd = '';
113 88 var selection = window.getSelection().toString();
114 89 if (selection.length == 0) {
115 90 selection = quoteButton.attr('data-text');
116 91 }
117 92 if (selection.length > 0) {
118 93 textToAdd += '[quote]' + selection + '[/quote]\n';
119 94 }
120 95
121 96 textAreaJq.val(textAreaJq.val() + textToAdd);
122 97
123 98 textAreaJq.focus();
124 99
125 100 moveCaretToEnd(textAreaJq);
126 101 }
127 102
128 103 function scrollToBottom() {
129 104 $html.animate({scrollTop: $html.height()}, "fast");
130 105 }
131 106
132 107 function showQuoteButton() {
133 108 var selection = window.getSelection().getRangeAt(0).getBoundingClientRect();
134 109 var quoteButton = $("#quote-button");
135 110 if (selection.width > 0) {
136 111 // quoteButton.offset({ top: selection.top - selection.height, left: selection.left });
137 112 quoteButton.css({top: selection.top + $(window).scrollTop() - 30, left: selection.left});
138 113 quoteButton.show();
139 114
140 115 var text = window.getSelection().toString();
141 116 quoteButton.attr('data-text', text);
142 117
143 118 var rect = window.getSelection().getRangeAt(0).getBoundingClientRect();
144 119 var element = $(document.elementFromPoint(rect.x, rect.y));
145 120 var postId = null;
146 121 if (element.hasClass('post')) {
147 122 postId = element.attr('id');
148 123 } else {
149 124 var postParent = element.parents('.post');
150 125 if (postParent.length > 0) {
151 126 postId = postParent.attr('id');
152 127 }
153 128 }
154 129 quoteButton.attr('data-post-id', postId);
155 130 } else {
156 131 quoteButton.hide();
157 132 }
158 133 }
159 134
160 135 $(document).ready(function() {
161 136 $('body').on('mouseup', function() {
162 137 showQuoteButton();
163 138 });
164 139 $("#quote-button").click(function() {
165 140 addQuickQuote();
166 141 })
167 142 });
@@ -1,44 +1,46 b''
1 1 {% load i18n %}
2 2 {% load board %}
3 3 {% load static %}
4 4
5 5 <div class="post-form-w">
6 6 <script src="{% static 'js/panel.js' %}"></script>
7 7
8 8 <div class="post-form" data-hasher="{% static 'js/3party/sha256.js' %}"
9 9 data-pow-script="{% static 'js/proof_of_work.js' %}">
10 10 {% if new_thread %}
11 11 <div class="form-title">{% trans "Create new thread" %}</div>
12 12 {% else %}
13 13 <div class="form-title">{% trans "Reply to thread" %} #{{ opening_post_id }}<span class="reply-to-message"> {% trans "to message " %} #<span id="reply-to-message-id"></span></span></div>
14 14 {% endif %}
15 15
16 16 <div class="swappable-form-full">
17 17 <form enctype="multipart/form-data" method="post" id="form">{% csrf_token %}
18 18 {{ form.as_div }}
19 19 <div class="form-submit">
20 20 <input type="submit" value="{% trans "Post" %}"/>
21 21 <button id="preview-button" type="button" onclick="return false;">{% trans 'Preview' %}</button>
22 22 </div>
23 23 </form>
24 24 </div>
25 25
26 <div><a href="#" onClick="resetForm(); return false;">{% trans 'Reset form' %}</a></div>
27
26 28 <div>
27 29 {% if new_thread %}
28 30 {% trans 'Tags must be delimited by spaces. Text or image is required.' %}<br />
29 31 {% endif %}
30 32 {% with size=max_file_size|filesizeformat %}
31 33 {% blocktrans %}Max total file size is {{ size }}.{% endblocktrans %}<br />
32 34 {% endwith %}
33 35 {% blocktrans %}Max file number is {{ max_files }}.{% endblocktrans %}
34 36 </div>
35 37
36 38 <div id="preview-text"></div>
37 39 <div><a href="{% url "staticpage" name="help" %}">{% trans 'Help' %}</a></div>
38 40 </div>
39 41 </div>
40 42
41 43 <script src="{% static 'js/form.js' %}"></script>
42 44 <script src="{% static 'js/jquery.form.min.js' %}"></script>
43 45 <script src="{% static 'js/3party/jquery.blockUI.js' %}"></script>
44 46
General Comments 0
You need to be logged in to leave comments. Login now