Merge remote-tracking branch 'github/master' into open1515
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
{
|
||||
"key": "menu",
|
||||
"implementation": "gestures/ContextMenuGesture.js",
|
||||
"depends": []
|
||||
"depends": ["$timeout", "agentService"]
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
@@ -54,7 +54,7 @@
|
||||
{
|
||||
"key": "menu",
|
||||
"implementation": "actions/ContextMenuAction.js",
|
||||
"depends": [ "$compile", "$document", "$window", "$rootScope" ]
|
||||
"depends": [ "$compile", "$document", "$window", "$rootScope", "agentService" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -49,8 +49,9 @@ define(
|
||||
* should be performed
|
||||
* @implements {Action}
|
||||
*/
|
||||
function ContextMenuAction($compile, $document, $window, $rootScope, actionContext) {
|
||||
function ContextMenuAction($compile, $document, $window, $rootScope, agentService, actionContext) {
|
||||
this.$compile = $compile;
|
||||
this.agentService = agentService;
|
||||
this.actionContext = actionContext;
|
||||
this.getDocument = function () { return $document; };
|
||||
this.getWindow = function () { return $window; };
|
||||
@@ -70,6 +71,7 @@ define(
|
||||
scope = $rootScope.$new(),
|
||||
goLeft = eventCoors[0] + menuDim[0] > winDim[0],
|
||||
goUp = eventCoors[1] + menuDim[1] > winDim[1],
|
||||
initiatingEvent = this.agentService.isMobile() ? 'touchstart' : 'mousedown',
|
||||
menu;
|
||||
|
||||
// Remove the context menu
|
||||
@@ -99,21 +101,22 @@ define(
|
||||
"go-up": goUp,
|
||||
"context-menu-holder": true
|
||||
};
|
||||
|
||||
// Create the context menu
|
||||
menu = $compile(MENU_TEMPLATE)(scope);
|
||||
|
||||
// Add the menu to the body
|
||||
body.append(menu);
|
||||
|
||||
// Stop propagation so that clicks on the menu do not close the menu
|
||||
menu.on('mousedown', function (event) {
|
||||
// Stop propagation so that clicks or touches on the menu do not close the menu
|
||||
menu.on(initiatingEvent, function (event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dismiss the menu when body is clicked elsewhere
|
||||
// Dismiss the menu when body is clicked/touched elsewhere
|
||||
// ('mousedown' because 'click' breaks left-click context menus)
|
||||
body.on('mousedown', dismiss);
|
||||
// ('touchstart' because 'touch' breaks context menus up)
|
||||
body.on(initiatingEvent, dismiss);
|
||||
// NOTE: Apply to mobile?
|
||||
menu.on('click', dismiss);
|
||||
|
||||
// Don't launch browser's context menu
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
/*global define,Promise*/
|
||||
|
||||
/**
|
||||
* Module defining ContextMenuGesture.
|
||||
* Module defining ContextMenuGesture.
|
||||
* Created by vwoeltje on 11/17/14. Modified by shale on 06/30/2015.
|
||||
*/
|
||||
define(
|
||||
@@ -41,7 +41,10 @@ define(
|
||||
* in the context menu will be performed
|
||||
* @implements {Gesture}
|
||||
*/
|
||||
function ContextMenuGesture(element, domainObject) {
|
||||
function ContextMenuGesture($timeout, agentService, element, domainObject) {
|
||||
var isPressing,
|
||||
longTouchTime = 500;
|
||||
|
||||
function showMenu(event) {
|
||||
domainObject.getCapability('action').perform({
|
||||
key: 'menu',
|
||||
@@ -51,7 +54,33 @@ define(
|
||||
}
|
||||
|
||||
// When context menu event occurs, show object actions instead
|
||||
element.on('contextmenu', showMenu);
|
||||
if (!agentService.isMobile()) {
|
||||
|
||||
// When context menu event occurs, show object actions instead
|
||||
element.on('contextmenu', showMenu);
|
||||
} else if (agentService.isMobile()) {
|
||||
|
||||
// If on mobile device, then start timeout for the single touch event
|
||||
// during the timeout 'isPressing' is true.
|
||||
element.on('touchstart', function (event) {
|
||||
if (event.touches.length < 2) {
|
||||
isPressing = true;
|
||||
|
||||
// After the timeout, if 'isPressing' is
|
||||
// true, display context menu for object
|
||||
$timeout(function () {
|
||||
if (isPressing) {
|
||||
showMenu(event);
|
||||
}
|
||||
}, longTouchTime);
|
||||
}
|
||||
});
|
||||
|
||||
// Whenever the touch event ends, 'isPressing' is false.
|
||||
element.on('touchend', function (event) {
|
||||
isPressing = false;
|
||||
});
|
||||
}
|
||||
|
||||
this.showMenuCallback = showMenu;
|
||||
this.element = element;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
|
||||
/*global define,describe,it,expect,beforeEach,jasmine*/
|
||||
|
||||
|
||||
/**
|
||||
@@ -43,6 +43,7 @@ define(
|
||||
mockBody,
|
||||
mockWindow,
|
||||
mockRootScope,
|
||||
mockAgentService,
|
||||
mockScope,
|
||||
mockElement,
|
||||
mockDomainObject,
|
||||
@@ -58,10 +59,11 @@ define(
|
||||
mockBody = jasmine.createSpyObj("body", JQLITE_FUNCTIONS);
|
||||
mockWindow = { innerWidth: MENU_DIMENSIONS[0] * 4, innerHeight: MENU_DIMENSIONS[1] * 4 };
|
||||
mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]);
|
||||
mockAgentService = jasmine.createSpyObj("agentService", ["isMobile"]);
|
||||
mockScope = {};
|
||||
mockElement = jasmine.createSpyObj("element", JQLITE_FUNCTIONS);
|
||||
mockDomainObject = jasmine.createSpyObj("domainObject", DOMAIN_OBJECT_METHODS);
|
||||
mockEvent = jasmine.createSpyObj("event", ["preventDefault"]);
|
||||
mockEvent = jasmine.createSpyObj("event", ["preventDefault", "stopPropagation"]);
|
||||
mockEvent.pageX = 0;
|
||||
mockEvent.pageY = 0;
|
||||
|
||||
@@ -77,6 +79,7 @@ define(
|
||||
mockDocument,
|
||||
mockWindow,
|
||||
mockRootScope,
|
||||
mockAgentService,
|
||||
mockActionContext
|
||||
);
|
||||
});
|
||||
@@ -156,6 +159,42 @@ define(
|
||||
// Menu should have been removed
|
||||
expect(mockMenu.remove).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps a menu when menu is clicked", function () {
|
||||
// Show the menu
|
||||
action.perform();
|
||||
// Find and fire body's mousedown listener
|
||||
mockMenu.on.calls.forEach(function (call) {
|
||||
if (call.args[0] === 'mousedown') {
|
||||
call.args[1](mockEvent);
|
||||
}
|
||||
});
|
||||
|
||||
// Menu should have been removed
|
||||
expect(mockMenu.remove).not.toHaveBeenCalled();
|
||||
|
||||
// Listener should have been detached from body
|
||||
expect(mockBody.off).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps a menu when menu is clicked on mobile", function () {
|
||||
mockAgentService.isMobile.andReturn(true);
|
||||
action = new ContextMenuAction(
|
||||
mockCompile,
|
||||
mockDocument,
|
||||
mockWindow,
|
||||
mockRootScope,
|
||||
mockAgentService,
|
||||
mockActionContext
|
||||
);
|
||||
action.perform();
|
||||
|
||||
mockMenu.on.calls.forEach(function (call) {
|
||||
if (call.args[0] === 'touchstart') {
|
||||
call.args[1](mockEvent);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -31,28 +31,54 @@ define(
|
||||
"use strict";
|
||||
|
||||
var JQLITE_FUNCTIONS = [ "on", "off", "find", "append", "remove" ],
|
||||
DOMAIN_OBJECT_METHODS = [ "getId", "getModel", "getCapability", "hasCapability", "useCapability" ];
|
||||
DOMAIN_OBJECT_METHODS = [ "getId", "getModel", "getCapability", "hasCapability", "useCapability"];
|
||||
|
||||
|
||||
describe("The 'context menu' gesture", function () {
|
||||
var mockElement,
|
||||
var mockTimeout,
|
||||
mockElement,
|
||||
mockAgentService,
|
||||
mockDomainObject,
|
||||
mockEvent,
|
||||
mockTouchEvent,
|
||||
mockContextMenuAction,
|
||||
mockActionContext,
|
||||
mockTouch,
|
||||
gesture,
|
||||
fireGesture;
|
||||
fireGesture,
|
||||
fireTouchStartGesture,
|
||||
fireTouchEndGesture;
|
||||
|
||||
beforeEach(function () {
|
||||
mockTimeout = jasmine.createSpy("$timeout");
|
||||
mockElement = jasmine.createSpyObj("element", JQLITE_FUNCTIONS);
|
||||
mockAgentService = jasmine.createSpyObj("agentService", ["isMobile"]);
|
||||
mockDomainObject = jasmine.createSpyObj("domainObject", DOMAIN_OBJECT_METHODS);
|
||||
mockEvent = jasmine.createSpyObj("event", ["preventDefault"]);
|
||||
|
||||
gesture = new ContextMenuGesture(mockElement, mockDomainObject);
|
||||
mockContextMenuAction = jasmine.createSpyObj(
|
||||
"action",
|
||||
[ "perform", "getActions" ]
|
||||
);
|
||||
mockActionContext = jasmine.createSpyObj(
|
||||
"actionContext",
|
||||
[ "" ]
|
||||
);
|
||||
|
||||
mockActionContext = {domainObject: mockDomainObject, event: mockEvent};
|
||||
mockDomainObject.getCapability.andReturn(mockContextMenuAction);
|
||||
mockContextMenuAction.perform.andReturn(jasmine.any(Function));
|
||||
mockAgentService.isMobile.andReturn(false);
|
||||
|
||||
|
||||
gesture = new ContextMenuGesture(mockTimeout, mockAgentService, mockElement, mockDomainObject);
|
||||
|
||||
// Capture the contextmenu callback
|
||||
fireGesture = mockElement.on.mostRecentCall.args[1];
|
||||
});
|
||||
|
||||
it("attaches a callback for context menu events", function () {
|
||||
// Fire a click and expect it to happen
|
||||
fireGesture();
|
||||
expect(mockElement.on).toHaveBeenCalledWith(
|
||||
"contextmenu",
|
||||
jasmine.any(Function)
|
||||
@@ -70,6 +96,34 @@ define(
|
||||
mockDomainObject.calls
|
||||
);
|
||||
});
|
||||
|
||||
it("attaches a callback for context menu events on mobile", function () {
|
||||
// Mock touch event and set to mobile device
|
||||
mockTouchEvent = jasmine.createSpyObj("event", ["preventDefault", "touches"]);
|
||||
mockTouch = jasmine.createSpyObj("touch", ["length"]);
|
||||
mockTouch.length = 1;
|
||||
mockTouchEvent.touches.andReturn(mockTouch);
|
||||
mockAgentService.isMobile.andReturn(true);
|
||||
|
||||
// Then create new (mobile) gesture
|
||||
gesture = new ContextMenuGesture(mockTimeout, mockAgentService, mockElement, mockDomainObject);
|
||||
|
||||
// Set calls for the touchstart and touchend gestures
|
||||
fireTouchStartGesture = mockElement.on.calls[1].args[1];
|
||||
fireTouchEndGesture = mockElement.on.mostRecentCall.args[1];
|
||||
|
||||
// Fire touchstart and expect touch start to begin
|
||||
fireTouchStartGesture(mockTouchEvent);
|
||||
expect(mockElement.on).toHaveBeenCalledWith(
|
||||
"touchstart",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
// Expect timeout to begin and then fireTouchEnd
|
||||
expect(mockTimeout).toHaveBeenCalled();
|
||||
mockTimeout.mostRecentCall.args[0]();
|
||||
fireTouchEndGesture(mockTouchEvent);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user