3 * Generic Tracker Content Widget Class
5 * Copyright 2016-2018,2021 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 = array();
32 function __construct() {
33 $owner_id = (int)substr(getStringFromRequest('owner'), 1);
35 $owner_id = getIntFromRequest('atid');
37 parent::__construct('trackercontent', $owner_id, WidgetLayoutManager::OWNER_TYPE_TRACKER);
38 $this->setOwner($owner_id, WidgetLayoutManager::OWNER_TYPE_TRACKER);
42 $hp = Codendi_HTMLPurifier::instance();
43 return $this->trackercontent_title ? $hp->purify($this->trackercontent_title, CODENDI_PURIFIER_CONVERT_HTML) : _('Tracker Content Box');
50 function isAvailable() {
54 function getDescription() {
55 return _('Create an empty widget to link fields together and then organize the artifact display view (update & submit new).');
58 function loadContent($id) {
59 $this->content_id = $id;
60 $this->fetchData($id);
63 function fetchData($id) {
64 $res = db_query_params('SELECT title FROM artifact_display_widget WHERE id = $1', array($id));
66 $title = db_result($res, 0, 'title');
68 $this->trackercontent_title = $title;
69 $this->layoutExtraFieldIDs = $this->getLayoutExtraFieldIDs($id);
73 $sanitizer = new TextSanitizer();
74 $hp = Codendi_HTMLPurifier::instance();
75 $this->trackercontent_title = $hp->purify(getStringFromRequest('title'), CODENDI_PURIFIER_CONVERT_HTML);
76 $trackerrows = getArrayFromRequest('trackercontent_layout');
77 $trackerextrafields = getArrayFromRequest('trackercontent_ef');
78 $trackercelltitles = getArrayFromRequest('trackercontent_title');
79 $res = db_query_params('INSERT INTO artifact_display_widget (owner_id, title) VALUES ($1, $2)', array($this->owner_id, $this->trackercontent_title));
80 $content_id = db_insertid($res, 'artifact_display_widget', 'id');
81 foreach ($trackerrows as $rowkey => $trackerrow) {
82 $columns = explode(',', $trackerrow);
83 $extrafields = explode(',', $trackerextrafields[$rowkey]);
84 $celltitle = explode(',', $trackercelltitles[$rowkey]);
86 foreach ($columns as $columnkey => $column) {
87 if ($extrafields[$columnkey] == "fake") {
90 $extrafieldid = substr($extrafields[$columnkey], 2); //remove prefix ef
92 $section = $sanitizer->SanitizeHtml($celltitle[$columnkey]);
93 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)',
94 array($content_id, $extrafieldid, $columnkey, $rowid, $column, $section));
100 function destroy($id) {
101 db_query_params('DELETE FROM artifact_display_widget WHERE id = $1 AND owner_id = $2',array($id, $this->owner_id));
102 db_query_params('DELETE FROM artifact_display_widget_field WHERE id = $1', array($id));
105 private function getPartialPreferencesFormTitle($title) {
106 return html_e('p', array(), _('Title')._(':').html_e('input', array('type' => 'text', 'name' => 'title', 'size' => 30, 'value' => htmlspecialchars($title))));
109 private function buildRenderWidget() {
112 $content = html_e('p', array(), _('Build your layout and drag & drop customfields in cells')._(':'));
113 $content .= $HTML->listTableTop(array(), array(), '', 'layout-manager').
116 .html_e('div', array('class' => 'layout-manager-row-add'), '+');
118 if (count($this->layoutExtraFieldIDs) > 0) {
119 foreach ($this->layoutExtraFieldIDs as $column_id) {
120 $content .= '<table class="layout-manager-row" id="widget_layout_build">
122 <td class="layout-manager-column-add">+</td>';
123 foreach ($column_id as $extrafieldID) {
124 $keys = array_keys($extrafieldID);
126 $extrafieldObject = new ArtifactExtraField($ath, $keys[0]);
127 $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>');
129 $divEF = '<div id="fake" class="wb_extrafield" style="display: none"></div>';
132 $content .= '<td class="layout-manager-column" width="'.$extrafieldID[$keys[0]][0].'%">
133 <div class="layout-manager-column-remove">x</div>
134 <div class="layout-manager-column-width">
135 '._('Section Title')._(':').'<br />
136 <input type="text" value="'.htmlspecialchars($extrafieldID[$keys[0]][1]).'" size="20" maxlength="20" /><br />
137 <input type="number" value="'.$extrafieldID[$keys[0]][0].'" autocomplete="off" size="1" maxlength="3" />%
140 $content .= '</td><td class="layout-manager-column-add">+</td>';
142 $content .= '</tr></table>';
143 $content .= html_e('div', array('class' => 'layout-manager-row-add'), '+');
146 $content .= '<table class="layout-manager-row" id="widget_layout_build">
148 <td class="layout-manager-column-add">+</td>';
149 $content .= '<td class="layout-manager-column">
150 <div class="layout-manager-column-remove">x</div>
151 <div class="layout-manager-column-width">
152 '._('Section Title')._(':').'<br />
153 <input type="text" value="" size="20" maxlength="20" /><br />
154 <input type="number" value="50" autocomplete="off" size="1" maxlength="3" />%
156 <div id="fake" class="wb_extrafield" style="display: none"></div>
158 <td class="layout-manager-column-add">+</td>';
159 $content .= '<td class="layout-manager-column">
160 <div class="layout-manager-column-remove">x</div>
161 <div class="layout-manager-column-width">
162 '._('Section Title')._(':').'<br />
163 <input type="text" value="" size="20" maxlength="20" /><br />
164 <input type="number" value="50" autocomplete="off" size="1" maxlength="3" />%
166 <div id="fake" class="wb_extrafield" style="display: none"></div>
168 <td class="layout-manager-column-add">+</td>
170 $content .= html_e('div', array('class' => 'layout-manager-row-add'), '+');
174 $HTML->listTableBottom();
175 $jsvariable = "var sectiontitle = '"._("Section Title")._(":")."';";
176 $javascript = <<<'EOS'
177 var controllerWidgetBuilder;
178 jQuery(document).ready(function() {
179 controllerWidgetBuilder = new WidgetBuilderController({
180 buttonAddRow: jQuery('.layout-manager-row-add'),
181 buttonAddColumn: jQuery('.layout-manager-column-add'),
182 buttonRemoveColumn: jQuery('.layout-manager-column-remove'),
183 buttonRemoveEF: jQuery('.ef-widget-remove'),
184 labelTitle: sectiontitle
186 jQuery('.layout-manager-column').droppable({
187 accept: '#extrafield_table .wb_extrafield',
188 drop: function(event, ui) {
189 ui.draggable.appendTo(this).css('position', '');
190 ui.draggable.parent().droppable('destroy');
191 ui.draggable.parent().find('#fake').remove();
192 ui.draggable.find('#x'+ui.draggable.attr('id')).show()},
193 over: function(event, ui) {
194 ui.helper.css('z-index', 1);
197 if (jQuery("[name='name[trackercontent][add]']") != 'undefined') {
198 jQuery("[name='name[trackercontent][add]']").click(function(){
199 var form = jQuery(this).parents('form').first();
200 form.find('.layout-manager-row').each(function(i, e) {
203 name: 'trackercontent_layout[]',
204 value: jQuery(e).find('.layout-manager-column input[type=number]').map(function(){ return this.value;}).get().join(',')
208 name: 'trackercontent_ef[]',
209 value: jQuery(e).find('.layout-manager-column > .wb_extrafield').map(function(){ return this.id;}).get().join(',')
213 name: 'trackercontent_title[]',
214 value: jQuery(e).find('.layout-manager-column input[type=text]').map(function(){ return this.value;}).get().join(',')
219 if (jQuery("[name='trackercontent-submit']") != 'undefined') {
220 jQuery("[name='trackercontent-submit']").click(function(){
221 var form = jQuery(this).parents('form').first();
222 form.find('.layout-manager-row').each(function(i, e) {
225 name: 'trackercontent_layout[]',
226 value: jQuery(e).find('.layout-manager-column input[type=number]').map(function(){ return this.value;}).get().join(',')
230 name: 'trackercontent_ef[]',
231 value: jQuery(e).find('.layout-manager-column > .wb_extrafield').map(function(){ return this.id;}).get().join(',')
235 name: 'trackercontent_title[]',
236 value: jQuery(e).find('.layout-manager-column input[type=text]').map(function(){ return this.value;}).get().join(',')
243 $content .= html_e('script', array( 'type'=>'text/javascript'), '//<![CDATA['."\n".'jQuery(function(){'.$jsvariable."\n".$javascript.'});'."\n".'//]]>');
247 private function getAvailableExtraFieldsForm($owner_id, $preference = false) {
250 $artifactTypeObject = artifactType_get_object($atid);
251 $availableExtraFields = $artifactTypeObject->getExtraFields();
252 $stillAvailableExtraFields = $this->availableExtrafields($owner_id, $availableExtraFields);
255 $arr = $this->getExtraFieldIDs($owner_id);
257 if (!empty($stillAvailableExtraFields) || !empty($arr)) {
258 $content = html_e('p', array(), sprintf(_('Drag & drop into your layout the available custom fields from %s to display into this widget'), $artifactTypeObject->getName())._(':'));
259 $content .= $HTML->listTableTop(array(), array(), 'full', 'extrafield_table');
261 if (!empty($stillAvailableExtraFields)) {
263 for ($i = 0; count($stillAvailableExtraFields) > $i; $i++) {
264 $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%');
266 $content .= $HTML->multiTableRow(array(), $cells);
271 $content .= $HTML->multiTableRow(array(), $cells);
276 for ($i = 0; count($arr) > $i; $i++) {
277 $cells[] = array('', 'id' => 'tdef'.$arr[$i], 'width' => '50%');
279 $content .= $HTML->multiTableRow(array(), $cells);
284 $content .= $HTML->multiTableRow(array(), $cells);
287 if (!empty($stillAvailableExtraFields) || !empty($arr)) {
288 $content .= $HTML->listTableBottom();
289 $javascript = <<<'EOS'
290 jQuery(document).ready(function() {
291 var wb_extrafield_start;
292 jQuery('.wb_extrafield', '#extrafield_table').draggable({
298 $content .= html_e('script', array( 'type'=>'text/javascript'), '//<![CDATA['."\n".'jQuery(function(){'.$javascript.'});'."\n".'//]]>');
301 if (!isset($content)) {
302 $content = $HTML->information(_('No customfields available to link to a widget'));
307 private function availableExtrafields($owner_id, $extrafields) {
308 $arr = $this->getExtraFieldIDs($owner_id);
309 $availableExtrafields = array();
310 foreach ($extrafields as $extrafield) {
311 if (($extrafield[3] != ARTIFACT_EXTRAFIELDTYPE_PARENT) && !in_array($extrafield[0], $arr)) {
312 $availableExtrafields[] = $extrafield;
315 return $availableExtrafields;
318 private function getExtraFieldIDs($id) {
319 $res = db_query_params('select field_id from artifact_display_widget_field, artifact_display_widget
320 where artifact_display_widget_field.id = artifact_display_widget.id and artifact_display_widget.owner_id = $1', array($id));
321 $extrafieldIDs = array();
323 $extrafieldIDs = util_result_column_to_array($res, 0);
325 return $extrafieldIDs;
328 private function getLayoutExtraFieldIDs($id) {
329 $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));
330 $extrafieldIDs = array();
331 if ($res && (db_numrows($res) > 0)) {
332 while ($arr = db_fetch_array($res)) {
333 // row_id is unique, column_id is unique per row, field_id is unique, width is not unique, section is not unique
334 $extrafieldIDs[$arr[0]][$arr[1]][$arr[2]] = array($arr[3], $arr[4]);
337 return $extrafieldIDs;
340 function getInstallPreferences() {
341 $owner_id = (int)substr(getStringFromRequest('owner'), 1);
342 $content = $this->getPartialPreferencesFormTitle(_('Enter title of Tracker Content Box'));
343 $content .= $this->buildRenderWidget();
344 $content .= $this->getAvailableExtraFieldsForm($owner_id);
348 function getContent() {
358 //manage redirect in case of missing required fields
359 global $extra_fields;
363 if (count($this->layoutExtraFieldIDs) > 0) {
364 $mandatoryDisplay = false;
366 if (is_object($ah)) {
367 $selected = $ah->getExtraFieldData();
368 $efInFormula = $ath->getExtraFieldsInFormula();
369 $efWithFormula = $ath->getExtraFieldsWithFormula();
370 } elseif ($func == 'add') {
371 $selected = $ath->getExtraFieldsDefaultValue();
372 $efInFormula = $ath->getExtraFieldsInFormula(array(), false, false);
373 $efWithFormula = $ath->getExtraFieldsWithFormula(array(), false, false);
375 if (!forge_check_perm('tracker', $atid, 'submit') || ($func == 'detail' && !session_loggedin())) {
378 foreach ($this->layoutExtraFieldIDs as $column_id) {
379 $return .= $HTML->listTableTop();
381 foreach ($column_id as $extrafieldID) {
382 $keys = array_keys($extrafieldID);
385 if (strlen($extrafieldID[$keys[0]][1]) > 0) {
386 $cellContent .= html_e('div', array('class' => 'widget_section_title'), htmlspecialchars($extrafieldID[$keys[0]][1]));
388 $extrafieldObject = new ArtifactExtraField($ath, $keys[0]);
389 if ($func == 'add') {
390 $display = !(int)$extrafieldObject->isHiddenOnSubmit();
397 if (isset($selected[$keys[0]])) {
398 $value = $selected[$keys[0]];
399 } elseif (isset($extra_fields[$keys[0]])) {
400 $value = $extra_fields[$keys[0]];
402 $attrs = array('form' => 'trackerform');
404 if ($extrafieldObject->isRequired() && !$readonly) {
405 $mandatory = utils_requiredField();
406 $mandatoryDisplay = true;
407 $attrs['required'] = 'required';
409 if (strlen($extrafieldObject->getDescription()) > 0) {
410 $attrs['title'] = $extrafieldObject->getDescription();
412 if (in_array($extrafieldObject->getID(), $efInFormula)) {
413 $attrs['class'] = (empty($attrs['class']) ? '' : $attrs['class'].' ').'in-formula';
415 if (in_array($extrafieldObject->getID(), $efWithFormula)) {
416 $attrs['class'] = (empty($attrs['class']) ? '' : $attrs['class'].' ').'with-formula readonly';
417 $attrs['readonly'] = 'readonly';
419 $cellContent .= html_e('strong', array(), $extrafieldObject->getName()._(':')).$mandatory.html_e('br');
420 switch ($extrafieldObject->getType()) {
421 case ARTIFACT_EXTRAFIELDTYPE_SELECT:
424 $value = $extrafieldObject->getShow100label();
426 $value = $ath->getElementName($value);
428 $cellContent .= $value;
430 $parent = $extrafieldObject->getParent();
431 if (!is_null($parent) && !empty($parent) && $parent != '100') {
432 $selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
433 $allowed = $extrafieldObject->getAllowedValues($selectedElmnts);
435 $cellContent .= $ath->renderSelect($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, $allowed, $attrs);
438 case ARTIFACT_EXTRAFIELDTYPE_CHECKBOX:
441 $value = $extrafieldObject->getShow100label();
443 $value = explode(',', $ath->getElementName($value));
445 $cellContent .= join(html_e('br'), $value);
447 $parent = $extrafieldObject->getParent();
448 if (!is_null($parent) && !empty($parent) && $parent != '100') {
449 $selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
450 $allowed = $extrafieldObject->getAllowedValues($selectedElmnts);
452 $cellContent .= $ath->renderCheckbox($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), $allowed, $attrs);
455 case ARTIFACT_EXTRAFIELDTYPE_RADIO:
458 $value = $extrafieldObject->getShow100label();
460 $value = $ath->getElementName($value);
462 $cellContent .= $value;
464 $parent = $extrafieldObject->getParent();
465 if (!is_null($parent) && !empty($parent) && $parent != '100') {
466 $selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
467 $allowed = $extrafieldObject->getAllowedValues($selectedElmnts);
469 $cellContent .= $ath->renderRadio($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, $allowed, $attrs);
472 case ARTIFACT_EXTRAFIELDTYPE_TEXT:
474 if (strlen($value) > 0) {
475 $value = preg_replace('/((http|https|ftp):\/\/\S+)/', "<a href=\"\\1\" target=\"_blank\">\\1</a>", $value);
479 $cellContent .= $value;
481 $attrs['style'] = 'box-sizing: border-box; width: 100%';
482 if ($extrafieldObject->getPattern()) {
483 $attrs['pattern'] = $extrafieldObject->getPattern();
485 $cellContent .= $ath->renderTextField($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
488 case ARTIFACT_EXTRAFIELDTYPE_MULTISELECT:
491 $value = $extrafieldObject->getShow100label();
493 $value = explode(',', $ath->getElementName($value));
495 $cellContent .= join(html_e('br'), $value);
497 $parent = $extrafieldObject->getParent();
498 if (!is_null($parent) && !empty($parent) && $parent != '100') {
499 $selectedElmnts = (isset($selected[$parent]) ? $selected[$parent] : '');
500 $allowed = $extrafieldObject->getAllowedValues($selectedElmnts);
502 $cellContent .= $ath->renderMultiSelectBox($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), $allowed, $attrs);
505 case ARTIFACT_EXTRAFIELDTYPE_TEXTAREA:
507 if (strlen($value) > 0) {
508 $value = preg_replace('/((http|https|ftp):\/\/\S+)/', "<a href=\"\\1\" target=\"_blank\">\\1</a>", $value);
512 $cellContent .= $value;
514 $attrs['style'] = 'box-sizing: border-box; width: 100%';
515 $cellContent .= $ath->renderTextArea($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
518 case ARTIFACT_EXTRAFIELDTYPE_STATUS:
521 $value = $extrafieldObject->getShow100label();
523 $value = $ath->getElementName($value);
525 $cellContent .= $value;
527 // parent artifact can't be close if a child is still open
528 if ( $func != "add" &&
529 $extrafieldObject->getAggregationRule() == ARTIFACT_EXTRAFIELD_AGGREGATION_RULE_STATUS_CLOSE_RESTRICTED &&
530 $ah->hasChildren()) {
531 $children = $ah->getChildren();
533 foreach ($children as $child) {
534 if ($child['status_id'] == 1) {
540 $extrafieldObject = new ArtifactExtraField($ath, $keys[0]);
541 //$extrafieldObject = new ArtifactExtraField($this, $efarr[$i]['extra_field_id']);
542 $statusArr = $extrafieldObject->getAvailableValues();
543 $openStatus = array();
544 foreach ($statusArr as $status) {
545 if ($child['status_id'] == 1) {
546 $openStatus[] = $status['element_id'];
550 $allowed = array_intersect($allowed, $openStatus);
552 $allowed = $openStatus;
556 $atw = new ArtifactWorkflow($ath, $keys[0]);
557 // Special treatment for the initial step (Submit). In this case, the initial value is the first value.
561 $allowedWF = $atw->getNextNodes($value);
563 $allowed = array_intersect($allowed, $allowedWF);
565 $allowed = $allowedWF;
568 $cellContent .= $ath->renderSelect($keys[0], $value, false, $extrafieldObject->getShow100label(), false, false, $allowed, $attrs);
571 //case ARTIFACT_EXTRAFIELDTYPE_ASSIGNEE:
572 case ARTIFACT_EXTRAFIELDTYPE_RELATION:
574 $value = preg_replace_callback('/\b(\d+)\b/', create_function('$matches', 'return _artifactid2url($matches[1], \'title\');'), $value);
575 $cellContent .= $value;
577 // specific rewrite of cellContent
578 $cellContent = '<div style="width:100%; line-height: 20px;">' .
579 '<div style="float:left;">'.html_e('strong', array(), $extrafieldObject->getName()._(':')).$mandatory.'</div>' .
580 '<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>'.
582 $cellContent .= $ath->renderRelationField($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
585 case ARTIFACT_EXTRAFIELDTYPE_PARENT:
587 $value = preg_replace_callback('/\b(\d+)\b/', create_function('$matches', 'return _artifactid2url($matches[1], \'title\');'), $value);
588 $cellContent .= $value;
590 // specific rewrite of cellContent
591 $cellContent = '<div style="width:100%; line-height: 20px;">' .
592 '<div style="float:left;">'.html_e('strong', array(), $extrafieldObject->getName()._(':')).$mandatory.'</div>' .
593 '<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>'.
595 $cellContent .= $ath->renderParentField($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
598 case ARTIFACT_EXTRAFIELDTYPE_INTEGER:
600 $cellContent .= $value;
602 $cellContent .= $ath->renderIntegerField($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
605 /* reserved for aljeux extension, for merge into FusionForge */
606 case ARTIFACT_EXTRAFIELDTYPE_FORMULA:
608 case ARTIFACT_EXTRAFIELDTYPE_DATETIME:
611 $cellContent .= date('Y-m-d H:i', $value);
613 $cellContent .= _('None');
616 $cellContent .= $ath->renderDatetime($keys[0], $value, $attrs);
619 case ARTIFACT_EXTRAFIELDTYPE_SLA:
622 $cellContent .= $ath->renderSLAField($keys[0], $value, $attrs);
625 case ARTIFACT_EXTRAFIELDTYPE_USER:
630 $user = user_get_object($value);
631 $value = $user->getRealName().' ('.html_e('samp', array(), util_make_link_u($user->getUnixname(),$value,$user->getUnixname())).')';
633 $cellContent .= $value;
635 $cellContent .= $ath->renderUserField($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, false, $attrs);
638 /* 15: reserved MULTIUSER */
639 case ARTIFACT_EXTRAFIELDTYPE_RELEASE:
642 $releaseObj = frsrelease_get_object($value);
643 if (is_object($releaseObj)) {
644 $value = $releaseObj->FRSPackage->getName().' - '.$releaseObj->getName();
645 $cellContent .= $value;
647 $cellContent .= ' ';
651 $cellContent .= $ath->renderReleaseField($keys[0], $value, $extrafieldObject->getShow100(), $extrafieldObject->getShow100label(), false, false, false, $attrs);
654 case ARTIFACT_EXTRAFIELDTYPE_EFFORT:
657 $effortUnitSet = New EffortUnitSet($ath, $ath->getEffortUnitSet());
658 $effortUnitFactory = New EffortUnitFactory($effortUnitSet);
659 $cellContent .= $effortUnitFactory->encodedToString($value);
661 $cellContent .= _('None');
664 $cellContent .= $ath->renderEffort($keys[0], $value, $extrafieldObject->getAttribute1(), $extrafieldObject->getAttribute2(), $attrs);
669 if ($extrafieldObject->isRequired()) {
670 switch ($extrafieldObject->getType()) {
671 case ARTIFACT_EXTRAFIELDTYPE_MULTISELECT:
672 $defaultValues = $extrafieldObject->getDefaultValues();
673 foreach ($defaultValues as $defaultValue) {
674 $cellContent .= html_e('input', array('type' => 'hidden', 'value' => $defaultValue, 'name' => 'extra_fields['.$extrafieldObject->getID().'][]', 'form' => 'trackerform'));
678 $cellContent .= html_e('input', array('type' => 'hidden', 'value' => $extrafieldObject->getDefaultValues(), 'name' => 'extra_fields['.$extrafieldObject->getID().']', 'form' => 'trackerform'));
681 $cellContent .= ' ';
685 $cellContent = ' ';
687 $cells[] = array($cellContent, 'style' => 'vertical-align: top; width: '.$extrafieldID[$keys[0]][0].'%');
689 $return .= $HTML->multiTableRow(array(), $cells);
690 $return .= $HTML->listTableBottom();
692 $return .= $ath->javascript();
693 $return .= init_datetimepicker();
694 if ($mandatoryDisplay) {
695 $return .= $HTML->addRequiredFieldsInfoBox();
699 $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()')));
704 function getCategory() {
705 return _('Trackers');
708 function canBeMinize() {
712 function hasPreferences() {
716 function getPreferences() {
717 return $this->getPartialPreferencesFormTitle($this->getTitle()).
718 $this->buildRenderWidget().
719 $this->getAvailableExtraFieldsForm($this->owner_id, true);
722 function getPreferencesForm($layout_id, $owner_id, $owner_type) {
726 $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;
728 $url .= '&aid='.$aid;
730 $prefs = $HTML->openForm(array('method' => 'post', 'action' => $url));
731 $prefs .= html_ao('fieldset').html_e('legend', array(), _('Preferences'));
732 $prefs .= $this->getPreferences();
733 $prefs .= html_e('br');
734 $prefs .= html_e('input', array('type' => 'submit', 'name' => 'cancel', 'value' => _('Cancel')));
735 $prefs .= html_e('input', array('type' => 'submit', 'name' => 'trackercontent-submit', 'value' => _('Submit')));
736 $prefs .= html_ac(html_ap() - 1);
737 $prefs .= $HTML->closeForm();
741 function updatePreferences() {
742 $sanitizer = new TextSanitizer();
744 $title = getStringFromRequest('title');
745 if(strlen($title) > 0) {
746 $title = $sanitizer->SanitizeHtml($title);
750 $content_id = getIntFromRequest('content_id');
752 $sql = "UPDATE artifact_display_widget SET title = $1 WHERE owner_id =$2 AND id = $3";
753 db_query_params($sql,array($title, $this->owner_id, $content_id));
756 $trackerrows = getArrayFromRequest('trackercontent_layout');
757 $trackerextrafields = getArrayFromRequest('trackercontent_ef');
758 $trackercelltitles = getArrayFromRequest('trackercontent_title');
759 db_query_params('DELETE FROM artifact_display_widget_field WHERE id = $1', array($content_id));
760 foreach ($trackerrows as $rowkey => $trackerrow) {
761 $columns = explode(',', $trackerrow);
762 $extrafields = explode(',', $trackerextrafields[$rowkey]);
763 $celltitle = explode(',', $trackercelltitles[$rowkey]);
765 foreach ($columns as $columnkey => $column) {
766 if ($extrafields[$columnkey] == "fake") {
769 $extrafieldid = substr($extrafields[$columnkey], 2); //remove prefix ef
771 $section = $sanitizer->SanitizeHtml($celltitle[$columnkey]);
772 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)',
773 array($content_id, $extrafieldid, $columnkey, $rowid, $column, $section));