Files
openmct/platform/representation/src/gestures/DropGesture.js

189 lines
8.2 KiB
JavaScript

/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining DropGesture. Created by vwoeltje on 11/17/14.
*/
define(
['./GestureConstants',
'../../../commonUI/edit/src/objects/EditableDomainObject',
'uuid'],
function (GestureConstants, EditableDomainObject, uuid) {
"use strict";
/**
* A DropGesture adds and maintains event handlers upon an element
* such that it may act as a drop target for drag-drop composition.
*
* @memberof platform/representation
* @constructor
* @param $q Angular's $q, for promise handling
* @param element the jqLite-wrapped representation element
* @param {DomainObject} domainObject the domain object whose
* composition should be modified as a result of the drop.
*/
function DropGesture(dndService, $q, navigationService, objectService, instantiate, typeService, element, domainObject) {
var actionCapability = domainObject.getCapability('action'),
editableDomainObject,
action; // Action for the drop, when it occurs
function broadcastDrop(id, event) {
// Find the relevant scope...
var scope = element && element.scope && element.scope(),
rect;
if (scope && scope.$broadcast) {
// Get the representation's bounds, to convert
// drop position
rect = element[0].getBoundingClientRect();
// ...and broadcast the event. This allows specific
// views to have post-drop behavior which depends on
// drop position.
scope.$broadcast(
GestureConstants.MCT_DROP_EVENT,
id,
{
x: event.pageX - rect.left,
y: event.pageY - rect.top
}
);
}
}
function shouldCreateVirtualPanel(domainObject){
return domainObject.useCapability('view').filter(function (view){
return view.key==='plot' && domainObject.getModel().type!== 'telemetry.panel'
}).length > 0;
}
function dragOver(e) {
//Refresh domain object on each dragOver to catch external
// updates to the model
//Don't use EditableDomainObject for folders, allow immediate persistence
editableDomainObject = domainObject.hasCapability('editor') || domainObject.getModel().type==='folder' ? domainObject : new EditableDomainObject(domainObject, $q);
actionCapability = editableDomainObject.getCapability('action');
var event = (e || {}).originalEvent || e,
selectedObject = dndService.getData(
GestureConstants.MCT_EXTENDED_DRAG_TYPE
);
if (selectedObject) {
// TODO: Vary this based on modifier keys
action = actionCapability.getActions({
key: 'compose',
selectedObject: selectedObject
})[0];
//TODO: Fix this. Define an action for creating new
// virtual panel
if (action || shouldCreateVirtualPanel(domainObject)) {
event.dataTransfer.dropEffect = 'move';
// Indicate that we will accept the drag
event.preventDefault(); // Required in Chrome?
return false;
}
}
}
function createVirtualPanel(base, overlayId){
var typeKey = 'telemetry.panel',
type = typeService.getType(typeKey),
model = type.getInitialModel(),
id = uuid(),
newPanel = undefined;
model.type = typeKey;
newPanel = new EditableDomainObject(instantiate(model, id), $q);
[base.getId(), overlayId].forEach(function(id){
newPanel.getCapability('composition').add(id)
});
newPanel.getCapability('location').setPrimaryLocation(base.getCapability('location').getContextualLocation());
//var virtualPanel = new EditableDomainObject(newPanel, $q);
//virtualPanel.setOriginalObject(base);
newPanel.setOriginalObject(base);
//return virtualPanel;
return newPanel;
}
function drop(e) {
var event = (e || {}).originalEvent || e,
id = event.dataTransfer.getData(GestureConstants.MCT_DRAG_TYPE),
domainObjectType = editableDomainObject.getModel().type,
virtualObj;
// If currently in edit mode allow drag and drop gestures to the
// domain object. An exception to this is folders which have drop
// gestures in browse mode.
//if (domainObjectType === 'folder' || domainObject.hasCapability('editor')) {
// Handle the drop; add the dropped identifier to the
// destination domain object's composition, and persist
// the change.
if (id) {
if (shouldCreateVirtualPanel(domainObject)){
navigationService.setNavigation(createVirtualPanel(domainObject, id));
broadcastDrop(id, event);
} else {
$q.when(action && action.perform()).then(function (result) {
//Don't go into edit mode for folders
if (domainObjectType!=='folder') {
navigationService.setNavigation(editableDomainObject);
}
broadcastDrop(id, event);
});
}
}
//}
// TODO: Alert user if drag and drop is not allowed
}
// We can only handle drops if we have access to actions...
if (actionCapability) {
// Listen for dragover, to indicate we'll accept a drag
element.on('dragover', dragOver);
// Listen for the drop itself
element.on('drop', drop);
}
this.element = element;
this.dragOverCallback = dragOver;
this.dropCallback = drop;
}
DropGesture.prototype.destroy = function () {
this.element.off('dragover', this.dragOverCallback);
this.element.off('drop', this.dropCallback);
};
return DropGesture;
}
);