From 6b997799acf25e34b632f760c5ef3f2eabb855d3 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvoborni@redhat.com>
Date: Mon, 7 May 2012 18:27:29 +0200
Subject: [PATCH 124/124] Events

---
 install/ui/framework.js            |  128 +++++++++++++++++++++++++++++++-----
 install/ui/test/framework_tests.js |   40 +++++++++++
 2 files changed, 152 insertions(+), 16 deletions(-)

diff --git a/install/ui/framework.js b/install/ui/framework.js
index ebd8df9bfca7c0a260bdb94fd99098adcc49bf38..6fa51daf8b8f381498c4266e08fcaf21dbab0bfd 100644
--- a/install/ui/framework.js
+++ b/install/ui/framework.js
@@ -43,7 +43,47 @@ IFW.unregister = function(class_name) {
 };
 
 IFW.event = function() {
-    return {};
+    var that = {};
+
+    that.listeners = [];
+
+    //adds callback to listeners. If context is specified it binds callback
+    //to context so 'this' property will be evaluated as context.
+    that.on = function(callback, context) {
+
+        var _callback = callback;
+
+        if (context) {
+            _callback = function() {
+                var args = Array.prototype.slice.call(arguments);
+                callback.apply(context, args);
+            };
+        }
+
+        this.listeners.push(_callback);
+    };
+
+    //removes listener
+    that.off = function(callback) {
+        for (var i=0; i < this.listeners.length; i++) {
+            if(callback === this.listeners[i]) {
+                this.listeners.splice(i,1);
+                break;
+            }
+        }
+    };
+
+    //triggers this event
+    that.trigger = function(args, context) {
+        args = args || [];
+        context = context || this;
+
+        for (var i=0; i < this.listeners.length; i++) {
+            this.listeners[i].apply(context, args);
+        }
+    };
+
+    return that;
 };
 
 //creates base object - Framework's root class
@@ -69,25 +109,48 @@ IFW.object = function() {
         //event catalogue
         events: $.ordered_map(),
 
-        //raises existing event
-        raise: function(event_name, args) {
+        //trigger existing event
+        trigger: function(event_name, args) {
 
-            var event = this.events[event_name];
+            var event = this.events.get(event_name);
 
-            if (event) event.notify(args);
+            if (event) event.trigger(args, this.obj);
         },
 
-        //registers event
+        //registers event - creates new event, no listeners
+        //If event exists, it doesn't create a new one.
         event: function(name) {
 
-            var event = IFW.event();
+            var event = this.events.get(name);
 
-            this.obj[name] = event;
-            this.events.put(name, event);
+            if (!event) {
+                event = IFW.event();
+                this.obj[name] = event;
+                this.events.put(name, event);
+            }
+            return event;
+        },
+
+        //adds listener to event
+        //proxy for events[name].on. Creates new one if it doesn't exists.
+        on: function(name, handler, context) {
+
+            var event = this.event(name);
+            event.on(handler, context);
+        },
+
+        //removes listeners from event
+        off: function(name, handler) {
+            var event = this.events.get(name);
+            if (event) {
+                event.off(handler);
+            }
         },
 
         //registers new method for current class. A way of overriding methods.
-        method: function(name, func, pre_event, post_event) {
+        method: function(name, func, options) {
+
+            options = options || {};
 
             //to 'that' objects sets functions which raises preevent then executes
             //function in 'that' object context and finishes with raising post event
@@ -97,16 +160,48 @@ IFW.object = function() {
             //method. And the nice part is that events are raised in proper way
             //regardless whether ancestor method is called.
             var _ = this;
-            this.obj[name] = function(args) {
+            var pre_handler, post_handler, pre_e_name, post_e_name;
 
-                if (pre_event) {
-                    _.raise('pre'+name, args);
+            if (options.pre_event) {
+
+                pre_e_name = typeof options.pre_event === 'string' ?
+                                options.pre_event : 'pre_'+name;
+
+                pre_handler = function(args) {
+                    _.trigger(pre_e_name, args);
+                };
+            }
+
+            if (options.post_event) {
+
+                post_e_name = typeof options.post_event === 'string' ?
+                                options.post_event : 'post_'+name;
+
+                post_handler = function(args) {
+                    _.trigger(post_e_name, args);
+                };
+            }
+
+            if (options.pre_handler) {
+                pre_handler = options.pre_handler;
+            }
+
+            if (options.post_handler) {
+                post_handler = options.post_handler;
+            }
+
+            this.obj[name] = function() {
+
+                var args = Array.prototype.slice.call(arguments);
+
+                if (pre_handler) {
+                    pre_handler.call(_.obj, args);
                 }
 
-                func.call(_.obj, args);
+                func.apply(_.obj, args);
 
-                if (post_event) {
-                    _.raise('post'+name, args);
+                if (post_handler) {
+                    post_handler.call(_.obj, args);
                 }
             };
 
@@ -161,6 +256,7 @@ IFW.object = function() {
     return that;
 };
 
+
 //main function for creating new classes
 IFW.type = function(class_name, ancestor) {
 
diff --git a/install/ui/test/framework_tests.js b/install/ui/test/framework_tests.js
index e82a54a5f5c8a797eb639d13c61e0f6b74eb6854..296e74ebeaf0bec29f55cd4d2d7cbe0604941ccf 100644
--- a/install/ui/test/framework_tests.js
+++ b/install/ui/test/framework_tests.js
@@ -33,6 +33,28 @@ module('framework',{
                 that.foo = spec.foo || 'facet_foo';
                 that.baz = spec.baz || 'facet_baz';
                 that.bar = spec.bar || 'facet_bar';
+                this._.on('pre_with_events', this.preevent_handler, this);
+                this._.on('post_with_events', this.postevent_handler, this);
+            });
+
+            that._.method('with_events', function(first, second) {
+                this.with_events_called = true;
+                this.with_events_attrs = [first, second];
+            }, {
+                pre_event: true,
+                post_event: true
+            });
+
+            that._.method('preevent_handler', function(first, second) {
+                that.preevent_handler_called = true;
+                this.preevent_handler_bound = true;
+                this.preevent_handler_attrs = [first, second];
+            });
+
+            that._.method('postevent_handler', function(first, second) {
+                that.postevent_handler_called = true;
+                this.postevent_handler_bound = true;
+                this.postevent_handler_attrs = [first, second];
             });
 
             return that;
@@ -79,4 +101,22 @@ test("Build and inheritence" ,function() {
     same(details_facet.foo, 'facet_foo', "Property - ancestor's default");
     same(details_facet.baz, 'details_baz', "Property - child's default");
     same(details_facet.bar, 'custom_bar', "Property - custom");
+
+    //test method calls and pre/post events
+
+    var attrs = ["first", "second"];
+    details_facet.with_events(attrs[0], attrs[1]);
+
+    ok(details_facet.with_events_called, "With events called.");
+    same(details_facet.with_events_attrs, attrs, "With event called with good attrs");
+
+    ok(details_facet.preevent_handler_called, "Pre event called.");
+    ok(details_facet.preevent_handler_bound, "Pre event correctly bounded.");
+    same(details_facet.preevent_handler_attrs, attrs, "Pre event called with good attrs");
+
+    ok(details_facet.postevent_handler_called, "Post event called.");
+    ok(details_facet.postevent_handler_bound, "Post event correctly bounded.");
+    same(details_facet.postevent_handler_attrs, attrs, "Post event called with good attrs");
+
+    //calls
 });
-- 
1.7.7.6

