-
Notifications
You must be signed in to change notification settings - Fork 62
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
Expand on F2.registerApps method for added app placement support #38
Comments
This looks like it will solve my problem. By AppConfig, I presume is meant the AppConfig argument to registerApps() method, not the private F2._apps kept internally by F2 itself ? It would not be good to allow direct modification of the _apps by the container code. Also, the hooks for beforeAppRender(), etc. would be temporary overrides? The next call to registerApps() would use the default ones defined via F2.init()? |
Thanks I-Lin—you're absolutely right. Read only makes sense... although we did kick around the idea of allowing Container code to add properties to the |
I would love to see something more along the lines of subscription/broadcast rather than a singular callback in Init() and eliminate beforeAppRender(), appRender(), afterAppRender() entirely (making those methods private to F2). I was thinking something like:
/\* Way to handle all apps (Your container's default) _/
// don't pass AppID means apply to all
F2.Container.AppRender.Before(function(app){ /_ call method for all apps_/ });
F2.Container.AppRender.Before(function(app){ /_ do this after because was bound second */ });
/\* Way to handle a specific app id, basically an override for specific App _/
F2.Container.AppRender.Before("SpecificAppID", function(app){ /_ do something special for this app only */ });
I would love to hear more thoughts on this... We could even open this up to allow apps to have a say in how they are rendered (although you could just do something inside your js you return from in the manifest) |
@markhealey , regarding
I would actually prefer the DOM node to be provided separately, not as part of AppConfig. This is to allow a more jQuery-flavored API. For example, registerApp(appRoot, appConfig, handlers) and allow the For the |
@Ali-Khatami - If we went the subscription/broadcast route, what should happen if the container subscribed to both |
@brianbaker - It's a tough call... Below are the pros and cons of the 2 use cases I feel are most logical... Case 1: Pros:
Cons:
Case 2: Pros:
Cons:
I personally feel that Case 1 is more useful and provides a better way to separate concerns and help reuse code. It is a design pattern a lot of object oriented programmers are used to. Obviously Case 1 doesn't really work so hot if a container developer just wants to pass a native dom node...
I feel the dom node approach should be app specific. I can't imagine a scenario where a container developer can trust apps enough to just place ALL requested apps in a single DOM node without manipulating or wrapping them first. So I think the 3 overloads should look like...
The order should be Generic/All Apps method(s) are called, then App specific method(s) are called which can either be a function or a straight up native node telling F2 where append the app. |
None of the alternate proposals for overriding handlers meet our needs. AppRender is not the only method that needs to be overridden.
Our use case is that we want to allow the reader to drag and drop F2 Apps into different regions on the page. Based on the division of responsibility in the example container.js, both F2.Container.AppRender.Before(function() { ... })
F2.Container.AppRender.Before("AppID", function() { ... }) Furthermore, the DOM node might not be the only variation of the handlers needed between invocations, as there might be other styling differences. So far, the only proposal that solves our problem is the one I laid out registerApp(appRoot, appConfig, handlers) where the handlers are overriden at the time of invocation. However, I see in the discussions a desire to interact with the base xxxAppRender methods and not just override them. That desire can be accommodated elegantly using the handlers object above. When a handlers object is received, set methods on the object {
afterAppRender: function(app, html){
html = "<div>" + html + "</div>";
return this._afterAppRender(app, html);
}
} |
I think the subscription/broadcast proposal was just looking at a single method for the sake of saving typing, but all methods could be overridden. For the sake of example (naming can be decided later - the names used below aren't good), you might have:
Not to get this thread side-tracked, but were you planning on calling
To clarify a bit if I'm understanding the proposals discussed, I think both proposals might be able to do the same thing. The following might be an example of the two:
|
To answer your question, Brian, for us, an F2 app might appear in one of several regions. In the Main region, the app can have all the width it wants. In the Dock, it's constrained to a width of ~160 pixels. When the user asks for an app, he/she might ask for it to be created in the lower left corner of the Main region or in the middle of the Dock, for example. This would involve a call to If a user were to remove an app from the Dock and recreate it in the Main, then this would involve a removeApp() followed by a Now, going back to the Proposals, // Proposal 1
F2.registerApps( $('#someSelector').get(0), appConfig, {
beforeAppRender: function() { ... },
appRender: function() { ... },
afterAppRender: function() { ... }
}); would certainly work for us, but I think would require additional changes in the signature of the var targetNode = $('#someSelector').get(0);
F2.registerApps( appConfig, {
beforeAppRender: function() { ... },
appRender: function() { ... },
afterAppRender: function() { ... }
}); where targetNode would be in the closures of the functions and would not require a signature change in the existing APIs. As for Proposal 2, // Proposal 2
F2.Container.AppRender.Before(appConfig.appId, $('#someSelector').get(0) );
F2.Container.AppRender.Before(appConfig.appId, function() { ... });
F2.Container.AppRender.During(appConfig.appId, function() { ... });
F2.Container.AppRender.After(appConfig.appId, function() { ... });
F2.registerApps(appConfig); I think that has to be modified to // Proposal 2
try {
F2.Container.AppRender.Before(appConfig.appId, $('#someSelector').get(0) ); //not sure how to clear this out
F2.Container.AppRender.Before(appConfig.appId, function() { ... });
F2.Container.AppRender.During(appConfig.appId, function() { ... });
F2.Container.AppRender.After(appConfig.appId, function() { ... });
F2.registerApps(appConfig);
} finally {
F2.Container.AppRender.ResetBefore(appConfig.appId);
F2.Container.AppRender.ResetDuring(appConfig.appId);
F2.Container.AppRender.ResetAfter(appConfig.appId);
} in order to clear out the overrides made before the So, while I agree that both proposals can provide the same functionality, I strongly disagree that the proposals are of equal merit. Indeed, the same functionality can even be done with the current release of F2 without any modifications to the framework itself, but it would be a hack in my opinion. Allow me then to throw back a couple of questions:
F2.Container.AppRender.Before(appConfig.appId, function() { ... });
|
My primary concern with overloading I like the thought of an event-based rendering system because it provides the single entry point for rendering. F2 already uses eventing for context passing and will likely use a similar system for secure messaging down the road. Additionally, web developers deal with dom events on a daily basis and this really would be no different. It meets the existing functionality of F2.init() and it also would allow for single-app customization. Also, it opens the door to other rendering scenarios ("Render all apps with an AppId of For the scenarios where you want to render something once and be done with it, instead of requiring a Perhaps the developer has one module that handles the layout of apps in the main column of the page and second module that handles the layout in a sidebar and a third module that provides the interface for a user to select apps. When the user selects an app, the third module would call |
I put together an example of an event-based rendering system from my understanding of @Ali-Khatami's proposal without modifying F2.js: http://jsfiddle.net/rekabnairb/efyH4/ For the sake of time, I'm just using jquery events and I'm not handling all of the edge cases. If we chose to roll something like this up into the framework, we could certainly provide a better interface and handle all edge cases. I would also envision that the handlers in
There's one handler that only applies when a certain location is selected. I could see this type of logic being rolled up into the framework so that the framework handles the logic and conditionally calls the handler. |
I think that's a problem of the existing API (regardless of any overloading), where
So ... this remains the major point of contention between us. I absolutely think the above is a trivial use case that can be adequately handled by a if-then-switch-case statement within the methods passed to
It's an interesting example, and I can see that it does address the location-dependent loading, and while in the fiddle the containers are created ahead of time, it can be easily adjusted to use just-in-time dynamically created containers. However, one of its flaws is that it still assumes handling is based on AppID only, not app instance. This will cause problems if |
Making use of AppConfig.context is definitely a supported practice and isn't a hack to do so. See http://docs.openf2.org/app-development.html#container-to-app-context-server Many, if not all, of your Just-In-Time instance concerns (width, height, and other runtime config) seem like perfect use cases for Context The single entry point to rendering would be the event system. Developers wouldn't need to learn about handling rendering in And to your final point about multiple instances of the same app - I'm not sure of your exact use case and what logic needs to be performed for each instance, but I would wonder if that too would be solved with context? |
Since you're recommending passing of parameters using the AppConfig.Context, that's what we'll go ahead and do, despite our reservations with this approach. This will also solve our problems with multiple instances, though it does not, at first thought, manage to resolve the mis-interception of events problem raised earlier, but that's not something that needs to be resolved now. So here are some clarifying questions/comments to this approach:
My opinion is that some of this information is sensitive and should not appear in a plain URL. Additional guidelines need to be added to prevent the appearance of sensitive information in URL querystring in a uniform way across all containers.
|
I think we'll handle these final questions via the newly created #46 if that's OK, as it seems like the framework needs a little more work in that area. I'll write up some comments over there and we'll keep this thread moving towards adding the expanded rendering functionality. |
I'd like to try and nail down the interfaces, namespaces, etc. and initial functionality for the subscription/broadcast (event) based rendering. Anyone have any suggestions? At one point, I thought that maybe we could use
|
@brianbaker is there anything from #4 that needs to be considered for this update? |
@brianbaker I know you're aware of this already, but just to point this out, you've got a mixture of event paradigms here. Most falls under simple pub/sub -- one publisher, multiple listeners, and the publisher doesn't really care what the subscribers do nor whether it is done synchronously or asynchronously. A variation of that is topic/channel-based pub/sub -- multiple publishers and listeners, but again the publishers don't care what the subscribers do. Most eventing libraries are setup to do pub/sub, which is why
While
would also technically fall under "eventing", it's really very different from the other methods -- only one publisher and one subscriber, and the publisher must wait synchronously for the return value from the subscriber before proceeding. As such, I'm a little wary of an api that makes the different kinds of events look the same. I'd prefer a different terminology, maybe callback? http://en.wikipedia.org/wiki/Callback_(computer_science) |
@markhealey Definitely, and with that in mind my @ilinkuo I think we could support multiple listeners/subscribers (my jsfiddle example had a few listeners on the beforeAppRender event), but they'd definitely be synchronous in execution and differ from Its also worth noting that this functionality really only applies to the Container so only a container developer would need to know the difference between |
This can be closed, with the resolution that the recommendation is to pass app placement information into the appConfig context itself. Future clarification needed for a standard way of expressing this within the appConfig. |
Like #4, we need to get documentation written in the spec before we can release this. |
Tests currently fail due to issues with #38
Extra bug fixes and updates for #38
The goal here is to expand on
F2.registerApps()
to provide Container Developers more control over placement of F2 apps. This includes initial placement on-page-load as well as on more rich client apps where F2 apps are loaded on-demand after the initial page-load.Two immediate additions are:
AppConfig
(currently handled by theappRoot
argument).beforeAppRender()
,appRender()
andafterAppRender()
throughF2.registerApps()
. Those handlers are currently only available inF2.init()
.We'll expand with more comments and commits on this Issue.
The text was updated successfully, but these errors were encountered: