diff --git a/calendar/inc/class.calendar_ui.inc.php b/calendar/inc/class.calendar_ui.inc.php
index d1a68255f3..c863873105 100644
--- a/calendar/inc/class.calendar_ui.inc.php
+++ b/calendar/inc/class.calendar_ui.inc.php
@@ -618,20 +618,45 @@ class calendar_ui
$content['date'] = $this->date ? $this->date : egw_time();
$owners = $this->owner ? is_array($this->owner) ? array($this->owner) : explode(',',$this->owner) : array($GLOBALS['egw_info']['user']['account_id']);
-
+
$sel_options = array();
+ // Get user accounts, formatted nicely for grouping and matching
+ // the ajax call calendar_uiforms->ajax_owner()
+ $account_options = array('account_type' => 'both');
+ $accounts = accounts::link_query('',$account_options);
+ $sel_options['owner'] = array_map(
+ function($account_id, $account_name) {
+ return array(
+ 'value' => $account_id,
+ 'label' => $account_name,
+ 'app' => lang('home-accounts')
+ );
+ },
+ array_keys($accounts), $accounts
+ );
+
// Add external owners that a select account widget will not find
$linked_owners = array();
- foreach($owners as $owner)
+ foreach($owners as &$owner)
{
+ $owner = ''.$owner;
if(!is_numeric($owner))
{
$resource = $this->bo->resources[substr($owner, 0,1)];
$label = egw_link::title($resource['app'], substr($owner,1));
$linked_owners[$resource['app']][substr($owner,1)] = $label;
- $sel_options['owner'][] = array('value' => $owner, 'label' => $label);
}
+ else if (!in_array($owner, array_keys($accounts)))
+ {
+ $label = egw_link::title('home-accounts',$owner);
+ $resource = array('app'=> 'home-accounts');
+ }
+ else
+ {
+ continue;
+ }
+ $sel_options['owner'][] = array('value' => $owner, 'label' => $label, 'app' => lang($resource['app']));
}
if($linked_owners)
{
diff --git a/calendar/inc/class.calendar_uiforms.inc.php b/calendar/inc/class.calendar_uiforms.inc.php
index ba800dfd2b..dbd5838479 100644
--- a/calendar/inc/class.calendar_uiforms.inc.php
+++ b/calendar/inc/class.calendar_uiforms.inc.php
@@ -2941,6 +2941,59 @@ class calendar_uiforms extends calendar_ui
}
}
+ /**
+ * Handle ajax searches for owner across all supported resources
+ *
+ * @return Array List of matching results
+ */
+ public function ajax_owner()
+ {
+ $query = $_REQUEST['query'];
+ $options = ['num_rows' => 100];
+ $results = [];
+ if($query)
+ {
+ foreach($this->bo->resources as $type => $data)
+ {
+ $mapped = array();
+ if ($data['app'] && egw_link::get_registry($data['app'], 'query'))
+ {
+ $_results = egw_link::query($data['app'], $query,$options);
+ if(!$_results) continue;
+ $r_results = array_unique($_results);
+ foreach($_results as $id => $title)
+ {
+ if($id && $title)
+ {
+ // Magicsuggest uses id, not value.
+ $value = [
+ 'id' => $type.$id,
+ 'value'=> $type.$id,
+ 'label' => $title,
+ 'app' => lang($data['app'])
+ ];
+ if(is_array($value['label']))
+ {
+ $value = array_merge($value, $value['label']);
+ }
+ $mapped[] = $value;
+ }
+ }
+ if(count($mapped))
+ {
+ $results = array_merge($results, $mapped);
+ }
+ }
+ }
+ }
+ // switch regular JSON response handling off
+ egw_json_request::isJSONRequest(false);
+
+ header('Content-Type: application/json; charset=utf-8');
+ echo json_encode($results);
+ common::egw_exit();
+ }
+
/**
* imports a mail as Calendar
*
diff --git a/calendar/js/app.js b/calendar/js/app.js
index 8476053d2d..0ae8250e23 100644
--- a/calendar/js/app.js
+++ b/calendar/js/app.js
@@ -12,6 +12,7 @@
/*egw:uses
/etemplate/js/etemplate2.js;
+ /calendar/js/et2_widget_owner.js;
/calendar/js/et2_widget_timegrid.js;
/calendar/js/et2_widget_planner.js;
*/
@@ -1972,13 +1973,6 @@ app.classes.calendar = AppJS.extend(
{
state.state.owner[state.state.owner.indexOf('0')] = this.egw.user('account_id');
}
- if(state.state.owner.length === 1 && this.sidebox_et2)
- {
- // If only one owner selected, go back to single select
- var owner = this.sidebox_et2.getWidgetById('owner');
- owner.set_multiple(false);
- }
-
// Show the correct number of grids
var grid_count = 0;
@@ -2747,6 +2741,10 @@ app.classes.calendar = AppJS.extend(
}
if(!found)
{
+ if(!widget.options.select_options.push)
+ {
+ widget.options.select_options = [];
+ }
widget.options.select_options.push(option);
}
}
@@ -2884,7 +2882,7 @@ app.classes.calendar = AppJS.extend(
for(var day in updated_days)
{
// Might be split by user, so we have to check that too
- for(var i = 0; i < state.owner.length; i++)
+ for(var i = 0; i < typeof state.owner == 'object' ? state.owner.length : 1; i++)
{
var owner = multiple_owner ? state.owner[i] : state.owner;
var cache_id = app.classes.calendar._daywise_cache_id(day, owner);
@@ -3247,6 +3245,14 @@ app.classes.calendar = AppJS.extend(
button.parent().css('margin-right',button.outerWidth(true)+2);
button.parent().parent().css('white-space','nowrap');
}
+ $j(window).on('resize.calendar-owner', function() {
+ var preferred_width = $j('#calendar-et2_target').children().first().outerWidth()||0;
+ var owner = app.calendar.sidebox_et2.getWidgetById('owner');
+ if(preferred_width && owner.input.hasClass("chzn-done"))
+ {
+ owner.input.next().css('width',preferred_width);
+ }
+ });
},
/**
diff --git a/calendar/js/et2_widget_owner.js b/calendar/js/et2_widget_owner.js
new file mode 100644
index 0000000000..5f6a9d4ee2
--- /dev/null
+++ b/calendar/js/et2_widget_owner.js
@@ -0,0 +1,59 @@
+/*
+ * Egroupware
+ * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
+ * @package
+ * @subpackage
+ * @link http://www.egroupware.org
+ * @author Nathan Gray
+ * @version $Id$
+ */
+
+
+"use strict";
+
+/*egw:uses
+ et2_widget_taglist;
+*/
+
+/**
+ * Tag list widget customised for calendar owner, which can be a user
+ * account or group, or an entry from almost any app, or an email address
+ *
+ * A cross between auto complete, selectbox and chosen multiselect
+ *
+ * Uses MagicSuggest library
+ * @see http://nicolasbize.github.io/magicsuggest/
+ * @augments et2_selectbox
+ */
+var et2_calendar_owner = et2_taglist_email.extend(
+{
+ attributes: {
+ "autocomplete_url": {
+ "default": "calendar.calendar_uiforms.ajax_owner.etemplate"
+ },
+ "autocomplete_params": {
+ "name": "Autocomplete parameters",
+ "type": "any",
+ "default": {},
+ "description": "Extra parameters passed to autocomplete URL. It should be a stringified JSON object."
+ },
+ allowFreeEntries: {
+ "default": false,
+ ignore: true
+ },
+ select_options: {
+ "type": "any",
+ "name": "Select options",
+ // Set to empty object to use selectbox's option finding
+ "default": {},
+ "description": "Internaly used to hold the select options."
+ },
+ },
+
+ // Allows sub-widgets to override options to the library
+ lib_options: {
+ groupBy: 'app',
+ expandOnFocus: true
+ }
+});
+et2_register_widget(et2_calendar_owner, ["calendar_owner"]);
\ No newline at end of file
diff --git a/calendar/templates/default/sidebox.xet b/calendar/templates/default/sidebox.xet
index b9e6b4d50b..98aee8933d 100644
--- a/calendar/templates/default/sidebox.xet
+++ b/calendar/templates/default/sidebox.xet
@@ -27,7 +27,7 @@ if(view_change >= 0) {update.view = app.calendar.sidebox_changes_views[view_chan
-
+