summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: ec0f006)
raw | patch | inline | side by side (parent: ec0f006)
author | ber <ber@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Tue, 9 Nov 2010 15:06:14 +0000 (15:06 +0000) | ||
committer | ber <ber@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Tue, 9 Nov 2010 15:06:14 +0000 (15:06 +0000) |
for multilinkgs, see issue2550648.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/roundup/trunk@4576 57a73879-2fb5-44c3-a270-3262357dd7e2
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/roundup/trunk@4576 57a73879-2fb5-44c3-a270-3262357dd7e2
roundup/cgi/KeywordsExpr.py | [new file with mode: 0644] | patch | blob |
share/roundup/templates/classic/html/_generic.keywords_expr.html | [new file with mode: 0644] | patch | blob |
diff --git a/roundup/cgi/KeywordsExpr.py b/roundup/cgi/KeywordsExpr.py
--- /dev/null
@@ -0,0 +1,273 @@
+# This module is free software, you may redistribute it
+# and/or modify under the same terms as Python.
+
+WINDOW_CONTENT = '''\
+<h3>Keyword Expression Editor:</h3>
+<hr/>
+<div id="content"></div>
+<script type="text/javascript">
+<!--
+
+var NOT_OP = "-2";
+var AND_OP = "-3";
+var OR_OP = "-4";
+
+var original = "%(original)s";
+var current = original;
+var undo = [];
+
+var KEYWORDS = [
+ %(keywords)s
+];
+
+function find_keyword(x) {
+ for (var i = 0; i < KEYWORDS.length; ++i) {
+ if (KEYWORDS[i][0] == x) {
+ return KEYWORDS[i][1];
+ }
+ }
+ return "unknown";
+}
+
+function Equals(x) {
+ this.x = x;
+ this.brackets = false;
+
+ this.infix = function() {
+ return find_keyword(this.x);
+ }
+
+ this.postfix = function() {
+ return this.x;
+ }
+}
+
+function Not(x) {
+ this.x = x;
+ this.brackets = false;
+
+ this.infix = function() {
+ return this.x.brackets
+ ? "NOT(" + this.x.infix() + ")"
+ : "NOT " + this.x.infix();
+ }
+
+ this.postfix = function() {
+ return this.x.postfix() + "," + NOT_OP;
+ }
+}
+
+function And(x, y) {
+ this.x = x;
+ this.y = y;
+ this.brackets = true;
+
+ this.infix = function() {
+ var a = this.x.brackets ? "(" + this.x.infix() + ")" : this.x.infix();
+ var b = this.y.brackets ? "(" + this.y.infix() + ")" : this.y.infix();
+ return a + " AND " + b;
+ }
+ this.postfix = function() {
+ return this.x.postfix() + "," + this.y.postfix() + "," + AND_OP;
+ }
+}
+
+function Or(x, y) {
+ this.x = x;
+ this.y = y;
+ this.brackets = true;
+
+ this.infix = function() {
+ var a = this.x.brackets ? "(" + this.x.infix() + ")" : this.x.infix();
+ var b = this.y.brackets ? "(" + this.y.infix() + ")" : this.y.infix();
+ return a + " OR " + b;
+ }
+
+ this.postfix = function() {
+ return this.x.postfix() + "," + this.y.postfix() + "," + OR_OP;
+ }
+}
+
+function trim(s) {
+ return s.replace (/^\s+/, '').replace(/\s+$/, '');
+}
+
+function parse(s) {
+ var operators = s.split(",");
+ var stack = [];
+ for (var i = 0; i < operators.length; ++i) {
+ var operator = trim(operators[i]);
+ if (operator == "") continue;
+ if (operator == NOT_OP) {
+ stack.push(new Not(stack.pop()));
+ }
+ else if (operator == AND_OP) {
+ var a = stack.pop();
+ var b = stack.pop();
+ stack.push(new And(b, a));
+ }
+ else if (operator == OR_OP) {
+ var a = stack.pop();
+ var b = stack.pop();
+ stack.push(new Or(b, a));
+ }
+ else {
+ stack.push(new Equals(operator));
+ }
+ }
+ return stack.length > 0 ? stack.pop() : null;
+}
+
+function render_select(handler) {
+ var out = '<select name="keyword" id="keyword"';
+ if (handler != null) {
+ out += ' onchange="' + handler + '"';
+ }
+ out += '>';
+ out += '<option value="-1"><\/option>';
+ for (var i = 0; i < KEYWORDS.length; ++i) {
+ out += '<option value="' + KEYWORDS[i][0] +
+ '">' + KEYWORDS[i][1] + "<\/option>";
+ }
+ out += '<\/select>';
+ return out;
+}
+
+function first_select() {
+ var value = document.getElementById("keyword").value;
+ current = value;
+ set_content();
+}
+
+function not_clicked() {
+ var expr = parse(current);
+ if (expr == null) return;
+ undo.push(current);
+ current = expr instanceof Not
+ ? expr.x.postfix()
+ : new Not(expr).postfix();
+ set_content();
+}
+
+function not_b_wrap(expr) {
+ var value = document.getElementById("not_b").checked;
+ return value ? new Not(expr) : expr;
+}
+
+function and_clicked() {
+ var expr = parse(current);
+ if (expr == null) return;
+ var value = document.getElementById("keyword").value;
+ if (value == "-1") return;
+ undo.push(current);
+ current = new And(expr, not_b_wrap(new Equals(value))).postfix();
+ set_content();
+}
+
+function or_clicked() {
+ var expr = parse(current);
+ if (expr == null) return;
+ var value = document.getElementById("keyword").value;
+ if (value == "-1") return;
+ undo.push(current);
+ current = new Or(expr, not_b_wrap(new Equals(value))).postfix();
+ set_content();
+}
+
+function undo_clicked() {
+ current = undo.length > 0
+ ? undo.pop()
+ : original;
+ set_content();
+}
+
+function enable_and_or() {
+ var value = document.getElementById("keyword").value;
+ value = value == "-1";
+ document.getElementById("and").disabled = value;
+ document.getElementById("or").disabled = value;
+ document.getElementById("not_b").disabled = value;
+}
+
+function create() {
+ var expr = parse(current);
+ var out = "";
+ if (expr == null) {
+ out += "Keyword: ";
+ out += render_select("first_select();");
+ }
+ else {
+ out += '<table><tr>'
+ out += '<td><input type="button" name="not" onclick="not_clicked();" value="NOT"\/><\/td>';
+ out += "<td><tt><strong>" + expr.infix() + "<\/strong><\/tt><\/td>";
+ out += '<td><table>';
+ out += '<tr><td><input type="button" id="and" name="and" onclick="and_clicked();"'
+ + ' value="AND" disabled="disabled"\/><\/td><\/tr>';
+ out += '<tr><td><input type="button" id="or" name="or" onclick="or_clicked();"'
+ + ' value="OR" disabled="disabled"\/><\/td><\/tr>';
+ out += '<\/table><\/td>';
+ out += '<td><label for="not_b">NOT<\/label><br/>'
+ + '<input type="checkbox" name="not_b" id="not_b" disabled="disabled"\/><\/td>';
+ out += '<td>' + render_select("enable_and_or();") + '<\/td>';
+ out += '<\/tr><\/table>'
+ }
+ out += '<hr\/>';
+ if (undo.length > 0 || (undo.length == 0 && current != original)) {
+ out += '<input type="button" onclick="undo_clicked();" value="Undo"\/>';
+ }
+ out += '<input type="button" onclick="modify_main();" value="Apply"\/>'
+ + '<input type="button" onclick="window.close();" value="Close Window"\/>';
+ return out;
+}
+
+function main_content() {
+ var out = '';
+ out += '<input type="hidden" name="%(prop)s" value="' + current + '"\/>';
+ out += parse(current).infix();
+ return out;
+}
+
+function modify_main() {
+ main = window.opener.document.getElementById("keywords_%(prop)s");
+ main.innerHTML = main_content();
+}
+
+function set_content() {
+ document.getElementById("content").innerHTML = create();
+}
+
+set_content();
+//-->
+</script>
+'''
+
+def list_nodes(request):
+ prop = request.form.getfirst("property")
+ cls = request.client.db.getclass(prop)
+ items = []
+ for nodeid in cls.getnodeids():
+ l = cls.getnode(nodeid).items()
+ l = dict([x for x in l if len(x) == 2])
+ try:
+ items.append((l['id'], l['name']))
+ except KeyError:
+ pass
+ items.sort(key=lambda x: int(x[0]))
+ return items
+
+def items_to_keywords(items):
+ return ',\n '.join(['["%s", "%s"]' % x for x in items])
+
+
+def render_keywords_expression_editor(request):
+ prop = request.form.getfirst("property")
+
+ window_content = WINDOW_CONTENT % {
+ 'prop' : prop,
+ 'keywords': items_to_keywords(list_nodes(request)),
+ 'original': ''
+ }
+
+ return window_content
+
+# vim: set et sts=4 sw=4 :
diff --git a/share/roundup/templates/classic/html/_generic.keywords_expr.html b/share/roundup/templates/classic/html/_generic.keywords_expr.html
--- /dev/null
@@ -0,0 +1,11 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <link rel="stylesheet" type="text/css" href="@@file/style.css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8;" />
+ <title tal:content="string:Roundup Keywords Expression Editor"></title>
+ </head>
+ <body class="body"
+ tal:content="structure python:utils.keywords_expressions(request)">
+ </body>
+</html>