Chasing the BestBecause what pushes us forward is what we see ahead.FREAKING FINALLY!!! #fbvia tweetie
Yeah... Those kinds of foods are related... #fbvia tweetie
OJUtils: A set of utilities for Objective-J
In developing Strophe.j and ojspec (more coming on that soon), I ran into the need for a couple of utility classes. To collect these utility classes, I've created a github repository named OJUtils. Currently the two classes in there are BlankSlate and DelegateProxy.
BlankSlate
BlankSlate is an equivalent to the BlankSlate class in Ruby: it provides the absolute minimum necessary for an Objective-J class to function correctly. This makes it ideal for use in proxying scenarios when you want as few methods interfering with proxying as possible. I use it in ojspec to set up a mocking framework. BlankSlate has 3 class methods and 5 instance methods, and nothing else. These are:
No other methods are defined, so a proxy class can easily use forwardInvocation: to proxy almost all method calls successfully. Something like BlankSlate is likely to go into Cappuccino itself soon (I'm hoping to have time to move this over there) -- possibly based on NSProxy concepts. DelegateProxy There is an oft-seen pattern in the Cappuccino codebase when invoking something on a delegate: It seemed annoying to do this every time, and thus during the creation of Strophe.j was born DelegateProxy. DelegateProxy acts as a simple wrapper around your delegate on which you can invoke any method you want with the knowledge that it will only be forwarded to the delegate if the delegate can handle it. If it can't, then the method call will be silently ignored without causing any errors. This means that code like the above turns into a simple: DelegateProxy itself is a super-simple class, and relies on BlankSlate to provide a very basic starting point. All you need to do is ensure that you keep a reference to a DelegateProxy wrapped around your delegate instead of keeping your delegate itself. Creating a new DelegateProxy is as simple as: And that's it, you're ready to just do method invocations without worrying about respondsToSelector checks! Strophe.j -- An Objective-J Wrapper for strophe.js
As I evaluated Cappuccino as our potential next step to move parts of our UI from Flex (the parts that are not necessarily well-suited to Flex's strengths), I was in charge of assembling some quick prototype code to show how Cappuccino would work for us. Since a part of our app is XMPP communications and publish-subscribe, I started writing a simple wrapper to the strophe.js Javascript Jabber library. It implements Jabber using BOSH, which uses long-lived (usually 60-second) AJAX requests to maintain a Jabber connection, instead of an always-on TCP connection to a port (which browsers currently cannot do). Strophe.j is this wrapper, and it's available on github at http://github.com/Shadowfiend/Strophe.j/tree/master . It provides a very basic implementation of the current user, a connection, and basic MUC support. It has some stubs for handling rosters, though they aren't implemented, and it pulls in jquery (for parsing the Jabber XML when needed). It's in the early stages, and my work on it is likely to be sporadic, since our ultimate decision was to go with GWT... But I kind of fell in love with Objective-J, so I won't be going anywhere anytime soon.
Havoc-Wreaking Flex Transitions
Flex transitions are damn sexy beasts. They let you animate things like movements and resizing. The trouble is that they do all of this asynchronously, firing every so many milliseconds. The result is that occasionally, a Flex transition will get in the way of a change you make. This isn't a very long post, more of a warning. If for some reason you try to (for example) resize or move an object and find that it doesn't work, make sure that you don't have a transition overriding your size settings somewhere. Occasionally, these can fire at just the wrong moment so that you end up with exactly the wrong result, but without your really being able to see the transition happening. This happens especially if the transition is supposed to happen over a very short period of time.
via tweetie
Flexlib's SuperTabNavigator and Truncated LabelsA quick `uh-oh, bug fix!' post here. We've been using the SuperTabNavigator from flexlib for some of our tabbing needs, and recently realized we had run into a bug: if your navigator is set to limit the width of tabs to a certain amount, thus causing labels to get truncated, then you will have trouble editing the labels on those tabs. The SuperTabNavgiator provides, amongst other features, the ability to edit a tab label in line. This is pretty cool, and the way it is implemented is even cooler: basically the same textField that is used by the Tab to display the actual label then has its type property set to TextFieldType.INPUT to make it editable. Pretty slick.
The troubles come when the label is truncated. By default, what tabs do when they have to truncate their labels is keep their label property the same, set their tooltip to their full label text, and then set their textField's text to a truncated version of the label with a `...' on the end. This works out nicely, as it means that you have a truncated label for width purposes, and can get the full label by looking at the tab's tooltip. But! Since SuperTabNavigator uses that same text field for editing, when you go to edit the text, it's the truncated version! That is to say, if I had a label title that was `This is a cool tab', that was truncated to `This is a coo...', when I went to edit it, I would be editing the text `This is a coo...', not my real label text!
This is a pretty huge problem, but it's also relatively easy to work around. When the SuperTab is switched into edit mode, we basically set its textField's text back to the value of the tab's label (remember that it is never truncated, only the text in the field is). When the text is updated, the field will get truncated again by the Tab class's own handling of the label property. Thus, we have the right editing functionality and the right viewing functionality.
Implementing this fix is a bit complicated, however. Basically, you need to implement it in a subclass of SuperTab. That's easy enough. The trouble comes with the fact that we need the SuperTabBar to use that subclass of SuperTab. Ok, so we create a subclass of SuperTabBar that instantiates FixedSuperTabs instead of SuperTabs. Now the problem is getting the SuperTabNavigator to use the FixedSuperTabBar instead of the SuperTabBar. So we need a trivial subclass of that. The solution is a set of three classes: FixedSuperTabNavigator, FixedSuperTabBar, and FixedSuperTab, with the real work done in the last one. We'll have a quick look at the code for the fix in FixedSuperTab:
We override the setter for editableLabel (which is where we are switched into editing mode). We let SuperTab do its thing, and then, if we need to, we do our own overriding of the textField's text. Then we also redo the selection of the text -- SuperTab selects the full text when the tab is made editable, but we've just changed the text in the field, so the selection will at best be off and at worst non-existent. Thus, we redo it so that it is correct.
Here is a ZIP file with the three necessary files for a fixed editing experience. I need to submit a patch for this to the flexlib folks, but this will do as a stopgap.
UPDATE: I went ahead and posted a patch to the appropriate issue at http://code.google.com/p/flexlib/issues/detail?id=82
Using Glows to Change Image Color in FlexIn a few cases in our application, we've been using buttons that consist primarily of an image that must then change colors for hover and down/selected states. For each of these, we initially embedded the images for the three states into the application and referred to them from there. The trouble is that this means a bit of bloat in the app itself. Not much for small buttons, more for larger buttons, but regardless if the space is unnecessary, then there's no need to have it there. Flex applications can get relatively large (the main module of our app is around 700K at the moment), and it's always nice to save some space. With that in mind, how can we include fewer assets in these cases? In our case, we decided to use a Glow effect. The Glow effect provides a certain color tint to a given component. By default, it's an external glow, meaning there is some color emanating from the borders of that component. However, there are a few properties of the effect that we can use to our great advantage:
A downside of the filter is that, in order to actually modify the color it is glowing with, you have to remove it from the list of a component's filters and then add it back in. Simply changing the color property is not enough. For all the discussion about rollovers above, the biggest win of using a glow to change colors is the ability to change an image with a color transition. In our case, we have a thumbs up image that changes colors when a user is rated up. The image has a color transition from green to white and then back. Usually, this would be relatively difficult to achieve; with the glow effect, however, we can change the color of the image without needing any additional embedded assets. Here is and adaptation of that code: <?xml version="1.0" encoding="utf-8"?> xmlns:effects="com.darronschall.effects.*" creationComplete="init()"> <mx:Script> <![CDATA[ import mx.events.EffectEvent; [Embed('assets/images/thumbs_up.png')] private static const HELPFUL_THUMBS_UP:Class; private static const THUMBS_UP_DEFAULT_COLOR:Number = 0xC3DA6E; [Bindable] public var helpfulImageColor:Number = THUMBS_UP_DEFAULT_COLOR; public function highlight(newColor:Number = NaN):void { if (! isNaN(newColor)) { helpfulImageColor = newColor; reloadHelpfulImageGlow(); ratingLabel.setStyle("color", newColor); } } public function fadeHighlight():void { highlightFader.play(); } /** * In order for a glow to have its color changed, it needs to be * removed and re-applied. This function does that for the helpful * image glow filter. */ private function reloadHelpfulImageGlow():void { helpfulImage.filters = null; helpfulImage.filters = [helpfulImageGlow]; } ]]> </mx:Script> <mx:Parallel id="highlightFader" duration="2000"> <effects:AnimateColor target="{ratingLabel}" property="color" isStyle="true" toValue="{THUMBS_UP_DEFAULT_COLOR}" /> <effects:AnimateColor target="{this}" property="helpfulImageColor" toValue="{THUMBS_UP_DEFAULT_COLOR}" tweenUpdate="reloadHelpfulImageGlow();" /> </mx:Parallel> <mx:GlowFilter id="helpfulImageGlow" color="{helpfulImageColor}" blurX="20" blurY="20" alpha="1" inner="true" /> <mx:VBox styleName="ratingWrapper" height="24"> <mx:Label id="ratingLabel" styleName="ratingLabel" width="100%" height="8" text="{data.rating}" /> <mx:Image id="helpfulImage" styleName="helpfulImage" height="10" scaleContent="true" source="{HELPFUL_THUMBS_UP}" filters="{[helpfulImageGlow]}" /> </mx:VBox> </mx:Canvas> Here, we given the color animation a tweenUpdate function that reloads the glow filter on the image. As I mentioned above, this happens because the filter is not reapplied unless you remove it and re-add it. Simply changing the color property of the filter, as the AnimateColor effect does, does not force that refresh. Other than that most of it is pretty self-explanatory. We have a bindable color that is updated continuously by the AnimateColor effect, and we have a parallel effect that updates the label that accompanies it. The component that contains this in our application changes its own background color at the same time, thus making this color change still result in a legible rating. All in all, glow filters are more useful than simply applying a glow. This technique can be a real keeper for color transitions on images. Pulling and merging with gitWhen you have a multi-user workflow with git, you usually have a central repository that you clone, and then you periodically push your changes back to it and pull the changes others have made down from it. On the surface, this seems sort of like a subversion workflow, only you can also commit locally; in practice, however, it is very different. Each clone of the repository is essentially a potentially different branch of changes. You and Mike (a fictional über-coder) may both have the same version from the central repository, and then you make eight commits and he makes 29. What, then, does git do? # git push Counting objects: 104, done. Compressing objects: 100% (73/73), done. Writing objects: 100% (73/73), 7.13 KiB, done. Total 73 (delta 58), reused 0 (delta 0) To git@github.com:magic/mikeFreakingRox0rz.git bc06779..d79eb17 master -> master
# git push To git@github.com:magic/mikeFreakingRox0rz.git ! [rejected] master -> master (non-fast forward) error: failed to push some refs to 'git@github.com:magic/mikeFreakingRox0rz.git'
# git pull remote: Counting objects: 20, done. remote: Compressing objects: 100% (11/11), done. remote: Total 11 (delta 8), reused 0 (delta 0) Unpacking objects: 100% (11/11), done. From git@github.com:magic/mikeFreakingRox0rz.git 38620e5..058cf00 master -> origin/master Merge made by recursive. mike/is/awesome/prove.rb | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
Merge made by recursive.
# git log commit eb8442977176a95568e27b40c169e2d97ab4e8f7 Merge: 0f6ef2d... 058cf00... Author: Antonio Salazar Cardozo Date: Wed Apr 22 16:55:41 2009 -0400 Merge branch 'master' of git@github.com:magic/mikeFreakingRox0rz.git
# git pull remote: Counting objects: 48, done. remote: Compressing objects: 100% (26/26), done. remote: Total 26 (delta 20), reused 0 (delta 0) Unpacking objects: 100% (26/26), done. From git@github.com:magic/mikeFreakingRox0rz.git 38620e5..eb84429 master -> origin/master Updating 38620e5..eb84429 mike/is/awesome/prove.rb: needs update error: Entry 'mike/is/awesome/prove.rb' not uptodate. Cannot merge.
# git commit -m "He is awesomer." mike/is/awesome/prove.rb
# git merge origin/master
Auto-merged mike/is/awesome/prove.rb CONFLICT (content): Merge conflict in mike/is/awesome/prove.rb
# git mergetool
merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff
Merging the files: mike/is/awesome/prove.rb
Normal merge conflict for 'mike/is/awesome/prove.rb':
{local}: modified
{remote}: modified
Hit return to start merge resolution tool (opendiff):
Using HAML with FBML
Just a quick post here, hopefully I'll get around to making some more posts. I've been busy getting my current job's project http://openstudy.com/ up in open mode. Still very beta, but very cool. Anyway, we needed to use FBML with HAML at some point, and it turns out that's super easy. Here's how to render a login-button from FBML in HAML:
%fb:login-button{:size => 'medium', :length => 'long', | :onlogin => 'facebookUserLoggedIn();'} | |
|