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

/*global module, test, htmlbody, ok, equals, same, stop, start */

var pane = SC.ControlTestPane.design({ height: 32 })

.add("basic", SC.ListItemView.design({
  content: "List Item"
}))

.add("full", SC.ListItemView.design({
  content: SC.Object.create({
    icon: "sc-icon-folder-16",
    rightIcon: "sc-icon-help-16",
    title: "List Item",
    checkbox: YES,
    count: 23,
    branch: YES
  }),

  hasContentIcon:  YES,
  hasContentRightIcon:  YES,
  hasContentBranch: YES,

  contentValueKey: "title",
  contentCheckboxKey: 'checkbox',
  contentIconKey:  "icon",
  contentRightIconKey:  "rightIcon",
  contentUnreadCountKey: 'count',
  contentIsBranchKey: 'branch',

  disclosureState: SC.BRANCH_OPEN

}))

.add("full - sel", SC.ListItemView.design({
  content: SC.Object.create({
    icon: "sc-icon-folder-16",
    rightIcon: "sc-icon-help-16",
    title: "List Item",
    checkbox: YES,
    count: 23,
    branch: YES
  }),

  isSelected: YES,

  hasContentIcon:  YES,
  hasContentRightIcon:  YES,
  hasContentBranch: YES,

  contentValueKey: "title",
  contentLeftActionKey: 'checkbox',
  leftAction: 'checkbox',

  contentRightActionKey: 'isLoading',

  contentCheckboxKey: 'checkbox',
  contentIconKey:  "icon",
  contentRightIconKey:  "rightIcon",
  contentUnreadCountKey: 'count',
  contentIsBranchKey: 'branch',

  disclosureState: SC.BRANCH_OPEN

}))

.add("icon", SC.ListItemView.design({
  content: SC.Object.create({
    title: "List Item",
    icon: "sc-icon-folder-16"
  }),

  contentValueKey: "title",

  contentIconKey:  "icon",
  hasContentIcon:  YES

}))

.add("icon - noIcon", SC.ListItemView.design({
  content: SC.Object.create({
    title: "List Item"
  }),
  contentValueKey: "title",
  contentIconKey:  "icon",
  hasContentIcon:  YES
}))

.add("icon - contentandview", SC.ListItemView.design({
  content: SC.Object.create({
    title: "List Item",
    icon: "sc-icon-folder-16"
  }),

  icon: "sc-icon-info-16",

  contentValueKey: "title",

  contentIconKey:  "icon",
  hasContentIcon:  YES

}))

.add("icon - view", SC.ListItemView.design({
  content: SC.Object.create({
    title: "List Item"
  }),

  icon: "sc-icon-info-16",

  contentValueKey: "title"
}))

.add("rightIcon", SC.ListItemView.design({
  content: SC.Object.create({
    title: "List Item",
    rightIcon: "sc-icon-help-16"
  }),

  contentValueKey: "title",

  contentRightIconKey:  "rightIcon",
  hasContentRightIcon:  YES

}))

.add("rightIcon - noRightIcon", SC.ListItemView.design({
  content: SC.Object.create({
    title: "List Item"
  }),
  contentValueKey: "title",
  contentRightIconKey:  "rightIcon",
  hasContentRightIcon:  YES
}))

.add("rightIcon - contentAndView", SC.ListItemView.design({
  content: SC.Object.create({
    title: "List Item",
    rightIcon: "sc-icon-help-16"
  }),

  rightIcon: "sc-icon-favorite-16",

  contentValueKey: "title",

  contentRightIconKey:  "rightIcon",
  hasContentRightIcon:  YES

}))

.add("rightIcon - view", SC.ListItemView.design({
  content: SC.Object.create({
    title: "List Item"
  }),

  rightIcon: "sc-icon-favorite-16",

  contentValueKey: "title"
}))

.add("disclosure - YES", SC.ListItemView.design({
  content: SC.Object.create({ title: "List Item" }),
  contentValueKey: "title",
  disclosureState: SC.BRANCH_OPEN
}))

.add("disclosure - NO", SC.ListItemView.design({
  content: SC.Object.create({ title: "List Item" }),
  contentValueKey: "title",
  disclosureState: SC.BRANCH_CLOSED
}))

.add("checkbox - YES", SC.ListItemView.design({
  content: SC.Object.create({ title: "List Item", checkbox: YES }),
  contentValueKey: "title",
  contentCheckboxKey:  "checkbox"
}))

.add("checkbox - NO", SC.ListItemView.design({
  content: SC.Object.create({ title: "List Item", checkbox: NO }),
  contentValueKey: "title",
  contentCheckboxKey:  "checkbox"
}))

.add("count - 0", SC.ListItemView.design({
  content: SC.Object.create({ title: "List Item", count: 0 }),
  contentValueKey: "title",
  contentUnreadCountKey:  "count"
}))

.add("count - 10", SC.ListItemView.design({
  content: SC.Object.create({ title: "List Item", count: 10 }),
  contentValueKey: "title",
  contentUnreadCountKey:  "count"
}))

.add("outline - 1", SC.ListItemView.design({
  content: SC.Object.create({ title: "List Item" }),
  contentValueKey: "title",
  contentUnreadCountKey:  "count",
  outlineLevel: 1
}))

.add("outline - 2", SC.ListItemView.design({
  content: SC.Object.create({ title: "List Item" }),
  contentValueKey: "title",
  contentUnreadCountKey:  "count",
  outlineLevel: 2
}))

.add("right icon", SC.ListItemView.design(SC.ActionSupport,{
  content: SC.Object.create({
    title: "List Item",
    icon: "sc-icon-folder-16"
  }),
  contentValueKey: "title",
  hasContentRightIcon: YES,
  contentRightIconKey: "icon",
  rightIconAction: "doOnRightIconAction",
  rightIconTarget: "onRightIconTarget"
}));

// .….….….….….….….….….….….….….….. // DETECTORS // // The functions below test the presence of a particular part of the view. If // you pass the second param then it expects the part to be in the view. If // you pass null, then it expects the part to NOT be in the view.

function basic(view, sel, disabled) {

var cq = view.$();
ok(cq.hasClass('sc-list-item-view'), 'should have sc-list-item-view class');

equals(cq.hasClass('sel'), !!sel, 'expect sel class');
equals(cq.hasClass('disabled'), !!disabled, 'expect disabled class');

var idx = view.get('contentIndex');
var evenOrOdd = (idx % 2 === 0) ? 'even' : 'odd';
ok(cq.hasClass(evenOrOdd), 'should have an %@ class'.fmt(evenOrOdd));

}

function label(view, labelText) {

if (labelText === null) {
  equals(view.$('label').size(), 0, 'should not have label');
} else {
  equals(view.$('label').text(), labelText, 'should have label text');
}

}

function icon(view, spriteName) {

var cq = view.$(), iconCQ = cq.find('img.icon');
if (spriteName === null) {
  ok(!cq.hasClass('has-icon'), "should not have has-icon class");
  equals(iconCQ.size(), 0, 'should not have image');
} else {
  ok(cq.hasClass('has-icon'), "should have has-icon class");
  equals(iconCQ.size(), 1, 'should have icon');
  ok(iconCQ.hasClass(spriteName), 'icon should have class name %@'.fmt(spriteName));
}

}

function rightIcon(view, spriteName) {

var cq = view.$(), iconCQ = cq.find('img.right-icon');
if (spriteName === null) {
  ok(!cq.hasClass('has-right-icon'), "should not have has-right-icon class");
  equals(iconCQ.size(), 0, 'should not have image');
} else {
  ok(cq.hasClass('has-right-icon'), "should have has-right-icon class");
  equals(iconCQ.size(), 1, 'should have right-icon');
  ok(iconCQ.hasClass(spriteName), 'icon should have class name %@'.fmt(spriteName));
}

}

function disclosure(view, state) {

var cq = view.$(), disclosureCQ = cq.find('.sc-disclosure-view');

if (state === null) {
  ok(!cq.hasClass('has-disclosure'), "should not have has-disclosure class");
  equals(disclosureCQ.size(), 0, "should not have disclosure");
} else {
  ok(cq.hasClass('has-disclosure'), "should have has-disclosure class");
  equals(disclosureCQ.size(), 1, "should have disclosure element");
  equals(disclosureCQ.hasClass('sel'), state === true, "disclosure expects sel class");
}

}

function checkbox(view, state) {

var cq = view.$(), checkboxCQ = cq.find('.sc-checkbox-view');
if (state === null) {
  ok(!cq.hasClass('has-checkbox'), "should not have has-checkbox class");
  equals(checkboxCQ.size(), 0, 'should not have checkbox');
} else {
  ok(cq.hasClass('has-checkbox'), "should have has-checkbox class");
  equals(checkboxCQ.size(), 1, 'should have checkbox element');
  equals(checkboxCQ.hasClass('sel'), state === true, 'expects sel class');
  equals(checkboxCQ.hasClass('mixed'), state === SC.MIXED_STATE, 'expects mixed class');
}

}

function count(view, cnt) {

var cq = view.$(), countCQ = cq.find('.count');
if (cnt === null) {
  ok(!cq.hasClass('has-count'), "should not have has-count class");
  equals(countCQ.size(), 0, 'should not have count');
} else {
  ok(cq.hasClass('has-count'), "should have has-count class");
  equals(countCQ.size(), 1, 'should have count');
  equals(countCQ.text(), cnt.toString(), 'should have count text');
}

}

function branch(view, visible) {

var cq = view.$(), branchCQ = cq.find('.branch');
if (visible === null) {
  ok(!cq.hasClass('has-branch'), "should not have has-branch class");
  equals(branchCQ.size(), 0, 'should not have branch');
} else {
  ok(cq.hasClass('has-branch'), "should have has-branch class");
  equals(branchCQ.size(), 1, 'should have branch');
  equals(branchCQ.hasClass('branch-visible'), visible, 'is visible');
}

}

function rightIcon(view, hasIt) {

var cq = view.$(), rightIconCQ = cq.find('.right-icon');
if (hasIt) {
  ok(cq.hasClass('has-right-icon'), "should have has-right-icon class");
  equals(rightIconCQ.size(), 1, 'should have right icon');
} else {
  ok(!cq.hasClass('has-right-icon'), "should not have has-right-icon class");
  equals(rightIconCQ.size(), 0, 'should not have branch') ;
}

}

// .….….….….….….….….….….….….….….. // Test Basic Setup //

module(“SC.ListItemView UI”, pane.standardSetup());

test(“basic”, function () {

var view = pane.view('basic');

basic(view, NO, NO);
icon(view, null);
rightIcon(view, null);
label(view, 'List Item');
disclosure(view, null);
checkbox(view, null);
count(view, null);
branch(view, null);

});

test(“full”, function () {

var view = pane.view('full');
basic(view, NO, NO);
icon(view, 'sc-icon-folder-16');
rightIcon(view, 'sc-icon-help-16');
label(view, 'List Item');
disclosure(view, YES);
checkbox(view, YES);
count(view, 23);
branch(view, YES);

});

test(“full - sel”, function () {

var view = pane.view('full - sel');
basic(view, YES, NO);
icon(view, 'sc-icon-folder-16');
rightIcon(view, 'sc-icon-help-16');
label(view, 'List Item');
disclosure(view, YES);
checkbox(view, YES);
count(view, 23);
branch(view, YES);

});

test(“icon”, function () {

var view = pane.view('icon');
icon(view, 'sc-icon-folder-16');

});

test(“icon defined but not in view or content”, function () {

var view = pane.view('icon - noIcon');
icon(view, null);

});

test(“icon defined in view and in content”, function () {

var view = pane.view('icon - contentandview');
icon(view, 'sc-icon-folder-16');

});

test(“icon defined only in view”, function () {

var view = pane.view('icon - view');
icon(view, 'sc-icon-info-16');

});

test(“rightIcon”, function () {

var view = pane.view('rightIcon');
rightIcon(view, 'sc-icon-help-16');

});

test(“rightIcon defined but not in view or content”, function () {

var view = pane.view('rightIcon - noRightIcon');
rightIcon(view, null);

});

test(“rightIcon defined in view and in content”, function () {

var view = pane.view('rightIcon - contentAndView');
rightIcon(view, 'sc-icon-help-16');

});

test(“rightIcon defined only in view”, function () {

var view = pane.view('rightIcon - view');
rightIcon(view, 'sc-icon-favorite-16');

});

test('disclosure', function () {

disclosure(pane.view('disclosure - YES'), YES);
disclosure(pane.view('disclosure - NO'), NO);

});

test('checkbox', function () {

checkbox(pane.view('checkbox - YES'), YES);
checkbox(pane.view('checkbox - NO'), NO);

});

test('count', function () {

// no count should show when count = 0;
count(pane.view('count - 0'), null);
count(pane.view('count - 10'), 10);

});

test(“outline - 1”, function () {

var v = pane.view('outline - 1'),
    indent = v.get('outlineIndent');

ok(indent > 0, 'precond - outlineIndent property should be > 0 (actual: %@)'.fmt(indent));

equals(v.$('.sc-outline').css('left'), indent * 1 + 16 + "px", 'sc-outline div should be offset by outline ammount');

});

test(“outline - 2”, function () {

var v = pane.view('outline - 2'),
    indent = v.get('outlineIndent');

ok(indent > 0, 'precond - outlineIndent property should be > 0 (actual: %@)'.fmt(indent));

equals(v.$('.sc-outline').css('left'), indent * 2 + 16 + "px", 'sc-outline div should be offset by outline ammount');

});

// .….….….….….….….….….….….….….….. // EDITING CONTENT //

function adjustView(view, key, value) {

SC.RunLoop.begin();
view.set(key, value);
SC.RunLoop.end();

}

// gets the view content and adjusts the value inside of a runloop, ensuring // the UI gets an update also. function adjustContent(view, key, value) {

var content = view.get('content');
SC.RunLoop.begin();
content.set(key, value);
SC.RunLoop.end();

}

test(“changing label should change display”, function () {

var view = pane.view('full');
adjustContent(view, 'title', 'FOO');
label(view, 'FOO'); // verify change

});

test(“changing disclosure value should update display”, function () {

var view = pane.view('full');
adjustView(view, 'disclosureState', SC.BRANCH_CLOSED);
disclosure(view, NO);

// changing to leaf node should remove disclosure view
adjustView(view, 'disclosureState', SC.LEAF_NODE);
disclosure(view, null);

// changing back to open/closed should add the disclosure back
adjustView(view, 'disclosureState', SC.BRANCH_OPEN);
disclosure(view, YES);

});

test(“changing checkbox value should update display”, function () {

var view = pane.view('full');
adjustContent(view, 'checkbox', NO);
checkbox(view, NO); // verify change

// changing to null should remove checkbox view
adjustContent(view, 'checkbox', null);
checkbox(view, null);

// changing back to YES should add the checkbox back
adjustContent(view, 'checkbox', YES);
checkbox(view, YES);

});

test(“changing count value should update display”, function () {

var view = pane.view('full');

adjustContent(view, 'count', 100);
count(view, 100); // verify change

adjustContent(view, 'count', 0);
count(view, null); // verify change

});

test(“right icon action dom”, function() {

// basic does not have right icon and action
var view = pane.view('basic');
rightIcon(view, false);

// has right icon and action
view = pane.view('right icon');
rightIcon(view, true);

});

test(“right icon action event”, function() {

var spiedRootResponder = { sendAction: function(){} };
var sendActionSpy = CoreTest.spyOn(spiedRootResponder, 'sendAction');

var view = pane.view('right icon'),
    spyPane = SC.Object.create({
      rootResponder: spiedRootResponder
    });

view.pane=spyPane;

var expectedAction = view.get("rightIconAction");
var expectedTarget = view.get("rightIconTarget");
var target = view.$('.right-icon').get(0);
var evt = { target: target, which: 1 };
view.mouseDown(evt);
view.mouseUp(evt);

ok(expectedAction === "doOnRightIconAction", 'expectedAction should have been doOnRightIconAction');
ok(sendActionSpy.wasCalled, 'action should have been called');
ok(sendActionSpy.wasCalledWith(expectedAction,expectedTarget,view,spyPane), 'should have triggered the action with these arguments');

});