fluid-work IRC Logs-2008-11-26
[07:51:25 EST(-0500)] * phiggins_ (n=dante@c-68-34-199-67.hsd1.tn.comcast.net) has joined #fluid-work
[09:03:44 EST(-0500)] * Justin_o (n=Justin@142.150.154.101) has joined #fluid-work
[09:42:18 EST(-0500)] * clown (n=clown@guiseppi.atrc.utoronto.ca) has joined #fluid-work
[09:51:14 EST(-0500)] * EricDalquist (n=dalquist@bohemia.doit.wisc.edu) has joined #fluid-work
[10:07:46 EST(-0500)] * anastasiac (n=team@142.150.154.160) has joined #fluid-work
[11:21:06 EST(-0500)] * michelled (n=team@142.150.154.197) has joined #fluid-work
[11:30:51 EST(-0500)] * athena7 (n=athena7@adsl-99-162-190-42.dsl.wlfrct.sbcglobal.net) has joined #fluid-work
[11:35:36 EST(-0500)] <Justin_o> http://kb.mozillazine.org/Security.fileuri.strict_origin_policy
[11:35:53 EST(-0500)] <Justin_o> that is the link about the ff3 security for local files
[11:42:43 EST(-0500)] * ecochran (n=ecochran@dhcp-169-229-212-44.LIPS.Berkeley.EDU) has joined #fluid-work
[11:53:48 EST(-0500)] <michelled> thanks justin
[13:12:43 EST(-0500)] * colinclark (n=colin@bas1-toronto09-1279621226.dsl.bell.ca) has joined #fluid-work
[13:16:33 EST(-0500)] <athena7> by the way, i was wondering if there'd been any discussion of the issues I asked about last weekly - namely whether it would be possible to add columns to the reorderer after it has been created
[13:17:37 EST(-0500)] <colinclark> athena7: I think it should be possible with the current implementation.
[13:17:45 EST(-0500)] <athena7> oh really?
[13:17:52 EST(-0500)] <colinclark> Just be sure to call refresh() on your Reorderer instance after you've changed the DOM.
[13:17:52 EST(-0500)] <athena7> that would be fantastic
[13:18:02 EST(-0500)] <athena7> oh! is that all i need to do?
[13:18:04 EST(-0500)] <colinclark> I have never tried it. I can check if there's a unit test that covers it.
[13:18:09 EST(-0500)] <athena7> that'd be wonderful
[13:18:10 EST(-0500)] <colinclark> athena7: In theory, anyway.
[13:18:37 EST(-0500)] <athena7> basically when we add columns in the uportal layout it'd be great to make the reorderer aware of them so they're available as drop targets without a page refresh
[13:18:58 EST(-0500)] <colinclark> Makes sense.
[13:19:15 EST(-0500)] <colinclark> Let me take a peek at the code.
[13:20:55 EST(-0500)] <colinclark> Here's the implementation of refresh():
[13:20:55 EST(-0500)] <colinclark> http://fluid.pastebin.com/m3cfadb30
[13:21:13 EST(-0500)] <colinclark> It does refresh the set of dropTargets, so you should be good to go.
[13:21:18 EST(-0500)] <colinclark> Try it and let me know how it works.
[13:22:27 EST(-0500)] <colinclark> (Basically, in that code, you can calls to our Framework's DOM binder feature to refresh the cache.)
[13:23:42 EST(-0500)] <athena7> wonderful!
[13:23:44 EST(-0500)] <athena7> thanks so much colin
[13:23:49 EST(-0500)] <athena7> i'll try that out in the uportal trunk
[13:24:08 EST(-0500)] <athena7> by the way, i upgraded the uportal trunk to the new fluid beta release
[13:24:12 EST(-0500)] <athena7> seems to be working well so far
[13:24:31 EST(-0500)] <colinclark> athena7: Awesome. That's good to know.
[13:24:53 EST(-0500)] <colinclark> Gary and I were talking at the summit about getting a few more accessibility tweaks into uPortal trunk soon, too.
[13:25:08 EST(-0500)] <colinclark> Just markup and styling tweaks to do better in terms of a11y checkers.
[13:31:44 EST(-0500)] <athena7> that'd be wonderful
[13:31:50 EST(-0500)] <athena7> sounds great to me
[13:35:56 EST(-0500)] <colinclark> anastasiac: Are you back now?
[13:46:24 EST(-0500)] <anastasiac> colinclark - I'm here now
[13:54:45 EST(-0500)] <colinclark> anastasiac: Sorry.
[13:54:56 EST(-0500)] <colinclark> One side-effect of my Pager refactoring:
[13:55:29 EST(-0500)] <colinclark> There was a callback function called pageWillChange.
[13:55:42 EST(-0500)] <colinclark> It has now been refactored into an event called onPageChange.
[13:55:52 EST(-0500)] <colinclark> So that will affect the documentation.
[13:56:19 EST(-0500)] <colinclark> The core API should still be the same: methods for selectPage(), next() and previous().
[13:56:32 EST(-0500)] <anastasiac> ok, cool, thanks colinclark
[13:56:35 EST(-0500)] <colinclark> The PagerBar view is now a subcomponent.
[13:56:41 EST(-0500)] <anastasiac> I was going to be updating the docs anyway
[13:56:44 EST(-0500)] <colinclark> So theoretically a user could override this implementation with their own.
[13:56:50 EST(-0500)] <anastasiac> I'll make sure these changes are in there
[13:56:59 EST(-0500)] <colinclark> Cool.
[14:20:30 EST(-0500)] * ecochran (n=ecochran@dhcp-169-229-212-44.LIPS.Berkeley.EDU) has left #fluid-work
[14:23:25 EST(-0500)] * hydee (n=hydee@bas10-ottawa23-1128688562.dsl.bell.ca) has joined #fluid-work
[14:24:30 EST(-0500)] <colinclark> hydee: Hey!
[14:24:32 EST(-0500)] <colinclark> You made it.
[14:24:46 EST(-0500)] <hydee> hey hey!
[14:24:51 EST(-0500)] <colinclark> Hey Justin_o, have you chatted with clown about your work on the automated testing last week at the summit?
[14:24:54 EST(-0500)] <hydee> so this is where the party's at
[14:24:57 EST(-0500)] <colinclark> And do you need any help with getting it ready for commit?
[14:25:05 EST(-0500)] <colinclark> hydee: It's a quiet party today.
[14:26:27 EST(-0500)] <hydee> to those that are here: is there a way to monitor if a textarea's value has changed? ie. a change event, in jquery or otherwise?
[14:26:32 EST(-0500)] <clown> colinclark: Justin_o and I chatted a lot about how to reinitialize data for a set of tests on the reorderer. i suggested an 'algorithm'.
[14:26:42 EST(-0500)] <colinclark> Cool.
[14:26:45 EST(-0500)] <clown> phone call...
[14:26:57 EST(-0500)] <colinclark> I had written some code to do this awhile back, prior to our switch to jqUnit.
[14:27:02 EST(-0500)] <colinclark> Maybe it will be helpful.
[14:27:21 EST(-0500)] <colinclark> jacobfarber: We were talking about hydee's issue the other week, weren't we?
[14:27:37 EST(-0500)] <jacobfarber> um, remind me?
[14:27:46 EST(-0500)] <Justin_o> colinclark: I am just trying something out right now... i'll let you know if it works
[14:27:49 EST(-0500)] <jacobfarber> hydee wanted something we couldnt solve
[14:28:03 EST(-0500)] <colinclark> jacobfarber: Change events in a text area.
[14:28:19 EST(-0500)] <colinclark> Certainly listening for blur is an easy solution, but it assumes the user will leave the field before you need to process it.
[14:28:27 EST(-0500)] <colinclark> Any other thoughts?
[14:28:34 EST(-0500)] <hydee> hmm... thinking if that would work..
[14:28:54 EST(-0500)] <jacobfarber> on key press?
[14:29:06 EST(-0500)] <colinclark> keypress with a timer would work
[14:29:12 EST(-0500)] <jacobfarber> yes, with a delay
[14:29:16 EST(-0500)] <hydee> aha...
[14:29:23 EST(-0500)] <jacobfarber> to avoid overprocessing
[14:29:36 EST(-0500)] <jacobfarber> i did some tests on acceptable delays with this a while ago
[14:30:21 EST(-0500)] <hydee> was there a magic number that worked well?
[14:30:28 EST(-0500)] <jacobfarber> after a pause of ~ 200 - 250 ms
[14:30:42 EST(-0500)] <jacobfarber> it was "safe" to assume the user was "thinking"
[14:30:47 EST(-0500)] <hydee> okay i'll play with that. thanks dudes
[14:30:51 EST(-0500)] <jacobfarber> or getting ready for their next action
[14:31:59 EST(-0500)] <hydee> keypress doesn't seem to be working with a textarea either
[14:32:08 EST(-0500)] <jacobfarber> on change?
[14:32:15 EST(-0500)] <hydee> nope that was my first try
[14:32:35 EST(-0500)] <jacobfarber> hmm
[14:32:47 EST(-0500)] <hydee> $("caption-text").keypress(function () {
[14:32:47 EST(-0500)] <hydee> alert('yo');
[14:32:47 EST(-0500)] <hydee> });
[14:32:58 EST(-0500)] <hydee> ahhh.
[14:33:01 EST(-0500)] <hydee> TYPO
[14:33:02 EST(-0500)] <jacobfarber> all these should work
[14:33:03 EST(-0500)] <jacobfarber> onfocus, onblur, onselect, onchange, onclick, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout, onkeypress, onkeydown, onkeyup
[14:33:10 EST(-0500)] <jacobfarber> oh
[14:33:11 EST(-0500)] <jacobfarber>
[14:33:17 EST(-0500)] <hydee> forgot the all important #
[14:34:08 EST(-0500)] <hydee> however.
[14:34:10 EST(-0500)] <hydee> still no luck
[14:34:43 EST(-0500)] <clown> colinclark, jacobfarber, hydee, warning: onchange event doesn't happen for textarea unitl focus leaves the area (and only if the contents changed), according to W3C. FF3 sends them out as you type. Not sure what IE8 does. [http://www.w3.org/TR/html401/interact/scripts.html#adef-onchange]
[14:35:03 EST(-0500)] <colinclark> clown: Yep, that's what we're trying to avoid.
[14:35:04 EST(-0500)] <jacobfarber> have you tried onkeyup?
[14:35:21 EST(-0500)] <hydee> let's se..
[14:35:43 EST(-0500)] <clown> colinclark: okay
[14:35:58 EST(-0500)] <colinclark> clown: If only it did actually work!
[14:36:18 EST(-0500)] <hydee> sorry, am a jquery newbie still.
[14:36:27 EST(-0500)] <hydee> .change does work, but only when you leave focus
[14:36:41 EST(-0500)] <clown> i just said that ()
[14:36:47 EST(-0500)] <jacobfarber> does .keyup() work?
[14:36:49 EST(-0500)] <hydee> right
[14:37:00 EST(-0500)] <hydee> and keypress does work
[14:37:05 EST(-0500)] <jacobfarber> ah
[14:37:12 EST(-0500)] <hydee> thank you all
[14:37:14 EST(-0500)] <jacobfarber>
[14:37:22 EST(-0500)] <hydee> ill set a delay so it's not going crazy
[14:37:25 EST(-0500)] <hydee> cheers
[14:37:26 EST(-0500)] <jacobfarber> now to set your reasonable delay
[14:37:49 EST(-0500)] <hydee> and will this work on IE?
[14:37:53 EST(-0500)] <jacobfarber> it should
[14:37:59 EST(-0500)] <jacobfarber> its a basic event
[14:38:59 EST(-0500)] <hydee> k
[14:52:13 EST(-0500)] <jacobfarber> Its not that easy to type faster than 200 ms between keystrokes!
[14:57:46 EST(-0500)] * phiggins (n=dante@c-68-34-199-67.hsd1.tn.comcast.net) has joined #fluid-work
[15:13:02 EST(-0500)] <colinclark> Justin_o: Can you add the issue with your automated test patches into the dev-iteration47 filter?
[15:55:34 EST(-0500)] <anastasiac> colinclark, am I remembering correctly that the Collection Space meeting will be in January, and not in Toronto?
[15:58:06 EST(-0500)] <colinclark> anastasiac: Second week in January in New York is the plan.
[15:58:21 EST(-0500)] <colinclark> I'd pencil it off in your calendar, just in case.
[15:58:32 EST(-0500)] <colinclark> let me get you the details
[15:58:39 EST(-0500)] <colinclark> http://wiki.collectionspace.org/display/collectionspace/All-Team+Meeting%2C+January+2009
[15:59:05 EST(-0500)] <anastasiac> cool, thanks
[16:45:37 EST(-0500)] <colinclark> michelled: I have an idea I wanted to bounce off you.
[16:45:39 EST(-0500)] <colinclark> Do you have a sec?
[16:45:42 EST(-0500)] <michelled> yup
[16:46:06 EST(-0500)] <colinclark> Okay... So we've got Uploader, which has a subcomponent view called FileQueueView.
[16:46:51 EST(-0500)] <colinclark> It has a function, called upon initialization, that binds a bunch of model events.
[16:46:56 EST(-0500)] <colinclark> Here's the current implementation.
[16:47:20 EST(-0500)] * colinclark is copy pasting code into the paste bin.
[16:48:00 EST(-0500)] <colinclark> http://fluid.pastebin.com/m21f7375a
[16:48:05 EST(-0500)] <colinclark> Notice how "gluey" it looks.
[16:48:11 EST(-0500)] * EricDalquist (n=dalquist@bohemia.doit.wisc.edu) has joined #fluid-work
[16:48:17 EST(-0500)] <michelled> yes
[16:48:18 EST(-0500)] <colinclark> It's really just binding listeners to events.
[16:48:44 EST(-0500)] <colinclark> Well, there is a bit of lifecycle in the framework for options that I didn't talk about in my presentation.
[16:49:00 EST(-0500)] <colinclark> But it is nifty. I had been suspicious of it initially, but it makes a lot of sense.
[16:49:10 EST(-0500)] <colinclark> A child component can push options back upstream to their parent.
[16:49:34 EST(-0500)] <colinclark> Reorderer does a few things this way, but one ideal use case is to allow subcomponents to declaratively register listeners.
[16:49:42 EST(-0500)] <michelled> yes, I vaguely remember a conversation about this when Bosmon was in town
[16:50:01 EST(-0500)] <colinclark> Pager does this, for example:
[16:50:22 EST(-0500)] <colinclark> http://fluid.pastebin.com/m15dca566
[16:50:55 EST(-0500)] <colinclark> It's a simple convention where the framework looks for a member called "returnedOptions" on the child component.
[16:51:06 EST(-0500)] <colinclark> I wonder if a different name wouldn't be more appropriate, but most of my ideas are nerdy...
[16:51:09 EST(-0500)] <colinclark> "upstreamOptions"
[16:51:10 EST(-0500)] <colinclark>
[16:51:17 EST(-0500)] <colinclark> Anyway, name is secondary. You can see what it's doing here, right?
[16:51:24 EST(-0500)] <michelled> yes
[16:51:36 EST(-0500)] <colinclark> So I thought, well, this will be much better for fileQueueView, too.
[16:51:46 EST(-0500)] <colinclark> And it made me think about scoping and public API for views...
[16:51:56 EST(-0500)] <colinclark> I mean, what do you want to do with a file queue view?
[16:52:03 EST(-0500)] <colinclark> Add files to the queue, remove them...
[16:52:16 EST(-0500)] <colinclark> And then adjust the display of them periodically.
[16:52:26 EST(-0500)] <colinclark> Does that make sense?
[16:52:30 EST(-0500)] <michelled> yes
[16:53:07 EST(-0500)] <colinclark> So I've come to think that the public API should be programmatic ways to trigger these various interesting moments.
[16:53:30 EST(-0500)] <colinclark> Put another way, the event listeners are the sorts of things you'd like public methods for.
[16:53:44 EST(-0500)] <colinclark> Since our event system doesn't bring in DOM-related baggage, this can be done easily and cleanly.
[16:54:18 EST(-0500)] <colinclark> So here's what bindEvents() in fileQueueView looks like now:
[16:54:20 EST(-0500)] <colinclark> http://fluid.pastebin.com/m5deecb4a
[16:54:29 EST(-0500)] <colinclark> Does this seem generally reasonable to you?
[16:55:14 EST(-0500)] <michelled> it's certainly a lot simpler
[16:55:25 EST(-0500)] <colinclark> I will probably tweak the method names a little bit to be more clear.
[16:55:26 EST(-0500)] <michelled> so, who does the actual binding now? the framework?
[16:55:42 EST(-0500)] <michelled> I guess the event system does
[16:55:45 EST(-0500)] <colinclark> that.startFileProgress = that.showProgressBarForFile or something along those lines, for example.
[16:55:53 EST(-0500)] <colinclark> initSubcomponents does the actual binding.
[16:55:57 EST(-0500)] <colinclark> I'll show you the code...
[16:56:49 EST(-0500)] <colinclark> http://fluid.pastebin.com/m4c3c2109
[16:56:53 EST(-0500)] <colinclark> This is very dense code...
[16:56:56 EST(-0500)] <colinclark> but if you look at the bottom...
[16:57:07 EST(-0500)] <colinclark> "togo" is the subcomponent that has just been initialized.
[16:57:23 EST(-0500)] <colinclark> It checks if there is a returnedOptions member on it, and if so, merges it back with the parent's options.
[16:57:35 EST(-0500)] <colinclark> It's a lifecycle for component initialization...
[16:58:00 EST(-0500)] <colinclark> The first point in the life cycle of creating a subcomponent is to look up its implementation and instantiate it...
[16:58:07 EST(-0500)] <colinclark> that's the mini IoC in our framework.
[16:58:33 EST(-0500)] <colinclark> Step 2 is feed options to the child from the parent.
[16:58:53 EST(-0500)] <colinclark> Step 3 in the lifecycle is to give the child a chance to feed options back up to the parent from the child.
[16:59:12 EST(-0500)] <colinclark> Make sense?
[16:59:31 EST(-0500)] <michelled> yes
[16:59:44 EST(-0500)] <michelled> this is a clever use of the framework
[16:59:56 EST(-0500)] <colinclark> I guess the exact lifecycle is really this:
[17:00:06 EST(-0500)] <michelled> I think it does need some explanation so it becomes a commonly used pattern.
[17:00:11 EST(-0500)] <colinclark> 1. Find the name of the creator function for the subcomponent implementation.
[17:00:21 EST(-0500)] <colinclark> 2. Look up the defaults for that subcomponent.
[17:00:32 EST(-0500)] <colinclark> 3. Grab any options from the parent component destined for the child.
[17:00:50 EST(-0500)] <colinclark> 4. Instantiate the subcomponent using these merged options.
[17:01:02 EST(-0500)] <colinclark> 5. Pass options back upstream to the parent component.
[17:01:06 EST(-0500)] <colinclark> But anyway, you get the idea.
[17:02:06 EST(-0500)] <michelled> yes
[17:02:13 EST(-0500)] <colinclark> michelled: Explanation in terms of what these "returnedOptions" are and how they get used?
[17:02:44 EST(-0500)] <michelled> perhaps a little higher level. How to expose the subcomponent's API in the parent using events
[17:03:37 EST(-0500)] <michelled> make sense?
[17:04:57 EST(-0500)] <colinclark> michelled: I'm not sure. Elaborate
[17:05:06 EST(-0500)] <colinclark> I dunno if anastasiac is watching and has any thoughts.
[17:05:17 EST(-0500)] <anastasiac> I'm trying to catch up
[17:05:18 EST(-0500)] <colinclark> I'd love to see "returnedOptions" get renamed, which is an easy change at some point.
[17:06:33 EST(-0500)] <colinclark> anastasiac: Sorry to distract you. Just wanted a quick reality check.
[17:06:48 EST(-0500)] <colinclark> It seems to make sense to me... if your View does something interesting, there should be a public API for it.
[17:07:01 EST(-0500)] <anastasiac> np, it's a good distraction
[17:07:07 EST(-0500)] <colinclark> If so, use it to bind event listeners, since your public method should naturally match the semantics of the event.
[17:07:17 EST(-0500)] <colinclark> Since these are, after all model-oriented events.
[17:09:00 EST(-0500)] <anastasiac> ok, I need some clarification
[17:09:08 EST(-0500)] <anastasiac> maybe it's just because it's 5pm...
[17:09:26 EST(-0500)] <michelled> colinclark: does the user of the component have access to the behaviour of the subcomponent through the events that were passed up stream?
[17:10:03 EST(-0500)] <anastasiac> your original filequeueview code bound listeners to events on its own that
[17:10:16 EST(-0500)] <colinclark> anastasiac: Yep.
[17:10:27 EST(-0500)] <colinclark> The events are passed as an argument to the fileQueueView.
[17:10:31 EST(-0500)] <anastasiac> but by passing the list of events and listeners back up to uploader, they get bound to uploaders events
[17:10:37 EST(-0500)] <anastasiac> ?
[17:10:38 EST(-0500)] <colinclark> anastasiac: Yep.
[17:10:43 EST(-0500)] <anastasiac> hm
[17:10:54 EST(-0500)] <colinclark> The parent component generally will own the events in terms of defining them in a user-visible place.
[17:11:05 EST(-0500)] <anastasiac> but the subcomponent fires them?
[17:11:32 EST(-0500)] <colinclark> anastasiac: Interestingly, no.
[17:11:34 EST(-0500)] <michelled> actually those look like the component's events, right?
[17:11:47 EST(-0500)] <colinclark> michelled: Exactly, yes.
[17:11:47 EST(-0500)] <anastasiac> ok, that's what I was trying to figure out
[17:11:49 EST(-0500)] <anastasiac> ok, I think I see
[17:11:56 EST(-0500)] <colinclark> This particular subcomponent doesn't fire events at all.
[17:12:00 EST(-0500)] <colinclark> It just happily listens for them.
[17:12:02 EST(-0500)] <anastasiac> the subcomponent wants to bind listeners to the component's events
[17:12:15 EST(-0500)] <anastasiac> instead of binding them itself, it passes them back to the component to bind
[17:12:18 EST(-0500)] <colinclark> Which means, in this approach, the subcomponent doesn't even need a reference to the parent's events structure.
[17:12:26 EST(-0500)] <colinclark> anastasiac: Exactly, yes.
[17:12:28 EST(-0500)] <colinclark> You got it.
[17:12:32 EST(-0500)] <colinclark> You've
[17:13:29 EST(-0500)] <anastasiac> so you're thinking of this as a general model for how subcomponents would attach listeners to component events?
[17:13:38 EST(-0500)] <colinclark> anastasiac: The key point here is that the subcomponent uses the same mechanism as the user does for configuring listeners...
[17:13:42 EST(-0500)] <colinclark> the declarative options structure.
[17:13:48 EST(-0500)] <colinclark> anastasiac: Yes.
[17:13:52 EST(-0500)] <colinclark> The model being:
[17:14:07 EST(-0500)] <colinclark> 1. Views provide useful public methods for doing interesting things with them.
[17:14:28 EST(-0500)] <colinclark> 2. Subcomponents register events by passing listeners upstream to their parent.
[17:14:35 EST(-0500)] <colinclark> All this is mediated by the framework.
[17:15:13 EST(-0500)] <colinclark> The only consequence, as I see it, is that it means a view assumes it will always be used as a subcomponent.
[17:15:25 EST(-0500)] <colinclark> Arguably, something like a progress bar might actually be treated as a component unto itself.
[17:15:52 EST(-0500)] <michelled> yes, and the subcomponent knows a lot about the component it assumes it's part of
[17:15:56 EST(-0500)] <anastasiac> ok, you've lost me at "a view assumes it will be used as a subcomponent"
[17:15:59 EST(-0500)] <colinclark> I think we could probably refine this slightly so that this assumption wouldn't be necessary.
[17:16:07 EST(-0500)] <colinclark> michelled: Well, it doesn't.
[17:16:15 EST(-0500)] <colinclark> It just knows that it needs to listen to some important events.
[17:16:20 EST(-0500)] <colinclark> All it knows is the name of those events.
[17:16:22 EST(-0500)] <michelled> yes, it knows the events
[17:16:30 EST(-0500)] <anastasiac> I'm thinking of inline edit, whose view is quite simple and built-in
[17:16:53 EST(-0500)] <colinclark> Right, but events are the fundamental contract between a component and its friends, right?
[17:17:44 EST(-0500)] <colinclark> anastasiac: This assumption about being a subcomponent is problematic for things that are top-level components, but who might want to register listeners for their own events. Which is a fairly odd case. But it does come up.
[17:18:02 EST(-0500)] <colinclark> For example, the Uploader Manager in the SWF case is generally the source of most event firings.
[17:18:13 EST(-0500)] <colinclark> So the Upload component adds listeners to its own events.
[17:18:36 EST(-0500)] <anastasiac> but this assumption requires that any top-level component must use sub-components for any views
[17:19:05 EST(-0500)] <Justin_o> colinclark: sorry just catching up on some irc talk, i was talking to the clown about some of those issues and may have a solution to it. I'll see if it works. If it doesn't I'll create a jira and add it to the dev iteration
[17:19:16 EST(-0500)] <colinclark> anastasiac: That's generally true, though.
[17:19:52 EST(-0500)] <anastasiac> oh?
[17:20:28 EST(-0500)] <colinclark> Well, in general if you have a view that does some work for a top-level component, it should be initialized as a subcomponent.
[17:20:39 EST(-0500)] <colinclark> Meaning it can be easily configured or replace by an alternative implementation.
[17:20:40 EST(-0500)] <michelled> unless the views are super simple and are just part of the component
[17:20:46 EST(-0500)] <colinclark> michelled: True
[17:21:02 EST(-0500)] <colinclark> In which case all this subcomponent stuff won't matter to you in the first place.
[17:21:07 EST(-0500)] <michelled> yes
[17:21:09 EST(-0500)] <michelled>
[17:21:27 EST(-0500)] <colinclark> So is this all seeming generally sensible and comprehensible?
[17:21:36 EST(-0500)] <anastasiac> well, inline edit is a case of super-simple, but it uses subcomponents for undo
[17:21:52 EST(-0500)] <colinclark> anastasiac: Indeed. And undo uses the subcomponent life cycle.
[17:21:56 EST(-0500)] <anastasiac> generally sensible and comprehensible and reasonable, yes
[17:22:10 EST(-0500)] <colinclark> It actually uses returnedOptions to listen invisibly to events on the thing it is decorating.
[17:22:14 EST(-0500)] <anastasiac> would we refactor existing components to use this model, like the Reorderer family?
[17:22:23 EST(-0500)] <colinclark> anastasiac: Reorderer already does.
[17:22:26 EST(-0500)] <colinclark> As does Undo.
[17:22:27 EST(-0500)] <colinclark> As does Pager.
[17:22:34 EST(-0500)] <colinclark> Uploader is really the only one behind the curve here.
[17:22:41 EST(-0500)] <anastasiac> what subcomponent does reorderer use for its view?
[17:22:48 EST(-0500)] <colinclark> anastasiac: Well...
[17:22:57 EST(-0500)] <colinclark> Reorderer doesn't have any views, per se.
[17:23:02 EST(-0500)] <colinclark> But it does have subcomponents.
[17:23:09 EST(-0500)] <colinclark> Keep in mind that really anything can be a subcomponent...
[17:23:17 EST(-0500)] <colinclark> the key thing is that it wants to participate in this life cycle.
[17:23:37 EST(-0500)] <anastasiac> ok, if we go with this model, we may need to rethink some function names?
[17:23:43 EST(-0500)] <colinclark> So Reorderer has layout handlers, whose responsibility is essentially to configure the top-level component correctly based on different scenarios.
[17:23:50 EST(-0500)] <anastasiac> all the components say "that = fluid.initView()"
[17:24:00 EST(-0500)] <colinclark> anastasiac: Can you think of some examples?
[17:24:01 EST(-0500)] <anastasiac> but if they don't have a view, it shouldn't be called view?
[17:24:21 EST(-0500)] <colinclark> Things should only be instantiated with initView() if they are Views.
[17:24:34 EST(-0500)] * clown (n=clown@guiseppi.atrc.utoronto.ca) has left #fluid-work
[17:24:35 EST(-0500)] <anastasiac> reorderer uses initView
[17:24:40 EST(-0500)] <colinclark> initSubcomponents just doesn't care less whether or not something is a View.
[17:24:49 EST(-0500)] <colinclark> Yes, because Reorderer is a View. Just like every other component.
[17:25:07 EST(-0500)] <michelled> colinclark: I'm trying to envision a reuse case for a subcomponent. I'm not sure it even makes sense but let's pretend for a moment that it does. The other component that would be reusing the subcomponent would either need to use the same events or the subcomponent would need to bind to another set of events. Yes?
[17:25:08 EST(-0500)] * anastasiac puts on her 'being difficult' hat
[17:25:15 EST(-0500)] <anastasiac> so then reorderer is a subcomponent?
[17:25:22 EST(-0500)] <michelled> anastasiac: all our components are views.
[17:25:24 EST(-0500)] <colinclark> anastasiac: No.
[17:25:26 EST(-0500)] <michelled> but not all views are components
[17:25:30 EST(-0500)] <michelled>
[17:25:31 EST(-0500)] <colinclark> View's don't have to be subcomponents.
[17:25:37 EST(-0500)] <colinclark> Views
[17:25:44 EST(-0500)] <colinclark> Subcompoents don't have to be Views.
[17:25:47 EST(-0500)] <colinclark> They're totally orthogonal.
[17:25:53 EST(-0500)] <colinclark> All components are, by nature, Views.
[17:26:02 EST(-0500)] <colinclark> So the terminology "subcomponent" is misleading.
[17:26:04 EST(-0500)] <colinclark> Is that your point?
[17:26:07 EST(-0500)] <colinclark> I am slow.
[17:26:14 EST(-0500)] <anastasiac> but back at 5:15, you said views assume that they're subcomponents...
[17:26:37 EST(-0500)] <colinclark> anastasiac: Well, that point was that some Views may choose to assume they're subcomponents.
[17:27:04 EST(-0500)] <anastasiac> "a view assumes it will always be used as a subcomponent"
[17:27:08 EST(-0500)] <anastasiac> "always" ??
[17:27:22 EST(-0500)] * anastasiac still has her 'being difficult' hat on
[17:27:23 EST(-0500)] <michelled> I think he meant in that particular example
[17:27:38 EST(-0500)] <colinclark> A particular View instance will make that decision.
[17:27:46 EST(-0500)] <colinclark> Not Views an entire category of things.
[17:27:47 EST(-0500)] * anastasiac may have had too many poppy seeds
[17:27:58 EST(-0500)] <colinclark> michelled: I'm trying to parse your comment...
[17:28:06 EST(-0500)] <michelled> yes, dense
[17:28:22 EST(-0500)] <colinclark> Using the returnedOptions approach, a View doesn't even really need to assume the events are there.
[17:28:32 EST(-0500)] <anastasiac> ok, so I should just ignore that 'always' bit
[17:28:53 EST(-0500)] <colinclark> That approach basically says "hey, if you want to implement these events, I here are how they relate to me."
[17:29:08 EST(-0500)] <michelled> yes, it could bind to several event if it needed to. And not worry about whether they are there or not
[17:29:12 EST(-0500)] <michelled> I just wanted to clarify
[17:29:17 EST(-0500)] <colinclark> Alternatively, you might take a particular view and just manipulate it using its public API.
[17:29:21 EST(-0500)] <michelled> so, yes, now I'm happy
[17:29:35 EST(-0500)] <colinclark> Whereas, in the .addListener approach, a view is being very demanding...
[17:29:45 EST(-0500)] <colinclark> It says "I need events to work at all."
[17:29:55 EST(-0500)] <colinclark> So this actually inverts the assumption!
[17:29:59 EST(-0500)] <michelled> yes, this is better
[17:30:02 EST(-0500)] <colinclark> anastasiac: I take my previous point back.
[17:30:10 EST(-0500)] <colinclark> Views never need to assume they are subcomponents.
[17:30:16 EST(-0500)] * anastasiac looks for more poppy seeds
[17:30:18 EST(-0500)] <michelled> the 5:15 one?
[17:30:23 EST(-0500)] <colinclark> michelled: yes
[17:30:39 EST(-0500)] <colinclark> They may provide their parent with some hints for how they might best be bound up to a set of events...
[17:30:49 EST(-0500)] <colinclark> but the parent is in charge of how that actually gets implemented.
[17:31:01 EST(-0500)] <colinclark> Either they use initSubcomponents and magic autobinding occurs.
[17:31:12 EST(-0500)] <colinclark> Or they choose to manually bind events for the subcomponent.
[17:31:15 EST(-0500)] <colinclark> Up to the parent.
[17:31:31 EST(-0500)] <colinclark> anastasiac: Am I now making sense?
[17:31:34 EST(-0500)] <anastasiac> so how does a view know whether or not it is being used as a subcomponent?
[17:31:43 EST(-0500)] <colinclark> It's this declarative vs. imperative distinction.
[17:31:49 EST(-0500)] <colinclark> anastasiac: It need not know that.
[17:32:12 EST(-0500)] <colinclark> My point here is that we've inverted the dependency.
[17:32:13 EST(-0500)] <anastasiac> if a view has listeners for events, how does it know whether or not to bind them, or hand them to a parent to bind?
[17:32:24 EST(-0500)] <michelled> it can pass back whether or not it has a parent. If there's no parent the pass back stuff just gets ignored
[17:32:45 EST(-0500)] <colinclark> anastasiac: I think the point I've realized is that a little View shouldn't bother to ever bind events.
[17:32:48 EST(-0500)] <anastasiac> but if the pass back stuff is ignored, listeners don't get bound?
[17:32:56 EST(-0500)] <colinclark> anastasiac: Exactly.
[17:33:00 EST(-0500)] <colinclark> But who's problem is that?
[17:33:07 EST(-0500)] <anastasiac> how does one measure size?
[17:33:14 EST(-0500)] <colinclark> anastasiac: haha
[17:33:19 EST(-0500)] <anastasiac> how little is 'little'?
[17:33:19 EST(-0500)] <colinclark> you are asking good questions!
[17:33:27 EST(-0500)] <colinclark> Well, there's a basic assumption here.
[17:33:36 EST(-0500)] <colinclark> "I am I independent enough to live on my own?"
[17:33:49 EST(-0500)] <colinclark> "Or am I a part of something larger."
[17:34:00 EST(-0500)] <colinclark> Clearly, a FileQueueView is part of something larger.
[17:34:07 EST(-0500)] <colinclark> In which case it needs to defer to its parent to handle event binding.
[17:34:16 EST(-0500)] <anastasiac> is this a case of the developer making the call?
[17:34:23 EST(-0500)] <colinclark> And the parent, in turn, can defer to the framework based on the advice provided by the child.
[17:34:28 EST(-0500)] <colinclark> anastasiac: Exactly.
[17:34:36 EST(-0500)] <anastasiac> if I'm writing a foo, I know whether or not the foo is going to be used as a subcomponent or not
[17:34:45 EST(-0500)] <anastasiac> ok, well, then, that's fine!
[17:35:19 EST(-0500)] <colinclark> It's not even necessarily that you'll decide that it will be used as a subcomponent...
[17:35:37 EST(-0500)] <colinclark> but rather whether or not it should be responsible for its own events.
[17:35:40 EST(-0500)] <anastasiac> right
[17:35:43 EST(-0500)] <colinclark> Does that make sense?
[17:35:46 EST(-0500)] <anastasiac> yes, it does
[17:35:48 EST(-0500)] <colinclark> So progress bar is a good example.
[17:35:58 EST(-0500)] <colinclark> It could either be a subcomponent or a full-blown component.
[17:36:04 EST(-0500)] <colinclark> So it defines it's own personal events.
[17:36:13 EST(-0500)] <colinclark> It's the job of the parent to correctly bind these to its own life cycle.
[17:36:35 EST(-0500)] <colinclark> Ok, so we've all learned a little bit tonight.
[17:36:47 EST(-0500)] <colinclark> And you all think I will be rocking it if I go ahead and finish this refactoring?
[17:36:48 EST(-0500)] <colinclark>
[17:36:59 EST(-0500)] <michelled> yes
[17:37:16 EST(-0500)] <anastasiac> I'm glad I got in on this discussion, thanks for pinging me
[17:37:23 EST(-0500)] <michelled> I glad you did too
[17:37:31 EST(-0500)] <colinclark> No problem. Thinking outloud was very helpful.
[17:37:37 EST(-0500)] <colinclark> This is an important thing to remember...
[17:37:48 EST(-0500)] <colinclark> this declarative approach is what makes Infusion a framework.
[17:38:00 EST(-0500)] <colinclark> There is a lot more inversion of control, where you ask for something and the framework does it.
[17:38:18 EST(-0500)] <colinclark> Whereas when you're writing imperative code, like for binding events, you're stubbornly assuming that you're in control.
[17:38:31 EST(-0500)] <colinclark> The less we assume we're in control, the easier it is to reuse pieces of our code.
[17:38:39 EST(-0500)] <anastasiac> just "let go"
[17:38:52 EST(-0500)] <colinclark>
[17:39:00 EST(-0500)] <colinclark> Sounds very relaxing.
[17:39:07 EST(-0500)] <anastasiac> peaceful
[17:39:23 EST(-0500)] <colinclark> Thanks again for chatting.
[17:39:30 EST(-0500)] <anastasiac> same to you
[17:39:30 EST(-0500)] <colinclark> wait, that wasn't supposed to be a wink
[17:39:32 EST(-0500)] <colinclark> just a smile
[17:39:33 EST(-0500)] <colinclark>
[17:39:36 EST(-0500)] <colinclark> stupid smileys
[17:39:46 EST(-0500)] <colinclark> I am ruined by instant messaging.
[17:39:50 EST(-0500)] <anastasiac> 8-P
[17:39:56 EST(-0500)] <anastasiac> hm. didn't work
[17:40:32 EST(-0500)] <anastasiac> ok g'nite all!
[17:41:09 EST(-0500)] <colinclark> see you tomorrow