forked from extern/egroupware
Some WIP on getting home working again
This commit is contained in:
parent
8fab640449
commit
cbbb0bf39f
@ -43,12 +43,21 @@ var et2_portlet = et2_valueWidget.extend(
|
||||
"type": "string",
|
||||
"default": window.egw_webserverUrl+"/home/templates/default/edit.xet"
|
||||
},
|
||||
"color": {
|
||||
"name": "Color",
|
||||
"description": "Set the portlet color",
|
||||
"type": "string",
|
||||
"default": ''
|
||||
},
|
||||
"settings": {
|
||||
"name": "Customization settings",
|
||||
"description": "Array of customization settings, similar in structure to preference settings",
|
||||
"type": "any",
|
||||
"default": et2_no_init
|
||||
},
|
||||
"actions": {
|
||||
default: {}
|
||||
},
|
||||
"width": { "default": 2, "ignore": true},
|
||||
"height": { "default": 1, "type": "integer"},
|
||||
"rows": {"ignore": true},
|
||||
@ -66,7 +75,7 @@ var et2_portlet = et2_valueWidget.extend(
|
||||
},
|
||||
|
||||
createNamespace: true,
|
||||
GRID: 50,
|
||||
GRID: 100,
|
||||
|
||||
/**
|
||||
* These are the "normal" actions that every portlet is expected to have.
|
||||
@ -126,10 +135,12 @@ var et2_portlet = et2_valueWidget.extend(
|
||||
}
|
||||
});
|
||||
this.header = $j(document.createElement("div"))
|
||||
.attr('id', this.getInstanceManager().uniqueId+'_'+this.id.replace(/\./g, '-') + '_header')
|
||||
.addClass("ui-widget-header ui-corner-all")
|
||||
.appendTo(this.div)
|
||||
.html(this.options.title);
|
||||
this.content = $j(document.createElement("div"))
|
||||
.attr('id', this.getInstanceManager().uniqueId+'_'+this.id.replace(/\./g, '-') + '_content')
|
||||
.appendTo(this.div);
|
||||
|
||||
this.setDOMNode(this.div[0]);
|
||||
@ -137,6 +148,15 @@ var et2_portlet = et2_valueWidget.extend(
|
||||
|
||||
destroy: function()
|
||||
{
|
||||
for(var i = 0; i < this._children.length; i++)
|
||||
{
|
||||
// Check for child is a different template and clear it,
|
||||
// since it won't be cleared by destroy()
|
||||
if(this._children[i]._inst != this._inst)
|
||||
{
|
||||
this._children[i]._inst.clear();
|
||||
}
|
||||
}
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
@ -233,7 +253,7 @@ var et2_portlet = et2_valueWidget.extend(
|
||||
buttons: et2_dialog.BUTTONS_OK_CANCEL
|
||||
},this);
|
||||
// Set seperately to avoid translation
|
||||
dialog.set_title(this.egw().lang("Edit") + " " + this.options.title);
|
||||
dialog.set_title(this.egw().lang("Edit") + " " + (this.options.title || ''));
|
||||
},
|
||||
|
||||
_process_edit: function(button_id, value)
|
||||
@ -241,10 +261,14 @@ var et2_portlet = et2_valueWidget.extend(
|
||||
if(button_id != et2_dialog.OK_BUTTON) return;
|
||||
|
||||
|
||||
// Save settings - server will reply with new content, if the portlet needs an update
|
||||
// Save settings - server might reply with new content if the portlet needs an update,
|
||||
// but ideally it doesn't
|
||||
this.div.addClass("loading");
|
||||
this.egw().jsonq("home.home_ui.ajax_set_properties",[this.id, this.options.settings || {}, value],
|
||||
function(data) {
|
||||
// This section not for us
|
||||
if(!data || typeof data.attributes == 'undefined') return false;
|
||||
|
||||
this.div.removeClass("loading");
|
||||
this.set_value(data.content);
|
||||
for(var key in data.attributes)
|
||||
@ -337,10 +361,6 @@ var et2_portlet = et2_valueWidget.extend(
|
||||
{
|
||||
this.options.height = value;
|
||||
this.div.attr("data-sizey", value);
|
||||
|
||||
// Explicitly set the height of the content, so it can properly scroll. Sometimes set_height()
|
||||
// is called before everything is in the DOM though, so use a magic 18px in that case.
|
||||
this.content.height(value * this.GRID - (this.header.outerHeight() > 0 ? this.header.outerHeight() : 18));
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -1154,9 +1154,6 @@ div.message.floating {
|
||||
/**
|
||||
* et2_portlet
|
||||
*/
|
||||
div.et2_portlet {
|
||||
min-width: 100px;
|
||||
}
|
||||
.et2_portlet .ui-widget-header {
|
||||
margin: 0em;
|
||||
padding-bottom: 4px;
|
||||
|
@ -29,7 +29,7 @@ class home_legacy_portlet extends home_portlet
|
||||
*/
|
||||
protected $content = '';
|
||||
|
||||
public function __construct(array &$context = array())
|
||||
public function __construct(array &$context = array(), &$need_reload = false)
|
||||
{
|
||||
$this->context = $context;
|
||||
|
||||
@ -90,9 +90,13 @@ class home_legacy_portlet extends home_portlet
|
||||
* unique, if needed.
|
||||
* @return string HTML fragment for display
|
||||
*/
|
||||
public function get_content($id = null)
|
||||
public function exec($id = null, etemplate_new &$etemplate = null)
|
||||
{
|
||||
return $this->content;
|
||||
$etemplate->read('home.legacy');
|
||||
|
||||
$etemplate->set_dom_id($id);
|
||||
|
||||
$etemplate->exec('home.home_link_portlet.exec',array('legacy' => $this->content), array(),array(),array(),2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,19 +24,27 @@ class home_link_portlet extends home_portlet
|
||||
*/
|
||||
protected $title = 'Link';
|
||||
|
||||
/**
|
||||
* Base name for template
|
||||
* @var string
|
||||
*/
|
||||
protected $template_name = 'home.link';
|
||||
|
||||
/**
|
||||
* Construct the portlet
|
||||
*
|
||||
* @param boolean $need_reload Flag to indicate that the portlet needs to be reloaded (exec will be called)
|
||||
*/
|
||||
public function __construct(Array &$context = array())
|
||||
public function __construct(Array &$context = array(), &$need_reload = false)
|
||||
{
|
||||
// Process dropped data into something useable
|
||||
if($context['dropped_data'])
|
||||
{
|
||||
list($context['entry']['app'], $context['entry']['id']) = explode('::', $context['dropped_data'][0], 2);
|
||||
unset($context['dropped_data']);
|
||||
$need_reload = true;
|
||||
}
|
||||
if($context['entry'])
|
||||
if($context['entry'] && is_array($context['entry']));
|
||||
{
|
||||
$this->title = $context['entry']['title'] = egw_link::title($context['entry']['app'], $context['entry']['id']);
|
||||
}
|
||||
@ -64,15 +72,33 @@ class home_link_portlet extends home_portlet
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a fragment of HTML for display
|
||||
* Generate display
|
||||
*
|
||||
* @param id String unique ID, provided to the portlet so it can make sure content is
|
||||
* unique, if needed.
|
||||
* @return string HTML fragment for display
|
||||
*/
|
||||
public function get_content($id = null)
|
||||
public function exec($id = null, etemplate_new &$etemplate = null)
|
||||
{
|
||||
return $this->title;
|
||||
// Check for custom template for app
|
||||
if($this->context && $this->context['entry'] && $this->context['entry']['app'] &&
|
||||
$etemplate->read($this->context['entry']['app'] . '.' . $this->template_name))
|
||||
{
|
||||
// No action needed, custom template loaded as side-effect
|
||||
}
|
||||
else
|
||||
{
|
||||
$etemplate->read($this->template_name);
|
||||
}
|
||||
|
||||
$etemplate->set_dom_id($id);
|
||||
|
||||
$content = $this->context;
|
||||
if(!is_array($content['entry']))
|
||||
{
|
||||
$content['entry'] = null;
|
||||
}
|
||||
|
||||
$etemplate->exec('home.home_link_portlet.exec',$content);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,13 +119,15 @@ class home_link_portlet extends home_portlet
|
||||
*/
|
||||
public function get_properties()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
$properties = parent::get_properties();
|
||||
|
||||
$properties[] = array(
|
||||
'name' => 'entry',
|
||||
'type' => 'link-entry',
|
||||
'label' => lang('Entry'),
|
||||
)
|
||||
) + parent::get_properties();
|
||||
'size' => ''
|
||||
);
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,7 +36,7 @@ class home_list_portlet extends home_portlet
|
||||
* Construct the portlet
|
||||
*
|
||||
*/
|
||||
public function __construct(Array &$context = array())
|
||||
public function __construct(Array &$context = array(), &$need_reload = false)
|
||||
{
|
||||
if(!is_array($context['list'])) $context['list'] = array();
|
||||
|
||||
@ -54,6 +54,7 @@ class home_list_portlet extends home_portlet
|
||||
}
|
||||
unset($add);
|
||||
unset($context['dropped_data']);
|
||||
$need_reload = true;
|
||||
}
|
||||
if($context['title'])
|
||||
{
|
||||
@ -89,37 +90,18 @@ class home_list_portlet extends home_portlet
|
||||
* unique, if needed.
|
||||
* @return string HTML fragment for display
|
||||
*/
|
||||
public function get_content($id = null)
|
||||
public function exec($id = null, etemplate_new &$etemplate = null)
|
||||
{
|
||||
$list = array();
|
||||
foreach($this->context['list'] as $link_id => $link)
|
||||
$etemplate->read('home.list');
|
||||
|
||||
$etemplate->set_dom_id($id);
|
||||
$content = $this->context;
|
||||
if(!is_array($content['list']))
|
||||
{
|
||||
$list[] = $link + array(
|
||||
'title' => egw_link::title($link['app'], $link['id']),
|
||||
'icon' => egw_link::get_registry($link['app'], 'icon')
|
||||
);
|
||||
$content['list'] = Array();
|
||||
}
|
||||
|
||||
// Find the portlet widget, and add a link-list to it
|
||||
$script = 'app.home.List.set_content("'.$id.'", '.json_encode($list).');';
|
||||
if(egw_json_response::isJSONResponse())
|
||||
{
|
||||
$response = egw_json_response::get();
|
||||
// This has to go last, after the template is loaded
|
||||
$response->addBeforeSendDataCallback(
|
||||
function($response, $script) {
|
||||
// Bind to load event to make sure template is loaded first
|
||||
$response->script('$j("#home-index").on("load", function() {'.$script.'});');
|
||||
}
|
||||
,$response, $script
|
||||
);
|
||||
} else {
|
||||
// Not a JSON Response? Probably an idots first load
|
||||
$response = egw_json_response::get();
|
||||
// Bind to load event to make sure template is loaded first
|
||||
$response->script('$j("#home-index").on("load", function() {'.$script.'});');
|
||||
}
|
||||
return '';
|
||||
$etemplate->exec('home.home_list_portlet.exec',$content);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,17 +122,18 @@ class home_list_portlet extends home_portlet
|
||||
*/
|
||||
public function get_properties()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
'name' => 'title',
|
||||
'type' => 'textbox',
|
||||
'label' => lang('Title'),
|
||||
),
|
||||
// Internal
|
||||
array(
|
||||
'name' => 'list'
|
||||
)
|
||||
) + parent::get_properties();
|
||||
$properties = parent::get_properties();
|
||||
|
||||
$properties[] = array(
|
||||
'name' => 'title',
|
||||
'type' => 'textbox',
|
||||
'label' => lang('Title'),
|
||||
);
|
||||
// Internal - no type means it won't show in configure dialog
|
||||
$properties[] = array(
|
||||
'name' => 'list'
|
||||
);
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,7 +156,7 @@ class home_list_portlet extends home_portlet
|
||||
'type' => 'drop',
|
||||
'caption' => lang('add'),
|
||||
'onExecute' => 'javaScript:app.home.add_link',
|
||||
'acceptedTypes' => array('file') + array_keys($GLOBALS['egw_info']['apps']),
|
||||
'acceptedTypes' => array('file','link') + array_keys($GLOBALS['egw_info']['apps']),
|
||||
)
|
||||
);
|
||||
return $actions;
|
||||
|
@ -30,8 +30,9 @@ abstract class home_portlet
|
||||
* better to use get_properties().
|
||||
*
|
||||
* @param context Array portlet settings such as size, as well as values for properties
|
||||
* @param boolean $need_reload Flag to indicate that the portlet needs to be reloaded (exec will be called)
|
||||
*/
|
||||
public abstract function __construct(Array &$context = array());
|
||||
public abstract function __construct(Array &$context = array(), &$need_reload = false);
|
||||
|
||||
/**
|
||||
* Some descriptive information about the portlet, so that users can decide if
|
||||
@ -47,13 +48,14 @@ abstract class home_portlet
|
||||
public abstract function get_description();
|
||||
|
||||
/**
|
||||
* Get a fragment of HTML for display
|
||||
* Generate the display for the portlet
|
||||
*
|
||||
* @param id String unique ID, provided to the portlet so it can make sure content is
|
||||
* unique, if needed.
|
||||
* @return string HTML fragment for display
|
||||
* @param etemplate etemplate_new Etemplate to generate content
|
||||
* @param dom_id String ID of the etemplate targe DOM node. If passed, send -1 to etemplate->exec()
|
||||
*/
|
||||
public abstract function get_content($id = null);
|
||||
public abstract function exec($id = null, etemplate_new &$etemplate = null);
|
||||
|
||||
/**
|
||||
* Return a list of settings to customize the portlet.
|
||||
@ -79,6 +81,12 @@ abstract class home_portlet
|
||||
{
|
||||
$properties[$prop] = array('name' => $prop);
|
||||
}
|
||||
|
||||
$properties[] = array(
|
||||
'name' => 'color',
|
||||
'type' => 'colorpicker',
|
||||
'label' => lang('Color'),
|
||||
);
|
||||
return $properties;
|
||||
}
|
||||
|
||||
|
@ -34,22 +34,31 @@ class home_ui
|
||||
*/
|
||||
public function index($content = array())
|
||||
{
|
||||
// Disabled, for now
|
||||
return;
|
||||
// CSS for Gridster grid layout
|
||||
egw_framework::includeCSS('/phpgwapi/js/jquery/gridster/jquery.gridster.css');
|
||||
|
||||
$template = new etemplate_new('home.index');
|
||||
|
||||
// Get a list of portlets
|
||||
$content = array(
|
||||
'portlets' => $this->get_user_portlets($template)
|
||||
);
|
||||
$template->setElementAttribute('portlets','actions',$this->get_actions());
|
||||
$template->setElementAttribute('home.index','actions',$this->get_actions());
|
||||
//$template->setElementAttribute('portlets[1]','settings',$settings[1]);
|
||||
|
||||
$GLOBALS['egw_info']['flags']['app_header'] = lang('home');
|
||||
$GLOBALS['egw_info']['flags']['currentapp'] = 'home';
|
||||
|
||||
$template->exec('home.home_ui.index', $content);
|
||||
|
||||
// Now run the portlets themselves
|
||||
foreach($content['portlets'] as $portlet => $p_data)
|
||||
{
|
||||
$id = $p_data['id'];
|
||||
|
||||
if(!$id) continue;
|
||||
$portlet = $this->get_portlet($id, $p_data, $content, $attrs, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,8 +74,8 @@ class home_ui
|
||||
foreach($add_portlets as $id => &$add)
|
||||
{
|
||||
$add['id'] = 'add_' . $id;
|
||||
$add['class'] = $id;
|
||||
}
|
||||
error_log(array2string($add_portlets));
|
||||
$actions = array(
|
||||
'add' => array(
|
||||
'type' => 'popup',
|
||||
@ -78,13 +87,14 @@ class home_ui
|
||||
|
||||
// Add all known portlets as drop actions too. If there are multiple matches, there will be a menu
|
||||
$drop_execute = 'javaScript:app.home.add_from_drop';
|
||||
foreach($portlets as $app => $children)
|
||||
foreach($portlets as $app => &$children)
|
||||
{
|
||||
// Home portlets - uses link system, so all apps that support that are accepted
|
||||
if(!$children['children'])
|
||||
{
|
||||
$children['class'] = $app;
|
||||
$children['onExecute'] = $drop_execute;
|
||||
$children['acceptedTypes'] = array_keys(egw_link::app_list());
|
||||
$children['acceptedTypes'] = array('file','link');
|
||||
$children['type'] = 'drop';
|
||||
$actions["drop_$app"] = $children;
|
||||
}
|
||||
@ -111,33 +121,45 @@ class home_ui
|
||||
*/
|
||||
protected function get_user_portlets(etemplate_new &$template)
|
||||
{
|
||||
$portlets = array(
|
||||
'Just a hard-coded test',
|
||||
);
|
||||
$attributes = array();
|
||||
$attributes[] = array(
|
||||
'title' => 'Has content',
|
||||
);
|
||||
$portlets = array();
|
||||
|
||||
foreach((array)$GLOBALS['egw_info']['user']['preferences']['home']['portlets'] as $id => $context)
|
||||
{
|
||||
error_log("Portlet: $id");
|
||||
error_log(array2string($context));
|
||||
if(!$id || in_array($id, array_keys($GLOBALS['egw_info']['user']['apps']))) continue;
|
||||
$content = '';
|
||||
$attrs = array();
|
||||
$this->get_portlet($id, $context, $content, $attrs);
|
||||
$portlets[$id] = $content;
|
||||
$attributes[$id] = $attrs;
|
||||
|
||||
$classname = $context['class'];
|
||||
$portlet = new $classname($context);
|
||||
$desc = $portlet->get_description();
|
||||
$portlet_content = array(
|
||||
'id' => $id
|
||||
) + $desc + $context;
|
||||
|
||||
|
||||
// Get settings
|
||||
// Exclude common attributes changed through UI and settings lacking a type
|
||||
$settings = $portlet->get_properties();
|
||||
foreach($settings as $key => $setting)
|
||||
{
|
||||
if(is_array($setting) && !array_key_exists('type',$setting)) unset($settings[$key]);
|
||||
}
|
||||
$settings += $context;
|
||||
foreach(home_portlet::$common_attributes as $attr)
|
||||
{
|
||||
unset($settings[$attr]);
|
||||
}
|
||||
$portlet_content['settings'] = $settings;
|
||||
|
||||
// Set actions
|
||||
// Must be after settings so actions can take settings into account
|
||||
$template->setElementAttribute("portlets[" . count($portlets) . "[$id]", 'actions', $portlet->get_actions());
|
||||
|
||||
$portlets[] = $portlet_content;
|
||||
}
|
||||
|
||||
// Add in legacy HTML home bits
|
||||
$this->get_legacy_portlets($template, $portlets, $attributes);
|
||||
|
||||
foreach($portlets as $index => $portlet)
|
||||
{
|
||||
$template->setElementAttribute('portlets', $index, (array)$attributes[$index]);
|
||||
}
|
||||
// TODO: DOM IDs still collide
|
||||
//$this->get_legacy_portlets($portlets, $attributes);
|
||||
|
||||
return $portlets;
|
||||
}
|
||||
|
||||
@ -148,18 +170,30 @@ class home_ui
|
||||
* These are specific values for the portlet's properties.
|
||||
* @param content String HTML fragment to be displayed - will be set by the portlet
|
||||
* @param attributes Array Settings that can be customized on a per-portlet basis - will be set
|
||||
* @param full_exec Boolean If set, the portlet etemplates should use mode 2, if not use mode -1
|
||||
* @return home_portlet The portlet object that created the content
|
||||
*/
|
||||
protected function get_portlet($id, &$context, &$content, &$attributes)
|
||||
protected function get_portlet($id, &$context, &$content, &$attributes, $full_exec = false)
|
||||
{
|
||||
if(!$context['class']) $context['class'] = 'home_link_portlet';
|
||||
|
||||
// This should be set already, but just in case the execution path
|
||||
// is different from normal...
|
||||
if(egw_json_response::isJSONResponse())
|
||||
{
|
||||
$GLOBALS['egw']->framework->response = egw_json_response::get();
|
||||
}
|
||||
|
||||
$classname = $context['class'];
|
||||
$portlet = new $classname($context);
|
||||
$portlet = new $classname($context, $full_exec);
|
||||
|
||||
$desc = $portlet->get_description();
|
||||
$content = $portlet->get_content($id);
|
||||
|
||||
// Pre-set up etemplate so it only needs done once
|
||||
$dom_id = 'home-index_'.$id.'_content';
|
||||
|
||||
$etemplate = new etemplate_new();
|
||||
|
||||
// Exclude common attributes changed through UI and settings lacking a type
|
||||
$settings = $portlet->get_properties();
|
||||
foreach($settings as $key => $setting)
|
||||
@ -174,6 +208,7 @@ class home_ui
|
||||
|
||||
$attributes = array(
|
||||
'title' => $desc['title'],
|
||||
'color' => $settings['color'],
|
||||
'settings' => $settings,
|
||||
'actions' => $portlet->get_actions(),
|
||||
);
|
||||
@ -186,6 +221,15 @@ class home_ui
|
||||
$attributes[$name] = $context[$name];
|
||||
}
|
||||
}
|
||||
foreach($attributes as $attr => $value)
|
||||
{
|
||||
$etemplate->setElementAttribute($id, $attr, $value);
|
||||
}
|
||||
if($full_exec)
|
||||
{
|
||||
$content = $portlet->exec($id, $etemplate, $full_exec ? 2 : -1);
|
||||
}
|
||||
|
||||
return $portlet;
|
||||
}
|
||||
|
||||
@ -195,7 +239,7 @@ class home_ui
|
||||
* wants some content, we make a portlet for that app using the home_legacy_portlet,
|
||||
* which fetches content from the home hook.
|
||||
*/
|
||||
protected function get_legacy_portlets(&$etemplate, &$content, &$attributes)
|
||||
protected function get_legacy_portlets(&$content, &$attributes)
|
||||
{
|
||||
$sorted_apps = array_keys($GLOBALS['egw_info']['user']['apps']);
|
||||
$portal_oldvarnames = array('mainscreen_showevents', 'homeShowEvents','homeShowLatest','mainscreen_showmail','mainscreen_showbirthdays','mainscreen_show_new_updated', 'homepage_display');
|
||||
@ -253,7 +297,7 @@ class home_ui
|
||||
|
||||
foreach($files as $entry)
|
||||
{
|
||||
if (!in_array($entry, array('.','..')) && substr($entry,-8) == '.inc.php' && strpos($entry,'portlet'))
|
||||
if (!in_array($entry, array('.','..','class.home_legacy_portlet.inc.php')) && substr($entry,-8) == '.inc.php' && strpos($entry,'portlet'))
|
||||
{
|
||||
list(,$classname) = explode('.', $entry);
|
||||
if(class_exists($classname) &&
|
||||
@ -323,9 +367,8 @@ class home_ui
|
||||
else
|
||||
{
|
||||
// Get portlet settings, and merge new with old
|
||||
$content = '';
|
||||
$context = $values+(array)$portlets[$portlet_id]; //array('class'=>$attributes['class']);
|
||||
|
||||
|
||||
// Handle add IDs
|
||||
$classname =& $context['class'];
|
||||
if(strpos($classname,'add_') == 0 && !class_exists($classname))
|
||||
@ -333,8 +376,8 @@ class home_ui
|
||||
$add = true;
|
||||
$classname = substr($classname, 4);
|
||||
}
|
||||
|
||||
$portlet = $this->get_portlet($portlet_id, $context,$content, $attributes);
|
||||
$full_exec = false;
|
||||
$portlet = $this->get_portlet($portlet_id, $context, $content, $attributes);
|
||||
|
||||
$context['class'] = get_class($portlet);
|
||||
foreach($portlet->get_properties() as $property)
|
||||
@ -349,17 +392,17 @@ class home_ui
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update client side
|
||||
$update = array('content' => $content, 'attributes' => $attributes);
|
||||
$update = array('attributes' => $attributes);
|
||||
|
||||
// New portlet? Flag going straight to edit mode
|
||||
if($add)
|
||||
{
|
||||
$update['edit_settings'] = true;
|
||||
}
|
||||
// Send this back to the portlet widget
|
||||
$response->data($update);
|
||||
|
||||
|
||||
// Store for preference update
|
||||
$portlets[$portlet_id] = $context;
|
||||
}
|
||||
|
233
home/js/app.js
233
home/js/app.js
@ -37,7 +37,7 @@ app.classes.home = AppJS.extend(
|
||||
/**
|
||||
* Grid resolution. Must match et2_portlet GRID
|
||||
*/
|
||||
GRID: 50,
|
||||
GRID: 100,
|
||||
|
||||
/**
|
||||
* Default size for new portlets
|
||||
@ -69,6 +69,13 @@ app.classes.home = AppJS.extend(
|
||||
|
||||
// call parent
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
// Make sure all other sub-etemplates in portlets are done
|
||||
var others = etemplate2.getByApplication(this.appname);
|
||||
for(var i = 0; i < others.length; i++)
|
||||
{
|
||||
others[i].clear();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -76,31 +83,71 @@ app.classes.home = AppJS.extend(
|
||||
* and ready. If you must store a reference to the et2 object,
|
||||
* make sure to clean it up in destroy().
|
||||
*
|
||||
* @param et2 etemplate2 Newly ready object
|
||||
* @param {etemplate2} et2 Newly ready object
|
||||
* @param {string} Template name
|
||||
*/
|
||||
et2_ready: function(et2)
|
||||
et2_ready: function(et2, name)
|
||||
{
|
||||
// call parent
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
this.portlet_container = this.et2.getWidgetById("portlets");
|
||||
|
||||
// Don't do twice
|
||||
if(this.portlet_container._children.length > 0) return;
|
||||
|
||||
// Add portlets
|
||||
var content = this.et2.getArrayMgr("content").getEntry("portlets");
|
||||
var modifications = this.et2.getArrayMgr("modifications").getEntry("portlets");
|
||||
for(var key in content)
|
||||
// Top level
|
||||
if(name == 'home.index')
|
||||
{
|
||||
//var attrs = jQuery.extend({id: key}, content[key], modifications[key]);
|
||||
var attrs = {id: key};
|
||||
var portlet = et2_createWidget('portlet',attrs, this.portlet_container);
|
||||
}
|
||||
this.et2.loadingFinished();
|
||||
// call parent
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
// Set up sorting of portlets
|
||||
this._do_ordering();
|
||||
this.et2.set_id('home.index');
|
||||
this.et2.set_actions(this.et2.getArrayMgr('modifications').getEntry('home.index')['actions']);
|
||||
|
||||
this.portlet_container = this.et2.getWidgetById("portlets");
|
||||
|
||||
// Set up sorting of portlets
|
||||
this._do_ordering();
|
||||
}
|
||||
else if (et2.uniqueId)
|
||||
{
|
||||
// Handle bad timing - a sub-template was finished first
|
||||
if(!this.portlet_container)
|
||||
{
|
||||
window.setTimeout(jQuery.proxy(this, function() {this.et2_ready(et2, name);}),200);
|
||||
return;
|
||||
}
|
||||
|
||||
var portlet = this.portlet_container.getWidgetById(et2.uniqueId);
|
||||
// Check for existing etemplate, this one loaded over it
|
||||
// NOTE: Moving them around like this can cause problems with event handlers
|
||||
var existing = etemplate2.getById(et2.uniqueId);
|
||||
if(portlet && existing && existing.etemplate_exec_id != et2.etemplate_exec_id)
|
||||
{
|
||||
for(var i = 0; i < portlet._children.length; i++)
|
||||
{
|
||||
portlet._children[i]._inst.clear();
|
||||
}
|
||||
portlet._children = [];
|
||||
}
|
||||
// It's in the right place for original load, but move it into portlet
|
||||
var misplaced = $j(etemplate2.getById('home-index').DOMContainer).siblings('#'+et2.DOMContainer.id);
|
||||
if(portlet)
|
||||
{
|
||||
portlet.addChild(et2.widgetContainer);
|
||||
}
|
||||
if(portlet && misplaced.length)
|
||||
{
|
||||
// etemplate->exec() always adds a new div, so if there's an extra one, move it
|
||||
$j(et2.DOMContainer).remove();
|
||||
et2.DOMContainer = portlet.getDOMNode(et2);
|
||||
et2.DOMContainer.id = et2.uniqueId;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set top level actions
|
||||
*
|
||||
* @param {type} action
|
||||
* @param {type} source
|
||||
* @returns {undefined}
|
||||
*/
|
||||
set_actions: function() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
@ -112,6 +159,8 @@ app.classes.home = AppJS.extend(
|
||||
var attrs = {id: this._create_id(), row: max_row + 1, col: 1};
|
||||
|
||||
var portlet = et2_createWidget('portlet',attrs, this.portlet_container);
|
||||
// Override content ID so etemplate loads
|
||||
portlet.content.attr('id', attrs.id);
|
||||
portlet.loadingFinished();
|
||||
|
||||
// Get actual attributes & settings, since they're not available client side yet
|
||||
@ -150,6 +199,8 @@ app.classes.home = AppJS.extend(
|
||||
}
|
||||
|
||||
var portlet = et2_createWidget('portlet',attrs, this.portlet_container);
|
||||
// Override content ID so etemplate loads
|
||||
portlet.content.attr('id', attrs.id);
|
||||
portlet.loadingFinished();
|
||||
|
||||
// Get actual attributes & settings, since they're not available client side yet
|
||||
@ -158,7 +209,7 @@ app.classes.home = AppJS.extend(
|
||||
{
|
||||
if(source[i].id) drop_data.push(source[i].id);
|
||||
}
|
||||
portlet._process_edit(et2_dialog.OK_BUTTON, {dropped_data: drop_data, class: action.id.substr(5)});
|
||||
portlet._process_edit(et2_dialog.OK_BUTTON, {dropped_data: drop_data, class: action.data.class || action.id.substr(5)});
|
||||
|
||||
// Set up sorting/grid of new portlet
|
||||
$portlet_container.data("gridster").add_widget(
|
||||
@ -227,11 +278,11 @@ app.classes.home = AppJS.extend(
|
||||
*/
|
||||
serialize_params: function($w, grid) {
|
||||
return {
|
||||
id: $w.attr("id"),
|
||||
id: $w.children('.ui-widget-header').next().attr('id'),
|
||||
row: grid.row,
|
||||
col: grid.col,
|
||||
width: grid.width,
|
||||
height: grid.height
|
||||
width: grid.size_x,
|
||||
height: grid.size_y
|
||||
};
|
||||
},
|
||||
/**
|
||||
@ -242,15 +293,18 @@ app.classes.home = AppJS.extend(
|
||||
stop: function(event,ui) {
|
||||
// Update widget(s)
|
||||
var changed = this.serialize_changed();
|
||||
|
||||
// Reset changed, or they keep accumulating
|
||||
this.$changed = $j([]);
|
||||
|
||||
for (var key in changed)
|
||||
{
|
||||
if(!changed[key].id) continue;
|
||||
// Changed ID is DOM id
|
||||
var widget_id = changed[key].id.substr(window.app.home.et2.getInstanceManager().uniqueId.length + 1);
|
||||
var widget = window.app.home.portlet_container.getWidgetById(widget_id);
|
||||
// Changed ID is the ID
|
||||
var widget = window.app.home.portlet_container.getWidgetById(changed[key].id);
|
||||
if(!widget || widget == window.app.home.portlet_container) continue;
|
||||
|
||||
egw().jsonq("home.home_ui.ajax_set_properties",[widget.id, widget.options.settings,{
|
||||
egw().jsonq("home.home_ui.ajax_set_properties",[changed[key].id, widget.options.settings,{
|
||||
row: changed[key].row,
|
||||
col: changed[key].col
|
||||
}],
|
||||
@ -263,6 +317,11 @@ app.classes.home = AppJS.extend(
|
||||
|
||||
});
|
||||
|
||||
// Bind window resize to re-layout gridster
|
||||
$j(window).one("resize."+this.et2._inst.uniqueId, function() {
|
||||
// Note this doesn't change the positions, just makes them invalid
|
||||
$portlet_container.data('gridster').recalculate_faux_grid();
|
||||
});
|
||||
// Bind resize to update gridster - this may happen _before_ the widget gets a
|
||||
// chance to update itself, so we can't use the widget
|
||||
$portlet_container
|
||||
@ -295,48 +354,6 @@ app.classes.home = AppJS.extend(
|
||||
*/
|
||||
List:
|
||||
{
|
||||
/**
|
||||
* List uses mostly JS to generate its content, so we just do it on the JS side by
|
||||
* returning a call to this function as the HTML content.
|
||||
*
|
||||
* @param id String The ID of the portlet
|
||||
* @param list_values Array List of information passed to the link widget
|
||||
*/
|
||||
set_content: function(id, list_values)
|
||||
{
|
||||
try {
|
||||
var portlet = app.home.portlet_container.getWidgetById(id);
|
||||
} catch(e) {
|
||||
egw.debug("log", "Tried to set home list content with no etemplate");
|
||||
return;
|
||||
};
|
||||
if(portlet != null)
|
||||
{
|
||||
var list = portlet.getWidgetById(id+'-list');
|
||||
if(list)
|
||||
{
|
||||
// List was just rudely pulled from DOM by the call to HTML, put it back
|
||||
portlet.content.append(list.getDOMNode());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create widget
|
||||
list = et2_createWidget('link-list', {id: id+'-list'}, portlet);
|
||||
list.doLoadingFinished();
|
||||
// Abuse link list by overwriting delete handler
|
||||
list._delete_link = app.home.List.delete_link;
|
||||
}
|
||||
list.set_value(list_values);
|
||||
|
||||
// Disable link list context menu
|
||||
$j('tr',list.list).unbind('contextmenu');
|
||||
|
||||
// Allow scroll bars
|
||||
portlet.content.css('overflow', 'auto');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* For list_portlet - opens a dialog to add a new entry to the list
|
||||
*/
|
||||
@ -360,55 +377,79 @@ app.classes.home = AppJS.extend(
|
||||
}
|
||||
if(target_action == null)
|
||||
{
|
||||
var link = et2_createWidget('link-entry', {label: this.egw.lang('Add')}, this.portlet_container);
|
||||
var dialog = et2_dialog.show_dialog(
|
||||
function(button_id) {
|
||||
// use template base url from initial template, to continue using webdav, if that was loaded via webdav
|
||||
var splitted = 'home.edit'.split('.');
|
||||
var path = app.home.portlet_container.getRoot()._inst.template_base_url + splitted.shift() + "/templates/default/" +
|
||||
splitted.join('.')+ ".xet";
|
||||
var dialog = et2_createWidget("dialog",{
|
||||
callback: function(button_id, value) {
|
||||
if(button_id == et2_dialog.CANCEL_BUTTON) return;
|
||||
var new_list = widget.options.settings.list || [];
|
||||
var add = link.getValue();
|
||||
link.destroy();
|
||||
for(var i = 0; i < new_list.length; i++)
|
||||
{
|
||||
if(new_list[i].app == add.app && new_list[i].id == add.id)
|
||||
if(new_list[i].app == value.add.app && new_list[i].id == value.add.id)
|
||||
{
|
||||
// Duplicate
|
||||
// Duplicate - skip it
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
new_list.push(add);
|
||||
value.add.link_id = value.add.app + ':' + value.add.id;
|
||||
// Update server side
|
||||
new_list.push(value.add);
|
||||
widget._process_edit(button_id,{list: new_list});
|
||||
// Update client side
|
||||
widget.getWidgetById('list').set_value(new_list);
|
||||
},
|
||||
'Add',
|
||||
this.egw.lang('Add'), {},
|
||||
et2_dialog.BUTTONS_OK_CANCEL
|
||||
);
|
||||
dialog.set_message(link.getDOMNode());
|
||||
buttons: et2_dialog.BUTTONS_OK_CANCEL,
|
||||
title: app.home.egw.lang('add'),
|
||||
template:path,
|
||||
value: { content: [{label: app.home.egw.lang('add'),type: 'link-entry',name: 'add',size:''}]}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Drag'n'dropped something on the list - just send action IDs
|
||||
var drop_data = [];
|
||||
var new_list = widget.options.settings.list || [];
|
||||
var changed = false;
|
||||
for(var i = 0; i < new_list.length; i++)
|
||||
{
|
||||
// Avoid duplicates
|
||||
for(var j = 0; j < source.length; j++)
|
||||
{
|
||||
if(!source[j].id || new_list[i].app+"::"+new_list[i].id == source[j].id)
|
||||
{
|
||||
// Duplicate - skip it
|
||||
source.splice(j,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(var i = 0; i < source.length; i++)
|
||||
{
|
||||
if(source[i].id) drop_data.push(source[i].id);
|
||||
var explode = source[i].id.split('::');
|
||||
new_list.push({app: explode[0],id: explode[1], link_id: explode.join(':')});
|
||||
changed = true;
|
||||
}
|
||||
widget.getWidgetById('list').set_value(new_list);
|
||||
if(changed)
|
||||
{
|
||||
widget._process_edit(et2_dialog.OK_BUTTON,{
|
||||
list: new_list || {}
|
||||
});
|
||||
}
|
||||
widget._process_edit(et2_dialog.BUTTONS_OK_CANCEL,{
|
||||
list: widget.options.settings.list || {},
|
||||
dropped_data: drop_data
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a link from the list
|
||||
*/
|
||||
delete_link: function(undef, row) {
|
||||
// Quick response
|
||||
link_change: function(list, link_id, row) {
|
||||
// Quick response client side
|
||||
row.slideUp(row.remove);
|
||||
|
||||
// Actual removal
|
||||
this._parent.options.settings.list.splice(row.index(), 1);
|
||||
this._parent._process_edit(et2_dialog.OK_BUTTON,{list: this._parent.options.settings.list || {}});
|
||||
var portlet = list._parent._parent;
|
||||
portlet.options.settings.list.splice(row.index(), 1);
|
||||
portlet._process_edit(et2_dialog.OK_BUTTON,{list: portlet.options.settings.list || {}});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -2,6 +2,12 @@
|
||||
* Home CSS
|
||||
*/
|
||||
|
||||
#home-index_home-index {
|
||||
height:100%;
|
||||
}
|
||||
#home-index_portlets {
|
||||
background-color: inherit;
|
||||
}
|
||||
#portlets {
|
||||
border: 1px solid silver;
|
||||
width: 100%;
|
||||
@ -20,20 +26,10 @@
|
||||
.et2_portlet.ui-widget-content > div:last-of-type {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Shapeshift
|
||||
#portlets {
|
||||
position: relative;
|
||||
.et2_portlet.ui-widget-content > div:last-of-type > div {
|
||||
height: 100%;
|
||||
background: linear-gradient(to bottom, rgba(255,255,255,.9) 10%,rgba(255,255,255,.75) 90%) /* W3C */
|
||||
}
|
||||
.home .et2_portlet {
|
||||
position: absolute;
|
||||
}
|
||||
#portlets .ss-placeholder-child {
|
||||
background: transparent;
|
||||
border: 1px dashed silver;
|
||||
position: absolute;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Gridster */
|
||||
#portlets {
|
||||
@ -41,7 +37,6 @@
|
||||
}
|
||||
.home .et2_portlet {
|
||||
position: absolute;
|
||||
margin: 5px;
|
||||
}
|
||||
#portlets .preview-holder {
|
||||
margin: 5px;
|
||||
|
@ -12,6 +12,8 @@
|
||||
</row>
|
||||
<row>
|
||||
<box id="portlets">
|
||||
<!-- Box wrapper needed to get box to auto-repeat -->
|
||||
<box id="${row}"><portlet id="${_cont[id]}" title="${_cont[title]}" color="@color" parent_node="home-index_portlets" settings="@settings" width="@width" height="@height" row="@row" col="@col" value="@content"/></box>
|
||||
</box>
|
||||
</row>
|
||||
</rows>
|
||||
|
7
home/templates/default/legacy.xet
Normal file
7
home/templates/default/legacy.xet
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- $Id$ -->
|
||||
<overlay>
|
||||
<template id="home.list" template="" lang="" group="0" version="1.9.001">
|
||||
<html id="legacy"/>
|
||||
</template>
|
||||
</overlay>
|
6
home/templates/default/link.xet
Normal file
6
home/templates/default/link.xet
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<overlay>
|
||||
<template id="home.link" template="" lang="" group="0" version="1.9.001">
|
||||
<link id="entry"/>
|
||||
</template>
|
||||
</overlay>
|
7
home/templates/default/list.xet
Normal file
7
home/templates/default/list.xet
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- $Id$ -->
|
||||
<overlay>
|
||||
<template id="home.list" template="" lang="" group="0" version="1.9.001">
|
||||
<link-list id="list" onchange="app.home.List.link_change"/>
|
||||
</template>
|
||||
</overlay>
|
@ -1,3 +1,4 @@
|
||||
@import "../default/app.css";
|
||||
/**
|
||||
* EGroupware: CSS with less preprocessor
|
||||
*
|
||||
@ -9,7 +10,3 @@
|
||||
* @package home
|
||||
* @version $Id$
|
||||
*/
|
||||
#divMain img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
@ -13,12 +13,4 @@
|
||||
@import (reference) "../../../pixelegg/less/def_buttons.less";
|
||||
@import (reference) "../../../pixelegg/less/def_design_pattern_color_font_shadow.less";
|
||||
|
||||
|
||||
// Dialog: Kalender Ressourcen
|
||||
|
||||
#divMain {
|
||||
|
||||
img {width: 16px; height: 16px;}
|
||||
|
||||
}
|
||||
//
|
||||
@import (reference) "../default/app.css";
|
@ -1165,8 +1165,6 @@ abstract class egw_framework
|
||||
$apps = array();
|
||||
foreach($GLOBALS['egw_info']['user']['apps'] as $app => $data)
|
||||
{
|
||||
// disable home until we get it working again
|
||||
if ($app == 'home') continue;
|
||||
if (is_long($app))
|
||||
{
|
||||
continue;
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user