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

Quilmes #8

Open
wants to merge 15 commits into
base: quilmes
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
737ef26
ImageButton renderer does not have a focus method, need to check insi…
ColinCampbell Jul 21, 2010
9fb9f7d
Fixed issue with SC.TabView CSS applying to its container CSS to all …
ColinCampbell Jul 23, 2010
347cdea
Added WellView renderers to the BaseTheme and AceTheme, as well as de…
ColinCampbell Jul 23, 2010
35d89c3
ListItem renderer now uses renderContents/updateContents functions to…
ColinCampbell Jul 24, 2010
e6a6947
SC.ListItemView checks rightIcon property when determining if click o…
ColinCampbell Jul 24, 2010
96edc8f
Fixed SC.FormRowView from blowing out passed label value
ColinCampbell Aug 6, 2010
b5a9612
Initial tests of SC.FixturesDataSource, issues remain with tests (fun…
ColinCampbell Aug 6, 2010
16b970e
Explicitly check falsity of isReady in SC._object_className so search…
ColinCampbell Aug 8, 2010
0336f94
Implemented polymorphic to-one relationships for record attributes th…
ColinCampbell Aug 8, 2010
3c80dc1
ScrollView now detects Safari 5 and changes to delta (was scrolling f…
ColinCampbell Aug 13, 2010
5f5e6b8
Created a renderer for SC.Toolbar
ColinCampbell Aug 19, 2010
10476fa
SC.ScrollerView's thumbs now default to their position -- solves an i…
ColinCampbell Aug 20, 2010
41c6d1a
Fixed issue with SC.ScrollerView not properly updating its element's …
ColinCampbell Aug 20, 2010
3cc5fba
Make SC.View#themed resilient to themed value not being present on re…
ColinCampbell Aug 21, 2010
a9dac18
SC.WellView now uses themed value for contentLayout
ColinCampbell Aug 21, 2010
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
48 changes: 41 additions & 7 deletions frameworks/datastore/data_sources/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ SC.FixturesDataSource = SC.DataSource.extend(

/** @private */
fetch: function(store, query) {
var latency = this.get('latency');

// can only handle local queries out of the box
if (query.get('location') !== SC.Query.LOCAL) {
Expand All @@ -75,7 +76,14 @@ SC.FixturesDataSource = SC.DataSource.extend(
}

if (this.get('simulateRemoteResponse')) {
this.invokeLater(this._fetch, this.get('latency'), store, query);
// during tests, invokeLater is undefined
if (this.invokeLater) {
this.invokeLater(this._fetch, latency, store, query);
} else {
setTimeout(function(that) {
that._fetch(store, query);
}, latency, this);
}

} else this._fetch(store, query);
},
Expand All @@ -84,7 +92,6 @@ SC.FixturesDataSource = SC.DataSource.extend(
Actually performs the fetch.
*/
_fetch: function(store, query) {

// NOTE: Assumes recordType or recordTypes is defined. checked in fetch()
var recordType = query.get('recordType'),
recordTypes = query.get('recordTypes') || [recordType];
Expand Down Expand Up @@ -115,14 +122,20 @@ SC.FixturesDataSource = SC.DataSource.extend(
if (!ret) return ret ;

if (this.get('simulateRemoteResponse')) {
this.invokeLater(this._retrieveRecords, latency, store, storeKeys);
// during tests, invokeLater is undefined
if (this.invokeLater) {
this.invokeLater(this._retrieveRecords, latency, store, storeKeys);
} else {
setTimeout(function(that) {
that._retrieveRecords(store, storeKeys);
}, latency, this);
}
} else this._retrieveRecords(store, storeKeys);

return ret ;
},

_retrieveRecords: function(store, storeKeys) {

storeKeys.forEach(function(storeKey) {
var ret = [],
recordType = SC.Store.recordTypeFor(storeKey),
Expand All @@ -146,7 +159,14 @@ SC.FixturesDataSource = SC.DataSource.extend(
if (!ret) return ret ;

if (this.get('simulateRemoteResponse')) {
this.invokeLater(this._updateRecords, latency, store, storeKeys);
// during tests, invokeLater is undefined
if (this.invokeLater) {
this.invokeLater(this._updateRecords, latency, store, storeKeys);
} else {
setTimeout(function(that) {
that._updateRecords(store, storeKeys);
}, latency, this);
}
} else this._updateRecords(store, storeKeys);

return ret ;
Expand All @@ -172,7 +192,14 @@ SC.FixturesDataSource = SC.DataSource.extend(
var latency = this.get('latency');

if (this.get('simulateRemoteResponse')) {
this.invokeLater(this._createRecords, latency, store, storeKeys);
// during tests, invokeLater is undefined
if (this.invokeLater) {
this.invokeLater(this._createRecords, latency, store, storeKeys);
} else {
setTimeout(function(that) {
that._createRecords(store, storeKeys);
}, latency, this);
}
} else this._createRecords(store, storeKeys);

return YES ;
Expand Down Expand Up @@ -206,7 +233,14 @@ SC.FixturesDataSource = SC.DataSource.extend(
if (!ret) return ret ;

if (this.get('simulateRemoteResponse')) {
this.invokeLater(this._destroyRecords, latency, store, storeKeys);
// during tests, invokeLater is undefined
if (this.invokeLater) {
this.invokeLater(this._destroyRecords, latency, store, storeKeys);
} else {
setTimeout(function(that) {
that._destroyRecords(store, storeKeys);
}, latency, this);
}
} else this._destroyRecords(store, storeKeys);

return ret ;
Expand Down
185 changes: 185 additions & 0 deletions frameworks/datastore/models/polymorphic_single_attribute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// ==========================================================================
// Project: SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
// Portions ©2008-2009 Apple Inc. All rights reserved.
// License: Licensed under MIT license (see license.js)
// ==========================================================================

sc_require('models/single_attribute');

/** @class

PolymorphicSingleAttribute is a subclass of SingleAttribute and handles polymorphic
to-one relationships.

@extends SC.SingleAttribute
@author Colin Campbell
@since SproutCore 1.0
*/
SC.PolymorphicSingleAttribute = SC.SingleAttribute.extend(
/** @scope SC.PolymorphicSingleAttribute.prototype */ {

/**
Contains information on how to transform from and from the passed attribute values.
This property is required so the attribute knows which type to use for the relationship.
If it is not included, it will default to the first provided type.

@property {String}
@default null
*/
typeKey: null,

/**
Provides the ability to map the type names provided by the attribute value into
something usable for record relationships. For example, you may need to store
record names on the server but only with the class name, not the fully qualified
path name (ie. 'Record' vs. 'MyApp.Record'). If the passed records are:

['MyApp.Foo', 'MyApp.Bar']

then your typeMap may be

['Foo', 'Bar']

'Foo' and 'Bar' are what gets saved to the datahash when writing to the server,
and the types are used for the relationship within the application.

@property {Array of Strings}
@default null
*/
typeMap: null,

/**
Returns the type, resolved to a class. If the type property is a regular
class, returns the type unchanged. Otherwise attempts to lookup the
type as a property path.

@property {Object}
*/
typeClass: function() {
var ret = this.get('type'),
l, i, type;
if (SC.isArray(ret)) {
l = ret.get('length');
for (i=0; i<length; i++) {
type = ret.objectAt(i);
if (SC.typeOf(type) === SC.T_STRING) ret.replace(i, 1, SC.objectForPropertyPath(type));
}
} else {
SC.Logger.warn("%@ is a polymorphic relationship without an array of types".fmt(this));
if (SC.typeOf(ret) === SC.T_STRING) ret = SC.objectForPropertyPath(ret);
}
return ret ;
}.property('type').cacheable(),

/** @private
Override the transform function, as we need it to change depending on the record.

@param {Class} typeClass The class of the type
@param {SC.Record} record The record of this attribute
*/
transform: function(klass) {
var transforms = SC.RecordAttribute.transforms,
ret ;

// walk up class hierarchy looking for a transform handler
while(klass && !(ret = transforms[SC.guidFor(klass)])) {
// check if super has create property to detect SC.Object's
if(klass.superclass.hasOwnProperty('create')) klass = klass.superclass;
// otherwise return the function transform handler
else klass = SC.T_FUNCTION;
}

return ret;
},

/**
Converts the passed value into the core attribute value. Uses the polymorphism
information provided to determine the correct type.

@param {SC.Record} record the record instance
@param {String} key the key used to access this attribute on the record
@param {Object} value the property value
@returns {Object} attribute value
*/
toType: function(record, key, value) {
var types = this.get('type'),
typeKey = this.get('typeKey'),
typeMap = this.get('typeMap'),
type, transform, idx;

if (typeKey) {
type = record.get(typeKey);
} else if (SC.isArray(types)) {
// default to the first object if no type is provided
type = types.get('firstObject');
}

if (typeMap) {
idx = typeMap.indexOf(type);
if (idx > -1) {
type = types[idx];
} else {
SC.Logger.warn("Polymorphic map on property %@ for %@ did not exist on %@".fmt(key, type, record.constructor.toString()));
}
}

if (types.indexOf(type) > -1) {
if (SC.typeOf(type) === SC.T_STRING) type = SC.objectForPropertyPath(type);
transform = this.transform(type);
if (transform && transform.to) {
value = transform.to(value, this, type, record, key);
}
} else {
SC.Logger.warn("%@ is not a type on %@ of %@".fmt(type.toString(), key, record.constructor.toString()));
}

return value;
},

/**
Converts the passed value from the core attribute value. Uses the polymorphism
information provided to determine the correct type, and sets the typeKey attribute
on the record.

@param {SC.Record} record the record instance
@param {String} key the key used to access this attribute on the record
@param {Object} value the property value
@returns {Object} attribute value
*/
fromType: function(record, key, value) {
var types = this.get('type'),
type = value.constructor,
typeString = type.toString(),
typeKey = this.get('typeKey'),
typeMap = this.get('typeMap'),
transform, idx;

if (!SC.empty(typeString)) {
if (typeMap) {
idx = types.indexOf(typeString);
if (idx > -1) {
typeString = typeMap[idx];
} else {
SC.Logger.warn("Polymorphic map on property %@ for %@ did not exist on %@".fmt(key, typeString, record.constructor.toString()));
}
}

if (typeKey) {
record.set(typeKey, typeString);
}
} else {
SC.Logger.warn("Could not determine type of %@ for polymorphic relation %@ on %@".fmt(value, key, record));
type = types.get('firstObject');
if (SC.typeOf(type) === SC.T_STRING) type = SC.objectForPropertyPath(type);
}

transform = this.transform(type);

if (transform && transform.from) {
value = transform.from(value, this, type, record, key);
}
return value;
}

});
13 changes: 13 additions & 0 deletions frameworks/datastore/models/record.js
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,19 @@ SC.Record.mixin( /** @scope SC.Record */ {
return attr;
},

/**
Returns a SC.PolymorphicSingleAttribute that converts the underlying ID to
a number of types, dependent on a attribute on the record (the name of this
attribute is provided by the typeKey property).

@param {Array} recordTypes the array of record types the object could be
@param {Hash} opts additional options
@returns {SC.PolymorphicSingleAttribute} created instance
*/
toOneOf: function(recordTypes, opts) {
return SC.PolymorphicSingleAttribute.attr(recordTypes, opts);
},

/**
Returns all storeKeys mapped by Id for this record type. This method is
used mostly by the SC.Store and the Record to coordinate. You will rarely
Expand Down
Loading