aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2016-04-02 02:06:31 -0400
committerPaul Duncan <pabs@pablotron.org>2016-04-02 02:06:31 -0400
commit6ceae6b02d89bfebbb3bec13ce9525014cbdd2a7 (patch)
tree3aa1292d70e199a7919c5ea522758e6d8ea0f5b6
parent23ba337de24e88c6aaf6ceb37507997f5c5f4920 (diff)
downloadold-guff-6ceae6b02d89bfebbb3bec13ce9525014cbdd2a7.tar.bz2
old-guff-6ceae6b02d89bfebbb3bec13ce9525014cbdd2a7.zip
add search-field and searching to users panel
-rw-r--r--data/stuff/js/search-field.js79
-rw-r--r--data/stuff/js/util.js15
-rw-r--r--data/stuff/test/auth.js30
-rw-r--r--src/guff/views/ecrs/test/auth.ecr80
-rw-r--r--src/guff/views/html/test/auth.cr6
5 files changed, 191 insertions, 19 deletions
diff --git a/data/stuff/js/search-field.js b/data/stuff/js/search-field.js
new file mode 100644
index 0000000..42bec10
--- /dev/null
+++ b/data/stuff/js/search-field.js
@@ -0,0 +1,79 @@
+jQuery(function($) {
+ "use strict";
+
+ function clear_delay(el) {
+ var ival = el.data('search-interval');
+
+ if (ival) {
+ // clear interval
+ clearInterval(ival);
+ el.data('search-interval', null);
+ }
+ }
+
+ function trigger_search(el, q) {
+ if (q == el.data('q'))
+ return;
+
+ // cache search
+ el.data('q', q);
+
+ // trigger search
+ el.trigger({
+ type: "search-update",
+ query: "",
+ });
+ }
+
+ $('.btn.search-toggle').click(function() {
+ var btn = $(this),
+ bar = btn.parents('.panel').find('.panel-heading.search-toggle'),
+ field = bar.find('input');
+
+ // toggle button highlight
+ btn.toggleClass('btn-primary btn-default')
+ var active = btn.hasClass('btn-primary');
+
+ // clear field
+ field.val('');
+
+ // toggle bar visibility
+ bar.toggleClass('hidden', !active);
+
+ if (active) {
+ setTimeout(function() {
+ // focus text field
+ field.focus();
+ }, 10);
+ } else {
+ // trigger search
+ trigger_search(field, '');
+ }
+ });
+
+ $('.panel-heading.search-toggle input').keydown(function(ev) {
+ var me = $(this),
+ trigger = me.data('search-trigger') || 'delay';
+
+ if (trigger == 'delay') {
+ clear_delay(me);
+
+ setTimeout(function() {
+ clear_delay(me);
+ trigger_search(me, me.val());
+ }, me.data('search-delay') || 100);
+ } else if (trigger == 'enter') {
+ if (ev.which == 13) {
+ setTimeout(function() {
+ trigger_search(me, me.val());
+ }, 10);
+
+ // stop event
+ return false;
+ }
+ } else {
+ // unknown trigger type
+ throw new Error('unknown search trigger: ' + trigger);
+ }
+ });
+});
diff --git a/data/stuff/js/util.js b/data/stuff/js/util.js
index c021499..ed048ec 100644
--- a/data/stuff/js/util.js
+++ b/data/stuff/js/util.js
@@ -1,3 +1,18 @@
+$.fn.reduce = (function() {
+ if (Array.prototype.reduce) {
+ return Array.prototype.reduce;
+ } else {
+ return function(a, cb, r) {
+ a = [].concat(a);
+
+ for (var i = 0, l = a.length; i < l; i++)
+ r = cb(r, a[i]);
+
+ return r;
+ };
+ }
+})();
+
jQuery(function($) {
"use strict";
diff --git a/data/stuff/test/auth.js b/data/stuff/test/auth.js
index 0776bfd..3960da6 100644
--- a/data/stuff/test/auth.js
+++ b/data/stuff/test/auth.js
@@ -7,6 +7,7 @@ jQuery(function($) {
"class='list-group-item %{css|h}' ",
"title='Edit user \"%{user_name|h}\".' ",
"data-row='%{row|json|h}' ",
+ "data-q='%{q|h}' ",
">",
"<i class='fa fa-fw fa-spinner fa-spin hidden loading'></i>",
"<i class='fa fa-fw fa-user loading'></i>",
@@ -34,6 +35,27 @@ jQuery(function($) {
],
});
+ function filter() {
+ var qs = $('#filter-q').val().replace(/^\s+|\s+$/g, '').toLowerCase().split(/\s+/);
+
+ if (qs.length > 0) {
+ // hide all users
+ $('#users .list-group-item').addClass('hidden');
+
+ // show matching users
+ $($.grep($('#users .list-group-item'), function(el) {
+ var eq = $(el).data('q');
+
+ return ($.grep(qs, function(q) {
+ return eq.indexOf(q) !== -1;
+ }).length == qs.length);
+ })).removeClass('hidden');
+ } else {
+ // show all users
+ $('#users .list-group-item').removeClass('hidden');
+ }
+ }
+
function reload() {
var btn = $('#reload'),
list = $('#users');
@@ -51,9 +73,13 @@ jQuery(function($) {
}).done(function(r) {
list.html($.map(r.users, function(row) {
return TEMPLATES.run('user', $.extend({}, row, {
+ q: [row.user_id, row.user_name, row.email, row.role_name].join(' ').toLowerCase(),
row: row,
}));
}).join(''));
+
+ // refresh filters
+ filter();
});
// stop event
@@ -70,6 +96,10 @@ jQuery(function($) {
});
}
+ $('#filter-q').on('search-update', function() {
+ filter();
+ });
+
$('#users').on('click', 'a.list-group-item', function() {
var me = $(this);
diff --git a/src/guff/views/ecrs/test/auth.ecr b/src/guff/views/ecrs/test/auth.ecr
index ab9f552..00cc918 100644
--- a/src/guff/views/ecrs/test/auth.ecr
+++ b/src/guff/views/ecrs/test/auth.ecr
@@ -27,25 +27,8 @@
<div class='btn-group btn-group-xs pull-right'>
<a
href='#'
- id='reload'
- class='btn btn-default btn-xs'
- title='Reload users.'
- >
- <span class='loading'>
- <i class='fa fa-refresh'></i>
- </span>
-
- <span class='loading hidden'>
- <i class='fa fa-spinner fa-spin'></i>
- </span>
- </a><!-- #reload -->
- </div><!-- btn-group -->
-
- <div class='btn-group btn-group-xs pull-right'>
- <a
- href='#'
class='btn btn-primary btn-xs'
- title='Add new user.'
+ title='Create new user.'
data-toggle='modal'
data-target='#add-dialog'
>
@@ -55,6 +38,67 @@
</div><!-- btn-group -->
</div><!-- panel-heading -->
+ <div class='panel-heading'>
+ <div class='btn-toolbar'>
+ <div class='btn-group btn-group-sm'>
+ <a
+ href='#'
+ class='btn btn-default'
+ title='Filter users by role.'
+ data-toggle='dropdown'
+ >
+ Role: <span></span>
+ <i class='fa fa-caret-down'></i>
+ </a>
+
+ <ul id='filter-roles' class='dropdown-menu'>
+ </ul>
+ </div><!-- btn-group -->
+
+ <div class='btn-group btn-group-sm pull-right'>
+ <a
+ href='#'
+ id='reload'
+ class='btn btn-default'
+ title='Reload users.'
+ >
+ <span class='loading'>
+ <i class='fa fa-refresh'></i>
+ </span>
+
+ <span class='loading hidden'>
+ <i class='fa fa-spinner fa-spin'></i>
+ </span>
+ </a><!-- #reload -->
+ </div><!-- btn-group -->
+
+ <div class='btn-group btn-group-sm pull-right'>
+ <a
+ href='#'
+ class='btn btn-default search-toggle'
+ title='Toggle search field.'
+ >
+ <i class='fa fa-search'></i>
+ </a><!-- btn-->
+ </div><!-- btn-group -->
+ </div><!-- btn-toolbar -->
+ </div><!-- panel-heading -->
+
+ <div class='panel-heading hidden search-toggle'>
+ <div class='input-group input-group-sm'>
+ <span class='input-group-addon'>
+ <i class='fa fa-search'></i>
+ </span>
+
+ <input
+ type='text'
+ id='filter-q'
+ class='form-control'
+ title='Enter search terms'
+ />
+ </div><!-- input-group -->
+ </div><!-- panel-heading -->
+
<div id='users' class='list-group'>
<span class='list-group-item disabled'>
<i class='fa fa-spinner fa-spin'></i>
diff --git a/src/guff/views/html/test/auth.cr b/src/guff/views/html/test/auth.cr
index 1baa7de..528b652 100644
--- a/src/guff/views/html/test/auth.cr
+++ b/src/guff/views/html/test/auth.cr
@@ -4,6 +4,10 @@ require "../page"
class Guff::TestAuthHTMLView
TITLE = "Guff Auth Test"
FEATURES = %w{bootstrap font-awesome guff/util}
+ SCRIPTS = %w{
+ /guff-stuff/js/search-field.js
+ /guff-stuff/test/auth.js
+ }
TEMPLATES = TemplateCache.new({
role: "
@@ -27,7 +31,7 @@ class Guff::TestAuthHTMLView
def run(context)
page = PageHTMLView.new(TITLE, self.to_s)
page.add_features(FEATURES)
- page.scripts << "/guff-stuff/test/auth.js"
+ page.scripts.concat(SCRIPTS)
context.response.content_type = page.content_type
context.response.puts page
end