views:

116

answers:

1

I need to write a DHTML page. But, since I have most of the code inside an AS3 library, I want to use ActionScript instead of JavaScript to do the most of work. In this case JavaScript layer (if any) would be just a write-once abstract proxy.

I know about ExternalInterface stuff, but I want something more high-level, which would ease creation of the JS proxy layer.

Any advice?

+2  A: 

I did an event driven gateway interface between ActionScript and JavaScript before:

IGateway.as

package gateway {
    import GatewayEvent;

    public interface IGateway {
        function send(event:GatewayEvent):void;
        function receive(event:GatewayEvent):void;
    }
}

GatewayEvent.as

package gateway
{
    import flash.events.Event;

    public class GatewayEvent extends Event {
        public var message:Object;
        public var flashId:String;

        public static const APP_START:String = 'appStart';
        public static const APP_END:String = 'appEnd';
        public static const APP_READY:String = 'appReady';

        public function GatewayEvent(flashId:String, type:String, message:Object = null) {
            super(type, false, false);
            this.flashId = flashId;
            this.message = message;
        }
    }
}

Gateway.as

package gateway {
    import flash.external.ExternalInterface;
    import flash.events.EventDispatcher;

    import GatewayEvent;
    import IGateway;

    public class Gateway extends EventDispatcher implements IGateway {
        private static const _instance:Gateway = new Gateway(SingletonLock);

        public function Gateway(lock:Class) {
            if (lock != SingletonLock) {
                throw new Error("invalid Singleton access.")
            }
            if (ExternalInterface.available) {
                ExternalInterface.addCallback('relayEvent', relayEvent);
            }
        }

        public static function get instance():Gateway {
            return _instance;
        }

        public function send(event:GatewayEvent):void{
            if (ExternalInterface.available) {
                    ExternalInterface.call("$.gateway.receive", event.flashId, event.type, event.message);
            }
        }

        public function receive(event:GatewayEvent):void{
            dispatchEvent(event);
        }

        protected function relayEvent(flashId:String, type:String, message:Object):void {
            Gateway.instance.receive(new GatewayEvent(flashId, type, message));
        }
    }
}

class SingletonLock {}

messenger.js (require jquery)

(function($){
  /*
  *  Messenger
  *  A basic facility for global message passing (event passing)
  */

  // constructor
  $.Messenger = function(){
    this.events = {};
  };

  // member functions
  $.Messenger.prototype = {
    /*
    * @name  send
    * @param String subject   subject of this message. (Event name)
    * @param Object message   body of the message containing relavent data in key value pairs.
    * @param Mixed  sender    the object responsible for sending this message.
    *
    * @desc  Sends a message out to all message listeners
    */
    send : function(subject, message, sender){
      var handlers = this.events[subject];
      if (!handlers) { return; }
      for (var i = 0; i < handlers.length; i++) {
        handlers[i].fn.call(handlers[i].scope, sender, message);
      }
    },

    /*
    * @name  on
    * @param String   subject   subject (Event name) to listen to
    * @param Function fn        Message Handler of signature function(sender, message)
    * @param Object   scope     the scope in which the handler will run
    *
    * @desc  Subscribe / listen to a mesasge
    */
    on : function(subject, fn, scope){
      this.events[subject] = this.events[subject] || [];
      var handler = {};
      handler.fn = fn;
      handler.scope = scope;
      this.events[subject].push(handler);
    },

    /*
    * @name  un
    * @param String   subject   subject (Event name) to stop listen to
    * @param Function fn        Message Handler of signature function(sender, message)
    * @param Object   scope     the scope in which the handler was run
    *
    * @desc  Unsubscribe / stop listening to a message
    */
    un : function(subject, fn, scope){
      var handlers = this.events[subject];
      if (!handlers) { return; }
      scope = scope;
      for (var i = 0; i < handlers.length; i++) {
        if (handlers[i].fn === fn && handlers[i].scope === scope) {
          handlers.splice(i--, 1);
        }
      }
    }
  };

  // singloten glboal messenger
  $.messenger = new $.Messenger();

  // shortcut for jquery elements to subscribe to a message event
  $.fn.listen = function(subject, fn){
    $.messenger.on(subject, fn, this);
  };

  // shortcut for jquery elements to unsubscribe to a message event
  $.fn.reject = function(subject, fn){
    $.messenger.un(subject, fn, this);
  };

  // shortcut for jquery elements to broadcast/fire a message event
  $.fn.broadcast = function(subject, message) {
    $.messenger.send(subject, message, this);
  };

})(jQuery);

gateway.js (require jquery)

(function($) {
  $.gateway = {

    messenger : new $.Messenger(),

    send: function(flashId, eventName, message){
      var sender = $('#'+flashId)[0];
      sender.relayEvent(flashId, eventName, message);
    },

    receive: function(flashId, eventName, message){
      var sender = $('#'+flashId)[0];
      $.gateway.messenger.send(eventName, message, sender);
    },

    listen: function(flashId, eventName, fn) {
      $.gateway.messenger.on(eventName, fn, $('.' + flashId)[0]);
    }
  };
})(jQuery);
Aaron Qian