@oat-sa/tao-core-ui 3.13.2 → 3.13.4

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.
@@ -55,6 +55,15 @@ define(['jquery', 'lodash', 'ui/ckeditor/dtdHandler', 'ckeditor', 'context', 'mo
55
55
  }, {
56
56
  name: 'language',
57
57
  items: ['Language']
58
+ }, {
59
+ name: 'styles',
60
+ items: ['Format']
61
+ }, {
62
+ name: 'paragraph',
63
+ items: ['NumberedList', 'BulletedList', '-', 'Blockquote', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock']
64
+ }, {
65
+ name: 'interactionsource',
66
+ items: ['InteractionSource']
58
67
  }],
59
68
  flow: [{
60
69
  name: 'basicstyles',
@@ -68,6 +77,9 @@ define(['jquery', 'lodash', 'ui/ckeditor/dtdHandler', 'ckeditor', 'context', 'mo
68
77
  }, {
69
78
  name: 'language',
70
79
  items: ['Language']
80
+ }, {
81
+ name: 'interactionsource',
82
+ items: ['InteractionSource']
71
83
  }],
72
84
  block: [{
73
85
  name: 'basicstyles',
@@ -87,6 +99,9 @@ define(['jquery', 'lodash', 'ui/ckeditor/dtdHandler', 'ckeditor', 'context', 'mo
87
99
  }, {
88
100
  name: 'paragraph',
89
101
  items: ['NumberedList', 'BulletedList', '-', 'Blockquote', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock']
102
+ }, {
103
+ name: 'interactionsource',
104
+ items: ['InteractionSource']
90
105
  }],
91
106
  extendedText: [{
92
107
  name: 'basicstyles',
@@ -140,6 +155,9 @@ define(['jquery', 'lodash', 'ui/ckeditor/dtdHandler', 'ckeditor', 'context', 'mo
140
155
  }, {
141
156
  name: 'language',
142
157
  items: ['Language']
158
+ }, {
159
+ name: 'interactionsource',
160
+ items: ['InteractionSource']
143
161
  }],
144
162
  table: [{
145
163
  name: 'basicstyles',
@@ -156,6 +174,9 @@ define(['jquery', 'lodash', 'ui/ckeditor/dtdHandler', 'ckeditor', 'context', 'mo
156
174
  }, {
157
175
  name: 'language',
158
176
  items: ['Language']
177
+ }, {
178
+ name: 'interactionsource',
179
+ items: ['InteractionSource']
159
180
  }]
160
181
  };
161
182
 
@@ -167,7 +188,7 @@ define(['jquery', 'lodash', 'ui/ckeditor/dtdHandler', 'ckeditor', 'context', 'mo
167
188
  entities: false,
168
189
  entities_processNumerical: true,
169
190
  autoParagraph: false,
170
- extraPlugins: 'confighelper, taolanguage',
191
+ extraPlugins: 'confighelper, taolanguage, interactionsource',
171
192
  floatSpaceDockedOffsetY: 0,
172
193
  forcePasteAsPlainText: true,
173
194
  skin: 'tao',
@@ -119,6 +119,182 @@ define(['jquery', 'lodash', 'interact', 'core/mouseEvent'], function ($, _, inte
119
119
  domElement.style.transform = 'translate(0px, 0px) translateZ(0px)';
120
120
  domElement.setAttribute('data-x', 0);
121
121
  domElement.setAttribute('data-y', 0);
122
+ },
123
+ /**
124
+ * Improve touch devices support:
125
+ * - prevent native scroll while dragging
126
+ * - start drag only after longpress:
127
+ * when user is scrolling through the long page, he can accidentally get his finger on the draggable element:
128
+ * this will cause unwanted, unnoticed drag and can mess up his response.
129
+ * @example
130
+ * touchPatch = interactUtils.touchPatchFactory();
131
+ * interact(selector)
132
+ * .draggable({
133
+ onstart: () => {
134
+ touchPatch.onstart();
135
+ },
136
+ onend: () => {
137
+ touchPatch.onend();
138
+ }
139
+ })
140
+ .actionChecker(touchPatch.actionChecker);
141
+ ...
142
+ function destroy() {
143
+ ` touchPatch.destroy()
144
+ interact(selector).unset();
145
+ }
146
+ * @returns {Object}
147
+ */
148
+ touchPatchFactory: function touchPatchFactory() {
149
+ const delayBefore = 300;
150
+ const distanceTolerance = 20; //while waiting for delayBefore, finger can move a little bit
151
+
152
+ interact.pointerMoveTolerance(distanceTolerance);
153
+ let isDragging = false;
154
+
155
+ // webKit requires cancelable `touchmove` events to be added as early as possible
156
+ // alternative: `touch-action: pinch-zoom` css: add it after drag start [?]; or have it always - worse ux
157
+ function touchmoveListener(e) {
158
+ if (isDragging) {
159
+ e.preventDefault();
160
+ }
161
+ }
162
+ window.addEventListener('touchmove', touchmoveListener, {
163
+ passive: false
164
+ });
165
+ function contextmenuListener(e) {
166
+ e.preventDefault();
167
+ }
168
+ return {
169
+ /**
170
+ * @param {PointerEvent} pointer
171
+ * @param {PointerEvent} event
172
+ * @param {Object} action
173
+ * @param {Object} interactable
174
+ * @returns {Object}
175
+ */
176
+ actionChecker: (pointer, event, action, interactable, element) => {
177
+ if (event && action && action.name === 'drag') {
178
+ const isTouch = event.pointerType === 'touch';
179
+ interactable.options[action.name].delay = isTouch ? delayBefore : 0;
180
+ if (isTouch && !element.dataset.noContextMenu) {
181
+ //prevent context menu on longpress
182
+ //this listener can stay forever until the element is destroyed
183
+ element.addEventListener('contextmenu', contextmenuListener);
184
+ element.dataset.noContextMenu = true;
185
+ }
186
+ }
187
+ return action;
188
+ },
189
+ onstart: () => {
190
+ isDragging = true;
191
+ },
192
+ onend: () => {
193
+ isDragging = false;
194
+ },
195
+ destroy: () => {
196
+ window.removeEventListener('touchmove', touchmoveListener);
197
+ }
198
+ };
199
+ },
200
+ /**
201
+ * Builds a scroll observer that will make sure the dragged element keeps an accurate positioning
202
+ * @example
203
+ * scrollObserver = interactUtils.scrollObserverFactory($container);
204
+ * dragOptions = {
205
+ autoScroll: {
206
+ container: scrollObserver.getScrollContainer().get(0)
207
+ },
208
+ onstart: function (e) {
209
+ scrollObserver.start($activeChoice);
210
+ },
211
+ onend: function (e) {
212
+ scrollObserver.stop();
213
+ }
214
+ };
215
+ * @param {jQuery} $scrollContainer
216
+ * @returns {scrollObserver}
217
+ */
218
+ scrollObserverFactory: function scrollObserverFactory($scrollContainer) {
219
+ let currentDraggable = null;
220
+ let beforeY = 0;
221
+ let beforeX = 0;
222
+ let afterY = 0;
223
+ let afterX = 0;
224
+
225
+ // reset the scroll observer context
226
+ function resetScrollObserver() {
227
+ currentDraggable = null;
228
+ beforeY = 0;
229
+ beforeX = 0;
230
+ afterY = 0;
231
+ afterX = 0;
232
+ }
233
+
234
+ // keep the position of the dragged element accurate with the scroll position
235
+ function onScrollCb() {
236
+ let x;
237
+ let y;
238
+ if (currentDraggable) {
239
+ beforeY = afterY;
240
+ beforeX = afterX;
241
+ if (afterY === 0 && beforeY === 0) beforeY = this.scrollTop;
242
+ if (afterX === 0 && beforeX === 0) beforeX = this.scrollLeft;
243
+ afterY = this.scrollTop;
244
+ afterX = this.scrollLeft;
245
+ y = (parseInt(currentDraggable.getAttribute('data-y'), 10) || 0) + (afterY - beforeY);
246
+ x = (parseInt(currentDraggable.getAttribute('data-x'), 10) || 0) + (afterX - beforeX);
247
+
248
+ // translate the element
249
+ currentDraggable.style.webkitTransform = currentDraggable.style.transform = `translate(${x}px, ${y}px)`;
250
+
251
+ // update the position attributes
252
+ currentDraggable.setAttribute('data-x', x);
253
+ currentDraggable.setAttribute('data-y', y);
254
+ }
255
+ }
256
+
257
+ // find the scroll container within the parents if any
258
+ $scrollContainer.parents().each(function findScrollContainer() {
259
+ const $el = $(this);
260
+ const ovf = $el.css('overflow');
261
+ if (ovf !== 'hidden' && ovf !== 'visible') {
262
+ $scrollContainer = $el;
263
+ return false;
264
+ }
265
+ });
266
+
267
+ // make sure the drop zones will follow the scroll
268
+ interact.dynamicDrop(true);
269
+
270
+ /**
271
+ * @typedef {Object} scrollObserver
272
+ */
273
+ return {
274
+ /**
275
+ * Gets the scroll container
276
+ * @returns {jQuery}
277
+ */
278
+ getScrollContainer: function getScrollContainer() {
279
+ return $scrollContainer;
280
+ },
281
+ /**
282
+ * Initializes the scroll observer while dragging a choice
283
+ * @param {HTMLElement|jQuery} draggedElement
284
+ */
285
+ start: function start(draggedElement) {
286
+ resetScrollObserver();
287
+ currentDraggable = draggedElement instanceof $ ? draggedElement.get(0) : draggedElement;
288
+ $scrollContainer.on('scroll.scrollObserver', _.throttle(onScrollCb, 50));
289
+ },
290
+ /**
291
+ * Tears down the the scroll observer once the dragging is done
292
+ */
293
+ stop: function stop() {
294
+ $scrollContainer.off('.scrollObserver');
295
+ resetScrollObserver();
296
+ }
297
+ };
122
298
  }
123
299
  };
124
300
  var interactHelper$1 = interactHelper;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oat-sa/tao-core-ui",
3
- "version": "3.13.2",
3
+ "version": "3.13.4",
4
4
  "displayName": "TAO Core UI",
5
5
  "description": "UI libraries of TAO",
6
6
  "scripts": {
@@ -61,6 +61,19 @@ const ckConfigurator = (function () {
61
61
  {
62
62
  name: 'language',
63
63
  items: ['Language']
64
+
65
+ },
66
+ {
67
+ name: 'styles',
68
+ items: ['Format']
69
+ },
70
+ {
71
+ name: 'paragraph',
72
+ items: ['NumberedList', 'BulletedList', '-', 'Blockquote', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock']
73
+ },
74
+ {
75
+ name: 'interactionsource',
76
+ items: ['InteractionSource']
64
77
  }
65
78
  ],
66
79
  flow: [
@@ -79,6 +92,10 @@ const ckConfigurator = (function () {
79
92
  {
80
93
  name: 'language',
81
94
  items: ['Language']
95
+ },
96
+ {
97
+ name: 'interactionsource',
98
+ items: ['InteractionSource']
82
99
  }
83
100
  ],
84
101
  block: [
@@ -114,6 +131,10 @@ const ckConfigurator = (function () {
114
131
  'JustifyRight',
115
132
  'JustifyBlock'
116
133
  ]
134
+ },
135
+ {
136
+ name: 'interactionsource',
137
+ items: ['InteractionSource']
117
138
  }
118
139
  ],
119
140
  extendedText: [
@@ -186,6 +207,10 @@ const ckConfigurator = (function () {
186
207
  {
187
208
  name: 'language',
188
209
  items: ['Language']
210
+ },
211
+ {
212
+ name: 'interactionsource',
213
+ items: ['InteractionSource']
189
214
  }
190
215
  ],
191
216
  table: [
@@ -208,6 +233,10 @@ const ckConfigurator = (function () {
208
233
  {
209
234
  name: 'language',
210
235
  items: ['Language']
236
+ },
237
+ {
238
+ name: 'interactionsource',
239
+ items: ['InteractionSource']
211
240
  }
212
241
  ]
213
242
  };
@@ -220,7 +249,7 @@ const ckConfigurator = (function () {
220
249
  entities: false,
221
250
  entities_processNumerical: true,
222
251
  autoParagraph: false,
223
- extraPlugins: 'confighelper, taolanguage',
252
+ extraPlugins: 'confighelper, taolanguage, interactionsource',
224
253
  floatSpaceDockedOffsetY: 0,
225
254
  forcePasteAsPlainText: true,
226
255
  skin: 'tao',
@@ -134,6 +134,190 @@ interactHelper = {
134
134
 
135
135
  domElement.setAttribute('data-x', 0);
136
136
  domElement.setAttribute('data-y', 0);
137
+ },
138
+
139
+ /**
140
+ * Improve touch devices support:
141
+ * - prevent native scroll while dragging
142
+ * - start drag only after longpress:
143
+ * when user is scrolling through the long page, he can accidentally get his finger on the draggable element:
144
+ * this will cause unwanted, unnoticed drag and can mess up his response.
145
+ * @example
146
+ * touchPatch = interactUtils.touchPatchFactory();
147
+ * interact(selector)
148
+ * .draggable({
149
+ onstart: () => {
150
+ touchPatch.onstart();
151
+ },
152
+ onend: () => {
153
+ touchPatch.onend();
154
+ }
155
+ })
156
+ .actionChecker(touchPatch.actionChecker);
157
+ ...
158
+ function destroy() {
159
+ ` touchPatch.destroy()
160
+ interact(selector).unset();
161
+ }
162
+ * @returns {Object}
163
+ */
164
+ touchPatchFactory: function touchPatchFactory() {
165
+ const delayBefore = 300;
166
+ const distanceTolerance = 20; //while waiting for delayBefore, finger can move a little bit
167
+
168
+ interact.pointerMoveTolerance(distanceTolerance);
169
+ let isDragging = false;
170
+
171
+ // webKit requires cancelable `touchmove` events to be added as early as possible
172
+ // alternative: `touch-action: pinch-zoom` css: add it after drag start [?]; or have it always - worse ux
173
+ function touchmoveListener(e) {
174
+ if (isDragging) {
175
+ e.preventDefault();
176
+ }
177
+ }
178
+ window.addEventListener('touchmove', touchmoveListener, { passive: false });
179
+
180
+ function contextmenuListener(e) {
181
+ e.preventDefault();
182
+ }
183
+
184
+ return {
185
+ /**
186
+ * @param {PointerEvent} pointer
187
+ * @param {PointerEvent} event
188
+ * @param {Object} action
189
+ * @param {Object} interactable
190
+ * @returns {Object}
191
+ */
192
+ actionChecker: (pointer, event, action, interactable, element) => {
193
+ if (event && action && action.name === 'drag') {
194
+ const isTouch = event.pointerType === 'touch';
195
+ interactable.options[action.name].delay = isTouch ? delayBefore : 0;
196
+
197
+ if (isTouch && !element.dataset.noContextMenu) {
198
+ //prevent context menu on longpress
199
+ //this listener can stay forever until the element is destroyed
200
+ element.addEventListener('contextmenu', contextmenuListener);
201
+ element.dataset.noContextMenu = true;
202
+ }
203
+ }
204
+ return action;
205
+ },
206
+ onstart: () => {
207
+ isDragging = true;
208
+ },
209
+ onend: () => {
210
+ isDragging = false;
211
+ },
212
+ destroy: () => {
213
+ window.removeEventListener('touchmove', touchmoveListener);
214
+ }
215
+ };
216
+ },
217
+
218
+ /**
219
+ * Builds a scroll observer that will make sure the dragged element keeps an accurate positioning
220
+ * @example
221
+ * scrollObserver = interactUtils.scrollObserverFactory($container);
222
+ * dragOptions = {
223
+ autoScroll: {
224
+ container: scrollObserver.getScrollContainer().get(0)
225
+ },
226
+ onstart: function (e) {
227
+ scrollObserver.start($activeChoice);
228
+ },
229
+ onend: function (e) {
230
+ scrollObserver.stop();
231
+ }
232
+ };
233
+ * @param {jQuery} $scrollContainer
234
+ * @returns {scrollObserver}
235
+ */
236
+ scrollObserverFactory: function scrollObserverFactory($scrollContainer) {
237
+ let currentDraggable = null;
238
+ let beforeY = 0;
239
+ let beforeX = 0;
240
+ let afterY = 0;
241
+ let afterX = 0;
242
+
243
+ // reset the scroll observer context
244
+ function resetScrollObserver() {
245
+ currentDraggable = null;
246
+ beforeY = 0;
247
+ beforeX = 0;
248
+ afterY = 0;
249
+ afterX = 0;
250
+ }
251
+
252
+ // keep the position of the dragged element accurate with the scroll position
253
+ function onScrollCb() {
254
+ let x;
255
+ let y;
256
+ if (currentDraggable) {
257
+ beforeY = afterY;
258
+ beforeX = afterX;
259
+
260
+ if (afterY === 0 && beforeY === 0) beforeY = this.scrollTop;
261
+ if (afterX === 0 && beforeX === 0) beforeX = this.scrollLeft;
262
+
263
+ afterY = this.scrollTop;
264
+ afterX = this.scrollLeft;
265
+
266
+ y = (parseInt(currentDraggable.getAttribute('data-y'), 10) || 0) + (afterY - beforeY);
267
+ x = (parseInt(currentDraggable.getAttribute('data-x'), 10) || 0) + (afterX - beforeX);
268
+
269
+ // translate the element
270
+ currentDraggable.style.webkitTransform = currentDraggable.style.transform = `translate(${x}px, ${y}px)`;
271
+
272
+ // update the position attributes
273
+ currentDraggable.setAttribute('data-x', x);
274
+ currentDraggable.setAttribute('data-y', y);
275
+ }
276
+ }
277
+
278
+ // find the scroll container within the parents if any
279
+ $scrollContainer.parents().each(function findScrollContainer() {
280
+ const $el = $(this);
281
+ const ovf = $el.css('overflow');
282
+ if (ovf !== 'hidden' && ovf !== 'visible') {
283
+ $scrollContainer = $el;
284
+ return false;
285
+ }
286
+ });
287
+
288
+ // make sure the drop zones will follow the scroll
289
+ interact.dynamicDrop(true);
290
+
291
+ /**
292
+ * @typedef {Object} scrollObserver
293
+ */
294
+ return {
295
+ /**
296
+ * Gets the scroll container
297
+ * @returns {jQuery}
298
+ */
299
+ getScrollContainer: function getScrollContainer() {
300
+ return $scrollContainer;
301
+ },
302
+
303
+ /**
304
+ * Initializes the scroll observer while dragging a choice
305
+ * @param {HTMLElement|jQuery} draggedElement
306
+ */
307
+ start: function start(draggedElement) {
308
+ resetScrollObserver();
309
+ currentDraggable = draggedElement instanceof $ ? draggedElement.get(0) : draggedElement;
310
+ $scrollContainer.on('scroll.scrollObserver', _.throttle(onScrollCb, 50));
311
+ },
312
+
313
+ /**
314
+ * Tears down the the scroll observer once the dragging is done
315
+ */
316
+ stop: function stop() {
317
+ $scrollContainer.off('.scrollObserver');
318
+ resetScrollObserver();
319
+ }
320
+ };
137
321
  }
138
322
  };
139
323