mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-06-25 12:21:26 +02:00
Link list
This commit is contained in:
parent
6b361f770f
commit
a3901bd00f
@ -61,8 +61,11 @@ class etemplate_widget_link extends etemplate_widget
|
|||||||
|
|
||||||
if($value && !is_array($value))
|
if($value && !is_array($value))
|
||||||
{
|
{
|
||||||
|
// Try to explode
|
||||||
|
if(!is_array(explode(':',$value))) {
|
||||||
throw new egw_exception_wrong_parameter("Wrong value sent to link widget, needs to be an array. ".array2string($value));
|
throw new egw_exception_wrong_parameter("Wrong value sent to link widget, needs to be an array. ".array2string($value));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
elseif (!$value)
|
elseif (!$value)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -150,13 +153,41 @@ error_log("$app, $pattern, $options");
|
|||||||
$response->data($result !== false);
|
$response->data($result !== false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_links($value) {
|
public function ajax_link_list($value) {
|
||||||
|
|
||||||
$app = $value['to_app'];
|
$app = $value['to_app'];
|
||||||
$id = $value['to_id'];
|
$id = $value['to_id'];
|
||||||
|
|
||||||
$links = egw_link::get_links($app,$id,'','link_lastmod DESC',true, $value['show_deleted']);
|
$links = egw_link::get_links($app,$id,$value['only_app'],'link_lastmod DESC',true, $value['show_deleted']);
|
||||||
_debug_array($links);
|
foreach($links as &$link)
|
||||||
return $links;
|
{
|
||||||
|
$link['title'] = egw_link::title($link['app'],$link['id'],$link);
|
||||||
|
if ($link['app'] == egw_link::VFS_APPNAME)
|
||||||
|
{
|
||||||
|
$link['target'] = '_blank';
|
||||||
|
$link['label'] = 'Delete';
|
||||||
|
$link['help'] = lang('Delete this file');
|
||||||
|
if ($GLOBALS['egw_info']['user']['preferences']['common']['link_list_format'] != 'text')
|
||||||
|
{
|
||||||
|
$link['title'] = preg_replace('/: ([^ ]+) /',': ',$link['title']); // remove mime-type, it's alread in the icon
|
||||||
|
}
|
||||||
|
$link['icon'] = egw_link::vfs_path($link['app2'],$link['id2'],$link['id'],true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$link['icon'] = egw_link::get_registry($link['app'], 'icon');
|
||||||
|
$link['label'] = 'Unlink';
|
||||||
|
$link['help'] = lang('Remove this link (not the entry itself)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = egw_json_response::get();
|
||||||
|
// Strip keys, unneeded and cause index problems on the client side
|
||||||
|
$response->data(array_values($links));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ajax_delete($value) {
|
||||||
|
$response = egw_json_response::get();
|
||||||
|
$response->data(egw_link::unlink($value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,24 @@ var et2_link_to = et2_inputWidget.extend({
|
|||||||
"default": "",
|
"default": "",
|
||||||
"description": "This text get displayed if an input-field is empty and does not have the input-focus (blur). It can be used to show a default value or a kind of help-text."
|
"description": "This text get displayed if an input-field is empty and does not have the input-focus (blur). It can be used to show a default value or a kind of help-text."
|
||||||
},
|
},
|
||||||
|
"no_files": {
|
||||||
|
"name": "No files",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Suppress attach-files"
|
||||||
|
},
|
||||||
|
"search_label": {
|
||||||
|
"name": "Search label",
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "Label to use for search"
|
||||||
|
},
|
||||||
|
"link_label": {
|
||||||
|
"name": "Link label",
|
||||||
|
"type": "string",
|
||||||
|
"default": "Link",
|
||||||
|
"description": "Label for the link button"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
search_timeout: 200, //ms after change to send query
|
search_timeout: 200, //ms after change to send query
|
||||||
@ -90,7 +108,7 @@ var et2_link_to = et2_inputWidget.extend({
|
|||||||
|
|
||||||
// One common link button
|
// One common link button
|
||||||
this.link_button = $j(document.createElement("button"))
|
this.link_button = $j(document.createElement("button"))
|
||||||
.text(egw.lang("link"))
|
.text(egw.lang(this.options.link_label))
|
||||||
.appendTo(this.div).hide()
|
.appendTo(this.div).hide()
|
||||||
.click(this, this.createLink);
|
.click(this, this.createLink);
|
||||||
|
|
||||||
@ -121,6 +139,7 @@ var et2_link_to = et2_inputWidget.extend({
|
|||||||
// Link-to
|
// Link-to
|
||||||
var link_entry_attrs = {
|
var link_entry_attrs = {
|
||||||
id: this.id + '_link_entry',
|
id: this.id + '_link_entry',
|
||||||
|
blur: this.options.search_label ? this.options.search_label : egw.lang('Search...'),
|
||||||
query: function() { self.link_button.hide(); self.comment.hide(); return true;},
|
query: function() { self.link_button.hide(); self.comment.hide(); return true;},
|
||||||
select: function() {self.link_button.show(); self.comment.show(); return true;}
|
select: function() {self.link_button.show(); self.comment.show(); return true;}
|
||||||
}
|
}
|
||||||
@ -178,13 +197,13 @@ var et2_link_to = et2_inputWidget.extend({
|
|||||||
event.data = self.link_entry;
|
event.data = self.link_entry;
|
||||||
self.link_entry.createLink(event,links);
|
self.link_entry.createLink(event,links);
|
||||||
// Add comment
|
// Add comment
|
||||||
if(links.length > 0 && self.comment.val())
|
if(links.length > 0 && self.comment.val() && self.comment.val() != self.comment.attr("placeholder"))
|
||||||
{
|
{
|
||||||
for(var i = 0; i < links.length; i++)
|
for(var i = 0; i < links.length; i++)
|
||||||
{
|
{
|
||||||
links[i].remark = self.comment.val();
|
links[i].remark = self.comment.val();
|
||||||
}
|
}
|
||||||
self.comment.val("");
|
self.comment.val(self.comment.attr("placeholder"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
@ -221,6 +240,17 @@ var et2_link_to = et2_inputWidget.extend({
|
|||||||
delete this.file_upload.options.value[file];
|
delete this.file_upload.options.value[file];
|
||||||
}
|
}
|
||||||
this.file_upload.progress.empty();
|
this.file_upload.progress.empty();
|
||||||
|
|
||||||
|
// Look for a link-list with the same ID, refresh it
|
||||||
|
var self = this;
|
||||||
|
this.getRoot().iterateOver(
|
||||||
|
function(widget) {
|
||||||
|
if(widget.id == self.id) {
|
||||||
|
widget._get_links();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this, et2_link_list
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -434,7 +464,9 @@ var et2_link_entry = et2_valueWidget.extend({
|
|||||||
if(typeof _links == 'undefined')
|
if(typeof _links == 'undefined')
|
||||||
{
|
{
|
||||||
links = [];
|
links = [];
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
links = _links;
|
links = _links;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,7 +545,19 @@ var et2_link = et2_valueWidget.extend([et2_IDetachedDOM], {
|
|||||||
console.warn("Bad value for link widget. Need an object with keys 'app', 'id', and optionally 'title'", _value);
|
console.warn("Bad value for link widget. Need an object with keys 'app', 'id', and optionally 'title'", _value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.node.text(_value.title)
|
if(!_value.title) {
|
||||||
|
var title = egw.link_title(_value.id, _value.app, this.set_value, this);
|
||||||
|
if(title != null) {
|
||||||
|
_value.title = title;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Title will be fetched from server and then set
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.node.text(_value.title).unbind()
|
||||||
.click( function(){egw.open(_value.id, _value.app, "edit", _value.extra);});
|
.click( function(){egw.open(_value.id, _value.app, "edit", _value.extra);});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -565,18 +609,30 @@ var et2_link_string = et2_valueWidget.extend([et2_IDetachedDOM], {
|
|||||||
"description": "Use the given application, so you can pass just the ID for value"
|
"description": "Use the given application, so you can pass just the ID for value"
|
||||||
},
|
},
|
||||||
"value": {
|
"value": {
|
||||||
description: "Either an array of link information (see link) or array with keys to_app and to_id",
|
"description": "Either an array of link information (see egw_link::link()) or array with keys to_app and to_id",
|
||||||
type: "any"
|
"type": "any"
|
||||||
|
},
|
||||||
|
"only_app": {
|
||||||
|
"name": "Application filter",
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "Appname, eg. 'projectmananager' to list only linked projects"
|
||||||
|
},
|
||||||
|
"link_type": {
|
||||||
|
"name": "Type filter",
|
||||||
|
"type": "string",
|
||||||
|
"default":"",
|
||||||
|
"description": "Sub-type key to list only entries of that type"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
init: function() {
|
init: function() {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
|
|
||||||
this.node = $j(document.createElement("ul"))
|
this.list = $j(document.createElement("ul"))
|
||||||
.addClass("et2_link_string");
|
.addClass("et2_link_string");
|
||||||
|
|
||||||
if(this.options.class) this.node.addClass(this.options.class);
|
if(this.options.class) this.node.addClass(this.options.class);
|
||||||
this.setDOMNode(this.node[0]);
|
this.setDOMNode(this.list[0]);
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
@ -586,31 +642,60 @@ var et2_link_string = et2_valueWidget.extend([et2_IDetachedDOM], {
|
|||||||
|
|
||||||
set_value: function(_value) {
|
set_value: function(_value) {
|
||||||
// Get data
|
// Get data
|
||||||
if(!_value) return;
|
if(!_value || _value == null) return;
|
||||||
if(typeof _value == 'object' && _value.to_app && _value.to_id) {
|
if(!_value.to_app && this.options.application) _value.to_app = this.options.application;
|
||||||
// TODO: Fetch data from server via caching queue
|
|
||||||
_value = [
|
if(typeof _value == 'object' && _value.to_app && _value.to_id)
|
||||||
{'id': '1','app': 'infolog','title': 'Fake entry #1'},
|
{
|
||||||
{'id': '2','app': 'infolog','title': 'Fake entry #2'}
|
this.value = _value;
|
||||||
];
|
this._get_links();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(typeof _value == 'object' && _value.length > 0) {
|
if(_value.length > 0) {
|
||||||
this.node.empty();
|
// Have full info
|
||||||
|
// Don't store new value, just update display
|
||||||
|
|
||||||
|
this.list.empty();
|
||||||
|
|
||||||
// Make new links
|
// Make new links
|
||||||
for(var i = 0; i < _value.length; i++) {
|
for(var i = 0; i < _value.length; i++)
|
||||||
|
{
|
||||||
|
if(!this.options.only_app || this.options.only_app && _value[i].app == this.options.only_app)
|
||||||
|
{
|
||||||
this._add_link(_value[i]);
|
this._add_link(_value[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_get_links: function() {
|
||||||
|
var _value = this.value;
|
||||||
|
// Just IDs - get from server
|
||||||
|
if(this.options.only_app)
|
||||||
|
{
|
||||||
|
_value.only_app = this.options.only_app;
|
||||||
|
}
|
||||||
|
egw.jsonq('etemplate.etemplate_widget_link.ajax_link_list', [_value], this.set_value, this);
|
||||||
|
return;
|
||||||
},
|
},
|
||||||
|
|
||||||
_add_link: function(_link_data) {
|
_add_link: function(_link_data) {
|
||||||
var link = jQuery(document.createElement("li"))
|
if(!_link_data.title) {
|
||||||
|
// No callback yet, need something to do with it
|
||||||
|
var title = egw.link_title(_link_data.app, _link_data.id);
|
||||||
|
// Need to set it to something, or call to text() will return current value
|
||||||
|
if(title == null || title == false) _link_data.title = "";
|
||||||
|
}
|
||||||
|
var link = $j(document.createElement("li"))
|
||||||
|
.appendTo(this.list)
|
||||||
.text(_link_data.title)
|
.text(_link_data.title)
|
||||||
.addClass("et2_link")
|
.addClass("et2_link")
|
||||||
.appendTo(this.node)
|
|
||||||
//.bind( 'click', jQuery.proxy( function(){egw.open(_link_data.id, _link_data.app, "edit", _link_data.extra)}, egw));
|
|
||||||
.click( function(){egw.open(_link_data.id, _link_data.app, "edit", _link_data.extra);});
|
.click( function(){egw.open(_link_data.id, _link_data.app, "edit", _link_data.extra);});
|
||||||
|
|
||||||
|
// Now that link is created, get title from server & update
|
||||||
|
if(!_link_data.title) {
|
||||||
|
egw.link_title(_link_data.app, _link_data.id, function(title) {this.text(title);}, link);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -627,7 +712,7 @@ _value = [
|
|||||||
* passed to the "setDetachedAttributes" function in the same order.
|
* passed to the "setDetachedAttributes" function in the same order.
|
||||||
*/
|
*/
|
||||||
getDetachedNodes: function() {
|
getDetachedNodes: function() {
|
||||||
return [this.node];
|
return [this.list[0]];
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -641,8 +726,80 @@ _value = [
|
|||||||
* given values.
|
* given values.
|
||||||
*/
|
*/
|
||||||
setDetachedAttributes: function(_nodes, _values) {
|
setDetachedAttributes: function(_nodes, _values) {
|
||||||
this.node = $j(_nodes[0]);
|
this.list = $j(_nodes[0]);
|
||||||
|
if(!_values.value) this.transformAttributes(_values);
|
||||||
this.set_value(_values["value"]);
|
this.set_value(_values["value"]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
et2_register_widget(et2_link_string, ["link-string"]);
|
et2_register_widget(et2_link_string, ["link-string"]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UI widget for one or more links in a list (table)
|
||||||
|
*/
|
||||||
|
var et2_link_list = et2_link_string.extend({
|
||||||
|
attributes: {
|
||||||
|
"show_deleted": {
|
||||||
|
"name": "Show deleted",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Show links that are marked as deleted, being held for purge"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
init: function() {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
|
||||||
|
this.list = $j(document.createElement("table"))
|
||||||
|
.addClass("et2_link_list");
|
||||||
|
if(this.options.class) this.node.addClass(this.options.class);
|
||||||
|
this.setDOMNode(this.list[0]);
|
||||||
|
},
|
||||||
|
|
||||||
|
_add_link: function(_link_data) {
|
||||||
|
var row = $j(document.createElement("tr"))
|
||||||
|
.appendTo(this.list)
|
||||||
|
|
||||||
|
// Icon
|
||||||
|
//TODO: Needs vfs widget
|
||||||
|
var icon = $j(document.createElement("td"))
|
||||||
|
.appendTo(row)
|
||||||
|
.addClass("icon");
|
||||||
|
if(_link_data.icon)
|
||||||
|
{
|
||||||
|
var icon_widget = et2_createWidget("image");
|
||||||
|
icon_widget.set_src(_link_data.icon);
|
||||||
|
icon.append(icon_widget.getDOMNode());
|
||||||
|
}
|
||||||
|
|
||||||
|
var columns = ['app','title','remark'];
|
||||||
|
for(var i = 0; i < columns.length; i++) {
|
||||||
|
$j(document.createElement("td"))
|
||||||
|
.appendTo(row)
|
||||||
|
.addClass(columns[i])
|
||||||
|
.text(_link_data[columns[i]])
|
||||||
|
.click( function(){egw.open(_link_data.id, _link_data.app, "edit", _link_data.extra);});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Date
|
||||||
|
/*
|
||||||
|
var date_row = $j(document.createElement("td"))
|
||||||
|
.appendTo(row);
|
||||||
|
if(_link_data.lastmod)
|
||||||
|
{
|
||||||
|
var date_widget = et2_createWidget("date-since");
|
||||||
|
date_widget.set_value(_link_data.lastmod);
|
||||||
|
date_row.append(date_widget.getDOMNode());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
var delete_button = $j(document.createElement("td"))
|
||||||
|
.appendTo(row)
|
||||||
|
.addClass("delete icon")
|
||||||
|
.bind( 'click', function(){
|
||||||
|
delete_button.addClass("loading").removeClass("delete");
|
||||||
|
new egw_json_request("etemplate.etemplate_widget_link.ajax_delete", [_link_data.link_id])
|
||||||
|
.sendRequest(true, function(data) { if(data) {row.slideUp(row.remove);}});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
et2_register_widget(et2_link_list, ["link-list"]);
|
||||||
|
@ -312,6 +312,28 @@ ul.et2_link_string {
|
|||||||
content: ', ';
|
content: ', ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.et2_link_list td.remark {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.et2_link_list td.delete {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
float: right;
|
||||||
|
display: none;
|
||||||
|
background-image: url("gfx/close.png");
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
.et2_link_list .icon img, .et2_link_list td.icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
.et2_link_list tr:hover td.delete {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
.egw_tooltip
|
.egw_tooltip
|
||||||
{
|
{
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user