qms-angular 1.0.39 → 1.0.40

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 (71) hide show
  1. package/bundles/qms-angular.umd.js +2845 -253
  2. package/bundles/qms-angular.umd.js.map +1 -1
  3. package/esm2015/lib/model/en.js +14 -1
  4. package/esm2015/lib/model/no.js +18 -5
  5. package/esm2015/lib/qms-ckeditor-components/common/constants/ckeditorEvent.constant.js +3 -1
  6. package/esm2015/lib/qms-ckeditor-components/common/constants/iconSvg.constants.js +8 -0
  7. package/esm2015/lib/qms-ckeditor-components/common/enums/image-mode.enum.js +9 -0
  8. package/esm2015/lib/qms-ckeditor-components/common/enums/protocol-type.enum.js +11 -3
  9. package/esm2015/lib/qms-ckeditor-components/common/enums/target-type.enum.js +8 -1
  10. package/esm2015/lib/qms-ckeditor-components/common/functions/common.function.js +3 -1
  11. package/esm2015/lib/qms-ckeditor-components/common/models/qms-ckeditor-data.model.js +1 -1
  12. package/esm2015/lib/qms-ckeditor-components/common/models/qms-ckeditor-input.model.js +1 -9
  13. package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-imagemap/qms-ckeditor-imagemap.component.js +524 -0
  14. package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-imagemap/qms-ckeditor-imagemap.lib.js +1948 -0
  15. package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-imagemap/qms-ckeditor-imagemap.validator.js +7 -0
  16. package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-link/qms-ckeditor-link.component.js +4 -4
  17. package/esm2015/lib/qms-ckeditor-components/models/qms-ckeditor-imagemap.model.js +22 -0
  18. package/esm2015/lib/qms-ckeditor-components/qms-ckeditor.component.js +45 -12
  19. package/esm2015/lib/qms-ckeditor-components/qms-ckeditor.module.js +11 -1
  20. package/esm2015/qms-angular.js +3 -1
  21. package/fesm2015/qms-angular.js +2822 -252
  22. package/fesm2015/qms-angular.js.map +1 -1
  23. package/lib/model/en.d.ts +13 -0
  24. package/lib/model/no.d.ts +13 -0
  25. package/lib/qms-ckeditor-components/common/constants/ckeditorEvent.constant.d.ts +2 -0
  26. package/lib/qms-ckeditor-components/common/constants/iconSvg.constants.d.ts +7 -0
  27. package/lib/qms-ckeditor-components/common/enums/image-mode.enum.d.ts +7 -0
  28. package/lib/qms-ckeditor-components/common/enums/protocol-type.enum.d.ts +9 -2
  29. package/lib/qms-ckeditor-components/common/enums/target-type.enum.d.ts +6 -0
  30. package/lib/qms-ckeditor-components/common/models/qms-ckeditor-data.model.d.ts +1 -0
  31. package/lib/qms-ckeditor-components/common/models/qms-ckeditor-input.model.d.ts +7 -7
  32. package/lib/qms-ckeditor-components/components/qms-ckeditor-imagemap/qms-ckeditor-imagemap.component.d.ts +123 -0
  33. package/lib/qms-ckeditor-components/components/qms-ckeditor-imagemap/qms-ckeditor-imagemap.lib.d.ts +542 -0
  34. package/lib/qms-ckeditor-components/components/qms-ckeditor-imagemap/qms-ckeditor-imagemap.validator.d.ts +2 -0
  35. package/lib/qms-ckeditor-components/models/qms-ckeditor-imagemap.model.d.ts +20 -0
  36. package/lib/qms-ckeditor-components/qms-ckeditor.component.d.ts +5 -4
  37. package/package.json +1 -1
  38. package/qms-angular.d.ts +2 -0
  39. package/qms-angular.metadata.json +1 -1
  40. package/src/assets/qms-ckeditor-plugin/build/ckeditor.js +2 -2
  41. package/src/assets/qms-ckeditor-plugin/build/ckeditor.js.map +1 -1
  42. package/src/assets/qms-ckeditor-plugin/package-lock.json +12177 -9
  43. package/src/assets/qms-ckeditor-plugin/src/ckeditor.js +3 -2
  44. package/src/assets/qms-ckeditor-plugin/src/plugins/common/qmsCKEditorConstant.js +4 -0
  45. package/src/assets/qms-ckeditor-plugin/src/plugins/common/qmsCKEditorService.js +10 -0
  46. package/src/assets/qms-ckeditor-plugin/src/plugins/fullscreen/dist/qmsCKEditorFullscreenPlugin.dev.js +87 -0
  47. package/src/assets/qms-ckeditor-plugin/src/plugins/imagemap/converters.js +378 -0
  48. package/src/assets/qms-ckeditor-plugin/src/plugins/imagemap/imagemap.js +14 -0
  49. package/src/assets/qms-ckeditor-plugin/src/plugins/imagemap/imagemapediting.js +183 -0
  50. package/src/assets/qms-ckeditor-plugin/src/plugins/imagemap/imagemapui.js +49 -0
  51. package/src/assets/qms-ckeditor-plugin/src/plugins/imagemap/insertimagemapcommand.js +127 -0
  52. package/src/assets/qms-ckeditor-plugin/src/plugins/imagemap/resizeimagemapcommand.js +82 -0
  53. package/src/assets/qms-ckeditor-plugin/src/plugins/imagemap/utils.js +234 -0
  54. package/src/assets/qms-ckeditor-plugin/src/plugins/link/linkediting.js +1 -1
  55. package/src/assets/qms-ckeditor-plugin/src/plugins/link/linkimage.js +1 -1
  56. package/src/assets/qms-ckeditor-plugin/src/plugins/link/ui/linkactionsview.js +1 -1
  57. package/src/assets/qms-ckeditor-plugin/src/plugins/link/ui/linkformview.js +1 -1
  58. package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/inserttooltipcommand.js +1 -1
  59. package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/tooltipediting.js +1 -1
  60. package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/ui/actionsview.js +1 -1
  61. package/src/assets/qms-ckeditor-plugin/src/themes/icons/imagemap.svg +56 -0
  62. package/src/assets/qms-ckeditor-plugin/src/themes/{tyles → styles}/anchor.css +0 -0
  63. package/src/assets/qms-ckeditor-plugin/src/themes/{tyles → styles}/link.css +0 -0
  64. package/src/assets/qms-ckeditor-plugin/src/themes/{tyles → styles}/linkactions.css +0 -0
  65. package/src/assets/qms-ckeditor-plugin/src/themes/{tyles → styles}/linkform.css +0 -0
  66. package/src/assets/qms-ckeditor-plugin/src/themes/{tyles → styles}/linkimage.css +0 -0
  67. package/src/assets/qms-ckeditor-plugin/src/themes/{tyles → styles}/tooltip.css +0 -0
  68. package/src/lib/qms-ckeditor-components/components/qms-ckeditor-imagemap/qms-ckeditor-imagemap.component.scss +27 -0
  69. package/src/themes/_color.scss +8 -0
  70. package/src/themes/core/_colors.scss +2 -0
  71. package/src/themes/core/_tab.scss +50 -49
@@ -0,0 +1,183 @@
1
+ import { Plugin } from '@ckeditor/ckeditor5-core';
2
+ import InsertImageMapCommand from './insertimagemapcommand';
3
+ import ResizeImageMapCommand from './resizeimagemapcommand';
4
+ import { ImageMapAttributes, ImageMapElements, debounced, trimStart, drawMap, ImageMapCommands, HtmlAttributes, HtmlElements, findMapNodes } from './utils';
5
+ import ImageLoadObserver from '@ckeditor/ckeditor5-image/src/image/imageloadobserver';
6
+ import { downcastImageWidthAttribute, downcastImageHeightAttribute, downcastImageSavedSrcAttribute, downcastImageMapAttribute,
7
+ upcastImageSavedSrcAttribute, upcastMapElement, dowcastMapNameAttribute, dowcastMapWidthAttribute, dowcastMapHeightAttribute,
8
+ dowcastMapAreaAttribute, upcastImageMapAttribute, upcastImageHeightAttribute, upcastImageWidthAttribute, downcastMapElement
9
+ } from './converters';
10
+ import { isWidget } from '@ckeditor/ckeditor5-widget/src/utils';
11
+
12
+ export default class ImageMapEditing extends Plugin {
13
+ static get requires() {
14
+ return ['ImageResize', 'Delete'];
15
+ }
16
+
17
+ static get pluginName() {
18
+ return 'ImageMapEditing';
19
+ }
20
+
21
+ init() {
22
+ const editor = this.editor;
23
+ const model = editor.model;
24
+ const schema = model.schema;
25
+ const conversion = editor.conversion;
26
+ const editingView = editor.editing.view;
27
+
28
+ editingView.addObserver(ImageLoadObserver);
29
+
30
+ schema.extend(ImageMapElements.IMAGE, {
31
+ allowAttributes: [
32
+ ImageMapAttributes.IMAGE_USE_MAP,
33
+ ImageMapAttributes.IMAGE_WIDTH,
34
+ ImageMapAttributes.IMAGE_HEIGHT,
35
+ ImageMapAttributes.IMAGE_SAVED_SRC
36
+ ]
37
+ });
38
+
39
+ schema.register(ImageMapElements.MAP, {
40
+ isObject: true,
41
+ allowWhere: '$block',
42
+ allowAttributes: [
43
+ ImageMapAttributes.MAP_NAME,
44
+ ImageMapAttributes.MAP_AREAS,
45
+ ImageMapAttributes.MAP_WIDTH,
46
+ ImageMapAttributes.MAP_HEIGHT
47
+ ]
48
+ });
49
+
50
+ conversion.for('dataDowncast').add(downcastImageWidthAttribute());
51
+ conversion.for('dataDowncast').add(downcastImageHeightAttribute());
52
+ conversion.for('dataDowncast').add(downcastImageSavedSrcAttribute(true));
53
+ conversion.for('editingDowncast').add(downcastImageSavedSrcAttribute(false));
54
+
55
+ conversion.for('downcast').add(downcastImageMapAttribute());
56
+ conversion.for('downcast').add(downcastMapElement());
57
+
58
+ conversion.for('downcast')
59
+ .add(dowcastMapNameAttribute())
60
+ .add(dowcastMapWidthAttribute())
61
+ .add(dowcastMapHeightAttribute())
62
+ .add(dowcastMapAreaAttribute());
63
+
64
+ conversion.for('upcast').add(upcastImageMapAttribute());
65
+ conversion.for('upcast').add(upcastImageHeightAttribute());
66
+ conversion.for('upcast').add(upcastImageWidthAttribute());
67
+ conversion.for('upcast').add(upcastImageSavedSrcAttribute());
68
+ conversion.for('upcast').add(upcastMapElement());
69
+
70
+ editor.commands.get('resizeImage').on('execute', debounced(() => {
71
+ editor.execute(ImageMapCommands.RESIZE);
72
+ }, 100));
73
+
74
+ // this.listenTo(editingView.document, 'delete', ( evt, data ) => {
75
+ // this.allowDeleteMap = true;
76
+ // }, { context: [isWidget] });
77
+
78
+ // this.listenTo(model.document, 'change:data', (event) => {
79
+ // if(this.allowDeleteMap == true){
80
+ // this.allowDeleteMap == false;
81
+ // OnImageDeleted(model, event);
82
+ // }
83
+ // });
84
+
85
+ this.listenTo(editingView.document, 'imageLoaded', (evt, domEvent) => {
86
+ onImageLoaded(domEvent);
87
+ });
88
+
89
+ editor.commands.add(ImageMapCommands.INSERT, new InsertImageMapCommand(editor));
90
+ editor.commands.add(ImageMapCommands.RESIZE, new ResizeImageMapCommand(editor));
91
+ }
92
+ }
93
+
94
+ function OnImageDeleted(model, event){
95
+ const differ = event.source.differ;
96
+ // if no difference
97
+ if (differ.isEmpty) { return; }
98
+ const changes = differ.getChanges({ includeChangesInGraveyard: true });
99
+ if (changes.length === 0) { return; }
100
+
101
+ let hasNoImageRemoved = true;
102
+ // check any image remove or not
103
+ for (let i = 0; i < changes.length; i++){
104
+ const change = changes[i]
105
+ // if image remove exists
106
+ if (change && change.type === 'remove' && change.name === 'image') {
107
+ hasNoImageRemoved = false
108
+ break
109
+ }
110
+ }
111
+
112
+ // if not image remove stop execution
113
+ if (hasNoImageRemoved) { return; }
114
+ // get removed nodes
115
+ const removedNodes = changes.filter(change => (change.type === 'insert' && change.name === 'image'))
116
+
117
+ // removed image nodes
118
+ const removedMapNames = []
119
+ removedNodes.forEach(node => {
120
+ let nodeAfter = node.position.nodeAfter;
121
+ if(nodeAfter && nodeAfter.hasAttribute(ImageMapAttributes.IMAGE_USE_MAP)){
122
+ let mapname = nodeAfter.getAttribute(ImageMapAttributes.IMAGE_USE_MAP) || '';
123
+ removedMapNames.push(trimStart(mapname, '#'));
124
+ }
125
+ });
126
+
127
+ if(removedMapNames && removedMapNames.length > 0){
128
+ const range = model.createRangeIn(model.document.getRoot());
129
+ const existingMapElements = findMapNodes(removedMapNames, range);
130
+
131
+ if(existingMapElements && existingMapElements.length > 0){
132
+ const redoingBatch = model.createBatch( 'transparent' );
133
+ model.enqueueChange(redoingBatch, writer => {
134
+ existingMapElements.forEach(element => {
135
+ writer.remove(element);
136
+ });
137
+ } );
138
+ }
139
+ }
140
+ }
141
+
142
+ function onImageLoaded(domEvent){
143
+ //Must be attached only to images loaded by the `ImageInsert`, `ImageUpload` or `LinkImage` plugins.
144
+ if (!domEvent.target.matches('figure.image.ck-widget > img, figure.image.ck-widget > a > img')) {
145
+ return;
146
+ }
147
+ if(domEvent.target.hasAttribute(HtmlAttributes.USE_MAP)
148
+ && domEvent.target.getAttribute(HtmlAttributes.USE_MAP)
149
+ && !domEvent.target.hasAttribute(HtmlAttributes.SAVED_SRC)){
150
+
151
+ const originalSrc = domEvent.target.getAttribute(HtmlAttributes.SRC);
152
+ const mapName = trimStart(domEvent.target.getAttribute(HtmlAttributes.USE_MAP), '#');
153
+ const selector = `${HtmlElements.MAP}[${HtmlAttributes.NAME}='${mapName}']`;
154
+ const map = document.querySelector(selector);
155
+ if(map && map.childNodes){
156
+ const areas = [];
157
+ map.childNodes.forEach((child) =>{
158
+ if(child.nodeName && child.nodeName.toLowerCase() === HtmlElements.AREA){
159
+ let area = {};
160
+ area[HtmlAttributes.COORDS] = child.getAttribute(HtmlAttributes.COORDS);
161
+ area[HtmlAttributes.SHAPE] = child.getAttribute(HtmlAttributes.SHAPE) || '';
162
+ areas.push(area);
163
+ }
164
+ });
165
+ if(areas.length > 0){
166
+ const width = map.getAttribute(HtmlAttributes.WIDTH) || domEvent.target.width;
167
+ const height = map.getAttribute(HtmlAttributes.HEIGHT) || domEvent.target.height;
168
+ const target = domEvent.target;
169
+ drawMap(originalSrc, width, height, areas, (oldsrc, newsrc) => {
170
+ if(target){
171
+ target.setAttribute(HtmlAttributes.SRC, newsrc);
172
+ target.setAttribute(HtmlAttributes.SAVED_SRC, oldsrc);
173
+ }
174
+
175
+ if(map){
176
+ map.setAttribute(HtmlAttributes.WIDTH, width);
177
+ map.setAttribute(HtmlAttributes.HEIGHT, height);
178
+ }
179
+ })
180
+ }
181
+ }
182
+ }
183
+ }
@@ -0,0 +1,49 @@
1
+ import { Plugin } from '@ckeditor/ckeditor5-core';
2
+ import { ButtonView, ContextualBalloon } from '@ckeditor/ckeditor5-ui';
3
+ import imageMapIcon from '../../themes/icons/imagemap.svg';
4
+ import { ImageMapCommands } from './utils';
5
+
6
+ export default class ImageMapUI extends Plugin {
7
+
8
+ static get requires() {
9
+ return [ ContextualBalloon];
10
+ }
11
+
12
+ static get pluginName() {
13
+ return 'ImageMapUI';
14
+ }
15
+
16
+ init() {
17
+ this._createButton();
18
+
19
+ }
20
+
21
+ destroy() {
22
+ super.destroy();
23
+ }
24
+
25
+ _createButton() {
26
+ const editor = this.editor;
27
+ const t = editor.t;
28
+
29
+ editor.ui.componentFactory.add('imageMap', locale => {
30
+ const command = editor.commands.get(ImageMapCommands.INSERT);
31
+ const view = new ButtonView(locale);
32
+
33
+ view.set({
34
+ label: t('Image Map'),
35
+ icon: imageMapIcon,
36
+ tooltip: true
37
+ });
38
+
39
+ view.bind('isEnabled').to(command, 'isEnabled');
40
+
41
+ this.listenTo(view, 'execute', () => {
42
+ editor.execute(ImageMapCommands.INSERT, {});
43
+ });
44
+
45
+ return view;
46
+ });
47
+ }
48
+ }
49
+
@@ -0,0 +1,127 @@
1
+
2
+ import { Command } from '@ckeditor/ckeditor5-core';
3
+ import { isImage } from '@ckeditor/ckeditor5-image/src/image/utils';
4
+ import * as QMSCKEditorConstant from '../common/qmsCKEditorConstant';
5
+ import * as QMSCKEditorService from '../common/qmsCKEditorService';
6
+ import { ImageMapAttributes, ImageMapElements, trimStart, parsePixelToFloat, findFirstMapNode, findMapNodes, drawMap } from './utils';
7
+ import { getSelectedImageWidget } from '@ckeditor/ckeditor5-image/src/image/utils';
8
+
9
+ export default class InsertImageMapCommand extends Command {
10
+
11
+ refresh() {
12
+ const element = this.editor.model.document.selection.getSelectedElement();
13
+ this.isEnabled = isImage(element);
14
+ }
15
+
16
+ execute() {
17
+ const editor = this.editor;
18
+ const model = editor.model;
19
+ const view = editor.editing.view;
20
+ const selectedElement = model.document.selection.getSelectedElement();
21
+
22
+ const mapName = selectedElement.getAttribute(ImageMapAttributes.IMAGE_USE_MAP);
23
+ let originalImageSrc = selectedElement.getAttribute(ImageMapAttributes.IMAGE_SRC);
24
+ if(selectedElement.hasAttribute(ImageMapAttributes.IMAGE_SAVED_SRC) && selectedElement.getAttribute(ImageMapAttributes.IMAGE_SAVED_SRC)){
25
+ originalImageSrc = selectedElement.getAttribute(ImageMapAttributes.IMAGE_SAVED_SRC);
26
+ }
27
+
28
+ const data = {'imageUrl': originalImageSrc, 'areas': [], imageWidth: null, imageHeight: null};
29
+ const imageWidget = getSelectedImageWidget( view.document.selection);
30
+ const widgetResizePlugin = editor.plugins.get('WidgetResize');
31
+ const resizer = widgetResizePlugin.getResizerByViewElement( imageWidget );
32
+
33
+ if(resizer){
34
+ const resizerWrapper = resizer._viewResizerWrapper;
35
+ data.imageWidth = parsePixelToFloat(resizerWrapper.getStyle('width', 0));
36
+ data.imageHeight = parsePixelToFloat(resizerWrapper.getStyle('height', 0));
37
+ }
38
+
39
+ if(!!mapName){
40
+ const range = model.createRangeIn(model.document.getRoot());
41
+ const existingMapElement = findFirstMapNode(trimStart(mapName, '#'), range);
42
+ if(existingMapElement){
43
+ data.areas = JSON.parse(existingMapElement.getAttribute(ImageMapAttributes.MAP_AREAS) || []);
44
+ }
45
+ }
46
+
47
+ QMSCKEditorService.imageMapNotify(data);
48
+ window[QMSCKEditorConstant.QMSCK_IMAGEMAP_IS_PROCESSING] = false;
49
+ window.addEventListener(QMSCKEditorConstant.QMSCK_IMAGEMAP_PLUGIN_RESP, (evt) => {
50
+ if (window[QMSCKEditorConstant.QMSCK_IMAGEMAP_IS_PROCESSING]) {
51
+ return;
52
+ }
53
+ window[QMSCKEditorConstant.QMSCK_IMAGEMAP_IS_PROCESSING] = true;
54
+ model.change(writer => {
55
+ var newMapName = trimStart(evt.detail.name, '#');
56
+ const areas = evt.detail.areas;
57
+ const width = evt.detail.imageWidth;
58
+ const height = evt.detail.imageHeight;
59
+ const imageElement = model.document.selection.getSelectedElement();
60
+ const oldMapName = imageElement.getAttribute(ImageMapAttributes.IMAGE_USE_MAP);
61
+
62
+ if(!!oldMapName){
63
+ const range = model.createRangeIn(model.document.getRoot());
64
+ const existingMapElements = findMapNodes([trimStart(oldMapName, '#')], range);
65
+ if(existingMapElements && existingMapElements.length > 0){
66
+ existingMapElements.forEach(element => {
67
+ writer.remove(element);
68
+ });
69
+ }
70
+ }
71
+
72
+ if(!!areas && areas.length > 0)
73
+ {
74
+ writer.setAttribute(ImageMapAttributes.IMAGE_USE_MAP, '#' + newMapName, imageElement);
75
+ writer.setAttribute(ImageMapAttributes.IMAGE_WIDTH, width, imageElement);
76
+ writer.setAttribute(ImageMapAttributes.IMAGE_HEIGHT, height, imageElement);
77
+
78
+ let originalImageSrc = imageElement.getAttribute(ImageMapAttributes.IMAGE_SRC);
79
+ if(!imageElement.hasAttribute(ImageMapAttributes.IMAGE_SAVED_SRC) || !imageElement.getAttribute(ImageMapAttributes.IMAGE_SAVED_SRC)){
80
+ writer.setAttribute(ImageMapAttributes.IMAGE_SAVED_SRC, originalImageSrc, imageElement);
81
+ }
82
+ else{
83
+ originalImageSrc = imageElement.getAttribute(ImageMapAttributes.IMAGE_SAVED_SRC);
84
+ }
85
+
86
+ drawMap(originalImageSrc, width, height, areas, (oldsrc, newsrc) =>{
87
+ model.enqueueChange(writer => {
88
+ writer.setAttribute(ImageMapAttributes.IMAGE_SRC, newsrc, imageElement);
89
+ } );
90
+ });
91
+
92
+ let attrs = {};
93
+ attrs[ImageMapAttributes.MAP_NAME] = newMapName;
94
+ attrs[ImageMapAttributes.MAP_AREAS] = JSON.stringify(areas);
95
+ attrs[ImageMapAttributes.MAP_WIDTH] = width;
96
+ attrs[ImageMapAttributes.MAP_HEIGHT] = height;
97
+ const mapElement = writer.createElement(ImageMapElements.MAP, attrs);
98
+
99
+ writer.insert(mapElement, writer.createPositionAt(imageElement, "after"));
100
+ }
101
+ else {
102
+ if(imageElement.hasAttribute(ImageMapAttributes.IMAGE_USE_MAP)){
103
+ writer.removeAttribute(ImageMapAttributes.IMAGE_USE_MAP, imageElement);
104
+ }
105
+
106
+ if(imageElement.hasAttribute(ImageMapAttributes.IMAGE_SAVED_SRC)){
107
+
108
+ let src = imageElement.getAttribute(ImageMapAttributes.IMAGE_SAVED_SRC);
109
+ if(!!src){
110
+ writer.setAttribute(ImageMapAttributes.IMAGE_SRC, src, imageElement);
111
+ }
112
+ writer.removeAttribute(ImageMapAttributes.IMAGE_SAVED_SRC, imageElement);
113
+ }
114
+
115
+ if(imageElement.hasAttribute(ImageMapAttributes.IMAGE_HEIGHT)){
116
+ writer.removeAttribute(ImageMapAttributes.IMAGE_HEIGHT, imageElement);
117
+ }
118
+
119
+ if(imageElement.hasAttribute(ImageMapAttributes.IMAGE_WIDTH)){
120
+ writer.removeAttribute(ImageMapAttributes.IMAGE_WIDTH, imageElement);
121
+ }
122
+ }
123
+ });
124
+ });
125
+ }
126
+ }
127
+
@@ -0,0 +1,82 @@
1
+
2
+ import { Command } from '@ckeditor/ckeditor5-core';
3
+ import { isImage } from '@ckeditor/ckeditor5-image/src/image/utils';
4
+ import { ImageMapAttributes, trimStart, parsePixelToFloat, findFirstMapNode, drawMap, resizeAreaWidth, resizeAreaHeight } from './utils';
5
+ import { getSelectedImageWidget} from '@ckeditor/ckeditor5-image/src/image/utils';
6
+
7
+ export default class ResizeImageMapCommand extends Command {
8
+
9
+ refresh() {
10
+ const element = this.editor.model.document.selection.getSelectedElement();
11
+ this.isEnabled = isImage(element) && element.hasAttribute(ImageMapAttributes.IMAGE_USE_MAP);
12
+ }
13
+
14
+ execute() {
15
+ const editor = this.editor;
16
+ const model = editor.model;
17
+ const view = this.editor.editing.view;
18
+ const imageElement = model.document.selection.getSelectedElement();
19
+ const mapName = imageElement.getAttribute(ImageMapAttributes.IMAGE_USE_MAP);
20
+ if(mapName){
21
+ const imageWidget = getSelectedImageWidget( view.document.selection);
22
+ const widgetResizePlugin = editor.plugins.get('WidgetResize');
23
+ const resizer = widgetResizePlugin.getResizerByViewElement( imageWidget );
24
+ if(resizer){
25
+ const resizerWrapper = resizer._viewResizerWrapper;
26
+ const newWidth = parsePixelToFloat(resizerWrapper.getStyle('width', 0));
27
+ const newHeight = parsePixelToFloat(resizerWrapper.getStyle('height', 0));
28
+
29
+ const range = model.createRangeIn(model.document.getRoot());
30
+ const existingMapElement = findFirstMapNode(trimStart(mapName, '#'), range);
31
+ if(existingMapElement){
32
+ const areas = JSON.parse(existingMapElement.getAttribute(ImageMapAttributes.MAP_AREAS) || []);
33
+ const width = parsePixelToFloat(existingMapElement.getAttribute(ImageMapAttributes.MAP_WIDTH, 0));
34
+ const height = parsePixelToFloat(existingMapElement.getAttribute(ImageMapAttributes.MAP_HEIGHT, 0));
35
+
36
+ const widthChanged = newWidth != width && width != 0 ;
37
+ const heightChanged = newHeight != height && height != 0 ;
38
+
39
+ if(widthChanged || heightChanged){
40
+ if(widthChanged){
41
+ const widthRatio = (newWidth * 1.0) / width;
42
+ for (var i = 0; i < areas.length; ++i) {
43
+ areas[i] = resizeAreaWidth(areas[i], widthRatio);
44
+ }
45
+ }
46
+
47
+ if(heightChanged){
48
+ const heightRatio = (newHeight * 1.0) / height;
49
+ for (var i = 0; i < areas.length; ++i) {
50
+ areas[i] = resizeAreaHeight(areas[i], heightRatio, widthChanged);
51
+ }
52
+ }
53
+
54
+ const areasAsString = JSON.stringify(areas);
55
+ model.change(writer => {
56
+ let originalImageSrc = imageElement.getAttribute(ImageMapAttributes.IMAGE_SRC);
57
+ if(!imageElement.hasAttribute(ImageMapAttributes.IMAGE_SAVED_SRC) || !imageElement.getAttribute(ImageMapAttributes.IMAGE_SAVED_SRC)){
58
+ writer.setAttribute(ImageMapAttributes.IMAGE_SAVED_SRC, originalImageSrc, imageElement);
59
+ }
60
+ else{
61
+ originalImageSrc = imageElement.getAttribute(ImageMapAttributes.IMAGE_SAVED_SRC);
62
+ }
63
+
64
+ writer.setAttribute(ImageMapAttributes.MAP_AREAS, areasAsString, existingMapElement);
65
+ writer.setAttribute(ImageMapAttributes.MAP_WIDTH, newWidth, existingMapElement);
66
+ writer.setAttribute(ImageMapAttributes.MAP_HEIGHT, newHeight, existingMapElement);
67
+ writer.setAttribute(ImageMapAttributes.IMAGE_WIDTH, newWidth, imageElement);
68
+ writer.setAttribute(ImageMapAttributes.IMAGE_HEIGHT, newHeight, imageElement);
69
+
70
+ drawMap(originalImageSrc, newWidth, newHeight, areas, (oldsrc, newsrc) =>{
71
+ model.enqueueChange(writer => {
72
+ writer.setAttribute(ImageMapAttributes.IMAGE_SRC, newsrc, imageElement);
73
+ });
74
+ });
75
+ });
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+ }
82
+
@@ -0,0 +1,234 @@
1
+ export const HtmlAttributes = {
2
+ COORDS: 'coords',
3
+ HREF: 'href',
4
+ SHAPE: 'shape',
5
+ NAME: 'name',
6
+ TARGET: 'target',
7
+ USE_MAP: 'usemap',
8
+ ALT: 'alt',
9
+ WIDTH: 'width',
10
+ HEIGHT: 'height',
11
+ SRC: 'src',
12
+ ID: 'id',
13
+ SAVED_SRC: 'savedsrc'
14
+ }
15
+
16
+
17
+ export const HtmlElements = {
18
+ MAP: 'map',
19
+ IMAGE: 'img',
20
+ AREA: 'area'
21
+ }
22
+
23
+
24
+ export const ImageMapAttributes = {
25
+ MAP_AREAS: 'mapareas',
26
+ MAP_NAME: 'mapname' ,
27
+ MAP_WIDTH: 'mapwidth',
28
+ MAP_HEIGHT: 'mapheight',
29
+ IMAGE_USE_MAP: 'imageusemap',
30
+ IMAGE_SAVED_SRC: 'imagesavedsrc',
31
+ IMAGE_SRC: 'src',//It is already defined by the image plugin
32
+ IMAGE_WIDTH: 'imagewidth',
33
+ IMAGE_HEIGHT: 'imageheight',
34
+ }
35
+
36
+ export const ImageMapCommands = {
37
+ INSERT: 'insertImageMap',
38
+ RESIZE: 'resizeImageMap'
39
+ }
40
+
41
+ export const ImageMapElements = {
42
+ MAP: 'npmap',
43
+ IMAGE: 'image'//It is already defined by the image plugin
44
+ }
45
+
46
+ export function trimStart(text, charToRemove){
47
+ if(text && text.length > 0){
48
+ if(text.charAt(0) == charToRemove){
49
+ return text.substring(1);
50
+ }
51
+ }
52
+ return text;
53
+ }
54
+
55
+ export function parsePixelToFloat(pixel, fractionDigits){
56
+ if(pixel){
57
+ pixel = pixel.toString().replaceAll('px', '');
58
+ try
59
+ {
60
+ return Number.parseFloat(pixel).toFixed(fractionDigits);
61
+ }
62
+ catch{
63
+
64
+ }
65
+ }
66
+ return 0;
67
+ }
68
+
69
+ function isMapNode(lowerCaseNameObject, node){
70
+ return node.is('element', ImageMapElements.MAP)
71
+ && node.hasAttribute(ImageMapAttributes.MAP_NAME)
72
+ && lowerCaseNameObject[getLowerCaseMapName(node)];
73
+ }
74
+
75
+ function getLowerCaseMapName(node){
76
+ return node.getAttribute(ImageMapAttributes.MAP_NAME).toLowerCase();
77
+ }
78
+
79
+ export function findMapNodes(names, range) {
80
+ if(!names) { return []; }
81
+
82
+ const lowerCaseNameObject = {};
83
+ names.forEach(name => {
84
+ let lowerCase = name.toLowerCase();
85
+ lowerCaseNameObject[lowerCase] = lowerCase;
86
+ });
87
+
88
+ const nodes = {};
89
+ for ( const value of range.getWalker() ) {
90
+ const node = value.item;
91
+ if (isMapNode(lowerCaseNameObject, node)) {
92
+ let mapname = getLowerCaseMapName(node);
93
+ nodes[mapname] = node;
94
+ }
95
+ }
96
+ return Object.keys(nodes).map(key => nodes[key]);
97
+ };
98
+
99
+
100
+ export function findFirstMapNode(name, range) {
101
+ if(!name) { return null; }
102
+
103
+ const lowerCaseNameObject = {};
104
+ let lowerCase = name.toLowerCase();
105
+ lowerCaseNameObject[lowerCase] = lowerCase;
106
+
107
+ for ( const value of range.getWalker() ) {
108
+ const node = value.item;
109
+ if (isMapNode(lowerCaseNameObject, node)) {
110
+ return node;
111
+ }
112
+ }
113
+ return null;
114
+ };
115
+
116
+
117
+
118
+ export function resizeAreaWidth(area, ratio) {
119
+ var coords = area.coords.split(',');
120
+ switch (area.shape) {
121
+ case 'circle':
122
+ coords[0] = Math.round(coords[0] * ratio); // Moves center point's left coordinate
123
+ coords[2] = Math.round(coords[2] * ratio); // Ajust radius
124
+ area.coords = coords.join(',');
125
+ return area;
126
+ case 'rect':
127
+ case 'poly':
128
+ // Moves each point's left coordinate
129
+ for (var i = 0; i < coords.length; i += 2) {
130
+ if (i >= coords.length) { break; }
131
+ coords[i] = Math.round(coords[i] * ratio);
132
+ }
133
+ area.coords = coords.join(',');
134
+ return area;
135
+ }
136
+ };
137
+
138
+ export function resizeAreaHeight(area, ratio, widthChanged) {
139
+ var coords = area.coords.split(',');
140
+ switch (area.shape) {
141
+ case 'circle':
142
+ coords[1] = Math.round(coords[1] * ratio); // Moves center point's top coordinate
143
+ if (!widthChanged) {
144
+ coords[2] = Math.round(coords[2] * ratio); // Ajust radius
145
+ }
146
+ area.coords = coords.join(',');
147
+ return area;
148
+ case 'rect':
149
+ case 'poly':
150
+ // Moves each point's top coordinate
151
+ for (var i = 1; i < coords.length; i += 2) {
152
+ if (i >= coords.length) { break; }
153
+ coords[i] = Math.round(coords[i] * ratio);
154
+ }
155
+ area.coords = coords.join(',');
156
+ return area;
157
+ }
158
+ };
159
+
160
+ export function debounced(fn, delay) {
161
+ let timerId;
162
+ return function (...args) {
163
+ if (timerId) {
164
+ clearTimeout(timerId);
165
+ }
166
+ timerId = setTimeout(() => {
167
+ fn(...args);
168
+ timerId = null;
169
+ }, delay);
170
+ }
171
+ }
172
+
173
+ export function drawMap(imageSrc, imageWidth, imageHeight, areas, callback){
174
+ if(areas && areas.length > 0){
175
+ try
176
+ {
177
+ var tempImage = new Image(imageWidth, imageHeight);
178
+ tempImage.src = imageSrc;
179
+ tempImage.addEventListener("load", () =>{
180
+ var canvas = document.createElement('canvas');
181
+ var context = canvas.getContext('2d');
182
+
183
+ canvas.width = imageWidth;
184
+ canvas.height = imageHeight;
185
+ context.drawImage(tempImage, 0, 0, imageWidth, imageHeight);
186
+ context.strokeStyle = "#FF0000";
187
+ context.lineWidth = 1;
188
+
189
+ for (var i = 0; i < areas.length; i++) {
190
+ const area = areas[i];
191
+ const coords = area.coords.split(',');
192
+ switch (area.shape) {
193
+ case 'circle':
194
+ context.beginPath();
195
+ context.arc(coords[0], coords[1], coords[2], 0, Math.PI * 2, true);
196
+ context.closePath();
197
+ context.stroke();
198
+ break;
199
+
200
+ case 'poly':
201
+ context.beginPath();
202
+ context.moveTo(coords[0], coords[1]);
203
+ for (var j = 2; j < coords.length; j += 2) {
204
+ context.lineTo(coords[j], coords[j + 1]);
205
+ }
206
+ context.closePath();
207
+ context.stroke();
208
+ break;
209
+
210
+ default:
211
+ context.strokeRect(coords[0], coords[1], coords[2] - coords[0], coords[3] - coords[1]);
212
+ break;
213
+ }
214
+ }
215
+ let newSrc = imageSrc;
216
+ let oldSrc = imageSrc;
217
+ try
218
+ {
219
+ newSrc = canvas.toDataURL();
220
+ }
221
+ catch(err){
222
+
223
+ }
224
+ if(callback){
225
+ callback(oldSrc, newSrc);
226
+ }
227
+
228
+ }, false);
229
+ }
230
+ catch(err){
231
+
232
+ }
233
+ }
234
+ }
@@ -18,7 +18,7 @@ import UnlinkCommand from './unlinkcommand';
18
18
  import ManualDecorator from './utils/manualdecorator';
19
19
  import { createLinkElement, ensureSafeUrl, getLocalizedDecorators, normalizeDecorators } from './utils';
20
20
  import * as QMSCKEditorConstant from '../common/qmsCKEditorConstant';
21
- import '../../themes/tyles/link.css';
21
+ import '../../themes/styles/link.css';
22
22
  import { isLinkElement } from './utils';
23
23
 
24
24
  const HIGHLIGHT_CLASS = 'ck-link_selected';
@@ -11,7 +11,7 @@ import { Plugin } from '@ckeditor/ckeditor5-core';
11
11
  import LinkImageEditing from './linkimageediting';
12
12
  import LinkImageUI from './linkimageui';
13
13
 
14
- import '../../themes/tyles/linkimage.css';
14
+ import '../../themes/styles/linkimage.css';
15
15
 
16
16
  /**
17
17
  * The `LinkImage` plugin.