Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes issue #1: multiple checkboxes were not handled separately #2

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@

# The repository has been moved to: https://github.com/sproutcore/sproutcore-table
------

#Overview

This is a table view for [Sproutcore](http://www.github.com/sproutcore/sproutcore).
Expand Down
222 changes: 208 additions & 14 deletions views/table_row.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ SC.TableRowView = SC.ListItemView.extend({
return this.getPath('displayDelegate.tableDelegate');
}.property('displayDelegate').cacheable(),


render: function(context) {
var tableDelegate = this.get('tableDelegate'),
left = 3,
Expand Down Expand Up @@ -61,8 +61,8 @@ SC.TableRowView = SC.ListItemView.extend({
context = context.push('<div class="cell col-'+index+'" style="left: '+left+'px; top: 0px; bottom: 0px; width: '+width+'px;">');

if (contentCheckboxKey && contentCheckboxKey.contains(key)) {
var value = SC.get(content, key) || false;
this.renderCheckbox(context, value);
var value = SC.getPath(content, key) || false;
this.renderCheckbox(context, value, key);
}
else {
tableDelegate.renderTableCellContent(this, context, content, contentIndex, col, key);
Expand All @@ -72,6 +72,7 @@ SC.TableRowView = SC.ListItemView.extend({

left += width;
}

},


Expand Down Expand Up @@ -105,8 +106,8 @@ SC.TableRowView = SC.ListItemView.extend({
$cell.css({ width: width+'px', left: left+'px', });

if (contentCheckboxKey && contentCheckboxKey.contains(key)) {
var value = SC.get(content, key) || false;
this.updateCheckbox($cell, value);
var value = SC.getPath(content, key) || false;
this.updateCheckbox($cell, value, key);
}
else {
tableDelegate.updateTableCellContent(this, $cell, content, contentIndex, col, key);
Expand All @@ -132,9 +133,12 @@ SC.TableRowView = SC.ListItemView.extend({
var content = this.get('content');

// There may be a memory leak in SC with _checkboxRenderSource
if (this._checkboxRenderSource) {
this._checkboxRenderSource.destroy();
this._checkboxRenderSource = this._checkboxRenderDelegate = null;
var sources = this._tr_cbSources;
if (sources) {
this.get('contentCheckboxKey').forEach(function(k) {
sources[k].destroy();
});
this._tr_cbSources = this._checkboxRenderDelegate = null;
}

this.updateContentObservers(null, content);
Expand Down Expand Up @@ -214,27 +218,217 @@ SC.TableRowView = SC.ListItemView.extend({
// CHECKBOX EDTITING
//

updateCheckbox: function (jQuery, state) {
/** @private
Adds a checkbox with the appropriate state to the content. This method
will only be called if the list item view is supposed to have a
checkbox.

@param {SC.RenderContext} context the render context
@param {Boolean} state YES, NO or SC.MIXED_STATE
@returns {void}
*/
renderCheckbox: function (context, state, key) {
var renderer = this.get('theme').checkboxRenderDelegate;

var source = this._checkboxRenderSource;
// note: checkbox-view is really not the best thing to do here; we should do
// sc-list-item-checkbox; however, themes expect something different, unfortunately.
context = context.begin('div')
.addClass('sc-checkbox-view')
.addClass('sc-checkbox-view-for-' + key)
.addClass(this.get('theme').classNames)
.addClass(renderer.get('className'));

var sources = this._tr_cbSources;
if (!sources) {
sources = this._tr_cbSources = {};
}

var source = sources[key];
if (!source) {
source = this._checkboxRenderSource =
SC.Object.create({ renderState: {}, theme: this.get('theme') });
source = sources[key] = SC.Object.create({
renderState: {},
theme: this.get('theme')
});
}

var editableKeys = this.get('editableKeys');
var keyInEditableKeys = editableKeys && editableKeys.indexOf(key) !== -1;

source
.set('controlSize', SC.SMALL_CONTROL_SIZE)
.set('isSelected', state && (state !== SC.MIXED_STATE))
.set('isEnabled', this.get('isEnabled') && this.get('contentIsEditable'))
.set('isEnabled', this.get('isEnabled') && this.get('contentIsEditable') && keyInEditableKeys)
.set('isActive', this._checkboxIsActive)
.set('title', '');

renderer.update(source, jQuery.find('.sc-checkbox-view'));
renderer.render(source, context);
context = context.end();

this._checkboxRenderDelegate = renderer;
},


updateCheckbox: function (jQuery, state, key) {
var renderer = this.get('theme').checkboxRenderDelegate;

var sources = this._tr_cbSources;
var source = sources[key];

var editableKeys = this.get('editableKeys');
var keyInEditableKeys = editableKeys && editableKeys.indexOf(key) !== -1;

source
.set('controlSize', SC.SMALL_CONTROL_SIZE)
.set('isSelected', state && (state !== SC.MIXED_STATE))
.set('isEnabled', this.get('isEnabled') && this.get('contentIsEditable') && keyInEditableKeys)
.set('isActive', this._checkboxIsActive)
.set('title', '');

renderer.update(source, jQuery.find('.sc-checkbox-view-for-' + key));

this._checkboxRenderDelegate = renderer;
},

_isInsideCheckbox: function (evt) {
var del = this.displayDelegate;
var checkboxKey = this.getDelegateProperty('contentCheckboxKey', del);
// should be an array as it is set that way through render and update

return checkboxKey && checkboxKey.find(function (k) {
return this._isInsideElementWithClassName('sc-checkbox-view-for-' + k, evt);
}, this);
},

_addCheckboxActiveState: function (key) {
if (this.get('isEnabled') && this.get('editableKeys') && this.get('editableKeys').contains(key)) {
if (this._checkboxRenderDelegate) {
var sources = this._tr_cbSources;
var source = sources[key];

source.set('isActive', YES);

this._checkboxRenderDelegate.update(source, this.$('.sc-checkbox-view-for-' + key));
} else {
// for backwards-compatibility.
this.$('.sc-checkbox-view-for-' + key).addClass('active');
}
}
},

_removeCheckboxActiveState: function () {
var key = this._isMouseDownOnCheckboxFor;
if (this._checkboxRenderer) {
var sources = this._tr_cbSources;
var source = sources[key];

source.set('isActive', NO);

this._checkboxRenderDelegate.update(source, this.$('.sc-checkbox-view-for-' + key));
} else {
// for backwards-compatibility.
this.$('.sc-checkbox-view-for-' + key).removeClass('active');
}
},


/** @private
mouseDown is handled only for clicks on the checkbox view or or action
button.
*/
mouseDown: function (evt) {
// Fast path, reject secondary clicks.
if (evt.which && evt.which !== 1) return false;

// if content is not editable, then always let collection view handle the
// event.
if (!this.get('contentIsEditable')) return NO;

// if occurred inside checkbox, item view should handle the event.
var inCheckboxForKey = this._isInsideCheckbox(evt);
if (inCheckboxForKey) {
this._addCheckboxActiveState(inCheckboxForKey);
this._isMouseDownOnCheckbox = YES;
this._isMouseInsideCheckbox = YES;
this._isMouseDownOnCheckboxFor = inCheckboxForKey;
return YES; // listItem should handle this event
} else if (this._isInsideDisclosure(evt)) {
this._addDisclosureActiveState();
this._isMouseDownOnDisclosure = YES;
this._isMouseInsideDisclosure = YES;
return YES;
} else if (this._isInsideRightIcon(evt)) {
this._addRightIconActiveState();
this._isMouseDownOnRightIcon = YES;
this._isMouseInsideRightIcon = YES;
return YES;
}
this.displayDidChange();
return NO; // let the collection view handle this event
},

/** @private */
mouseUp: function (evt) {
var ret = NO;

// if mouse was down in checkbox -- then handle mouse up, otherwise
// allow parent view to handle event.
if (this._isMouseDownOnCheckbox) {
// update only if mouse inside on mouse up...
var inCheckboxForKey = this._isInsideCheckbox(evt);
if (inCheckboxForKey && inCheckboxForKey === this._isMouseDownOnCheckboxFor) {
if (this.get('editableKeys') && this.get('editableKeys').contains(inCheckboxForKey)) {
this.toggleCheckbox(inCheckboxForKey);
}
}

this._removeCheckboxActiveState();
ret = YES;

// if mouse as down on disclosure -- handle mouse up. otherwise pass on
// to parent.
} else if (this._isMouseDownOnDisclosure) {
if (this._isInsideDisclosure(evt)) {
this.toggleDisclosure();
}

this._removeDisclosureActiveState();
ret = YES;
// if mouse was down in right icon -- then handle mouse up, otherwise
// allow parent view to handle event.
} else if (this._isMouseDownOnRightIcon) {
this._removeRightIconActiveState();
ret = YES;
}

// clear cached info
this._isMouseInsideCheckbox = this._isMouseDownOnCheckbox = NO;
this._isMouseDownOnDisclosure = this._isMouseInsideDisclosure = NO;
this._isMouseInsideRightIcon = this._isMouseDownOnRightIcon = NO;
// this._isMouseDownOnCheckboxFor = null;

return ret;
},

/** @private */
mouseMoved: function (evt) {
return NO;
},

toggleCheckbox: function (key) {
var content = this.get('content');
//del = this.displayDelegate;

if (content && content.get) {
var value = content.get(key);

value = (value === SC.MIXED_STATE) ? YES : !value;
content.set(key, value); // update content

this.displayDidChange(); // repaint view...
}

}

});


Expand Down