[Rt-commit] rt branch, lcore, updated. b59c91200560931f2b32e173ed480fee8ae185bc

clkao at bestpractical.com clkao at bestpractical.com
Fri Jul 31 06:12:58 EDT 2009


The branch, lcore has been updated
       via  b59c91200560931f2b32e173ed480fee8ae185bc (commit)
       via  0d038099919e138739bcccfb26dbe8ce476cff8c (commit)
      from  c3d60783fa30f1076bd27ae0229201f5e0190e6d (commit)

Summary of changes:
 lib/RT.pm                                    |    2 +-
 lib/RT/Lorzy.pm                              |    6 +-
 lib/RT/Lorzy/Package/RT.pm                   |    1 +
 lib/RT/View.pm                               |    3 +
 lib/RT/View/RuleBuilder.pm                   |   53 +++++++++
 share/web/static/css/app.css                 |    2 +
 share/web/static/css/rulebuilder.css         |    6 +
 share/web/static/js/jquery.createdomnodes.js |   86 +++++++++++++++
 share/web/static/js/rulebuilder.js           |  152 ++++++++++++++++++++++++++
 9 files changed, 309 insertions(+), 2 deletions(-)
 create mode 100644 lib/RT/View/RuleBuilder.pm
 create mode 100644 share/web/static/css/rulebuilder.css
 create mode 100644 share/web/static/js/jquery.createdomnodes.js
 create mode 100644 share/web/static/js/rulebuilder.js

- Log -----------------------------------------------------------------
commit 0d038099919e138739bcccfb26dbe8ce476cff8c
Author: Chia-liang Kao <clkao at clkao.org>
Date:   Fri Jul 31 10:25:39 2009 +0100

    basic client only rule builder with type filtering.

diff --git a/lib/RT.pm b/lib/RT.pm
index 7ea5f45..49d77cc 100644
--- a/lib/RT.pm
+++ b/lib/RT.pm
@@ -322,7 +322,7 @@ sub init_jifty {
 
     Jifty->web->add_javascript(
         qw( titlebox-state.js util.js ahah.js fckeditor.js list.js class.js
-        combobox.js  cascaded.js )
+        combobox.js  cascaded.js rulebuilder.js jquery.createdomnodes.js )
     );
 
     Jifty::Web->add_trigger(
diff --git a/lib/RT/Lorzy.pm b/lib/RT/Lorzy.pm
index f350bdc..2d2c1dc 100644
--- a/lib/RT/Lorzy.pm
+++ b/lib/RT/Lorzy.pm
@@ -22,7 +22,11 @@ $LCORE->env->set_symbol('Native.Invoke' => LCore::Primitive->new
 $LCORE->env->set_symbol('Str.Eq' => LCore::Primitive->new
                         ( body => sub {
                               return $_[0] eq $_[1];
-                          }));
+                          },
+                          parameters => [ LCore::Parameter->new({ name => 'left', type => 'Str' }),
+                                          LCore::Parameter->new({ name => 'right', type => 'Str' })],
+                          return_type => 'Bool'
+                      ));
 
 $LCORE->env->set_symbol('RT.RuleAction.Prepare' => LCore::Primitive->new
                         ( body => sub {
diff --git a/lib/RT/Lorzy/Package/RT.pm b/lib/RT/Lorzy/Package/RT.pm
index bc63eeb..e473f8c 100644
--- a/lib/RT/Lorzy/Package/RT.pm
+++ b/lib/RT/Lorzy/Package/RT.pm
@@ -11,6 +11,7 @@ sub lcore_defun {
                   transaction => $transaction });
         },
         lazy => 0,
+        return_type => 'Bool',
         parameters => [ LCore::Parameter->new({ name => 'ticket', type => 'RT::Model::Ticket' }),
                         LCore::Parameter->new({ name => 'transaction', type => 'RT::Model::Transaction' }) ],
     ));
diff --git a/lib/RT/View.pm b/lib/RT/View.pm
index 1087b66..658ed49 100644
--- a/lib/RT/View.pm
+++ b/lib/RT/View.pm
@@ -60,6 +60,9 @@ alias RT::View::Ticket under 'ticket/';
 require RT::View::SetupWizard;
 alias RT::View::SetupWizard under '__jifty/admin/setupwizard';
 
+require RT::View::RuleBuilder;
+alias RT::View::RuleBuilder under 'rulebuilder/';
+
 __PACKAGE__->use_mason_wrapper;
 
 template login_widget => sub {
diff --git a/lib/RT/View/RuleBuilder.pm b/lib/RT/View/RuleBuilder.pm
new file mode 100644
index 0000000..1adfc13
--- /dev/null
+++ b/lib/RT/View/RuleBuilder.pm
@@ -0,0 +1,53 @@
+use warnings;
+use strict;
+
+package RT::View::RuleBuilder;
+use Jifty::View::Declare -base;
+
+template 'index.html' => page {
+    title => "rule",
+} content {
+    h1 { "to build a rule" };
+    # given transaction :: RT::Model::Transaction
+    #       ticket :: RT::Model::Ticket
+    # expect Bool
+    input { { id is 'type-filter-type', type is 'text' } };
+    input { { id is 'type-filter', type is 'button', value is 'filter' } };
+    input { { id is 'type-unfilter', type is 'button', value is 'unfilter' } };
+    div { { id is 'expressionbuilder' } };
+    input { { id is 'add-expression', type is 'button', value is 'Add Expression' } };
+    outs_raw('<script type="text/javascript">
+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>
+');
+    
+#    show('list_functions');
+
+};
+
+template 'list_functions' => sub {
+    my $l = $RT::Lorzy::LCORE;
+    my $env = $l->env;
+    my $functions;
+    while ($env) {
+        for (keys %{$env->symbols}) {
+            if ($env->symbols->{$_}->does('LCore::Function')) {
+                $functions->{$_} ||= $env->symbols->{$_};
+            }
+        }
+        $env = $env->parent;
+    }
+    ul {
+        for (keys %$functions) {
+            next unless $functions->{$_}->return_type && $functions->{$_}->return_type eq 'Bool';
+            li { $_ };
+        }
+    }
+};
+
+1;
diff --git a/share/web/static/css/app.css b/share/web/static/css/app.css
index edc996e..db359d5 100644
--- a/share/web/static/css/app.css
+++ b/share/web/static/css/app.css
@@ -14,3 +14,5 @@
 @import "misc.css";
 @import "yui/calendar/calendar.css";
 
+ at import "rulebuilder.css";
+
diff --git a/share/web/static/css/rulebuilder.css b/share/web/static/css/rulebuilder.css
new file mode 100644
index 0000000..615b4f2
--- /dev/null
+++ b/share/web/static/css/rulebuilder.css
@@ -0,0 +1,6 @@
+div.application_params span.param-placeholder,
+div.expression span.type {
+  color:#555555;
+  font-style:italic;
+}
+
diff --git a/share/web/static/js/rulebuilder.js b/share/web/static/js/rulebuilder.js
new file mode 100644
index 0000000..62e9193
--- /dev/null
+++ b/share/web/static/js/rulebuilder.js
@@ -0,0 +1,152 @@
+RuleBuilder = function (sel) {
+    this.sel = sel;
+    /* defaults for now, should use ajax query */
+    this.functions = RuleBuilder.functions;
+    this.expressions = RuleBuilder.expressions;
+
+    this.current_application = null;
+    this.init();
+};
+
+RuleBuilder.functions = {
+    'or': { 'return_type': 'Bool' },
+    'and': { 'return_type': 'Bool' },
+    'RT.Condition.OnCreate': { 'return_type': 'Bool',
+                               'parameters':
+                               [{name: 'ticket', type: 'RT::Model::Ticket'},
+                                {name: 'transaction', type: 'RT::Model::Transaction'}
+                               ]},
+    'blah': { 'return_type': 'Str' }
+};
+
+RuleBuilder.expressions = [
+    { expression: 'ticket',
+      type: 'RT::Model::Ticket',
+    },
+    { expression: 'transaction',
+      type: 'RT::Model::Transaction',
+    }
+];
+
+RuleBuilder.prototype.init = function () {
+    var sel = this.sel;
+    var ebuilder = jQuery(sel);
+    var that = this;
+
+    jQuery._div({class: 'application'})
+            ._h3_().text("New Expression")
+            ._div_({class: 'application-function'})
+            ._div_({class: 'application-params'})
+          .div_()
+        .appendTo(ebuilder);
+
+    ebuilder.append('<h3>Functions</h3>');
+    ebuilder.append('<div class="functions">');
+    jQuery.each(this.functions,
+                function(key, val) {
+                    ebuilder.append('<div class="function ret_'+val.return_type+'"><span class="function_name">'+key+'</span> <span class="type">'+val.return_type+'</span></div>');
+                });
+    ebuilder.append('</div>');
+
+    this.update_expressions();
+
+    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();
+        });
+//    jQuery(this.sel+' div.application').hide();
+};
+
+RuleBuilder.prototype.update_expressions = function() {
+    var sel = this.sel;
+    var ebuilder = jQuery(sel);
+    var that = this;
+
+    jQuery('div.expressions', ebuilder).remove();
+
+    jQuery._div({class: 'expressions'})
+            ._h3_().text("Current Expressions")
+          .div_()
+        .appendTo(ebuilder);
+
+    var expressions_div = jQuery('div.expressions', ebuilder);
+
+    jQuery.each(this.expressions,
+                function(idx, val) {
+                    jQuery._div({class: 'expression ret_'+val.type})
+                            ._span_({ class: 'expression-text' }).text(val.expression)
+                            ._span_({ class: 'type' }).text(val.type)
+                          .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");
+                        }
+                      }).appendTo(expressions_div);
+                });
+};
+
+
+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-params').html('');
+    var params = jQuery(this.sel+' div.application-params');
+    var that = this;
+    jQuery.each(this.functions[this.current_application].parameters,
+                function(idx, val) {
+                    params.append('<span class="param param-placeholder">'+val.type+'</span> ').children(':last-child')
+         .click(function(e) {
+             jQuery(that.sel+ ' .param-placeholder').removeClass('current');
+             jQuery(this).addClass('current');
+             that.filter_expression_type(jQuery(this).text());
+             that.current_application_param = idx; });
+                });
+};
+
+RuleBuilder.prototype.add_expression = function () {
+    var params = jQuery.map(
+        jQuery(".application-params span.param"),
+        function(elt) { return elt.textContent });
+  
+    params.unshift(this.current_application);
+    var expression = {
+        expression: '('+params.join(' ')+')',
+        type: this.functions[this.current_application].return_type
+    };
+
+    this.expressions.push(expression);
+    this.update_expressions();
+}
+
+var e_sel = function(sel) {
+    return sel.replace(/:/g, '\\\\\\:');
+};
+
+var e_jquery = function(sel) {
+    return jQuery(e_sel(sel));
+};
+
+RuleBuilder.prototype.unfilter_return_type = function () {
+    jQuery(this.sel+' .function').show();
+};
+
+RuleBuilder.prototype.filter_return_type = function (type) {
+    jQuery(this.sel+' .function').show();
+    jQuery(this.sel+' .function').not(e_sel('.ret_'+type)).hide();
+};
+
+RuleBuilder.prototype.filter_expression_type = function (type) {
+    jQuery(this.sel+' .expression').show();
+    jQuery(this.sel+' .expression:not(.ret_'+e_sel(type)+')').hide();
+};
+

commit b59c91200560931f2b32e173ed480fee8ae185bc
Author: Chia-liang Kao <clkao at clkao.org>
Date:   Fri Jul 31 10:26:18 2009 +0100

    createdomnotes jquery plugin.

diff --git a/share/web/static/js/jquery.createdomnodes.js b/share/web/static/js/jquery.createdomnodes.js
new file mode 100644
index 0000000..bdba3b8
--- /dev/null
+++ b/share/web/static/js/jquery.createdomnodes.js
@@ -0,0 +1,86 @@
+/*
+ * jQuery CreateNode Plugin
+ * By Sylvain MATHIEU (www.sylvain-mathieu.com) for Zenexity (zenexity.fr)
+ * MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+
+jQuery.createDomNodes = {
+    virtualBracket: 0,
+    currentBracket: 0,
+    starter: false
+};
+
+jQuery.fn.applyAttrs = function(attrs) {
+    return this.each(function() {
+        var attrName;
+        for(attrName in attrs) {
+            jQuery(this).attr(attrName,attrs[attrName]);
+        }
+    });
+};
+
+jQuery.fn._tag_ = function(tagName, attrs, appendTag) {
+    if(jQuery.createDomNodes.virtualBracket>jQuery.createDomNodes.currentBracket||jQuery.createDomNodes.starter) {
+        jQuery.createDomNodes.starter = false;
+        jQuery.createDomNodes.currentBracket = jQuery.createDomNodes.virtualBracket;
+        return jQuery(document.createElement(tagName)).applyAttrs(attrs).appendTo(this);
+    }
+    else {
+        jQuery.createDomNodes.currentBracket = jQuery.createDomNodes.virtualBracket;
+        return jQuery(document.createElement(tagName)).applyAttrs(attrs).appendTo(this.parent());
+    }
+};
+
+jQuery.fn._tag = function(tagName, attrs) {
+    var tmp = this._tag_(tagName, attrs);
+    jQuery.createDomNodes.virtualBracket++;
+    return tmp;
+};
+
+jQuery.fn.tag_ = function() {
+    jQuery.createDomNodes.virtualBracket--;
+    return this.parent();
+};
+
+jQuery.fn._append_ = function(text) {
+    this.parent().append(text);
+    return this;
+};
+
+jQuery.addSupportedTag = function() {
+    var tagName = this;
+    jQuery.fn["_"+tagName+"_"] = function(attrs) {
+        return this._tag_(tagName, attrs);
+    };
+    jQuery.fn["_"+tagName] = function(attrs) {
+        return this._tag(tagName, attrs);
+    };
+    jQuery.fn[tagName+"_"] = function() {
+        return this.tag_();
+    };
+    jQuery["_"+tagName+"_"] = function(attrs) {
+        jQuery.createDomNodes.starter = true;
+        return jQuery(document.createElement(tagName)).applyAttrs(attrs);
+    };
+    jQuery["_"+tagName] = function(attrs) { 
+        jQuery.createDomNodes.starter = true;
+        return jQuery(document.createElement(tagName)).applyAttrs(attrs);
+    };
+};
+
+jQuery(document).ready(function(){
+    var supportedTags = [
+        "head","title","base","meta","link","style","script","noscript","body","div",
+        "span","p","h1","h2","h3","h4","h5","h6","ul","ol",
+        "li","dl","dt","dd","address","hr","pre","blockquote","ins","del",
+        "a","span","bdo","br","em","strong","dfn","code","samp","kbd",
+        "var","cite","abbr","acronym","q","sub","sup","tt","i","b",
+        "big","small","object","param","img","map","area",
+        "form","label","input","select","optgroup","option","textarea","fieldset","legend","fieldset",
+        "button","fieldset","table","caption","thead","tfoot","tbody","colgroup","col","tr",
+        "th","td"
+    ];
+    jQuery(supportedTags).each(jQuery.addSupportedTag);
+});
+
+

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


More information about the Rt-commit mailing list