// ========================================================================== // 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) // ==========================================================================

/*

This test evaluates drag and drop support for SC.ListView

*/

// Create a fake content array. Generates a list with whatever length you // want of objects with a title based on the index. Cannot mutate. var ContentArray = SC.Object.extend(SC.Array, {

length: 0,

objectAt: function(idx) {
  if (idx >= this.get('length')) { return undefined; }

  var content = this._content, ret ;
  if (!content) { content = this._content = []; }

  ret = content[idx];
  if (!ret) {
    ret = content[idx] = SC.Object.create({
      title: "ContentItem %@".fmt(idx),
      isDone: (idx % 3)===0,
      unread: (Math.random() > 0.5) ? Math.floor(Math.random() * 100) : 0
    });
  }

  return ret ;
}

});

var pane = SC.ControlTestPane.design()

.add("basic", SC.ScrollView.design({
  borderStyle: SC.BORDER_NONE,
  layout: { left: 0, right: 0, top: 0, height: 300 },
  hasHorizontalScroller: NO,
  contentView: SC.ListView.design({
    content: ContentArray.create({ length: 5 }),
    contentValueKey: "title",
    contentCheckboxKey: "isDone",
    contentUnreadCountKey: "unread",
    rowHeight: 20,
    _didCallDragEnded: false,
    dragEnded: function() {
      sc_super();
      this._didCallDragEnded = true;
    }
  })
}))
.add("empty", SC.ScrollView.design({
  borderStyle: SC.BORDER_NONE,
  layout: { left: 0, right: 0, top: 0, height: 300 },
  hasHorizontalScroller: NO,
  contentView: SC.ListView.design({
    contentValueKey: "title",
    contentCheckboxKey: "isDone",
    contentUnreadCountKey: "unread",
    rowHeight: 20,
    _didCallDragEnded: false,
    dragEnded: function() {
      sc_super();
      this._didCallDragEnded = true;
    }
  })
}));

module(“SC.ListView - drag and drop”, pane.standardSetup());

test(“drag on default list view”, function() {

var ev,
  itemView,
  frame,
  layer,
  listView = pane.view("basic").get('contentView');

itemView = listView.itemViewForContentIndex(0);
frame = itemView.get('frame');
layer = itemView.get('layer');
ev = SC.Event.simulateEvent(layer, 'mousedown', { pageX: frame.x, pageY: frame.y });
SC.Event.trigger(layer, 'mousedown', [ev]);

ev = SC.Event.simulateEvent(layer, 'mousemove', { pageX: frame.x, pageY: frame.y });
SC.Event.trigger(layer, 'mousemove', [ev]);

equals(listView.get('dragContent'), null, 'dragContent should not be set, because the default implementation should prevent dragging');

// Clean up
ev = SC.Event.simulateEvent(layer, 'mouseup', { pageX: frame.x, pageY: frame.y });
SC.Event.trigger(layer, 'mouseup', [ev]);

});

test(“drag on list view with SC.DROP_ON support”, function() {

var ev,
  itemView,
  frame,
  layer,
  listView = pane.view("basic").get('contentView');

// Configure the view to accept drop on.
listView.set('canReorderContent', YES);
listView.set('isDropTarget', YES);
listView.set('delegate', SC.Object.create(SC.CollectionViewDelegate, {
   collectionViewValidateDragOperation: function(view, drag, op, proposedInsertionIndex, proposedDropOperation) {
    return SC.DRAG_ANY;
  }
}));

itemView = listView.itemViewForContentIndex(0);
layer = itemView.get('layer');
frame = itemView.get('frame');
ev = SC.Event.simulateEvent(layer, 'mousedown', { pageX: frame.x, pageY: frame.y });
SC.Event.trigger(layer, 'mousedown', [ev]);

var f = function() {
  var itemView2,
    point;

  SC.RunLoop.begin();
  ev = SC.Event.simulateEvent(layer, 'mousemove', { pageX: frame.x, pageY: frame.y });
  SC.Event.trigger(layer, 'mousemove', [ev]);

  equals(listView.get('dragContent').content, listView.get('content'), "dragContent.content should be equal to the ListView's content");
  ok(listView.get('dragContent').indexes.isEqual(SC.IndexSet.create(0)), "dragContent.indexes should be equal to indexes equal to [{0}]");
  SC.RunLoop.end();

  // Drag over 2nd item
  itemView2 = listView.itemViewForContentIndex(1);
  layer = itemView2.get('layer');
  point = SC.offset(layer);

  ev = SC.Event.simulateEvent(layer, 'mousemove', { pageX: point.x + 1, pageY: point.y + 1 });
  SC.Event.trigger(layer, 'mousemove', [ev]);

  ok(itemView2.get('isDropTarget'), "second list item should have isDropTarget set to true");

  // This test only works because SC.ListItemView supports adding the class to match the property.
  ok(itemView2.$().hasClass('drop-target'), "second list item should add drop-target class");

  // Drag over 3rd item
  itemView = listView.itemViewForContentIndex(2);
  layer = itemView.get('layer');
  point = SC.offset(layer);

  ev = SC.Event.simulateEvent(layer, 'mousemove', { pageX: point.x + 1, pageY: point.y + 1 });
  SC.Event.trigger(layer, 'mousemove', [ev]);

  ok(itemView.get('isDropTarget'), "third list item should have isDropTarget set to true");
  ok(!itemView2.get('isDropTarget'), "second list item should not have isDropTarget set to true");

  // This test only works because SC.ListItemView supports adding the class to match the property.
  ok(itemView.$().hasClass('drop-target'), "third list item should add drop-target class");
  ok(!itemView2.$().hasClass('drop-target'), "second list item should not add drop-target class");

  // Clean up
  ev = SC.Event.simulateEvent(layer, 'mouseup', { pageX: point.x + 1, pageY: point.y + 1 });
  SC.Event.trigger(layer, 'mouseup', [ev]);

  window.start();
};

stop(); // stops the test runner
setTimeout(f, 200);

});

test(“insertion point when drag on list view”, function() {

var ev,
  itemView,
  layer,
  frame,
  listView = pane.view("basic").get('contentView');

listView.set('canReorderContent', YES);

itemView = listView.itemViewForContentIndex(0);
frame = itemView.get('frame');
layer = itemView.get('layer');
ev = SC.Event.simulateEvent(layer, 'mousedown', { pageX: frame.x, pageY: frame.y });
SC.Event.trigger(layer, 'mousedown', [ev]);

var f = function() {
  var itemView2,
    point;

  SC.RunLoop.begin();
  ev = SC.Event.simulateEvent(layer, 'mousemove', { pageX: frame.x, pageY: frame.y });
  SC.Event.trigger(layer, 'mousemove', [ev]);

  // Drag over 2nd item
  itemView2 = listView.itemViewForContentIndex(1);
  layer = itemView2.get('layer');
  point = SC.offset(layer);

  ev = SC.Event.simulateEvent(layer, 'mousemove', { pageX: point.x + 1, pageY: point.y + 1 });
  SC.Event.trigger(layer, 'mousemove', [ev]);

  ok(listView._sc_insertionPointView, "An insertion point should have been added");

  equals(listView._sc_insertionPointView.get('layout').top, 20, "The drag having been over item 2, the insertion point should be located at the top of item 2");

  // Clean up
  ev = SC.Event.simulateEvent(layer, 'mouseup', { pageX: point.x + 1, pageY: point.y + 1 });
  SC.Event.trigger(layer, 'mouseup', [ev]);

  equals(listView._sc_insertionPointView, null, "The insertion point should have been destroyed");

  window.start();
};

stop(); // stops the test runner
setTimeout(f, 200);

});

test(“insertion point when cancel drag on list view”, function() {

var ev,
  itemView,
  frame,
  layer,
  listView = pane.view("basic").get('contentView');

listView.set('canReorderContent', YES);

itemView = listView.itemViewForContentIndex(0);
frame = itemView.get('frame');
layer = itemView.get('layer');
ev = SC.Event.simulateEvent(layer, 'mousedown', { pageX: frame.x, pageY: frame.y });
SC.Event.trigger(layer, 'mousedown', [ev]);

var f = function() {
  var itemView2,
    point;

  SC.RunLoop.begin();
  ev = SC.Event.simulateEvent(layer, 'mousemove', { pageX: frame.x, pageY: frame.y });
  SC.Event.trigger(layer, 'mousemove', [ev]);

  // Drag over 2nd item
  itemView2 = listView.itemViewForContentIndex(1);
  layer = itemView2.get('layer');
  point = SC.offset(layer);

  ev = SC.Event.simulateEvent(layer, 'mousemove', { pageX: point.x + 1, pageY: point.y + 1 });
  SC.Event.trigger(layer, 'mousemove', [ev]);

  ok(listView._sc_insertionPointView, "An insertion point should have been added");

  // cancel drag
  ev = SC.Event.simulateEvent(layer, 'keydown', { keyCode: 27 });
  SC.Event.trigger(layer, 'keydown', [ev]);

  equals(listView._sc_insertionPointView, null, "The insertion point should have been destroyed");
  equals(listView._didCallDragEnded, true, "dragEnded should have been call");

  window.start();
};

stop(); // stops the test runner
setTimeout(f, 200);

});

test(“insertion point on empty list”, function() {

var listView = pane.view('empty').get('contentView'),
    didError = NO;

try {
  SC.run(function() {
    listView.showInsertionPoint(null, SC.DRAG_MOVE);
  });
} catch (e) {
  didError = YES;
}

ok(!didError, "An insertion point was added onto no item view without incident.");

});