3 * Generic Tracker Content Widget Class
5 * Copyright 2016-2018, Franck Villaume - TrivialDev
6 * Copyright 2017, Stephane-Eymeric Bredthauer - TrivialDev
7 * http://fusionforge.org
9 * This file is a part of Fusionforge.
11 * Fusionforge is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * Fusionforge is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with Fusionforge. If not, see <http://www.gnu.org/licenses/>.
25 require_once 'Widget.class.php';
26 require_once $gfwww.'include/jquery_plugins.php';
28 class Widget_TrackerContent extends Widget {
29 var $trackercontent_title;
30 var $layoutExtraFieldIDs;
32 function __construct() {
33 $request =& HTTPRequest::instance();
34 $owner_id = (int)substr($request->get('owner'), 1);
36 $owner_id = (int)$request->get('atid');
38 parent::__construct('trackercontent', $owner_id, WidgetLayoutManager::OWNER_TYPE_TRACKER);
39 $this->setOwner($owner_id, WidgetLayoutManager::OWNER_TYPE_TRACKER);
43 $hp = Codendi_HTMLPurifier::instance();
44 return $this->trackercontent_title ? $hp->purify($this->trackercontent_title, CODENDI_PURIFIER_CONVERT_HTML) : _('Tracker Content Box');
51 function isAvailable() {
55 function getDescription() {
56 return _('Create an empty widget to link fields together and then organize the artifact display view (update & submit new).');
59 function loadContent($id) {
60 $this->content_id = $id;
61 $this->fetchData($id);
64 function fetchData($id) {
65 $res = db_query_params('SELECT title FROM artifact_display_widget WHERE id = $1', array($id));
67 $title = db_result($res, 0, 'title');
69 $this->trackercontent_title = $title;
70 $this->layoutExtraFieldIDs = $this->getLayoutExtraFieldIDs($id);
73 function create(&$request) {
74 $sanitizer = new TextSanitizer();
75 $hp = Codendi_HTMLPurifier::instance();
76 $this->trackercontent_title = $hp->purify($request->get('title'), CODENDI_PURIFIER_CONVERT_HTML);
77 $trackerrows = getArrayFromRequest('trackercontent_layout');
78 $trackerextrafields = getArrayFromRequest('trackercontent_ef');
79 $trackercelltitles = getArrayFromRequest('trackercontent_title');
80 $res = db_query_params('INSERT INTO artifact_display_widget (owner_id, title) VALUES ($1, $2)', array($this->owner_id, $this->trackercontent_title));
81 $content_id = db_insertid($res, 'artifact_display_widget', 'id');
82 foreach ($trackerrows as $rowkey => $trackerrow) {
83 $columns = explode(',', $trackerrow);
84 $extrafields = explode(',', $trackerextrafields[$rowkey]);
85 $celltitle = explode(',', $trackercelltitles[$rowkey]);
87 foreach ($columns as $columnkey => $column) {
88 if ($extrafields[$columnkey] == "fake") {
91 $extrafieldid = substr($extrafields[$columnkey], 2); //remove prefix ef
93 $section = $sanitizer->SanitizeHtml($celltitle[$columnkey]);
94 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)',
95 array($content_id, $extrafieldid, $columnkey, $rowid, $column, $section));
101 function destroy($id) {
102 db_query_params('DELETE FROM artifact_display_widget WHERE id = $1 AND owner_id = $2',array($id, $this->owner_id));
103 db_query_params('DELETE FROM artifact_display_widget_field WHERE id = $1', array($id));
106 private function getPartialPreferencesFormTitle($title) {
107 return html_e('p', array(), _('Title')._(':').html_e('input', array('type' => 'text', 'name' => 'title', 'size' => 30, 'value' => htmlspecialchars($title))));
110 private function buildRenderWidget() {
113 $content = html_e('p', array(), _('Build your layout and drag & drop customfields in cells')._(':'));
114 $content .= $HTML->listTableTop(array(), array(), '', 'layout-manager').
117 .html_e('div', array('class' => 'layout-manager-row-add'), '+');
119 if (count($this->layoutExtraFieldIDs) > 0) {
120 foreach ($this->layoutExtraFieldIDs as $row_id => $column_id) {
122 $content .= '<table class="layout-manager-row" id="widget_layout_build">
124 <td class="layout-manager-column-add">+</td>';
125 foreach ($column_id as $extrafieldID) {
126 $keys = array_keys($extrafieldID);
128 $extrafieldObject = new ArtifactExtraField($ath, $keys[0]);
129 $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>');
131 $divEF = '<div id="fake" class="wb_extrafield" style="display: none"></div>';
134 $content .= '<td class="layout-manager-column" width="'.$extrafieldID[$keys[0]][0].'%">
135 <div class="layout-manager-column-remove">x</div>
136 <div class="layout-manager-column-width">
137 '._('Section Title')._(':').'<br />
138 <input type="text" value="'.htmlspecialchars($extrafieldID[$keys[0]][1]).'" size="20" maxlength="20" /><br />
139 <input type="number" value="'.$extrafieldID[$keys[0]][0].'" autocomplete="off" size="1" maxlength="3" />%
142 $content .= '</td><td class="layout-manager-column-add">+</td>';
144 $content .= '</tr></table>';
145 $content .= html_e('div', array('class' => 'layout-manager-row-add'), '+');
148 $content .= '<table class="layout-manager-row" id="widget_layout_build">
150 <td class="layout-manager-column-add">+</td>';
151 $content .= '<td class="layout-manager-column">
152 <div class="layout-manager-column-remove">x</div>
153 <div class="layout-manager-column-width">
154 '._('Section Title')._(':').'<br />
155 <input type="text" value="" size="20" maxlength="20" /><br />
156 <input type="number" value="50" autocomplete="off" size="1" maxlength="3" />%
158 <div id="fake" class="wb_extrafield" style="display: none"></div>
160 <td class="layout-manager-column-add">+</td>';
161 $content .= '<td class="layout-manager-column">
162 <div class="layout-manager-column-remove">x</div>
163 <div class="layout-manager-column-width">
164 '._('Section Title')._(':').'<br />
165 <input type="text" value="" size="20" maxlength="20" /><br />
166 <input type="number" value="50" autocomplete="off" size="1" maxlength="3" />%
168 <div id="fake" class="wb_extrafield" style="display: none"></div>
170 <td class="layout-manager-column-add">+</td>
172 $content .= html_e('div', array('class' => 'layout-manager-row-add'), '+');
176 $HTML->listTableBottom();
177 $jsvariable = "var sectiontitle = '"._("Section Title")._(":")."';";
178 $javascript = <<<'EOS'
179 var controllerWidgetBuilder;
180 jQuery(document).ready(function() {
181 controllerWidgetBuilder = new WidgetBuilderController({
182 buttonAddRow: jQuery('.layout-manager-row-add'),
183 buttonAddColumn: jQuery('.layout-manager-column-add'),
184 buttonRemoveColumn: jQuery('.layout-manager-column-remove'),
185 buttonRemoveEF: jQuery('.ef-widget-remove'),
186 labelTitle: sectiontitle
188 jQuery('.layout-manager-column').droppable({
189 accept: '#extrafield_table .wb_extrafield',
190 drop: function(event, ui) {
191 ui.draggable.appendTo(this).css('position', '');
192 ui.draggable.parent().droppable('destroy');
193 ui.draggable.parent().find('#fake').remove();
194 ui.draggable.find('#x'+ui.draggable.attr('id')).show()},
195 over: function(event, ui) {
196 ui.helper.css('z-index', 1);
199 if (jQuery("[name='name[trackercontent][add]']") != 'undefined') {
200 jQuery("[name='name[trackercontent][add]']").click(function(){
201 var form = jQuery(this).parents('form').first();
202 form.find('.layout-manager-row').each(function(i, e) {
205 name: 'trackercontent_layout[]',
206 value: jQuery(e).find('.layout-manager-column input[type=number]').map(function(){ return this.value;}).get().join(',')
210 name: 'trackercontent_ef[]',
211 value: jQuery(e).find('.layout-manager-column > .wb_extrafield').map(function(){ return this.id;}).get().join(',')
215 name: 'trackercontent_title[]',
216 value: jQuery(e).find('.layout-manager-column input[type=text]').map(function(){ return this.value;}).get().join(',')
221 if (jQuery("[name='trackercontent-submit']") != 'undefined') {
222 jQuery("[name='trackercontent-submit']").click(function(){
223 var form = jQuery(this).parents('form').first();
224 form.find('.layout-manager-row').each(function(i, e) {
227 name: 'trackercontent_layout[]',
228 value: jQuery(e).find('.layout-manager-column input[type=number]').map(function(){ return this.value;}).get().join(',')
232 name: 'trackercontent_ef[]',
233 value: jQuery(e).find('.layout-manager-column > .wb_extrafield').map(function(){ return this.id;}).get().join(',')
237 name: 'trackercontent_title[]',
238 value: jQuery(e).find('.layout-manager-column input[type=text]').map(function(){ return this.value;}).get().join(',')
245 $content .= html_e('script', array( 'type'=>'text/javascript'), '//<![CDATA['."\n".'jQuery(function(){'.$jsvariable."\n".$javascript.'});'."\n".'//]]>');
249 private function getAvailableExtraFieldsForm($owner_id, $preference = false) {
252 $artifactTypeObject = artifactType_get_object($atid);
253 $availableExtraFields = $artifactTypeObject->getExtraFields();
254 $stillAvailableExtraFields = $this->availableExtrafields($owner_id, $availableExtraFields);
257 $arr = $this->getExtraFieldIDs($owner_id);
259 if (count($stillAvailableExtraFields) > 0 || count($arr) > 0) {
260 $content = html_e('p', array(), sprintf(_('Drag & drop into your layout the available custom fields from %s to display into this widget'), $artifactTypeObject->getName())._(':'));
261 $content .= $HTML->listTableTop(array(), array(), 'full', 'extrafield_table');
263 if (count($stillAvailableExtraFields) > 0) {
265 for ($i = 0; count($stillAvailableExtraFields) > $i; $i++) {
266 $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%');
268 $content .= $HTML->multiTableRow(array(), $cells);
273 $content .= $HTML->multiTableRow(array(), $cells);
276 if (count($arr) > 0) {
278 for ($i = 0; count($arr) > $i; $i++) {
279 $cells[] = array('', 'id' => 'tdef'.$arr[$i], 'width' => '50%');
281 $content .= $HTML->multiTableRow(array(), $cells);
286 $content .= $HTML->multiTableRow(array(), $cells);
289 if (count($stillAvailableExtraFields) > 0 || count($arr) > 0) {
290 $content .= $HTML->listTableBottom();
291 $javascript = <<<'EOS'
292 jQuery(document).ready(function() {
293 var wb_extrafield_start;
294 jQuery('.wb_extrafield', '#extrafield_table').draggable({
300 $content .= html_e('script', array( 'type'=>'text/javascript'), '//<![CDATA['."\n".'jQuery(function(){'.$javascript.'});'."\n".'//]]>');
303 if (!isset($content)) {
304 $content = $HTML->information(_('No customfields available to link to a widget'));
309 private function availableExtrafields($owner_id, $extrafields) {
310 $arr = $this->getExtraFieldIDs($owner_id);
311 $availableExtrafields = array();
312 foreach ($extrafields as $extrafield) {
313 if (($extrafield[3] != ARTIFACT_EXTRAFIELDTYPE_PARENT) && !in_array($extrafield[0], $arr)) {
314 $availableExtrafields[] = $extrafield;
317 return $availableExtrafields;
320 private function getExtraFieldIDs($id) {
321 $res = db_query_params('select field_id from artifact_display_widget_field, artifact_display_widget
322 where artifact_display_widget_field.id = artifact_display_widget.id and artifact_display_widget.owner_id = $1', array($id));
323 $extrafieldIDs = array();
325 $extrafieldIDs = util_result_column_to_array($res, 0);
327 return $extrafieldIDs;
330 private function getLayoutExtraFieldIDs($id) {
331 $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));
332 $extrafieldIDs = array();
333 if ($res && (db_numrows($res) > 0)) {
334 while ($arr = db_fetch_array($res)) {
335 // row_id is unique, column_id is unique per row, field_id is unique, width is not unique, section is not unique
336 $extrafieldIDs[$arr[0]][$arr[1]][$arr[2]] = array($arr[3], $arr[4]);
339 return $extrafieldIDs;
342 function getInstallPreferences() {
343 $request =& HTTPRequest::instance();
344 $owner_id = (int)substr($request->get('owner'), 1);
345 $content = $this->getPartialPreferencesFormTitle(_('Enter title of Tracker Content Box'));
346 $content .= $this->buildRenderWidget();
347 $content .= $this->getAvailableExtraFieldsForm($owner_id);
351 function getContent() {
361 //manage redirect in case of missing required fields
362 global $extra_fields;
366 if (count($this->layoutExtraFieldIDs) > 0) {
367 $mandatoryDisplay = false;
369 if (is_object($ah)) {
370 $selected = $ah->getExtraFieldData();
371 $efInFormula = $ath->getExtraFieldsInFormula();
372 $efWithFormula = $ath->getExtraFieldsWithFormula();
373 } elseif ($func == 'add') {
374 $selected = $ath->getExtraFieldsDefaultValue();
375 $efInFormula = $ath->getExtraFieldsInFormula(array(), false, false);
376 $efWithFormula = $ath->getExtraFieldsWithFormula(array(), false, false);
378 if (!forge_check_perm('tracker', $atid, 'submit') || ($func == 'detail' && !session_loggedin())) {
381 foreach ($this->layoutExtraFieldIDs as $row_id => $column_id) {
382 $return .= $HTML->listTableTop();
384 foreach ($column_id as $extrafieldID) {
385 $keys = array_keys($extrafieldID);
388 if (strlen($extrafieldID[$keys[0]][1]) > 0) {
389 $cellContent .= html_e('div', array('class' => 'widget_section_title'), htmlspecialchars($extrafieldID[$keys[0]][1]));
391 $extrafieldObject = new ArtifactExtraField($ath, $keys[0]);
392 if ($func == 'add') {
393 $display = !(int)$extrafieldObject->isHiddenOnSubmit();
400 if (isset($selected[$keys[0]])) {
401 $value = $selected[$keys[0]];
402 } elseif (isset($extra_fields[$keys[0]])) {
403 $value = $extra_fields[$keys[0]];
405 $attrs = array('form' => 'trackerform');
407 if ($extrafieldObject->isRequired() && !$readonly) {
408 $mandatory = utils_requiredField();
409 $mandatoryDisplay = true;
410 $attrs['required'] = 'required';
412 if (strlen($extrafieldObject->getDescription()) > 0) {
413 $attrs['title'] = $extrafieldObject->getDescription();
415 if (in_array($extrafieldObject->getID(), $efInFormula)) {
416 $attrs['class'] = (empty($attrs['class']) ? '' : $attrs['class'].' ').'in-formula';
418 if (in_array($extrafieldObject->getID(), $efWithFormula)) {
419 $attrs['class'] = (empty($attrs['class']) ? '' : $attrs['class'].' ').'with-formula readonly';
420 $attrs['readonly'] = 'readonly';
422 $cellContent .= html_e('strong', array(), $extrafieldObject->getName()._(':')).$mandatory.html_e('br');
423 switch ($extrafieldObject->getType()) {
424 case ARTIFACT_EXTRAFIELDTYPE_SELECT:
427 $value = $extrafieldObject->getShow100label();
429 $value = $ath->getElementName($value);
431 $cellContent .= $value;
433 $parent = $extrafieldObject->getParent();
434 if (!is_null($parent) && !empty($parent) && $parent != '100') {
435 $selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
436 $allowed = $extrafieldObject->getAllowedValues($selectedElmnts);
438 $cellContent .= $ath->renderSelect($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, $allowed, $attrs);
441 case ARTIFACT_EXTRAFIELDTYPE_CHECKBOX:
444 $value = $extrafieldObject->getShow100label();
446 $value = explode(',', $ath->getElementName($value));
448 $cellContent .= join(html_e('br'), $value);
450 $parent = $extrafieldObject->getParent();
451 if (!is_null($parent) && !empty($parent) && $parent != '100') {
452 $selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
453 $allowed = $extrafieldObject->getAllowedValues($selectedElmnts);
455 $cellContent .= $ath->renderCheckbox($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), $allowed, $attrs);
458 case ARTIFACT_EXTRAFIELDTYPE_RADIO:
461 $value = $extrafieldObject->getShow100label();
463 $value = $ath->getElementName($value);
465 $cellContent .= $value;
467 $parent = $extrafieldObject->getParent();
468 if (!is_null($parent) && !empty($parent) && $parent != '100') {
469 $selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
470 $allowed = $extrafieldObject->getAllowedValues($selectedElmnts);
472 $cellContent .= $ath->renderRadio($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, $allowed, $attrs);
475 case ARTIFACT_EXTRAFIELDTYPE_TEXT:
477 if (strlen($value) > 0) {
478 $value = preg_replace('/((http|https|ftp):\/\/\S+)/', "<a href=\"\\1\" target=\"_blank\">\\1</a>", $value);
482 $cellContent .= $value;
484 $attrs['style'] = 'box-sizing: border-box; width: 100%';
485 if ($extrafieldObject->getPattern()) {
486 $attrs['pattern'] = $extrafieldObject->getPattern();
488 $cellContent .= $ath->renderTextField($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
491 case ARTIFACT_EXTRAFIELDTYPE_MULTISELECT:
494 $value = $extrafieldObject->getShow100label();
496 $value = explode(',', $ath->getElementName($value));
498 $cellContent .= join(html_e('br'), $value);
500 $parent = $extrafieldObject->getParent();
501 if (!is_null($parent) && !empty($parent) && $parent != '100') {
502 $selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
503 $allowed = $extrafieldObject->getAllowedValues($selectedElmnts);
505 $cellContent .= $ath->renderMultiSelectBox($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), $allowed, $attrs);
508 case ARTIFACT_EXTRAFIELDTYPE_TEXTAREA:
510 if (strlen($value) > 0) {
511 $value = preg_replace('/((http|https|ftp):\/\/\S+)/', "<a href=\"\\1\" target=\"_blank\">\\1</a>", $value);
515 $cellContent .= $value;
517 $attrs['style'] = 'box-sizing: border-box; width: 100%';
518 $cellContent .= $ath->renderTextArea($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
521 case ARTIFACT_EXTRAFIELDTYPE_STATUS:
524 $value = $extrafieldObject->getShow100label();
526 $value = $ath->getElementName($value);
528 $cellContent .= $value;
530 // parent artifact can't be close if a child is still open
531 if ( $func != "add" &&
532 $extrafieldObject->getAggregationRule() == ARTIFACT_EXTRAFIELD_AGGREGATION_RULE_STATUS_CLOSE_RESTRICTED &&
533 $ah->hasChildren()) {
534 $children = $ah->getChildren();
536 foreach ($children as $child) {
537 if ($child['status_id'] == 1) {
543 $extrafieldObject = new ArtifactExtraField($ath, $keys[0]);
544 //$extrafieldObject = new ArtifactExtraField($this, $efarr[$i]['extra_field_id']);
545 $statusArr = $extrafieldObject->getAvailableValues();
546 $openStatus = array();
547 foreach ($statusArr as $status) {
548 if ($child['status_id'] == 1) {
549 $openStatus[] = $status['element_id'];
553 $allowed = array_intersect($allowed, $openStatus);
555 $allowed = $openStatus;
559 $atw = new ArtifactWorkflow($ath, $keys[0]);
560 // Special treatment for the initial step (Submit). In this case, the initial value is the first value.
564 $allowedWF = $atw->getNextNodes($value);
566 $allowed = array_intersect($allowed, $allowedWF);
568 $allowed = $allowedWF;
571 $cellContent .= $ath->renderSelect($keys[0], $value, false, $extrafieldObject->getShow100label(), false, false, $allowed, $attrs);
574 //case ARTIFACT_EXTRAFIELDTYPE_ASSIGNEE:
575 case ARTIFACT_EXTRAFIELDTYPE_RELATION:
577 $value = preg_replace_callback('/\b(\d+)\b/', create_function('$matches', 'return _artifactid2url($matches[1], \'title\');'), $value);
578 $cellContent .= $value;
580 // specific rewrite of cellContent
581 $cellContent = '<div style="width:100%; line-height: 20px;">' .
582 '<div style="float:left;">'.html_e('strong', array(), $extrafieldObject->getName()._(':')).$mandatory.'</div>' .
583 '<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>'.
585 $cellContent .= $ath->renderRelationField($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
588 case ARTIFACT_EXTRAFIELDTYPE_PARENT:
590 $value = preg_replace_callback('/\b(\d+)\b/', create_function('$matches', 'return _artifactid2url($matches[1], \'title\');'), $value);
591 $cellContent .= $value;
593 // specific rewrite of cellContent
594 $cellContent = '<div style="width:100%; line-height: 20px;">' .
595 '<div style="float:left;">'.html_e('strong', array(), $extrafieldObject->getName()._(':')).$mandatory.'</div>' .
596 '<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>'.
598 $cellContent .= $ath->renderParentField($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
601 case ARTIFACT_EXTRAFIELDTYPE_INTEGER:
603 $cellContent .= $value;
605 $cellContent .= $ath->renderIntegerField($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
608 /* reserved for aljeux extension, for merge into FusionForge */
609 case ARTIFACT_EXTRAFIELDTYPE_FORMULA:
611 case ARTIFACT_EXTRAFIELDTYPE_DATETIME:
614 $cellContent .= date('Y-m-d H:i', $value);
616 $cellContent .= _('None');
619 $cellContent .= $ath->renderDatetime($keys[0], $value, $attrs);
622 case ARTIFACT_EXTRAFIELDTYPE_SLA:
625 $cellContent .= $ath->renderSLAField($keys[0], $value, $attrs);
628 case ARTIFACT_EXTRAFIELDTYPE_USER:
633 $user = user_get_object($value);
634 $value = $user->getRealName().' ('.html_e('samp', array(), util_make_link_u($user->getUnixname(),$value,$user->getUnixname())).')';
636 $cellContent .= $value;
638 $cellContent .= $ath->renderUserField($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, false, $attrs);
641 /* 15: reserved MULTIUSER */
642 case ARTIFACT_EXTRAFIELDTYPE_RELEASE:
645 $releaseObj = frsrelease_get_object($value);
646 if (is_object($releaseObj)) {
647 $value = $releaseObj->FRSPackage->getName().' - '.$releaseObj->getName();
648 $cellContent .= $value;
650 $cellContent .= ' ';
654 $cellContent .= $ath->renderReleaseField($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, false, $attrs);
657 case ARTIFACT_EXTRAFIELDTYPE_EFFORT:
660 $effortUnitSet = New EffortUnitSet($ath, $ath->getEffortUnitSet());
661 $effortUnitFactory = New EffortUnitFactory($effortUnitSet);
662 $cellContent .= $effortUnitFactory->encodedToString($value);
664 $cellContent .= _('None');
667 $cellContent .= $ath->renderEffort($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
672 if ($extrafieldObject->isRequired()) {
673 switch ($extrafieldObject->getType()) {
674 case ARTIFACT_EXTRAFIELDTYPE_MULTISELECT:
675 $defaultValues = $extrafieldObject->getDefaultValues();
676 foreach ($defaultValues as $defaultValue) {
677 $cellContent .= html_e('input', array('type' => 'hidden', 'value' => $defaultValue, 'name' => 'extra_fields['.$extrafieldObject->getID().'][]', 'form' => 'trackerform'));
681 $cellContent .= html_e('input', array('type' => 'hidden', 'value' => $extrafieldObject->getDefaultValues(), 'name' => 'extra_fields['.$extrafieldObject->getID().']', 'form' => 'trackerform'));
684 $cellContent .= ' ';
688 $cellContent = ' ';
690 $cells[] = array($cellContent, 'style' => 'vertical-align: top; width: '.$extrafieldID[$keys[0]][0].'%');
692 $return .= $HTML->multiTableRow(array(), $cells);
693 $return .= $HTML->listTableBottom();
695 $return .= $ath->javascript();
696 $return .= init_datetimepicker();
697 if ($mandatoryDisplay) {
698 $return .= $HTML->addRequiredFieldsInfoBox();
702 $return .= html_e('p', array('class' => 'middleRight'), html_e('input', array('form' => 'trackerform', 'type' => 'submit', 'name' => 'submit', 'value' => _('Save Changes'), 'title' => _('Save is validating the complete form'), 'onClick' => 'iefixform()')));
707 function getCategory() {
708 return _('Trackers');
711 function canBeMinize() {
715 function hasPreferences() {
719 function getPreferences() {
720 return $this->getPartialPreferencesFormTitle($this->getTitle()).
721 $this->buildRenderWidget().
722 $this->getAvailableExtraFieldsForm($this->owner_id, true);
725 function getPreferencesForm($layout_id, $owner_id, $owner_type) {
729 $url = '/widgets/widget.php?owner='.$owner_type.$owner_id.'&action=update&name['.$this->id.']='.$this->getInstanceId().'&content_id='.$this->getInstanceId().'&layout_id='.$layout_id.'&func='.$func;
731 $url .= '&aid='.$aid;
733 $prefs = $HTML->openForm(array('method' => 'post', 'action' => $url));
734 $prefs .= html_ao('fieldset').html_e('legend', array(), _('Preferences'));
735 $prefs .= $this->getPreferences();
736 $prefs .= html_e('br');
737 $prefs .= html_e('input', array('type' => 'submit', 'name' => 'cancel', 'value' => _('Cancel')));
738 $prefs .= html_e('input', array('type' => 'submit', 'name' => 'trackercontent-submit', 'value' => _('Submit')));
739 $prefs .= html_ac(html_ap() - 1);
740 $prefs .= $HTML->closeForm();
744 function updatePreferences(&$request) {
745 $sanitizer = new TextSanitizer();
747 $vContentId = new Valid_UInt('content_id');
748 $vContentId->required();
749 if ($request->valid($vContentId)) {
750 $vTitle = new Valid_String('title');
751 if($request->valid($vTitle)) {
752 $title = $sanitizer->SanitizeHtml($request->get('title'));
756 $content_id = (int)$request->get('content_id');
758 $sql = "UPDATE artifact_display_widget SET title = $1 WHERE owner_id =$2 AND id = $3";
759 db_query_params($sql,array($title, $this->owner_id, $content_id));
762 $trackerrows = getArrayFromRequest('trackercontent_layout');
763 $trackerextrafields = getArrayFromRequest('trackercontent_ef');
764 $trackercelltitles = getArrayFromRequest('trackercontent_title');
765 db_query_params('DELETE FROM artifact_display_widget_field WHERE id = $1', array($content_id));
766 foreach ($trackerrows as $rowkey => $trackerrow) {
767 $columns = explode(',', $trackerrow);
768 $extrafields = explode(',', $trackerextrafields[$rowkey]);
769 $celltitle = explode(',', $trackercelltitles[$rowkey]);
771 foreach ($columns as $columnkey => $column) {
772 if ($extrafields[$columnkey] == "fake") {
775 $extrafieldid = substr($extrafields[$columnkey], 2); //remove prefix ef
777 $section = $sanitizer->SanitizeHtml($celltitle[$columnkey]);
778 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)',
779 array($content_id, $extrafieldid, $columnkey, $rowid, $column, $section));