3 * FusionForge Generic Tracker facility
5 * Copyright 1999-2001 (c) VA Linux Systems - Sourceforge
6 * Copyright 2010 (c) Fusionforge Team
7 * Copyright 2011, Franck Villaume - Capgemini
8 * Copyright (C) 2011 Alain Peyrat - Alcatel-Lucent
9 * Copyright 2014,2016, Franck Villaume - TrivialDev
10 * Copyright 2016, Stéphane-Eymeric Bredthauer - TrivialDev
11 * http://fusionforge.org
13 * This file is part of FusionForge. FusionForge is free software;
14 * you can redistribute it and/or modify it under the terms of the
15 * GNU General Public License as published by the Free Software
16 * Foundation; either version 2 of the Licence, or (at your option)
19 * FusionForge is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 require_once $gfcommon.'tracker/ArtifactType.class.php';
30 require_once $gfcommon.'tracker/ArtifactExtraField.class.php';
31 require_once $gfcommon.'tracker/ArtifactExtraFieldElement.class.php';
32 require_once $gfcommon.'tracker/ArtifactWorkflow.class.php';
33 require_once $gfcommon.'include/utils_crossref.php';
34 require_once $gfcommon.'include/UserManager.class.php';
36 class ArtifactTypeHtml extends ArtifactType {
38 function header($params) {
40 if (!forge_get_config('use_tracker')) {
43 $group_id= $this->Group->getID();
45 //required by new site_project_header
46 $params['group']=$group_id;
47 $params['toptab']='tracker';
48 $params['tabtext']=$this->getName();
54 $labels[] = _("View Trackers");
55 $links[] = '/tracker/?group_id='.$group_id;
56 $attr[] = array('title' => _('Get the list of available trackers'));
57 $labels[] = $this->getName();
58 $links[] = '/tracker/?func=browse&group_id='.$group_id.'&atid='. $this->getID();
59 $attr[] = array('title' => _('Browse this tracker.'));
60 $labels[] = _('Export CSV');
61 $links[] = '/tracker/?func=csv&group_id='.$group_id.'&atid='. $this->getID();
62 $attr[] = array('title' => _('Download data from this tracker as csv file.'));
63 if (forge_check_perm ('tracker',$this->getID(),'submit')) {
64 $labels[] = _('Submit New');
65 $links[] = '/tracker/?func=add&group_id='.$group_id.'&atid='. $this->getID();
66 $attr[] = array('title' => _('Add a new issue.'));
69 if (session_loggedin()) {
70 $labels[] = _('Reporting');
71 $links[] = '/tracker/reporting/?group_id='.$group_id.'&atid='. $this->getID();
72 $attr[] = array('title' => _('Various graph about statistics.'));
73 if ($this->isMonitoring()) {
74 $labels[] = _('Stop Monitor');
75 $links[] = '/tracker/?group_id='.$group_id.'&atid='. $this->getID().'&func=monitor&stopmonitor=1';
76 $attr[] = array('title' => _('Remove this tracker from your monitoring.'));
78 $labels[] = _('Monitor');
79 $links[] = '/tracker/?group_id='.$group_id.'&atid='. $this->getID().'&func=monitor&startmonitor=1';
80 $attr[] = array('title' => _('Add this tracker from your monitoring.'));
83 if (forge_check_perm ('tracker', $this->getID(), 'manager')) {
84 $labels[] = _('Administration');
85 $links[] = '/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID();
86 $attr[] = array('title' => _('Global administration for trackers. Create, clone, workflow, fields ...'));
90 $params['submenu'] = $HTML->subMenu($labels, $links, $attr);
91 site_project_header($params);
94 plugin_hook("blocks", "tracker_".$this->getName());
98 function footer($params = array()) {
99 site_project_footer($params);
102 function adminHeader($params) {
104 $this->header($params);
105 $group_id= $this->Group->getID();
107 $links_arr[]='/tracker/admin/?group_id='.$group_id;
108 $title_arr[]=_('New Tracker');
109 $attr_arr[] = array('title'=>_('Create a new tracker.'));
111 $links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&update_type=1';
112 $title_arr[]=_('Update Settings');
113 $attr_arr[] = array('title'=>_('Set up preferences like expiration times, email addresses.'));
115 $links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&add_extrafield=1';
116 $title_arr[]=_('Manage Custom Fields');
117 $attr_arr[] = array('title'=>_('Add new boxes like Phases, Quality Metrics, Components, etc. Once added they can be used with other selection boxes (for example, Categories or Groups) to describe and browse bugs or other artifact types.'));
119 $links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&workflow=1';
120 $title_arr[]=_('Manage Workflow');
121 $attr_arr[] = array('title'=>_('Edit tracker workflow.'));
123 $links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&customize_list=1';
124 $title_arr[]=_('Customize List');
125 $attr_arr[] = array('title'=>_('Customize display for the tracker.'));
127 $links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&add_canned=1';
128 $title_arr[]=_('Manage Canned Responses');
129 $attr_arr[] = array('title'=>_('Create/change generic response messages for the tracker.'));
131 $links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&clone_tracker=1';
132 $title_arr[]=_('Apply Template Tracker');
133 $attr_arr[] = array('title'=>_('Duplicate parameters and fields from a template trackers in this one.'));
135 $links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&delete=1';
136 $title_arr[]=_('Delete');
137 $attr_arr[] = array('title'=>_('Permanently delete this tracker.'));
139 echo $HTML->printSubMenu($title_arr, $links_arr, $attr_arr);
142 function adminFooter($params) {
143 $this->footer($params);
146 function renderSubmitInstructions() {
147 $msg = $this->getSubmitInstructions();
148 return str_replace("\n","<br />", $msg);
151 function renderBrowseInstructions() {
152 $msg = $this->getBrowseInstructions();
153 return str_replace("\n","<br />", $msg);
157 * renderExtraFields - ???
159 * @param array $selected
160 * @param bool $show_100 Display the specific '100' value. Default is false.
161 * @param string $text_100 Label displayed for the '100' value. Default is 'none'
162 * @param bool $show_any
163 * @param string $text_any
164 * @param array $types
165 * @param bool $status_show_100 Force display of the '100' value if needed. Default is false.
166 * @param string $mode QUERY, DISPLAY, UPDATE, NEW
168 function renderExtraFields($selected = array(),
169 $show_100 = false, $text_100 = 'none',
170 $show_any = false, $text_any = 'Any',
172 $status_show_100 = false,
174 if ($mode == 'NEW') {
175 $efarr = $this->getExtraFields($types, false, false);
177 $efarr = $this->getExtraFields($types);
179 //each two columns, we'll reset this and start a new row
180 $template = $this->getRenderHTML($types, $mode);
182 if ($mode=='QUERY') {
183 $keys=array_keys($efarr);
184 for ($k=0; $k<count($keys); $k++) {
186 $type = $efarr[$i]['field_type'];
187 if ($type == ARTIFACT_EXTRAFIELDTYPE_SELECT ||
188 $type == ARTIFACT_EXTRAFIELDTYPE_CHECKBOX ||
189 $type == ARTIFACT_EXTRAFIELDTYPE_RADIO ||
190 $type == ARTIFACT_EXTRAFIELDTYPE_STATUS ||
191 $type == ARTIFACT_EXTRAFIELDTYPE_MULTISELECT) {
192 $efarr[$i]['field_type'] = ARTIFACT_EXTRAFIELDTYPE_MULTISELECT;
194 $efarr[$i]['field_type'] = ARTIFACT_EXTRAFIELDTYPE_TEXT;
199 // 'DISPLAY' mode is for rendering in 'read-only' mode (for detail view).
200 if ($mode === 'DISPLAY') {
201 $keys=array_keys($efarr);
202 for ($k=0; $k<count($keys); $k++) {
206 if (!isset($selected[$efarr[$i]['extra_field_id']]))
207 $selected[$efarr[$i]['extra_field_id']] = '';
209 $value = $selected[$efarr[$i]['extra_field_id']];
210 $type = $efarr[$i]['field_type'];
212 if ($type == ARTIFACT_EXTRAFIELDTYPE_SELECT ||
213 $type == ARTIFACT_EXTRAFIELDTYPE_CHECKBOX ||
214 $type == ARTIFACT_EXTRAFIELDTYPE_RADIO ||
215 $type == ARTIFACT_EXTRAFIELDTYPE_STATUS ||
216 $type == ARTIFACT_EXTRAFIELDTYPE_MULTISELECT) {
218 $value = $efarr[$i]['show100label'];
220 $arr = $this->getExtraFieldElements($efarr[$i]['extra_field_id']);
222 // Convert the values (ids) to names in the ids order.
224 for ($j=0; $j<count($arr); $j++) {
225 if (is_array($value) && in_array($arr[$j]['element_id'],$value)) {
226 $new[]= $arr[$j]['element_name'];
227 } elseif ($arr[$j]['element_id'] === $value) {
228 $new[] = $arr[$j]['element_name'];
231 $value = join('<br />', $new);
233 } elseif ($type == ARTIFACT_EXTRAFIELDTYPE_TEXT ||
234 $type == ARTIFACT_EXTRAFIELDTYPE_TEXTAREA) {
235 $value = preg_replace('/((http|https|ftp):\/\/\S+)/',
236 "<a href=\"\\1\" target=\"_blank\">\\1</a>", $value);
237 } elseif ($type == ARTIFACT_EXTRAFIELDTYPE_RELATION) {
238 // Convert artifact id to links.
239 $value = preg_replace_callback('/\b(\d+)\b/', create_function('$matches', 'return _artifactid2url($matches[1], \'title\');'), $value);
240 } elseif ($type == ARTIFACT_EXTRAFIELDTYPE_DATETIME && $value!='') {
241 $value = date('Y-m-d H:i', $value);
243 $template = str_replace('{$PostName:'.$efarr[$i]['field_name'].'}', $post_name, $template);
244 $template = str_replace('{$'.$efarr[$i]['field_name'].'}', $value, $template);
250 $keys = array_keys($efarr);
251 for ($k = 0; $k < count($keys); $k++) {
256 if (!empty($efarr[$i]['description'])) {
257 $attrs['title'] = $efarr[$i]['description'];
259 if ($efarr[$i]['is_required'] == 1 && $mode != 'QUERY') {
260 $attrs['required'] = 'required';
263 if (!isset($selected[$efarr[$i]['extra_field_id']]))
264 $selected[$efarr[$i]['extra_field_id']] = '';
266 if ($status_show_100) {
267 $efarr[$i]['show100'] = $status_show_100;
270 if ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_SELECT ||
271 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_CHECKBOX ||
272 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_RADIO ||
273 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_MULTISELECT) {
275 if (!is_null($efarr[$i]['parent']) && !empty($efarr[$i]['parent']) && $efarr[$i]['parent']!='100') {
276 $aefParentId = $efarr[$i]['parent'];
277 $selectedElmnts = (isset($selected[$aefParentId]) ? $selected[$aefParentId] : '');
278 $aef = new ArtifactExtraField($this,$efarr[$i]['extra_field_id']);
279 $allowed = $aef->getAllowedValues($selectedElmnts);
283 if ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_SELECT) {
285 $str = $this->renderSelect($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],$show_any,$text_any,$allowed, $attrs);
287 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_CHECKBOX) {
289 $str = $this->renderCheckbox($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'], $allowed, $attrs);
291 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_RADIO) {
293 $str = $this->renderRadio($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],$show_any, $text_any, $allowed, $attrs);
295 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_TEXT ||
296 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_INTEGER) {
298 if (!empty($efarr[$i]['pattern'])) {
299 $attrs['pattern'] = $efarr[$i]['pattern'];
301 if ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_TEXT) {
302 $str = $this->renderTextField($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['attribute1'],$efarr[$i]['attribute2'], $attrs);
304 $str = $this->renderIntegerField($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['attribute1'],$efarr[$i]['attribute2'], $attrs);
306 if ($mode == 'QUERY') {
307 $post_name = ' <i>'._('(%% for wildcards)').'</i> ';
310 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_TEXTAREA) {
312 $str = $this->renderTextArea($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['attribute1'],$efarr[$i]['attribute2'], $attrs);
313 if ($mode == 'QUERY') {
314 $post_name = ' <i>'._('(%% for wildcards)').'</i>';
317 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_MULTISELECT) {
319 $str = $this->renderMultiSelectBox($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'], $allowed, $attrs);
321 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_STATUS) {
323 // Get the allowed values from the workflow.
324 $atw = new ArtifactWorkflow($this, $efarr[$i]['extra_field_id']);
326 // Special treatment for the initial step (Submit).
327 // In this case, the initial value is the first value.
328 if (isset($selected[$efarr[$i]['extra_field_id']]) && $selected[$efarr[$i]['extra_field_id']]) {
329 $selected_node = $selected[$efarr[$i]['extra_field_id']];
331 $selected_node = 100;
334 $allowed = $atw->getNextNodes($selected_node);
335 $allowed[] = $selected_node;
336 $str = $this->renderSelect($efarr[$i]['extra_field_id'],$selected_node,$status_show_100,$text_100,$show_any,$text_any, $allowed, $attrs);
338 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_RELATION) {
340 $str = $this->renderRelationField($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['attribute1'],$efarr[$i]['attribute2'], $attrs);
341 if ($mode == 'UPDATE' || $mode == 'NEW') {
342 $post_name = html_image('ic/forum_edit.gif', 37, 15 ,array('title'=>"Click to edit", 'alt'=>"Click to edit", 'onclick'=>"switch2edit(this, 'show$i', 'edit$i')"));
344 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_DATETIME) {
345 $str = $this->renderDatetime($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']], $attrs);
346 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_USER) {
347 $str = $this->renderUserField($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],$show_any,$text_any,false, $attrs);
348 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_RELEASE) {
349 $str = $this->renderReleaseField($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],$show_any,$text_any,false, $attrs);
351 $template = str_replace('{$PostName:'.$efarr[$i]['field_name'].'}',$post_name,$template);
352 $template = str_replace('{$'.$efarr[$i]['field_name'].'}',$str,$template);
354 if($template != NULL){
355 if ($mode == 'UPDATE' || $mode == 'NEW') {
356 echo $this->javascript();
362 function renderRelatedTasks($group, $ah) {
364 if (!$group->usesPM()) {
370 $taskcount = db_numrows($ah->getRelatedTasks());
371 db_result_reset($ah->getRelatedTasks());
373 if (forge_check_perm('tracker_admin', $ah->ArtifactType->Group->getID())) {
379 $totalPercentage = 0;
380 if ($taskcount > 0) {
381 $title_arr = array();
382 $title_arr[] = _('Task Id and Summary');
383 $title_arr[] = _('Progress');
384 $title_arr[] = _('Start Date');
385 $title_arr[] = _('End Date');
386 $title_arr[] = _('Status');
387 (($is_admin) ? $title_arr[]=_('Remove Relation') : '');
388 $return .= $HTML->listTableTop($title_arr);
390 for ($i = 0; $i < $taskcount; $i++) {
391 $taskinfo = db_fetch_array($ah->relatedtasks, $i);
392 $totalPercentage += $taskinfo['percent_complete'];
393 $taskid = $taskinfo['project_task_id'];
394 $projectid = $taskinfo['group_project_id'];
395 $groupid = $taskinfo['group_id'];
396 if (forge_check_perm('pm', $projectid, 'read')) {
397 $summary = util_unconvert_htmlspecialchars($taskinfo['summary']);
398 $startdate = date(_('Y-m-d H:i'), $taskinfo['start_date']);
399 $enddate = date(_('Y-m-d H:i'), $taskinfo['end_date']);
400 $status = $taskinfo['status_name'];
402 <td>'.util_make_link('/pm/task.php?func=detailtask&project_task_id='.$taskid.'&group_id='.$groupid.'&group_project_id='.$projectid, '[T'.$taskid.'] '.$summary).'</td>
403 <td><div class="percentbar" style="width: 100px;">
404 <div style="width:'.round($taskinfo['percent_complete']).'px;"></div></div></td>
405 <td>'.$startdate.'</td>
406 <td>'.$enddate.'</td>
407 <td>'.$status.' ('.$taskinfo['percent_complete'].'%)</td>'.
408 (($is_admin) ? '<td><input type="checkbox" name="remlink[]" value="'.$taskid.'" /></td>' : '').
412 $return .= $HTML->listTableBottom();
414 $return .= "\n<hr /><p style=\"text-align:right;\">";
415 $return .= _('Average completion rate')._(': ').(int)($totalPercentage/$taskcount).'%';
418 $return .= $HTML->information(_('No related tasks'));
423 function renderFiles($group_id, $ah) {
425 $file_list =& $ah->getFiles();
426 $count=count($file_list);
430 $return .= '<strong>'._("Attachments")._(':').'</strong>'.'<br/>';
432 $title_arr[] = _('Size');
433 $title_arr[] = _('Name');
434 $title_arr[] = _('Date');
435 $title_arr[] = _('By');
436 $title_arr[] = _('Download');
437 $return .= $HTML->listTableTop($title_arr);
439 foreach ($file_list as $file) {
441 $return .= '<td>'.human_readable_bytes($file->getSize()).'</td>';
442 $return .= '<td>'.htmlspecialchars($file->getName()).'</td>';
443 $return .= '<td>'.date(_('Y-m-d H:i'), $file->getDate()).'</td>';
444 $return .= '<td>'.$file->getSubmittedUnixName().'</td>';
445 $return .= '<td>'.util_make_link('/tracker/download.php/'.$group_id.'/'. $this->getID().'/'. $ah->getID() .'/'.$file->getID().'/'.$file->getName(), htmlspecialchars($file->getName())).'</td>';
446 if (forge_check_perm ('tracker', $this->getID(), 'tech')) {
447 $return .= '<td><input type="checkbox" name="delete_file[]" value="'. $file->getID() .'">'._('Delete').'</td>';
452 $return .= $HTML->listTableBottom();
454 $return .= $HTML->information(_('No attached documents'));
462 * @param array $types
463 * @param string $mode
464 * @return string HTML template.
466 function getRenderHTML($types=array(), $mode='') {
467 // Use template only for the browse (not for query or mass update)
468 if (($mode === 'DISPLAY' || $mode === 'DETAIL' || $mode === 'UPDATE' || $mode == 'NEW')
469 && $this->data_array['custom_renderer']) {
470 return preg_replace('/<!--(\S+.*?)-->/','{$\\1}',$this->data_array['custom_renderer']);
472 return $this->generateRenderHTML($types, $mode);
479 * @param array $types
480 * @param string $mode Display mode (QUERY OR DISPLAY OR NEW)
481 * @return string HTML template.
483 function generateRenderHTML($types=array(), $mode) {
484 if ($mode == 'NEW') {
485 $efarr = $this->getExtraFields($types, false, false);
487 $efarr = $this->getExtraFields($types);
489 //each two columns, we'll reset this and start a new row
492 <!-- Start Extra Fields Rendering -->
496 $keys=array_keys($efarr);
498 if ($count == 0) return '';
500 for ($k=0; $k<$count; $k++) {
503 // Do not show the required star in query mode (creating/updating a query).
504 $is_required = ($mode == 'QUERY' || $mode == 'DISPLAY') ? 0 : $efarr[$i]['is_required'];
505 $name = $efarr[$i]['field_name'].($is_required ? utils_requiredField() : '')._(': ');
506 $name = '<strong>'.$name.'</strong>';
508 if ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_SELECT ||
509 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_CHECKBOX ||
510 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_RADIO ||
511 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_MULTISELECT ||
512 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_STATUS ||
513 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_USER ||
514 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_RELEASE ) {
517 <td class="halfwidth top">'.$name.'<br />{$'.$efarr[$i]['field_name'].'}</td>';
519 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_TEXT ||
520 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_INTEGER ||
521 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_RELATION ||
522 $efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_DATETIME) {
524 //text fields might be really wide, so need a row to themselves.
525 if (($col_count == 1) && ($efarr[$i]['attribute1'] > 30)) {
535 <td style="width:'.(50*$colspan).'%" colspan="'.$colspan.'" class="top">'.$name.'{$PostName:'.$efarr[$i]['field_name'].'}<br />{$'.$efarr[$i]['field_name'].'}</td>';
537 } elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_TEXTAREA) {
539 //text areas might be really wide, so need a row to themselves.
540 if (($col_count == 1) && ($efarr[$i]['attribute2'] > 30)) {
550 <td style="width:'.(50*$colspan).'%" colspan="'.$colspan.'" class="top">'.$name.'{$PostName:'.$efarr[$i]['field_name'].'}<br />{$'.$efarr[$i]['field_name'].'}</td>';
555 //we've done two columns - if there are more to do, start a new row
556 if (($col_count == 2) && ($k != $count-1)) {
563 if ($col_count == 1) {
569 <!-- End Extra Fields Rendering -->';
574 * renderSelect - this function builds pop up box with choices.
576 * @param int $extra_field_id The ID of this field.
577 * @param string $checked The item that should be checked
578 * @param bool|string $show_100 Whether to show the '100 row'
579 * @param string $text_100 What to call the '100 row'
580 * @param bool $show_any
581 * @param string $text_any
582 * @param bool $allowed
583 * @param array $attrs
584 * @return string HTML code for the box and choices
586 function renderSelect ($extra_field_id,$checked='xzxz',$show_100=false,$text_100='none',$show_any=false,$text_any='Any', $allowed=false, $attrs = array ()) {
587 if ($text_100 == 'none'){
590 $arr = $this->getExtraFieldElements($extra_field_id);
591 $aef = new ArtifactExtraField($this, $extra_field_id);
592 $aefChildren = $aef->getChildren();
593 if (!empty($aefChildren)) {
594 $attrs['class'] = (empty($attrs['class']) ? '':$attrs['class'].' ').'with-depcy';
596 if ($aef->isAutoAssign()) {
597 $attrs['class'] = (empty($attrs['class']) ? '':$attrs['class'].' ').'autoassign';
601 $opt_attrs = array();
602 $attrs_100 = array();
604 for ($i=0; $i<count($arr); $i++) {
605 $vals[$i]=$arr[$i]['element_id'];
606 $texts[$i]=$arr[$i]['element_name'];
607 $opt_attrs[$i]=array();
608 $aefe = new ArtifactExtraFieldElement($aef, $arr[$i]['element_id']);
609 if (!empty($aefChildren)) {
610 $cElmntArr = $aefe->getChildrenElements();
611 if (!empty($cElmntArr))
614 foreach ($cElmntArr as $key=>$cElmnt) {
615 $childField = new ArtifactExtraField($this, $key);
616 $dependency .= (empty($dependency) ? '':', ').'{"field":'.$key.', "elmnt": ['.implode(', ', $cElmnt).']}';
618 $dependency = '['.$dependency.']';
619 $opt_attrs[$i]= array( 'data-dependency'=>$dependency);
622 if ($aef->isAutoAssign()) {
623 $autoAssignTo = UserManager::instance()->getUserById($aefe->getAutoAssignto());
624 $opt_attrs[$i]=array_merge(isset($opt_attrs[$i]) ? $opt_attrs[$i] : array(), array( 'data-autoassignto'=>'{"id":'.$aefe->getAutoAssignto().', "name":"'.$autoAssignTo->getRealName().' ('.$autoAssignTo->getUnixName().')"}'));
628 if ($show_100 && !empty($aefChildren)) {
629 $attrs_100 = array( 'data-dependency'=>'{"fields": ['.implode(', ',$aefChildren).']}');
631 return html_build_select_box_from_arrays ($vals,$texts,'extra_fields['.$extra_field_id.']',$checked,$show_100,$text_100,$show_any,$text_any, $allowed, $attrs, $opt_attrs, $attrs_100);
635 * renderUserField - this function builds pop up box with users.
637 * @param int $extra_field_id The ID of this field.
638 * @param string $checked The item that should be checked
639 * @param bool|string $show_100 Whether to show the '100 row'
640 * @param string $text_100 What to call the '100 row'
641 * @param bool $show_any
642 * @param string $text_any
643 * @param bool $allowed
644 * @param array $attrs
645 * @return string HTML code for the box and choices
647 function renderUserField ($extra_field_id,$checked='xzxz',$show_100=false,$text_100='none',$show_any=false,$text_any='Any', $allowed=false, $attrs = array ()) {
648 if ($text_100 == 'none' || $text_100 == 'nobody'){
649 $text_100=_('Nobody');
651 $arr = $this->getExtraFieldElements($extra_field_id);
652 $selectedRolesId = array();
653 for ($i=0; $i<count($arr); $i++) {
654 $selectedRolesId[$i]=$arr[$i]['element_name'];
656 $roles = $this->getGroup()->getRoles();
657 $userArray = array();
658 foreach ($roles as $role) {
659 if (in_array($role->getID(), $selectedRolesId)) {
660 foreach ($role->getUsers() as $user) {
661 $userArray[$user->getID()] = $user->getRealName().(($user->getStatus()=='S') ? ' '._('[SUSPENDED]') : '');
665 if (is_integer($checked) && !isset($userArray[$checked])) {
666 $checkedUser = user_get_object($checked);
667 $userArray[$checkedUser->getID()] = $checkedUser->getRealName().' '._('[DELETED]');
669 asort($userArray,SORT_FLAG_CASE | SORT_STRING);
670 $keys = array_keys($userArray);
671 $vals = array_values($userArray);
672 return html_build_select_box_from_arrays ($keys,$vals,'extra_fields['.$extra_field_id.']',$checked,$show_100,$text_100,$show_any,$text_any, $allowed, $attrs);
676 * renderReleaseField - this function builds 2 pop up boxes with packages & releases.
678 * @param int $extra_field_id The ID of this field.
679 * @param string $checked The item that should be checked
680 * @param bool|string $show_100 Whether to show the '100 row'
681 * @param string $text_100 What to call the '100 row'
682 * @param bool $show_any
683 * @param string $text_any
684 * @param bool $allowed
685 * @param array $attrs
686 * @return string HTML code for the box and choices
688 function renderReleaseField ($extra_field_id,$checked='xzxz',$show_100=false,$text_100='none',$show_any=false,$text_any='Any', $allowed=false, $attrs = array ()) {
689 if ($text_100 == 'none'){
693 $releasesArray = array();
694 $defaultRelease = $checked;
695 $releaseAttrs = $attrs;
696 $releasesAttrs = array();
698 $packagesArray = array();
699 $defaultPackage = 100;
700 $packageAttrs = array('class'=>'package');
701 $packagesAttrs = array();
703 $arr = $this->getExtraFieldElements($extra_field_id);
704 $selectedPackagesId = array();
705 for ($i=0; $i<count($arr); $i++) {
706 $selectedPackagesId[$i]=$arr[$i]['element_name'];
708 $packages = get_frs_packages($this->getGroup());
710 if ((integer)$defaultRelease!=0 && $defaultRelease!=100) {
711 $releaseObj = frsrelease_get_object($defaultRelease);
712 $defaultPackage = $releaseObj->getFRSPackage()->getID();
715 uasort($packages, 'compareObjectName');
716 foreach ($packages as $package) {
717 if (in_array($package->getID(), $selectedPackagesId)) {
718 $packagesArray[$package->getID()] = $package->getName();
720 $releases = $package->getReleases();
721 uasort($releases, 'compareObjectName');
722 foreach ($releases as $release) {
723 $releasesArray[$release->getID()] = $release->getName();
724 $releasesList .= (empty($releasesList) ? '':', ').$release->getID();
725 if ($defaultPackage == 100 || $defaultPackage==$package->getID()) {
726 $allowed[] = $release->getID();
729 $releasesList = '{"field": '.$extra_field_id.', "elmnt": ['.$releasesList.']}';
730 $packagesAttrs [] = array('data-releases'=>$releasesList);
733 $keys = array_keys($packagesArray);
734 $vals = array_values($packagesArray);
736 $return = html_build_select_box_from_arrays ($keys,$vals,'package['.$extra_field_id.']',$defaultPackage,$show_100,$text_100,$show_any,$text_any, false, $packageAttrs, $packagesAttrs);
737 $keys = array_keys($releasesArray);
738 $vals = array_values($releasesArray);
739 $return .= html_build_select_box_from_arrays ($keys,$vals,'extra_fields['.$extra_field_id.']',$defaultRelease,$show_100,$text_100,$show_any,$text_any, $allowed, $releaseAttrs, $releasesAttrs);
744 * renderRadio - this function builds radio buttons.
746 * @param int $extra_field_id The $int ID of this field.
747 * @param string $checked The $string item that should be checked
748 * @param bool $show_100 Whether $string to show the '100 row'
749 * @param string $text_100 What $string to call the '100 row'
750 * @param bool $show_any
751 * @param string $text_any
752 * @param array $attrs Array of other attributes
753 * @return string HTML code using radio buttons
755 function renderRadio ($extra_field_id,$checked='xzxz',$show_100=false,$text_100='none',$show_any=false,$text_any='Any', $allowed = false, $attrs = array()) {
757 $arr = $this->getExtraFieldElements($extra_field_id);
758 $aef = new ArtifactExtraField($this, $extra_field_id);
759 $aefChildren = $aef->getChildren();
760 if (!empty($aefChildren)) {
761 $attrs['class'] = (empty($attrs['class']) ? '':$attrs['class'].' ').'with-depcy';
766 $radios_attrs = array();
767 $attrs_100 = array();
769 for ($i=0; $i<count($arr); $i++) {
770 $vals[$i]=$arr[$i]['element_id'];
771 $texts[$i]=$arr[$i]['element_name'];
772 $aefe = new ArtifactExtraFieldElement($aef, $arr[$i]['element_id']);
774 if (!empty($aefChildren)) {
775 $cElmntArr = $aefe->getChildrenElements();
776 if (!empty($cElmntArr))
778 foreach ($cElmntArr as $key=>$cElmnt) {
779 $childField = new ArtifactExtraField($this, $key);
780 $dependency .= (empty($dependency) ? '':', ').'{"field":'.$key.', "elmnt": ['.implode(', ', $cElmnt).']}';
782 $dependency = '['.$dependency.']';
783 $radios_attrs[$i]['data-dependency']=$dependency;
786 if ($aef->isAutoAssign()) {
787 $autoAssignTo = UserManager::instance()->getUserById($aefe->getAutoAssignto());
788 $radios_attrs[$i]=array_merge(isset($radios_attrs[$i]) ? $radios_attrs[$i] : array(), array( 'data-autoassignto'=>'{"id":'.$aefe->getAutoAssignto().', "name":"'.$autoAssignTo->getRealName().' ('.$autoAssignTo->getUnixName().')"}'));
791 if ($show_100 && !empty($aefChildren)) {
792 $attrs_100 = array( 'data-dependency'=>'{"fields": ['.implode(', ',$aefChildren).']}');
794 return html_build_radio_buttons_from_arrays ($vals,$texts,'extra_fields['.$extra_field_id.']',$checked,$show_100,$text_100,$show_any,$text_any,$allowed,$attrs,$radios_attrs,$attrs_100);
798 * renderCheckbox - this function builds checkboxes.
800 * @param int $extra_field_id The ID of this field.
801 * @param array $checked The items that should be checked
802 * @param bool|string $show_100 Whether to show the '100 row'
803 * @param string $text_100 What to call the '100 row'
804 * @param array $attrs Array of other attributes
805 * @return string radio buttons
807 function renderCheckbox ($extra_field_id,$checked=array(),$show_100=false,$text_100='none', $allowed=false, $attrs = array()) {
808 if ($text_100 == 'none'){
812 if (!$checked || !is_array($checked)) {
815 if (!empty($attrs['title'])) {
816 $attrs['title'] = util_html_secure($attrs['title']);
819 $arr = $this->getExtraFieldElements($extra_field_id);
820 $aef = new ArtifactExtraField($this, $extra_field_id);
821 $aefChildren = $aef->getChildren();
822 if (!empty($aefChildren)) {
823 $attrs['class'] = (empty($attrs['class']) ? '':$attrs['class'].' ').'with-depcy';
828 $chk_attrs = array();
829 $attrs_100 = array();
831 for ($i=0; $i<count($arr); $i++) {
832 $aefe = new ArtifactExtraFieldElement($aef, $arr[$i]['element_id']);
833 $vals[$i] = $arr[$i]['element_id'];
834 $texts[$i] = $arr[$i]['element_name'];
835 $chk_attrs[$i] = array();
837 if (!empty($aefChildren)) {
838 $cElmntArr = $aefe->getChildrenElements();
839 if (!empty($cElmntArr))
841 foreach ($cElmntArr as $key=>$cElmnt) {
842 $childField = new ArtifactExtraField($this, $key);
843 $dependency .= (empty($dependency) ? '':', ').'{"field":'.$key.', "elmnt": ['.implode(', ', $cElmnt).']}';
845 $dependency = '['.$dependency.']';
846 $chk_attrs[$i]['data-dependency']=$dependency;
850 if ($show_100 && !empty($aefChildren)) {
851 $attrs_100['data-dependency'] ='{"fields": ['.implode(', ',$aefChildren).']}';
853 return html_build_checkboxes_from_arrays($vals,$texts,'extra_fields['.$extra_field_id.']',$checked,false,$show_100,$text_100,$allowed,$attrs,$chk_attrs,$attrs_100);
857 * renderMultiSelectBox - this function builds checkboxes.
859 * @param int $extra_field_id The ID of this field.
860 * @param array $checked The items that should be checked
861 * @param bool|string $show_100 Whether to show the '100 row'
862 * @param string $text_100 What to call the '100 row'
863 * @param array $attrs Array of other attributes
864 * @return string radio multiselectbox
866 function renderMultiSelectBox($extra_field_id,$checked=array(),$show_100=false,$text_100='none', $allowed=false, $attrs=array()) {
870 if (!is_array($checked)) {
871 $checked = explode(',',$checked);
873 $arr = $this->getExtraFieldElements($extra_field_id);
874 $aef = new ArtifactExtraField($this, $extra_field_id);
875 $aefChildren = $aef->getChildren();
876 if (!empty($aefChildren)) {
877 $attrs['class'] = (empty($attrs['class']) ? '':$attrs['class'].' ').'with-depcy';
881 $opt_attrs = array();
882 $attrs_100 = array();
884 for ($i=0; $i<count($arr); $i++) {
885 $vals[$i]=$arr[$i]['element_id'];
886 $texts[$i]=$arr[$i]['element_name'];
887 $aefe = new ArtifactExtraFieldElement($aef, $arr[$i]['element_id']);
888 if (!empty($aefChildren)) {
889 $cElmntArr = $aefe->getChildrenElements();
890 if (!empty($cElmntArr))
893 foreach ($cElmntArr as $key=>$cElmnt) {
894 $childField = new ArtifactExtraField($this, $key);
895 $dependency .= (empty($dependency) ? '':', ').'{"field":'.$key.', "elmnt": ['.implode(', ', $cElmnt).']}';
897 $dependency = '['.$dependency.']';
898 $opt_attrs[$i]= array( 'data-dependency'=>$dependency);
902 $size = min( count($arr)+1, 15);
903 if ($show_100 && !empty($aefChildren)) {
904 $attrs_100 = array( 'data-dependency'=>'{"fields": ['.implode(', ',$aefChildren).']}');
906 return html_build_multiple_select_box_from_arrays($vals,$texts,"extra_fields[$extra_field_id][]",$checked,$size,$show_100,$text_100, $allowed, $attrs, $opt_attrs, $attrs_100);
910 * renderTextField - this function builds a text field.
912 * @param int $extra_field_id The ID of this field.
913 * @param string $contents The data for this field.
914 * @param string $size
915 * @param string $maxlength
916 * @param array $attrs Array of other attributes
917 * @return string HTML code of corresponding input tag.
919 function renderTextField ($extra_field_id, $contents, $size, $maxlength, $attrs = array()) {
920 return html_e('input', array_merge(array('type'=>'text', 'name'=>'extra_fields['.$extra_field_id.']', 'value'=>$contents, 'size'=>$size, 'maxlength'=>$maxlength), $attrs));
924 * renderIntegerField - this function builds a text field.
926 * @param int $extra_field_id The ID of this field.
927 * @param string $contents The data for this field.
928 * @param string $size
929 * @param string $maxlength
930 * @param array $attrs Array of other attributes
931 * @return string HTML code of corresponding input tag.
933 function renderIntegerField ($extra_field_id, $contents, $size, $maxlength, $attrs = array()) {
934 return html_e('input', array_merge(array('type'=>'number', 'name'=>'extra_fields['.$extra_field_id.']', 'value'=>$contents, 'size'=>$size, 'maxlength'=>$maxlength, 'min'=>0), $attrs));
938 * renderRelationField - this function builds a relation field.
940 * @param int $extra_field_id The ID of this field.
941 * @param string $contents The data for this field.
942 * @param string $size
943 * @param string $maxlength
944 * @param array $attrs Array of other attributes
945 * @return string text area and data.
947 function renderRelationField ($extra_field_id,$contents,$size,$maxlength, $attrs = array()) {
948 $arr = $this->getExtraFieldElements($extra_field_id);
949 for ($i=0; $i<count($arr); $i++) {
950 $keys[$i]=$arr[$i]['element_id'];
951 $vals[$i]=$arr[$i]['element_name'];
953 // Convert artifact id to links.
954 $html_contents = preg_replace_callback('/\b(\d+)\b/', create_function('$matches', 'return _artifactid2url($matches[1], \'title\');'), $contents);
955 $edit_contents = $this->renderTextField ($extra_field_id,$contents,$size,$maxlength);
956 return html_e('div',array_merge(array( 'id'=>'edit'.$extra_field_id, 'style'=>'display: none', 'title'=>_('Tip: Enter a space-separated list of artifact ids ([#NNN] also accepted)')), $attrs), $edit_contents)
957 .html_e('div',array_merge(array( 'id'=>'show'.$extra_field_id, 'style'=>'display: block'), $attrs), $html_contents);
961 * renderTextArea - this function builds a text area.
963 * @param int $extra_field_id The ID of this field.
964 * @param string $contents The data for this field.
965 * @param string $rows
966 * @param string $cols
967 * @param array $attrs Array of other attributes
968 * @return string text area and data.
970 function renderTextArea ($extra_field_id,$contents,$rows,$cols, $attrs = array()) {
971 return html_e('textarea', array_merge(array('name'=>'extra_fields['.$extra_field_id.']', 'rows'=>$rows, 'cols'=>$cols), $attrs), $contents, false);
976 * renderDatetime - this function builds a Datetime field.
978 * @param int $extra_field_id The ID of this field.
979 * @param string $datetime datetime for this field.
980 * @param array $attrs Array of other attributes
981 * @return string datetime.
983 function renderDatetime($extra_field_id, $datetime, $attrs = array()) {
984 if (!$datetime=='') {
985 $datetime = date('Y-m-d H:i',$datetime);
987 return html_e('input', array_merge(array('type'=>'text', 'name'=>'extra_fields['.$extra_field_id.']', 'class'=>'datetimepicker', 'value'=>$datetime),$attrs));
990 function technicianBox ($name='assigned_to[]',$checked='xzxz',$show_100=true,$text_100='none',$extra_id='-1',$extra_name='',$multiple=false) {
991 if ($text_100=='none'){
992 $text_100=_('Nobody');
995 $engine = RBACEngine::getInstance () ;
996 $techs = $engine->getUsersByAllowedAction ('tracker', $this->getID(), 'tech') ;
1001 sortUserList($techs);
1003 foreach ($techs as $tech) {
1004 $ids[] = $tech->getID() ;
1005 $names[] = $tech->getRealName() ;
1008 if ($extra_id != '-1') {
1010 $names[]=$extra_name;
1014 if (!is_array($checked)) {
1015 $checked = explode(',',$checked);
1017 $size = min( count($ids)+1, 15);
1018 return html_build_multiple_select_box_from_arrays ($ids,$names,$name,$checked,$size,$show_100,$text_100);
1020 return html_build_select_box_from_arrays ($ids,$names,$name,$checked,$show_100,$text_100);
1024 function submitterBox ($name='submitted_by[]',$checked='xzxz',$show_100=true,$text_100='none',$extra_id='-1',$extra_name='',$multiple=false) {
1025 if ($text_100=='none'){
1026 $text_100=_('Nobody');
1028 $result = $this->getSubmitters();
1029 $ids =& util_result_column_to_array($result,0);
1030 $names =& util_result_column_to_array($result,1);
1031 if ($extra_id != '-1') {
1033 $names[]=$extra_name;
1037 if (!is_array($checked)) {
1038 $checked = explode(',',$checked);
1040 $size = min( count($ids)+1, 15);
1041 return html_build_multiple_select_box_from_arrays ($ids,$names,$name,$checked,$size,$show_100,$text_100);
1043 return html_build_select_box_from_arrays ($ids,$names,$name,$checked,$show_100,$text_100);
1047 function lastModifierBox ($name='last_modified_by[]',$checked='xzxz',$show_100=true,$text_100='none',$extra_id='-1',$extra_name='',$multiple=false) {
1048 if ($text_100=='none'){
1049 $text_100=_('Nobody');
1051 $result = $this->getLastModifiers();
1052 $ids =& util_result_column_to_array($result,0);
1053 $names =& util_result_column_to_array($result,1);
1054 if ($extra_id != '-1') {
1056 $names[]=$extra_name;
1060 if (!is_array($checked)) {
1061 $checked = explode(',',$checked);
1063 $size = min( count($ids)+1, 15);
1064 return html_build_multiple_select_box_from_arrays ($ids,$names,$name,$checked,$size,$show_100,$text_100);
1066 return html_build_select_box_from_arrays ($ids,$names,$name,$checked,$show_100,$text_100);
1070 function cannedResponseBox ($name='canned_response',$checked='xzxz') {
1071 return html_build_select_box ($this->getCannedResponses(),$name,$checked);
1075 * statusBox - show the statuses - automatically shows the "custom statuses" if they exist
1079 function statusBox ($name='status_id',$checked='xzxz',$show_100=false,$text_100='none') {
1080 if ($text_100=='none'){
1081 $text_100=_('None');
1083 return html_build_select_box($this->getStatuses(),$name,$checked,$show_100,$text_100);
1086 function javascript() {
1088 var invalidSelectMsg = '"._("One or more of the selected options is not allowed")."';
1089 var invalidInputMsg = '". _("This choice is not allowed")."';";
1090 $javascript = <<<'EOS'
1091 $.expr[':'].invalid = function(elem, index, match) {
1092 for (let invalid of document.querySelectorAll(':invalid') ) {
1093 if (elem === invalid) { return true; }
1097 $(".package").on('change', function(){
1098 $(this).children('option:selected').each(function(i){
1099 var releases = $(this).data("releases");
1100 $("select[name^='extra_fields["+releases.field+"]']")[0].setCustomValidity("");
1101 $("select[name^='extra_fields["+releases.field+"]'] option").not( "[value='100']" ).each(function(j,opt){
1102 if (this.value!='100') {
1103 if ($.inArray(parseInt(this.value),releases.elmnt)>-1) {
1104 $(this).prop('disabled', false).removeClass('option_disabled');
1106 $(this).prop('disabled', true);
1107 $(this).addClass('option_disabled');
1111 $("select[name^='extra_fields["+releases.field+"]'] option:selected:disabled").parent().each(function() {
1112 $(this).children('option:selected:disabled').prop('disabled', false);
1113 this.setCustomValidity(invalidSelectMsg);
1114 $(this).on("change.invalid", function() {
1115 $(this).children('option.option_disabled:not(:disabled):not(:selected)').prop('disabled', true);
1116 if (!$(this).children('option.option_disabled:selected').length) {
1117 this.setCustomValidity("");
1118 $(this).off("change.invalid");
1124 $(".autoassign[name^='extra_fields']").on('change', function(){
1125 if ($(this).prop('tagName') == 'SELECT') {
1126 var elmnts = $(this).children('option:selected');
1128 var elmnts = $(this).siblings('input:checked');
1130 elmnts.each(function(i){
1131 var aat = $(this).data("autoassignto");
1132 $("select#tracker-assigned_to option[value="+aat.id+"]").prop('selected', true);
1133 $("span#tracker-assigned_to").text(aat.name);
1136 $(".with-depcy[name^='extra_fields']").on('change', function(){
1137 if ($(this).prop('tagName') == 'SELECT') {
1138 var elmnts = $(this).children('option:selected');
1140 var elmnts = $(this).siblings('input:checked');
1142 elmnts.each(function(i){
1143 var dep = $(this).data("dependency");
1144 if (this.value!='100') {
1145 $(dep).each(function(j, val) {
1146 $("select[name^='extra_fields["+val.field+"]']:invalid, input[name^='extra_fields["+val.field+"]']:invalid").each(function() {
1147 this.setCustomValidity("");
1148 $(this).off("change.invalid");
1150 $("select[name^='extra_fields["+val.field+"]'] option").each(function(k,opt){
1151 if (this.value!='100') {
1152 if ($.inArray(parseInt(this.value),val.elmnt)>-1) {
1153 $(this).prop('disabled', false).removeClass('option_disabled');
1155 $(this).prop('disabled', true);
1156 $(this).addClass('option_disabled');
1160 $("input[name^='extra_fields["+val.field+"]']").each(function(k,opt){
1161 if (this.value!='100') {
1162 if ($.inArray(parseInt(this.value),val.elmnt)>-1) {
1163 $(this).prop('disabled', false).removeClass($(this).attr('type')+'_disabled');
1165 $(this).prop('disabled', true);
1166 $(this).addClass($(this).attr('type')+'_disabled');
1172 $(dep.fields).each(function(j, val) {
1173 $("select[name^='extra_fields["+val+"]']:invalid, input[name^='extra_fields["+val+"]']:invalid").each(function() {
1174 this.setCustomValidity("");
1176 $("select[name^='extra_fields["+val+"]'] option.option_disabled").each(function() {
1177 $(this).prop('disabled', false).removeClass('option_disabled');
1179 $("input.radio_disable[name^='extra_fields["+val+"]']").each(function() {
1180 $(this).prop('disabled', false).removeClass('radio_disabled');
1182 $("input.checkbox_disabled[name^='extra_fields["+val+"]']").each(function() {
1183 $(this).prop('disabled', false).removeClass('checkbox_disabled');
1188 $("select[name^='extra_fields'] option:selected:disabled").parent().each(function() {
1189 $(this).children('option:selected:disabled').prop('disabled', false);
1190 this.setCustomValidity(invalidSelectMsg);
1191 $(this).on("change.invalid", function() {
1192 $(this).children('option.option_disabled:not(:disabled):not(:selected)').prop('disabled', true);
1193 if (!$(this).children('option.option_disabled:selected').length) {
1194 this.setCustomValidity("");
1195 $(this).off("change.invalid");
1199 $("input[name^='extra_fields']:checked:disabled").each(function() {
1200 $(this).prop('disabled', false);
1201 this.setCustomValidity(invalidInputMsg);
1202 if ($(this).attr('type') == 'radio') {
1203 $(this).siblings('input[type="radio"]').on("change.invalid", function() {
1204 $(this).siblings('input[type="radio"]:invalid').prop('disabled', true).addClass('input_disabled').each(function() {
1205 this.setCustomValidity("");
1207 $(this).siblings('input[type="radio"]').off("change.invalid");
1208 $(this).off("change.invalid");
1211 $(this).on("change.invalid", function() {
1212 $(this).prop('disabled', true);
1213 this.setCustomValidity("");
1214 $(this).off("change.invalid");
1220 return html_e('script', array( 'type'=>'text/javascript'), '//<![CDATA['."\n".'$(function(){'.$jsvariable."\n".$javascript.'});'."\n".'//]]>');
1227 // c-file-style: "bsd"