tag:blogger.com,1999:blog-81777804424059092362009-07-03T09:03:55.660-07:00Techish dot Jeremy Mooeranother lame blog by jeremy mooer -- maybe i can find some time to actually do this blogging thing.Jeremyhttp://www.blogger.com/profile/15502013328032987665noreply@blogger.comBlogger8125tag:blogger.com,1999:blog-8177780442405909236.post-83097145822101960842009-06-10T12:01:00.000-07:002009-06-10T12:28:52.897-07:00Flex AsyncToken ProgressBarBrian Holmes originally created an AsyncTokenProgressBar at my current place of employment and included it in the <a href="http://code.google.com/p/smashedapples/source/browse/trunk/SmashedApplesSDK/smashedapples/controls/progressbars/AsyncTokenProgressBar.as?spec=svn128&r=128">SmashedApples Framework</a>.<br /><br />After our FortFUG meeting lastnight and talking to <a href='http://freeflowingcode.com/'>Brian Coleman</a> who uses it, I thought I'd post my updates to the class here. When I have some time, I'll update the SmashedApples framework library project and check it in.<br /><br />it's used, obviously, by calling the static method AsyncTokenProgressBar.show(asyncToken, uiComponentToOverlayWithProgressBar);<br /><br /><br /><br /><pre><br />public class AsyncTokenProgressBar extends ProgressBar<br />{<br /><br />public static function show(token:AsyncToken, parent:UIComponent, label:String=null):void<br />{<br /> var container : AsyncTokenProgressBarContainer = new AsyncTokenProgressBarContainer();<br /> container.height = parent.height;<br /> container.width = parent.width;<br /><br /> var bar : AsyncTokenProgressBar = new AsyncTokenProgressBar();<br /><br /> parent.callLater(bar.doShowLater,[token,parent,container,label]);<br />}<br /><br />// the easiest way to align the asyncTokenProgressBarContainer with the parent was to call centerPopup after the parent has been rendered/displayed.<br />private function doShowLater(token:AsyncToken, parent:UIComponent, container:AsyncTokenProgressBarContainer, label:String=null):void<br />{<br /> if(label!= null)<br /> this.label = label;<br /><br /> container.addChild( this );<br /><br /> PopUpManager.addPopUp( container, parent, false );<br /> PopUpManager.centerPopUp( container );<br /><br /> if(parent is Container && (parent as Container).enabled == true )<br /> {<br /> (parent as Container).enabled = false;<br /> token['parentWasDisabledByAsyncBar'] = true;<br /> token['parentReference'] = parent;<br /> }<br /><br /> this.start(token);<br /><br />}<br /><br /><br /><br />public function AsyncTokenProgressBar()<br />{<br /> super();<br /> this.indeterminate = true;<br /> this.mode = "manual";<br /> this.maximum = 0;<br /> this.minimum = 0;<br /> this.label = "";<br />}<br /><br /><br /><br />public function start(token:AsyncToken):void<br />{<br /> this.setProgress( 0,1 );<br /> var responder : AsyncResponder = new AsyncResponder( handler, handler );<br /> token.addResponder( responder );<br />}<br /><br />public function stop():void<br />{<br /> this.setProgress( 1,1 );<br /><br /> if( (this.parent as Container).isPopUp)<br /> PopUpManager.removePopUp(this.parent as IFlexDisplayObject);<br />}<br /><br />//AsyncResponder fault and result handler<br />private function handler(data:Object, token:Object=null):void<br />{<br /> if(token == null && data.hasOwnProperty('token'))<br /> token = data['token'];<br /><br /> if(shouldReEnableParent(token)) {<br /> (token['parentReference'] as Container).enabled = true;<br /> }<br /><br /> stop();<br />}<br /><br />private function shouldReEnableParent(token:Object):Boolean<br />{<br /> if(!token)<br /> return false;<br /><br /> if(!token.hasOwnProperty('parentWasDisabledByAsyncBar'))<br /> return false;<br /><br /> if(!token.hasOwnProperty('parentReference'))<br /> return false;<br /><br /> if(token['parentWasDisabledByAsyncBar'] == false)<br /> return false;<br /><br /> if( !(token['parentReference'] is Container) )<br /> return false;<br /><br /> return true;<br />}<br /><br /><br /><br /><br /><br /><br />}<br /></pre><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8177780442405909236-8309714582210196084?l=techishdotjeremy.blogspot.com'/></div>Jeremyhttp://www.blogger.com/profile/15502013328032987665noreply@blogger.com0tag:blogger.com,1999:blog-8177780442405909236.post-42322635945925727292009-05-18T14:36:00.000-07:002009-05-18T22:01:50.334-07:00AutoScrolling Flex Form.At work we have an extensive library for our internal ERP application. A component therein is our Form component. It does a lot of little things such as adding default keyListeners for regularly used form shortcuts, or a getFormValues that loops through all children (and all children of childrenContainers ad infinitum), returning a class that we use for most RemoteObject calls.<br /><br />Last week I added an autoScroll property to that internal form, using code from <a href="http://www.webapper.com/blog/index.php/2008/02/01/flex-making-scrollbars-follow-focus">Daryl Bantarri's AutoScroll</a> utility class (a class that has a single static method). I had a slight problem with it that required a slight edit or two (breaking the method into a few more manageable functions). (and, of course, my edits had to conform to our internal architectural standards and naming conventions)... so if the "doFunctionName," "canRuleName" or redundant returns in the rule are annoying -- that's my fault --> I wrote a lot of those ridiculous rules over here.<br /><br />Also, in the comments of <a href="http://www.webapper.com/blog/index.php/2008/02/01/flex-making-scrollbars-follow-focus">Daryl's post</a>, some talked of removing the updateComplete listener. We add a lot of form components dynamically to forms, so listening for anything after an updateDisplayList, etc., is a necessity for our framework. Feel free to get rid of that updateComplete listener if need be, especially if your intended use is to hard-code your components in the form.<br /><br />A shout out to <a href="http://www.webapper.com/index.cfm/about-us">Patrick who is part owner of Webapper</a>... fellow Northern Coloradan whom I've met a small handful of times at random local tech meetups.<br /><br /><pre><br />private var _autoScroll : Boolean = false;<br />public function get autoScroll():Boolean<br />{<br /> return _autoScroll;<br />}<br />public function set autoScroll(value:Boolean):void<br />{<br /> _autoScroll = value;<br /> if(value)<br /> activateAutoscrollListeners();<br />}<br /><br /><br /><br />private function activateAutoscrollListeners():void<br />{<br /> var container : DisplayObjectContainer = this.parent;<br /> if(container)<br /> {<br /> container.addEventListener(FlexEvent.UPDATE_COMPLETE, doAutoScroll);<br /> container.addEventListener(FocusEvent.FOCUS_IN, doAutoScroll);<br /> }<br />}<br /></pre><br /><br />also, on creationComplete (or earlier, since we only need the this.parent in activeAutoScrollLIsteners()):<br /><pre><br />if(autoScroll)<br /> activateAutoscrollListeners();<br /></pre><br /><br /><pre><br />private function canAutoScroll(container:Container, focusObject:DisplayObject):Boolean<br />{<br /> if(!focusObject)<br /> return false;<br /><br /> if(!container)<br /> return false;<br /><br /> if(!container.verticalScrollBar)<br /> return false;<br /><br /> if(!this.contains(focusObject))<br /> return false;<br /><br /> if(focusObject == this)<br /> return false;<br /><br /> return true;<br />}<br /><br />/**<br />* doAutoScroll is the eventListener for the parent container's updateComplete and focusIn. if(canAutoScroll), this method calls<br />* completeAutoScroll and updates the parent container's verticalScrollPosition.<br />*<br />*/<br />private function doAutoScroll(event:Event):void<br />{<br /> var container : Container = Container(event.currentTarget);<br /> //Don't want displayObject.Y of event.target. getFocus() is more accurate (i.e., mx.controls.combobox).<br /> var focusObject : DisplayObject = DisplayObject(container.focusManager.getFocus());<br /><br /> if(canAutoScroll(container,focusObject))<br /> {<br /> var itemParent : DisplayObjectContainer = focusObject.parent;<br /> var focusObjectTopY : int = (focusObject.parent == this) ? focusObject.y : addTotalYoffSets(focusObject);<br /> if(container.verticalScrollPosition != focusObjectTopY)<br /> {<br /> completeAutoScroll(container, focusObjectTopY, focusObject);<br /> }<br /> }<br />}<br /><br />private function addTotalYoffSets(focusObject:DisplayObject):int<br />{<br /> var parentContainer : DisplayObjectContainer = focusObject.parent;<br /> var focusObjectTopY : int = focusObject.y ;<br /><br /> while(parentContainer != this.parent) {<br /> focusObjectTopY += parentContainer.y;<br /> parentContainer = parentContainer.parent;<br /> }<br /><br /> return focusObjectTopY;<br />}<br /><br />private function completeAutoScroll(container:Container, focusObjectTopY:int, focusObject:DisplayObject):void<br />{<br /> var focusObjectBottomY : int = focusObjectTopY + focusObject.height;<br /> var lastVisibleY : int = container.height + container.verticalScrollPosition;<br /><br /> if(container.horizontalScrollBar)<br /> lastVisibleY -= container.horizontalScrollBar.height;<br /><br /><br /> if(focusObjectTopY < container.verticalScrollPosition)<br /> {<br /> container.verticalScrollPosition = Math.max( 0, focusObjectTopY - 5 );<br /> }<br /> else if(focusObjectBottomY > lastVisibleY)<br /> {<br /> //scroll down. +5 pixels for good measure.<br /> var newPosition : int = Math.min( container.verticalScrollBar.maxScrollPosition, (container.verticalScrollPosition + (focusObjectBottomY - lastVisibleY)) );<br /> container.verticalScrollPosition = newPosition + 5;<br /> }<br /><br />}<br /></pre><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8177780442405909236-4232263594592572729?l=techishdotjeremy.blogspot.com'/></div>Jeremyhttp://www.blogger.com/profile/15502013328032987665noreply@blogger.com1tag:blogger.com,1999:blog-8177780442405909236.post-11949949079019150592009-05-12T21:25:00.000-07:002009-05-12T21:27:42.663-07:00FlexPerspective projectAs per yesterday's random post, I decided to post my little FlexPerspective project. The details are at <a href="http://github.com/jeremym/FlexPerspective/tree/master">gitHub</a>. I'll get around to posting a decent example in the coming weeks.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8177780442405909236-1194994907901915059?l=techishdotjeremy.blogspot.com'/></div>Jeremyhttp://www.blogger.com/profile/15502013328032987665noreply@blogger.com0tag:blogger.com,1999:blog-8177780442405909236.post-91501645999183221852009-05-11T19:57:00.000-07:002009-05-11T20:31:20.049-07:00A Note on SAP / Flex and iPerspectiveRidiculously long time since a post, but, for anyone who knew I went, my trip to Palo Alto wasn't what I had expected. I thought I'd be writing an interface to parse the SAP metadata used to render an SAP screen and render it in a Flex application.<br /><br />It appears as though it had already been done... not sure if it was/is an open source project, but one thing that did come out of my own experimentation is a little interface called <span style="font-weight: bold; font-style: italic;">iPerspective</span>.<br /><br />iPerspective: In the app I was building it seemed to make sense to (instead of manage components' interactivity through states) dispatch a PerspectiveEvent (listened for in the App and pushed back down to all registered components), changing the look of the ApplicationControlBar, and anything else that is a mx.core.container that implements iPerspective.<br /><br />I'll work with it next week if/when I have time -- if it makes sense in practice, maybe I'll open source it.<br />Anyway, no real stories. Hope all is well out there.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8177780442405909236-9150164599918322185?l=techishdotjeremy.blogspot.com'/></div>Jeremyhttp://www.blogger.com/profile/15502013328032987665noreply@blogger.com0tag:blogger.com,1999:blog-8177780442405909236.post-69064824445031881452008-09-13T10:28:00.001-07:002009-05-11T19:45:18.881-07:00a random utility class: ObjectSerializer.I'm just going through and editing a few old posts. This package (objectSerializer) was one that was needed in the case of a serialized object needing to be passed through a url (yes, we had a case where that was needed).<br /><br /><pre>package of.lovin<br />{<br /> import flash.utils.ByteArray;<br /> <br /> import mx.utils.Base64Decoder;<br /> import mx.utils.Base64Encoder;<br /> <br /> public class ObjectSerializer<br /> {<br /><br /> public static function decode(str:String):*<br /> {<br /> // '+' equals '-' and '/' equals '_'<br /> <br /> if (str != null)<br /> {<br /> <br /> var myPattern : RegExp = new RegExp("-", "g");<br /> var myPattern2 : RegExp = new RegExp("_", "g");<br /> var myPattern3 : RegExp = new RegExp("~", "g");<br /> <br /> var urlModifiedString : String = str;<br /> urlModifiedString = urlModifiedString.replace(myPattern,"=");<br /> urlModifiedString = urlModifiedString.replace(myPattern2,"/");<br /> urlModifiedString = urlModifiedString.replace(myPattern3,"\n");<br /> <br /> <br /> var bytes:ByteArray = new ByteArray();<br /> var bDecoder : Base64Decoder = new Base64Decoder();<br /> bDecoder.decode(urlModifiedString);<br /> bytes = bDecoder.toByteArray() ;<br /> <br /> bytes.position = 0;<br /> <br /> return bytes.readObject();<br /> }<br /> return null;<br /> <br /> }<br /> <br /> public static function encode(obj:*):String<br /> {<br /> // '+' equals '-' and '/' equals '_'<br /> <br /> var bytes:ByteArray = new ByteArray();<br /> bytes.writeObject( obj );<br /> <br /> var bEncoder : Base64Encoder = new Base64Encoder();<br /> bEncoder.encodeBytes(bytes);<br /><br /> var myPattern : RegExp = new RegExp("=", "g");<br /> var myPattern2 : RegExp = new RegExp("/", "g");<br /> var myPattern3 : RegExp = new RegExp('\n', "g");<br /> <br /> var urlModifiedString : String = bEncoder.toString();<br /> urlModifiedString = urlModifiedString.replace(myPattern,"-");<br /> urlModifiedString = urlModifiedString.replace(myPattern2,"_");<br /> urlModifiedString = urlModifiedString.replace(myPattern3,"~");<br /> <br /> return urlModifiedString ;<br /> }<br /><br /> }<br />}</pre><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8177780442405909236-6906482444503188145?l=techishdotjeremy.blogspot.com'/></div>Jeremyhttp://www.blogger.com/profile/15502013328032987665noreply@blogger.com0tag:blogger.com,1999:blog-8177780442405909236.post-61444990987894297442008-05-13T11:22:00.000-07:002009-05-11T21:10:28.873-07:00missing enabledChanged metadata in mx.core.UIComponentI could write a long drawn-out post about how we were creating event listeners today to set the enabled property of some of the button classes in our custom forms at work... blah blah blah.<br /><br />Bottom line, UIComponent.as is missing this line:<br />[Event(name="enabledChanged", type="flash.events.Event")]<br /><br />Give it a shot. Create a component that extends mx.core.Container (or, in our case, extends a custom component that extends Form.as) and create a function bindable to "enabledChanged" (so that the binding is done via metadata). It won't work until you add the metadata for the event somewhere.<br /><br />That is all.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8177780442405909236-6144499098789429744?l=techishdotjeremy.blogspot.com'/></div>Jeremyhttp://www.blogger.com/profile/15502013328032987665noreply@blogger.com0tag:blogger.com,1999:blog-8177780442405909236.post-20302346650257063282008-05-10T11:09:00.000-07:002008-05-15T22:06:35.684-07:00Flex Builder / Eclipse tip du jour.It's inevitable. You'll be debugging a Flex application, get an error and will need to look at a class, object, function or the like. Instead of scrolling up and down, or digging through directories, do the following:<br /><br /><span style="font-weight:bold;">Ctrl-click</span> on the 'identifier' in question and you're in like Flynn.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8177780442405909236-2030234665025706328?l=techishdotjeremy.blogspot.com'/></div>Jeremyhttp://www.blogger.com/profile/15502013328032987665noreply@blogger.com0tag:blogger.com,1999:blog-8177780442405909236.post-48345607664666797652008-05-10T10:38:00.000-07:002008-05-10T10:39:41.664-07:0030th time is the charm?Maybe it's a bad idea to start ANOTHER blog that may fall into the same ol' my-last-post-was-five-months-ago pit. But, what the hell...<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8177780442405909236-4834560766466679765?l=techishdotjeremy.blogspot.com'/></div>Jeremyhttp://www.blogger.com/profile/15502013328032987665noreply@blogger.com0