forked from extern/egroupware
Favorites progress - safe names, delete confirmation, automagic sidebox favorites
This commit is contained in:
parent
176307335e
commit
e63ea5a1e4
@ -795,7 +795,10 @@ class etemplate_widget_nextmatch extends etemplate_widget
|
|||||||
*/
|
*/
|
||||||
public static function ajax_set_favorite($app, $name, $action, $group, $filters = array())
|
public static function ajax_set_favorite($app, $name, $action, $group, $filters = array())
|
||||||
{
|
{
|
||||||
$pref_name = "favorite_".$name;
|
// Only use alphanumeric for preference name, so it can be used directly as DOM ID
|
||||||
|
$name = strip_tags($name);
|
||||||
|
$pref_name = "favorite_".preg_replace('/[^A-Za-z0-9-_]/','_',$name);
|
||||||
|
|
||||||
if($group && $GLOBALS['egw_info']['apps']['admin'])
|
if($group && $GLOBALS['egw_info']['apps']['admin'])
|
||||||
{
|
{
|
||||||
$prefs = new preferences(is_numeric($group) ? $group: $GLOBALS['egw_info']['user']['account_id']);
|
$prefs = new preferences(is_numeric($group) ? $group: $GLOBALS['egw_info']['user']['account_id']);
|
||||||
@ -809,7 +812,9 @@ class etemplate_widget_nextmatch extends etemplate_widget
|
|||||||
if($action == "add")
|
if($action == "add")
|
||||||
{
|
{
|
||||||
$filters = array(
|
$filters = array(
|
||||||
'group' => $group,
|
// This is the name as user entered it, minus tags
|
||||||
|
'name' => $name,
|
||||||
|
'group' => $group ? $group : false,
|
||||||
'filter' => $filters
|
'filter' => $filters
|
||||||
);
|
);
|
||||||
$result = $prefs->add($app,$pref_name,$filters,$type);
|
$result = $prefs->add($app,$pref_name,$filters,$type);
|
||||||
|
@ -1367,6 +1367,18 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
|
|||||||
* saved filters, pulled from preferences. Clicking a filter from the dropdown list sets the
|
* saved filters, pulled from preferences. Clicking a filter from the dropdown list sets the
|
||||||
* filters as saved.
|
* filters as saved.
|
||||||
*
|
*
|
||||||
|
* Favorites can also automatically be shown in the sidebox, using the special ID favorite_sidebox:
|
||||||
|
* display_sidebox($appname,lang('Favorites'),array(
|
||||||
|
* array(
|
||||||
|
* 'no_lang' => true,
|
||||||
|
* 'text'=>'<span id="favorite_sidebox"/>',
|
||||||
|
* 'link'=>false,
|
||||||
|
* 'icon' => false
|
||||||
|
* )
|
||||||
|
* ));
|
||||||
|
* This sidebox list will be automatically generated and kept up to date.
|
||||||
|
*
|
||||||
|
*
|
||||||
* Favorites are implemented by saving the values for [column] filters. Filters are stored
|
* 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
|
* in preferences, with the name favorite_<name>. The favorite favorite used for clicking on
|
||||||
* the filter button is stored in nextmatch-<columnselection_pref>-favorite.
|
* the filter button is stored in nextmatch-<columnselection_pref>-favorite.
|
||||||
@ -1375,28 +1387,34 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
|
|||||||
* additional fields/settings to add in to the favorite.
|
* additional fields/settings to add in to the favorite.
|
||||||
*/
|
*/
|
||||||
_setup_favorites: function(filters) {
|
_setup_favorites: function(filters) {
|
||||||
// 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";
|
|
||||||
|
|
||||||
var apps = this.egw().user('apps');
|
|
||||||
var is_admin = (typeof apps['admin'] != "undefined");
|
|
||||||
|
|
||||||
if(typeof filters == "undefined")
|
if(typeof filters == "undefined")
|
||||||
{
|
{
|
||||||
// No favorites configured
|
// No favorites configured
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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";
|
||||||
|
var sidebox_target = $j("#favorite_sidebox");
|
||||||
|
if(sidebox_target.length == 0 && egw_getFramework() != null)
|
||||||
|
{
|
||||||
|
var egw_fw = egw_getFramework();
|
||||||
|
sidebox_target = $j("#favorite_sidebox",egw_fw.sidemenuDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
var apps = this.egw().user('apps');
|
||||||
|
var is_admin = (typeof apps['admin'] != "undefined");
|
||||||
|
|
||||||
var list = et2_csvSplit(this.options.get_rows, 2, ".");
|
var list = et2_csvSplit(this.options.get_rows, 2, ".");
|
||||||
var app = list[0];
|
var app = list[0];
|
||||||
|
|
||||||
// Load saved favorites
|
// Load saved favorites
|
||||||
var stored_filters = {};
|
var stored_filters = {};
|
||||||
|
var preferred = this.egw().preference(favorite_preference, app);
|
||||||
var preferences = this.egw().preference("*",app);
|
var preferences = this.egw().preference("*",app);
|
||||||
for(var pref_name in preferences)
|
for(var pref_name in preferences)
|
||||||
{
|
{
|
||||||
@ -1411,6 +1429,40 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
|
|||||||
stored_filters = {};
|
stored_filters = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a favorite from the list and update preferences
|
||||||
|
* Registered as a handler on the delete icons
|
||||||
|
*/
|
||||||
|
var delete_favorite = function(event)
|
||||||
|
{
|
||||||
|
// Don't do the menu
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
|
||||||
|
var name = $j(this).parentsUntil("li").parent().attr("id");
|
||||||
|
|
||||||
|
// Make sure first
|
||||||
|
if(!confirm(header.egw().lang("Delete") + " " +stored_filters[name].name +"?")) return;
|
||||||
|
|
||||||
|
// Hide the trash
|
||||||
|
$j(this).hide();
|
||||||
|
|
||||||
|
// Delete preference server side
|
||||||
|
var request = new egw_json_request("etemplate_widget_nextmatch::ajax_set_favorite::etemplate",
|
||||||
|
[app, name, "delete", stored_filters[name].group ? stored_filters[name].group : '', ''],
|
||||||
|
header
|
||||||
|
);
|
||||||
|
request.sendRequest(true, function(result) {
|
||||||
|
if(result)
|
||||||
|
{
|
||||||
|
// Remove line from list
|
||||||
|
this.slideUp("slow", function() { header.favorites.menu.hide();});
|
||||||
|
delete stored_filters[name];
|
||||||
|
init_filters(header.favorites);
|
||||||
|
}
|
||||||
|
}, $j(this).parentsUntil("li").parent());
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
// Create & set filter options for dropdown menu
|
// Create & set filter options for dropdown menu
|
||||||
var init_filters = function(widget)
|
var init_filters = function(widget)
|
||||||
{
|
{
|
||||||
@ -1418,7 +1470,8 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
|
|||||||
for(var name in stored_filters)
|
for(var name in stored_filters)
|
||||||
{
|
{
|
||||||
options[name] = "<input type='radio' name='favorite[button][favorite]' value='"+name+"' title='" + header.egw().lang('Set as default') + "'/>"+
|
options[name] = "<input type='radio' name='favorite[button][favorite]' value='"+name+"' title='" + header.egw().lang('Set as default') + "'/>"+
|
||||||
name + (stored_filters[name].group != false ? " ♦" :"") +
|
(stored_filters[name].name != undefined ? stored_filters[name].name : name) +
|
||||||
|
(stored_filters[name].group != false ? " ♦" :"") +
|
||||||
(stored_filters[name].group != false && !is_admin ? "" :
|
(stored_filters[name].group != false && !is_admin ? "" :
|
||||||
"<div class='ui-icon ui-icon-trash' title='" + header.egw().lang('Delete') + "'/>");
|
"<div class='ui-icon ui-icon-trash' title='" + header.egw().lang('Delete') + "'/>");
|
||||||
}
|
}
|
||||||
@ -1427,6 +1480,21 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
|
|||||||
|
|
||||||
// Set radio to current value
|
// Set radio to current value
|
||||||
$j("input[value='"+ preferred +"']:radio", header.favorites.menu).attr("checked",true);
|
$j("input[value='"+ preferred +"']:radio", header.favorites.menu).attr("checked",true);
|
||||||
|
|
||||||
|
// Clone for sidebox
|
||||||
|
if(sidebox_target.length)
|
||||||
|
{
|
||||||
|
sidebox_target.empty();
|
||||||
|
var sidebox_clone = widget.menu.clone();
|
||||||
|
sidebox_clone
|
||||||
|
.appendTo(sidebox_target)
|
||||||
|
.menu()
|
||||||
|
.show()
|
||||||
|
.find("input:checked").replaceWith("<div class='ui-icon ui-icon-heart'/>");
|
||||||
|
sidebox_clone
|
||||||
|
.find("input").replaceWith("<img class='sideboxstar'/>");
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Favorite dropdown button
|
// Favorite dropdown button
|
||||||
@ -1438,12 +1506,12 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
|
|||||||
tooltip: "Favorite queries"
|
tooltip: "Favorite queries"
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
|
this.favorites.menu.addClass("favorites");
|
||||||
this.favorites.onclick= function(node) {
|
this.favorites.onclick= function(node) {
|
||||||
// Apply preferred filter - make sure it's an object, and not a reference
|
// Apply preferred filter - make sure it's an object, and not a reference
|
||||||
var favorite = header.egw().preference(favorite_preference,app);
|
if(preferred && stored_filters[preferred])
|
||||||
if(favorite && stored_filters[favorite])
|
|
||||||
{
|
{
|
||||||
nextmatch.activeFilters = jQuery.extend({},stored_filters[favorite].filter);
|
nextmatch.activeFilters = jQuery.extend({},stored_filters[preferred].filter);
|
||||||
nextmatch.applyFilters();
|
nextmatch.applyFilters();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1452,10 +1520,53 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var preferred = this.egw().preference(favorite_preference, app);
|
|
||||||
this.favorites.set_value(preferred && stored_filters[preferred] ? preferred : "");
|
this.favorites.set_value(preferred && stored_filters[preferred] ? preferred : "");
|
||||||
init_filters(this.favorites);
|
init_filters(this.favorites);
|
||||||
|
|
||||||
|
// Initialize sidebox
|
||||||
|
if(sidebox_target.length)
|
||||||
|
{
|
||||||
|
sidebox_target
|
||||||
|
.on("mouseenter","div.ui-icon-trash", function() {$j(this).wrap("<span class='ui-state-active'/>");})
|
||||||
|
.on("mouseleave","div.ui-icon-trash", function() {$j(this).unwrap();})
|
||||||
|
.on("click","div.ui-icon-trash", delete_favorite);
|
||||||
|
if(header.favorites)
|
||||||
|
{
|
||||||
|
sidebox_target.on("click","li",function() {
|
||||||
|
header.favorites.set_value($j(this).attr("id"));
|
||||||
|
header.favorites.change(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
preferred = $j(this).val();
|
||||||
|
|
||||||
|
// Update sidebox, if there
|
||||||
|
if(sidebox_target.length)
|
||||||
|
{
|
||||||
|
sidebox_target.find(".ui-icon-heart")
|
||||||
|
.replaceWith("<img class='sideboxstar'/>");
|
||||||
|
$j("li#"+preferred+" img",sidebox_target)
|
||||||
|
.replaceWith("<div class='ui-icon ui-icon-heart'/>");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Apply the favorite when you pick from the list
|
// Apply the favorite when you pick from the list
|
||||||
this.favorites.change = function(selected_node) {
|
this.favorites.change = function(selected_node) {
|
||||||
if(this.get_value() == "add")
|
if(this.get_value() == "add")
|
||||||
@ -1507,6 +1618,9 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
|
|||||||
|
|
||||||
// Popup
|
// Popup
|
||||||
header.favorites_popup.dialog("open");
|
header.favorites_popup.dialog("open");
|
||||||
|
|
||||||
|
// Reset value
|
||||||
|
this.set_value(preferred && stored_filters[preferred] ? preferred : "");
|
||||||
}
|
}
|
||||||
else if(stored_filters[this.get_value()])
|
else if(stored_filters[this.get_value()])
|
||||||
{
|
{
|
||||||
@ -1517,57 +1631,23 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// 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 a listener on the delete to remove
|
// Add a listener on the delete to remove
|
||||||
$j(this.favorites.menu).on("click","div.ui-icon-trash", function(event) {
|
$j(this.favorites.menu).on("click","div.ui-icon-trash", delete_favorite)
|
||||||
// Don't do the menu
|
|
||||||
event.stopImmediatePropagation();
|
|
||||||
|
|
||||||
// Hide the trash
|
|
||||||
$j(this).hide();
|
|
||||||
|
|
||||||
var name = $j(this).parentsUntil("li").parent().attr("id");
|
|
||||||
|
|
||||||
// Delete preference server side
|
|
||||||
var request = new egw_json_request("etemplate_widget_nextmatch::ajax_set_favorite::etemplate",
|
|
||||||
[app, name, "delete", stored_filters[name].group ? stored_filters[name].group : '', ''],
|
|
||||||
header
|
|
||||||
);
|
|
||||||
request.sendRequest(true, function(result) {
|
|
||||||
if(result)
|
|
||||||
{
|
|
||||||
// Remove line from list
|
|
||||||
this.slideUp("slow", function() {header.favorites.menu.hide();});
|
|
||||||
delete stored_filters[name];
|
|
||||||
init_filters(header.favorites);
|
|
||||||
}
|
|
||||||
}, $j(this).parentsUntil("li").parent());
|
|
||||||
|
|
||||||
})
|
|
||||||
// Wrap and unwrap because jQueryUI styles use a parent, and we don't want to change the state of the menu item
|
// Wrap and unwrap because jQueryUI styles use a parent, and we don't want to change the state of the menu item
|
||||||
// Use a span instead of a div because div gets a border
|
// Wrap in a span instead of a div because div gets a border
|
||||||
.on("mouseenter","div.ui-icon-trash", function() {$j(this).wrap("<span class='ui-state-active'/>");})
|
.on("mouseenter","div.ui-icon-trash", function() {$j(this).wrap("<span class='ui-state-active'/>");})
|
||||||
.on("mouseleave","div.ui-icon-trash", function() {$j(this).unwrap();});
|
.on("mouseleave","div.ui-icon-trash", function() {$j(this).unwrap();});
|
||||||
|
|
||||||
// Add into header
|
// Add into header
|
||||||
$j(this.favorites.getDOMNode(this.favorites)).insertAfter(this.count).css("float","right");
|
$j(this.favorites.getDOMNode(this.favorites)).insertAfter(this.count).css("float","right");
|
||||||
|
|
||||||
|
// Trigger refresh of menu options now that events are registered
|
||||||
|
// to update sidebox
|
||||||
|
if(sidebox_target.length > 0)
|
||||||
|
{
|
||||||
|
init_filters(this.favorites);
|
||||||
|
}
|
||||||
|
|
||||||
// Create popup
|
// Create popup
|
||||||
this.favorites_popup = $j('<div id="nm_favorites_popup" title="' + egw().lang("New favorite") + '">\
|
this.favorites_popup = $j('<div id="nm_favorites_popup" title="' + egw().lang("New favorite") + '">\
|
||||||
<form>\
|
<form>\
|
||||||
@ -1610,15 +1690,18 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
|
|||||||
|
|
||||||
if(name.val())
|
if(name.val())
|
||||||
{
|
{
|
||||||
|
|
||||||
// Add to the list
|
// Add to the list
|
||||||
stored_filters[name.val()] = {
|
name.val(name.val().replace(/(<([^>]+)>)/ig,""));
|
||||||
group: (typeof header.favorites_popup.group != "undefined" ? header.favorites_popup.group.get_value() != "": false),
|
var safe_name = name.val().replace(/[^A-Za-z0-9-_]/g,"_");
|
||||||
|
stored_filters[safe_name] = {
|
||||||
|
name: name.val(),
|
||||||
|
group: (typeof header.favorites_popup.group != "undefined" &&
|
||||||
|
header.favorites_popup.group.get_value() ? header.favorites_popup.group.get_value() : false),
|
||||||
filter: header.favorites_popup.current_filters
|
filter: header.favorites_popup.current_filters
|
||||||
};
|
};
|
||||||
init_filters(header.favorites);
|
init_filters(header.favorites);
|
||||||
|
|
||||||
var favorite_pref = favorite_prefix+name.val();
|
var favorite_pref = favorite_prefix+safe_name;
|
||||||
|
|
||||||
// Save to preferences
|
// Save to preferences
|
||||||
if(typeof header.favorites_popup.group != "undefined")
|
if(typeof header.favorites_popup.group != "undefined")
|
||||||
@ -1645,7 +1728,11 @@ var et2_nextmatch_header_bar = et2_DOMWidget.extend(et2_INextmatchHeader, {
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Normal user - just save to preferences client side
|
// Normal user - just save to preferences client side
|
||||||
header.egw().set_preference(app,favorite_pref,{filter:header.favorites_popup.current_filters});
|
header.egw().set_preference(app,favorite_pref,{
|
||||||
|
name: name.val(),
|
||||||
|
group: false,
|
||||||
|
filter:header.favorites_popup.current_filters
|
||||||
|
});
|
||||||
}
|
}
|
||||||
delete header.favorites_popup.current_filters;
|
delete header.favorites_popup.current_filters;
|
||||||
}
|
}
|
||||||
|
@ -768,17 +768,27 @@ label input, label span, label div, label select, label textarea {
|
|||||||
width: 45%;
|
width: 45%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
#favorite\[button\]_menu li a {
|
.favorites li a {
|
||||||
}
|
}
|
||||||
#favorite\[button\]_menu input, #favorite\[button\]_menu img {
|
.favorites input, .favorites img {
|
||||||
margin-right: 2ex;
|
margin-right: 2ex;
|
||||||
}
|
}
|
||||||
#favorite\[button\]_menu div.ui-icon {
|
.favorites div.ui-icon-trash {
|
||||||
float:right;
|
float:right;
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
#favorite\[button\]_menu li:hover div.ui-icon {
|
.favorites li:hover div.ui-icon {
|
||||||
display:block;
|
display:inline-block;
|
||||||
|
}
|
||||||
|
#favorite_sidebox ul {
|
||||||
|
width: 99%;
|
||||||
|
padding: 0px;
|
||||||
|
border: none;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
#favorite_sidebox div.ui-icon-heart{
|
||||||
|
float: left;
|
||||||
|
display:inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nextmatch_sortheader {
|
.nextmatch_sortheader {
|
||||||
|
Loading…
Reference in New Issue
Block a user