Some WIP on getting home working again

This commit is contained in:
Nathan Gray 2014-11-06 21:40:03 +00:00
parent 8fab640449
commit cbbb0bf39f
17 changed files with 1546 additions and 1043 deletions

View File

@ -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));
}
});

View File

@ -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;

View File

@ -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);
}
/**

View File

@ -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;
}
/**

View File

@ -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(
$properties = parent::get_properties();
$properties[] = array(
'name' => 'title',
'type' => 'textbox',
'label' => lang('Title'),
),
// Internal
array(
);
// Internal - no type means it won't show in configure dialog
$properties[] = array(
'name' => 'list'
)
) + parent::get_properties();
);
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;

View File

@ -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;
}

View File

@ -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);
// TODO: DOM IDs still collide
//$this->get_legacy_portlets($portlets, $attributes);
foreach($portlets as $index => $portlet)
{
$template->setElementAttribute('portlets', $index, (array)$attributes[$index]);
}
return $portlets;
}
@ -148,17 +170,29 @@ 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();
@ -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,7 +367,6 @@ 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
@ -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,15 +392,15 @@ 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

View File

@ -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)
{
// Top level
if(name == 'home.index')
{
// call parent
this._super.apply(this, arguments);
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");
// 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)
{
//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();
// 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._process_edit(et2_dialog.BUTTONS_OK_CANCEL,{
list: widget.options.settings.list || {},
dropped_data: drop_data
widget.getWidgetById('list').set_value(new_list);
if(changed)
{
widget._process_edit(et2_dialog.OK_BUTTON,{
list: new_list || {}
});
}
}
},
/**
* 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 || {}});
}
}
});

View File

@ -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;

View File

@ -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>

View 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>

View 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>

View 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>

View File

@ -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;
}

View File

@ -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";

View File

@ -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