Taxons: Add support in the portal (UI still to be done).

This commit is contained in:
Molkobain
2018-09-26 17:13:55 +02:00
parent 1530bb89fe
commit 9397d1ac2e
11 changed files with 281 additions and 44 deletions

View File

@@ -6714,47 +6714,6 @@ class AttributeTagSet extends AttributeDBFieldVoid
return array_merge(parent::ListExpectedParams(), array('is_null_allowed', 'tag_max_nb', 'tag_code_max_len'));
}
/**
* @param \ormTagSet $oValue
*
* @return string JSON to be used in the itop.set_widget JQuery widget
* @throws \CoreException
*/
public function GetJsonForWidget($oValue)
{
$aJson = array();
// possible_values
$aTagSetObjectData = $this->GetAllowedValues();
$aTagSetKeyValData = array();
foreach($aTagSetObjectData as $sTagCode => $sTagLabel)
{
$aTagSetKeyValData[] = [
'code' => $sTagCode,
'label' => $sTagLabel,
];
}
$aJson['possible_values'] = $aTagSetKeyValData;
if (is_null($oValue))
{
$aJson['partial_values'] = array();
$aJson['orig_value'] = array();
}
else
{
$aJson['partial_values'] = $oValue->GetModifiedTags();
$aJson['orig_value'] = array_merge($oValue->GetValue(), $oValue->GetModifiedTags());
}
$aJson['added'] = array();
$aJson['removed'] = array();
$iMaxTags = $this->GetTagMaxNb();
$aJson['max_items_allowed'] = $iMaxTags;
return json_encode($aJson);
}
public function GetDefaultValue(DBObject $oHostObject = null)
{
return null;
@@ -7411,6 +7370,47 @@ class AttributeTagSet extends AttributeDBFieldVoid
return $oSet;
}
/**
* @param \ormTagSet $oValue
*
* @return string JSON to be used in the itop.tagset_widget JQuery widget
* @throws \CoreException
*/
public function GetJsonForWidget($oValue)
{
$aJson = array();
// possible_values
$aTagSetObjectData = $this->GetAllowedValues();
$aTagSetKeyValData = array();
foreach($aTagSetObjectData as $sTagCode => $sTagLabel)
{
$aTagSetKeyValData[] = [
'code' => $sTagCode,
'label' => $sTagLabel,
];
}
$aJson['possible_values'] = $aTagSetKeyValData;
if (is_null($oValue))
{
$aJson['partial_values'] = array();
$aJson['orig_value'] = array();
}
else
{
$aJson['partial_values'] = $oValue->GetModifiedTags();
$aJson['orig_value'] = array_merge($oValue->GetValue(), $oValue->GetModifiedTags());
}
$aJson['added'] = array();
$aJson['removed'] = array();
$iMaxTags = $this->GetTagMaxNb();
$aJson['max_tags_allowed'] = $iMaxTags;
return json_encode($aJson);
}
/**
* The part of the current attribute in the object's signature, for the supplied value
*
@@ -7430,6 +7430,10 @@ class AttributeTagSet extends AttributeDBFieldVoid
return parent::Fingerprint($value);
}
static public function GetFormFieldClass()
{
return '\\Combodo\\iTop\\Form\\Field\\TagSetField';
}
}
/**

View File

@@ -2921,6 +2921,7 @@ table.listResults .originColor {
margin-bottom: 3px;
padding: 4px 6px;
max-width: 120px;
vertical-align: middle;
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;

View File

@@ -3345,6 +3345,7 @@ table.listResults .originColor{
margin-bottom: 3px;
padding: 4px 6px;
max-width: 120px;
vertical-align: middle;
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;

View File

@@ -32,6 +32,7 @@ use DBObjectSet;
use DBSearch;
use DBObjectSearch;
use InlineImage;
use ormTagSet;
use AttributeDateTime;
use AttributeTagSet;
use AttachmentPlugIn;
@@ -1123,13 +1124,13 @@ class ObjectFormManager extends FormManager
}
elseif ($oAttDef instanceof AttributeTagSet)
{
/** @var ormTagSet $oTagSet */
/** @var \ormTagSet $oTagSet */
$oTagSet = $this->oObject->Get($sAttCode);
if (is_null($oTagSet))
{
$oTagSet = new ormTagSet(get_class($this->oObject), $sAttCode);
}
$oTagSet->ApplyDelta($value);
$oTagSet->ApplyDelta(json_decode($value, true));
$this->oObject->Set($sAttCode, $oTagSet);
}
elseif ($oAttDef instanceof AttributeDateTime) // AttributeDate is derived from AttributeDateTime

View File

@@ -45,6 +45,7 @@
<link href="{{ app['combodo.absolute_url'] ~ 'css/font-awesome/css/font-awesome.min.css'|add_itop_version }}" rel="stylesheet">
{# - Misc libs #}
<link href="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/typeahead/css/typeaheadjs.bootstrap.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ 'css/selectize.default.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ 'css/magnific-popup.css'|add_itop_version }}" rel="stylesheet">
<link href="{{ app['combodo.absolute_url'] ~ 'css/c3.min.css'|add_itop_version }}" rel="stylesheet">
{# - Bootstrap theme #}
@@ -85,6 +86,7 @@
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.magnific-popup.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.iframe-transport.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.fileupload.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/utils.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/d3.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/c3.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/bootstrap/js/bootstrap.min.js'|add_itop_version }}"></script>
@@ -114,6 +116,9 @@
{# Typeahead files for autocomplete #}
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/typeahead/js/typeahead.bundle.min.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'lib/handlebars/js/handlebars.min-768ddbd.js'|add_itop_version }}"></script>
{# Selectize for sets #}
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/selectize.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/jquery.itop-tagset-widget.js'|add_itop_version }}"></script>
{# Form files #}
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/form_handler.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.absolute_url'] ~ 'js/form_field.js'|add_itop_version }}"></script>
@@ -123,6 +128,7 @@
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'js/portal_form_handler.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'js/portal_form_field.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'js/portal_form_field_html.js'|add_itop_version }}"></script>
<script type="text/javascript" src="{{ app['combodo.portal.base.absolute_url'] ~ 'js/portal_form_field_tagset.js'|add_itop_version }}"></script>
{# UI Extensions JS, in an undefined order #}
{% if app['combodo.portal.instance.conf'].ui_extensions.js_files is defined %}
{% for js_file in app['combodo.portal.instance.conf'].ui_extensions.js_files %}

View File

@@ -0,0 +1,56 @@
//iTop Portal Form field TagSet
//Used for field containing tagset ...
;
$(function()
{
// the widget definition, where 'itop' is the namespace,
// 'portal_form_field' the widget name
$.widget( 'itop.portal_form_field_tagset', $.itop.portal_form_field,
{
// the constructor
_create: function()
{
this.element
.addClass('portal_form_field_tagset');
this.element.find('input[type="hidden"]').tagset_widget();
this._super();
},
// events bound via _bind are removed automatically
// revert other modifications here
_destroy: function()
{
this.element
.removeClass('portal_form_field_tagset');
this._super();
},
// _setOptions is called with a hash of all options that are changing
// always refresh when changing options
_setOptions: function()
{
this._superApply(arguments);
},
// _setOption is called for each individual option that is changing
_setOption: function( key, value )
{
this._super( key, value );
},
validate: function(oEvent, oData)
{
var oResult = { is_valid: true, error_messages: [] };
// Doing data validation
if(this.options.validators !== null)
{
// TODO
}
this.options.on_validation_callback(this, oResult);
return oResult;
}
});
});
light

View File

@@ -46,6 +46,7 @@ require_once APPROOT . 'sources/form/field/selectobjectfield.class.inc.php';
require_once APPROOT . 'sources/form/field/checkboxfield.class.inc.php';
require_once APPROOT . 'sources/form/field/radiofield.class.inc.php';
require_once APPROOT . 'sources/form/field/linkedsetfield.class.inc.php';
require_once APPROOT . 'sources/form/field/tagsetfield.class.inc.php';
require_once APPROOT . 'sources/form/validator/validator.class.inc.php';
require_once APPROOT . 'sources/form/validator/mandatoryvalidator.class.inc.php';
require_once APPROOT . 'sources/form/validator/integervalidator.class.inc.php';
@@ -57,5 +58,6 @@ require_once APPROOT . 'sources/renderer/bootstrap/bsformrenderer.class.inc.php'
require_once APPROOT . 'sources/renderer/bootstrap/fieldrenderer/bssimplefieldrenderer.class.inc.php';
require_once APPROOT . 'sources/renderer/bootstrap/fieldrenderer/bsselectobjectfieldrenderer.class.inc.php';
require_once APPROOT . 'sources/renderer/bootstrap/fieldrenderer/bslinkedsetfieldrenderer.class.inc.php';
require_once APPROOT . 'sources/renderer/bootstrap/fieldrenderer/bstagsetfieldrenderer.class.inc.php';
require_once APPROOT . 'sources/renderer/bootstrap/fieldrenderer/bssubformfieldrenderer.class.inc.php';
require_once APPROOT . 'sources/renderer/bootstrap/fieldrenderer/bsfileuploadfieldrenderer.class.inc.php';

View File

@@ -0,0 +1,30 @@
<?php
// Copyright (C) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
namespace Combodo\iTop\Form\Field;
/**
* Description of TagSetField
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class TagSetField extends Field
{
}

View File

@@ -55,6 +55,7 @@ class BsFormRenderer extends FormRenderer
$this->AddSupportedField('SubFormField', 'BsSubFormFieldRenderer');
$this->AddSupportedField('SelectObjectField', 'BsSelectObjectFieldRenderer');
$this->AddSupportedField('LinkedSetField', 'BsLinkedSetFieldRenderer');
$this->AddSupportedField('TagSetField', 'BsTagSetFieldRenderer');
$this->AddSupportedField('DateTimeField', 'BsSimpleFieldRenderer');
$this->AddSupportedField('DurationField', 'BsSimpleFieldRenderer');
$this->AddSupportedField('FileUploadField', 'BsFileUploadFieldRenderer');

View File

@@ -288,7 +288,7 @@ EOF
{
// TODO
}
// ... clasic rendering for fields with only one value
// ... classic rendering for fields with only one value
else
{
switch ($sFieldClass)

View File

@@ -0,0 +1,135 @@
<?php
// Copyright (C) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
namespace Combodo\iTop\Renderer\Bootstrap\FieldRenderer;
use Exception;
use ApplicationContext;
use IssueLog;
use Dict;
use MetaModel;
use AttributeFriendlyName;
use Combodo\iTop\Renderer\FieldRenderer;
use Combodo\iTop\Renderer\RenderingOutput;
/**
* Description of BsTagSetFieldRenderer
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class BsTagSetFieldRenderer extends FieldRenderer
{
/**
* @inheritdoc
*/
public function Render()
{
$oOutput = new RenderingOutput();
$oOutput->AddCssClass('form_field_' . $this->oField->GetDisplayMode());
$sFieldMandatoryClass = ($this->oField->GetMandatory()) ? 'form_mandatory' : '';
// Vars to build the table
// $sAttributesToDisplayAsJson = json_encode($this->oField->GetAttributesToDisplay());
// $sAttCodesToDisplayAsJson = json_encode($this->oField->GetAttributesToDisplay(true));
// $aItems = array();
// $aItemIds = array();
// $this->PrepareItems($aItems, $aItemIds);
// $sItemsAsJson = json_encode($aItems);
// $sItemIdsAsJson = htmlentities(json_encode(array('current' => $aItemIds)), ENT_QUOTES, 'UTF-8');
// Rendering field
if (!$this->oField->GetHidden())
{
/** @var \ormTagSet $oOrmSet */
$oOrmSet = $this->oField->GetCurrentValue();
// Opening container
$oOutput->AddHtml('<div class="form-group form_group_small ' . $sFieldMandatoryClass . '">');
// Label
$oOutput->AddHtml('<div class="form_field_label">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $this->oField->GetGlobalId() . '" class="control-label">')
->AddHtml($this->oField->GetLabel(), true)
->AddHtml('</label>');
}
$oOutput->AddHtml('</div>');
// Value
$oOutput->AddHtml('<div class="form_field_control">');
// ... in edit mode
if(!$this->oField->GetReadOnly())
{
$oAttDef = MetaModel::GetAttributeDef($oOrmSet->GetClass(), $oOrmSet->GetAttCode());
$sJSONForWidget = $oAttDef->GetJsonForWidget($oOrmSet);
// - Help block
$oOutput->AddHtml('<div class="help-block"></div>');
// - Value regarding the field type
$oOutput->AddHtml('<input type="hidden" id="' . $this->oField->GetGlobalId() . '" name="' . $this->oField->GetId() . '" value="')
->AddHtml($sJSONForWidget, true)
->AddHtml('" class="form-control" />');
// Attaching JS widget only if field is hidden or NOT read only
// JS Form field widget construct
$aValidators = array();
$sValidators = json_encode($aValidators);
$oOutput->AddJs(
<<<EOF
$("[data-field-id='{$this->oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").portal_form_field_tagset({
validators: $sValidators,
// Overloading default callback as the Selectize widget adds several inputs and we want to retrieve only the one with the value.
get_current_value_callback: function(me, oEvent, oData){
var value = null;
// Retrieving JSON value as a string and not an object
value = me.element.find('#{$this->oField->GetGlobalId()}').val();
return value;
},
set_current_value_callback: function(me, oEvent, oData){ console.log($(me).element); /*$(me.element).find('textarea').val(oData);*/ }
});
EOF
);
}
// ... in view mode
else
{
$aTags = $oOrmSet->GetTags();
$oOutput->AddHtml('<div class="form-control-static">')
->AddHtml('<span class="label-group">');
foreach($aTags as $sTagCode => $oTag)
{
$sTagLabel = $oTag->Get('label');
$sTagDescription = $oTag->Get('description');
$oOutput->AddHtml('<span class="label label-default" data-tag-code="'.$sTagCode.'" data-tag-label="'.$sTagLabel.'" data-tag-description="">')
->AddHtml($sTagLabel, true)
->AddHtml('</span>');
}
$oOutput->AddHtml('</span>')
->AddHtml('</div>');
}
$oOutput->AddHtml('</div>');
}
return $oOutput;
}
}