Rift.IO OSM R1 Initial Submission
[osm/UI.git] / skyquake / plugins / composer / src / src / libraries / DeletionManager.js
1
2 /*
3 *
4 * Copyright 2016 RIFT.IO Inc
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19 /**
20 * Created by onvelocity on 10/2/15.
21 */
22
23 import _ from 'lodash'
24 import d3 from 'd3'
25 import UID from './UniqueId'
26 import SelectionManager from './SelectionManager'
27 import CatalogItemsActions from '../actions/CatalogItemsActions'
28 import DescriptorModelFactory from './model/DescriptorModelFactory'
29
30 import '../styles/Animations.scss'
31
32 const DELETE = 26;
33 const BACKSPACE = 8;
34
35 function onlyUnique(value, index, self) {
36 return self.indexOf(value) === index;
37 }
38
39 function createDeleteEvent(e, uid, eventName = 'cut') {
40 const data = {
41 bubbles: true,
42 cancelable: true,
43 detail: {
44 uid: uid,
45 originalEvent: e
46 }
47 };
48 if (window.CustomEvent.prototype.initCustomEvent) {
49 // support IE
50 var evt = document.createEvent('CustomEvent');
51 evt.initCustomEvent(eventName, data.bubbles, data.cancelable, data.detail);
52 return evt;
53 }
54 return new CustomEvent(eventName, data);
55 }
56
57 export default class DeletionManager {
58
59 static onDeleteKey(event) {
60 const target = event.target;
61 if (event.defaultPrevented) {
62 return
63 }
64 if ((event.which === DELETE || event.which === BACKSPACE) && /^BODY|SVG|DIV$/i.test(target.tagName)) {
65 event.preventDefault();
66 DeletionManager.deleteSelected(event);
67 return false;
68 }
69 }
70
71 static deleteSelected(event) {
72
73 // TODO refactor this to be a flux action e.g. move this code into ComposerAppActions.deleteSelected()
74
75 const selected = SelectionManager.getSelections();
76
77 const canvasPanelDiv = document.getElementById('canvasPanelDiv');
78
79 if (!canvasPanelDiv) {
80 return
81 }
82
83 // get a valid list of items to potentially remove via the cut event handler
84 const removeElementList = selected.filter(d => d).filter(onlyUnique).reduce((r, uid) => {
85 const elements = Array.from(canvasPanelDiv.querySelectorAll('[data-uid="' + uid + '"]'));
86 return r.concat(elements);
87 }, []).filter(d => d);
88
89 if (removeElementList.length === 0 && selected.length > 0) {
90 // something was selected but we did not find any dom elements with data-uid!
91 console.error(`No valid DescriptorModel instance found on element. Did you forget to put data-uid={m.uid}`,
92 selected.map(uid => Array.from(canvasPanelDiv.querySelectorAll(`[data-uid="${uid}"]`))));
93 }
94
95 SelectionManager.removeOutline();
96
97 // now actually update the model
98 const invokedEventAlreadyMap = {};
99 const failedToRemoveList = removeElementList.map(element => {
100
101 const uid = UID.from(element);
102
103 if (invokedEventAlreadyMap[uid]) {
104 return
105 }
106
107 try {
108 // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent
109 // false means event.preventDefault() was called by one of the handlers
110 const deleteEvent = createDeleteEvent(event, uid);
111 const preventDefault = (false === element.dispatchEvent(deleteEvent));
112 if (preventDefault) {
113 console.log('cut event was cancelled', element);
114 //d3.select(element).classed('-with-animations deleteItemAnimation', false).style({opacity: null});
115 return element;
116 }
117
118 } catch (error) {
119 console.warn(`Exception caught dispatching 'cut' event: ${error}`,
120 selected.map(uid => Array.from(canvasPanelDiv.querySelectorAll(`[data-uid="${uid}"]`)))
121 );
122 return element;
123 } finally {
124 invokedEventAlreadyMap[uid] = true;
125 }
126
127 }).filter(d => d).filter(onlyUnique);
128
129 SelectionManager.clearSelectionAndRemoveOutline();
130 failedToRemoveList.forEach(d => SelectionManager.addSelection(d));
131 SelectionManager.refreshOutline();
132
133 }
134
135 static addEventListeners() {
136 DeletionManager.removeEventListeners();
137 document.body.addEventListener('keydown', DeletionManager.onDeleteKey);
138 }
139
140 static removeEventListeners() {
141 document.body.removeEventListener('keydown', DeletionManager.onDeleteKey);
142 }
143
144 }