[Rt-commit] rt branch, lcore, updated. 16a214eaff54dce4af902225a2113fac0b2e797a

clkao at bestpractical.com clkao at bestpractical.com
Thu Sep 10 01:41:52 EDT 2009


The branch, lcore has been updated
       via  16a214eaff54dce4af902225a2113fac0b2e797a (commit)
       via  dbe2977a1bfd1a44929e9230e1de7bcd6a32d4c4 (commit)
       via  5309d67747ae752c0da1084bf8d0f6140b770d21 (commit)
       via  cdb68f8027a42ced31462d4494686dddc07c645a (commit)
       via  69c59a9a7162108aa9c5be74f853f1533e67ce9f (commit)
      from  15860210fb79387908c4dd82a92d3893c4e6a927 (commit)

Summary of changes:
 lib/RT/Lorzy.pm                      |   19 ++--
 lib/RT/View/RuleBuilder.pm           |   11 ++-
 share/web/static/css/rulebuilder.css |   57 +++++++---
 share/web/static/js/rulebuilder.js   |  201 ++++++++++++++++++++++++++++------
 4 files changed, 231 insertions(+), 57 deletions(-)

- Log -----------------------------------------------------------------
commit 69c59a9a7162108aa9c5be74f853f1533e67ce9f
Author: Chia-liang Kao <clkao at bestpractical.com>
Date:   Thu Sep 10 12:08:16 2009 +0900

    rulebuilder context object.

diff --git a/share/web/static/css/rulebuilder.css b/share/web/static/css/rulebuilder.css
index bf945e7..d7c8534 100644
--- a/share/web/static/css/rulebuilder.css
+++ b/share/web/static/css/rulebuilder.css
@@ -1,34 +1,43 @@
 div.application-params span.param-placeholder,
 div.function span.return-type,
-div.expression span.type {
+div.context span.return-type,
+div.expression span.return-type {
   color:#555555;
   font-style:italic;
 }
-div.application-params span.param-placeholder,
-div.function span.return-type {
-  background-color:lightBlue;
-  border:2px solid blue;
-
-}
 
 .signature .parameter {
-	border: 1px solid red;
+    border: 1px solid red;
 }
 
 .expression .type {
-	background-color: lightGreen;
-	border: 2px solid green;
+    background-color: lightGreen;
+    border: 2px solid green;
 }
 
 .signature .parameter {
-	background-color: lightGreen;
-	border: 2px solid green;
+    background-color: lightBlue;
+    border: 2px solid blue;
+}
+
+div.top-context {
+    position: relative;
+    left: 20em;
+}
+
+div.context {
+    border: 1px dashed;
+    min-height: 1.5em;
+}
+
+div.current {
+    border: 1px dotted red;
 }
 
 div.application-params span.param-placeholder,
 div.function span.return-type, 
 .signature .parameter,
-.expression .type {
+.expression .return-type {
 	font-size: 0.8em;
   display: inline-block;
   text-align: left;
@@ -51,7 +60,7 @@ div#body {
 
 #expressionbuilder {
 }
-.application {
+.application-old {
 	position: relative;
 	top: -7em;
 	left: 20em;
@@ -72,8 +81,8 @@ div#body {
 
 div.application-params span.param {
   padding:0.5em;
-	background: lightGreen;
-	border 1px solid green;
+  background: lightBlue;
+  border 1px solid blue;
 
 }
 
@@ -87,6 +96,20 @@ div.application-params span.param-placeholder.current {
 	background: #f99;	
 }
 
+.return-type.unmatched {
+    background: #f99;
+    border: 1px solid red;
+}
+
+.return-type.matched {
+    background: lightGreen;
+    border: 1px solid green;
+}
+
 .signature {
 	padding-left: 2em;
 }
+
+div.context span.expression {
+    padding-left: 1em;
+}
\ No newline at end of file
diff --git a/share/web/static/js/rulebuilder.js b/share/web/static/js/rulebuilder.js
index f9f7102..0bf28e3 100644
--- a/share/web/static/js/rulebuilder.js
+++ b/share/web/static/js/rulebuilder.js
@@ -11,7 +11,7 @@ RuleBuilder = function (sel) {
                    that.functions = response;
                    that.init();
                },
-               'json'); // handle errors.
+               'json'); // XXX: handle errors.
 };
 
 RuleBuilder.expressions = [
@@ -28,17 +28,17 @@ RuleBuilder.prototype.init = function () {
     var ebuilder = jQuery(sel);
     var that = this;
 
-    jQuery._div({'class': 'application'})
-            ._h3_().text("New Expression")
-            ._div_({'class': 'application-function function'})
-           ._div_({'class': 'application-params signature'})
-          .div_()
+    this.ebuilder = ebuilder;
+    
+    jQuery._div_({'class': 'context top-context'})
         .appendTo(ebuilder);
 
-    jQuery("#add-expression")
-		.appendTo(jQuery(".application"));
-
-
+    this.top_context = new RuleBuilder.Context(
+        'Bool',
+        jQuery(".top-context").get(0),
+        null,
+        this
+    );
     this.update_expressions();
 
     ebuilder.append('<div class="functions">');
@@ -53,8 +53,9 @@ RuleBuilder.prototype.init = function () {
     jQuery(this.sel+' div.function').click(
         function(e) {
             var func_name = jQuery('span.function-name', this).text();
-            that.current_application = func_name;
-            that.update_application();
+            that.push_application(func_name);
+//            that.current_application = func_name;
+//            that.update_application();
         });
 //    jQuery(this.sel+' div.application').hide();
 	function render_signature(sig) {
@@ -74,6 +75,37 @@ RuleBuilder.prototype.init = function () {
 					});
 			return content;
 	}
+
+    this.focus(this.top_context);
+};
+
+RuleBuilder.prototype.push_application = function(func_name) {
+    this.current_ctx.set_application(func_name, this.functions[func_name]);
+};
+
+
+RuleBuilder.prototype.push_expression = function(expression) {
+    this.current_ctx.set_expression(expression);
+};
+
+RuleBuilder.prototype.focus = function(ctx) {
+    if( this.current_ctx )
+        jQuery(this.current_ctx.element).removeClass('current');
+
+    this.current_ctx = ctx;
+    jQuery(this.current_ctx.element).addClass('current');
+    var type = this.current_ctx.expected_type;
+    jQuery('.functions .return-type', this.ebuilder).removeClass('matched')
+                                                     .addClass('unmatched');
+
+    jQuery('.expressions .return-type', this.ebuilder).removeClass('matched')
+                                                   .addClass('unmatched');
+
+    jQuery('.functions .return-type:contains('+type+')', this.ebuilder)
+    .addClass('matched');
+
+    jQuery('.expressions .return-type:contains('+type+')', this.ebuilder)
+    .addClass('matched');
 };
 
 RuleBuilder.prototype.update_expressions = function() {
@@ -93,24 +125,15 @@ RuleBuilder.prototype.update_expressions = function() {
     jQuery.each(this.expressions,
                 function(idx, val) {
                     jQuery._div({'class': 'expression ret_'+val.type})
-                            ._span_({ 'class': 'type' }).text(val.type)
+                            ._span_({ 'class': 'return-type' }).text(val.type)
                             ._span_({ 'class': 'expression-text' }).text(val.expression)
                           .div_().click(function(e) {
-                        if (that.current_application_param != null) {
-                            if (val.type != 
-                                that.functions[that.current_application].parameters[that.current_application_param].type) {
-                                alert("type mismatch: "+val.type+" vs "+that.functions[that.current_application].parameters[that.current_application_param].type);
-                                return;
-                            }
-                            jQuery(that.sel+ ' .param:eq('+parseInt(idx)+')').removeClass('param-placeholder').text(val.expression);
-                        }
-                        else {
-                            alert("must select param first");
-                        }
+                              that.push_expression(val);
                           })
                     .appendTo(expressions_div);
                 });
 
+
     var options = {
         onClick: function(e,item) { x=e;y=item },
         minWidth: 120,
@@ -123,14 +146,14 @@ RuleBuilder.prototype.update_expressions = function() {
         {src: 'test2', subMenu: [   {src: 'sub 1'},
                                     {src: 'sub 2' },
                                     {src: 'sub 3'}]}];
-    jQuery('.ret_'+e_sel('RT::Model::Ticket')).menu(options, items);
+//    jQuery('.ret_'+e_sel('RT::Model::Ticket')).menu(options, items);
 };
 
 
 RuleBuilder.prototype.update_application = function () {
     /* might be an expression too */
     jQuery(this.sel+' div.application-function').html(this.current_application);
-    jQuery(this.sel+' div.application').show();
+    jQuery(this.sel+' div.application-old').show();
     jQuery(this.sel+' div.application-params').html('');
     var params = jQuery(this.sel+' div.application-params');
     var that = this;
@@ -182,3 +205,85 @@ RuleBuilder.prototype.filter_expression_type = function (type) {
     jQuery(this.sel+' .expression:not(.ret_'+e_sel(type)+')').hide();
 };
 
+
+RuleBuilder.Context = function(expected_type, element, parent, rb) {
+    this.expected_type = expected_type;
+    this.element = element;
+    this.parent = parent;
+    this.rb = rb;
+
+    var that = this;
+    jQuery(this.element).click(function(e) { rb.focus(that); return false });
+    jQuery._span_({ 'class': 'return-type'})
+          .text(expected_type)
+          .appendTo(this.element);
+};
+
+RuleBuilder.Context.prototype.update_return_type = function(type) {
+    if (this.expected_type == type) {
+        jQuery("span.return-type", this.element).removeClass("unmatched").addClass("matched");
+    }
+    else {
+        jQuery("span.return-type", this.element).removeClass("matched").addClass("unmatched");
+    }
+}
+
+RuleBuilder.Context.prototype.clear = function() {
+    jQuery('div.application', this.element).remove();
+    jQuery('span.expression', this.element).remove();
+}
+
+RuleBuilder.Context.prototype.set_expression = function(expression) {
+    this.clear();
+    this.expression = expression.expression;
+    this.update_return_type(expression.type);
+
+    jQuery._span_({ 'class': 'expression'})
+          .text(this.expression)
+          .appendTo(this.element);
+}
+
+
+
+RuleBuilder.Context.prototype.set_application = function(func_name, func) {
+    this.clear();
+    this.func = func;
+    this.children = [];
+    this.update_return_type(func.return_type);
+    jQuery._div({'class': 'application'})
+            ._div_({'class': 'application-function function'})
+           ._div_({'class': 'application-params signature'})
+          .div_()
+        .appendTo(this.element);
+
+//    jQuery(this.sel+' div.application-function').html(this.current_application);
+    jQuery('div.application-function',this.element).html(func_name);
+    jQuery('div.application', this.element).show();
+    jQuery('div.application-params', this.element).html('');
+    var params = jQuery('div.application-params', this.element);
+    var that = this;
+    jQuery.each(func.parameters,
+                function(idx, val) {
+                    var x = jQuery._div_({'class': 'context'})
+                    .appendTo(params);
+
+                    var child = new RuleBuilder.Context(val.type, x, that, that.rb);
+                    that.children.push(child);
+                });
+    if (this.children.length) {
+        this.rb.focus(this.children[0]);
+    }
+};
+
+RuleBuilder.Context.prototype.init = function() {
+
+};
+
+jQuery.fn.sort = function() {
+    return this.pushStack( [].sort.apply( this, arguments ), []);
+};
+
+function sortAlpha(a,b){
+     return a.innerHTML > b.innerHTML ? 1 : -1;
+};
+

commit cdb68f8027a42ced31462d4494686dddc07c645a
Author: Chia-liang Kao <clkao at bestpractical.com>
Date:   Thu Sep 10 12:31:03 2009 +0900

    basic accessor menu.

diff --git a/lib/RT/View/RuleBuilder.pm b/lib/RT/View/RuleBuilder.pm
index 98ae5d8..8ad827c 100644
--- a/lib/RT/View/RuleBuilder.pm
+++ b/lib/RT/View/RuleBuilder.pm
@@ -25,6 +25,16 @@ template 'allfunctions.json' => sub {
     print to_json($data);
 };
 
+template 'getfunctions.json' => sub {
+    Jifty->handler->apache->header_out('Content-Type' => 'application/json; charset=UTF-8' );
+    Jifty->handler->send_http_header;
+
+    my $functions = $RT::Lorzy::LCORE->env->find_functions_by_type(get('parameters'), get('return_type'));
+
+    my $data = { map { $_ => _function_as_hash($functions->{$_}) } keys %$functions };
+    print to_json($data);
+};
+
 template 'index.html' => page {
     title => "rule",
 } content {
@@ -44,7 +54,6 @@ jQuery(function() {
     var rb = new RuleBuilder("#expressionbuilder");
     jQuery("#type-filter").click(function(e) { rb.filter_return_type(jQuery("#type-filter-type").val())});
     jQuery("#type-unfilter").click(function(e) { rb.unfilter_return_type()});
-    jQuery("#add-expression").click(function(e) { rb.add_expression()});
 });
 </script>
 ');
diff --git a/share/web/static/js/rulebuilder.js b/share/web/static/js/rulebuilder.js
index 0bf28e3..14a64ad 100644
--- a/share/web/static/js/rulebuilder.js
+++ b/share/web/static/js/rulebuilder.js
@@ -141,12 +141,18 @@ RuleBuilder.prototype.update_expressions = function() {
         hoverOpenDelay: 500,
         hideDelay: 500 };
 
-    var items = [   {src: 'test' },
-        {src: ''}, /* separator */
-        {src: 'test2', subMenu: [   {src: 'sub 1'},
-                                    {src: 'sub 2' },
-                                    {src: 'sub 3'}]}];
-//    jQuery('.ret_'+e_sel('RT::Model::Ticket')).menu(options, items);
+    jQuery.get('/rulebuilder/getfunctions.json',
+               { parameters: ['RT::Model::Ticket'] },
+               function(response, status) {
+                   var entries = [];
+                   for (var name in response) {
+                       if (/^RT::Model::Ticket\./.match(name))
+                           entries.push(name);
+                   }
+                   var x = jQuery.map(entries, function(val) { return {src: val}});
+                   jQuery('.ret_'+e_sel('RT::Model::Ticket')).menu(options, x);
+               },
+               'json');
 };
 
 

commit 5309d67747ae752c0da1084bf8d0f6140b770d21
Author: Chia-liang Kao <clkao at bestpractical.com>
Date:   Thu Sep 10 14:10:02 2009 +0900

    make attribute menu actually work.

diff --git a/share/web/static/css/rulebuilder.css b/share/web/static/css/rulebuilder.css
index d7c8534..253ae2e 100644
--- a/share/web/static/css/rulebuilder.css
+++ b/share/web/static/css/rulebuilder.css
@@ -1,7 +1,8 @@
 div.application-params span.param-placeholder,
 div.function span.return-type,
 div.context span.return-type,
-div.expression span.return-type {
+div.expression span.return-type,
+div.menu-item span.return-type {
   color:#555555;
   font-style:italic;
 }
diff --git a/share/web/static/js/rulebuilder.js b/share/web/static/js/rulebuilder.js
index 14a64ad..d5a1d03 100644
--- a/share/web/static/js/rulebuilder.js
+++ b/share/web/static/js/rulebuilder.js
@@ -135,7 +135,12 @@ RuleBuilder.prototype.update_expressions = function() {
 
 
     var options = {
-        onClick: function(e,item) { x=e;y=item },
+        onClick: function(e,item) {
+            that.push_expression({ expression: "("+item.data.func+" "+item.data.expression+")",
+                                   type: item.data.type });
+            jQuery.Menu.closeAll();
+            return false;
+        },
         minWidth: 120,
         arrowSrc: '/images/arrow_right.gif',
         hoverOpenDelay: 500,
@@ -149,8 +154,20 @@ RuleBuilder.prototype.update_expressions = function() {
                        if (/^RT::Model::Ticket\./.match(name))
                            entries.push(name);
                    }
-                   var x = jQuery.map(entries, function(val) { return {src: val}});
-                   jQuery('.ret_'+e_sel('RT::Model::Ticket')).menu(options, x);
+                   jQuery('.ret_'+e_sel('RT::Model::Ticket'), that.ebuilder)
+                   .each(function() {
+                       var expression = jQuery('span.expression-text',this).text();
+                       jQuery._span_().text('...')
+                       .appendTo(this)
+                       .menu(options,
+                             jQuery.map(entries,
+                                        function(val) {
+                                            var attribute = val.replace(/^RT::Model::Ticket\./, '');
+                                            var type = that.functions[val].return_type;
+                                            attribute += ' <span class="return-type">'+type+'</span>';
+                                            return {src: attribute, data: { type: type, expression: expression, func: val } }}
+                                       ));
+                   });
                },
                'json');
 };

commit dbe2977a1bfd1a44929e9230e1de7bcd6a32d4c4
Author: Chia-liang Kao <clkao at bestpractical.com>
Date:   Thu Sep 10 14:17:26 2009 +0900

    refactor attribute menu heper to build_accessor_menu

diff --git a/share/web/static/js/rulebuilder.js b/share/web/static/js/rulebuilder.js
index d5a1d03..1bd1413 100644
--- a/share/web/static/js/rulebuilder.js
+++ b/share/web/static/js/rulebuilder.js
@@ -133,6 +133,11 @@ RuleBuilder.prototype.update_expressions = function() {
                     .appendTo(expressions_div);
                 });
 
+    this.build_accessor_menu('RT::Model::Ticket');
+}
+
+RuleBuilder.prototype.build_accessor_menu = function(model) {
+    var that = this;
 
     var options = {
         onClick: function(e,item) {
@@ -146,15 +151,17 @@ RuleBuilder.prototype.update_expressions = function() {
         hoverOpenDelay: 500,
         hideDelay: 500 };
 
+    var re = new RegExp('^'+model+'\.');
+
     jQuery.get('/rulebuilder/getfunctions.json',
-               { parameters: ['RT::Model::Ticket'] },
+               { parameters: [model] },
                function(response, status) {
                    var entries = [];
                    for (var name in response) {
-                       if (/^RT::Model::Ticket\./.match(name))
+                       if (re.match(name))
                            entries.push(name);
                    }
-                   jQuery('.ret_'+e_sel('RT::Model::Ticket'), that.ebuilder)
+                   jQuery('.ret_'+e_sel(model), that.ebuilder)
                    .each(function() {
                        var expression = jQuery('span.expression-text',this).text();
                        jQuery._span_().text('...')
@@ -162,7 +169,7 @@ RuleBuilder.prototype.update_expressions = function() {
                        .menu(options,
                              jQuery.map(entries,
                                         function(val) {
-                                            var attribute = val.replace(/^RT::Model::Ticket\./, '');
+                                            var attribute = val.replace(re, '');
                                             var type = that.functions[val].return_type;
                                             attribute += ' <span class="return-type">'+type+'</span>';
                                             return {src: attribute, data: { type: type, expression: expression, func: val } }}

commit 16a214eaff54dce4af902225a2113fac0b2e797a
Author: Chia-liang Kao <clkao at bestpractical.com>
Date:   Thu Sep 10 14:41:27 2009 +0900

    more model attributes.

diff --git a/lib/RT/Lorzy.pm b/lib/RT/Lorzy.pm
index 8c82c1e..4c4e02a 100644
--- a/lib/RT/Lorzy.pm
+++ b/lib/RT/Lorzy.pm
@@ -71,9 +71,11 @@ $LCORE->env->set_symbol('RT.RuleAction.Run' => LCore::Primitive->new
 
                       ));
 
-sub install_ticket_accessors {
-    my ($env) = @_;
-    for my $column (RT::Model::Ticket->columns) {
+sub install_model_accessors {
+    my ($env, $model) = @_;
+    my $modelname = lc($model);
+    $modelname =~ s/.*://;
+    for my $column ($model->columns) {
         my $name = $column->name;
         my $type = $column->type;
         $type = $type =~ m/^varchar/ ? 'Str'
@@ -85,19 +87,20 @@ sub install_ticket_accessors {
               : $type eq 'serial'    ? 'Int'
               :                        next;
 
-        $env->set_symbol('RT::Model::Ticket.'.$name => LCore::Primitive->new
+        $env->set_symbol($model.'.'.$name => LCore::Primitive->new
                              ( body => sub {
-                                   my ($ticket) = @_;
-                                   $ticket->$name
+                                   my ($object) = @_;
+                                   $object->$name
                                },
                                lazy => 0,
-                               parameters => [ LCore::Parameter->new({ name => 'ticket', type => 'RT::Model::Ticket' }) ],
+                               parameters => [ LCore::Parameter->new({ name => $modelname, type => $model }) ],
                                return_type => $type
                            ));
     }
 }
 
-RT::Lorzy::install_ticket_accessors($RT::Lorzy::LCORE->env);
+install_model_accessors($RT::Lorzy::LCORE->env, $_)
+    for qw(RT::Model::Ticket RT::Model::Transaction RT::Model::Queue);
 
 
 my %cond_compat_map = ( 'On Create' => 'OnCreate',
diff --git a/share/web/static/css/rulebuilder.css b/share/web/static/css/rulebuilder.css
index 253ae2e..34f6448 100644
--- a/share/web/static/css/rulebuilder.css
+++ b/share/web/static/css/rulebuilder.css
@@ -2,6 +2,7 @@ div.application-params span.param-placeholder,
 div.function span.return-type,
 div.context span.return-type,
 div.expression span.return-type,
+div.parameter .type,
 div.menu-item span.return-type {
   color:#555555;
   font-style:italic;
diff --git a/share/web/static/js/rulebuilder.js b/share/web/static/js/rulebuilder.js
index 1bd1413..74e8e58 100644
--- a/share/web/static/js/rulebuilder.js
+++ b/share/web/static/js/rulebuilder.js
@@ -134,6 +134,7 @@ RuleBuilder.prototype.update_expressions = function() {
                 });
 
     this.build_accessor_menu('RT::Model::Ticket');
+    this.build_accessor_menu('RT::Model::Transaction');
 }
 
 RuleBuilder.prototype.build_accessor_menu = function(model) {
@@ -172,6 +173,7 @@ RuleBuilder.prototype.build_accessor_menu = function(model) {
                                             var attribute = val.replace(re, '');
                                             var type = that.functions[val].return_type;
                                             attribute += ' <span class="return-type">'+type+'</span>';
+                                            // XXX: submenu here for known types
                                             return {src: attribute, data: { type: type, expression: expression, func: val } }}
                                        ));
                    });

-----------------------------------------------------------------------


More information about the Rt-commit mailing list