// ========================================================================== // Project: SproutCore
- JavaScript Application Framework // Copyright: ©2006-2011 Strobe Inc. and contributors. // portions copyright @2011 Apple Inc. // License: Licensed under MIT license (see license.js) // ========================================================================== /* globals equals, ok, test, module, start, stop */ var view, content, contentController, pane, actionCalled = 0;
module(“SC.CollectionView Mouse Events”, {
setup: function() { SC.run(function () { content = "1 2 3 4 5 6 7 8 9 10".w().map(function(x) { return SC.Object.create({ value: x }); }); contentController = SC.ArrayController.create({ content: content, allowsMultipleSelection: YES }); view = SC.CollectionView.create({ content: contentController, layout: { top: 0, left: 0, width: 300, height: 500 }, layoutForContentIndex: function(idx) { return { left: 0, right: 0, top: idx * 50, height: 50 }; }, isVisibleInWindow: YES, acceptsFirstResponder: YES, action: function() { actionCalled++; } }); pane = SC.MainPane.create(); pane.appendChild(view); pane.append(); }); }, teardown: function() { SC.run(function () { pane.destroy(); pane = view = content = contentController = null; actionCalled = 0; }); }
});
/*
Simulates clicking on the specified index. If you pass verify as YES or NO also verifies that the item view is subsequently selected or not. @param {SC.CollectionView} view the view @param {Number} index the index to click on @param {Boolean} shiftKey simulate shift key pressed @param {Boolean} ctrlKey simulate ctrlKey pressed @param {SC.SelectionSet} expected expected selection @param {Number} delay delay before running the test (optional) @returns {void}
*/ function clickOn(view, index, shiftKey, ctrlKey, expected, delay) {
var itemView = view.itemViewForContentIndex(index), layer = itemView.get('layer'), opts = { shiftKey: shiftKey, ctrlKey: ctrlKey }, sel, ev, modifiers; ok(layer, 'precond - itemView[%@] should have layer'.fmt(index)); ev = SC.Event.simulateEvent(layer, 'mousedown', opts); SC.Event.trigger(layer, 'mousedown', [ev]); ev = SC.Event.simulateEvent(layer, 'mouseup', opts); SC.Event.trigger(layer, 'mouseup', [ev]); if (expected !== undefined) { var f = function() { SC.RunLoop.begin(); sel = view.get('selection'); modifiers = []; if (shiftKey) modifiers.push('shift'); if (ctrlKey) modifiers.push('ctrl'); modifiers = modifiers.length > 0 ? modifiers.join('+') : 'no modifiers'; ok(expected ? expected.isEqual(sel) : expected === sel, 'should have selection: %@ after click with %@ on item[%@], actual: %@'.fmt(expected, modifiers, index, sel)); SC.RunLoop.end(); if (delay) { start(); }// starts the test runner }; if (delay) { stop() ; // stops the test runner setTimeout(f, delay) ; } else f() ; } layer = itemView = null ;
}
/*
Creates an SC.SelectionSet from a given index. @param {Number} index the index of the content to select @returns {SC.SelectionSet}
*/
function selectionFromIndex(index) {
var ret = SC.SelectionSet.create(); ret.addObject(content.objectAt(index)); return ret;
}
/*
Creates an SC.SelectionSet from a given SC.IndexSet. @param {Number} index the index of the content to select @returns {SC.SelectionSet}
*/ function selectionFromIndexSet(indexSet) {
var ret = SC.SelectionSet.create(); ret.add(content, indexSet); return ret;
}
// .….….….….….….….….….….….….….….. // basic click //
test(“clicking on an item should select it”, function() {
clickOn(view, 3, NO, NO, selectionFromIndex(3));
});
test(“clicking on a selected item should clear selection after 300ms and reselect it”, function() {
SC.run(function () { view.select(SC.IndexSet.create(1,5)); }); clickOn(view, 3, NO, NO, selectionFromIndex(3), 500);
});
test(“clicking on unselected item should clear selection and select it”, function() {
SC.run(function () { view.select(SC.IndexSet.create(1,5)); }); clickOn(view, 7, NO, NO, selectionFromIndex(7));
});
test(“first responder”, function() {
clickOn(view, 3); equals(view.get('isFirstResponder'), YES, 'view.isFirstResponder should be YES after mouse down');
});
test(“clicking on a collection view with null content should not throw an error”, function() {
var failed = NO; SC.run(function () { view.set('content', null); }); try { var l = view.get('layer'), evt = SC.Event.simulateEvent(l, 'mousedown'); SC.Event.trigger(l, 'mousedown', [evt]); } catch (e) { failed = YES; } ok(!failed, "clicking on a collection view with null content should not throw an error");
});
test(“clicking on an item should select it when useToggleSelection is true”, function() {
view.set('useToggleSelection', YES); clickOn(view, 3, NO, NO, selectionFromIndex(3));
});
test(“clicking on an unselected item should select it when useToggleSelection is true”, function() {
view.set('useToggleSelection', YES); clickOn(view, 3, NO, NO, selectionFromIndex(3));
});
test(“clicking on a selected item should deselect it when useToggleSelection is true”, function() {
view.set('useToggleSelection', YES); SC.run(function () { view.select(SC.IndexSet.create(3,1)); }); clickOn(view, 3, NO, NO, SC.SelectionSet.create());
});
test(“clicking on an unselected item should select it and add it to the selection when useToggleSelection is true”, function() {
view.set('useToggleSelection', YES); clickOn(view, 1, NO, NO, selectionFromIndex(1)); clickOn(view, 3, NO, NO, selectionFromIndex(1).addObject(content.objectAt(3)));
});
test(“clicking on a selected item should remove it from the selection when useToggleSelection is true”, function() {
view.set('useToggleSelection', YES); SC.run(function () { view.select(SC.IndexSet.create(1,5)); }); clickOn(view, 5, NO, NO, selectionFromIndexSet(SC.IndexSet.create(1,4)));
});
test(“clicking on an unselected item should select it and clear the previous selection when useToggleSelection is true and allowsMultipleSelection is not”, function() {
view.set('useToggleSelection', YES); contentController.set('allowsMultipleSelection', NO); clickOn(view, 1, NO, NO, selectionFromIndex(1)); clickOn(view, 3, NO, NO, selectionFromIndex(3));
});
test(“clicking on an unselected item should fire action when actOnSelect is true”, function() {
view.set('actOnSelect', YES); equals(actionCalled, 0, "precond - action hasn't been called"); clickOn(view, 1, NO, NO); equals(actionCalled, 1, "Action called when item is selected");
});
test(“clicking on an unselected item should fire action when useToggleSelection is true and actOnSelect is true”, function() {
view.set('useToggleSelection', YES); view.set('actOnSelect', YES); equals(actionCalled, 0, "precond - action hasn't been called"); clickOn(view, 1, NO, NO); equals(actionCalled, 1, "Action called when item is selected");
});
test(“clicking on an unselected item should fire action when useToggleSelection is true and selectOnMouseDown is true and actOnSelect is true”, function() {
view.set('actOnSelect', YES); view.set('useToggleSelection', YES); view.set('selectOnMouseDown', YES); equals(actionCalled, 0, "precond - action hasn't been called"); clickOn(view, 1, NO, NO); equals(actionCalled, 1, "Action called when item is selected");
});
test(“click on an item when isSelectable is false doesn't do anything”, function() {
view.set('isSelectable', NO); clickOn(view, 1, NO, NO, null);
});
test(“click on an item when isEnabled is false doesn't do anything”, function() {
SC.run(function () { view.set('isEnabled', NO); }); clickOn(view, 1, NO, NO, null);
});
// .….….….….….….….….….….….….….….. // double click //
test(“double-clicking on an unselected item should fire action when actOnSelect is false”, function() {
equals(actionCalled, 0, "precond - action hasn't been called"); clickOn(view, 1, NO, NO); equals(actionCalled, 0, "No action is called on first click"); clickOn(view, 1, NO, NO); equals(actionCalled, 1, "Action called when item receives second click");
});
// .….….….….….….….….….….….….….….. // ctrl-click mouse down //
test(“ctrl-clicking on unselected item should add to selection”, function() {
clickOn(view,3, NO, YES, selectionFromIndex(3)); clickOn(view,5, NO, YES, selectionFromIndex(3).addObject(content.objectAt(5)));
});
test(“ctrl-clicking on selected item should remove from selection”, function() {
clickOn(view,3, NO, YES, selectionFromIndex(3)); clickOn(view,5, NO, YES, selectionFromIndex(3).addObject(content.objectAt(5))); clickOn(view,3, NO, YES, selectionFromIndex(5)); clickOn(view,5, NO, YES, SC.SelectionSet.create());
});
// .….….….….….….….….….….….….….….. // shift-click mouse down //
test(“shift-clicking on an item below should extend the selection”, function() {
clickOn(view, 3, NO, NO, selectionFromIndex(3)); clickOn(view, 5, YES, NO, selectionFromIndexSet(SC.IndexSet.create(3,3)));
});
test(“shift-clicking on an item above should extend the selection”, function() {
clickOn(view, 3, NO, NO, selectionFromIndex(3)); clickOn(view, 1, YES, NO, selectionFromIndexSet(SC.IndexSet.create(1,3)));
});
test(“shift-clicking inside selection first time should reduce selection from top”, function() {
SC.run(function () { view.select(SC.IndexSet.create(3,4)); }); clickOn(view,4, YES, NO, selectionFromIndexSet(SC.IndexSet.create(3,2)));
});
test(“shift-click below to extend selection down then shift-click inside selection should reduce selection”, function() {
clickOn(view, 3, NO, NO, selectionFromIndex(3)); clickOn(view, 5, YES, NO, selectionFromIndexSet(SC.IndexSet.create(3,3))); clickOn(view,4, YES, NO, selectionFromIndexSet(SC.IndexSet.create(3,2)));
});
test(“shift-click above to extend selection down then shift-click inside selection should reduce top of selection”, function() {
clickOn(view, 3, NO, NO, selectionFromIndex(3)); clickOn(view, 1, YES, NO, selectionFromIndexSet(SC.IndexSet.create(1,3))); clickOn(view,2, YES, NO, selectionFromIndexSet(SC.IndexSet.create(2,2)));
});
test(“shift-click below bottom of selection then shift click on top of selection should select only top item”, function() {
clickOn(view, 3, NO, NO, selectionFromIndex(3)); clickOn(view, 5, YES, NO, selectionFromIndexSet(SC.IndexSet.create(3,3))); clickOn(view,3, YES, NO, selectionFromIndex(3));
});