import Ember from "ember";
import EmberTimerUtils from "ember-timer-utils";
import getEmberId from "./getEmberId";
import hashHasKeys from "./hashHasKeys";
/**
* A mixin that aliases the value of the attribute given by 'columnData' in 'record' to 'value'.
*
* @class EmberColumnData.ColumnDataValueMixin
* @module ember-column-data
*/
export default Ember.Mixin.create({
init : function() {
this._super();
this.recordDidChange();
this.registerForValChangeChild();
},
/**
* Column data instance to be used to extract value.
*
* @property columnData
* @type Class
*/
columnData : null,
/**
* Record to extract the value from.
*
* @property record
* @type Class
*/
record : null,
listenedColumnChanged : function(changedColumnData, changedValue, oldValue) {
this.listenedColumnChangedHook(changedColumnData, changedValue, oldValue);
if(changedColumnData.get("name") === this.get("columnData.name")) {
var that = this;
//The delay is added cos destroy on the view of removed record is called before it is actually removed from array
//TODO : find a better way to do this check
EmberTimerUtils.addToQue("duplicateCheck-" + getEmberId(this), 100).then(function() {
if(!that.get("isDestroyed")) {
that.validateValue(that.get("val"));
}
});
}
},
/**
* Callback callled when the column listened on changes.
*
* @method listenedColumnChangedHook
* @param {ColumnData} changedColumnData ColumnData instance of the changed column.
* @param {any} changedValue
* @param {any} oldValue
*/
listenedColumnChangedHook : function(/*changedColumnData, changedValue, oldValue*/) {
},
disableValidation : false,
validateValue : function(value) {
var columnData = this.get("columnData"), record = this.get("record"),
validation = columnData.get("validation");
if(validation && !this.get("disableValidation")) {
var validVal = validation.validateValue(value, record);
if(validVal[0]) {
record._validation[columnData.name] = 1;
}
else {
delete record._validation[columnData.name];
}
this.set("invalid", validVal[0]);
this.set("invalidReason", !Ember.isEmpty(validVal[1]) && validVal[1]);
}
else {
delete record._validation[columnData.name];
}
record.set("validationFailed", hashHasKeys(record._validation));
},
/**
* An alias to the value in attribute. It undergoes validations and the change will be bubbled.
*
* @property value
*/
value : Ember.computed("columnData.key", "view.columnData.key", "disableValidation", "view.disableValidation", {
get : function() {
var columnData = this.get("columnData"), record = this.get("record"),
parentForBubbling = this.get("parentForBubbling"), val;
if(!record || !columnData) {
return val;
}
record._validation = record._validation || {};
val = record.get(columnData.get("key"));
this.validateValue(val);
if(parentForBubbling && parentForBubbling.bubbleValChange) {
parentForBubbling.bubbleValChange(columnData, val, null, this);
}
return val;
},
set : function(key, val) {
var columnData = this.get("columnData"), record = this.get("record"),
parentForBubbling = this.get("parentForBubbling");
if(!record || !columnData) {
return val;
}
record._validation = record._validation || {};
if(!record.currentState || (record.currentState && !record.currentState.stateName.match("deleted"))) {
var oldVal = record.get(columnData.get("key"));
this.validateValue(val);
//TODO : find a better way to fix value becoming null when selection changes
//if(val || !columnData.get("cantBeNull")) {
record.set(columnData.get("key"), val);
this.valueChangeHook(val);
if(parentForBubbling && parentForBubbling.bubbleValChange) {
parentForBubbling.bubbleValChange(columnData, val, oldVal, this);
}
//}
}
return val;
},
}),
/**
* Callback called when the value changes.
*
* @method valueChangeHook
* @param {any} val
*/
valueChangeHook : function(/*val*/) {
},
prevRecord : null,
recordDidChange : Ember.observer("record", "view.record", function() {
var record = this.get("record"), prevRecord = this.get("prevRecord"),
columnData = this.get("columnData");
if(prevRecord) {
Ember.removeObserver(prevRecord, columnData.get("key"), this, "notifyValChange");
}
if(record) {
this.recordChangeHook();
Ember.addObserver(record, columnData.get("key"), this, "notifyValChange");
this.set("prevRecord", record);
}
else if(prevRecord) {
this.recordRemovedHook();
}
this.notifyPropertyChange("value");
}),
/**
* Callback called when record changes.
*
* @method recordChangeHook
*/
recordChangeHook : function() {
},
/**
* Callback called when record is removed (set to null).
*
* @method recordRemovedHook
*/
recordRemovedHook : function(){
},
notifyValChange : function(/*obj, key*/) {
this.notifyPropertyChange("value");
this.valueChangeHook(this.get("value"));
},
registerForValChangeChild : Ember.observer("columnData", "view.columnData", function() {
var columnData = this.get("columnData"), parentForBubbling = this.get("parentForBubbling");
if(columnData && columnData.get("columnListenerEntries")) {
columnData.get("columnListenerEntries").forEach(function(listenCol) {
if(parentForBubbling && parentForBubbling.registerForValChange) {
parentForBubbling.registerForValChange(this, listenCol);
}
}, this);
}
}),
unregisterForValChangeChild : function() {
var columnData = this.get("columnData"), parentForBubbling = this.get("parentForBubbling");
if(columnData.get("columnListenerEntries")) {
columnData.get("columnListenerEntries").forEach(function(listenCol) {
if(parentForBubbling && parentForBubbling.unregisterForValChange) {
parentForBubbling.unregisterForValChange(this, listenCol);
}
}, this);
}
},
/**
* Parent object with mixin EmberColumnData.ColumnDataChangeCollectorMixin to bubble to.
*
* @property parentForBubbling
* @type Instance
*/
parentForBubbling : null,
destroy : function() {
this._super();
this.unregisterForValChangeChild();
},
});