nodebb-plugin-composer-default 10.3.20 → 10.3.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/library.js CHANGED
@@ -241,7 +241,7 @@ function generateDiscardRoute(req, topicData) {
241
241
  }
242
242
 
243
243
  async function generateBody(req, postData) {
244
- let body = '';
244
+ let body;
245
245
  // Quoted reply
246
246
  if (req.query.toPid && parseInt(req.query.quoted, 10) === 1 && postData) {
247
247
  const username = await user.getUserField(postData.uid, 'username');
@@ -250,8 +250,9 @@ async function generateBody(req, postData) {
250
250
  `> ${postData ? `${postData.content.replace(/\n/g, '\n> ')}\n\n` : ''}`;
251
251
  } else if (req.query.body || req.query.content) {
252
252
  body = validator.escape(String(req.query.body || req.query.content));
253
+ } else {
254
+ body = postData ? postData.content : '';
253
255
  }
254
- body = postData ? postData.content : '';
255
256
  return translator.escape(body);
256
257
  }
257
258
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-composer-default",
3
- "version": "10.3.20",
3
+ "version": "10.3.22",
4
4
  "description": "Default composer for NodeBB",
5
5
  "main": "library.js",
6
6
  "repository": {
@@ -33,8 +33,8 @@
33
33
  "validator": "^13.7.0"
34
34
  },
35
35
  "devDependencies": {
36
- "eslint": "^9.25.1",
37
- "eslint-config-nodebb": "^1.1.4",
36
+ "eslint": "^10.0.0",
37
+ "eslint-config-nodebb": "^2.0.1",
38
38
  "eslint-plugin-import": "^2.31.0"
39
39
  }
40
40
  }
@@ -74,7 +74,7 @@ $(document).ready(function () {
74
74
  data.title = data.title || data.topicName;
75
75
  if (config['composer-default'].composeRouteEnabled !== 'on') {
76
76
  require(['composer'], function (composer) {
77
- var topicUUID = composer.findByTid(data.tid);
77
+ const topicUUID = composer.findByTid(data.tid);
78
78
  composer.addQuote({
79
79
  tid: data.tid,
80
80
  toPid: data.pid,
@@ -3,7 +3,7 @@
3
3
  define('composer/autocomplete', [
4
4
  'composer/preview', 'autocomplete',
5
5
  ], function (preview, Autocomplete) {
6
- var autocomplete = {
6
+ const autocomplete = {
7
7
  _active: {},
8
8
  };
9
9
 
@@ -15,9 +15,9 @@ define('composer/autocomplete', [
15
15
  });
16
16
 
17
17
  autocomplete.init = function (postContainer, post_uuid) {
18
- var element = postContainer.find('.write');
19
- var dropdownClass = 'composer-autocomplete-dropdown-' + post_uuid;
20
- var timer;
18
+ const element = postContainer.find('.write');
19
+ const dropdownClass = 'composer-autocomplete-dropdown-' + post_uuid;
20
+ let timer;
21
21
 
22
22
  if (!element.length) {
23
23
  /**
@@ -29,7 +29,7 @@ define('composer/autocomplete', [
29
29
  return;
30
30
  }
31
31
 
32
- var data = {
32
+ const data = {
33
33
  element: element,
34
34
  strategies: [],
35
35
  options: {
@@ -46,13 +46,13 @@ define('composer/autocomplete', [
46
46
  element.on('keyup', function () {
47
47
  clearTimeout(timer);
48
48
  timer = setTimeout(function () {
49
- var dropdown = document.querySelector('.' + dropdownClass);
49
+ const dropdown = document.querySelector('.' + dropdownClass);
50
50
  if (dropdown) {
51
- var pos = dropdown.getBoundingClientRect();
51
+ const pos = dropdown.getBoundingClientRect();
52
52
 
53
- var margin = parseFloat(dropdown.style.marginTop, 10) || 0;
53
+ const margin = parseFloat(dropdown.style.marginTop, 10) || 0;
54
54
 
55
- var offset = window.innerHeight + margin - 10 - pos.bottom;
55
+ const offset = window.innerHeight + margin - 10 - pos.bottom;
56
56
  dropdown.style.marginTop = Math.min(offset, 0) + 'px';
57
57
  }
58
58
  }, 0);
@@ -3,12 +3,13 @@
3
3
  define('composer/categoryList', [
4
4
  'categorySelector', 'taskbar', 'api',
5
5
  ], function (categorySelector, taskbar, api) {
6
- var categoryList = {};
6
+ const categoryList = {};
7
7
 
8
- var selector;
8
+ let selector;
9
+ let mobileSelector;
9
10
 
10
11
  categoryList.init = function (postContainer, postData) {
11
- var listContainer = postContainer.find('.category-list-container');
12
+ const listContainer = postContainer.find('.category-list-container');
12
13
  if (!listContainer.length) {
13
14
  return;
14
15
  }
@@ -25,31 +26,35 @@ define('composer/categoryList', [
25
26
  onSelect: function (selectedCategory) {
26
27
  if (postData.hasOwnProperty('cid')) {
27
28
  changeCategory(postContainer, postData, selectedCategory);
29
+ mobileSelector.selectCategory(selectedCategory.cid, selectedCategory.categoryEl);
28
30
  }
29
31
  },
30
32
  });
31
33
  if (!selector) {
32
34
  return;
33
35
  }
34
- if (postData.cid && postData.category) {
35
- selector.selectedCategory = { cid: postData.cid, name: postData.category.name };
36
- } else if (ajaxify.data.template.compose && ajaxify.data.selectedCategory) {
37
- // separate composer route
38
- selector.selectedCategory = { cid: ajaxify.data.cid, name: ajaxify.data.selectedCategory };
39
- }
40
-
41
36
  // this is the mobile category selector
42
- categorySelector.init(
37
+ mobileSelector = categorySelector.init(
43
38
  postContainer.find('.mobile-navbar [component="category-selector"]'), {
44
39
  privilege: 'topics:create',
45
40
  states: ['watching', 'tracking', 'notwatching', 'ignoring'],
46
41
  onSelect: function (selectedCategory) {
47
42
  if (postData.hasOwnProperty('cid')) {
48
43
  changeCategory(postContainer, postData, selectedCategory);
44
+ selector.selectCategory(selectedCategory.cid, selectedCategory.categoryEl);
49
45
  }
50
46
  },
51
47
  });
52
48
 
49
+ if (postData.cid && postData.category) {
50
+ selector.selectedCategory = { cid: postData.cid, name: postData.category.name };
51
+ mobileSelector.selectedCategory = { cid: postData.cid, name: postData.category.name };
52
+ } else if (ajaxify.data.template.compose && ajaxify.data.selectedCategory) {
53
+ // separate composer route
54
+ selector.selectedCategory = { cid: ajaxify.data.cid, name: ajaxify.data.selectedCategory };
55
+ mobileSelector.selectedCategory = { cid: ajaxify.data.cid, name: ajaxify.data.selectedCategory };
56
+ }
57
+
53
58
  toggleDropDirection(postContainer);
54
59
  };
55
60
 
@@ -58,7 +63,7 @@ define('composer/categoryList', [
58
63
  }
59
64
 
60
65
  categoryList.getSelectedCid = function () {
61
- var selectedCategory;
66
+ let selectedCategory;
62
67
  if (selector) {
63
68
  selectedCategory = selector.getSelectedCategory();
64
69
  }
@@ -75,7 +80,7 @@ define('composer/categoryList', [
75
80
 
76
81
  function updateTaskbarByCategory(postContainer, category) {
77
82
  if (category) {
78
- var uuid = postContainer.attr('data-uuid');
83
+ const uuid = postContainer.attr('data-uuid');
79
84
  taskbar.update('composer', uuid, {
80
85
  image: category.backgroundImage,
81
86
  color: category.color,
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  define('composer/controls', ['composer/preview'], function (preview) {
4
- var controls = {};
4
+ const controls = {};
5
5
 
6
6
  /** ********************************************** */
7
7
  /* Rich Textarea Controls */
8
8
  /** ********************************************** */
9
9
  controls.insertIntoTextarea = function (textarea, value) {
10
- var payload = {
10
+ const payload = {
11
11
  context: this,
12
12
  textarea: textarea,
13
13
  value: value,
@@ -19,9 +19,9 @@ define('composer/controls', ['composer/preview'], function (preview) {
19
19
  return;
20
20
  }
21
21
 
22
- var $textarea = $(payload.textarea);
23
- var currentVal = $textarea.val();
24
- var postContainer = $textarea.parents('[component="composer"]');
22
+ const $textarea = $(payload.textarea);
23
+ const currentVal = $textarea.val();
24
+ const postContainer = $textarea.parents('[component="composer"]');
25
25
 
26
26
  $textarea.val(
27
27
  currentVal.slice(0, payload.textarea.selectionStart) +
@@ -33,7 +33,7 @@ define('composer/controls', ['composer/preview'], function (preview) {
33
33
  };
34
34
 
35
35
  controls.replaceSelectionInTextareaWith = function (textarea, value) {
36
- var payload = {
36
+ const payload = {
37
37
  context: this,
38
38
  textarea: textarea,
39
39
  value: value,
@@ -45,9 +45,9 @@ define('composer/controls', ['composer/preview'], function (preview) {
45
45
  return;
46
46
  }
47
47
 
48
- var $textarea = $(payload.textarea);
49
- var currentVal = $textarea.val();
50
- var postContainer = $textarea.parents('[component="composer"]');
48
+ const $textarea = $(payload.textarea);
49
+ const currentVal = $textarea.val();
50
+ const postContainer = $textarea.parents('[component="composer"]');
51
51
 
52
52
  $textarea.val(
53
53
  currentVal.slice(0, payload.textarea.selectionStart) +
@@ -59,7 +59,7 @@ define('composer/controls', ['composer/preview'], function (preview) {
59
59
  };
60
60
 
61
61
  controls.wrapSelectionInTextareaWith = function (textarea, leading, trailing) {
62
- var payload = {
62
+ const payload = {
63
63
  context: this,
64
64
  textarea: textarea,
65
65
  leading: leading,
@@ -76,10 +76,10 @@ define('composer/controls', ['composer/preview'], function (preview) {
76
76
  trailing = leading;
77
77
  }
78
78
 
79
- var $textarea = $(textarea);
80
- var currentVal = $textarea.val();
79
+ const $textarea = $(textarea);
80
+ const currentVal = $textarea.val();
81
81
 
82
- var matches = /^(\s*)([\s\S]*?)(\s*)$/.exec(currentVal.slice(textarea.selectionStart, textarea.selectionEnd));
82
+ let matches = /^(\s*)([\s\S]*?)(\s*)$/.exec(currentVal.slice(textarea.selectionStart, textarea.selectionEnd));
83
83
 
84
84
  if (!matches[2]) {
85
85
  // selection is entirely whitespace
@@ -100,7 +100,7 @@ define('composer/controls', ['composer/preview'], function (preview) {
100
100
  };
101
101
 
102
102
  controls.updateTextareaSelection = function (textarea, start, end) {
103
- var payload = {
103
+ const payload = {
104
104
  context: this,
105
105
  textarea: textarea,
106
106
  start: start,
@@ -119,12 +119,11 @@ define('composer/controls', ['composer/preview'], function (preview) {
119
119
 
120
120
  controls.getBlockData = function (textareaEl, query, selectionStart) {
121
121
  // Determines whether the cursor is sitting inside a block-type element (bold, italic, etc.)
122
- var value = textareaEl.value;
122
+ let value = textareaEl.value;
123
123
  query = query.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
124
- var regex = new RegExp(query, 'g');
125
- var match;
126
- var matchIndices = [];
127
- var payload;
124
+ const regex = new RegExp(query, 'g');
125
+ let match;
126
+ const matchIndices = [];
128
127
 
129
128
  // Isolate the line the cursor is on
130
129
  value = value.split('\n').reduce(function (memo, line) {
@@ -146,7 +145,7 @@ define('composer/controls', ['composer/preview'], function (preview) {
146
145
  matchIndices.push(match.index);
147
146
  }
148
147
 
149
- payload = {
148
+ const payload = {
150
149
  in: !!(matchIndices.reduce(function (memo, cur) {
151
150
  if (selectionStart >= cur + 2) {
152
151
  memo += 1;
@@ -259,6 +259,7 @@ define('composer/drafts', ['api', 'alerts'], function (api, alerts) {
259
259
  require(['composer'], function (composer) {
260
260
  if (draft.action === 'topics.post') {
261
261
  composer.newTopic({
262
+ fromDraft: true,
262
263
  save_id: draft.save_id,
263
264
  cid: draft.cid,
264
265
  handle: app.user && app.user.uid ? undefined : utils.escapeHTML(draft.handle),
@@ -274,6 +275,7 @@ define('composer/drafts', ['api', 'alerts'], function (api, alerts) {
274
275
  }
275
276
 
276
277
  composer.newReply({
278
+ fromDraft: true,
277
279
  save_id: draft.save_id,
278
280
  tid: draft.tid,
279
281
  toPid: draft.toPid,
@@ -283,6 +285,7 @@ define('composer/drafts', ['api', 'alerts'], function (api, alerts) {
283
285
  });
284
286
  } else if (draft.action === 'posts.edit') {
285
287
  composer.editPost({
288
+ fromDraft: true,
286
289
  save_id: draft.save_id,
287
290
  pid: draft.pid,
288
291
  title: draft.title ? utils.escapeHTML(draft.title) : undefined,
@@ -295,10 +298,10 @@ define('composer/drafts', ['api', 'alerts'], function (api, alerts) {
295
298
 
296
299
  // Feature detection courtesy of: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
297
300
  function canSave(type) {
298
- var storage;
301
+ let storage;
299
302
  try {
300
303
  storage = window[type];
301
- var x = '__storage_test__';
304
+ const x = '__storage_test__';
302
305
  storage.setItem(x, x);
303
306
  storage.removeItem(x);
304
307
  return true;
@@ -3,18 +3,18 @@
3
3
  define('composer/formatting', [
4
4
  'composer/preview', 'composer/resize', 'topicThumbs', 'screenfull',
5
5
  ], function (preview, resize, topicThumbs, screenfull) {
6
- var formatting = {};
6
+ const formatting = {};
7
7
 
8
- var formattingDispatchTable = {
8
+ const formattingDispatchTable = {
9
9
  picture: function () {
10
- var postContainer = this;
10
+ const postContainer = this;
11
11
  postContainer.find('#files')
12
12
  .attr('accept', 'image/*')
13
13
  .click();
14
14
  },
15
15
 
16
16
  upload: function () {
17
- var postContainer = this;
17
+ const postContainer = this;
18
18
  postContainer.find('#files')
19
19
  .attr('accept', '')
20
20
  .click();
@@ -22,7 +22,7 @@ define('composer/formatting', [
22
22
 
23
23
  thumbs: function () {
24
24
  formatting.exitFullscreen();
25
- var postContainer = this;
25
+ const postContainer = this;
26
26
  require(['composer'], function (composer) {
27
27
  const uuid = postContainer.get(0).getAttribute('data-uuid');
28
28
  const composerObj = composer.posts[uuid];
@@ -39,12 +39,12 @@ define('composer/formatting', [
39
39
  },
40
40
 
41
41
  tags: function () {
42
- var postContainer = this;
42
+ const postContainer = this;
43
43
  postContainer.find('.tags-container').toggleClass('hidden');
44
44
  },
45
45
 
46
46
  zen: function () {
47
- var postContainer = this;
47
+ const postContainer = this;
48
48
  $(window).one('resize', function () {
49
49
  function onResize() {
50
50
  if (!screenfull.isFullscreen) {
@@ -70,7 +70,7 @@ define('composer/formatting', [
70
70
  },
71
71
  };
72
72
 
73
- var buttons = [];
73
+ const buttons = [];
74
74
 
75
75
  formatting.exitFullscreen = function () {
76
76
  if (screenfull.isEnabled && screenfull.isFullscreen) {
@@ -82,7 +82,7 @@ define('composer/formatting', [
82
82
  const formattingBarEl = $('.formatting-bar');
83
83
  const fileForm = formattingBarEl.find('.formatting-group #fileForm');
84
84
  buttons.forEach((btn) => {
85
- let markup = ``;
85
+ let markup;
86
86
  if (Array.isArray(btn.dropdownItems) && btn.dropdownItems.length) {
87
87
  markup = generateFormattingDropdown(btn);
88
88
  } else {
@@ -178,8 +178,8 @@ define('composer/formatting', [
178
178
 
179
179
  formatting.addHandler = function (postContainer) {
180
180
  postContainer.on('click', '.formatting-bar [data-format]', function (event) {
181
- var format = $(this).attr('data-format');
182
- var textarea = $(this).parents('[component="composer"]').find('textarea')[0];
181
+ const format = $(this).attr('data-format');
182
+ const textarea = $(this).parents('[component="composer"]').find('textarea')[0];
183
183
 
184
184
  if (formattingDispatchTable.hasOwnProperty(format)) {
185
185
  formattingDispatchTable[format].call(
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  define('composer/preview', ['hooks'], function (hooks) {
4
- var preview = {};
4
+ const preview = {};
5
5
 
6
6
  preview.render = function (postContainer, callback) {
7
7
  callback = callback || function () {};
@@ -9,7 +9,7 @@ define('composer/preview', ['hooks'], function (hooks) {
9
9
  return callback();
10
10
  }
11
11
 
12
- var textarea = postContainer.find('textarea');
12
+ const textarea = postContainer.find('textarea');
13
13
 
14
14
  socket.emit('plugins.composer.renderPreview', textarea.val(), function (err, preview) {
15
15
  if (err) {
@@ -27,17 +27,17 @@ define('composer/preview', ['hooks'], function (hooks) {
27
27
  if (!postContainer.find('.preview-container').is(':visible')) {
28
28
  return;
29
29
  }
30
- var textarea = postContainer.find('textarea');
31
- var preview = postContainer.find('.preview');
30
+ const textarea = postContainer.find('textarea');
31
+ const preview = postContainer.find('.preview');
32
32
 
33
33
  if (textarea.length && preview.length) {
34
- var diff = textarea[0].scrollHeight - textarea.height();
34
+ const diff = textarea[0].scrollHeight - textarea.height();
35
35
 
36
36
  if (diff === 0) {
37
37
  return;
38
38
  }
39
39
 
40
- var scrollPercent = textarea.scrollTop() / diff;
40
+ const scrollPercent = textarea.scrollTop() / diff;
41
41
 
42
42
  preview.scrollTop(Math.max(preview[0].scrollHeight - preview.height(), 0) * scrollPercent);
43
43
  }
@@ -2,18 +2,18 @@
2
2
  'use strict';
3
3
 
4
4
  define('composer/resize', ['taskbar'], function (taskbar) {
5
- var resize = {};
6
- var oldRatio = 0;
7
- var minimumRatio = 0.3;
8
- var snapMargin = 0.05;
9
- var smallMin = 768;
10
-
11
- var $body = $('body');
12
- var $window = $(window);
13
- var $headerMenu = $('[component="navbar"]');
5
+ const resize = {};
6
+ let oldRatio = 0;
7
+ const minimumRatio = 0.3;
8
+ const snapMargin = 0.05;
9
+ const smallMin = 768;
10
+
11
+ const $body = $('body');
12
+ const $window = $(window);
13
+ const $headerMenu = $('[component="navbar"]');
14
14
  const content = document.getElementById('content');
15
15
 
16
- var header = $headerMenu[0];
16
+ const header = $headerMenu[0];
17
17
 
18
18
  function getSavedRatio() {
19
19
  return localStorage.getItem('composer:resizeRatio') || 0.5;
@@ -24,7 +24,7 @@ define('composer/resize', ['taskbar'], function (taskbar) {
24
24
  }
25
25
 
26
26
  function getBounds() {
27
- var headerRect;
27
+ let headerRect;
28
28
  if (header) {
29
29
  headerRect = header.getBoundingClientRect();
30
30
  } else {
@@ -32,9 +32,9 @@ define('composer/resize', ['taskbar'], function (taskbar) {
32
32
  headerRect = { bottom: 0 };
33
33
  }
34
34
 
35
- var headerBottom = Math.max(headerRect.bottom, 0);
35
+ const headerBottom = Math.max(headerRect.bottom, 0);
36
36
 
37
- var rect = {
37
+ const rect = {
38
38
  top: 0,
39
39
  left: 0,
40
40
  right: window.innerWidth,
@@ -51,24 +51,24 @@ define('composer/resize', ['taskbar'], function (taskbar) {
51
51
  }
52
52
 
53
53
  function doResize(postContainer, ratio) {
54
- var bounds = getBounds();
55
- var elem = postContainer[0];
56
- var style = window.getComputedStyle(elem);
54
+ const bounds = getBounds();
55
+ const elem = postContainer[0];
56
+ const style = window.getComputedStyle(elem);
57
57
 
58
58
  // Adjust minimumRatio for shorter viewports
59
- var minHeight = parseInt(style.getPropertyValue('min-height'), 10);
60
- var adjustedMinimum = Math.max(minHeight / window.innerHeight, minimumRatio);
59
+ const minHeight = parseInt(style.getPropertyValue('min-height'), 10);
60
+ const adjustedMinimum = Math.max(minHeight / window.innerHeight, minimumRatio);
61
61
 
62
62
  if (bounds.width >= smallMin) {
63
63
  const boundedDifference = (bounds.height - bounds.boundedHeight) / bounds.height;
64
64
  ratio = Math.min(Math.max(ratio, adjustedMinimum + boundedDifference), 1);
65
65
 
66
- var top = ratio * bounds.boundedHeight / bounds.height;
66
+ const top = ratio * bounds.boundedHeight / bounds.height;
67
67
  elem.style.top = ((1 - top) * 100).toString() + '%';
68
68
 
69
69
  // Add some extra space at the bottom of the body so that
70
70
  // the user can still scroll to the last post w/ composer open
71
- var rect = elem.getBoundingClientRect();
71
+ const rect = elem.getBoundingClientRect();
72
72
  content.style.paddingBottom = (rect.bottom - rect.top).toString() + 'px';
73
73
  } else {
74
74
  elem.style.top = 0;
@@ -80,8 +80,8 @@ define('composer/resize', ['taskbar'], function (taskbar) {
80
80
  taskbar.updateActive(postContainer.attr('data-uuid'));
81
81
  }
82
82
 
83
- var resizeIt = doResize;
84
- var raf = window.requestAnimationFrame ||
83
+ let resizeIt = doResize;
84
+ const raf = window.requestAnimationFrame ||
85
85
  window.webkitRequestAnimationFrame ||
86
86
  window.mozRequestAnimationFrame;
87
87
 
@@ -99,7 +99,7 @@ define('composer/resize', ['taskbar'], function (taskbar) {
99
99
  }
100
100
 
101
101
  resize.reposition = function (postContainer) {
102
- var ratio = getSavedRatio();
102
+ let ratio = getSavedRatio();
103
103
 
104
104
  if (ratio >= 1 - snapMargin) {
105
105
  ratio = 1;
@@ -118,15 +118,15 @@ define('composer/resize', ['taskbar'], function (taskbar) {
118
118
  };
119
119
 
120
120
  resize.handleResize = function (postContainer) {
121
- var resizeOffset = 0;
122
- var resizeBegin = 0;
123
- var resizeEnd = 0;
124
- var $resizer = postContainer.find('.resizer');
125
- var resizer = $resizer[0];
121
+ let resizeOffset = 0;
122
+ let resizeBegin = 0;
123
+ let resizeEnd = 0;
124
+ const $resizer = postContainer.find('.resizer');
125
+ const resizer = $resizer[0];
126
126
 
127
127
  function resizeStart(e) {
128
- var resizeRect = resizer.getBoundingClientRect();
129
- var resizeCenterY = (resizeRect.top + resizeRect.bottom) / 2;
128
+ const resizeRect = resizer.getBoundingClientRect();
129
+ const resizeCenterY = (resizeRect.top + resizeRect.bottom) / 2;
130
130
 
131
131
  resizeOffset = (resizeCenterY - e.clientY) / 2;
132
132
  resizeBegin = e.clientY;
@@ -137,9 +137,9 @@ define('composer/resize', ['taskbar'], function (taskbar) {
137
137
  }
138
138
 
139
139
  function resizeAction(e) {
140
- var position = e.clientY - resizeOffset;
141
- var bounds = getBounds();
142
- var ratio = (bounds.height - position) / (bounds.boundedHeight);
140
+ const position = e.clientY - resizeOffset;
141
+ const bounds = getBounds();
142
+ const ratio = (bounds.height - position) / (bounds.boundedHeight);
143
143
 
144
144
  resizeIt(postContainer, ratio);
145
145
  }
@@ -153,9 +153,9 @@ define('composer/resize', ['taskbar'], function (taskbar) {
153
153
  $window.off('mouseup', resizeStop);
154
154
  $body.off('touchmove', resizeTouchAction);
155
155
 
156
- var position = resizeEnd - resizeOffset;
157
- var bounds = getBounds();
158
- var ratio = (bounds.height - position) / (bounds.boundedHeight);
156
+ const position = resizeEnd - resizeOffset;
157
+ const bounds = getBounds();
158
+ let ratio = (bounds.height - position) / (bounds.boundedHeight);
159
159
 
160
160
  if (resizeEnd - resizeBegin === 0 && postContainer.hasClass('maximized')) {
161
161
  postContainer.removeClass('maximized');
@@ -2,13 +2,13 @@
2
2
  'use strict';
3
3
 
4
4
  define('composer/tags', ['alerts'], function (alerts) {
5
- var tags = {};
5
+ const tags = {};
6
6
 
7
- var minTags;
8
- var maxTags;
7
+ let minTags;
8
+ let maxTags;
9
9
 
10
10
  tags.init = function (postContainer, postData) {
11
- var tagEl = postContainer.find('.tags');
11
+ const tagEl = postContainer.find('.tags');
12
12
  if (!tagEl.length) {
13
13
  return;
14
14
  }
@@ -58,9 +58,9 @@ define('composer/tags', ['alerts'], function (alerts) {
58
58
  addTags(postData.tags, tagEl);
59
59
 
60
60
  tagEl.on('beforeItemAdd', function (event) {
61
- var reachedMaxTags = maxTags && maxTags <= tags.getTags(postContainer.attr('data-uuid')).length;
62
- var cleanTag = utils.cleanUpTag(event.item, config.maximumTagLength);
63
- var different = cleanTag !== event.item;
61
+ const reachedMaxTags = maxTags && maxTags <= tags.getTags(postContainer.attr('data-uuid')).length;
62
+ const cleanTag = utils.cleanUpTag(event.item, config.maximumTagLength);
63
+ const different = cleanTag !== event.item;
64
64
  event.cancel = different ||
65
65
  event.item.length < config.minimumTagLength ||
66
66
  event.item.length > config.maximumTagLength ||
@@ -73,7 +73,7 @@ define('composer/tags', ['alerts'], function (alerts) {
73
73
  } else if (reachedMaxTags) {
74
74
  return alerts.error('[[error:too-many-tags, ' + maxTags + ']]');
75
75
  }
76
- var cid = postData.hasOwnProperty('cid') ? postData.cid : ajaxify.data.cid;
76
+ const cid = postData.hasOwnProperty('cid') ? postData.cid : ajaxify.data.cid;
77
77
  $(window).trigger('action:tag.beforeAdd', {
78
78
  cid,
79
79
  tagEl,
@@ -109,7 +109,7 @@ define('composer/tags', ['alerts'], function (alerts) {
109
109
  if (event.options && event.options.skipAddCheck) {
110
110
  return;
111
111
  }
112
- var cid = postData.hasOwnProperty('cid') ? postData.cid : ajaxify.data.cid;
112
+ const cid = postData.hasOwnProperty('cid') ? postData.cid : ajaxify.data.cid;
113
113
  socket.emit('topics.isTagAllowed', { tag: event.item, cid: cid || 0 }, function (err, allowed) {
114
114
  if (err) {
115
115
  return alerts.error(err);
@@ -136,7 +136,7 @@ define('composer/tags', ['alerts'], function (alerts) {
136
136
  });
137
137
 
138
138
  $('[component="composer/tag/dropdown"]').on('click', 'li', function () {
139
- var tag = $(this).attr('data-tag');
139
+ const tag = $(this).attr('data-tag');
140
140
  if (tag) {
141
141
  addTags([tag], tagEl);
142
142
  }
@@ -153,7 +153,7 @@ define('composer/tags', ['alerts'], function (alerts) {
153
153
  };
154
154
 
155
155
  tags.onChangeCategory = function (postContainer, postData, cid, categoryData) {
156
- var tagDropdown = postContainer.find('[component="composer/tag/dropdown"]');
156
+ const tagDropdown = postContainer.find('[component="composer/tag/dropdown"]');
157
157
  if (!tagDropdown.length) {
158
158
  return;
159
159
  }
@@ -168,8 +168,8 @@ define('composer/tags', ['alerts'], function (alerts) {
168
168
  };
169
169
 
170
170
  function toggleTagInput(postContainer, postData, data) {
171
- var tagEl = postContainer.find('.tags');
172
- var input = postContainer.find('.bootstrap-tagsinput input');
171
+ const tagEl = postContainer.find('.tags');
172
+ const input = postContainer.find('.bootstrap-tagsinput input');
173
173
  if (!input.length) {
174
174
  return;
175
175
  }
@@ -212,7 +212,7 @@ define('composer/tags', ['alerts'], function (alerts) {
212
212
 
213
213
  function triggerEnter(input) {
214
214
  // http://stackoverflow.com/a/3276819/583363
215
- var e = jQuery.Event('keypress');
215
+ const e = jQuery.Event('keypress');
216
216
  e.which = 13;
217
217
  e.keyCode = 13;
218
218
  setTimeout(function () {
@@ -222,7 +222,7 @@ define('composer/tags', ['alerts'], function (alerts) {
222
222
 
223
223
  function addTags(tags, tagEl) {
224
224
  if (tags && tags.length) {
225
- for (var i = 0; i < tags.length; ++i) {
225
+ for (let i = 0; i < tags.length; ++i) {
226
226
  tagEl.tagsinput('add', tags[i]);
227
227
  }
228
228
  }
@@ -8,11 +8,11 @@ define('composer/uploads', [
8
8
  'uploadHelpers',
9
9
  'jquery-form',
10
10
  ], function (preview, categoryList, translator, alerts, uploadHelpers) {
11
- var uploads = {
11
+ const uploads = {
12
12
  inProgress: {},
13
13
  };
14
14
 
15
- var uploadingText = '';
15
+ let uploadingText = '';
16
16
 
17
17
  uploads.initialize = function (post_uuid) {
18
18
  initializeDragAndDrop(post_uuid);
@@ -26,10 +26,10 @@ define('composer/uploads', [
26
26
  };
27
27
 
28
28
  function addChangeHandlers(post_uuid) {
29
- var postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
29
+ const postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
30
30
 
31
31
  postContainer.find('#files').on('change', function (e) {
32
- var files = (e.target || {}).files ||
32
+ const files = (e.target || {}).files ||
33
33
  ($(this).val() ? [{ name: $(this).val(), type: utils.fileMimeType($(this).val()) }] : null);
34
34
  if (files) {
35
35
  uploadContentFiles({ files: files, post_uuid: post_uuid, route: '/api/post/upload' });
@@ -38,7 +38,7 @@ define('composer/uploads', [
38
38
  }
39
39
 
40
40
  function initializeDragAndDrop(post_uuid) {
41
- var postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
41
+ const postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
42
42
  uploadHelpers.handleDragDrop({
43
43
  container: postContainer,
44
44
  callback: function (upload) {
@@ -53,7 +53,7 @@ define('composer/uploads', [
53
53
  }
54
54
 
55
55
  function initializePaste(post_uuid) {
56
- var postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
56
+ const postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
57
57
  uploadHelpers.handlePaste({
58
58
  container: postContainer,
59
59
  callback: function (upload) {
@@ -77,35 +77,34 @@ define('composer/uploads', [
77
77
  }
78
78
 
79
79
  function uploadContentFiles(params) {
80
- var files = [...params.files];
81
- var post_uuid = params.post_uuid;
82
- var postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
83
- var textarea = postContainer.find('textarea');
84
- var text = textarea.val();
85
- var uploadForm = postContainer.find('#fileForm');
86
- var doneUploading = false;
80
+ const files = [...params.files];
81
+ const post_uuid = params.post_uuid;
82
+ const postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
83
+ const textarea = postContainer.find('textarea');
84
+ let text = textarea.val();
85
+ const uploadForm = postContainer.find('#fileForm');
86
+ let doneUploading = false;
87
87
  uploadForm.attr('action', config.relative_path + params.route);
88
88
 
89
- var cid = categoryList.getSelectedCid();
89
+ let cid = categoryList.getSelectedCid();
90
90
  if (!cid && ajaxify.data.cid) {
91
91
  cid = ajaxify.data.cid;
92
92
  }
93
- var i = 0;
94
- var isImage = false;
95
- for (i = 0; i < files.length; ++i) {
96
- isImage = files[i].type.match(/image./);
93
+
94
+ for (let i = 0; i < files.length; ++i) {
95
+ const isImage = files[i].type.match(/image./);
97
96
  if ((isImage && !app.user.privileges['upload:post:image']) || (!isImage && !app.user.privileges['upload:post:file'])) {
98
97
  return alerts.error('[[error:no-privileges]]');
99
98
  }
100
99
  }
101
100
 
102
- var filenameMapping = [];
101
+ const filenameMapping = [];
103
102
  let filesText = '';
104
- for (i = 0; i < files.length; ++i) {
103
+ for (let i = 0; i < files.length; ++i) {
105
104
  // The filename map has datetime and iterator prepended so that they can be properly tracked even if the
106
105
  // filenames are identical.
107
106
  filenameMapping.push(i + '_' + Date.now() + '_' + (params.fileNames ? params.fileNames[i] : files[i].name));
108
- isImage = files[i].type.match(/image./);
107
+ const isImage = files[i].type.match(/image./);
109
108
 
110
109
  if (!app.user.isAdmin && files[i].size > parseInt(config.maximumFileSize, 10) * 1024) {
111
110
  uploadForm[0].reset();
@@ -136,12 +135,12 @@ define('composer/uploads', [
136
135
 
137
136
  uploadForm.off('submit').submit(function () {
138
137
  function updateTextArea(filename, text, trim) {
139
- var newFilename;
138
+ let newFilename;
140
139
  if (trim) {
141
140
  newFilename = filename.replace(/^\d+_\d{13}_/, '');
142
141
  }
143
- var current = textarea.val();
144
- var re = new RegExp(escapeRegExp(filename) + ']\\([^)]+\\)', 'g');
142
+ const current = textarea.val();
143
+ const re = new RegExp(escapeRegExp(filename) + ']\\([^)]+\\)', 'g');
145
144
  textarea.val(current.replace(re, (newFilename || filename) + '](' + text + ')'));
146
145
 
147
146
  $(window).trigger('action:composer.uploadUpdate', {
@@ -171,7 +170,7 @@ define('composer/uploads', [
171
170
  doneUploading = true;
172
171
  postContainer.find('[data-action="post"]').prop('disabled', false);
173
172
  const errorMsg = onUploadError(xhr, post_uuid);
174
- for (var i = 0; i < files.length; ++i) {
173
+ for (let i = 0; i < files.length; ++i) {
175
174
  updateTextArea(filenameMapping[i], errorMsg, true);
176
175
  }
177
176
  preview.render(postContainer);
@@ -182,7 +181,7 @@ define('composer/uploads', [
182
181
  if (doneUploading) {
183
182
  return;
184
183
  }
185
- for (var i = 0; i < files.length; ++i) {
184
+ for (let i = 0; i < files.length; ++i) {
186
185
  updateTextArea(filenameMapping[i], translated);
187
186
  }
188
187
  });
@@ -192,7 +191,7 @@ define('composer/uploads', [
192
191
  const uploads = res.response.images;
193
192
  doneUploading = true;
194
193
  if (uploads && uploads.length) {
195
- for (var i = 0; i < uploads.length; ++i) {
194
+ for (let i = 0; i < uploads.length; ++i) {
196
195
  uploads[i].filename = filenameMapping[i].replace(/^\d+_\d{13}_/, '');
197
196
  uploads[i].isImage = /image./.test(files[i].type);
198
197
  updateTextArea(filenameMapping[i], uploads[i].url, true);
@@ -221,7 +220,7 @@ define('composer/uploads', [
221
220
  }
222
221
 
223
222
  function onUploadError(xhr, post_uuid) {
224
- var msg = (xhr.responseJSON &&
223
+ let msg = (xhr.responseJSON &&
225
224
  (xhr.responseJSON.error || (xhr.responseJSON.status && xhr.responseJSON.status.message))) ||
226
225
  '[[error:parse-error]]';
227
226
 
@@ -25,7 +25,7 @@ define('composer', [
25
25
  ], function (taskbar, translator, uploads, formatting, drafts, tags,
26
26
  categoryList, preview, resize, autocomplete, scheduler, postQueue, scrollStop,
27
27
  topicThumbs, api, bootbox, alerts, hooks, messagesModule, search, screenfull) {
28
- var composer = {
28
+ const composer = {
29
29
  active: undefined,
30
30
  posts: {},
31
31
  bsEnvironment: undefined,
@@ -41,7 +41,7 @@ define('composer', [
41
41
  });
42
42
 
43
43
  window.addEventListener('popstate', function () {
44
- var env = utils.findBootstrapEnvironment();
44
+ const env = utils.findBootstrapEnvironment();
45
45
  if (composer.active && (env === 'xs' || env === 'sm')) {
46
46
  if (!composer.posts[composer.active].modified) {
47
47
  composer.discard(composer.active);
@@ -64,15 +64,15 @@ define('composer', [
64
64
  });
65
65
 
66
66
  function removeComposerHistory() {
67
- var env = composer.bsEnvironment;
67
+ const env = composer.bsEnvironment;
68
68
  if (ajaxify.data.template.compose === true || env === 'xs' || env === 'sm') {
69
69
  history.back();
70
70
  }
71
71
  }
72
72
 
73
73
  function onWindowResize() {
74
- var env = utils.findBootstrapEnvironment();
75
- var isMobile = env === 'xs' || env === 'sm';
74
+ const env = utils.findBootstrapEnvironment();
75
+ const isMobile = env === 'xs' || env === 'sm';
76
76
 
77
77
  if (preview.toggle && preview.env !== env) {
78
78
  preview.env = env;
@@ -93,9 +93,7 @@ define('composer', [
93
93
 
94
94
  function alreadyOpen(post) {
95
95
  // If a composer for the same cid/tid/pid is already open, return the uuid, else return bool false
96
- var type;
97
- var id;
98
-
96
+ let type;
99
97
  if (post.hasOwnProperty('cid')) {
100
98
  type = 'cid';
101
99
  } else if (post.hasOwnProperty('tid')) {
@@ -104,11 +102,11 @@ define('composer', [
104
102
  type = 'pid';
105
103
  }
106
104
 
107
- id = post[type];
105
+ const id = String(post[type]);
108
106
 
109
107
  // Find a match
110
108
  for (const uuid of Object.keys(composer.posts)) {
111
- if (composer.posts[uuid].hasOwnProperty(type) && id === composer.posts[uuid][type]) {
109
+ if (composer.posts[uuid].hasOwnProperty(type) && id === String(composer.posts[uuid][type])) {
112
110
  return uuid;
113
111
  }
114
112
  }
@@ -122,12 +120,10 @@ define('composer', [
122
120
  return;
123
121
  }
124
122
 
125
- var uuid = utils.generateUUID();
126
- var existingUUID = alreadyOpen(post);
127
-
123
+ const existingUUID = alreadyOpen(post);
128
124
  if (existingUUID) {
129
125
  taskbar.updateActive(existingUUID);
130
- if (post.body) {
126
+ if (post.body && !post.fromDraft) {
131
127
  const postContainer = $('.composer[data-uuid="' + existingUUID + '"]');
132
128
  const bodyEl = postContainer.find('textarea');
133
129
  const prevText = bodyEl.val();
@@ -137,18 +133,16 @@ define('composer', [
137
133
  }
138
134
  return composer.load(existingUUID);
139
135
  }
140
-
141
- var actionText = '[[topic:composer.new-topic]]';
136
+ const uuid = utils.generateUUID();
137
+ let actionText = '[[topic:composer.new-topic]]';
142
138
  if (post.action === 'posts.reply') {
143
- actionText = '[[topic:composer.replying-to]]';
139
+ actionText = translator.compile('topic:composer.replying-to', `"${post.title}"`);
144
140
  } else if (post.action === 'posts.edit') {
145
- actionText = '[[topic:composer.editing-in]]';
141
+ actionText = translator.compile('topic:composer.editing-in', `"${post.title}"`);
146
142
  }
147
143
 
148
- translator.translate(actionText, function (translatedAction) {
149
- taskbar.push('composer', uuid, {
150
- title: translatedAction.replace('%1', '"' + post.title + '"'),
151
- });
144
+ taskbar.push('composer', uuid, {
145
+ title: actionText,
152
146
  });
153
147
 
154
148
  composer.posts[uuid] = post;
@@ -188,6 +182,7 @@ define('composer', [
188
182
 
189
183
  composer.newTopic = async (data) => {
190
184
  let pushData = {
185
+ fromDraft: data.fromDraft,
191
186
  save_id: data.save_id,
192
187
  action: 'topics.post',
193
188
  cid: data.cid,
@@ -212,7 +207,7 @@ define('composer', [
212
207
  // tid, toPid, selectedPid, title, username, text, uuid
213
208
  data.uuid = data.uuid || composer.active;
214
209
 
215
- var escapedTitle = (data.title || '')
210
+ const escapedTitle = (data.title || '')
216
211
  .replace(/([\\`*_{}[\]()#+\-.!])/g, '\\$1')
217
212
  .replace(/\[/g, '&#91;')
218
213
  .replace(/\]/g, '&#93;')
@@ -246,9 +241,9 @@ define('composer', [
246
241
  composer.load(data.uuid);
247
242
  }
248
243
 
249
- var postContainer = $('.composer[data-uuid="' + data.uuid + '"]');
250
- var bodyEl = postContainer.find('textarea');
251
- var prevText = bodyEl.val();
244
+ const postContainer = $('.composer[data-uuid="' + data.uuid + '"]');
245
+ const bodyEl = postContainer.find('textarea');
246
+ const prevText = bodyEl.val();
252
247
 
253
248
  translator.translate(quoteKey, config.defaultLang, function (translated) {
254
249
  composer.posts[data.uuid].body = (prevText.length ? prevText + '\n\n' : '') + translated + data.body;
@@ -261,6 +256,7 @@ define('composer', [
261
256
  composer.newReply = function (data) {
262
257
  translator.translate(data.body, config.defaultLang, function (translated) {
263
258
  push({
259
+ fromDraft: data.fromDraft,
264
260
  save_id: data.save_id,
265
261
  action: 'posts.reply',
266
262
  tid: data.tid,
@@ -279,6 +275,7 @@ define('composer', [
279
275
  if (err) {
280
276
  return alerts.error(err);
281
277
  }
278
+ postData.fromDraft = data.fromDraft;
282
279
  postData.save_id = data.save_id;
283
280
  postData.action = 'posts.edit';
284
281
  postData.pid = data.pid;
@@ -296,7 +293,7 @@ define('composer', [
296
293
  };
297
294
 
298
295
  composer.load = function (post_uuid) {
299
- var postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
296
+ const postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
300
297
  if (postContainer.length) {
301
298
  activate(post_uuid);
302
299
  resize.reposition(postContainer);
@@ -432,12 +429,12 @@ define('composer', [
432
429
  }
433
430
 
434
431
  async function createNewComposer(post_uuid) {
435
- var postData = composer.posts[post_uuid];
432
+ let postData = composer.posts[post_uuid];
436
433
 
437
- var isTopic = postData ? postData.hasOwnProperty('cid') : false;
438
- var isMain = postData ? !!postData.isMain : false;
439
- var isEditing = postData ? !!postData.pid : false;
440
- var isGuestPost = postData ? parseInt(postData.uid, 10) === 0 : false;
434
+ const isTopic = postData ? postData.hasOwnProperty('cid') : false;
435
+ const isMain = postData ? !!postData.isMain : false;
436
+ const isEditing = postData ? !!postData.pid : false;
437
+ const isGuestPost = postData ? parseInt(postData.uid, 10) === 0 : false;
441
438
  const isScheduled = postData.timestamp > Date.now();
442
439
 
443
440
  postData.category = await getSelectedCategory(postData);
@@ -512,7 +509,7 @@ define('composer', [
512
509
 
513
510
  $(document.body).append(composerTemplate);
514
511
 
515
- var postContainer = $(composerTemplate[0]);
512
+ const postContainer = $(composerTemplate[0]);
516
513
 
517
514
  resize.reposition(postContainer);
518
515
  composer.enhance(postContainer, post_uuid, postData);
@@ -535,10 +532,10 @@ define('composer', [
535
532
  resize.handleResize(postContainer);
536
533
 
537
534
  if (composer.bsEnvironment === 'xs' || composer.bsEnvironment === 'sm') {
538
- var submitBtns = postContainer.find('.composer-submit');
539
- var mobileSubmitBtn = postContainer.find('.mobile-navbar .composer-submit');
540
- var textareaEl = postContainer.find('.write');
541
- var idx = textareaEl.attr('tabindex');
535
+ const submitBtns = postContainer.find('.composer-submit');
536
+ const mobileSubmitBtn = postContainer.find('.mobile-navbar .composer-submit');
537
+ const textareaEl = postContainer.find('.write');
538
+ const idx = textareaEl.attr('tabindex');
542
539
 
543
540
  submitBtns.removeAttr('tabindex');
544
541
  mobileSubmitBtn.attr('tabindex', parseInt(idx, 10) + 1);
@@ -582,7 +579,7 @@ define('composer', [
582
579
  message: '[[modules:composer.remote-pid-content-immutable]]',
583
580
  timeout: 15000,
584
581
  });
585
- var container = postContainer.find('.write-container');
582
+ const container = postContainer.find('.write-container');
586
583
  container.addClass('hidden');
587
584
  }
588
585
 
@@ -605,10 +602,10 @@ define('composer', [
605
602
  }
606
603
 
607
604
  function handleSearch(postContainer) {
608
- var uuid = postContainer.attr('data-uuid');
609
- var isEditing = composer.posts[uuid] && composer.posts[uuid].action === 'posts.edit';
610
- var env = utils.findBootstrapEnvironment();
611
- var isMobile = env === 'xs' || env === 'sm';
605
+ const uuid = postContainer.attr('data-uuid');
606
+ const isEditing = composer.posts[uuid] && composer.posts[uuid].action === 'posts.edit';
607
+ const env = utils.findBootstrapEnvironment();
608
+ const isMobile = env === 'xs' || env === 'sm';
612
609
  if (isEditing || isMobile) {
613
610
  return;
614
611
  }
@@ -642,7 +639,7 @@ define('composer', [
642
639
 
643
640
  function focusElements(postContainer) {
644
641
  setTimeout(function () {
645
- var title = postContainer.find('input.title');
642
+ const title = postContainer.find('input.title');
646
643
 
647
644
  if (title.length) {
648
645
  title.focus();
@@ -653,13 +650,13 @@ define('composer', [
653
650
  }
654
651
 
655
652
  async function post(post_uuid) {
656
- var postData = composer.posts[post_uuid];
657
- var postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
658
- var handleEl = postContainer.find('.handle');
659
- var titleEl = postContainer.find('.title');
660
- var bodyEl = postContainer.find('textarea');
661
- var thumbEl = postContainer.find('input#topic-thumb-url');
662
- var onComposeRoute = postData.hasOwnProperty('template') && postData.template.compose === true;
653
+ const postData = composer.posts[post_uuid];
654
+ const postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
655
+ const handleEl = postContainer.find('.handle');
656
+ const titleEl = postContainer.find('.title');
657
+ const bodyEl = postContainer.find('textarea');
658
+ const thumbEl = postContainer.find('input#topic-thumb-url');
659
+ const onComposeRoute = postData.hasOwnProperty('template') && postData.template.compose === true;
663
660
  const submitBtn = postContainer.find('.composer-submit');
664
661
 
665
662
  titleEl.val(titleEl.val().trim());
@@ -668,13 +665,13 @@ define('composer', [
668
665
  thumbEl.val(thumbEl.val().trim());
669
666
  }
670
667
 
671
- var action = postData.action;
668
+ const action = postData.action;
672
669
 
673
- var checkTitle = (postData.hasOwnProperty('cid') || parseInt(postData.pid, 10)) && postContainer.find('input.title').length;
674
- var isCategorySelected = !checkTitle || (checkTitle && postData.cid);
670
+ const checkTitle = (postData.hasOwnProperty('cid') || parseInt(postData.pid, 10)) && postContainer.find('input.title').length;
671
+ const isCategorySelected = !checkTitle || (checkTitle && postData.cid);
675
672
 
676
673
  // Specifically for checking title/body length via plugins
677
- var payload = {
674
+ const payload = {
678
675
  post_uuid: post_uuid,
679
676
  postData: postData,
680
677
  postContainer: postContainer,
@@ -751,7 +748,7 @@ define('composer', [
751
748
  timestamp: scheduler.getTimestamp(),
752
749
  };
753
750
  }
754
- var submitHookData = {
751
+ const submitHookData = {
755
752
  composerEl: postContainer,
756
753
  action: action,
757
754
  composerData: composerData,
@@ -763,8 +760,8 @@ define('composer', [
763
760
  hooks.fire('action:composer.submit', Object.freeze(submitHookData));
764
761
 
765
762
  // Minimize composer (and set textarea as readonly) while submitting
766
- var taskbarIconEl = $('#taskbar .composer[data-uuid="' + post_uuid + '"] i');
767
- var textareaEl = postContainer.find('.write');
763
+ const taskbarIconEl = $('#taskbar .composer[data-uuid="' + post_uuid + '"] i');
764
+ const textareaEl = postContainer.find('.write');
768
765
  taskbarIconEl.removeClass('fa-plus').addClass('fa-circle-o-notch fa-spin');
769
766
  composer.minimize(post_uuid);
770
767
  textareaEl.prop('readonly', true);
@@ -830,8 +827,8 @@ define('composer', [
830
827
 
831
828
  composer.discard = function (post_uuid) {
832
829
  if (composer.posts[post_uuid]) {
833
- var postData = composer.posts[post_uuid];
834
- var postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
830
+ const postData = composer.posts[post_uuid];
831
+ const postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
835
832
  postContainer.remove();
836
833
  drafts.removeDraft(postData.save_id);
837
834
  topicThumbs.deleteAll(post_uuid);
@@ -854,7 +851,7 @@ define('composer', [
854
851
  composer.close = composer.discard;
855
852
 
856
853
  composer.minimize = function (post_uuid) {
857
- var postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
854
+ const postContainer = $('.composer[data-uuid="' + post_uuid + '"]');
858
855
  postContainer.css('visibility', 'hidden');
859
856
  composer.active = undefined;
860
857
  taskbar.minimize('composer', post_uuid);
@@ -17,7 +17,7 @@
17
17
 
18
18
  <div class="d-flex gap-1 flex-nowrap">
19
19
  <button class="btn btn-sm btn-primary display-scheduler fs-5 {{{ if !canSchedule }}} hidden{{{ end }}}">
20
- <i class="fa fa-clock-o"></i>
20
+ <i class="fa fa-fw fa-clock-o"></i>
21
21
  </button>
22
22
  <button class="btn btn-sm btn-primary composer-submit fs-5" data-action="post" tabindex="-1"><i class="fa fa-fw fa-chevron-right"></i></button>
23
23
  </div>