Add Favorite filters to nextmatch - W.I.P

This commit is contained in:
Nathan Gray 2013-02-27 18:13:54 +00:00
parent 9616e44aff
commit 9a7f5102cf
5 changed files with 392 additions and 18 deletions

View File

@ -70,6 +70,8 @@
* 'selected' => // O array with selected id's
* 'checkboxes' => // O array with checkbox id as key and boolean checked value
* 'select_all' => // O boolean value of select_all checkbox, reference to above value for key 'select_all'
* 'favorites' => // I boolean|array True to enable favorites, or an array of additional, app specific settings to include
* in the saved filters (eg: pm_id)
*/
class etemplate_widget_nextmatch extends etemplate_widget
{
@ -135,6 +137,13 @@ class etemplate_widget_nextmatch extends etemplate_widget
}
}
}
// Favorite group for admins
if($GLOBALS['egw_info']['apps']['admin'] && $value['favorites'])
{
self::$request->sel_options[$form_name]['favorite']['group'] = array('all' => lang('All users')) +
etemplate_widget_menupopup::typeOptions('select-account',',groups');
}
foreach($value as $name => $_value)
{
if(strpos($name, 'options-') !== false)
@ -735,6 +744,7 @@ class etemplate_widget_nextmatch extends etemplate_widget
{
$form_name = self::form_name($cname, $this->id, $expand);
$value = self::get_array($content, $form_name);
list($app) = explode('.',$this->attrs['template']);
// On client, rows does not get its own namespace, but all apps are expecting it
$value['rows'] = $value;
@ -750,7 +760,6 @@ class etemplate_widget_nextmatch extends etemplate_widget
if($value['as_default'])
{
unset($value['as_default']);
list($app) = explode('.',$this->attrs['template']);
if($GLOBALS['egw_info']['user']['apps']['admin'] && $app)
{
$pref_name = 'nextmatch-' . (isset($value['columnselection_pref']) ? $value['columnselection_pref'] : $this->attrs['template']);
@ -770,6 +779,46 @@ class etemplate_widget_nextmatch extends etemplate_widget
$validated[$form_name] = $value;
}
/**
* Create or delete a favorite for multiple users
*
* Need to be an admin or it will just do nothing quietly
*
* @param $app Current application, needed to save preference
* @param $name String Name of the favorite
* @param $action String add or delete
* @param $group int|String ID of the group to create the favorite for, or All for all users
* @param $filters Array of key => value pairs for the filter
*
* @return boolean Success
*/
public static function ajax_set_favorite($app, $name, $action, $group, $filters = array())
{
$pref_name = "favorite_".$name;
if($group && $GLOBALS['egw']['apps']['admin'])
{
$prefs = new preferences(is_numeric($group) ? $group: $GLOBALS['egw_info']['user']['account_id']);
}
else
{
$prefs =& $GLOBALS['egw']->preferences;
$type = 'user';
}
$type = $group == "all" ? "default" : "user";
if($action == "add")
{
$prefs->add($app,$pref_name,$filters,$type);
}
else if ($action == "delete")
{
$prefs->delete($app,$pref_name, $type);
}
$prefs->save_repository(false,$type);
egw_json_response::get()->data(true);
}
/**
* Run a given method on all children
*

View File

@ -247,12 +247,36 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput], {
applyFilters: function() {
this.egw().debug("info", "Changing nextmatch filters to ", this.activeFilters);
if(typeof this.activeFilters == "undefined")
{
this.activeFilters = {col_filter: {}};
}
if(typeof this.activeFilters.col_filter == "undefined")
{
this.activeFilters.col_filter = {};
}
// Update the filters in the grid controller
this.controller.setFilters(this.activeFilters);
// Update the header
this.header.setFilters(this.activeFilters);
// Update any column filters
this.iterateOver(function(column) {
if(typeof column.set_value != "undefined" && column.id)
{
column.set_value(typeof this[column.id] == "undefined" ? "" : this[column.id]);
}
if (column.id && typeof column.get_value == "function")
{
this[column.id] = column.get_value();
}
}, this.activeFilters.col_filter, et2_INextmatchHeader);
// Trigger an update
this.controller.update();
this.controller.update(true);
},
/**
@ -269,15 +293,16 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput], {
refresh: function(_row_ids, _type) {
if (typeof _type == 'undefined') _type = 'edit';
if (typeof _row_ids == 'string') _rowids = [_row_ids];
if (typeof _row_ids == "undefined")
{
this.applyFilters();
return;
}
// Use jsapi data module to update
var list = et2_csvSplit(this.options.settings.get_rows, 2, ".");
var app = list[0];
if(typeof _row_ids == "string")
{
_row_ids = _row_ids.split(",");
}
id_loop:
for(var i = 0; i < _row_ids.length; i++)
{
@ -922,7 +947,6 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput], {
var refresh_preference = "nextmatch-" + this.options.settings.columnselection_pref + "-autorefresh";
var app = this.options.template.split(".");
return this.egw().preference(refresh_preference,app[0]);
console.log(this);
},
/**
@ -1061,6 +1085,9 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
destroy: function() {
this.nextmatch = null;
this.div = null;
this.favorites = null;
this.favorites_popup.dialog("destroy");
this.favorites_popup = null;
},
setNextmatch: function(nextmatch) {
@ -1124,6 +1151,9 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
self.nextmatch.applyFilters();
}
}
// Set activeFilters to current value
self.nextmatch.activeFilters[_widget.id] = _widget.getValue();
}, this, et2_inputWidget);
}
}
@ -1173,9 +1203,12 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
// Search
this.search = et2_createWidget("textbox", {"blur":egw.lang("search")}, this);
this.search = et2_createWidget("textbox", {"id":"search","blur":egw.lang("search")}, this);
this.search.input.attr("type", "search");
this.search.input.val(settings.search);
// Set activeFilters to current value
this.nextmatch.activeFilters.search = settings.search;
this.search_button = et2_createWidget("button", {"label":">"}, this);
this.search_button.onclick = function(event) {
@ -1220,6 +1253,8 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
event.data.activeFilters.searchletter = (letter == "" ? false : letter);
event.data.applyFilters();
});
// Set activeFilters to current value
this.nextmatch.activeFilters.searchletter = current_letter;
}
},
@ -1283,6 +1318,9 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
// Set value
select.set_value(value);
// Set activeFilters to current value
this.nextmatch.activeFilters[select.id] = select.get_value();
// Set onChange
var input = select.input;
@ -1324,12 +1362,20 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
/**
* Set up the favorites UI control
*
* Favorites are implemented by saving the values for [column] filters. Filters used/stored are
* listed in the favorites nm setting.
* Favorites are implemented by saving the values for [column] filters. Filters are stored
* in preferences, with the name favorite_<name>. The favorite favorite used for clicking on
* the filter button is stored in nextmatch-<columnselection_pref>-favorite.
*
* @param filters Array|boolean The nextmatch setting for favorites. Either true, or a list of
* additional fields/settings to add in to the favorite.
*/
_setup_favorites: function(filters) {
var self = this;
// Some convenient variables, used in closures / event handlers
var header = this;
var nextmatch = this.nextmatch;
var nm_div = this.nextmatch.div;
var favorite_prefix = "favorite_";
var favorite_preference = "nextmatch-" + nextmatch.options.settings.columnselection_pref + "-favorite";
if(typeof filters == "undefined")
{
@ -1337,23 +1383,254 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
return;
}
var list = et2_csvSplit(this.options.get_rows, 2, ".");
var app = list[0];
var stored_filters = this.egw().preference("nextmatch-"+this.options.columnselection_pref+"-favorites", app);
// Load saved favorites
var stored_filters = {};
var preferences = this.egw().preference("*",app);
for(var pref_name in preferences)
{
if(pref_name.indexOf(favorite_prefix) == 0)
{
stored_filters[pref_name.substr(favorite_prefix.length)] = preferences[pref_name];
}
}
if(typeof stored_filters == "undefined" || !stored_filters)
{
stored_filters = {};
}
/*
// Create filter options
var init_filters = function()
{
var options = {};
for(var name in stored_filters)
{
options[name] = "<input type='radio' name='favorite[button][favorite]' value='"+name+"'/>"+name;
}
options.add = "<img src='"+header.egw().image("new") +"'/>Add current";
return options;
};
// Favorite dropdown button
this.favorites = et2_createWidget("dropdown_button", {
id: "nm_favorites",
id: "favorite[button]",
label: "",
label_updates: false,
image: "etemplate/filter",
onclick: self.applyFilters,
select_options: stored_filters
image: "etemplate/fav_filter",
tooltip: "Favorite queries"
}, this);
this.favorites.onclick= function(node) {
// Apply preferred filter - make sure it's an object, and not a reference
nextmatch.activeFilters = jQuery.extend({},stored_filters[header.egw().preference(favorite_preference,app)]);
nextmatch.applyFilters();
};
var preferred = this.egw().preference(favorite_preference, app);
this.favorites.set_value(preferred && stored_filters[preferred] ? preferred : "");
this.favorites.set_select_options(init_filters());
// Apply the favorite when you pick from the list
this.favorites.change = function(selected_node) {
if(this.get_value() == "add")
{
// Get current filters
header.favorites_popup.current_filters = $j.extend({},nextmatch.activeFilters);
// Add in application's settings
if(filters != true)
{
for(var i = 0; i < filters.length; i++)
{
header.favorites_popup.current_filters[filters[i]] = nextmatch.options.settings[filters[i]];
}
}
// Remove some internal values
delete header.favorites_popup.current_filters[header.favorites.id];
delete header.favorites_popup.current_filters[header.favorites_popup.group.id];
// Make sure it's an object
header.favorites_popup.current_filters = jQuery.extend({},header.favorites_popup.current_filters);
// Update popup with current set filters (more for debug than user)
var filter_list = [];
var add_to_popup = function(arr) {
filter_list.push("<ul>");
jQuery.each(arr, function(index, filter) {
filter_list.push("<li id='index'><span class='filter_id'>"+index+"</span>" +
(typeof filter != "object" ? "<span class='filter_value'>"+filter+"</span>": "")
);
if(typeof filter == "object" && filter != null) add_to_popup(filter);
filter_list.push("</li>");
});
filter_list.push("</ul>");
}
add_to_popup(header.favorites_popup.current_filters);
$j("#nm_favorites_popup_filters",header.favorites_popup)
.replaceWith(
$j(filter_list.join("")).attr("id","nm_favorites_popup_filters")
);
// Popup
header.favorites_popup.dialog("open");
}
else if(stored_filters[this.get_value()])
{
// Apply selected filter - make sure it's an object, and not a reference
nextmatch.activeFilters = jQuery.extend({},stored_filters[this.get_value()]);
nextmatch.applyFilters();
}
};
// Set radio to current value
$j("input[value='"+ preferred +"']:radio", this.favorites.menu).attr("checked",true);
// Add a listener on the radio buttons to set default filter
$j(this.favorites.menu).on("click","input:radio",function(event){
// Don't do the menu
event.stopImmediatePropagation();
// Save as default favorite - used when you click the button
header.egw().set_preference(app,favorite_preference,$j(this).val());
// Close the menu
header.favorites.menu.hide();
// Some user feedback
header.favorites.button.addClass("ui-state-active", 500,"swing",function(){
header.favorites.button.removeClass("ui-state-active",2000);
});
});
// Add into header
$j(this.favorites.getDOMNode(this.favorites)).insertAfter(this.count).css("float","right");
*/
// Create popup
this.favorites_popup = $j('<div id="nm_favorites_popup" title="' + egw().lang("New favorite") + '">\
<form>\
<label for="name">'+
this.egw().lang("name") +
'</label>' +
'<input type="text" name="name" id="name"/>\
<div id="nm_favorites_popup_admin"/>\
<ul id="nm_favorites_popup_filters"/>\
</form>\
</div>');
this.favorites_popup.name = et2_createWidget("text",{id:"favorite[name]"},this);
$j("name",this.favorites_popup).replaceWith(this.favorites_popup.name.getDOMNode());
// Add some controls if user is an admin
var apps = this.egw().user('apps');
if(apps['admin'])
{
this.favorites_popup.group = et2_createWidget("select-account",{
id: "favorite[group]",
account_type: "groups",
empty_label: "Groups",
no_lang: true
},this);
$j("#nm_favorites_popup_admin",this.favorites_popup)
.append(this.favorites_popup.group.getDOMNode(this.favorites_popup.group));
}
var buttons = {};
buttons[this.egw().lang("save")] = function() {
// Add a new favorite
var name = $j("#name",this);
if(name.val())
{
// Add to the list
stored_filters[name.val()] = header.favorites_popup.current_filters;
header.favorites.set_select_options(init_filters());
var favorite_pref = favorite_prefix+name.val();
// Save to preferences
if(typeof header.favorites_popup.group != "undefined")
{
// Admin stuff - save preference server side
var request = new egw_json_request("etemplate_widget_nextmatch::ajax_set_favorite::etemplate",
[app, name.val(), "add", header.favorites_popup.group.get_value(), header.favorites_popup.current_filters],
header
);
request.sendRequest(true, function(result) {
if(result)
{
// Do something nice and confirmy if result is true - not really needed
}
}, header);
}
else
{
// Normal user - just save to preferences client side
header.egw().set_preference(app,favorite_pref,header.favorites_popup.current_filters);
}
delete header.favorites_popup.current_filters;
}
// Reset form
name.val("");
header.favorites_popup.group.set_value("");
$j("#filters",header.favorites_popup).empty();
$j(this).dialog("close");
};
buttons[this.egw().lang("cancel")] = function() {
$j(this).dialog("close");
};
this.favorites_popup.dialog({
autoOpen: false,
modal: true,
buttons: buttons,
close: function() {
}
});
},
/**
* Updates all the filter elements in the header
*
* Does not actually refresh the data, just sets values to match those given.
* Called by et2_nextmatch.applyFilters().
*
* @param filters Array Key => Value pairs of current filters
*/
setFilters: function(filters) {
this.iterateOver(function(child) {
if(typeof child.set_value != "undefined" && child.id)
{
child.set_value(typeof this[child.id] == "undefined" ? "" : this[child.id]);
}
if(typeof child.get_value == "function" && child.id)
{
this[child.id] = child.get_value();
}
}, filters);
// Letter search
if(this.nextmatch.options.settings.lettersearch)
{
jQuery("td",this.lettersearch).removeClass("lettersearch_active");
$j(filters.searchletter ? "td#"+filters.searchletter : "td.lettersearch[id='']").addClass("lettersearch_active");
// Set activeFilters to current value
filters.searchletter = $j("td.lettersearch_active").attr("id")
}
// Remove some internal values
if(typeof this.favorites != "undefined")
{
delete filters[this.favorites.id];
delete filters[this.favorites_popup.group.id];
}
},
/**

View File

@ -287,6 +287,16 @@ var et2_dropdown_button = et2_inputWidget.extend({
this.change(selected_node);
},
attachToDOM: function() {
this._super.apply(this, arguments);
// Move the parent's handler to the button, or we can't tell the difference between the clicks
$j(this.node).unbind("click.et2_baseWidget");
this.button.bind("click.et2_baseWidget", this, function(e) {
return e.data.click.call(e.data, this);
});
},
set_label: function(_value) {
if (this.button)
{
@ -345,6 +355,10 @@ var et2_dropdown_button = et2_inputWidget.extend({
this.set_label(this.options.label);
}
}
},
getValue: function() {
return this.value;
}
});

View File

@ -189,6 +189,27 @@ button.et2_button_text:focus, input[type=button]:focus {
outline: none;
}
/**
* Drop down button
*/
.et2_dropdown button {
height: 3.0ex;
display: inline-block;
vertical-align: middle;
margin-right: -2px;
padding: 0px 1ex;
}
.et2_dropdown button > div {
vertical-align: middle;
}
.et2_dropdown button:last-child {
padding: 0px
}
.et2_dropdown + ul.ui-menu {
position: absolute;
z-index: 2;
}
/**
* Color picker widget
*/
@ -738,6 +759,19 @@ label input, label span, label div, label select, label textarea {
.nextmatch_header > .filters .et2_button_icon {
margin-top: 8px;
}
/* Favorites */
.nextmatch_header div#favorite\[button\]_wrapper {
margin-top: 5px;
vertical-align: middle;
}
#nm_favorites_popup_filters .filter_id, #nm_favorites_popup_filters .filter_value {
width: 10ex;
display: inline-block;
}
#favorite\[button\]_menu input, #favorite\[button\]_menu img {
margin-right: 2ex;
}
.nextmatch_sortheader {
color: #003075;
cursor: pointer;

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB