[Fusionforge-commits] FusionForge branch master updated. v6.0.5-1300-g279bff2

Franck Villaume nerville at libremir.placard.fr.eu.org
Wed Dec 28 15:30:16 CET 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "FusionForge".

The branch, master has been updated
       via  279bff205cb745e729dd77c77930fc20c0fe2f3e (commit)
       via  b65ca5d5bc66b7c9c2ec6635c2ae0472f3548114 (commit)
       via  641b7bb0f9e7e198138078e250c9d5139818205a (commit)
      from  acd1b9d1d310e126bb4f59735f393f68d3ee2c67 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=279bff205cb745e729dd77c77930fc20c0fe2f3e

commit 279bff205cb745e729dd77c77930fc20c0fe2f3e
Author: Franck Villaume <franck.villaume at trivialdev.com>
Date:   Wed Dec 28 15:29:22 2016 +0100

    Artifact Display Widget: support drag&drop widget creation, support section title

diff --git a/src/common/tracker/actions/widget_artifact_display.php b/src/common/tracker/actions/widget_artifact_display.php
index 96075a8..864261c 100644
--- a/src/common/tracker/actions/widget_artifact_display.php
+++ b/src/common/tracker/actions/widget_artifact_display.php
@@ -49,6 +49,7 @@ $id = db_result($res, 0 , 'id');
 
 html_use_jqueryui();
 html_use_jquerydatetimepicker();
+use_javascript('/widgets/scripts/WidgetController.js');
 if ($func == 'add') {
 	$ath->header(array('title' => _('Submit New'), 'modal' => 1));
 } elseif ($func == 'detail') {
diff --git a/src/common/widget/WidgetLayoutManager.class.php b/src/common/widget/WidgetLayoutManager.class.php
index 95eaa93..4143370 100644
--- a/src/common/widget/WidgetLayoutManager.class.php
+++ b/src/common/widget/WidgetLayoutManager.class.php
@@ -410,7 +410,7 @@ class WidgetLayoutManager {
 			$action = 'widget';
 		}
 		echo $HTML->html_list($elementsLi, array('class' => 'widget_toolbar'));
-		echo $HTML->openForm(array('action' => '/widgets/updatelayout.php?owner='.$owner_type.$owner_id.'&action='.$action.'&layout_id='.$layout_id, 'method' => 'post'));
+		echo $HTML->openForm(array('id' => 'builder', 'action' => '/widgets/updatelayout.php?owner='.$owner_type.$owner_id.'&action='.$action.'&layout_id='.$layout_id, 'method' => 'post'));
 		if ($update_layout) {
 			?>
 			<script type='text/javascript'>//<![CDATA[
@@ -819,7 +819,6 @@ class WidgetLayoutManager {
 	 * @param	object	$widget
 	 */
 	function removeWidget($owner_id, $owner_type, $layout_id, $name, $instance_id, &$widget) {
-		error_log('o='.$owner_id.',t='.$owner_type.',layout_id='.$layout_id.',instance_id='.$instance_id);
 		$sql = "DELETE FROM layouts_contents WHERE owner_type =$1 AND owner_id = $2 AND layout_id = $3 AND name = $4 AND content_id = $5";
 		db_query_params($sql,array($owner_type,$owner_id,$layout_id,$name,$instance_id));
 		if (!db_error()) {
diff --git a/src/common/widget/Widget_TrackerContent.class.php b/src/common/widget/Widget_TrackerContent.class.php
index c948faa..5077787 100644
--- a/src/common/widget/Widget_TrackerContent.class.php
+++ b/src/common/widget/Widget_TrackerContent.class.php
@@ -26,7 +26,6 @@ require_once $gfwww.'include/jquery_plugins.php';
 
 class Widget_TrackerContent extends Widget {
 	var $trackercontent_title;
-	var $trackercolumns;
 
 	function __construct() {
 		$request =& HTTPRequest::instance();
@@ -43,10 +42,6 @@ class Widget_TrackerContent extends Widget {
 		return $this->trackercontent_title ? $hp->purify($this->trackercontent_title, CODENDI_PURIFIER_CONVERT_HTML)  : _('Tracker Content Box');
 	}
 
-	function getColumns() {
-		return $this->trackercolumns;
-	}
-
 	function isUnique() {
 		return false;
 	}
@@ -56,7 +51,7 @@ class Widget_TrackerContent extends Widget {
 	}
 
 	function getDescription() {
-		return _("Create an empty widget to link fields together and then organize the artifact display view (update & submit new).");
+		return _('Create an empty widget to link fields together and then organize the artifact display view (update & submit new).');
 	}
 
 	function loadContent($id) {
@@ -66,29 +61,33 @@ class Widget_TrackerContent extends Widget {
 	}
 
 	function fetchData($id) {
-		$res = db_query_params('select * from artifact_display_widget where id = $1', array($id));
-		$title = false;
-		$columns = 0;
+		$res = db_query_params('SELECT title FROM artifact_display_widget WHERE id = $1', array($id));
 		if ($res) {
-			$arr = db_fetch_array($res);
-			$title = $arr['title'];
-			$columns = $arr['cols'];
+			$title = db_result($res, 0, 'title');
 		}
 		$this->trackercontent_title = $title;
-		$this->trackercolumns = $columns;
 	}
 
 	function create(&$request) {
 		$hp = Codendi_HTMLPurifier::instance();
 		$this->trackercontent_title = $hp->purify($request->get('title'), CODENDI_PURIFIER_CONVERT_HTML);
-		$this->trackercolumns = (int)$request->get('columns');
-		$res = db_query_params('INSERT INTO artifact_display_widget (owner_id, title, cols) VALUES ($1, $2, $3)', array($this->owner_id, $this->trackercontent_title, $this->trackercolumns));
+		$trackerrows = getArrayFromRequest('trackercontent_layout');
+		$trackerextrafields = getArrayFromRequest('trackercontent_ef');
+		$res = db_query_params('INSERT INTO artifact_display_widget (owner_id, title) VALUES ($1, $2)', array($this->owner_id, $this->trackercontent_title));
 		$content_id = db_insertid($res, 'artifact_display_widget', 'id');
-		$extrafieldIDs = getArrayFromRequest('extrafieldids');
-		$extrafieldIDColumns = getArrayFromRequest('extrafield_column_ids');
-		$extrafieldIDRows = getArrayFromRequest('extrafield_row_ids');
-		foreach ($extrafieldIDs as $key => $extrafieldID) {
-			db_query_params('INSERT INTO artifact_display_widget_field (id, field_id, column_id, row_id) VALUES ($1, $2, $3, $4)', array($content_id, $extrafieldID, $extrafieldIDColumns[$key], $extrafieldIDRows[$key]));
+		foreach ($trackerrows as $rowkey => $trackerrow) {
+			$columns = explode(',', $trackerrow);
+			$extrafields = explode(',', $trackerextrafields[$rowkey]);
+			$rowid = $rowkey;
+			foreach ($columns as $columnkey => $column) {
+				if ($extrafields[$columnkey] == "fake") {
+					$extrafieldid = 0;
+				} else {
+					$extrafieldid = substr($extrafields[$columnkey], 2); //remove prefix ef
+				}
+				db_query_params('INSERT INTO artifact_display_widget_field (id, field_id, column_id, row_id, width) VALUES ($1, $2, $3, $4, $5)',
+						array($content_id, $extrafieldid, $columnkey, $rowid, $column));
+			}
 		}
 		return $content_id;
 	}
@@ -102,60 +101,194 @@ class Widget_TrackerContent extends Widget {
 		return html_e('p', array(), _('Title')._(':').html_e('input', array('type' => 'text', 'name' => 'title', 'size' => 30, 'value' => htmlspecialchars($title))));
 	}
 
-	private function getPartialPreferencesFormColumns($column_number) {
-		return html_e('p', array(), _('Number of vertical columns')._(':').html_e('input', array('type' => 'number', 'name' => 'columns', 'value' => $column_number, 'step' => 1, 'min' => 1, 'title' => _('Set number of columns to split your box into columns'))));
-	}
-
-	private function getAvailableExtraFieldsForm($owner_id) {
+	private function buildRenderWidget() {
 		global $HTML;
-		$atid = $owner_id;
-		$artifactTypeObject = artifactType_get_object($atid);
-		$availableExtraFields = $artifactTypeObject->getExtraFields();
-		$stillAvailableExtraFields = $this->availableExtrafields($owner_id, $availableExtraFields);
-		if (count($stillAvailableExtraFields) > 0) {
-			$content = html_e('p', array(), sprintf(_('Tick available custom fields from %s to display into this widget'), $artifactTypeObject->getName())._(':'));
-			$content .= $HTML->listTableTop(array('', '', _('Column ID'), _('Row ID')));
-			foreach ($stillAvailableExtraFields as $key => $stillAvailableExtraField) {
+		global $ath;
+		$content = html_e('p', array(), _('Build your layout and drag & drop customfields in cells')._(':'));
+		$content .= $HTML->listTableTop(array(), array(), '', 'layout-manager').
+				'<tr>
+				<td>'
+				.html_e('div', array('class' => 'layout-manager-row-add'), '+');
+		$layoutExtraFieldIDs = $this->getLayoutExtraFieldIDs($this->content_id);
+		if (count($layoutExtraFieldIDs) > 0) {
+			foreach ($layoutExtraFieldIDs as $row_id => $column_id) {
 				$cells = array();
-				$cells[][] = util_unconvert_htmlspecialchars($stillAvailableExtraField['field_name']);
-				$cells[][] = html_e('input', array('type' => 'checkbox', 'name' => 'extrafieldids[]', 'value' => $stillAvailableExtraField[0]));
-				$cells[][] = html_e('input', array('type' => 'number', 'name' => 'extrafield_column_ids[]', 'value' => 1, 'step' => 1, 'min' => 1, 'title' => _('Set the column number accordingly to the number of columns you created')));
-				$cells[][] = html_e('input', array('type' => 'number', 'name' => 'extrafield_row_ids[]', 'value' => 1, 'step' => 1, 'min' => 1, 'title' => _('Set the row number accordingly to organize the extrafields')));
-				$content .= $HTML->multiTableRow(array('class' => $HTML->boxGetAltRowStyle($key, true)), $cells);
+				$content .= '<table class="layout-manager-row" id="widget_layout_build">
+							<tr>
+							<td class="layout-manager-column-add">+</td>';
+				foreach ($column_id as $extrafieldID) {
+					$keys = array_keys($extrafieldID);
+					if ($keys[0]) {
+						$extrafieldObject = new ArtifactExtraField($ath, $keys[0]);
+						$divEF = html_e('div', array('id' => 'ef'.$keys[0], 'class' => 'wb_extrafield', 'style' => 'background: #e6e6e6 none repeat scroll 0 0; padding: 2px; text-align: center;'), $extrafieldObject->getName().'<div id="xef'.$keys[0].'" class="ef-widget-remove">x</div>');
+					} else {
+						$divEF = '<div id="fake" class="wb_extrafield" style="display: hidden" />';
+					}
+
+					$content .= '<td class="layout-manager-column" width="'.$extrafieldID[$keys[0]][0].'%">
+							<div class="layout-manager-column-remove">x</div>
+							<div class="layout-manager-column-width">
+							'._('Section Title')._(':').'<br  />
+							<input type="text" value="'.htmlspecialchars($extrafieldID[$keys[0]][1]).'" size="20" maxsize="20" /><br />
+							<input type="number" value="'.$extrafieldID[$keys[0]][0].'" autocomplete="off" size="1" maxlength="3" />%
+							</div>';
+					$content .= $divEF;
+					$content .= '</td><td class="layout-manager-column-add">+</td>';
+				}
+				$content .= '</tr></table>';
 			}
-			$content .= $HTML->listTableBottom();
 		} else {
-			$content = $HTML->information(_('No custom fields available to link to this widget'));
+			$content .= '<table class="layout-manager-row" id="widget_layout_build">
+				<tr>
+				<td class="layout-manager-column-add">+</td>';
+			$content .= '<td class="layout-manager-column">
+				<div class="layout-manager-column-remove">x</div>
+				<div class="layout-manager-column-width">
+				'._('Section Title')._(':').'<br  />
+				<input type="text" value="" size="20" maxsize="20" /><br />
+				<input type="number" value="50" autocomplete="off" size="1" maxlength="3" />%
+				</div>
+				<div id="fake" class="wb_extrafield" style="display: hidden" />
+				</td>
+				<td class="layout-manager-column-add">+</td>';
+			$content .= '<td class="layout-manager-column">
+				<div class="layout-manager-column-remove">x</div>
+				<div class="layout-manager-column-width">
+				'._('Section Title')._(':').'<br  />
+				<input type="text" value="" size="20" maxsize="20" /><br />
+				<input type="number" value="50" autocomplete="off" size="1" maxlength="3" />%
+				</div>
+				<div id="fake" class="wb_extrafield" style="display: hidden" />
+				</td>
+				<td class="layout-manager-column-add">+</td>
+				</tr></table>';
 		}
+		$content .= html_e('div', array('class' => 'layout-manager-row-add'), '+');
+		$content .= '</td>
+			</tr>'.
+			$HTML->listTableBottom();
+		$javascript = <<<'EOS'
+				var controllerWidgetBuilder;
+				jQuery(document).ready(function() {
+					controllerWidgetBuilder = new WidgetBuilderController({
+						buttonAddRow:		jQuery('.layout-manager-row-add'),
+						buttonAddColumn:	jQuery('.layout-manager-column-add'),
+						buttonRemoveColumn:	jQuery('.layout-manager-column-remove'),
+						buttonRemoveEF:		jQuery('.ef-widget-remove')
+					});
+					jQuery('.layout-manager-column').droppable({
+										accept: '#extrafield_table .wb_extrafield',
+										drop: function(event, ui) {
+											ui.draggable.appendTo(this).css('position', '');
+											ui.draggable.parent().droppable('destroy');
+											ui.draggable.parent().find('#fake').remove();
+											ui.draggable.find('#x'+ui.draggable.attr('id')).show()},
+										over: function(event, ui) {
+											ui.helper.css('z-index', 1);
+										},
+					});
+					if (jQuery("[name='name[trackercontent][add]']") != 'undefined') {
+						jQuery("[name='name[trackercontent][add]']").click(function(){
+							var form = jQuery(this).parents('form').first();
+							form.find('.layout-manager-row').each(function(i, e) {
+								jQuery('<input>', {
+									type: 'hidden',
+									name: 'trackercontent_layout[]',
+									value: jQuery(e).find('.layout-manager-column input[type=number]').map(function(){ return this.value;}).get().join(',')
+								}).appendTo(form);
+								jQuery('<input>', {
+									type: 'hidden',
+									name: 'trackercontent_ef[]',
+									value: jQuery(e).find('.layout-manager-column > .wb_extrafield').map(function(){ return this.id;}).get().join(',')
+								}).appendTo(form);
+								jQuery('<input>', {
+									type: 'hidden',
+									name: 'trackercontent_title[]',
+									value: jQuery(e).find('.layout-manager-column input[type=text]').map(function(){ return this.value;}).get().join(',')
+								}).appendTo(form);
+							});
+						});
+					}
+					if (jQuery("[name='trackercontent-submit']") != 'undefined') {
+						jQuery("[name='trackercontent-submit']").click(function(){
+							var form = jQuery(this).parents('form').first();
+							form.find('.layout-manager-row').each(function(i, e) {
+								jQuery('<input>', {
+									type: 'hidden',
+									name: 'trackercontent_layout[]',
+									value: jQuery(e).find('.layout-manager-column input[type=number]').map(function(){ return this.value;}).get().join(',')
+								}).appendTo(form);
+								jQuery('<input>', {
+									type: 'hidden',
+									name: 'trackercontent_ef[]',
+									value: jQuery(e).find('.layout-manager-column > .wb_extrafield').map(function(){ return this.id;}).get().join(',')
+								}).appendTo(form);
+								jQuery('<input>', {
+									type: 'hidden',
+									name: 'trackercontent_title[]',
+									value: jQuery(e).find('.layout-manager-column input[type=text]').map(function(){ return this.value;}).get().join(',')
+								}).appendTo(form);
+							});
+						});
+					}
+				});
+EOS;
+		$content .= html_e('script', array( 'type'=>'text/javascript'), '//<![CDATA['."\n".'jQuery(function(){'.$javascript.'});'."\n".'//]]>');
 		return $content;
 	}
 
-	private function getExtraFieldsForm($id) {
+	private function getAvailableExtraFieldsForm($owner_id, $preference = false) {
 		global $HTML;
-		global $ath;
-		global $atid;
+		$atid = $owner_id;
 		$artifactTypeObject = artifactType_get_object($atid);
-		$layoutExtraFieldIDs = $this->getLayoutExtraFieldIDs($id);
-		$content = html_e('p', array(), sprintf(_('Adjust already used ExtraFields from %s to display into this widget'), $artifactTypeObject->getName())._(':'));
-		if (count($layoutExtraFieldIDs) > 0) {
-			$content .= $HTML->listTableTop(array('', '', _('Column ID'), _('Row ID')));
-			foreach ($layoutExtraFieldIDs as $row_id => $column_id) {
-				foreach ($column_id as $key => $extrafieldIDs) {
-					foreach ($extrafieldIDs as $extrafieldID) {
-						$extrafieldObject = new ArtifactExtraField($ath, $extrafieldID);
-						$cells = array();
-						$cells[][] = $extrafieldObject->getName();
-						$cells[][] = html_e('input', array('type' => 'checkbox', 'name' => 'extrafieldids[]', 'value' => $extrafieldID, 'checked' => 'checked'));
-						$cells[][] = html_e('input', array('type' => 'number', 'name' => 'extrafield_column_ids[]', 'value' => $key, 'step' => 1, 'min' => 1, 'title' => _('Set the column number accordingly to the number of columns you created')));
-						$cells[][] = html_e('input', array('type' => 'number', 'name' => 'extrafield_row_ids[]', 'value' => $row_id, 'step' => 1, 'min' => 1, 'title' => _('Set the row number accordingly to organize the extrafields')));
-						$content .= $HTML->multiTableRow(array('class' => $HTML->boxGetAltRowStyle($key, true)), $cells);
-					}
+		$availableExtraFields = $artifactTypeObject->getExtraFields();
+		$stillAvailableExtraFields = $this->availableExtrafields($owner_id, $availableExtraFields);
+		$arr = array();
+		if ($preference) {
+			$arr = $this->getExtraFieldIDs($owner_id);
+		}
+		if (count($stillAvailableExtraFields) > 0 || count($arr) > 0) {
+			$content = html_e('p', array(), sprintf(_('Drag & drop into your layout the available custom fields from %s to display into this widget'), $artifactTypeObject->getName())._(':'));
+			$content .= $HTML->listTableTop(array(), array(), 'full', 'extrafield_table');
+		}
+		if (count($stillAvailableExtraFields) > 0) {
+			$cells = array();
+			for ($i = 0; count($stillAvailableExtraFields) > $i; $i++) {
+				$cells[] = array(html_e('div', array('id' => 'ef'.$stillAvailableExtraFields[$i][0], 'class' => 'wb_extrafield', 'style' => 'background: #e6e6e6 none repeat scroll 0 0; padding: 2px; text-align: center;'), util_unconvert_htmlspecialchars($stillAvailableExtraFields[$i]['field_name']).'<div id="xef'.$stillAvailableExtraFields[$i][0].'" style="display: none" class="ef-widget-remove">x</div>'), 'id' => 'tdef'.$stillAvailableExtraFields[$i][0], 'class' => 'td-droppable', 'width' => '50%');
+				if ((($i % 2) > 0) || count($stillAvailableExtraFields) == 1) {
+					$content .= $HTML->multiTableRow(array('class' => $HTML->boxGetAltRowStyle($i, true)), $cells);
+					$cells = array();
 				}
 			}
+		}
+		if (count($arr) > 0) {
+			$cells = array();
+			for ($i = 0; count($arr) > $i; $i++) {
+				$cells[] = array('', 'id' => 'tdef'.$arr[$i], 'width' => '50%');
+				if ((($i % 2) > 0) || count($arr) == 1) {
+					$content .= $HTML->multiTableRow(array('class' => $HTML->boxGetAltRowStyle($i, true)), $cells);
+					$cells = array();
+				}
+			}
+		}
+		if (count($stillAvailableExtraFields) > 0 || count($arr) > 0) {
 			$content .= $HTML->listTableBottom();
+			$javascript = <<<'EOS'
+				jQuery(document).ready(function() {
+					var wb_extrafield_start;
+					jQuery('.wb_extrafield', '#extrafield_table').draggable({
+												cursor: "move",
+												helper: "clone",
+												});
+				});
+EOS;
+			$content .= html_e('script', array( 'type'=>'text/javascript'), '//<![CDATA['."\n".'jQuery(function(){'.$javascript.'});'."\n".'//]]>');
 		}
-		return $content;
 
+		if (!isset($content)) {
+			$content = $HTML->information(_('No customfields available to link to a widget'));
+		}
+		return $content;
 	}
 
 	private function availableExtrafields($owner_id, $extrafields) {
@@ -180,11 +313,12 @@ class Widget_TrackerContent extends Widget {
 	}
 
 	private function getLayoutExtraFieldIDs($id) {
-		$res = db_query_params('select row_id, column_id, field_id from artifact_display_widget_field where id = $1 order by row_id, column_id', array($id));
+		$res = db_query_params('select row_id, column_id, field_id, width, section from artifact_display_widget_field where id = $1 order by row_id, column_id', array($id));
 		$extrafieldIDs = array();
 		if ($res && (db_numrows($res) > 0)) {
 			while ($arr = db_fetch_array($res)) {
-				$extrafieldIDs[$arr[0]][$arr[1]][] = $arr[2];
+				// row_id is unique, column_id is unique per row, field_id is unique, width is not unique, section is not unique
+				$extrafieldIDs[$arr[0]][$arr[1]][$arr[2]] = array($arr[3], $arr[4]);
 			}
 		}
 		return $extrafieldIDs;
@@ -194,7 +328,7 @@ class Widget_TrackerContent extends Widget {
 		$request =& HTTPRequest::instance();
 		$owner_id = (int)substr($request->get('owner'), 1);
 		$content = $this->getPartialPreferencesFormTitle(_('Enter title of Tracker Content Box'));
-		$content .= $this->getPartialPreferencesFormColumns(1);
+		$content .= $this->buildRenderWidget();
 		$content .= $this->getAvailableExtraFieldsForm($owner_id);
 		return $content;
 	}
@@ -217,7 +351,6 @@ class Widget_TrackerContent extends Widget {
 		$readonly = false;
 		if (count($layoutExtraFieldIDs) > 0) {
 			$mandatoryDisplay = false;
-			$return .= $HTML->listTableTop();
 			$selected = array();
 			$i = 0;
 			if (is_object($ah)) {
@@ -228,16 +361,17 @@ class Widget_TrackerContent extends Widget {
 			if (!forge_check_perm('tracker', $atid, 'submit')) {
 				$readonly = true;
 			}
-			$maxcol = 0;
 			foreach ($layoutExtraFieldIDs as $row_id => $column_id) {
-				$numcol = 1;
+				$return .= $HTML->listTableTop();
 				$cells = array();
-				foreach ($column_id as $key => $extrafieldIDs) {
-					if ($key != $numcol) {
-						$cells[][] = ' ';
-					}
-					foreach ($extrafieldIDs as $extrafieldID) {
-						$extrafieldObject = new ArtifactExtraField($ath, $extrafieldID);
+				foreach ($column_id as $extrafieldID) {
+					$keys = array_keys($extrafieldID);
+					if ($keys[0]) {
+						$cellContent = '';
+						if (strlen($extrafieldID[$keys[0]][1]) > 0) {
+							$cellContent .= html_e('div', array('class' => 'widget_section_title'), htmlspecialchars($extrafieldID[$keys[0]][1]));
+						}
+						$extrafieldObject = new ArtifactExtraField($ath, $keys[0]);
 						if ($func == 'add') {
 							$display = !(int)$extrafieldObject->isHiddenOnSubmit();
 						} else {
@@ -246,10 +380,10 @@ class Widget_TrackerContent extends Widget {
 						if ($display) {
 							$value = null;
 							$allowed = false;
-							if (isset($selected[$extrafieldID])) {
-								$value = $selected[$extrafieldID];
-							} elseif (isset($extra_fields[$extrafieldID])) {
-								$value = $extra_fields[$extrafieldID];
+							if (isset($selected[$keys[0]])) {
+								$value = $selected[$keys[0]];
+							} elseif (isset($extra_fields[$keys[0]])) {
+								$value = $extra_fields[$keys[0]];
 							}
 							$attrs = array('form' => 'trackerform');
 							$mandatory = '';
@@ -261,7 +395,7 @@ class Widget_TrackerContent extends Widget {
 							if (strlen($extrafieldObject->getDescription()) > 0) {
 								$attrs['title'] = $extrafieldObject->getDescription();
 							}
-							$cellContent = html_e('strong', array(), $extrafieldObject->getName()._(':')).$mandatory.html_e('br');
+							$cellContent .= html_e('strong', array(), $extrafieldObject->getName()._(':')).$mandatory.html_e('br');
 							switch ($extrafieldObject->getType()) {
 								case ARTIFACT_EXTRAFIELDTYPE_SELECT:
 									if ($readonly) {
@@ -270,14 +404,14 @@ class Widget_TrackerContent extends Widget {
 										} else {
 											$value = $ath->getElementName($value);
 										}
-										$cells[] = array($cellContent.$value, 'style' => 'vertical-align: top;');
+										$cellContent .= $value;
 									} else {
 										$parent = $extrafieldObject->getParent();
 										if (!is_null($parent) && !empty($parent) && $parent != '100') {
 											$selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
 											$allowed = $aef->getAllowedValues($selectedElmnts);
 										}
-										$cells[] = array($cellContent.$ath->renderSelect($extrafieldID, $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, $allowed, $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderSelect($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, $allowed, $attrs);
 									}
 									break;
 								case ARTIFACT_EXTRAFIELDTYPE_CHECKBOX:
@@ -287,14 +421,14 @@ class Widget_TrackerContent extends Widget {
 										} else {
 											$value = explode(',', $ath->getElementName($value));
 										}
-										$cells[] = array($cellContent.join(html_e('br'), $value), 'style' => 'vertical-align: top;');
+										$cellContent .= join(html_e('br'), $value);
 									} else {
 										$parent = $extrafieldObject->getParent();
 										if (!is_null($parent) && !empty($parent) && $parent != '100') {
 											$selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
 											$allowed = $aef->getAllowedValues($selectedElmnts);
 										}
-										$cells[] = array($cellContent.$ath->renderCheckbox($extrafieldID, $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), $allowed, $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderCheckbox($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), $allowed, $attrs);
 									}
 									break;
 								case ARTIFACT_EXTRAFIELDTYPE_RADIO:
@@ -304,14 +438,14 @@ class Widget_TrackerContent extends Widget {
 										} else {
 											$value = $ath->getElementName($value);
 										}
-										$cells[] = array($cellContent.$value, 'style' => 'vertical-align: top;');
+										$cellContent .= $value;
 									} else {
 										$parent = $extrafieldObject->getParent();
 										if (!is_null($parent) && !empty($parent) && $parent != '100') {
 											$selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
 											$allowed = $aef->getAllowedValues($selectedElmnts);
 										}
-										$cells[] = array($cellContent.$ath->renderRadio($extrafieldID, $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, $allowed, $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderRadio($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, $allowed, $attrs);
 									}
 									break;
 								case ARTIFACT_EXTRAFIELDTYPE_TEXT:
@@ -321,13 +455,13 @@ class Widget_TrackerContent extends Widget {
 										} else {
 											$value = ' ';
 										}
-										$cells[] = array($cellContent.$value, 'style' => 'vertical-align: top;');
+										$cellContent .= $value;
 									} else {
 										$attrs['style'] = 'box-sizing: border-box; width: 100%';
 										if ($extrafieldObject->getPattern()) {
 											$attrs['pattern'] = $extrafieldObject->getPattern();
 										}
-										$cells[] = array($cellContent.$ath->renderTextField($extrafieldID, $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderTextField($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
 									}
 									break;
 								case ARTIFACT_EXTRAFIELDTYPE_MULTISELECT:
@@ -337,14 +471,14 @@ class Widget_TrackerContent extends Widget {
 										} else {
 											$value = explode(',', $ath->getElementName($value));
 										}
-										$cells[] = array($cellContent.join(html_e('br'), $value), 'style' => 'vertical-align: top;');
+										$cellContent .= join(html_e('br'), $value);
 									} else {
 										$parent = $extrafieldObject->getParent();
 										if (!is_null($parent) && !empty($parent) && $parent != '100') {
 											$selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
 											$allowed = $aef->getAllowedValues($selectedElmnts);
 										}
-										$cells[] = array($cellContent.$ath->renderMultiSelectBox($extrafieldID, $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), $allowed, $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderMultiSelectBox($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), $allowed, $attrs);
 									}
 									break;
 								case ARTIFACT_EXTRAFIELDTYPE_TEXTAREA:
@@ -354,10 +488,10 @@ class Widget_TrackerContent extends Widget {
 										} else {
 											$value = ' ';
 										}
-										$cells[] = array($cellContent.$value, 'style' => 'vertical-align: top;');
+										$cellContent .= $value;
 									} else {
 										$attrs['style'] = 'box-sizing: border-box; width: 100%';
-										$cells[] = array($cellContent.$ath->renderTextArea($extrafieldID, $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderTextArea($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
 									}
 									break;
 								case ARTIFACT_EXTRAFIELDTYPE_STATUS:
@@ -367,37 +501,37 @@ class Widget_TrackerContent extends Widget {
 										} else {
 											$value = $ath->getElementName($value);
 										}
-										$cells[] = array($cellContent.$value, 'style' => 'vertical-align: top;');
+										$cellContent .= $value;
 									} else {
-										$atw = new ArtifactWorkflow($ath, $extrafieldID);
+										$atw = new ArtifactWorkflow($ath, $keys[0]);
 										// Special treatment for the initial step (Submit). In this case, the initial value is the first value.
 										if (!$value) {
 											$value = 100;
 										}
 										$allowed = $atw->getNextNodes($value);
 										$allowed[] = $value;
-										$cells[] = array($cellContent.$ath->renderSelect($extrafieldID, $value, false, $extrafieldObject->getShow100label(), false, false, $allowed, $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderSelect($keys[0], $value, false, $extrafieldObject->getShow100label(), false, false, $allowed, $attrs);
 									}
 									break;
 								//case ARTIFACT_EXTRAFIELDTYPE_ASSIGNEE:
 								case ARTIFACT_EXTRAFIELDTYPE_RELATION:
 									if ($readonly) {
 										$value = preg_replace_callback('/\b(\d+)\b/', create_function('$matches', 'return _artifactid2url($matches[1], \'title\');'), $value);
-										$cells[] = array($cellContent.$value, 'style' => 'vertical-align: top;');
+										$cellContent .= $value;
 									} else {
 										// specific rewrite of cellContent
 										$cellContent = '<div style="width:100%; line-height: 20px;">' .
 												'<div style="float:left;">'.html_e('strong', array(), $extrafieldObject->getName()._(':')).$mandatory.'</div>' .
-												'<div>' . $HTML->getEditFilePic(_('Click to edit'), _('Click to edit'), array('class' => 'mini_buttons tip-ne', 'onclick'=>"switch2edit(this, 'show$extrafieldID', 'edit$extrafieldID')")) . '</div>' .
+												'<div>' . $HTML->getEditFilePic(_('Click to edit'), _('Click to edit'), array('class' => 'mini_buttons tip-ne', 'onclick'=>"switch2edit(this, 'show$keys[0]', 'edit$keys[0]')")).'</div>'.
 												'</div>';
-										$cells[] = array($cellContent.$ath->renderRelationField($extrafieldID, $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderRelationField($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
 									}
 									break;
 								case ARTIFACT_EXTRAFIELDTYPE_INTEGER:
 									if ($readonly) {
-										$cells[] = array($cellContent.$value, 'style' => 'vertical-align: top;');
+										$cellContent .= $value;
 									} else {
-										$cells[] = array($cellContent.$ath->renderIntegerField($extrafieldID, $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderIntegerField($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
 									}
 									break;
 								/* reserved for aljeux extension, for merge into FusionForge */
@@ -406,9 +540,9 @@ class Widget_TrackerContent extends Widget {
 								/* reserved for Evolvis extension, for merge into FusionForge */
 								case ARTIFACT_EXTRAFIELDTYPE_DATETIME:
 									if ($readonly) {
-										$cells[] = array($cellContent.date('Y-m-d H:i', $value), 'style' => 'vertical-align: top;');
+										$cellContent .= date('Y-m-d H:i', $value);
 									} else {
-										$cells[] = array($cellContent.$ath->renderDatetime($extrafieldID, $value, $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderDatetime($keys[0], $value, $attrs);
 									}
 									break;
 								/* 12: reserved DATETIME*/
@@ -423,9 +557,9 @@ class Widget_TrackerContent extends Widget {
 											$user = user_get_object($value);
 											$value = $user->getRealName().' ('.html_e('samp', array(), util_make_link_u($user->getUnixname(),$value,$user->getUnixname())).')';
 										}
-										$cells[] = array($cellContent.$value, 'style' => 'vertical-align: top;');
+										$cellContent .= $value;
 									} else {
-										$cells[] = array($cellContent.$ath->renderUserField($extrafieldID, $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, false, $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderUserField($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, false, $attrs);
 									}
 									break;
 								/* 15: reserved MULTIUSER */
@@ -435,29 +569,27 @@ class Widget_TrackerContent extends Widget {
 											$releaseObj = frsrelease_get_object($value);
 											if (is_object($releaseObj)) {
 												$value = $releaseObj->FRSPackage->getName().' - '.$releaseObj->getName();
-												$cells[] = array($cellContent.$value, 'style' => 'vertical-align: top;');
+												$cellContent .= $value;
 											} else {
-												$cells[][] = ' ';
+												$cellContent .= ' ';
 											}
 										}
 									} else {
-										$cells[] = array($cellContent.$ath->renderReleaseField($extrafieldID, $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, false, $attrs), 'style' => 'vertical-align: top;');
+										$cellContent .= $ath->renderReleaseField($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, false, $attrs);
 									}
 									break;
 							}
+						} else {
+							$cellContent = '&nbsp';
 						}
+					} else {
+						$cellContent = ' ';
 					}
-					$numcol++;
-					if ($numcol > $maxcol) {
-						$maxcol = $numcol;
-					}
-				}
-				while (count($cells) < ($maxcol -1)) {
-					$cells[][] = ' ';
+					$cells[] = array($cellContent, 'width' => $extrafieldID[$keys[0]][0].'%', 'style' => 'vertical-align: top;');
 				}
-				$return .= $HTML->multiTableRow(array('class' => $HTML->boxGetAltRowStyle($i++, true)), $cells);
+				$return .= $HTML->multiTableRow(array('class' => $HTML->boxGetAltRowStyle($row_id, true)), $cells);
+				$return .= $HTML->listTableBottom();
 			}
-			$return .= $HTML->listTableBottom();
 			$return .= $ath->javascript();
 			$return .= init_datetimepicker();
 			if ($mandatoryDisplay) {
@@ -484,9 +616,8 @@ class Widget_TrackerContent extends Widget {
 
 	function getPreferences() {
 		return $this->getPartialPreferencesFormTitle($this->getTitle()).
-			$this->getPartialPreferencesFormColumns($this->getColumns()).
-			$this->getAvailableExtraFieldsForm($this->owner_id).
-			$this->getExtraFieldsForm($this->content_id);
+			$this->buildRenderWidget().
+			$this->getAvailableExtraFieldsForm($this->owner_id, true);
 	}
 
 	function getPreferencesForm($layout_id, $owner_id, $owner_type) {
@@ -502,46 +633,49 @@ class Widget_TrackerContent extends Widget {
 		$prefs .= $this->getPreferences();
 		$prefs .= html_e('br');
 		$prefs .= html_e('input', array('type' => 'submit', 'name' => 'cancel', 'value' => _('Cancel')));
-		$prefs .= html_e('input', array('type' => 'submit', 'value' => _('Submit')));
+		$prefs .= html_e('input', array('type' => 'submit', 'name' => 'trackercontent-submit', 'value' => _('Submit')));
 		$prefs .= html_ac(html_ap() - 1);
 		$prefs .= $HTML->closeForm();
 		return $prefs;
 	}
 
 	function updatePreferences(&$request) {
+		$sanitizer = new TextSanitizer();
 		$done = false;
 		$vContentId = new Valid_UInt('content_id');
 		$vContentId->required();
 		if ($request->valid($vContentId)) {
 			$vTitle = new Valid_String('title');
 			if($request->valid($vTitle)) {
-				$title = htmlspecialchars($request->get('title'));
+				$title = $sanitizer->SanitizeHtml($request->get('title'));
 			} else {
 				$title = '';
 			}
-			$vColumns = new Valid_String('columns');
-			if($request->valid($vColumns)) {
-				$columns = (int)$request->get('columns');
-			} else {
-				$columns = 1;
-			}
-
+			$content_id = (int)$request->get('content_id');
 			if ($title) {
 				$sql = "UPDATE artifact_display_widget SET title = $1 WHERE owner_id =$2 AND id = $3";
-				$res = db_query_params($sql,array($title, $this->owner_id, (int)$request->get('content_id')));
-				$done = true;
-			}
-			if ($columns) {
-				$sql = "UPDATE artifact_display_widget SET cols = $1 WHERE owner_id =$2 AND id = $3";
-				$res = db_query_params($sql,array($columns, $this->owner_id, (int)$request->get('content_id')));
+				$res = db_query_params($sql,array($title, $this->owner_id, $content_id));
 				$done = true;
 			}
-			$extrafieldIDs = getArrayFromRequest('extrafieldids');
-			$extrafieldIDColumns = getArrayFromRequest('extrafield_column_ids');
-			$extrafieldIDRows = getArrayFromRequest('extrafield_row_ids');
-			$res = db_query_params('DELETE FROM artifact_display_widget_field WHERE id = $1', array((int)$request->get('content_id')));
-			foreach ($extrafieldIDs as $key => $extrafieldID) {
-				db_query_params('INSERT INTO artifact_display_widget_field (id, field_id, column_id, row_id) VALUES ($1, $2, $3, $4)', array((int)$request->get('content_id'), $extrafieldID, $extrafieldIDColumns[$key], $extrafieldIDRows[$key]));
+			$trackerrows = getArrayFromRequest('trackercontent_layout');
+			$trackerextrafields = getArrayFromRequest('trackercontent_ef');
+			$trackercelltitles = getArrayFromRequest('trackercontent_title');
+			$res = db_query_params('DELETE FROM artifact_display_widget_field WHERE id = $1', array($content_id));
+			foreach ($trackerrows as $rowkey => $trackerrow) {
+				$columns = explode(',', $trackerrow);
+				$extrafields = explode(',', $trackerextrafields[$rowkey]);
+				$celltitle = explode(',', $trackercelltitles[$rowkey]);
+				$rowid = $rowkey;
+				foreach ($columns as $columnkey => $column) {
+					if ($extrafields[$columnkey] == "fake") {
+						$extrafieldid = 0;
+					} else {
+						$extrafieldid = substr($extrafields[$columnkey], 2); //remove prefix ef
+					}
+					$section = $sanitizer->SanitizeHtml($celltitle[$columnkey]);
+					db_query_params('INSERT INTO artifact_display_widget_field (id, field_id, column_id, row_id, width, section) VALUES ($1, $2, $3, $4, $5, $6)',
+							array($content_id, $extrafieldid, $columnkey, $rowid, $column, $section));
+				}
 				$done = true;
 			}
 		}
diff --git a/src/db/20161228-widget-artifact-display-2.sql b/src/db/20161228-widget-artifact-display-2.sql
new file mode 100644
index 0000000..99fb22d
--- /dev/null
+++ b/src/db/20161228-widget-artifact-display-2.sql
@@ -0,0 +1,4 @@
+ALTER TABLE artifact_display_widget DROP COLUMNS cols;
+ALTER TABLE artifact_display_widget_field ADD COLUMN width integer;
+ALTER TABLE artifact_display_widget_field ADD COLUMN section text;
+
diff --git a/src/www/themes/css/fusionforge.css b/src/www/themes/css/fusionforge.css
index 521eb40..87c3446 100644
--- a/src/www/themes/css/fusionforge.css
+++ b/src/www/themes/css/fusionforge.css
@@ -380,6 +380,12 @@ p.information {
 .widget_preferences form {
 	margin:0;
 }
+.widget_section_title {
+	padding: 2px;
+	font-variant: small-caps;
+	border-bottom: 1px solid #bcbcad;
+	margin-bottom: 4px;
+}
 .widget_titlebar {
 	font-weight: bold;
 	text-align: center;
@@ -699,9 +705,9 @@ div.layout-manager-column-remove_hover {
 	color:red;
 	cursor:pointer;
 }
-.layout-manager-column-width {
+/*.layout-manager-column-width {
 	padding-top:2.5em;
-}
+}*/
 
 .layout-manager-chooser {
 	vertical-align:top
@@ -713,6 +719,17 @@ div.layout-manager-column-remove_hover {
 	background:#f0f0f0;
 }
 
+div.ef-column-remove {
+	padding:0 0.5em 0.5em 0.5em;
+	font-size:0.8em;
+	color:#fff;
+	float:right;
+}
+div.ef-column-remove_hover {
+	color:red;
+	cursor:pointer;
+}
+
 /* }}} */
 
 #ffErrors {
diff --git a/src/www/widgets/widgets.php b/src/www/widgets/widgets.php
index 5731f0c..9768674 100644
--- a/src/www/widgets/widgets.php
+++ b/src/www/widgets/widgets.php
@@ -92,7 +92,7 @@ if (session_loggedin()) {
 					break;
 				case WidgetLayoutManager::OWNER_TYPE_TRACKER:
 					if ($at = artifactType_get_object($owner_id)) {
-
+						use_javascript('/widgets/scripts/WidgetController.js');
 						$_REQUEST['group_id'] = $_GET['group_id'] = $at->Group->getID();
 						$request->params['group_id'] = $at->Group->getID(); //bad!
 						$redirect = '/tracker/?group_id='. $at->Group->getID();

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=b65ca5d5bc66b7c9c2ec6635c2ae0472f3548114

commit b65ca5d5bc66b7c9c2ec6635c2ae0472f3548114
Author: Franck Villaume <franck.villaume at trivialdev.com>
Date:   Tue Dec 27 12:58:50 2016 +0100

    space vs. tab

diff --git a/src/common/widget/WidgetLayout_Row_Column.class.php b/src/common/widget/WidgetLayout_Row_Column.class.php
index 2d89bfd..7cd5134 100644
--- a/src/common/widget/WidgetLayout_Row_Column.class.php
+++ b/src/common/widget/WidgetLayout_Row_Column.class.php
@@ -38,7 +38,7 @@ class WidgetLayout_Row_Column {
 	function display($readonly, $owner_id, $owner_type, $is_last) {
 		echo html_ao('td', array('style' => 'height:10px; width:'. $this->width .'%; '. (!$is_last ? 'padding-right:20px;' : ''), 'id' => $this->getColumnId()));
 		foreach ($this->contents as $key => $nop) {
-		$this->contents[$key]['content']->display($this->row->layout->id, $this->id, $readonly, $this->contents[$key]['is_minimized'], $this->contents[$key]['display_preferences'], $owner_id, $owner_type);
+			$this->contents[$key]['content']->display($this->row->layout->id, $this->id, $readonly, $this->contents[$key]['is_minimized'], $this->contents[$key]['display_preferences'], $owner_id, $owner_type);
 		}
 		echo html_ac(html_ap() -1);
 	}

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=641b7bb0f9e7e198138078e250c9d5139818205a

commit 641b7bb0f9e7e198138078e250c9d5139818205a
Author: Franck Villaume <franck.villaume at trivialdev.com>
Date:   Tue Dec 27 12:58:10 2016 +0100

    space vs. tab

diff --git a/src/common/widget/WidgetLayout_Row_Column.class.php b/src/common/widget/WidgetLayout_Row_Column.class.php
index ab487e8..2d89bfd 100644
--- a/src/common/widget/WidgetLayout_Row_Column.class.php
+++ b/src/common/widget/WidgetLayout_Row_Column.class.php
@@ -20,29 +20,29 @@
  */
 
 class WidgetLayout_Row_Column {
-    var $id;
-    var $width;
-    var $contents;
-    var $row;
-    function WidgetLayout_Row_Column($id, $width) {
-        $this->id       = $id;
-        $this->width    = $width;
-        $this->contents = array();
-    }
-    function setRow(&$row) {
-        $this->row =& $row;
-    }
-    function add(&$c, $is_minimized, $display_preferences) {
-        $this->contents[] = array('content' => &$c, 'is_minimized' => $is_minimized, 'display_preferences' => $display_preferences);
-    }
-    function display($readonly, $owner_id, $owner_type, $is_last) {
-        echo html_ao('td', array('style' => 'height:10px; width:'. $this->width .'%; '. (!$is_last ? 'padding-right:20px;' : ''), 'id' => $this->getColumnId()));
-        foreach ($this->contents as $key => $nop) {
-            $this->contents[$key]['content']->display($this->row->layout->id, $this->id, $readonly, $this->contents[$key]['is_minimized'], $this->contents[$key]['display_preferences'], $owner_id, $owner_type);
-        }
-        echo html_ac(html_ap() -1);
-    }
-    function getColumnId() {
-        return 'widgetlayout_col_'. $this->id;
-    }
+	var $id;
+	var $width;
+	var $contents;
+	var $row;
+	function WidgetLayout_Row_Column($id, $width) {
+		$this->id       = $id;
+		$this->width    = $width;
+		$this->contents = array();
+	}
+	function setRow(&$row) {
+		$this->row =& $row;
+	}
+	function add(&$c, $is_minimized, $display_preferences) {
+		$this->contents[] = array('content' => &$c, 'is_minimized' => $is_minimized, 'display_preferences' => $display_preferences);
+	}
+	function display($readonly, $owner_id, $owner_type, $is_last) {
+		echo html_ao('td', array('style' => 'height:10px; width:'. $this->width .'%; '. (!$is_last ? 'padding-right:20px;' : ''), 'id' => $this->getColumnId()));
+		foreach ($this->contents as $key => $nop) {
+		$this->contents[$key]['content']->display($this->row->layout->id, $this->id, $readonly, $this->contents[$key]['is_minimized'], $this->contents[$key]['display_preferences'], $owner_id, $owner_type);
+		}
+		echo html_ac(html_ap() -1);
+	}
+	function getColumnId() {
+		return 'widgetlayout_col_'. $this->id;
+	}
 }

-----------------------------------------------------------------------

Summary of changes:
 .../tracker/actions/widget_artifact_display.php    |   1 +
 src/common/widget/WidgetLayoutManager.class.php    |   3 +-
 .../widget/WidgetLayout_Row_Column.class.php       |  50 +--
 src/common/widget/Widget_TrackerContent.class.php  | 406 ++++++++++++++-------
 src/db/20161228-widget-artifact-display-2.sql      |   4 +
 src/www/themes/css/fusionforge.css                 |  21 +-
 src/www/widgets/widgets.php                        |   2 +-
 7 files changed, 321 insertions(+), 166 deletions(-)
 create mode 100644 src/db/20161228-widget-artifact-display-2.sql


hooks/post-receive
-- 
FusionForge



More information about the Fusionforge-commits mailing list