enrolments MDL-24317 Permission filter now remembers what you type into it.
authorSam Hemelryk <sam@moodle.com>
Tue, 21 Sep 2010 06:09:14 +0000 (06:09 +0000)
committerSam Hemelryk <sam@moodle.com>
Tue, 21 Sep 2010 06:09:14 +0000 (06:09 +0000)
admin/roles/lib.php
admin/roles/module.js
lib/outputrequirementslib.php
theme/standard/style/admin.css

index a42e712..d77694d 100644 (file)
@@ -85,7 +85,8 @@ abstract class capability_table_base {
     public function display() {
         if (count($this->capabilities) > capability_table_base::NUM_CAPS_FOR_SEARCH) {
             global $PAGE;
-            $PAGE->requires->js_init_call('M.core_role.init_cap_table_filter', array($this->id, get_string('filter'), get_string('clear')));
+            $PAGE->requires->strings_for_js(array('filter','clear'),'moodle');
+            $PAGE->requires->js_init_call('M.core_role.init_cap_table_filter', array($this->id, $this->context->id));
         }
         echo '<table class="' . implode(' ', $this->classes) . '" id="' . $this->id . '">' . "\n<thead>\n";
         echo '<tr><th class="name" align="left" scope="col">' . get_string('capability','role') . '</th>';
index 08bec4d..c306400 100644 (file)
-/* This class filters the rows of a table like the one on the define or
-override roles pages. It adds a search box just above the table, and if
-content is typed into that box, it hides any rows in the table where the
-capability name does not contain that text. */
-
+/**
+ * This class filters the rows of a table like the one on the define or
+ * override roles pages. It adds a search box just above the table, and if
+ * content is typed into that box, it hides any rows in the table where the
+ * capability name does not contain that text.
+ */
+
+/**
+ * Role namespace
+ */
 M.core_role = {};
 
-M.core_role.init_cap_table_filter = function(Y, tableid, strsearch, strclear) {
-    var CapTableFilter = function(tableid, strsearch, strclear) {
-        this.delayhandle = -1,
-        this.searchdelay = 100, // milliseconds
-
-        // Find the form controls.
-        this.table = document.getElementById(tableid);
-
-        // Create a div to hold the search UI.
-        this.div = document.createElement('div');
-        this.div.className = 'capabilitysearchui';
-        this.div.style.width = this.table.offsetWidth + 'px';
-
-        // Create the capability search input.
-        this.input = document.createElement('input');
-        this.input.type = 'text';
-        this.input.id = tableid + 'capabilitysearch';
-
-        // Create a label for the search input.
-        this.label = document.createElement('label');
-        this.label.htmlFor = this.input.id;
-        this.label.appendChild(document.createTextNode(strsearch + ' '));
-
-        // Create a clear button to clear the input.
-        this.button = document.createElement('input');
-        this.button.value = strclear;
-        this.button.type = 'button';
-        this.button.disabled = true;
-
-        // Tie it all together
-        this.div.appendChild(this.label);
-        this.div.appendChild(this.input);
-        this.div.appendChild(this.button);
-        this.table.parentNode.insertBefore(this.div, this.table);
-        Y.on('keyup', this.change, this.input, this);
-        Y.on('click', this.clear, this.button, this);
-
-        // Horrible hack!
-        var hidden = document.createElement('input');
-        hidden.type = 'hidden';
-        hidden.disabled = true;
-        this.div.appendChild(hidden);
-        hidden = document.createElement('input');
-        hidden.type = 'hidden';
-        hidden.disabled = true;
-        this.div.appendChild(hidden);
-    };
-
-    CapTableFilter.prototype.clear = function () {
-        this.input.value = '';
-        if (this.delayhandle != -1) {
-            clearTimeout(this.delayhandle);
-            this.delayhandle = -1;
-        }
-        this.filter();
-    };
-
-    CapTableFilter.prototype.change = function() {
-        var self = this;
-        var handle = setTimeout(function(){self.filter();}, this.searchdelay);
-        if (this.delayhandle != -1) {
-            clearTimeout(this.delayhandle);
-        }
-        this.delayhandle = handle;
-    };
-
-    CapTableFilter.prototype.set_visible = function(row, visible) {
-        if (visible) {
-            Y.one(row).removeClass('hiddenrow');
-        } else {
-            Y.one(row).addClass('hiddenrow');
-        }
+/**
+ * @param {YUI} Y
+ * @param {string} tableid
+ * @param {int} contextid
+ */
+M.core_role.init_cap_table_filter = function(Y, tableid, contextid) {
+
+    var CapTableFilter = function(tableid) {
+        this.tableid = tableid;
+        this.context = contextid;
+        this.initializer();
     };
-
-    CapTableFilter.prototype.filter = function() {
-        var filtertext = this.input.value.toLowerCase();
-        this.button.disabled = (filtertext == '');
-        var lastheading = null;
-        var capssincelastheading = 0;
-
-        Y.all('#'+this.table.id+' tr').each(function(row, index, list) {
-            if (row.hasClass('rolecapheading')) {
-                if (lastheading) {
-                    this.set_visible(lastheading, capssincelastheading > 0);
-                }
-                lastheading = row;
-                capssincelastheading = 0;
+    CapTableFilter.prototype = {
+        tableid : null,     // ID of the cap table
+        context : null,    // Context ID associated with what ever we are looking at
+        delayhandle : -1,
+        searchdelay : 100,  // milliseconds
+        table : null,
+        div : null,
+        input : null,
+        label : null,
+        button : null,
+        /**
+         * Initialises the CapTableFilter object.
+         * This is called initializer so that a move to convert this to a proper
+         * YUI module will be easier.
+         */
+        initializer : function() {
+            // Get any existing filter value
+            var filtervalue = this.getFilterCookieValue();
+
+            // Find the form controls.
+            this.table = Y.one('#'+this.tableid);
+
+            // Create a div to hold the search UI.
+            this.div = Y.Node.create('<div class="capabilitysearchui"></div>').setStyle('width', this.table.get('offsetWidth'));
+            // Create the capability search input.
+            this.input = Y.Node.create('<input type="text" id="'+this.table.get('id')+'capabilitysearch" value="'+filtervalue+'" />');
+            // Create a label for the search input.
+            this.label = Y.Node.create('<label for="'+this.input.get('id')+'">'+M.str.moodle.filter+' </label>');
+            // Create a clear button to clear the input.
+            this.button = Y.Node.create('<input type="button" value="'+M.str.moodle.clear+'" />').set('disabled', filtervalue=='');
+
+            // Tie it all together
+            this.div.append(this.label).append(this.input).append(this.button);
+
+            // Insert it into the div
+            this.table.ancestor().insert(this.div, this.table);
+
+            // Wire the events so it actually does something
+            this.input.on('keyup', this.change, this);
+            this.button.on('click', this.clear, this);
+
+            if (filtervalue != '') {
+                this.filter();
             }
-            if (row.hasClass('rolecap')) {
-                var capname = row.one('.cap-name').get('text') + '|' + row.one('.cap-desc a').get('text').toLowerCase();
-                if (capname.indexOf(filtertext) >= 0) {
-                    this.set_visible(row, true);
-                    capssincelastheading += 1;
-                } else {
-                    this.set_visible(row, false);
-                }
+        },
+        /**
+         * Sets a cookie that describes the filter value.
+         * The cookie stores the context, and the time it was created and upon
+         * retrieval is checked to ensure that the cookie is for the correct
+         * context and is no more than an hour old.
+         */
+        setFilterCookieValue : function(value) {
+            var cookie = {
+                fltcontext : this.context,
+                flttime : new Date().getTime(),
+                fltvalue : value
             }
-        }, this);
-
-        if (lastheading) {
-            this.set_visible(lastheading, capssincelastheading > 0);
+            Y.Cookie.setSubs("captblflt", cookie);
+        },
+        /**
+         * Gets the existing filter value if there is one.
+         * The cookie stores the context, and the time it was created and upon
+         * retrieval is checked to ensure that the cookie is for the correct
+         * context and is no more than an hour old.
+         */
+        getFilterCookieValue : function() {
+            var cookie = Y.Cookie.getSubs('captblflt');
+            if (cookie.fltcontext && cookie.fltcontext == this.context && parseInt(cookie.flttime) > new Date().getTime()-(60*60*1000)) {
+                return cookie.fltvalue;
+            }
+            return '';
+        },
+        /**
+         * Clears the filter value.
+         */
+        clear : function() {
+            this.input.set('value', '');
+            if (this.delayhandle != -1) {
+                clearTimeout(this.delayhandle);
+                this.delayhandle = -1;
+            }
+            this.filter();
+        },
+        /**
+         * Event callback for when the filter value changes
+         */
+        change : function() {
+            var self = this;
+            var handle = setTimeout(function(){self.filter();}, this.searchdelay);
+            if (this.delayhandle != -1) {
+                clearTimeout(this.delayhandle);
+            }
+            this.delayhandle = handle;
+        },
+        /**
+         * Marks a row as visible or hidden
+         */
+        setVisible : function(row, visible) {
+            if (visible) {
+                row.removeClass('hiddenrow');
+            } else {
+                row.addClass('hiddenrow');
+            }
+        },
+        /**
+         * Filters the capability table
+         */
+        filter : function() {
+            var filtertext = this.input.get('value').toLowerCase(),
+                lastheading = null;
+
+            this.setFilterCookieValue(filtertext);
+            
+            this.button.set('disabled', (filtertext == ''));
+
+            this.table.all('tr').each(function(row){
+                if (row.hasClass('rolecapheading')) {
+                    this.setVisible(row, false);
+                    lastheading = row;
+                }
+                if (row.hasClass('rolecap')) {
+                    var capname = row.one('.cap-name').get('text') + '|' + row.one('.cap-desc a').get('text').toLowerCase();
+                    if (capname.indexOf(filtertext) >= 0) {
+                        this.setVisible(row, true);
+                        if (lastheading) {
+                            this.setVisible(lastheading, true);
+                            lastheading = null;
+                        }
+                    } else {
+                        this.setVisible(row, false);
+                    }
+                }
+            }, this);
         }
-    };
+    }
 
-    new CapTableFilter(tableid, strsearch, strclear);
+    new CapTableFilter(tableid);
 };
 
-
 M.core_role.init_add_assign_page = function(Y) {
     var add = Y.one('#add');
     var addselect = M.core_user.get_user_selector('addselect');
index 7b507a0..c0b112b 100644 (file)
@@ -418,7 +418,8 @@ class page_requirements_manager {
                     break;
                 case 'core_role':
                     $module = array('name'     => 'core_role',
-                                    'fullpath' => '/admin/roles/module.js');
+                                    'fullpath' => '/admin/roles/module.js',
+                                    'requires' => array('node', 'cookie'));
                     break;
                 case 'core_completion':
                     $module = array('name'     => 'core_completion',
index f5601c5..e204c12 100644 (file)
@@ -56,6 +56,7 @@
 #page-admin-uploaduser table#uuresults {font-size: 0.9em;}
 #page-admin-auth_config .required {background-color:#DDDDDD;}
 #page-admin-report-unittest-index .sep {color:#AAAAAA;}
+.path-admin-roles .capabilitysearchui {text-align:center;margin:0.5em;}
 
 .path-admin .rolecap .cap-name,
 .path-admin .rolecap .note {color: #888;font-size: 0.75em;}