@nextcloud/vue 3.10.2 → 4.1.1

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.
Files changed (290) hide show
  1. package/CHANGELOG.md +114 -19
  2. package/README.md +9 -10
  3. package/dist/Components/ActionButton.js +24 -3
  4. package/dist/Components/ActionButton.js.map +1 -1
  5. package/dist/Components/ActionCaption.js +23 -0
  6. package/dist/Components/ActionCaption.js.map +1 -0
  7. package/dist/Components/ActionCheckbox.js +24 -3
  8. package/dist/Components/ActionCheckbox.js.map +1 -1
  9. package/dist/Components/ActionInput.js +124 -21
  10. package/dist/Components/ActionInput.js.map +1 -1
  11. package/dist/Components/ActionLink.js +24 -3
  12. package/dist/Components/ActionLink.js.map +1 -1
  13. package/dist/Components/ActionRadio.js +24 -3
  14. package/dist/Components/ActionRadio.js.map +1 -1
  15. package/dist/Components/ActionRouter.js +23 -2
  16. package/dist/Components/ActionRouter.js.map +1 -1
  17. package/dist/Components/ActionSeparator.js +1 -1
  18. package/dist/Components/ActionSeparator.js.map +1 -1
  19. package/dist/Components/ActionText.js +23 -2
  20. package/dist/Components/ActionText.js.map +1 -1
  21. package/dist/Components/ActionTextEditable.js +45 -3
  22. package/dist/Components/ActionTextEditable.js.map +1 -1
  23. package/dist/Components/Actions.js +25 -4
  24. package/dist/Components/Actions.js.map +1 -1
  25. package/dist/Components/AppContent.js +21 -1
  26. package/dist/Components/AppContent.js.map +1 -1
  27. package/dist/Components/AppContentDetails.js +1 -1
  28. package/dist/Components/AppContentDetails.js.map +1 -1
  29. package/dist/Components/AppContentList.js +1 -1
  30. package/dist/Components/AppContentList.js.map +1 -1
  31. package/dist/Components/AppNavigation.js +109 -2
  32. package/dist/Components/AppNavigation.js.map +1 -1
  33. package/dist/Components/AppNavigationCaption.js +66 -1
  34. package/dist/Components/AppNavigationCaption.js.map +1 -1
  35. package/dist/Components/AppNavigationCounter.js +2 -2
  36. package/dist/Components/AppNavigationCounter.js.map +1 -1
  37. package/dist/Components/AppNavigationIconBullet.js +2 -2
  38. package/dist/Components/AppNavigationIconBullet.js.map +1 -1
  39. package/dist/Components/AppNavigationItem.js +49 -7
  40. package/dist/Components/AppNavigationItem.js.map +1 -1
  41. package/dist/Components/AppNavigationNew.js +1 -1
  42. package/dist/Components/AppNavigationNew.js.map +1 -1
  43. package/dist/Components/AppNavigationNewItem.js +2 -2
  44. package/dist/Components/AppNavigationNewItem.js.map +1 -1
  45. package/dist/Components/AppNavigationSettings.js +5 -5
  46. package/dist/Components/AppNavigationSettings.js.map +1 -1
  47. package/dist/Components/AppNavigationSpacer.js +1 -1
  48. package/dist/Components/AppNavigationSpacer.js.map +1 -1
  49. package/dist/Components/AppNavigationToggle.js +109 -2
  50. package/dist/Components/AppNavigationToggle.js.map +1 -1
  51. package/dist/Components/AppSettingsDialog.js +64 -22
  52. package/dist/Components/AppSettingsDialog.js.map +1 -1
  53. package/dist/Components/AppSettingsSection.js +1 -1
  54. package/dist/Components/AppSettingsSection.js.map +1 -1
  55. package/dist/Components/AppSidebar.js +38 -17
  56. package/dist/Components/AppSidebar.js.map +1 -1
  57. package/dist/Components/AppSidebarTab.js +1 -1
  58. package/dist/Components/AppSidebarTab.js.map +1 -1
  59. package/dist/Components/Avatar.js +9 -10
  60. package/dist/Components/Avatar.js.map +1 -1
  61. package/dist/Components/Breadcrumb.js +33 -12
  62. package/dist/Components/Breadcrumb.js.map +1 -1
  63. package/dist/Components/Breadcrumbs.js +59 -17
  64. package/dist/Components/Breadcrumbs.js.map +1 -1
  65. package/dist/Components/CheckboxRadioSwitch.js +44 -0
  66. package/dist/Components/CheckboxRadioSwitch.js.map +1 -0
  67. package/dist/Components/ColorPicker.js +6 -7
  68. package/dist/Components/ColorPicker.js.map +1 -1
  69. package/dist/Components/Content.js +2 -2
  70. package/dist/Components/Content.js.map +1 -1
  71. package/dist/Components/CounterBubble.js +23 -0
  72. package/dist/Components/CounterBubble.js.map +1 -0
  73. package/dist/Components/DatetimePicker.js +341 -3
  74. package/dist/Components/DatetimePicker.js.map +1 -1
  75. package/dist/Components/EmojiPicker.js +14 -14
  76. package/dist/Components/EmojiPicker.js.map +1 -1
  77. package/dist/Components/EmptyContent.js +2 -2
  78. package/dist/Components/EmptyContent.js.map +1 -1
  79. package/dist/Components/Highlight.js +3 -3
  80. package/dist/Components/Highlight.js.map +1 -1
  81. package/dist/Components/ListItem.js +130 -0
  82. package/dist/Components/ListItem.js.map +1 -0
  83. package/dist/Components/ListItemIcon.js +20 -21
  84. package/dist/Components/ListItemIcon.js.map +1 -1
  85. package/dist/Components/Modal.js +53 -11
  86. package/dist/Components/Modal.js.map +1 -1
  87. package/dist/Components/Multiselect.js +22 -23
  88. package/dist/Components/Multiselect.js.map +1 -1
  89. package/dist/Components/MultiselectTags.js +24 -25
  90. package/dist/Components/MultiselectTags.js.map +1 -1
  91. package/dist/Components/Popover.js +2 -2
  92. package/dist/Components/Popover.js.map +1 -1
  93. package/dist/Components/PopoverMenu.js +1 -1
  94. package/dist/Components/PopoverMenu.js.map +1 -1
  95. package/dist/Components/ProgressBar.js +2 -2
  96. package/dist/Components/ProgressBar.js.map +1 -1
  97. package/dist/Components/RichContenteditable.js +2 -2
  98. package/dist/Components/RichContenteditable.js.map +1 -1
  99. package/dist/Components/SettingsInputText.js +22 -1
  100. package/dist/Components/SettingsInputText.js.map +1 -1
  101. package/dist/Components/SettingsSection.js +2 -2
  102. package/dist/Components/SettingsSection.js.map +1 -1
  103. package/dist/Components/SettingsSelectGroup.js +41 -21
  104. package/dist/Components/SettingsSelectGroup.js.map +1 -1
  105. package/dist/Components/TimezonePicker.js +340 -0
  106. package/dist/Components/TimezonePicker.js.map +1 -0
  107. package/dist/Components/UserBubble.js +35 -36
  108. package/dist/Components/UserBubble.js.map +1 -1
  109. package/dist/Directives/Focus.js +1 -1
  110. package/dist/Directives/Focus.js.map +1 -1
  111. package/dist/Directives/Linkify.js +1 -1
  112. package/dist/Directives/Linkify.js.map +1 -1
  113. package/dist/Directives/Tooltip.js +2 -2
  114. package/dist/Directives/Tooltip.js.map +1 -1
  115. package/dist/Functions/usernameToColor.js +2 -3
  116. package/dist/Functions/usernameToColor.js.map +1 -1
  117. package/dist/Mixins/excludeClickOutsideClasses.js +2 -2
  118. package/dist/Mixins/excludeClickOutsideClasses.js.map +1 -1
  119. package/dist/Mixins/isFullscreen.js +1 -1
  120. package/dist/Mixins/isFullscreen.js.map +1 -1
  121. package/dist/Mixins/isMobile.js +1 -1
  122. package/dist/Mixins/isMobile.js.map +1 -1
  123. package/dist/Mixins/richEditor.js +1 -1
  124. package/dist/Mixins/richEditor.js.map +1 -1
  125. package/dist/ncvuecomponents.js +276 -69
  126. package/dist/ncvuecomponents.js.map +1 -1
  127. package/package.json +28 -43
  128. package/src/assets/action.scss +0 -132
  129. package/src/assets/iconfont/README.md +0 -30
  130. package/src/assets/iconfont/arrow-left-double.svg +0 -3
  131. package/src/assets/iconfont/arrow-left.svg +0 -3
  132. package/src/assets/iconfont/arrow-right-double.svg +0 -3
  133. package/src/assets/iconfont/arrow-right.svg +0 -3
  134. package/src/assets/iconfont/breadcrumb.svg +0 -1
  135. package/src/assets/iconfont/checkmark.svg +0 -1
  136. package/src/assets/iconfont/close.svg +0 -1
  137. package/src/assets/iconfont/confirm.svg +0 -1
  138. package/src/assets/iconfont/info.svg +0 -1
  139. package/src/assets/iconfont/menu.svg +0 -1
  140. package/src/assets/iconfont/more.svg +0 -1
  141. package/src/assets/iconfont/pause.svg +0 -1
  142. package/src/assets/iconfont/play.svg +0 -1
  143. package/src/assets/iconfont/triangle-s.svg +0 -1
  144. package/src/assets/iconfont/user-status-away.svg +0 -2
  145. package/src/assets/iconfont/user-status-dnd.svg +0 -2
  146. package/src/assets/iconfont/user-status-invisible.svg +0 -2
  147. package/src/assets/iconfont/user-status-online.svg +0 -2
  148. package/src/assets/inputs.scss +0 -104
  149. package/src/assets/variables.scss +0 -57
  150. package/src/components/ActionButton/ActionButton.vue +0 -160
  151. package/src/components/ActionButton/index.js +0 -24
  152. package/src/components/ActionCheckbox/ActionCheckbox.vue +0 -220
  153. package/src/components/ActionCheckbox/index.js +0 -24
  154. package/src/components/ActionInput/ActionInput.vue +0 -418
  155. package/src/components/ActionInput/index.js +0 -24
  156. package/src/components/ActionLink/ActionLink.vue +0 -132
  157. package/src/components/ActionLink/index.js +0 -24
  158. package/src/components/ActionRadio/ActionRadio.vue +0 -219
  159. package/src/components/ActionRadio/index.js +0 -24
  160. package/src/components/ActionRouter/ActionRouter.vue +0 -100
  161. package/src/components/ActionRouter/index.js +0 -24
  162. package/src/components/ActionSeparator/ActionSeparator.vue +0 -43
  163. package/src/components/ActionSeparator/index.js +0 -24
  164. package/src/components/ActionText/ActionText.vue +0 -87
  165. package/src/components/ActionText/index.js +0 -24
  166. package/src/components/ActionTextEditable/ActionTextEditable.vue +0 -306
  167. package/src/components/ActionTextEditable/index.js +0 -24
  168. package/src/components/Actions/Actions.vue +0 -764
  169. package/src/components/Actions/index.js +0 -24
  170. package/src/components/AppContent/AppContent.vue +0 -93
  171. package/src/components/AppContent/index.js +0 -23
  172. package/src/components/AppContentDetails/AppContentDetails.vue +0 -34
  173. package/src/components/AppContentDetails/index.js +0 -23
  174. package/src/components/AppContentList/AppContentList.vue +0 -44
  175. package/src/components/AppContentList/index.js +0 -23
  176. package/src/components/AppNavigation/AppNavigation.vue +0 -190
  177. package/src/components/AppNavigation/index.js +0 -23
  178. package/src/components/AppNavigationCaption/AppNavigationCaption.vue +0 -39
  179. package/src/components/AppNavigationCaption/index.js +0 -3
  180. package/src/components/AppNavigationCounter/AppNavigationCounter.vue +0 -82
  181. package/src/components/AppNavigationCounter/index.js +0 -25
  182. package/src/components/AppNavigationIconBullet/AppNavigationIconBullet.vue +0 -95
  183. package/src/components/AppNavigationIconBullet/index.js +0 -24
  184. package/src/components/AppNavigationItem/AppNavigationIconCollapsible.vue +0 -90
  185. package/src/components/AppNavigationItem/AppNavigationItem.vue +0 -629
  186. package/src/components/AppNavigationItem/InputConfirmCancel.vue +0 -134
  187. package/src/components/AppNavigationItem/index.js +0 -24
  188. package/src/components/AppNavigationNew/AppNavigationNew.vue +0 -76
  189. package/src/components/AppNavigationNew/index.js +0 -23
  190. package/src/components/AppNavigationNewItem/AppNavigationNewItem.vue +0 -165
  191. package/src/components/AppNavigationNewItem/index.js +0 -24
  192. package/src/components/AppNavigationSettings/AppNavigationSettings.vue +0 -105
  193. package/src/components/AppNavigationSettings/index.js +0 -23
  194. package/src/components/AppNavigationSpacer/AppNavigationSpacer.vue +0 -39
  195. package/src/components/AppNavigationSpacer/index.js +0 -23
  196. package/src/components/AppNavigationToggle/AppNavigationToggle.vue +0 -78
  197. package/src/components/AppNavigationToggle/index.js +0 -24
  198. package/src/components/AppSettingsDialog/AppSettingsDialog.vue +0 -331
  199. package/src/components/AppSettingsDialog/index.js +0 -25
  200. package/src/components/AppSettingsSection/AppSettingsSection.vue +0 -64
  201. package/src/components/AppSettingsSection/index.js +0 -25
  202. package/src/components/AppSidebar/AppSidebar.vue +0 -802
  203. package/src/components/AppSidebar/AppSidebarTabs.vue +0 -348
  204. package/src/components/AppSidebar/index.js +0 -23
  205. package/src/components/AppSidebarTab/AppSidebarTab.vue +0 -103
  206. package/src/components/AppSidebarTab/index.js +0 -23
  207. package/src/components/Avatar/Avatar.vue +0 -758
  208. package/src/components/Avatar/index.js +0 -25
  209. package/src/components/Breadcrumb/Breadcrumb.vue +0 -262
  210. package/src/components/Breadcrumb/index.js +0 -25
  211. package/src/components/Breadcrumbs/Breadcrumbs.vue +0 -537
  212. package/src/components/Breadcrumbs/index.js +0 -25
  213. package/src/components/ColorPicker/ColorPicker.vue +0 -380
  214. package/src/components/ColorPicker/index.js +0 -25
  215. package/src/components/Content/Content.vue +0 -77
  216. package/src/components/Content/index.js +0 -23
  217. package/src/components/DatetimePicker/DatetimePicker.vue +0 -195
  218. package/src/components/DatetimePicker/index.js +0 -28
  219. package/src/components/DatetimePicker/index.scss +0 -405
  220. package/src/components/EmojiPicker/EmojiPicker.vue +0 -302
  221. package/src/components/EmojiPicker/index.js +0 -23
  222. package/src/components/EmptyContent/EmptyContent.vue +0 -120
  223. package/src/components/EmptyContent/index.js +0 -24
  224. package/src/components/Highlight/Highlight.vue +0 -183
  225. package/src/components/Highlight/index.js +0 -25
  226. package/src/components/ListItemIcon/ListItemIcon.vue +0 -277
  227. package/src/components/ListItemIcon/index.js +0 -25
  228. package/src/components/Modal/Modal.vue +0 -833
  229. package/src/components/Modal/index.js +0 -27
  230. package/src/components/Multiselect/EllipsisedOption.vue +0 -141
  231. package/src/components/Multiselect/Multiselect.vue +0 -430
  232. package/src/components/Multiselect/index.js +0 -28
  233. package/src/components/Multiselect/index.scss +0 -290
  234. package/src/components/MultiselectTags/MultiselectTags.vue +0 -179
  235. package/src/components/MultiselectTags/api.js +0 -115
  236. package/src/components/MultiselectTags/index.js +0 -23
  237. package/src/components/Popover/Popover.vue +0 -208
  238. package/src/components/Popover/index.js +0 -25
  239. package/src/components/PopoverMenu/PopoverMenu.vue +0 -62
  240. package/src/components/PopoverMenu/PopoverMenuItem.vue +0 -382
  241. package/src/components/PopoverMenu/index.js +0 -24
  242. package/src/components/ProgressBar/ProgressBar.vue +0 -135
  243. package/src/components/ProgressBar/index.js +0 -25
  244. package/src/components/RichContenteditable/AutoCompleteResult.vue +0 -191
  245. package/src/components/RichContenteditable/MentionBubble.vue +0 -165
  246. package/src/components/RichContenteditable/RichContenteditable.vue +0 -517
  247. package/src/components/RichContenteditable/index.js +0 -25
  248. package/src/components/SettingsInputText/SettingsInputText.vue +0 -207
  249. package/src/components/SettingsInputText/index.js +0 -24
  250. package/src/components/SettingsSection/SettingsSection.vue +0 -151
  251. package/src/components/SettingsSection/index.js +0 -24
  252. package/src/components/SettingsSelectGroup/SettingsSelectGroup.vue +0 -149
  253. package/src/components/SettingsSelectGroup/index.js +0 -25
  254. package/src/components/UserBubble/UserBubble.vue +0 -319
  255. package/src/components/UserBubble/index.js +0 -25
  256. package/src/components/index.js +0 -110
  257. package/src/directives/Focus/index.js +0 -29
  258. package/src/directives/Linkify/index.js +0 -31
  259. package/src/directives/Tooltip/index.js +0 -32
  260. package/src/directives/Tooltip/index.scss +0 -117
  261. package/src/directives/index.js +0 -31
  262. package/src/fonts/iconfont-vue-f56d517.eot +0 -0
  263. package/src/fonts/iconfont-vue-f56d517.svg +0 -1
  264. package/src/fonts/iconfont-vue-f56d517.ttf +0 -0
  265. package/src/fonts/iconfont-vue-f56d517.woff +0 -0
  266. package/src/fonts/scss/iconfont-vue.scss +0 -115
  267. package/src/functions/usernameToColor/index.js +0 -25
  268. package/src/functions/usernameToColor/usernameToColor.js +0 -68
  269. package/src/index.js +0 -40
  270. package/src/l10n.js +0 -42
  271. package/src/mixins/actionGlobal.js +0 -59
  272. package/src/mixins/actionText.js +0 -85
  273. package/src/mixins/excludeClickOutsideClasses/index.js +0 -72
  274. package/src/mixins/index.js +0 -35
  275. package/src/mixins/isFullscreen/index.js +0 -46
  276. package/src/mixins/isMobile/index.js +0 -43
  277. package/src/mixins/l10n.js +0 -8
  278. package/src/mixins/richEditor/index.js +0 -160
  279. package/src/mixins/userStatus.js +0 -76
  280. package/src/utils/FindRanges.js +0 -47
  281. package/src/utils/GenColors.js +0 -79
  282. package/src/utils/GenRandomId.js +0 -31
  283. package/src/utils/GetChildren.js +0 -47
  284. package/src/utils/GetParent.js +0 -41
  285. package/src/utils/IsMobileState.js +0 -49
  286. package/src/utils/IsOutOfViewport.js +0 -36
  287. package/src/utils/ScopeComponent.js +0 -37
  288. package/src/utils/Timer.js +0 -61
  289. package/src/utils/ValidateChildren.js +0 -50
  290. package/src/utils/ValidateSlot.js +0 -57
@@ -1,517 +0,0 @@
1
- <!--
2
- - @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com>
3
- -
4
- - @author John Molakvoæ <skjnldsv@protonmail.com>
5
- -
6
- - @license GNU AGPL version 3 or any later version
7
- -
8
- - This program is free software: you can redistribute it and/or modify
9
- - it under the terms of the GNU Affero General Public License as
10
- - published by the Free Software Foundation, either version 3 of the
11
- - License, or (at your option) any later version.
12
- -
13
- - This program is distributed in the hope that it will be useful,
14
- - but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- - GNU Affero General Public License for more details.
17
- -
18
- - You should have received a copy of the GNU Affero General Public License
19
- - along with this program. If not, see <http://www.gnu.org/licenses/>.
20
- -->
21
-
22
- <docs>
23
-
24
- ### General description
25
-
26
- This component displays contenteditable div with automated @ autocompletion [at].
27
-
28
- ### Examples
29
-
30
- ```vue
31
- <template>
32
- <div>
33
- <RichContenteditable
34
- v-model="message"
35
- :auto-complete="autoComplete"
36
- :maxlength="100"
37
- :user-data="userData"
38
- placeholder="Try mentioning the user Test01"
39
- @submit="onSubmit" />
40
- <br>
41
-
42
- <RichContenteditable
43
- v-model="message"
44
- :auto-complete="autoComplete"
45
- :maxlength="400"
46
- :multiline="true"
47
- :user-data="userData"
48
- placeholder="Try mentioning the user Test01"
49
- @submit="onSubmit" />
50
- <br>
51
- <br>
52
- {{ JSON.stringify(message) }}
53
- </div>
54
- </template>
55
- <script>
56
- export default {
57
- data() {
58
- return {
59
- message: 'Lorem ipsum dolor sit amet.',
60
-
61
- // You need to provide this for the inline
62
- // mention to understand what to display or not.
63
- userData: {
64
- Test01: {
65
- icon: 'icon-user',
66
- id: 'Test01',
67
- label: 'Test01',
68
- source: 'users',
69
- primary: true,
70
- },
71
- Test02: {
72
- icon: 'icon-user',
73
- id: 'Test02',
74
- label: 'Test02',
75
- source: 'users',
76
- status: {
77
- clearAt: null,
78
- icon: '🎡',
79
- message: 'Visiting London',
80
- status: 'away',
81
- },
82
- subline: 'Visiting London',
83
- }
84
- }
85
- }
86
- },
87
- methods: {
88
- /**
89
- * Do your own query to the autocompletion api.
90
- * The returned data bellow is a fake data example.
91
- * The callback expects the same format returned by the core/autocomplete/get ocs api endpoint!
92
- * @see userData example above
93
- *
94
- * @param {string} search the query
95
- * @param {Function} callback the callback to process the results with
96
- */
97
- autoComplete(search, callback) {
98
- callback(Object.values(this.userData))
99
- },
100
- onSubmit() {
101
- alert(this.message)
102
- }
103
- }
104
- }
105
- </script>
106
- ```
107
-
108
- </docs>
109
-
110
- <template>
111
- <div ref="contenteditable"
112
- v-tooltip="tooltip"
113
- :class="{
114
- 'rich-contenteditable__input--empty': isEmptyValue,
115
- 'rich-contenteditable__input--multiline': multiline,
116
- 'rich-contenteditable__input--overflow': isOverMaxlength,
117
- }"
118
- :contenteditable="contenteditable"
119
- :placeholder="placeholder"
120
- aria-multiline="true"
121
- class="rich-contenteditable__input"
122
- role="textbox"
123
- @input="onInput"
124
- v-on="$listeners"
125
- @keydown.delete="onDelete"
126
- @keydown.enter.exact="onEnter"
127
- @keydown.ctrl.enter.exact.stop.prevent="onCtrlEnter"
128
- @paste="onPaste" />
129
- </template>
130
-
131
- <script>
132
- import Tribute from 'tributejs/dist/tribute.esm'
133
- import debounce from 'debounce'
134
- import stringLength from 'string-length'
135
-
136
- import { t } from '../../l10n.js'
137
- import AutoCompleteResult from './AutoCompleteResult'
138
- import richEditor from '../../mixins/richEditor/index'
139
-
140
- export default {
141
- name: 'RichContenteditable',
142
-
143
- mixins: [richEditor],
144
-
145
- props: {
146
- value: {
147
- type: String,
148
- default: '',
149
- required: true,
150
- },
151
- placeholder: {
152
- type: String,
153
- default: t('Write message, @ to mention someone …'),
154
- },
155
- autoComplete: {
156
- type: Function,
157
- required: true,
158
- },
159
- menuContainer: {
160
- type: Element,
161
- default: () => document.body,
162
- },
163
-
164
- /**
165
- * Make the contenteditable looks like a textarea or not.
166
- * Default looks like a single-line input.
167
- * This also handle the default enter/shift+enter behaviour.
168
- * if multiline, enter = newline; otherwise enter = submit
169
- * shift+enter always add a new line. ctrl+enter always submits
170
- */
171
- multiline: {
172
- type: Boolean,
173
- default: false,
174
- },
175
-
176
- /**
177
- * Is the content editable ?
178
- */
179
- contenteditable: {
180
- type: Boolean,
181
- default: true,
182
- },
183
-
184
- /**
185
- * Max allowed length
186
- */
187
- maxlength: {
188
- type: Number,
189
- default: null,
190
- },
191
- },
192
-
193
- data() {
194
- return {
195
- tribute: null,
196
- options: {
197
- fillAttr: 'id',
198
- // Search against id and label (display name)
199
- lookup: result => `${result.id} ${result.label}`,
200
- // Where to inject the menu popup
201
- menuContainer: this.menuContainer,
202
- // Popup mention autocompletion templates
203
- menuItemTemplate: item => this.renderComponentHtml(item.original, AutoCompleteResult),
204
- // Hide if no results
205
- noMatchTemplate: () => '<span class="hidden"></span>',
206
- // Inner display of mentions
207
- selectTemplate: item => this.genSelectTemplate(item?.original?.id),
208
- // Autocompletion results
209
- values: this.debouncedAutoComplete,
210
- },
211
-
212
- // Represent the raw untrimmed text of the contenteditable
213
- // serves no other purpose than to check whether the
214
- // content is empty or not
215
- localValue: this.value,
216
- }
217
- },
218
-
219
- computed: {
220
- /**
221
- * Is the current trimmed value empty?
222
- * @returns {boolean}
223
- */
224
- isEmptyValue() {
225
- return !this.localValue
226
- || (this.localValue && this.localValue.trim() === '')
227
- },
228
-
229
- /**
230
- * Is this Firefox? 🙄
231
- * @returns {boolean}
232
- */
233
- isFF() {
234
- return !!navigator.userAgent.match(/firefox/i)
235
- },
236
-
237
- /**
238
- * Is the current value over maxlength?
239
- * @returns {boolean}
240
- */
241
- isOverMaxlength() {
242
- if (this.isEmptyValue || !this.maxlength) {
243
- return false
244
- }
245
- return stringLength(this.localValue) > this.maxlength
246
- },
247
-
248
- /**
249
- * Tooltip to show if characters count is over limit
250
- * @returns {string}
251
- */
252
- tooltip() {
253
- if (!this.isOverMaxlength) {
254
- return null
255
- }
256
- return {
257
- content: t('Message limit of {count} characters reached', { count: this.maxlength }),
258
- show: true,
259
- trigger: 'manual',
260
- }
261
- },
262
- },
263
-
264
- watch: {
265
- /**
266
- * If the parent value change, we compare the plain text rendering
267
- * If it's different, we render everything and update the main content
268
- */
269
- value() {
270
- const html = this.$refs.contenteditable.innerHTML
271
- // Compare trimmed versions to be safe
272
- if (this.value.trim() !== this.parseContent(html).trim()) {
273
- this.updateContent(this.value)
274
- }
275
- },
276
- },
277
-
278
- mounted() {
279
- this.tribute = new Tribute(this.options)
280
- this.tribute.attach(this.$el)
281
-
282
- // Update default value
283
- this.updateContent(this.value)
284
-
285
- // Removes the contenteditable attribute at first load if the prop is
286
- // set to false.
287
- this.$refs.contenteditable.contentEditable = this.contenteditable
288
- },
289
- beforeDestroy() {
290
- if (this.tribute) {
291
- this.tribute.detach(this.$el)
292
- }
293
- },
294
-
295
- methods: {
296
- /**
297
- * Re-emit the input event to the parent
298
- * @param {Event} event the input event
299
- */
300
- onInput(event) {
301
- this.updateValue(event.target.innerHTML)
302
- },
303
-
304
- /**
305
- * When pasting, sanitize the content, extract text
306
- * and render it again
307
- * @param {Event} event the paste event
308
- * @emits {Event} paste the original paste event
309
- */
310
- onPaste(event) {
311
- event.preventDefault()
312
- const clipboardData = event.clipboardData
313
-
314
- /** The original paste event */
315
- this.$emit('paste', event)
316
-
317
- // If we have a file or if we don't have any text, ignore
318
- if (clipboardData.files.length !== 0
319
- || !Object.values(clipboardData.items).find(item => item?.type.startsWith('text'))) {
320
- return
321
- }
322
-
323
- const html = clipboardData.getData('text')
324
- const selection = window.getSelection()
325
-
326
- // If no selection, replace the whole data
327
- if (!selection.rangeCount) {
328
- this.updateValue(html)
329
- }
330
-
331
- // Generate text and insert
332
- const text = this.parseContent(html)
333
- const range = selection.getRangeAt(0)
334
- selection.deleteFromDocument()
335
- range.insertNode(document.createTextNode(text))
336
-
337
- // Put cursor at the end of the selection
338
- const newRange = document.createRange()
339
- newRange.setStart(event.target, range.endOffset)
340
- newRange.collapse(true)
341
- selection.removeAllRanges()
342
- selection.addRange(newRange)
343
-
344
- // Propagate data
345
- this.updateValue(event.target.innerHTML)
346
- },
347
-
348
- /**
349
- * Update the value text from the provided html
350
- * @param {string} htmlOrText the html content (or raw text with @mentions)
351
- */
352
- updateValue(htmlOrText) {
353
- const text = this.parseContent(htmlOrText)
354
- this.localValue = text
355
- this.$emit('input', text)
356
- this.$emit('update:value', text)
357
- },
358
-
359
- /**
360
- * Update content and local value
361
- * @param {string} value the message value
362
- */
363
- updateContent(value) {
364
- const renderedContent = this.renderContent(value)
365
- this.$refs.contenteditable.innerHTML = renderedContent
366
- this.localValue = value
367
- },
368
-
369
- /**
370
- * Because FF have a decade old bug preventing contenteditable=false
371
- * to properly be deleted on backspace, we have to hack 👀
372
- * https://stackoverflow.com/a/59383394/3885878
373
- * https://stackoverflow.com/a/30574622
374
- *
375
- * @param {Event} event the delete keydown event
376
- */
377
- onDelete(event) {
378
- if (!this.isFF || !window.getSelection) {
379
- return
380
- }
381
-
382
- // fix backspace bug in FF
383
- // https://bugzilla.mozilla.org/show_bug.cgi?id=685445
384
- const selection = window.getSelection()
385
- const node = event.target
386
- if (!selection.isCollapsed || !selection.rangeCount) {
387
- return
388
- }
389
-
390
- const curRange = selection.getRangeAt(selection.rangeCount - 1)
391
- if (curRange.commonAncestorContainer.nodeType === 3 && curRange.startOffset > 0) {
392
- // we are in child selection. The characters of the text node is being deleted
393
- return
394
- }
395
-
396
- const range = document.createRange()
397
- if (selection.anchorNode !== node) {
398
- // selection is in character mode. expand it to the whole editable field
399
- range.selectNodeContents(node)
400
- range.setEndBefore(selection.anchorNode)
401
- } else if (selection.anchorOffset > 0) {
402
- range.setEnd(node, selection.anchorOffset)
403
- } else {
404
- // reached the beginning of editable field
405
- return
406
- }
407
- range.setStart(node, range.endOffset - 1)
408
-
409
- const previousNode = range.cloneContents().lastChild
410
- if (previousNode && previousNode.contentEditable === 'false') {
411
- // this is some rich content, e.g. smile. We should help the user to delete it
412
- range.deleteContents()
413
- event.preventDefault()
414
- }
415
- },
416
-
417
- /**
418
- * Enter key pressed. Submits if not multiline
419
- * @param {Event} event the keydown event
420
- */
421
- onEnter(event) {
422
- // Prevent submitting if autocompletion menu
423
- // is opened or length is over maxlength
424
- if (this.multiline || this.isOverMaxlength || this.tribute.isActive) {
425
- return
426
- }
427
-
428
- event.preventDefault()
429
- event.stopPropagation()
430
- this.$emit('submit', event)
431
- },
432
- /**
433
- * Ctrl + Enter key pressed
434
- * @param {Event} event the keydown event
435
- */
436
- onCtrlEnter(event) {
437
- if (this.isOverMaxlength) {
438
- return
439
- }
440
- this.$emit('submit', event)
441
- },
442
-
443
- /**
444
- * Debounce the autocomplete function
445
- */
446
- debouncedAutoComplete: debounce(async function(search, callback) {
447
- this.autoComplete(search, callback)
448
- }, 100),
449
- },
450
- }
451
- </script>
452
-
453
- <style lang="scss" scoped>
454
- // Standalone styling, independent from server
455
- .rich-contenteditable__input {
456
- overflow-y: auto;
457
- width: auto;
458
- margin: 0;
459
- padding: 6px;
460
- cursor: text;
461
- white-space: pre-wrap;
462
- word-break: break-word;
463
- color: var(--color-main-text);
464
- border: 1px solid var(--color-border-dark);
465
- border-radius: var(--border-radius);
466
- outline: none;
467
- background-color: var(--color-main-background);
468
- font-family: var(--font-face);
469
- font-size: inherit;
470
- min-height: $clickable-area;
471
- max-height: $clickable-area * 5.5;
472
-
473
- // Cannot use :empty because of firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=1513303
474
- &--empty:before {
475
- position: absolute;
476
- content: attr(placeholder);
477
- color: var(--color-text-maxcontrast);
478
- }
479
-
480
- &[contenteditable='false'] {
481
- cursor: default;
482
- opacity: .5;
483
- color: var(--color-text-lighter);
484
- border: 1px solid var(--color-background-darker);
485
- border-radius: var(--border-radius);
486
- background-color: var(--color-background-dark);
487
- }
488
-
489
- &--multiline {
490
- min-height: $clickable-area * 3;
491
- // No max for mutiline
492
- max-height: none;
493
- }
494
- }
495
-
496
- </style>
497
-
498
- <style lang="scss">
499
- @import '../../fonts/scss/iconfont-vue';
500
-
501
- .tribute-container {
502
- z-index: 9000;
503
- overflow: auto;
504
- min-width: 250px;
505
- max-width: 300px;
506
- // Show maximum 4 entries and a half to show scroll
507
- // 44px + 10px padding
508
- max-height: ($clickable-area + 20px) * 4.5;
509
- // Space it out a bit from the text
510
- margin: 5px 0;
511
- color: var(--color-main-text);
512
- border-radius: var(--border-radius);
513
- background: var(--color-main-background);
514
- box-shadow: 0 1px 5px var(--color-box-shadow);
515
- }
516
-
517
- </style>