You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@royale.apache.org by Alex Harui <ah...@adobe.com.INVALID> on 2020/01/20 16:41:37 UTC

Re: [royale-asjs] branch develop updated: Added Router

Nit-picky comments:

1) there is already a bead that watches location.hash.  It might be worth using it to share code
2) forward/backward/go/title doesn't seem PAYG to me.  I can imagine lots of users won't need it, or might use it independently of routing (especially Title).

My 2 cents,
-Alex

On 1/20/20, 4:11 AM, "harbs@apache.org" <ha...@apache.org> wrote:

    This is an automated email from the ASF dual-hosted git repository.
    
    harbs pushed a commit to branch develop
    in repository https://nam04.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&amp;data=02%7C01%7Caharui%40adobe.com%7C4b6313defb3e4535c98808d79da1d29d%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151190667743872&amp;sdata=8WwlelechwWHKMy8IfC4PpPRu4phg0n%2BZxFKcgUyd%2BE%3D&amp;reserved=0
    
    
    The following commit(s) were added to refs/heads/develop by this push:
         new 6cbc555  Added Router
    6cbc555 is described below
    
    commit 6cbc5559bcc99bf2ceb3e033747ca3680b3b0d91
    Author: Harbs <ha...@in-tools.com>
    AuthorDate: Mon Jan 20 14:10:42 2020 +0200
    
        Added Router
    ---
     .../Basic/src/main/resources/basic-manifest.xml    |   2 +
     .../royale/org/apache/royale/routing/RouteState.as |  34 +++
     .../royale/org/apache/royale/routing/Router.as     | 274 +++++++++++++++++++++
     3 files changed, 310 insertions(+)
    
    diff --git a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
    index 00e2325..3c30bed 100644
    --- a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
    +++ b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
    @@ -273,4 +273,6 @@
         <component id="ModalDisplay" class="org.apache.royale.html.beads.plugin.ModalDisplay"/>
         <component id="ModalOverlay" class="org.apache.royale.html.beads.plugin.ModalOverlay"/>
     
    +    <component id="Router" class="org.apache.royale.routing.Router"/>
    +
     </componentPackage>
    diff --git a/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
    new file mode 100644
    index 0000000..84fcc4c
    --- /dev/null
    +++ b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
    @@ -0,0 +1,34 @@
    +////////////////////////////////////////////////////////////////////////////////
    +//
    +//  Licensed to the Apache Software Foundation (ASF) under one or more
    +//  contributor license agreements.  See the NOTICE file distributed with
    +//  this work for additional information regarding copyright ownership.
    +//  The ASF licenses this file to You under the Apache License, Version 2.0
    +//  (the "License"); you may not use this file except in compliance with
    +//  the License.  You may obtain a copy of the License at
    +//
    +//      https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7C4b6313defb3e4535c98808d79da1d29d%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151190667743872&amp;sdata=lOqUZl4l%2FMj28XKuqVcIpSAWIBdIXy0c9JmkAzjYx28%3D&amp;reserved=0
    +//
    +//  Unless required by applicable law or agreed to in writing, software
    +//  distributed under the License is distributed on an "AS IS" BASIS,
    +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +//  See the License for the specific language governing permissions and
    +//  limitations under the License.
    +//
    +////////////////////////////////////////////////////////////////////////////////
    +package org.apache.royale.routing
    +{
    +  public class RouteState
    +  {
    +    public function RouteState(state:String="",title:String="")
    +    {
    +      this.state = state;
    +      this.title = title;
    +
    +    }
    +    public var state:String;
    +    public var title:String;
    +    public var parameters:Object;
    +    public var path:Array;
    +  }
    +}
    \ No newline at end of file
    diff --git a/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
    new file mode 100644
    index 0000000..98b9fc6
    --- /dev/null
    +++ b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
    @@ -0,0 +1,274 @@
    +////////////////////////////////////////////////////////////////////////////////
    +//
    +//  Licensed to the Apache Software Foundation (ASF) under one or more
    +//  contributor license agreements.  See the NOTICE file distributed with
    +//  this work for additional information regarding copyright ownership.
    +//  The ASF licenses this file to You under the Apache License, Version 2.0
    +//  (the "License"); you may not use this file except in compliance with
    +//  the License.  You may obtain a copy of the License at
    +//
    +//      https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7C4b6313defb3e4535c98808d79da1d29d%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151190667743872&amp;sdata=lOqUZl4l%2FMj28XKuqVcIpSAWIBdIXy0c9JmkAzjYx28%3D&amp;reserved=0
    +//
    +//  Unless required by applicable law or agreed to in writing, software
    +//  distributed under the License is distributed on an "AS IS" BASIS,
    +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +//  See the License for the specific language governing permissions and
    +//  limitations under the License.
    +//
    +////////////////////////////////////////////////////////////////////////////////
    +package org.apache.royale.routing
    +{
    +  import org.apache.royale.core.DispatcherBead;
    +  import org.apache.royale.core.IStrand;
    +  import org.apache.royale.debugging.assert;
    +  import org.apache.royale.core.IStatesObject;
    +  import org.apache.royale.events.Event;
    +  import org.apache.royale.core.IInitialViewApplication;
    +    /**
    +     *  Dispatched when the state is changed.
    +     *
    +     *  @langversion 3.0
    +     *  @playerversion Flash 10.2
    +     *  @playerversion AIR 2.6
    +     *  @productversion Royale 0.9.7
    +     */
    +    [Event(name="stateChange", type="org.apache.royale.events.Event")]
    +
    +    /**
    +     * Router is a bead which automatically handles browsing history.
    +     * It could be attached to any strand, but typically it would be attached to Application or View
    +     * Listen to stateChange events to handle changes to browsing history and use setState and renderState for modifying the history.
    +     * The state of the router can be modified before committing the state changes.
    +     *  @langversion 3.0
    +     *  @playerversion Flash 10.2
    +     *  @playerversion AIR 2.6
    +     *  @productversion Royale 0.9.7
    +     */
    +  public class Router extends DispatcherBead
    +  {
    +    public function Router()
    +    {
    +      
    +    }
    +    /**
    +     * Use this to automatically sync the state of the strand.
    +     * This only works for the state property of the RouterState.
    +     * It also assumes that the strand is an IStatesObject.
    +     * For this to work correctly, it's usually assumed that the bead is attached to the application View
    +     *  @langversion 3.0
    +     *  @playerversion Flash 10.2
    +     *  @playerversion AIR 2.6
    +     *  @productversion Royale 0.9.7
    +     */
    +    public var syncState:Boolean;
    +		override public function set strand(value:IStrand):void
    +		{	
    +			_strand = value;
    +			COMPILE::JS
    +			{
    +				window.addEventListener("hashchange", hashChangeHandler);
    +        initialTitle = document.title;
    +			}
    +      // If it's an Application, listen to applicationComplete
    +      if(_strand is IInitialViewApplication)
    +        listenOnStrand("applicationComplete",onInit);
    +      //Otherwise listen to initComplete
    +      else
    +        listenOnStrand("initComplete",onInit);
    +		}
    +    private function onInit(event:Event):void
    +    {
    +      COMPILE::JS
    +      {
    +        if(location.hash)
    +        {
    +          hashChangeHandler();
    +        }
    +      }
    +    }
    +    private var initialTitle:String;
    +		private function hashChangeHandler():void
    +		{
    +      parseHash();
    +      if(syncState)
    +      {
    +        assert(_strand is IStatesObject,"syncState can only be used on IStatesObjects");
    +        (_strand as IStatesObject).currentState = _routeState.state;
    +      }
    +			dispatchEvent(new Event("stateChange"));
    +		}
    +    private function parseHash():void
    +    {
    +      //TODO SWF implementation
    +      COMPILE::JS
    +      {
    +        var hash:String = location.hash;
    +        var index:int = 0;
    +        if(hash.indexOf("!")==1){
    +          index = 1;
    +        }
    +        hash = hash.slice(index+1);
    +        var paths:Array = hash.split("/");
    +        var statePart:String = paths.pop();
    +        var splitParts:Array = statePart.split("?");
    +        statePart = splitParts[0];
    +        _routeState = new RouteState(statePart,document.title);
    +        _routeState.path = paths;
    +        _routeState.parameters = parseParameters(splitParts[1]);
    +      }
    +    }
    +    private function parseParameters(query:String):Object
    +    {
    +      var urlVars:Object;
    +      if(query){
    +        var vars:Array = query.split("&");
    +        if(vars.length){
    +          urlVars = {};
    +        }
    +        for (var i:int=0;i<vars.length;i++) {
    +            var pair:Array = vars[i].split("=");
    +            urlVars[pair[0]] = pair[1] == undefined ? undefined : decodeURIComponent(pair[1]);
    +        }
    +      }
    +      return urlVars;
    +    }
    +
    +    private function buildHash():String
    +    {
    +      var hash:String = "#!";
    +      if(_routeState.path && routeState.path.length){
    +        hash += (_routeState.path.join("/") + "/");
    +      }
    +      if(_routeState.state){
    +        hash += _routeState.state;
    +      }
    +      hash+= buildParameterString();
    +      return hash;
    +    }
    +    private function buildParameterString():String{
    +      var retVal:String = "";
    +      if(_routeState.parameters){
    +        retVal += "?";
    +        for(var x:String in _routeState.parameters){
    +          retVal += x;
    +          if(_routeState.parameters[x] != undefined){
    +            retVal += "=" + encodeURIComponent(_routeState.parameters[x]);
    +            retVal += "&";
    +          }
    +        }
    +        //remove trailing &
    +        retVal = retVal.slice(0, -1);
    +      }
    +
    +      return retVal;
    +    }
    +
    +    private var _routeState:RouteState;
    +
    +    public function get routeState():RouteState
    +    {
    +      if(!_routeState){
    +        _routeState = new RouteState();
    +      }
    +    	return _routeState;
    +    }
    +
    +    public function set routeState(value:RouteState):void
    +    {
    +    	_routeState = value;
    +    }
    +    /**
    +     * Commits the current state to the browsing history
    +     *  @langversion 3.0
    +     *  @playerversion Flash 10.2
    +     *  @playerversion AIR 2.6
    +     *  @productversion Royale 0.9.7
    +     */
    +    public function setState():void
    +    {
    +      COMPILE::JS
    +      {
    +        window.history.pushState({"title":_routeState.title},_routeState.title,buildHash());
    +        if(_routeState.title)
    +        {
    +          document.title = _routeState.title;
    +        }
    +      }
    +    }
    +    /**
    +     * Same as setState, but also notifies of the state change 
    +     *  @langversion 3.0
    +     *  @playerversion Flash 10.2
    +     *  @playerversion AIR 2.6
    +     *  @productversion Royale 0.9.7
    +     */
    +    public function renderState():void
    +    {
    +      setState();
    +      if(syncState)
    +      {
    +        assert(_strand is IStatesObject,"syncState can only be used on IStatesObjects");
    +        (_strand as IStatesObject).currentState = _routeState.state;
    +      }
    +      dispatchEvent(new Event("stateChange"));
    +    }
    +    private function setTitle():void
    +    {
    +      COMPILE::JS
    +      {
    +        if(window.history.state){
    +          document.title = window.history.state["title"];
    +        } else {
    +          document.title = initialTitle;
    +        }
    +      }
    +    }
    +    /**
    +     * Goes forward in the history
    +     *  @langversion 3.0
    +     *  @playerversion Flash 10.2
    +     *  @playerversion AIR 2.6
    +     *  @productversion Royale 0.9.7
    +     */
    +    public function forward():void{
    +      COMPILE::JS
    +      {
    +         window.history.forward();
    +         setTitle();
    +         parseHash();
    +      }
    +    }
    +    /**
    +     * Goes backwards in the history
    +     *  @langversion 3.0
    +     *  @playerversion Flash 10.2
    +     *  @playerversion AIR 2.6
    +     *  @productversion Royale 0.9.7
    +     */
    +    public function back():void{
    +      COMPILE::JS
    +      {
    +         window.history.back();
    +         setTitle();
    +         parseHash();
    +      }
    +    }
    +
    +    /**
    +     * Moved the specified number of steps (forward or backwards) in the history
    +     * calling it with 0 or no value will reload the page.
    +     *  @langversion 3.0
    +     *  @playerversion Flash 10.2
    +     *  @playerversion AIR 2.6
    +     *  @productversion Royale 0.9.7
    +     */
    +    public function go(steps:int=0):void{
    +      COMPILE::JS
    +      {
    +         window.history.go(steps);
    +         parseHash();
    +      }
    +    }
    +
    +  }
    +}
    \ No newline at end of file
    
    


Re: [royale-asjs] branch develop updated: Added Router

Posted by Harbs <ha...@gmail.com>.
I like that idea.

> On Jan 20, 2020, at 8:13 PM, Carlos Rovira <ca...@apache.org> wrote:
> 
> Other thing could be to create a new library ("Routing"), that could have
> all implementations (easy, and advanced)


Re: [royale-asjs] branch develop updated: Added Router

Posted by Alex Harui <ah...@adobe.com.INVALID>.
Carlos,

ANT does not force all libs.  Royale has chosen to provide a default configuration that provides most libs.  Royale provides other configurations with subsets of libs, as well as one with "all".  The user can specify their own set of libs.

Folks who like Maven don't like the lack of explicit dependency inclusions.  That's why Apache has both Ant and Maven projects.  Some folks have different preferences.  There are no right or wrong answers.  There are trade-offs to Maven as well.

In Royale, we want to give our users choices.  Users should be able to grab a single component from a SWC and use it with other SWCs although there may be some interoperability issues in some configurations.  We don't want to say it is wrong to use a single component from a SWC.

My 2 cents,
-Alex

On 1/20/20, 10:43 AM, "Carlos Rovira" <ca...@apache.org> wrote:

    Hi Alex,
    
    I think one of the problems is something I just get to know recently in
    other discussion. With ANT all SWCs are available. With Maven you set
    dependencies when you need it. I don't like how ANT manages it (don't know
    if is something we set that way, or something ANT imposes). I think having
    all libs available, will potentially generate various issues. I remember
    put a list in other thread, but I'll put here what I remember:
    
    1.- Having all classes available can make users and developers use
    definitions that can entangle libraries unnecessarily if don't have special
    care. Is easy to go fast and depend on something that a library makes
    available for you instead of taking the time to use some interfaces or make
    the code more smart to not use certain dependencies. Having all classes at
    hand does not help on this. While having just the set of libraries that you
    really required will ensure you use just the code you should use. In case
    you can't will mean something must be refactored to offer the right
    structures, libraries and definitions to the user.
    
    2.- A usability thing (not as dangerous as point 1), is that you end having
    in IDEs all the classes. That means you can have 7/8 Button classes, and
    you probably only want just 1. If I work with Jewel, probably will want
    just Jewel Button, and not having in code intelligence the rest (buttons
    from basic, express, createjs, jQuery, mdl, etc...). It's a bit cumbersome
    to go through all Button classes hitting CTRL+SPACE on and IDE. That can be
    solved creating configs, but that's not an easy task, and a bit cumbersome
    to do, and just the opposite to PAYG applied to how to configure a project.
    
    We have other things like the CSS you commented or the extra processing of
    classes that will never be needed, but maybe we're going a bit off topic
    with this.
    I think far beyond other ANT/MAVEN things, all build systems should put
    available all libs to use, but the user should enable each one to avoid
    potential problems and ensure codification is done in the proper way,
    without mixing definitions that can pull from a tree or other ones not
    wanted, enforcing PAYG.
    


Re: [royale-asjs] branch develop updated: Added Router

Posted by Carlos Rovira <ca...@apache.org>.
Hi Alex,

I think one of the problems is something I just get to know recently in
other discussion. With ANT all SWCs are available. With Maven you set
dependencies when you need it. I don't like how ANT manages it (don't know
if is something we set that way, or something ANT imposes). I think having
all libs available, will potentially generate various issues. I remember
put a list in other thread, but I'll put here what I remember:

1.- Having all classes available can make users and developers use
definitions that can entangle libraries unnecessarily if don't have special
care. Is easy to go fast and depend on something that a library makes
available for you instead of taking the time to use some interfaces or make
the code more smart to not use certain dependencies. Having all classes at
hand does not help on this. While having just the set of libraries that you
really required will ensure you use just the code you should use. In case
you can't will mean something must be refactored to offer the right
structures, libraries and definitions to the user.

2.- A usability thing (not as dangerous as point 1), is that you end having
in IDEs all the classes. That means you can have 7/8 Button classes, and
you probably only want just 1. If I work with Jewel, probably will want
just Jewel Button, and not having in code intelligence the rest (buttons
from basic, express, createjs, jQuery, mdl, etc...). It's a bit cumbersome
to go through all Button classes hitting CTRL+SPACE on and IDE. That can be
solved creating configs, but that's not an easy task, and a bit cumbersome
to do, and just the opposite to PAYG applied to how to configure a project.

We have other things like the CSS you commented or the extra processing of
classes that will never be needed, but maybe we're going a bit off topic
with this.
I think far beyond other ANT/MAVEN things, all build systems should put
available all libs to use, but the user should enable each one to avoid
potential problems and ensure codification is done in the proper way,
without mixing definitions that can pull from a tree or other ones not
wanted, enforcing PAYG.

Re: [royale-asjs] branch develop updated: Added Router

Posted by Alex Harui <ah...@adobe.com.INVALID>.

On 1/20/20, 10:13 AM, "Carlos Rovira" <ca...@apache.org> wrote:

    Hi,
    
    don't think so. I don't use Express at all. But will use Router, and I
    think many others will do.
    I see it as a Basic bead, since Express is a UI Set for preconfigured Basic
    components.
    but don't see a need to make an App like TDJ, add express lib to the set of
    needed libraries just for one class.
    Other thing could be to create a new library ("Routing"), that could have
    all implementations (easy, and advanced)
    
In the future, many people will hopefully be able to use a single component from a SWC.  Maybe there are some CSS sharing issues now, but we need to resolve them.  If someone wants to add a new SWC, fine, but they must also update the release scripts as well.

Ideally, ths "full" Routing implementation would be composited from separate beads and utility functions.  Otherwise, when we do create more basic implementations, we'll either duplicate code or will finally get around to refactoring the current implementation, and then it will be more obvious it should go in Express.

-Alex

    just my 2
    
    El lun., 20 ene. 2020 a las 18:33, Alex Harui (<ah...@adobe.com.invalid>)
    escribió:
    
    >
    >
    > On 1/20/20, 9:27 AM, "Harbs" <ha...@gmail.com> wrote:
    >
    >     Yeah. I thought about subclassing HashChangeNotifierBead and the
    > version with Title, but almost all the code would have needed to be
    > overridden (i.e. I’m auto-stipping off the hash, etc.), so I decided to
    > write it from scratch.
    >
    >     The bead was not intended to be a lightweight PAYG bead. If someone
    > wants very lightweight, they should use the Notifier beads. It’s meant to
    > be as drop-in as possible to make it easier on the developer.
    >
    > IMO, in that case, it should go in Express not, Basic.
    >
    > -Alex
    >
    >     > On Jan 20, 2020, at 6:41 PM, Alex Harui <ah...@adobe.com.INVALID>
    > wrote:
    >     >
    >     > Nit-picky comments:
    >     >
    >     > 1) there is already a bead that watches location.hash.  It might be
    > worth using it to share code
    >     > 2) forward/backward/go/title doesn't seem PAYG to me.  I can imagine
    > lots of users won't need it, or might use it independently of routing
    > (especially Title).
    >     >
    >     > My 2 cents,
    >     > -Alex
    >     >
    >     > On 1/20/20, 4:11 AM, "harbs@apache.org <ma...@apache.org>" <
    > harbs@apache.org <ma...@apache.org>> wrote:
    >     >
    >     >    This is an automated email from the ASF dual-hosted git
    > repository.
    >     >
    >     >    harbs pushed a commit to branch develop
    >     >    in repository
    > https://nam04.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&amp;data=02%7C01%7Caharui%40adobe.com%7C00d05a524e8d4b885b8708d79dd46e7a%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151408025782002&amp;sdata=c6EX3o59qj2bPTbGrLaAVpSVZueOBloXgvPL7aQ2iTk%3D&amp;reserved=0
    > <
    > https://nam04.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&amp;data=02%7C01%7Caharui%40adobe.com%7C00d05a524e8d4b885b8708d79dd46e7a%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151408025782002&amp;sdata=c6EX3o59qj2bPTbGrLaAVpSVZueOBloXgvPL7aQ2iTk%3D&amp;reserved=0
    > >
    >     >
    >     >
    >     >    The following commit(s) were added to refs/heads/develop by this
    > push:
    >     >         new 6cbc555  Added Router
    >     >    6cbc555 is described below
    >     >
    >     >    commit 6cbc5559bcc99bf2ceb3e033747ca3680b3b0d91
    >     >    Author: Harbs <harbs@in-tools.com <ma...@in-tools.com>>
    >     >    AuthorDate: Mon Jan 20 14:10:42 2020 +0200
    >     >
    >     >        Added Router
    >     >    ---
    >     >     .../Basic/src/main/resources/basic-manifest.xml    |   2 +
    >     >     .../royale/org/apache/royale/routing/RouteState.as |  34 +++
    >     >     .../royale/org/apache/royale/routing/Router.as     | 274
    > +++++++++++++++++++++
    >     >     3 files changed, 310 insertions(+)
    >     >
    >     >    diff --git
    > a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
    > b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
    >     >    index 00e2325..3c30bed 100644
    >     >    ---
    > a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
    >     >    +++
    > b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
    >     >    @@ -273,4 +273,6 @@
    >     >         <component id="ModalDisplay"
    > class="org.apache.royale.html.beads.plugin.ModalDisplay"/>
    >     >         <component id="ModalOverlay"
    > class="org.apache.royale.html.beads.plugin.ModalOverlay"/>
    >     >
    >     >    +    <component id="Router"
    > class="org.apache.royale.routing.Router"/>
    >     >    +
    >     >     </componentPackage>
    >     >    diff --git
    > a/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
    > b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
    >     >    new file mode 100644
    >     >    index 0000000..84fcc4c
    >     >    --- /dev/null
    >     >    +++
    > b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
    >     >    @@ -0,0 +1,34 @@
    >     >
    > +////////////////////////////////////////////////////////////////////////////////
    >     >    +//
    >     >    +//  Licensed to the Apache Software Foundation (ASF) under one
    > or more
    >     >    +//  contributor license agreements.  See the NOTICE file
    > distributed with
    >     >    +//  this work for additional information regarding copyright
    > ownership.
    >     >    +//  The ASF licenses this file to You under the Apache License,
    > Version 2.0
    >     >    +//  (the "License"); you may not use this file except in
    > compliance with
    >     >    +//  the License.  You may obtain a copy of the License at
    >     >    +//
    >     >    +//
    > https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7C00d05a524e8d4b885b8708d79dd46e7a%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151408025786987&amp;sdata=lPwSPg539sFLGvCaV7lgRhQ4EbdZqrm8wfr45VFvFFQ%3D&amp;reserved=0
    > <
    > https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7C00d05a524e8d4b885b8708d79dd46e7a%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151408025786987&amp;sdata=lPwSPg539sFLGvCaV7lgRhQ4EbdZqrm8wfr45VFvFFQ%3D&amp;reserved=0
    > >
    >     >    +//
    >     >    +//  Unless required by applicable law or agreed to in writing,
    > software
    >     >    +//  distributed under the License is distributed on an "AS IS"
    > BASIS,
    >     >    +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
    > or implied.
    >     >    +//  See the License for the specific language governing
    > permissions and
    >     >    +//  limitations under the License.
    >     >    +//
    >     >
    > +////////////////////////////////////////////////////////////////////////////////
    >     >    +package org.apache.royale.routing
    >     >    +{
    >     >    +  public class RouteState
    >     >    +  {
    >     >    +    public function RouteState(state:String="",title:String="")
    >     >    +    {
    >     >    +      this.state = state;
    >     >    +      this.title = title;
    >     >    +
    >     >    +    }
    >     >    +    public var state:String;
    >     >    +    public var title:String;
    >     >    +    public var parameters:Object;
    >     >    +    public var path:Array;
    >     >    +  }
    >     >    +}
    >     >    \ No newline at end of file
    >     >    diff --git
    > a/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
    > b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
    >     >    new file mode 100644
    >     >    index 0000000..98b9fc6
    >     >    --- /dev/null
    >     >    +++
    > b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
    >     >    @@ -0,0 +1,274 @@
    >     >
    > +////////////////////////////////////////////////////////////////////////////////
    >     >    +//
    >     >    +//  Licensed to the Apache Software Foundation (ASF) under one
    > or more
    >     >    +//  contributor license agreements.  See the NOTICE file
    > distributed with
    >     >    +//  this work for additional information regarding copyright
    > ownership.
    >     >    +//  The ASF licenses this file to You under the Apache License,
    > Version 2.0
    >     >    +//  (the "License"); you may not use this file except in
    > compliance with
    >     >    +//  the License.  You may obtain a copy of the License at
    >     >    +//
    >     >    +//
    > https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7C00d05a524e8d4b885b8708d79dd46e7a%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151408025786987&amp;sdata=lPwSPg539sFLGvCaV7lgRhQ4EbdZqrm8wfr45VFvFFQ%3D&amp;reserved=0
    > <
    > https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7C00d05a524e8d4b885b8708d79dd46e7a%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151408025786987&amp;sdata=lPwSPg539sFLGvCaV7lgRhQ4EbdZqrm8wfr45VFvFFQ%3D&amp;reserved=0
    > >
    >     >    +//
    >     >    +//  Unless required by applicable law or agreed to in writing,
    > software
    >     >    +//  distributed under the License is distributed on an "AS IS"
    > BASIS,
    >     >    +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
    > or implied.
    >     >    +//  See the License for the specific language governing
    > permissions and
    >     >    +//  limitations under the License.
    >     >    +//
    >     >
    > +////////////////////////////////////////////////////////////////////////////////
    >     >    +package org.apache.royale.routing
    >     >    +{
    >     >    +  import org.apache.royale.core.DispatcherBead;
    >     >    +  import org.apache.royale.core.IStrand;
    >     >    +  import org.apache.royale.debugging.assert;
    >     >    +  import org.apache.royale.core.IStatesObject;
    >     >    +  import org.apache.royale.events.Event;
    >     >    +  import org.apache.royale.core.IInitialViewApplication;
    >     >    +    /**
    >     >    +     *  Dispatched when the state is changed.
    >     >    +     *
    >     >    +     *  @langversion 3.0
    >     >    +     *  @playerversion Flash 10.2
    >     >    +     *  @playerversion AIR 2.6
    >     >    +     *  @productversion Royale 0.9.7
    >     >    +     */
    >     >    +    [Event(name="stateChange",
    > type="org.apache.royale.events.Event")]
    >     >    +
    >     >    +    /**
    >     >    +     * Router is a bead which automatically handles browsing
    > history.
    >     >    +     * It could be attached to any strand, but typically it
    > would be attached to Application or View
    >     >    +     * Listen to stateChange events to handle changes to
    > browsing history and use setState and renderState for modifying the history.
    >     >    +     * The state of the router can be modified before committing
    > the state changes.
    >     >    +     *  @langversion 3.0
    >     >    +     *  @playerversion Flash 10.2
    >     >    +     *  @playerversion AIR 2.6
    >     >    +     *  @productversion Royale 0.9.7
    >     >    +     */
    >     >    +  public class Router extends DispatcherBead
    >     >    +  {
    >     >    +    public function Router()
    >     >    +    {
    >     >    +
    >     >    +    }
    >     >    +    /**
    >     >    +     * Use this to automatically sync the state of the strand.
    >     >    +     * This only works for the state property of the RouterState.
    >     >    +     * It also assumes that the strand is an IStatesObject.
    >     >    +     * For this to work correctly, it's usually assumed that the
    > bead is attached to the application View
    >     >    +     *  @langversion 3.0
    >     >    +     *  @playerversion Flash 10.2
    >     >    +     *  @playerversion AIR 2.6
    >     >    +     *  @productversion Royale 0.9.7
    >     >    +     */
    >     >    +    public var syncState:Boolean;
    >     >    +              override public function set
    > strand(value:IStrand):void
    >     >    +              {
    >     >    +                      _strand = value;
    >     >    +                      COMPILE::JS
    >     >    +                      {
    >     >    +
    > window.addEventListener("hashchange", hashChangeHandler);
    >     >    +        initialTitle = document.title;
    >     >    +                      }
    >     >    +      // If it's an Application, listen to applicationComplete
    >     >    +      if(_strand is IInitialViewApplication)
    >     >    +        listenOnStrand("applicationComplete",onInit);
    >     >    +      //Otherwise listen to initComplete
    >     >    +      else
    >     >    +        listenOnStrand("initComplete",onInit);
    >     >    +              }
    >     >    +    private function onInit(event:Event):void
    >     >    +    {
    >     >    +      COMPILE::JS
    >     >    +      {
    >     >    +        if(location.hash)
    >     >    +        {
    >     >    +          hashChangeHandler();
    >     >    +        }
    >     >    +      }
    >     >    +    }
    >     >    +    private var initialTitle:String;
    >     >    +              private function hashChangeHandler():void
    >     >    +              {
    >     >    +      parseHash();
    >     >    +      if(syncState)
    >     >    +      {
    >     >    +        assert(_strand is IStatesObject,"syncState can only be
    > used on IStatesObjects");
    >     >    +        (_strand as IStatesObject).currentState =
    > _routeState.state;
    >     >    +      }
    >     >    +                      dispatchEvent(new Event("stateChange"));
    >     >    +              }
    >     >    +    private function parseHash():void
    >     >    +    {
    >     >    +      //TODO SWF implementation
    >     >    +      COMPILE::JS
    >     >    +      {
    >     >    +        var hash:String = location.hash;
    >     >    +        var index:int = 0;
    >     >    +        if(hash.indexOf("!")==1){
    >     >    +          index = 1;
    >     >    +        }
    >     >    +        hash = hash.slice(index+1);
    >     >    +        var paths:Array = hash.split("/");
    >     >    +        var statePart:String = paths.pop();
    >     >    +        var splitParts:Array = statePart.split("?");
    >     >    +        statePart = splitParts[0];
    >     >    +        _routeState = new RouteState(statePart,document.title);
    >     >    +        _routeState.path = paths;
    >     >    +        _routeState.parameters = parseParameters(splitParts[1]);
    >     >    +      }
    >     >    +    }
    >     >    +    private function parseParameters(query:String):Object
    >     >    +    {
    >     >    +      var urlVars:Object;
    >     >    +      if(query){
    >     >    +        var vars:Array = query.split("&");
    >     >    +        if(vars.length){
    >     >    +          urlVars = {};
    >     >    +        }
    >     >    +        for (var i:int=0;i<vars.length;i++) {
    >     >    +            var pair:Array = vars[i].split("=");
    >     >    +            urlVars[pair[0]] = pair[1] == undefined ? undefined
    > : decodeURIComponent(pair[1]);
    >     >    +        }
    >     >    +      }
    >     >    +      return urlVars;
    >     >    +    }
    >     >    +
    >     >    +    private function buildHash():String
    >     >    +    {
    >     >    +      var hash:String = "#!";
    >     >    +      if(_routeState.path && routeState.path.length){
    >     >    +        hash += (_routeState.path.join("/") + "/");
    >     >    +      }
    >     >    +      if(_routeState.state){
    >     >    +        hash += _routeState.state;
    >     >    +      }
    >     >    +      hash+= buildParameterString();
    >     >    +      return hash;
    >     >    +    }
    >     >    +    private function buildParameterString():String{
    >     >    +      var retVal:String = "";
    >     >    +      if(_routeState.parameters){
    >     >    +        retVal += "?";
    >     >    +        for(var x:String in _routeState.parameters){
    >     >    +          retVal += x;
    >     >    +          if(_routeState.parameters[x] != undefined){
    >     >    +            retVal += "=" +
    > encodeURIComponent(_routeState.parameters[x]);
    >     >    +            retVal += "&";
    >     >    +          }
    >     >    +        }
    >     >    +        //remove trailing &
    >     >    +        retVal = retVal.slice(0, -1);
    >     >    +      }
    >     >    +
    >     >    +      return retVal;
    >     >    +    }
    >     >    +
    >     >    +    private var _routeState:RouteState;
    >     >    +
    >     >    +    public function get routeState():RouteState
    >     >    +    {
    >     >    +      if(!_routeState){
    >     >    +        _routeState = new RouteState();
    >     >    +      }
    >     >    +      return _routeState;
    >     >    +    }
    >     >    +
    >     >    +    public function set routeState(value:RouteState):void
    >     >    +    {
    >     >    +      _routeState = value;
    >     >    +    }
    >     >    +    /**
    >     >    +     * Commits the current state to the browsing history
    >     >    +     *  @langversion 3.0
    >     >    +     *  @playerversion Flash 10.2
    >     >    +     *  @playerversion AIR 2.6
    >     >    +     *  @productversion Royale 0.9.7
    >     >    +     */
    >     >    +    public function setState():void
    >     >    +    {
    >     >    +      COMPILE::JS
    >     >    +      {
    >     >    +
    > window.history.pushState({"title":_routeState.title},_routeState.title,buildHash());
    >     >    +        if(_routeState.title)
    >     >    +        {
    >     >    +          document.title = _routeState.title;
    >     >    +        }
    >     >    +      }
    >     >    +    }
    >     >    +    /**
    >     >    +     * Same as setState, but also notifies of the state change
    >     >    +     *  @langversion 3.0
    >     >    +     *  @playerversion Flash 10.2
    >     >    +     *  @playerversion AIR 2.6
    >     >    +     *  @productversion Royale 0.9.7
    >     >    +     */
    >     >    +    public function renderState():void
    >     >    +    {
    >     >    +      setState();
    >     >    +      if(syncState)
    >     >    +      {
    >     >    +        assert(_strand is IStatesObject,"syncState can only be
    > used on IStatesObjects");
    >     >    +        (_strand as IStatesObject).currentState =
    > _routeState.state;
    >     >    +      }
    >     >    +      dispatchEvent(new Event("stateChange"));
    >     >    +    }
    >     >    +    private function setTitle():void
    >     >    +    {
    >     >    +      COMPILE::JS
    >     >    +      {
    >     >    +        if(window.history.state){
    >     >    +          document.title = window.history.state["title"];
    >     >    +        } else {
    >     >    +          document.title = initialTitle;
    >     >    +        }
    >     >    +      }
    >     >    +    }
    >     >    +    /**
    >     >    +     * Goes forward in the history
    >     >    +     *  @langversion 3.0
    >     >    +     *  @playerversion Flash 10.2
    >     >    +     *  @playerversion AIR 2.6
    >     >    +     *  @productversion Royale 0.9.7
    >     >    +     */
    >     >    +    public function forward():void{
    >     >    +      COMPILE::JS
    >     >    +      {
    >     >    +         window.history.forward();
    >     >    +         setTitle();
    >     >    +         parseHash();
    >     >    +      }
    >     >    +    }
    >     >    +    /**
    >     >    +     * Goes backwards in the history
    >     >    +     *  @langversion 3.0
    >     >    +     *  @playerversion Flash 10.2
    >     >    +     *  @playerversion AIR 2.6
    >     >    +     *  @productversion Royale 0.9.7
    >     >    +     */
    >     >    +    public function back():void{
    >     >    +      COMPILE::JS
    >     >    +      {
    >     >    +         window.history.back();
    >     >    +         setTitle();
    >     >    +         parseHash();
    >     >    +      }
    >     >    +    }
    >     >    +
    >     >    +    /**
    >     >    +     * Moved the specified number of steps (forward or
    > backwards) in the history
    >     >    +     * calling it with 0 or no value will reload the page.
    >     >    +     *  @langversion 3.0
    >     >    +     *  @playerversion Flash 10.2
    >     >    +     *  @playerversion AIR 2.6
    >     >    +     *  @productversion Royale 0.9.7
    >     >    +     */
    >     >    +    public function go(steps:int=0):void{
    >     >    +      COMPILE::JS
    >     >    +      {
    >     >    +         window.history.go(steps);
    >     >    +         parseHash();
    >     >    +      }
    >     >    +    }
    >     >    +
    >     >    +  }
    >     >    +}
    >     >    \ No newline at end of file
    >
    >
    >
    >
    
    -- 
    Carlos Rovira
    https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fabout.me%2Fcarlosrovira&amp;data=02%7C01%7Caharui%40adobe.com%7C00d05a524e8d4b885b8708d79dd46e7a%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151408025791973&amp;sdata=p2BJS0GEUCoPsr0WBZIODOfZmvKJ6R20LwiPzPOEQCY%3D&amp;reserved=0
    


Re: [royale-asjs] branch develop updated: Added Router

Posted by Carlos Rovira <ca...@apache.org>.
Hi,

don't think so. I don't use Express at all. But will use Router, and I
think many others will do.
I see it as a Basic bead, since Express is a UI Set for preconfigured Basic
components.
but don't see a need to make an App like TDJ, add express lib to the set of
needed libraries just for one class.
Other thing could be to create a new library ("Routing"), that could have
all implementations (easy, and advanced)

just my 2

El lun., 20 ene. 2020 a las 18:33, Alex Harui (<ah...@adobe.com.invalid>)
escribió:

>
>
> On 1/20/20, 9:27 AM, "Harbs" <ha...@gmail.com> wrote:
>
>     Yeah. I thought about subclassing HashChangeNotifierBead and the
> version with Title, but almost all the code would have needed to be
> overridden (i.e. I’m auto-stipping off the hash, etc.), so I decided to
> write it from scratch.
>
>     The bead was not intended to be a lightweight PAYG bead. If someone
> wants very lightweight, they should use the Notifier beads. It’s meant to
> be as drop-in as possible to make it easier on the developer.
>
> IMO, in that case, it should go in Express not, Basic.
>
> -Alex
>
>     > On Jan 20, 2020, at 6:41 PM, Alex Harui <ah...@adobe.com.INVALID>
> wrote:
>     >
>     > Nit-picky comments:
>     >
>     > 1) there is already a bead that watches location.hash.  It might be
> worth using it to share code
>     > 2) forward/backward/go/title doesn't seem PAYG to me.  I can imagine
> lots of users won't need it, or might use it independently of routing
> (especially Title).
>     >
>     > My 2 cents,
>     > -Alex
>     >
>     > On 1/20/20, 4:11 AM, "harbs@apache.org <ma...@apache.org>" <
> harbs@apache.org <ma...@apache.org>> wrote:
>     >
>     >    This is an automated email from the ASF dual-hosted git
> repository.
>     >
>     >    harbs pushed a commit to branch develop
>     >    in repository
> https://nam04.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297043799&amp;sdata=UDJSMyIC%2FDXJZCm0M5xDb3GGNzXRyhMUe7bHu0anz%2Fc%3D&amp;reserved=0
> <
> https://nam04.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297043799&amp;sdata=UDJSMyIC%2FDXJZCm0M5xDb3GGNzXRyhMUe7bHu0anz%2Fc%3D&amp;reserved=0
> >
>     >
>     >
>     >    The following commit(s) were added to refs/heads/develop by this
> push:
>     >         new 6cbc555  Added Router
>     >    6cbc555 is described below
>     >
>     >    commit 6cbc5559bcc99bf2ceb3e033747ca3680b3b0d91
>     >    Author: Harbs <harbs@in-tools.com <ma...@in-tools.com>>
>     >    AuthorDate: Mon Jan 20 14:10:42 2020 +0200
>     >
>     >        Added Router
>     >    ---
>     >     .../Basic/src/main/resources/basic-manifest.xml    |   2 +
>     >     .../royale/org/apache/royale/routing/RouteState.as |  34 +++
>     >     .../royale/org/apache/royale/routing/Router.as     | 274
> +++++++++++++++++++++
>     >     3 files changed, 310 insertions(+)
>     >
>     >    diff --git
> a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
> b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
>     >    index 00e2325..3c30bed 100644
>     >    ---
> a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
>     >    +++
> b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
>     >    @@ -273,4 +273,6 @@
>     >         <component id="ModalDisplay"
> class="org.apache.royale.html.beads.plugin.ModalDisplay"/>
>     >         <component id="ModalOverlay"
> class="org.apache.royale.html.beads.plugin.ModalOverlay"/>
>     >
>     >    +    <component id="Router"
> class="org.apache.royale.routing.Router"/>
>     >    +
>     >     </componentPackage>
>     >    diff --git
> a/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
> b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
>     >    new file mode 100644
>     >    index 0000000..84fcc4c
>     >    --- /dev/null
>     >    +++
> b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
>     >    @@ -0,0 +1,34 @@
>     >
> +////////////////////////////////////////////////////////////////////////////////
>     >    +//
>     >    +//  Licensed to the Apache Software Foundation (ASF) under one
> or more
>     >    +//  contributor license agreements.  See the NOTICE file
> distributed with
>     >    +//  this work for additional information regarding copyright
> ownership.
>     >    +//  The ASF licenses this file to You under the Apache License,
> Version 2.0
>     >    +//  (the "License"); you may not use this file except in
> compliance with
>     >    +//  the License.  You may obtain a copy of the License at
>     >    +//
>     >    +//
> https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297043799&amp;sdata=dS98z1bAFk5RE0uJ6WmdDTvkuXIMbrQIfyfy9aGNBEk%3D&amp;reserved=0
> <
> https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297043799&amp;sdata=dS98z1bAFk5RE0uJ6WmdDTvkuXIMbrQIfyfy9aGNBEk%3D&amp;reserved=0
> >
>     >    +//
>     >    +//  Unless required by applicable law or agreed to in writing,
> software
>     >    +//  distributed under the License is distributed on an "AS IS"
> BASIS,
>     >    +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
> or implied.
>     >    +//  See the License for the specific language governing
> permissions and
>     >    +//  limitations under the License.
>     >    +//
>     >
> +////////////////////////////////////////////////////////////////////////////////
>     >    +package org.apache.royale.routing
>     >    +{
>     >    +  public class RouteState
>     >    +  {
>     >    +    public function RouteState(state:String="",title:String="")
>     >    +    {
>     >    +      this.state = state;
>     >    +      this.title = title;
>     >    +
>     >    +    }
>     >    +    public var state:String;
>     >    +    public var title:String;
>     >    +    public var parameters:Object;
>     >    +    public var path:Array;
>     >    +  }
>     >    +}
>     >    \ No newline at end of file
>     >    diff --git
> a/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
> b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
>     >    new file mode 100644
>     >    index 0000000..98b9fc6
>     >    --- /dev/null
>     >    +++
> b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
>     >    @@ -0,0 +1,274 @@
>     >
> +////////////////////////////////////////////////////////////////////////////////
>     >    +//
>     >    +//  Licensed to the Apache Software Foundation (ASF) under one
> or more
>     >    +//  contributor license agreements.  See the NOTICE file
> distributed with
>     >    +//  this work for additional information regarding copyright
> ownership.
>     >    +//  The ASF licenses this file to You under the Apache License,
> Version 2.0
>     >    +//  (the "License"); you may not use this file except in
> compliance with
>     >    +//  the License.  You may obtain a copy of the License at
>     >    +//
>     >    +//
> https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297043799&amp;sdata=dS98z1bAFk5RE0uJ6WmdDTvkuXIMbrQIfyfy9aGNBEk%3D&amp;reserved=0
> <
> https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297053790&amp;sdata=NY4972Z6X3a%2BHWhuAA9r2ViKiWpNJQIzaCcQlkH4TLI%3D&amp;reserved=0
> >
>     >    +//
>     >    +//  Unless required by applicable law or agreed to in writing,
> software
>     >    +//  distributed under the License is distributed on an "AS IS"
> BASIS,
>     >    +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
> or implied.
>     >    +//  See the License for the specific language governing
> permissions and
>     >    +//  limitations under the License.
>     >    +//
>     >
> +////////////////////////////////////////////////////////////////////////////////
>     >    +package org.apache.royale.routing
>     >    +{
>     >    +  import org.apache.royale.core.DispatcherBead;
>     >    +  import org.apache.royale.core.IStrand;
>     >    +  import org.apache.royale.debugging.assert;
>     >    +  import org.apache.royale.core.IStatesObject;
>     >    +  import org.apache.royale.events.Event;
>     >    +  import org.apache.royale.core.IInitialViewApplication;
>     >    +    /**
>     >    +     *  Dispatched when the state is changed.
>     >    +     *
>     >    +     *  @langversion 3.0
>     >    +     *  @playerversion Flash 10.2
>     >    +     *  @playerversion AIR 2.6
>     >    +     *  @productversion Royale 0.9.7
>     >    +     */
>     >    +    [Event(name="stateChange",
> type="org.apache.royale.events.Event")]
>     >    +
>     >    +    /**
>     >    +     * Router is a bead which automatically handles browsing
> history.
>     >    +     * It could be attached to any strand, but typically it
> would be attached to Application or View
>     >    +     * Listen to stateChange events to handle changes to
> browsing history and use setState and renderState for modifying the history.
>     >    +     * The state of the router can be modified before committing
> the state changes.
>     >    +     *  @langversion 3.0
>     >    +     *  @playerversion Flash 10.2
>     >    +     *  @playerversion AIR 2.6
>     >    +     *  @productversion Royale 0.9.7
>     >    +     */
>     >    +  public class Router extends DispatcherBead
>     >    +  {
>     >    +    public function Router()
>     >    +    {
>     >    +
>     >    +    }
>     >    +    /**
>     >    +     * Use this to automatically sync the state of the strand.
>     >    +     * This only works for the state property of the RouterState.
>     >    +     * It also assumes that the strand is an IStatesObject.
>     >    +     * For this to work correctly, it's usually assumed that the
> bead is attached to the application View
>     >    +     *  @langversion 3.0
>     >    +     *  @playerversion Flash 10.2
>     >    +     *  @playerversion AIR 2.6
>     >    +     *  @productversion Royale 0.9.7
>     >    +     */
>     >    +    public var syncState:Boolean;
>     >    +              override public function set
> strand(value:IStrand):void
>     >    +              {
>     >    +                      _strand = value;
>     >    +                      COMPILE::JS
>     >    +                      {
>     >    +
> window.addEventListener("hashchange", hashChangeHandler);
>     >    +        initialTitle = document.title;
>     >    +                      }
>     >    +      // If it's an Application, listen to applicationComplete
>     >    +      if(_strand is IInitialViewApplication)
>     >    +        listenOnStrand("applicationComplete",onInit);
>     >    +      //Otherwise listen to initComplete
>     >    +      else
>     >    +        listenOnStrand("initComplete",onInit);
>     >    +              }
>     >    +    private function onInit(event:Event):void
>     >    +    {
>     >    +      COMPILE::JS
>     >    +      {
>     >    +        if(location.hash)
>     >    +        {
>     >    +          hashChangeHandler();
>     >    +        }
>     >    +      }
>     >    +    }
>     >    +    private var initialTitle:String;
>     >    +              private function hashChangeHandler():void
>     >    +              {
>     >    +      parseHash();
>     >    +      if(syncState)
>     >    +      {
>     >    +        assert(_strand is IStatesObject,"syncState can only be
> used on IStatesObjects");
>     >    +        (_strand as IStatesObject).currentState =
> _routeState.state;
>     >    +      }
>     >    +                      dispatchEvent(new Event("stateChange"));
>     >    +              }
>     >    +    private function parseHash():void
>     >    +    {
>     >    +      //TODO SWF implementation
>     >    +      COMPILE::JS
>     >    +      {
>     >    +        var hash:String = location.hash;
>     >    +        var index:int = 0;
>     >    +        if(hash.indexOf("!")==1){
>     >    +          index = 1;
>     >    +        }
>     >    +        hash = hash.slice(index+1);
>     >    +        var paths:Array = hash.split("/");
>     >    +        var statePart:String = paths.pop();
>     >    +        var splitParts:Array = statePart.split("?");
>     >    +        statePart = splitParts[0];
>     >    +        _routeState = new RouteState(statePart,document.title);
>     >    +        _routeState.path = paths;
>     >    +        _routeState.parameters = parseParameters(splitParts[1]);
>     >    +      }
>     >    +    }
>     >    +    private function parseParameters(query:String):Object
>     >    +    {
>     >    +      var urlVars:Object;
>     >    +      if(query){
>     >    +        var vars:Array = query.split("&");
>     >    +        if(vars.length){
>     >    +          urlVars = {};
>     >    +        }
>     >    +        for (var i:int=0;i<vars.length;i++) {
>     >    +            var pair:Array = vars[i].split("=");
>     >    +            urlVars[pair[0]] = pair[1] == undefined ? undefined
> : decodeURIComponent(pair[1]);
>     >    +        }
>     >    +      }
>     >    +      return urlVars;
>     >    +    }
>     >    +
>     >    +    private function buildHash():String
>     >    +    {
>     >    +      var hash:String = "#!";
>     >    +      if(_routeState.path && routeState.path.length){
>     >    +        hash += (_routeState.path.join("/") + "/");
>     >    +      }
>     >    +      if(_routeState.state){
>     >    +        hash += _routeState.state;
>     >    +      }
>     >    +      hash+= buildParameterString();
>     >    +      return hash;
>     >    +    }
>     >    +    private function buildParameterString():String{
>     >    +      var retVal:String = "";
>     >    +      if(_routeState.parameters){
>     >    +        retVal += "?";
>     >    +        for(var x:String in _routeState.parameters){
>     >    +          retVal += x;
>     >    +          if(_routeState.parameters[x] != undefined){
>     >    +            retVal += "=" +
> encodeURIComponent(_routeState.parameters[x]);
>     >    +            retVal += "&";
>     >    +          }
>     >    +        }
>     >    +        //remove trailing &
>     >    +        retVal = retVal.slice(0, -1);
>     >    +      }
>     >    +
>     >    +      return retVal;
>     >    +    }
>     >    +
>     >    +    private var _routeState:RouteState;
>     >    +
>     >    +    public function get routeState():RouteState
>     >    +    {
>     >    +      if(!_routeState){
>     >    +        _routeState = new RouteState();
>     >    +      }
>     >    +      return _routeState;
>     >    +    }
>     >    +
>     >    +    public function set routeState(value:RouteState):void
>     >    +    {
>     >    +      _routeState = value;
>     >    +    }
>     >    +    /**
>     >    +     * Commits the current state to the browsing history
>     >    +     *  @langversion 3.0
>     >    +     *  @playerversion Flash 10.2
>     >    +     *  @playerversion AIR 2.6
>     >    +     *  @productversion Royale 0.9.7
>     >    +     */
>     >    +    public function setState():void
>     >    +    {
>     >    +      COMPILE::JS
>     >    +      {
>     >    +
> window.history.pushState({"title":_routeState.title},_routeState.title,buildHash());
>     >    +        if(_routeState.title)
>     >    +        {
>     >    +          document.title = _routeState.title;
>     >    +        }
>     >    +      }
>     >    +    }
>     >    +    /**
>     >    +     * Same as setState, but also notifies of the state change
>     >    +     *  @langversion 3.0
>     >    +     *  @playerversion Flash 10.2
>     >    +     *  @playerversion AIR 2.6
>     >    +     *  @productversion Royale 0.9.7
>     >    +     */
>     >    +    public function renderState():void
>     >    +    {
>     >    +      setState();
>     >    +      if(syncState)
>     >    +      {
>     >    +        assert(_strand is IStatesObject,"syncState can only be
> used on IStatesObjects");
>     >    +        (_strand as IStatesObject).currentState =
> _routeState.state;
>     >    +      }
>     >    +      dispatchEvent(new Event("stateChange"));
>     >    +    }
>     >    +    private function setTitle():void
>     >    +    {
>     >    +      COMPILE::JS
>     >    +      {
>     >    +        if(window.history.state){
>     >    +          document.title = window.history.state["title"];
>     >    +        } else {
>     >    +          document.title = initialTitle;
>     >    +        }
>     >    +      }
>     >    +    }
>     >    +    /**
>     >    +     * Goes forward in the history
>     >    +     *  @langversion 3.0
>     >    +     *  @playerversion Flash 10.2
>     >    +     *  @playerversion AIR 2.6
>     >    +     *  @productversion Royale 0.9.7
>     >    +     */
>     >    +    public function forward():void{
>     >    +      COMPILE::JS
>     >    +      {
>     >    +         window.history.forward();
>     >    +         setTitle();
>     >    +         parseHash();
>     >    +      }
>     >    +    }
>     >    +    /**
>     >    +     * Goes backwards in the history
>     >    +     *  @langversion 3.0
>     >    +     *  @playerversion Flash 10.2
>     >    +     *  @playerversion AIR 2.6
>     >    +     *  @productversion Royale 0.9.7
>     >    +     */
>     >    +    public function back():void{
>     >    +      COMPILE::JS
>     >    +      {
>     >    +         window.history.back();
>     >    +         setTitle();
>     >    +         parseHash();
>     >    +      }
>     >    +    }
>     >    +
>     >    +    /**
>     >    +     * Moved the specified number of steps (forward or
> backwards) in the history
>     >    +     * calling it with 0 or no value will reload the page.
>     >    +     *  @langversion 3.0
>     >    +     *  @playerversion Flash 10.2
>     >    +     *  @playerversion AIR 2.6
>     >    +     *  @productversion Royale 0.9.7
>     >    +     */
>     >    +    public function go(steps:int=0):void{
>     >    +      COMPILE::JS
>     >    +      {
>     >    +         window.history.go(steps);
>     >    +         parseHash();
>     >    +      }
>     >    +    }
>     >    +
>     >    +  }
>     >    +}
>     >    \ No newline at end of file
>
>
>
>

-- 
Carlos Rovira
http://about.me/carlosrovira

Re: [royale-asjs] branch develop updated: Added Router

Posted by Alex Harui <ah...@adobe.com.INVALID>.

On 1/20/20, 9:27 AM, "Harbs" <ha...@gmail.com> wrote:

    Yeah. I thought about subclassing HashChangeNotifierBead and the version with Title, but almost all the code would have needed to be overridden (i.e. I’m auto-stipping off the hash, etc.), so I decided to write it from scratch.
    
    The bead was not intended to be a lightweight PAYG bead. If someone wants very lightweight, they should use the Notifier beads. It’s meant to be as drop-in as possible to make it easier on the developer.
    
IMO, in that case, it should go in Express not, Basic.

-Alex

    > On Jan 20, 2020, at 6:41 PM, Alex Harui <ah...@adobe.com.INVALID> wrote:
    > 
    > Nit-picky comments:
    > 
    > 1) there is already a bead that watches location.hash.  It might be worth using it to share code
    > 2) forward/backward/go/title doesn't seem PAYG to me.  I can imagine lots of users won't need it, or might use it independently of routing (especially Title).
    > 
    > My 2 cents,
    > -Alex
    > 
    > On 1/20/20, 4:11 AM, "harbs@apache.org <ma...@apache.org>" <harbs@apache.org <ma...@apache.org>> wrote:
    > 
    >    This is an automated email from the ASF dual-hosted git repository.
    > 
    >    harbs pushed a commit to branch develop
    >    in repository https://nam04.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297043799&amp;sdata=UDJSMyIC%2FDXJZCm0M5xDb3GGNzXRyhMUe7bHu0anz%2Fc%3D&amp;reserved=0 <https://nam04.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297043799&amp;sdata=UDJSMyIC%2FDXJZCm0M5xDb3GGNzXRyhMUe7bHu0anz%2Fc%3D&amp;reserved=0>
    > 
    > 
    >    The following commit(s) were added to refs/heads/develop by this push:
    >         new 6cbc555  Added Router
    >    6cbc555 is described below
    > 
    >    commit 6cbc5559bcc99bf2ceb3e033747ca3680b3b0d91
    >    Author: Harbs <harbs@in-tools.com <ma...@in-tools.com>>
    >    AuthorDate: Mon Jan 20 14:10:42 2020 +0200
    > 
    >        Added Router
    >    ---
    >     .../Basic/src/main/resources/basic-manifest.xml    |   2 +
    >     .../royale/org/apache/royale/routing/RouteState.as |  34 +++
    >     .../royale/org/apache/royale/routing/Router.as     | 274 +++++++++++++++++++++
    >     3 files changed, 310 insertions(+)
    > 
    >    diff --git a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
    >    index 00e2325..3c30bed 100644
    >    --- a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
    >    +++ b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
    >    @@ -273,4 +273,6 @@
    >         <component id="ModalDisplay" class="org.apache.royale.html.beads.plugin.ModalDisplay"/>
    >         <component id="ModalOverlay" class="org.apache.royale.html.beads.plugin.ModalOverlay"/>
    > 
    >    +    <component id="Router" class="org.apache.royale.routing.Router"/>
    >    +
    >     </componentPackage>
    >    diff --git a/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
    >    new file mode 100644
    >    index 0000000..84fcc4c
    >    --- /dev/null
    >    +++ b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
    >    @@ -0,0 +1,34 @@
    >    +////////////////////////////////////////////////////////////////////////////////
    >    +//
    >    +//  Licensed to the Apache Software Foundation (ASF) under one or more
    >    +//  contributor license agreements.  See the NOTICE file distributed with
    >    +//  this work for additional information regarding copyright ownership.
    >    +//  The ASF licenses this file to You under the Apache License, Version 2.0
    >    +//  (the "License"); you may not use this file except in compliance with
    >    +//  the License.  You may obtain a copy of the License at
    >    +//
    >    +//      https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297043799&amp;sdata=dS98z1bAFk5RE0uJ6WmdDTvkuXIMbrQIfyfy9aGNBEk%3D&amp;reserved=0 <https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297043799&amp;sdata=dS98z1bAFk5RE0uJ6WmdDTvkuXIMbrQIfyfy9aGNBEk%3D&amp;reserved=0>
    >    +//
    >    +//  Unless required by applicable law or agreed to in writing, software
    >    +//  distributed under the License is distributed on an "AS IS" BASIS,
    >    +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    >    +//  See the License for the specific language governing permissions and
    >    +//  limitations under the License.
    >    +//
    >    +////////////////////////////////////////////////////////////////////////////////
    >    +package org.apache.royale.routing
    >    +{
    >    +  public class RouteState
    >    +  {
    >    +    public function RouteState(state:String="",title:String="")
    >    +    {
    >    +      this.state = state;
    >    +      this.title = title;
    >    +
    >    +    }
    >    +    public var state:String;
    >    +    public var title:String;
    >    +    public var parameters:Object;
    >    +    public var path:Array;
    >    +  }
    >    +}
    >    \ No newline at end of file
    >    diff --git a/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
    >    new file mode 100644
    >    index 0000000..98b9fc6
    >    --- /dev/null
    >    +++ b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
    >    @@ -0,0 +1,274 @@
    >    +////////////////////////////////////////////////////////////////////////////////
    >    +//
    >    +//  Licensed to the Apache Software Foundation (ASF) under one or more
    >    +//  contributor license agreements.  See the NOTICE file distributed with
    >    +//  this work for additional information regarding copyright ownership.
    >    +//  The ASF licenses this file to You under the Apache License, Version 2.0
    >    +//  (the "License"); you may not use this file except in compliance with
    >    +//  the License.  You may obtain a copy of the License at
    >    +//
    >    +//      https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297043799&amp;sdata=dS98z1bAFk5RE0uJ6WmdDTvkuXIMbrQIfyfy9aGNBEk%3D&amp;reserved=0 <https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7Cf932412ad0a24a40856a08d79dcdfa32%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151380297053790&amp;sdata=NY4972Z6X3a%2BHWhuAA9r2ViKiWpNJQIzaCcQlkH4TLI%3D&amp;reserved=0>
    >    +//
    >    +//  Unless required by applicable law or agreed to in writing, software
    >    +//  distributed under the License is distributed on an "AS IS" BASIS,
    >    +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    >    +//  See the License for the specific language governing permissions and
    >    +//  limitations under the License.
    >    +//
    >    +////////////////////////////////////////////////////////////////////////////////
    >    +package org.apache.royale.routing
    >    +{
    >    +  import org.apache.royale.core.DispatcherBead;
    >    +  import org.apache.royale.core.IStrand;
    >    +  import org.apache.royale.debugging.assert;
    >    +  import org.apache.royale.core.IStatesObject;
    >    +  import org.apache.royale.events.Event;
    >    +  import org.apache.royale.core.IInitialViewApplication;
    >    +    /**
    >    +     *  Dispatched when the state is changed.
    >    +     *
    >    +     *  @langversion 3.0
    >    +     *  @playerversion Flash 10.2
    >    +     *  @playerversion AIR 2.6
    >    +     *  @productversion Royale 0.9.7
    >    +     */
    >    +    [Event(name="stateChange", type="org.apache.royale.events.Event")]
    >    +
    >    +    /**
    >    +     * Router is a bead which automatically handles browsing history.
    >    +     * It could be attached to any strand, but typically it would be attached to Application or View
    >    +     * Listen to stateChange events to handle changes to browsing history and use setState and renderState for modifying the history.
    >    +     * The state of the router can be modified before committing the state changes.
    >    +     *  @langversion 3.0
    >    +     *  @playerversion Flash 10.2
    >    +     *  @playerversion AIR 2.6
    >    +     *  @productversion Royale 0.9.7
    >    +     */
    >    +  public class Router extends DispatcherBead
    >    +  {
    >    +    public function Router()
    >    +    {
    >    +      
    >    +    }
    >    +    /**
    >    +     * Use this to automatically sync the state of the strand.
    >    +     * This only works for the state property of the RouterState.
    >    +     * It also assumes that the strand is an IStatesObject.
    >    +     * For this to work correctly, it's usually assumed that the bead is attached to the application View
    >    +     *  @langversion 3.0
    >    +     *  @playerversion Flash 10.2
    >    +     *  @playerversion AIR 2.6
    >    +     *  @productversion Royale 0.9.7
    >    +     */
    >    +    public var syncState:Boolean;
    >    +		override public function set strand(value:IStrand):void
    >    +		{	
    >    +			_strand = value;
    >    +			COMPILE::JS
    >    +			{
    >    +				window.addEventListener("hashchange", hashChangeHandler);
    >    +        initialTitle = document.title;
    >    +			}
    >    +      // If it's an Application, listen to applicationComplete
    >    +      if(_strand is IInitialViewApplication)
    >    +        listenOnStrand("applicationComplete",onInit);
    >    +      //Otherwise listen to initComplete
    >    +      else
    >    +        listenOnStrand("initComplete",onInit);
    >    +		}
    >    +    private function onInit(event:Event):void
    >    +    {
    >    +      COMPILE::JS
    >    +      {
    >    +        if(location.hash)
    >    +        {
    >    +          hashChangeHandler();
    >    +        }
    >    +      }
    >    +    }
    >    +    private var initialTitle:String;
    >    +		private function hashChangeHandler():void
    >    +		{
    >    +      parseHash();
    >    +      if(syncState)
    >    +      {
    >    +        assert(_strand is IStatesObject,"syncState can only be used on IStatesObjects");
    >    +        (_strand as IStatesObject).currentState = _routeState.state;
    >    +      }
    >    +			dispatchEvent(new Event("stateChange"));
    >    +		}
    >    +    private function parseHash():void
    >    +    {
    >    +      //TODO SWF implementation
    >    +      COMPILE::JS
    >    +      {
    >    +        var hash:String = location.hash;
    >    +        var index:int = 0;
    >    +        if(hash.indexOf("!")==1){
    >    +          index = 1;
    >    +        }
    >    +        hash = hash.slice(index+1);
    >    +        var paths:Array = hash.split("/");
    >    +        var statePart:String = paths.pop();
    >    +        var splitParts:Array = statePart.split("?");
    >    +        statePart = splitParts[0];
    >    +        _routeState = new RouteState(statePart,document.title);
    >    +        _routeState.path = paths;
    >    +        _routeState.parameters = parseParameters(splitParts[1]);
    >    +      }
    >    +    }
    >    +    private function parseParameters(query:String):Object
    >    +    {
    >    +      var urlVars:Object;
    >    +      if(query){
    >    +        var vars:Array = query.split("&");
    >    +        if(vars.length){
    >    +          urlVars = {};
    >    +        }
    >    +        for (var i:int=0;i<vars.length;i++) {
    >    +            var pair:Array = vars[i].split("=");
    >    +            urlVars[pair[0]] = pair[1] == undefined ? undefined : decodeURIComponent(pair[1]);
    >    +        }
    >    +      }
    >    +      return urlVars;
    >    +    }
    >    +
    >    +    private function buildHash():String
    >    +    {
    >    +      var hash:String = "#!";
    >    +      if(_routeState.path && routeState.path.length){
    >    +        hash += (_routeState.path.join("/") + "/");
    >    +      }
    >    +      if(_routeState.state){
    >    +        hash += _routeState.state;
    >    +      }
    >    +      hash+= buildParameterString();
    >    +      return hash;
    >    +    }
    >    +    private function buildParameterString():String{
    >    +      var retVal:String = "";
    >    +      if(_routeState.parameters){
    >    +        retVal += "?";
    >    +        for(var x:String in _routeState.parameters){
    >    +          retVal += x;
    >    +          if(_routeState.parameters[x] != undefined){
    >    +            retVal += "=" + encodeURIComponent(_routeState.parameters[x]);
    >    +            retVal += "&";
    >    +          }
    >    +        }
    >    +        //remove trailing &
    >    +        retVal = retVal.slice(0, -1);
    >    +      }
    >    +
    >    +      return retVal;
    >    +    }
    >    +
    >    +    private var _routeState:RouteState;
    >    +
    >    +    public function get routeState():RouteState
    >    +    {
    >    +      if(!_routeState){
    >    +        _routeState = new RouteState();
    >    +      }
    >    +    	return _routeState;
    >    +    }
    >    +
    >    +    public function set routeState(value:RouteState):void
    >    +    {
    >    +    	_routeState = value;
    >    +    }
    >    +    /**
    >    +     * Commits the current state to the browsing history
    >    +     *  @langversion 3.0
    >    +     *  @playerversion Flash 10.2
    >    +     *  @playerversion AIR 2.6
    >    +     *  @productversion Royale 0.9.7
    >    +     */
    >    +    public function setState():void
    >    +    {
    >    +      COMPILE::JS
    >    +      {
    >    +        window.history.pushState({"title":_routeState.title},_routeState.title,buildHash());
    >    +        if(_routeState.title)
    >    +        {
    >    +          document.title = _routeState.title;
    >    +        }
    >    +      }
    >    +    }
    >    +    /**
    >    +     * Same as setState, but also notifies of the state change 
    >    +     *  @langversion 3.0
    >    +     *  @playerversion Flash 10.2
    >    +     *  @playerversion AIR 2.6
    >    +     *  @productversion Royale 0.9.7
    >    +     */
    >    +    public function renderState():void
    >    +    {
    >    +      setState();
    >    +      if(syncState)
    >    +      {
    >    +        assert(_strand is IStatesObject,"syncState can only be used on IStatesObjects");
    >    +        (_strand as IStatesObject).currentState = _routeState.state;
    >    +      }
    >    +      dispatchEvent(new Event("stateChange"));
    >    +    }
    >    +    private function setTitle():void
    >    +    {
    >    +      COMPILE::JS
    >    +      {
    >    +        if(window.history.state){
    >    +          document.title = window.history.state["title"];
    >    +        } else {
    >    +          document.title = initialTitle;
    >    +        }
    >    +      }
    >    +    }
    >    +    /**
    >    +     * Goes forward in the history
    >    +     *  @langversion 3.0
    >    +     *  @playerversion Flash 10.2
    >    +     *  @playerversion AIR 2.6
    >    +     *  @productversion Royale 0.9.7
    >    +     */
    >    +    public function forward():void{
    >    +      COMPILE::JS
    >    +      {
    >    +         window.history.forward();
    >    +         setTitle();
    >    +         parseHash();
    >    +      }
    >    +    }
    >    +    /**
    >    +     * Goes backwards in the history
    >    +     *  @langversion 3.0
    >    +     *  @playerversion Flash 10.2
    >    +     *  @playerversion AIR 2.6
    >    +     *  @productversion Royale 0.9.7
    >    +     */
    >    +    public function back():void{
    >    +      COMPILE::JS
    >    +      {
    >    +         window.history.back();
    >    +         setTitle();
    >    +         parseHash();
    >    +      }
    >    +    }
    >    +
    >    +    /**
    >    +     * Moved the specified number of steps (forward or backwards) in the history
    >    +     * calling it with 0 or no value will reload the page.
    >    +     *  @langversion 3.0
    >    +     *  @playerversion Flash 10.2
    >    +     *  @playerversion AIR 2.6
    >    +     *  @productversion Royale 0.9.7
    >    +     */
    >    +    public function go(steps:int=0):void{
    >    +      COMPILE::JS
    >    +      {
    >    +         window.history.go(steps);
    >    +         parseHash();
    >    +      }
    >    +    }
    >    +
    >    +  }
    >    +}
    >    \ No newline at end of file
    
    


Re: [royale-asjs] branch develop updated: Added Router

Posted by Harbs <ha...@gmail.com>.
Yeah. I thought about subclassing HashChangeNotifierBead and the version with Title, but almost all the code would have needed to be overridden (i.e. I’m auto-stipping off the hash, etc.), so I decided to write it from scratch.

The bead was not intended to be a lightweight PAYG bead. If someone wants very lightweight, they should use the Notifier beads. It’s meant to be as drop-in as possible to make it easier on the developer.

> On Jan 20, 2020, at 6:41 PM, Alex Harui <ah...@adobe.com.INVALID> wrote:
> 
> Nit-picky comments:
> 
> 1) there is already a bead that watches location.hash.  It might be worth using it to share code
> 2) forward/backward/go/title doesn't seem PAYG to me.  I can imagine lots of users won't need it, or might use it independently of routing (especially Title).
> 
> My 2 cents,
> -Alex
> 
> On 1/20/20, 4:11 AM, "harbs@apache.org <ma...@apache.org>" <harbs@apache.org <ma...@apache.org>> wrote:
> 
>    This is an automated email from the ASF dual-hosted git repository.
> 
>    harbs pushed a commit to branch develop
>    in repository https://nam04.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&amp;data=02%7C01%7Caharui%40adobe.com%7C4b6313defb3e4535c98808d79da1d29d%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151190667743872&amp;sdata=8WwlelechwWHKMy8IfC4PpPRu4phg0n%2BZxFKcgUyd%2BE%3D&amp;reserved=0 <https://nam04.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgitbox.apache.org%2Frepos%2Fasf%2Froyale-asjs.git&amp;data=02%7C01%7Caharui%40adobe.com%7C4b6313defb3e4535c98808d79da1d29d%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151190667743872&amp;sdata=8WwlelechwWHKMy8IfC4PpPRu4phg0n%2BZxFKcgUyd%2BE%3D&amp;reserved=0>
> 
> 
>    The following commit(s) were added to refs/heads/develop by this push:
>         new 6cbc555  Added Router
>    6cbc555 is described below
> 
>    commit 6cbc5559bcc99bf2ceb3e033747ca3680b3b0d91
>    Author: Harbs <harbs@in-tools.com <ma...@in-tools.com>>
>    AuthorDate: Mon Jan 20 14:10:42 2020 +0200
> 
>        Added Router
>    ---
>     .../Basic/src/main/resources/basic-manifest.xml    |   2 +
>     .../royale/org/apache/royale/routing/RouteState.as |  34 +++
>     .../royale/org/apache/royale/routing/Router.as     | 274 +++++++++++++++++++++
>     3 files changed, 310 insertions(+)
> 
>    diff --git a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
>    index 00e2325..3c30bed 100644
>    --- a/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
>    +++ b/frameworks/projects/Basic/src/main/resources/basic-manifest.xml
>    @@ -273,4 +273,6 @@
>         <component id="ModalDisplay" class="org.apache.royale.html.beads.plugin.ModalDisplay"/>
>         <component id="ModalOverlay" class="org.apache.royale.html.beads.plugin.ModalOverlay"/>
> 
>    +    <component id="Router" class="org.apache.royale.routing.Router"/>
>    +
>     </componentPackage>
>    diff --git a/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
>    new file mode 100644
>    index 0000000..84fcc4c
>    --- /dev/null
>    +++ b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/RouteState.as
>    @@ -0,0 +1,34 @@
>    +////////////////////////////////////////////////////////////////////////////////
>    +//
>    +//  Licensed to the Apache Software Foundation (ASF) under one or more
>    +//  contributor license agreements.  See the NOTICE file distributed with
>    +//  this work for additional information regarding copyright ownership.
>    +//  The ASF licenses this file to You under the Apache License, Version 2.0
>    +//  (the "License"); you may not use this file except in compliance with
>    +//  the License.  You may obtain a copy of the License at
>    +//
>    +//      https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7C4b6313defb3e4535c98808d79da1d29d%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151190667743872&amp;sdata=lOqUZl4l%2FMj28XKuqVcIpSAWIBdIXy0c9JmkAzjYx28%3D&amp;reserved=0 <https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7C4b6313defb3e4535c98808d79da1d29d%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151190667743872&amp;sdata=lOqUZl4l%2FMj28XKuqVcIpSAWIBdIXy0c9JmkAzjYx28%3D&amp;reserved=0>
>    +//
>    +//  Unless required by applicable law or agreed to in writing, software
>    +//  distributed under the License is distributed on an "AS IS" BASIS,
>    +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>    +//  See the License for the specific language governing permissions and
>    +//  limitations under the License.
>    +//
>    +////////////////////////////////////////////////////////////////////////////////
>    +package org.apache.royale.routing
>    +{
>    +  public class RouteState
>    +  {
>    +    public function RouteState(state:String="",title:String="")
>    +    {
>    +      this.state = state;
>    +      this.title = title;
>    +
>    +    }
>    +    public var state:String;
>    +    public var title:String;
>    +    public var parameters:Object;
>    +    public var path:Array;
>    +  }
>    +}
>    \ No newline at end of file
>    diff --git a/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
>    new file mode 100644
>    index 0000000..98b9fc6
>    --- /dev/null
>    +++ b/frameworks/projects/Basic/src/main/royale/org/apache/royale/routing/Router.as
>    @@ -0,0 +1,274 @@
>    +////////////////////////////////////////////////////////////////////////////////
>    +//
>    +//  Licensed to the Apache Software Foundation (ASF) under one or more
>    +//  contributor license agreements.  See the NOTICE file distributed with
>    +//  this work for additional information regarding copyright ownership.
>    +//  The ASF licenses this file to You under the Apache License, Version 2.0
>    +//  (the "License"); you may not use this file except in compliance with
>    +//  the License.  You may obtain a copy of the License at
>    +//
>    +//      https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7C4b6313defb3e4535c98808d79da1d29d%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151190667743872&amp;sdata=lOqUZl4l%2FMj28XKuqVcIpSAWIBdIXy0c9JmkAzjYx28%3D&amp;reserved=0 <https://nam04.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.apache.org%2Flicenses%2FLICENSE-2.0&amp;data=02%7C01%7Caharui%40adobe.com%7C4b6313defb3e4535c98808d79da1d29d%7Cfa7b1b5a7b34438794aed2c178decee1%7C0%7C0%7C637151190667743872&amp;sdata=lOqUZl4l%2FMj28XKuqVcIpSAWIBdIXy0c9JmkAzjYx28%3D&amp;reserved=0>
>    +//
>    +//  Unless required by applicable law or agreed to in writing, software
>    +//  distributed under the License is distributed on an "AS IS" BASIS,
>    +//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>    +//  See the License for the specific language governing permissions and
>    +//  limitations under the License.
>    +//
>    +////////////////////////////////////////////////////////////////////////////////
>    +package org.apache.royale.routing
>    +{
>    +  import org.apache.royale.core.DispatcherBead;
>    +  import org.apache.royale.core.IStrand;
>    +  import org.apache.royale.debugging.assert;
>    +  import org.apache.royale.core.IStatesObject;
>    +  import org.apache.royale.events.Event;
>    +  import org.apache.royale.core.IInitialViewApplication;
>    +    /**
>    +     *  Dispatched when the state is changed.
>    +     *
>    +     *  @langversion 3.0
>    +     *  @playerversion Flash 10.2
>    +     *  @playerversion AIR 2.6
>    +     *  @productversion Royale 0.9.7
>    +     */
>    +    [Event(name="stateChange", type="org.apache.royale.events.Event")]
>    +
>    +    /**
>    +     * Router is a bead which automatically handles browsing history.
>    +     * It could be attached to any strand, but typically it would be attached to Application or View
>    +     * Listen to stateChange events to handle changes to browsing history and use setState and renderState for modifying the history.
>    +     * The state of the router can be modified before committing the state changes.
>    +     *  @langversion 3.0
>    +     *  @playerversion Flash 10.2
>    +     *  @playerversion AIR 2.6
>    +     *  @productversion Royale 0.9.7
>    +     */
>    +  public class Router extends DispatcherBead
>    +  {
>    +    public function Router()
>    +    {
>    +      
>    +    }
>    +    /**
>    +     * Use this to automatically sync the state of the strand.
>    +     * This only works for the state property of the RouterState.
>    +     * It also assumes that the strand is an IStatesObject.
>    +     * For this to work correctly, it's usually assumed that the bead is attached to the application View
>    +     *  @langversion 3.0
>    +     *  @playerversion Flash 10.2
>    +     *  @playerversion AIR 2.6
>    +     *  @productversion Royale 0.9.7
>    +     */
>    +    public var syncState:Boolean;
>    +		override public function set strand(value:IStrand):void
>    +		{	
>    +			_strand = value;
>    +			COMPILE::JS
>    +			{
>    +				window.addEventListener("hashchange", hashChangeHandler);
>    +        initialTitle = document.title;
>    +			}
>    +      // If it's an Application, listen to applicationComplete
>    +      if(_strand is IInitialViewApplication)
>    +        listenOnStrand("applicationComplete",onInit);
>    +      //Otherwise listen to initComplete
>    +      else
>    +        listenOnStrand("initComplete",onInit);
>    +		}
>    +    private function onInit(event:Event):void
>    +    {
>    +      COMPILE::JS
>    +      {
>    +        if(location.hash)
>    +        {
>    +          hashChangeHandler();
>    +        }
>    +      }
>    +    }
>    +    private var initialTitle:String;
>    +		private function hashChangeHandler():void
>    +		{
>    +      parseHash();
>    +      if(syncState)
>    +      {
>    +        assert(_strand is IStatesObject,"syncState can only be used on IStatesObjects");
>    +        (_strand as IStatesObject).currentState = _routeState.state;
>    +      }
>    +			dispatchEvent(new Event("stateChange"));
>    +		}
>    +    private function parseHash():void
>    +    {
>    +      //TODO SWF implementation
>    +      COMPILE::JS
>    +      {
>    +        var hash:String = location.hash;
>    +        var index:int = 0;
>    +        if(hash.indexOf("!")==1){
>    +          index = 1;
>    +        }
>    +        hash = hash.slice(index+1);
>    +        var paths:Array = hash.split("/");
>    +        var statePart:String = paths.pop();
>    +        var splitParts:Array = statePart.split("?");
>    +        statePart = splitParts[0];
>    +        _routeState = new RouteState(statePart,document.title);
>    +        _routeState.path = paths;
>    +        _routeState.parameters = parseParameters(splitParts[1]);
>    +      }
>    +    }
>    +    private function parseParameters(query:String):Object
>    +    {
>    +      var urlVars:Object;
>    +      if(query){
>    +        var vars:Array = query.split("&");
>    +        if(vars.length){
>    +          urlVars = {};
>    +        }
>    +        for (var i:int=0;i<vars.length;i++) {
>    +            var pair:Array = vars[i].split("=");
>    +            urlVars[pair[0]] = pair[1] == undefined ? undefined : decodeURIComponent(pair[1]);
>    +        }
>    +      }
>    +      return urlVars;
>    +    }
>    +
>    +    private function buildHash():String
>    +    {
>    +      var hash:String = "#!";
>    +      if(_routeState.path && routeState.path.length){
>    +        hash += (_routeState.path.join("/") + "/");
>    +      }
>    +      if(_routeState.state){
>    +        hash += _routeState.state;
>    +      }
>    +      hash+= buildParameterString();
>    +      return hash;
>    +    }
>    +    private function buildParameterString():String{
>    +      var retVal:String = "";
>    +      if(_routeState.parameters){
>    +        retVal += "?";
>    +        for(var x:String in _routeState.parameters){
>    +          retVal += x;
>    +          if(_routeState.parameters[x] != undefined){
>    +            retVal += "=" + encodeURIComponent(_routeState.parameters[x]);
>    +            retVal += "&";
>    +          }
>    +        }
>    +        //remove trailing &
>    +        retVal = retVal.slice(0, -1);
>    +      }
>    +
>    +      return retVal;
>    +    }
>    +
>    +    private var _routeState:RouteState;
>    +
>    +    public function get routeState():RouteState
>    +    {
>    +      if(!_routeState){
>    +        _routeState = new RouteState();
>    +      }
>    +    	return _routeState;
>    +    }
>    +
>    +    public function set routeState(value:RouteState):void
>    +    {
>    +    	_routeState = value;
>    +    }
>    +    /**
>    +     * Commits the current state to the browsing history
>    +     *  @langversion 3.0
>    +     *  @playerversion Flash 10.2
>    +     *  @playerversion AIR 2.6
>    +     *  @productversion Royale 0.9.7
>    +     */
>    +    public function setState():void
>    +    {
>    +      COMPILE::JS
>    +      {
>    +        window.history.pushState({"title":_routeState.title},_routeState.title,buildHash());
>    +        if(_routeState.title)
>    +        {
>    +          document.title = _routeState.title;
>    +        }
>    +      }
>    +    }
>    +    /**
>    +     * Same as setState, but also notifies of the state change 
>    +     *  @langversion 3.0
>    +     *  @playerversion Flash 10.2
>    +     *  @playerversion AIR 2.6
>    +     *  @productversion Royale 0.9.7
>    +     */
>    +    public function renderState():void
>    +    {
>    +      setState();
>    +      if(syncState)
>    +      {
>    +        assert(_strand is IStatesObject,"syncState can only be used on IStatesObjects");
>    +        (_strand as IStatesObject).currentState = _routeState.state;
>    +      }
>    +      dispatchEvent(new Event("stateChange"));
>    +    }
>    +    private function setTitle():void
>    +    {
>    +      COMPILE::JS
>    +      {
>    +        if(window.history.state){
>    +          document.title = window.history.state["title"];
>    +        } else {
>    +          document.title = initialTitle;
>    +        }
>    +      }
>    +    }
>    +    /**
>    +     * Goes forward in the history
>    +     *  @langversion 3.0
>    +     *  @playerversion Flash 10.2
>    +     *  @playerversion AIR 2.6
>    +     *  @productversion Royale 0.9.7
>    +     */
>    +    public function forward():void{
>    +      COMPILE::JS
>    +      {
>    +         window.history.forward();
>    +         setTitle();
>    +         parseHash();
>    +      }
>    +    }
>    +    /**
>    +     * Goes backwards in the history
>    +     *  @langversion 3.0
>    +     *  @playerversion Flash 10.2
>    +     *  @playerversion AIR 2.6
>    +     *  @productversion Royale 0.9.7
>    +     */
>    +    public function back():void{
>    +      COMPILE::JS
>    +      {
>    +         window.history.back();
>    +         setTitle();
>    +         parseHash();
>    +      }
>    +    }
>    +
>    +    /**
>    +     * Moved the specified number of steps (forward or backwards) in the history
>    +     * calling it with 0 or no value will reload the page.
>    +     *  @langversion 3.0
>    +     *  @playerversion Flash 10.2
>    +     *  @playerversion AIR 2.6
>    +     *  @productversion Royale 0.9.7
>    +     */
>    +    public function go(steps:int=0):void{
>    +      COMPILE::JS
>    +      {
>    +         window.history.go(steps);
>    +         parseHash();
>    +      }
>    +    }
>    +
>    +  }
>    +}
>    \ No newline at end of file