[Cosmo-dev] CosmoUI Data Model Proposal

Matthew Eernisse mde at osafoundation.org
Wed Mar 28 10:36:29 PST 2007


Responses/questions below.

Bobby Rullo wrote:
> yes, namespace is down in metadata. But, no not a new stamp, you just 
> handed it an instance, why create a new one?

Ah, for some reason I didn't get that you were passing it an instance. 
It all makes sense now.

>> It looks like the only stuff that's actually hardcoded is the name of 
>> the pseudo-class (e.g., 'EventStamp'), and all the attributes in 
>> StampAttribute. Is the idea to have some code that runs on init that 
>> creates the constructor functions for all the various stamp types 
>> programmatically?
>>
> Not sure what you mean. When you create a new item, it's "stamps" 
> attribute is just an empty hash.
> 
> Adding a new stamp is just putting a new stamp in the hash, keyed on the 
> namespace.
> 

I'm talking about doing some metaprogramming fu to generate the 
constructor functions for the specific stamps (e.g., the sub-class 
definition for, say, EventStamp) from the list of StampAttributes in 
stampMetaData.

So if you add an attribute to the list of StampAttributes, you don't 
also have to add it mechanically to the constructor function -- the 
constructor func is generated from the list of attributes. In other 
words, this function:

some.long.namespace.EventStamp = function (foo, bar, baz) {
   this.foo = foo || fooDefault;
   this.bar = bar || barDefault;
   this.baz = baz || bazDefault;
}

Would be dynamically generated from the attribute list.

I wanted to make sure this would all work, so I wrote a quickie example:

function BaseStamp(metaData) {
   this.stampMetaData = metaData;
}

// Hash of stamp metadata keyed by stamp type
var stamps = {
   'Event': [
     // Array of event attributes
     {foo: 'fooEvent'},
     {bar: 'barEvent'},
     {baz: function () { alert('bazEvent'); }}
   ],
   'Task': [
     // Array of task attributes
     {foo: 'fooTask'},
     {bar: 'barTask'},
     {baz: function () { alert('bazTask'); }}
   ]
}
// Create constructor functions for each type of stamp
for (var prop in stamps) {
   // Create a blank function for the constructor
   window[prop + 'Stamp'] = function () {};
   var constr = window[prop + 'Stamp'];

   // The constructor is a subclass of the BaseStamp
   constr.prototype = new BaseStamp(stamps[prop]);

   var proto = constr.prototype;
   // Give the constructor all the attributes
   // from the metadata
   for (var i = 0; i < proto.stampMetaData.length; i++) {
     for (var j in proto.stampMetaData[i]) {
       proto[j] = proto.stampMetaData[i][j];
     }
   }
}
var ev = new EventStamp();
var ta = new TaskStamp();

Hope that makes sense. It's just a way of avoiding manual work in 
keeping the constructor and its metadata in synch.

It also occurred to me that the StampAttribute object might also have 
defaultValue property (e.g., empty array).

>>
>> If there's no central list of items, where do you put the things you 
>> load from the server? Or rather, if there are multiple views all 
>> consuming the same data, where does that data live?
> 
> Each widget is responsible for maintaining its own state. If it changes 
> the state of an item and persists it, topics are published and consumed 
> by other widgets and they update themselves accordingly.
> 

Ah, I had originally been thinking that the two different views (cal, 
dashboard) could potentially be based on the same set of data, and that 
we wouldn't have to go back to the server when toggling from cal to 
dashboard. But I can now see that that is not the case, since dashboard 
isn't time-bound the same way the cal view is.

This is getting more into implementation, but -- does it make more sense 
simply to do a fresh data pull from the server if changes have been made 
in the other view, or to try to build in all the logic on the client to 
reconcile what happened?

Off the top of my head, an example:

1. User is in calendar view.
2. User switches to dashboard view
3. User goes back to calendar view and edits a weekly recurring event 
such that it now ends in the previous week.
4. User goes back to dashboard view.

We're already going back to the server for recurrence expansions in the 
calendar view, but the request is time-bound, and might not get all the 
instances back that the dashboard needs. Seems like we have a couple of 
options:

1. Just pull all the data down again (could be a big query).
2. Keep track of what's changed. Handle changes to individual items all 
on the client-side. Do recurrence re-expansion on the server for changed 
recurring event-items all at once when the view changes.
3. Keep track of what's changed. Handle changes to individual items all 
on the client-side. Change our recurrence expansion somehow to provide 
both views what they need, and do the re-expansion with each change as 
we do now.

Hmm, methinks this is going to require some phone time ... :)


Matthew






More information about the cosmo-dev mailing list