misago-posting.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. // Controller for posting actions
  2. $(function() {
  3. MisagoPreview = function(_controller, options) {
  4. this.$form = options.form;
  5. this.$area = options.$area;
  6. this.$frame = this.$area.find('.frame');
  7. this.is_visible = true;
  8. this.$markup = this.$area.find('.misago-markup');
  9. this.$message = this.$area.find('.empty-message');
  10. if (this.$markup.text() == '') {
  11. this.$markup.hide();
  12. } else {
  13. this.$message.hide();
  14. Misago.Onebox.activate(this.$markup);
  15. }
  16. this.api_url = options.api_url;
  17. this.active = true;
  18. this.previewed_data = this.$form.serialize() + '&preview=1';
  19. this.frequency = 1500;
  20. this.height = this.$markup.height();
  21. var _this = this;
  22. this.last_key_press = (new Date().getTime() / 1000);
  23. this.$form.find('.misago-editor textarea').keyup(function() {
  24. _this.last_key_press = (new Date().getTime() / 1000);
  25. })
  26. this.update_height = function() {
  27. this.$frame.height(this.$form.find('.misago-editor').innerHeight() - this.$area.find('.preview-footer').outerHeight());
  28. }
  29. this.update_height();
  30. this.update = function() {
  31. var form_data = _this.$form.serialize() + '&preview=1';
  32. var last_key = (new Date().getTime() / 1000) - _this.last_key_press;
  33. if (_this.previewed_data != form_data && last_key > 2) {
  34. $.post(_this.api_url, form_data, function(data) {
  35. var scroll = _this.$markup.height() - _this.$frame.scrollTop();
  36. if (data.preview) {
  37. if (_this.$message.is(":visible")) {
  38. _this.$message.fadeOut(function() {
  39. _this.$markup.html(data.preview);
  40. Misago.Onebox.activate(_this.$markup);
  41. _this.$markup.fadeIn();
  42. });
  43. } else {
  44. _this.$markup.html(data.preview);
  45. Misago.Onebox.activate(_this.$markup);
  46. }
  47. if (_this.$markup.height() > _this.height) {
  48. _this.$frame.scrollTop(_this.$markup.height() - scroll);
  49. }
  50. } else {
  51. _this.$markup.fadeOut(function() {
  52. _this.$markup.html("");
  53. _this.$message.fadeIn();
  54. _this.$frame.scrollTop(0);
  55. });
  56. }
  57. Misago.DOM.changed();
  58. _this.previewed_data = form_data;
  59. // set timeout
  60. if (_this.active) {
  61. window.setTimeout(function() {
  62. _this.update();
  63. }, _this.frequency);
  64. }
  65. });
  66. } else if (_this.active) {
  67. window.setTimeout(function() {
  68. _this.update();
  69. }, _this.frequency);
  70. }
  71. }
  72. this.stop = function() {
  73. this.active = false;
  74. }
  75. }
  76. MisagoPosting = function() {
  77. this._clear = function() {
  78. this.$spacer = null;
  79. this.$container = null;
  80. this.$form = null;
  81. this.$textarea = null;
  82. this.$ajax_loader = null;
  83. this.$ajax_complete = null;
  84. this.$preview = null;
  85. this.submitted = false;
  86. this.posted = false;
  87. this.on_cancel = null;
  88. this.on_post = null;
  89. this.is_resized = false;
  90. this.min_height = 102;
  91. this.max_height = Math.round($(window).height() * 0.6);
  92. }
  93. this._clear();
  94. var _this = this;
  95. this.init = function(options) {
  96. if (this.$form !== null) {
  97. return false;
  98. }
  99. this.$form = $('#posting-form');
  100. this.$container = this.$form.parent();
  101. this.$spacer = this.$container.parent();
  102. this.$textarea = this.$form.find('textarea');
  103. if (options.on_cancel !== undefined) {
  104. this.on_cancel = options.on_cancel
  105. } else {
  106. this.on_cancel = null;
  107. }
  108. if (options.on_post !== undefined) {
  109. this.on_post = options.on_post
  110. } else {
  111. this.on_post = null;
  112. }
  113. this.$ajax_loader = this.$container.find('.ajax-loader');
  114. this.$ajax_complete = this.$container.find('.ajax-complete');
  115. var editor_height = Misago.Storage.get('posting_height', this.min_height);
  116. if (editor_height > this.max_height) {
  117. editor_height = this.max_height
  118. } else if (editor_height < this.min_height) {
  119. editor_height = this.min_height
  120. }
  121. this.$textarea.height(editor_height);
  122. // preview
  123. this.$editor_col = this.$container.find('.col-editor');
  124. this.editor_preview_on_class = 'col-md-6 col-editor';
  125. this.editor_preview_off_class = 'col-md-12 col-editor';
  126. this.$preview_col = this.$container.find('.col-preview');
  127. this.$preview = new MisagoPreview(this, {$area: this.$form.find('.editor-preview'), form: this.$form, api_url: options.api_url});
  128. this.$preview.update();
  129. this.$preview_btn = this.$form.find('.btn-preview');
  130. this.preview_on_icon = "fa fa-file-text-o fa-fw";
  131. this.preview_off_icon = "fa fa-file-o fa-fw";
  132. this.$preview.is_visible = Misago.Storage.get('posting_preview', "true") == "true";
  133. this.hide_preview = function() {
  134. this.$preview.stop();
  135. this.$preview_col.hide();
  136. this.$preview_btn.find('.fa').attr('class', this.preview_off_icon);
  137. this.$editor_col.attr('class', this.editor_preview_off_class);
  138. }
  139. this.show_preview = function() {
  140. this.$preview.update();
  141. this.$preview_col.show();
  142. this.$preview_btn.find('.fa').attr('class', this.preview_on_icon);
  143. this.$editor_col.attr('class', this.editor_preview_on_class);
  144. }
  145. if (!this.$preview.is_visible) {
  146. this.hide_preview();
  147. }
  148. this.$preview_btn.click(function() {
  149. if (_this.$preview.is_visible) {
  150. _this.$preview.is_visible = false;
  151. _this.hide_preview();
  152. Misago.Storage.set('posting_preview', "false");
  153. } else {
  154. _this.$preview.is_visible = true;
  155. _this.show_preview();
  156. Misago.Storage.set('posting_preview', "true");
  157. }
  158. });
  159. // spacer
  160. this.$spacer.height(this.$container.outerHeight() - ($(document).height() - this.$spacer.offset().top));
  161. this.$container.addClass('fixed');
  162. // resize
  163. this.$container.find('.resize-handle').mousedown(function(e) {
  164. _this.is_resized = {start_height: _this.$textarea.height(), start_pageY: e.pageY};
  165. });
  166. $(document).mouseup(function() {
  167. if (_this.is_resized !== false) {
  168. Misago.Storage.set('posting_height', _this.$textarea.height());
  169. }
  170. _this.is_resized = false;
  171. });
  172. $(document).mousemove(function(e) {
  173. if (_this.is_resized !== false) {
  174. var height_change = _this.is_resized.start_pageY - e.pageY;
  175. var new_height = _this.is_resized.start_height + height_change;
  176. if (new_height > _this.max_height) {
  177. new_height = _this.max_height;
  178. } else if (new_height < _this.min_height) {
  179. new_height = _this.min_height;
  180. }
  181. _this.$textarea.height(new_height);
  182. _this.$preview.update_height();
  183. }
  184. });
  185. // submit
  186. this.$container.find('button[name="submit"]').click(function() {
  187. if (!_this.submitted && !_this.posted) {
  188. _this.submitted = true; // lock submit process until after response
  189. _this.$ajax_loader.addClass('in');
  190. var form_data = _this.$form.serialize() + '&submit=1';
  191. $.post(options.api_url, form_data, function(data) {
  192. _this.$ajax_loader.removeClass('in');
  193. if (data.post_url !== undefined) {
  194. _this.posted = true;
  195. _this.$ajax_loader.hide();
  196. var on_post = true;
  197. if (_this.on_post != null) {
  198. on_post = _this.on_post(data);
  199. }
  200. if (on_post) {
  201. _this.$ajax_complete.addClass('in');
  202. var past_location = String(window.location.href);
  203. window.location.href = data.post_url.replace('#post', '#goto-post');
  204. if (past_location.indexOf(window.location.href)) {
  205. window.location.reload();
  206. }
  207. }
  208. } else if (data.errors !== undefined) {
  209. Misago.Alerts.error(data.errors[0]);
  210. } else if (data.interrupt !== undefined) {
  211. Misago.Alerts.info(data.interrupt);
  212. } else {
  213. Misago.Alerts.error();
  214. }
  215. _this.submitted = false;
  216. });
  217. }
  218. return false;
  219. })
  220. this.$container.find('button[name="cancel"]').click(function() {
  221. _this.cancel();
  222. });
  223. return true;
  224. }
  225. // public api
  226. this.load = function(options) {
  227. if (this.$form !== null) {
  228. return false;
  229. }
  230. $.get(options.api_url, function(data) {
  231. $('#reply-form-placeholder').html(data);
  232. Misago.DOM.changed();
  233. _this.init(options);
  234. Misago.DOM.changed();
  235. if (options.on_load !== undefined) {
  236. options.on_load();
  237. }
  238. });
  239. }
  240. this.cancel = function() {
  241. if (this.$form !== null) {
  242. if (this.has_content() && !this.posted) {
  243. var decision = confirm(lang_dismiss_editor);
  244. if (!decision) {
  245. return false;
  246. }
  247. }
  248. this.$preview.stop();
  249. this.$spacer.fadeOut(function() {
  250. $(this).remove();
  251. $('.main-footer').show();
  252. });
  253. if (this.on_cancel !== null) {
  254. this.on_cancel();
  255. }
  256. this._clear();
  257. return true;
  258. }
  259. return false;
  260. }
  261. this.is_open = function() {
  262. return this.$form !== null;
  263. }
  264. this.has_content = function() {
  265. if (_this.$form !== null) {
  266. var length = $.trim(_this.$form.find('input[name="title"]').val()).length;
  267. length += $.trim(_this.$form.find('textarea').val()).length;
  268. return length > 0;
  269. } else {
  270. return false;
  271. }
  272. }
  273. this.append = function(text) {
  274. var $textarea = this.$form.find('textarea');
  275. $textarea.val($.trim($.trim($textarea.val()) + '\n\n' + text));
  276. $textarea.scrollTop($textarea.prop("scrollHeight"));
  277. this.$preview.update();
  278. }
  279. }
  280. Misago.Posting = new MisagoPosting();
  281. $(window).on("beforeunload", function() {
  282. if (Misago.Posting.is_open() && Misago.Posting.has_content() && !Misago.Posting.posted) {
  283. return lang_dismiss_editor;
  284. }
  285. })
  286. // we are meddling in window.location, which means we need js to fix scrolls to fragments
  287. if(window.location.hash.indexOf('#goto-post-') == 0) {
  288. window.location.hash = window.location.hash.replace('#goto-post', '#post');
  289. }
  290. });