| Current Path : /home/cbequiperp/www/administrator/components/com_flexicontent/helpers/fcfield/ |
| Current File : /home/cbequiperp/www/administrator/components/com_flexicontent/helpers/fcfield/indexedfield.php |
<?php
/**
* @package FLEXIcontent
* @version 3.4
*
* @author Emmanuel Danan, Georgios Papadakis, Yannick Berges, others, see contributor page
* @link https://flexicontent.org
* @copyright Copyright � 2020, FLEXIcontent team, All Rights Reserved
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
*/
defined( '_JEXEC' ) or die( 'Restricted access' );
JLoader::register('FCField', JPATH_ADMINISTRATOR . '/components/com_flexicontent/helpers/fcfield/parentfield.php');
class FCIndexedField extends FCField
{
var $task_callable = array('getCascadedField');
static $extra_props = array();
static $valueIsArr = 0;
static $isDropDown = 0;
static $promptEnabled = 0;
static $usesImages = 0;
static $cascaded_values = array();
/**
* CONSTRUCTOR
*/
public function __construct(&$subject, $params)
{
$fieldtype = str_replace('plgflexicontent_fields', '', strtolower(get_class($this)));
static::$field_types = array($fieldtype);
parent::__construct($subject, $params);
}
// ***
// *** DISPLAY methods, item form & frontend views
// ***
// Method to create field's HTML display for item form
public function onDisplayField(&$field, &$item)
{
if ( !in_array($field->field_type, static::$field_types) ) return;
$field->label = $field->parameters->get('label_form') ? JText::_($field->parameters->get('label_form')) : JText::_($field->label);
// Set field and item objects
$this->setField($field);
$this->setItem($item);
$use_ingroup = $field->parameters->get('use_ingroup', 0);
$ajax = !empty($field->isAjax);
if (!isset($field->formhidden_grp)) $field->formhidden_grp = $field->formhidden;
if ($use_ingroup) $field->formhidden = 3;
if ($use_ingroup && empty($field->ingroup) && !$ajax) return;
/**
* Check if using 'auto_value_code', clear 'auto_value', if function not set
*/
$auto_value = (int) $field->parameters->get('auto_value', 0);
if ($auto_value === 2)
{
$auto_value_code = $field->parameters->get('auto_value_code', '');
$auto_value_code = preg_replace('/^<\?php(.*)(\?>)?$/s', '$1', $auto_value_code);
}
$auto_value = $auto_value === 2 && !$auto_value_code ? 0 : $auto_value;
// Initialize framework objects and other variables
$document = JFactory::getDocument();
$cparams = JComponentHelper::getParams( 'com_flexicontent' );
$tooltip_class = 'hasTooltip';
$add_on_class = $cparams->get('bootstrap_ver', 2)==2 ? 'add-on' : 'input-group-addon';
$input_grp_class = $cparams->get('bootstrap_ver', 2)==2 ? 'input-append input-prepend' : 'input-group';
$form_font_icons = $cparams->get('form_font_icons', 1);
$font_icon_class = $form_font_icons ? ' fcfont-icon' : '';
$font_icon_class .= FLEXI_J40GE ? ' icon icon- ' : '';
// some parameter shortcuts
$sql_mode = $field->parameters->get( 'sql_mode', 0 ) ;
$field_elements = $field->parameters->get( 'field_elements' ) ;
$cascade_after = (int) $field->parameters->get('cascade_after', 0);
$sortable = static::$valueIsArr && (int) $field->parameters->get('sortable', 0);
/**
* Number of values
*/
$multiple = $use_ingroup || (int) $field->parameters->get('allow_multiple', 0);
$min_values = $use_ingroup || !static::$valueIsArr ? 0 : (int) $field->parameters->get( 'min_values', 0 ) ;
$max_values = $use_ingroup ? 0 : (int) $field->parameters->get('max_values', 0);
$exact_values = $use_ingroup || !static::$valueIsArr ? 0 : (int) $field->parameters->get( 'exact_values', 0 ) ;
$required = (int) $field->parameters->get('required', 0);
$add_position = (int) $field->parameters->get('add_position', 3);
// Sanitize limitations
if ($required && !$min_values && static::$valueIsArr) $min_values = 1; // Comment this to allow simpler 'required' validation
if ($exact_values) $max_values = $min_values = $exact_values;
// If we are multi-value and not inside fieldgroup then add the control buttons (move, delete, add before/after)
$add_ctrl_btns = !$use_ingroup && $multiple;
$fields_box_placing = (int) $field->parameters->get('fields_box_placing', 0);
/**
* Value handling
*/
// Default value
$default_values = !$ajax ? $this->getDefaultValues($isform = true) : array('');
// ***
// *** Input field configuration
// ***
$display_label_form = (int) $field->parameters->get( 'display_label_form', 1 ) ;
$display_as_select = static::$isDropDown || (int) $field->parameters->get( 'display_as_select', 0 );
// DISPLAY using select2 JS
if ($display_as_select)
{
$use_jslib = (int) $field->parameters->get('use_jslib', 1);
$use_select2 = $use_jslib === 1 || $use_jslib === 2;
if ($sortable && !$use_select2)
{
$use_select2 = true;
$error_msg = '<div class="alert alert-warning fc-small fc-iblock">Sortable property enabled, please also enable using select2 JS (usage of it forced to ON)</div><div class="fcclear"></div>';
}
static $select2_added = null;
if ($use_select2 && $select2_added === null)
{
$select2_added = flexicontent_html::loadFramework('select2');
}
// Fields: select / selectmultiple and fields: radioimage / checkboximage displayed as drop-down select in item edit form
$usefirstoption = $field->parameters->get( 'usefirstoption', 1 ) ;
$firstoptiontext = $field->parameters->get( 'firstoptiontext', 'FLEXI_SELECT' ) ;
// Useful when displaying as multi-select without select2 JS
$size = (int) $field->parameters->get('size', 6);
}
// DISPLAY using prettyCheckable JS
else
{
$use_jslib = (int) $field->parameters->get('use_jslib', 2);
$use_prettycheckable = $use_jslib === 2;
static $prettycheckable_added = null;
if ($use_prettycheckable && $prettycheckable_added === null)
{
$prettycheckable_added = flexicontent_html::loadFramework('prettyCheckable');
}
$placeInsideLabel = static::$usesImages && !($use_jslib === 3) && !($use_prettycheckable && $prettycheckable_added);
}
// Custom HTML placed before / after form fields
$opentag = $field->parameters->get( 'opentag_form', '' ) ;
$closetag = $field->parameters->get( 'closetag_form', '' ) ;
// For radio /checkbox display
if (!$display_as_select)
{
$fftype = static::$valueIsArr ? 'checkbox' : 'radio';
// Applicable only for radioimage/checkboximage fields, it allows a more compact display in item form
$form_vals_display = static::$usesImages ? (int) $field->parameters->get( 'form_vals_display', 1 ) : 0 ; // 0: label, 1: image, 2: both
// Prefix - Suffix - Separator (item FORM) parameters, for the checkbox/radio elements
$pretext = $field->parameters->get( 'pretext_form', '' ) ;
$posttext = $field->parameters->get( 'posttext_form', '' ) ;
$separator = $field->parameters->get( 'separator', 0 ) ;
switch($separator)
{
case 0:
$separator = ' ';
break;
case 1:
$separator = '<br />';
break;
case 2:
$separator = ' | ';
break;
case 3:
$separator = ', ';
break;
case 4:
$separator = $closetag . $opentag;
break;
default:
$separator = ' ';
break;
}
}
// Initialise property with default value
if (!$field->value || (count($field->value) === 1 && $field->value[0] === null))
{
$field->value = static::$valueIsArr && !empty($field->ingroup)
? array($default_values)
: $default_values;
}
// CSS classes of value container
$value_classes = 'fcfieldval_container valuebox fcfieldval_container_'.$field->id;
$value_classes .= $fields_box_placing ? ' floated' : '';
// Field name and HTML TAG id
$valueholder_nm = 'custom[_fcfield_valueholder_]['.$field->name.']';
$valueholder_id = 'custom__fcfield_valueholder__'.$field->name;
$fieldname = 'custom['.$field->name.']';
$elementid = 'custom_'.$field->name;
// Create the attributes of the form field
$input_classes = array();
$attribs = '';
// Extra attributes for multi-value field
if (static::$valueIsArr)
{
if ($exact_values)
$attribs .= ' data-exact_values="'.$exact_values.'" ';
else
{
if ($max_values) $attribs .= ' data-max_values="'.$max_values.'" ';
if ($min_values) $attribs .= ' data-min_values="'.$min_values.'" ';
}
}
// Readonly if values are created automatically
if ($auto_value) $attribs .= ' disabled="disabled" ';
// Attributes if displaying as radio / checkbox set
if (!$display_as_select)
{
if ($use_prettycheckable && $prettycheckable_added)
{
$input_classes[] = 'use_prettycheckable';
$attribs .= static::$usesImages ? ' data-customClass="fcradiocheckimage"' : ' data-customClass="fcradiocheck"';
}
if (static::$valueIsArr)
{
if ($max_values || $min_values || $exact_values)
{
$input_classes[] = 'validate-cboxlimitations';
}
else if ($required)
{
$input_classes[] = 'required validate-checkbox'; // do basic checkbox-required validation
}
}
else if ($required)
{
$input_classes[] = 'required validate-radio'; // do basic radio-required validation
}
if ($use_jslib === 3)
{
$input_classes[] = 'fc_checkradio'; // do default CSS styling for checkbox / radio
}
// Attributes for input-labels
$label_class = ($use_jslib === 3 ? '' : 'fccheckradio_lbl ')
. ($form_vals_display==1 ? $tooltip_class : '');
$label_style = static::$usesImages ? 'vertical-align: unset!important;' : ''; // fix for image placement inside label
}
// Attributes if displaying as select
else
{
$input_classes[] = 'fcfield_textselval';
if ($use_jslib && $select2_added) $input_classes[] = 'use_select2_lib';
if ($required) $input_classes[] = 'required';
// Attributes multi-select field
if (static::$valueIsArr)
{
$add_placeholder = $display_label_form==-1 ? 1 : $field->parameters->get( 'usefirstoption', 1 );
$placeholder = $display_label_form==-1 ? $field->label : JText::_($field->parameters->get( 'firstoptiontext', 'FLEXI_SELECT' ));
$attribs .=
' multiple="multiple"' . ($size ? ' size="'.$size.'"' : '')
. ($add_placeholder ? ' data-placeholder="'.$placeholder.'" ' : '');
}
// Attribute for default value(s)
if (!empty($default_values))
{
$attribs .= ' data-defvals="'.implode('|||', $default_values).'" ';
}
// Client-side Validation and sortable class
if (static::$valueIsArr)
{
if ($max_values || $min_values || $exact_values)
{
$input_classes[] = 'validate-sellimitations';
}
if ($sortable)
{
$input_classes[] = 'fc_select2_sortable';
}
}
}
// Form element classes
$input_classes = implode(' ', $input_classes);
// *********************************************************************************************
// Handle adding the needed JS code to CASCADE (listen to) changes of the dependent master field
// *********************************************************************************************
JText::script('FLEXI_PLEASE_WAIT',true);
$js = "";
$css = "";
if ($cascade_after && !$ajax)
{
$byIds = FlexicontentFields::indexFieldsByIds($item->fields, $item);
if ( isset($byIds[$cascade_after]) )
{
$master_field = $byIds[$cascade_after];
$cascade_prompt = $field->parameters->get('cascade_prompt', '');
$cascade_prompt = $cascade_prompt ? JText::_($cascade_prompt) : JText::_('FLEXI_PLEASE_SELECT') . ': ' . JText::_($master_field->label);
$srcELid = 'custom_' . $master_field->name;
$trgELid = $elementid;
$single_master = ! $master_field->parameters->get('use_ingroup', 0) && !$master_field->parameters->get('multiple', 0);
// Get values of cascade (on) source field
$field->valgrps = $master_field->value ?:
(isset(static::$cascaded_values[$master_field->id]) ? static::$cascaded_values[$master_field->id] : array());
//echo ' SLAVE: ' . $field->label . ' with master values : ' . print_r($field->valgrps, true) . '<br/>';
foreach($field->valgrps as & $vg)
{
if (!is_array($vg))
{
$vg = $this->unserialize_array($vg, $force_array=true, $force_value=true);
}
}
unset($vg);
}
else
{
foreach($field->value as $value)
{
$field->html[] = '<div class="alert alert-error fc-small fc-iblock">Error, master field no: '.$cascade_after.' is not assigned to current item type or was unpublished</div><br/>';
}
$cascade_after = 0;
return;
}
}
else if ($cascade_after && $ajax)
{
$field->valgrps = isset($field->valgrps) ? $field->valgrps : array();
$field->valgrps = is_array($field->valgrps) ? $field->valgrps : preg_split("/\s*,\s*/u", trim($field->valgrps));
}
// Handle multiple records
if ($multiple && !$ajax)
{
// Add the drag and drop sorting feature
if ($add_ctrl_btns) $js .= "
jQuery(document).ready(function(){
jQuery('#sortables_".$field->id."').sortable({
handle: '.fcfield-drag-handle',
/*containment: 'parent',*/
tolerance: 'pointer'
".($fields_box_placing ? "
,start: function(e) {
//jQuery(e.target).children().css('float', 'left');
//fc_setEqualHeights(jQuery(e.target), 0);
}
,stop: function(e) {
//jQuery(e.target).children().css({'float': 'none', 'min-height': '', 'height': ''});
}
" : '')."
});
});
";
if ($max_values) JText::script("FLEXI_FIELD_MAX_ALLOWED_VALUES_REACHED", true);
$js .= "
function addField".$field->id."(el, groupval_box, fieldval_box, params)
{
var insert_before = (typeof params!== 'undefined' && typeof params.insert_before !== 'undefined') ? params.insert_before : 0;
var remove_previous = (typeof params!== 'undefined' && typeof params.remove_previous !== 'undefined') ? params.remove_previous : 0;
var scroll_visible = (typeof params!== 'undefined' && typeof params.scroll_visible !== 'undefined') ? params.scroll_visible : 1;
var animate_visible = (typeof params!== 'undefined' && typeof params.animate_visible !== 'undefined') ? params.animate_visible : 1;
if(!remove_previous && (rowCount".$field->id." >= maxValues".$field->id.") && (maxValues".$field->id." != 0)) {
alert(Joomla.JText._('FLEXI_FIELD_MAX_ALLOWED_VALUES_REACHED') + maxValues".$field->id.");
return 'cancel';
}
// Find last container of fields and clone it to create a new container of fields
var lastField = fieldval_box ? fieldval_box : jQuery(el).prev().children().last();
var newField = lastField.clone();
".(!$display_as_select ? "
// Remove HTML added by prettyCheckable JS, from the dupicate new INPUT SET
var prettyContainers = newField.find('.prettyradio, .prettycheckbox');
prettyContainers.find('input, label').each(function() {
var el = jQuery(this);
el.insertAfter(el.parent());
});
prettyContainers.remove();
// Update INPUT SET container id
newField.find('.fc_input_set').attr('id', '".$elementid."_'+uniqueRowNum".$field->id.");
// Update the new INPUT SET
var theSet = newField.find('input:radio, input:checkbox');
//if(window.console) window.console.log('theSet.length: ' + theSet.length);
var nr = 0;
theSet.each(function() {
var elem = jQuery(this);
elem.attr('name', '".$fieldname."['+uniqueRowNum".$field->id."+']".(static::$valueIsArr ? '[]' : '')."');
elem.attr('id', '".$elementid."_'+uniqueRowNum".$field->id."+'_'+nr);
elem.attr('class', '".$elementid."_'+uniqueRowNum".$field->id." + ' " . $input_classes . "');
elem.attr('data-is-defval') ?
elem.attr('checked', 'checked') :
elem.removeAttr('checked') ;
".($use_prettycheckable && $prettycheckable_added ?
"elem.attr('data-element-grpid', '".$elementid."_'+uniqueRowNum".$field->id.");" :
"elem.attr('data-element-grpid', '".$elementid."_'+uniqueRowNum".$field->id.");" )."
".(!$placeInsideLabel ?
"elem.next('label').attr('for', '".$elementid."_'+uniqueRowNum".$field->id."+'_'+nr);" :
"elem.closest('label').attr('for', '".$elementid."_'+uniqueRowNum".$field->id."+'_'+nr);" )." // special case for field with image place input and image inside labels
nr++;
});
// Reapply prettyCheckable JS
newField.find('.use_prettycheckable').each(function() {
var elem = jQuery(this);
var lbl = elem.prev('label');
var lbl_html = lbl.html();
lbl.remove();
elem.prettyCheckable({ label: lbl_html });
});
" : "
// Update the new select field
var elem= newField.find('select.fcfield_textselval').first();
var defvals = elem.attr('data-defvals');
if ( defvals && defvals.length )
{
jQuery.each(defvals.split('|||'), function(i, val){
elem.find('option[value=\"' + val + '\"]').attr('selected', 'selected');
});
}
else elem.val('');
elem.attr('name', '".$fieldname."['+uniqueRowNum".$field->id."+']".(static::$valueIsArr ? '[]' : '')."');
elem.attr('id', '".$elementid."_'+uniqueRowNum".$field->id.");
elem.attr('data-uniqueRowNum', uniqueRowNum".$field->id.");
// Destroy any select2 elements
var sel2_elements = newField.find('div.select2-container');
if (sel2_elements.length)
{
sel2_elements.remove();
newField.find('select.use_select2_lib').select2('destroy').show();
}
")."
// Update value holder
newField.find('.fcfield_value_holder')
.attr('id', '".$valueholder_id."_'+uniqueRowNum".$field->id.")
.attr('name', '".$valueholder_nm."['+uniqueRowNum".$field->id."+']');
";
// Add new field to DOM
$js .= "
lastField ?
(insert_before ? newField.insertBefore( lastField ) : newField.insertAfter( lastField ) ) :
newField.appendTo( jQuery('#sortables_".$field->id."') ) ;
if (remove_previous) lastField.remove();
// Attach form validation on new element
fc_validationAttach(newField);
// Re-init any select2 elements
fc_attachSelect2(newField);
";
// Listen to the changes of depends-on-master field
if ($cascade_after)
{
$mvno = $single_master ? "'0'" : "rowNo";
$js .= "
fc_cascade_field_funcs['".$srcELid."_'+uniqueRowNum".$field->id."] = function(rowNo){
return function () {
fcCascadedField(".$field->id.", '".$item->id."', '".$field->field_type."', 'select#".$srcELid."_'+".$mvno."+', input.".$srcELid."_'+".$mvno.", '".$trgELid."_'+rowNo, '".htmlspecialchars( $cascade_prompt, ENT_COMPAT, 'UTF-8' )."', ".static::$promptEnabled.", rowNo);
}
}(uniqueRowNum".$field->id.");
fc_cascade_field_funcs['".$srcELid."_'+uniqueRowNum".$field->id."]();
";
}
else
{
$js .= "
jQuery('#".$elementid."_'+uniqueRowNum".$field->id.").each(function() {
var el = jQuery(this);
setTimeout(function(){
el.trigger('change');
}, 20); // >0 is enough
});
";
}
// Add new element to sortable objects (if field not in group)
if ($add_ctrl_btns) $js .= "
//jQuery('#sortables_".$field->id."').sortable('refresh'); // Refresh was done appendTo ?
";
// Show new field, increment counters
$js .="
//newField.fadeOut({ duration: 400, easing: 'swing' }).fadeIn({ duration: 200, easing: 'swing' });
if (scroll_visible) fc_scrollIntoView(newField, 1);
if (animate_visible) newField.css({opacity: 0.1}).animate({ opacity: 1 }, 800, function() { jQuery(this).css('opacity', ''); });
// Enable tooltips on new element
newField.find('.hasTooltip').tooltip({html: true, container: newField});
newField.find('.hasPopover').popover({html: true, container: newField, trigger : 'hover focus'});
rowCount".$field->id."++; // incremented / decremented
uniqueRowNum".$field->id."++; // incremented only
}
function deleteField".$field->id."(el, groupval_box, fieldval_box)
{
// Disable clicks on remove button, so that it is not reclicked, while we do the field value hide effect (before DOM removal of field value)
var btn = fieldval_box ? false : jQuery(el);
if (btn && rowCount".$field->id." > 1) btn.css('pointer-events', 'none').off('click');
// Find field value container
var row = fieldval_box ? fieldval_box : jQuery(el).closest('li');
// Add empty container if last element, instantly removing the given field value container
if(rowCount".$field->id." == 1)
addField".$field->id."(null, groupval_box, row, {remove_previous: 1, scroll_visible: 0, animate_visible: 0});
// Remove if not last one, if it is last one, we issued a replace (copy,empty new,delete old) above
if (rowCount".$field->id." > 1)
{
// Destroy the remove/add/etc buttons, so that they are not reclicked, while we do the field value hide effect (before DOM removal of field value)
row.find('.fcfield-delvalue').remove();
row.find('.fcfield-expand-view').remove();
row.find('.fcfield-insertvalue').remove();
row.find('.fcfield-drag-handle').remove();
// Do hide effect then remove from DOM
row.slideUp(400, function(){ jQuery(this).remove(); });
rowCount".$field->id."--;
}
}
";
$css .= '';
$remove_button = '<span class="' . $add_on_class . ' fcfield-delvalue ' . $font_icon_class . '" title="'.JText::_( 'FLEXI_REMOVE_VALUE' ).'" onclick="deleteField'.$field->id.'(this);"></span>';
$move2 = '<span class="' . $add_on_class . ' fcfield-drag-handle ' . $font_icon_class . '" title="'.JText::_( 'FLEXI_CLICK_TO_DRAG' ).'"></span>';
$add_here = '';
$add_here .= $add_position==2 || $add_position==3 ? '<span class="' . $add_on_class . ' fcfield-insertvalue fc_before ' . $font_icon_class . '" onclick="addField'.$field->id.'(null, jQuery(this).closest(\'ul\'), jQuery(this).closest(\'li\'), {insert_before: 1});" title="'.JText::_( 'FLEXI_ADD_BEFORE' ).'"></span> ' : '';
$add_here .= $add_position==1 || $add_position==3 ? '<span class="' . $add_on_class . ' fcfield-insertvalue fc_after ' . $font_icon_class . '" onclick="addField'.$field->id.'(null, jQuery(this).closest(\'ul\'), jQuery(this).closest(\'li\'), {insert_before: 0});" title="'.JText::_( 'FLEXI_ADD_AFTER' ).'"></span> ' : '';
}
// Field not multi-value
else
{
$remove_button = '';
$move2 = '';
$add_here = '';
$js .= '';
$css .= '';
}
// Added field's custom CSS / JS
if ($multiple) $js .= "
var uniqueRowNum".$field->id." = ".count($field->value)."; // Unique row number incremented only
var rowCount".$field->id." = ".count($field->value)."; // Counts existing rows to be able to limit a max number of values
var maxValues".$field->id." = ".$max_values.";
";
if (!$ajax && $js) $document->addScriptDeclaration($js);
if (!$ajax && $css) $document->addStyleDeclaration($css);
/**
* Handle case of FORM fields that each value is an array of values
* (e.g. selectmultiple, checkbox), and that multi-value input is also enabled
*/
$is_array_already = is_array($field->value) ? is_array(reset($field->value)) : false;
$values = static::$valueIsArr && !$multiple && !$is_array_already ? array($field->value) : $field->value;
/**
* Create field's HTML display for item form
*/
$field->html = array();
$n = $ajax ? $field->valindex : 0;
$per_val_js = '';
foreach ($values as $value)
{
// Compatibility for serialized values
if ( static::$valueIsArr )
{
if (!is_array($value))
{
$value = $this->unserialize_array($value, $force_array=true, $force_value=true);
}
}
// Make sure value is an array
if (!is_array($value))
{
$value = strlen($value) ? array($value) : array();
}
// Skip empty if not in field group, and at least one value was added
if (!count($value) && !$use_ingroup && $n) continue;
// Only if needed ...
if (!$ajax || !$display_as_select)
{
$fieldname_n = $fieldname.'['.$n.']'. (static::$valueIsArr ? '[]' : '');
$elementid_n = $elementid.'_'.$n;
}
// Get options according to cascading and according to per element state, this is here so that it works with field grouping too
$elements = $cascade_after
? $this->getLimitedProps($field, $item, !$ajax ? $cascade_prompt : null, $ajax, $n, $value)
: $this->getLimitedProps($field, $item, null, $ajax, $n, $value);
if ($display_as_select)
{
/**
* If field is sortable - and - values have been set for this field,
* then re-order elements list so that elements (select-options) for these values
* are to placed (in correct order) at the beggining options list
*/
if ($sortable && (count($value) > 1 || strlen(reset($value))))
{
// The re-ordered elements array
$elements_new = array();
// First check to see if the first child of elements is the placeholder so that it can be added before anything else
reset($elements);
if (key($elements) == '_field_selection_prompt_')
{
$elements_new['_field_selection_prompt_'] = $elements['_field_selection_prompt_'];
}
// Then iterate through selected values, figure out their index, and add these first.
foreach ($value as $v)
{
$elements_new[$v] = $elements[$v];
}
// Go through the elements array now and add any non-selected elements as options.
foreach ($elements as $v => $e)
{
if (!isset($elements_new[$v]))
{
$elements_new[$v] = $e;
}
}
// Assign the new elements array as select-options
$options = $elements_new;
}
else
{
$options = & $elements;
}
}
else
{
// Create form field options
$i = 0;
$options = array();
foreach ($elements as $element)
{
if ( !empty($element->isprompt) )
{
$options[] = '<span class="'.$element->isprompt.'">'.$element->text.'</span>';
continue;
}
$checked = (in_array($element->value, $value) ? ' checked="checked"' : '') . (in_array($element->value, $default_values) ? ' data-is-defval="1"' : '');
$elementid_no = $elementid_n.'_'.$i;
//echo " $elementid_n , $elementid_no , $fieldname_n , value: {$element->value} <br/>\n";
$input_attribs = ''; //$use_prettycheckable && $prettycheckable_added ? ' data-labelPosition="right" data-labeltext="'.$element->text.'"' : '';
if ( !empty($element->disable) )
{
$input_attribs .= ' disabled ';
}
$input_attribs .= ' class="' . $input_classes .' '. $elementid_n . '" ';
$input_fld = ' <input type="'.$fftype.'" id="'.$elementid_no.'" data-element-grpid="'.$elementid_n.'" name="'.$fieldname_n.'" '.$attribs.$input_attribs.' value="'.$element->value.'" '.$checked.' />';
$options[] = ''
.$pretext
.(!$placeInsideLabel ? $input_fld : '')
.'<label for="'.$elementid_no.'" class="'.$label_class.'" style="'.$label_style.'" '.($form_vals_display==1 ? 'title="'.@ $element->label_tip.'"' : '').'>'
. ($placeInsideLabel ? $input_fld : '') . ' '
.($form_vals_display!=1 ? JText::_($element->text) : '')
.($form_vals_display==2 ? ' <br/>' : '')
.($form_vals_display >0 ? $element->image_html : '')
.'</label>'
.$posttext
;
$i++;
}
// Apply (item form) separator and open/close tags to create the radio field
$form_field = $opentag . implode($separator, $options) . $closetag;
}
// Rendering field during initial form loading (non-AJAX)
if (!$ajax)
{
// Set order of selected values for the case that field is sortable
$this_val_attribs = '';
if ($sortable && $display_as_select)
{
$d = array();
foreach($value as $v)
{
if ( isset($options[$v]) && $v != '_field_selection_prompt_' )
{
$d[] = (object) array('id' => $options[$v]->value, 'text' => $options[$v]->text);
}
}
//$per_val_js .= 'jQuery("#'.$elementid_n.'").select2("data", '.json_encode($d).');';
$this_val_attribs .= ' data-select2-initdata = "' . htmlentities(json_encode($d), ENT_QUOTES, 'UTF-8') . '"';
}
$field->html[] = '
'.($display_as_select ?
$opentag
. JHtml::_('select.genericlist', $options, $fieldname_n, $attribs . $this_val_attribs . ' class="'.$input_classes.'" data-uniqueRowNum="'.$n.'"', 'value', 'text', $value, $elementid_n)
. ($auto_value ? '<span class="fc-mssg-inline fc-info fc-nobgimage">' . JText::_('FLEXI_AUTO') . '</span>' : '')
. $closetag :
'<div id="'.$elementid_n.'" class="' . ($use_jslib === 3 ? 'group-fcset ' : '') . 'fc_input_set">
' . $form_field . '
'.($auto_value ? '<span class="fc-mssg-inline fc-info fc-nobgimage">' . JText::_('FLEXI_AUTO') . '</span>' : '').'
</div>'
).'
'.($cascade_after ? '<span class="field_cascade_loading"></span>' : '').'
'.($use_ingroup ? '<input type="hidden" class="fcfield_value_holder" name="'.$valueholder_nm.'['.$n.']" id="'.$valueholder_id.'_'.$n.'" value="-">' : '').'
'.(!$add_ctrl_btns || $auto_value ? '' : '
<div class="'.$input_grp_class.' fc-xpended-btns">
'.$move2.'
'.$remove_button.'
'.(!$add_position ? '' : $add_here).'
</div>
');
// Listen to the changes of depends-on-master field (non-AJAX)
// NOTE: Add listening code only for value 0 if listening to single master value
if ($cascade_after)
{
$mvno = $single_master ? '0' : $n;
$per_val_js .= "
fc_cascade_field_funcs['".$srcELid.'_'.$n."'] = function(){
fcCascadedField(".$field->id.", '".$item->id."', '".$field->field_type."', 'select#".$srcELid.'_'.$mvno.", input.".$srcELid.'_'.$mvno."', '".$trgELid.'_'.$n."', '".htmlspecialchars( $cascade_prompt, ENT_COMPAT, 'UTF-8' )."', ".static::$promptEnabled.", ".$n.");
}
fc_cascade_field_funcs['".$srcELid.'_'.$n."']();
";
}
}
// Rendering field via AJAX call
else
{
$field->html = !$display_as_select ? $form_field : JHtml::_('select.options', $options, 'value', 'text', $value, $translate = false);
}
$n++;
if (!$multiple) break; // multiple values disabled, break out of the loop, not adding further values even if the exist
}
if ($per_val_js)
$document->addScriptDeclaration('
jQuery(document).ready(function(){
'.$per_val_js.'
});
');
if ($ajax)
{
// Done
return;
}
// Do not convert the array to string if field is in a group
elseif ($use_ingroup);
// Handle multiple records
elseif ($multiple)
{
$field->html = !count($field->html) ? '' :
'<li class="'.$value_classes.'">'.
implode('</li><li class="'.$value_classes.'">', $field->html).
'</li>';
$field->html = '<ul class="fcfield-sortables" id="sortables_'.$field->id.'">' .$field->html. '</ul>';
if (!$add_position) $field->html .= '
<div class="input-append input-prepend fc-xpended-btns">
<span class="fcfield-addvalue ' . $font_icon_class . ' fccleared" onclick="addField'.$field->id.'(jQuery(this).closest(\'.fc-xpended-btns\').get(0));" title="'.JText::_( 'FLEXI_ADD_TO_BOTTOM' ).'">
'.JText::_( 'FLEXI_ADD_VALUE' ).'
</span>
</div>';
}
// Handle single values
else
{
$field->html = '<div class="fcfieldval_container valuebox fcfieldval_container_'.$field->id.'">' . $field->html[0] .'</div>';
}
// For multi-value fields add configured limits
if (static::$valueIsArr)
{
// Add message box about allowed # values
if ($exact_values) {
$values_msg = '<div class="alert alert-info fc-small fc-iblock">'.JText::sprintf('FLEXI_FIELD_NUM_VALUES_EXACTLY', $exact_values) .'</div><div class="fcclear"></div>';
} else if ($max_values || $min_values > 1) {
$values_msg = '<div class="alert alert-info fc-small fc-iblock">'.JText::sprintf('FLEXI_FIELD_NUM_VALUES_BETWEEN', $min_values, $max_values) .'</div><div class="fcclear"></div>';
}
// Add VALUE message to every value if inside field group
if ( !empty($values_msg) )
{
if (!$use_ingroup) {
$field->html = $values_msg . $field->html;
} else {
foreach($field->html as & $html) $html = $values_msg . $html;
unset($html);
}
}
}
// Add ERROR message to every value if inside field group
if ( !empty($error_msg) )
{
if (!$use_ingroup) {
$field->html = $error_msg . $field->html;
} else {
foreach($field->html as & $html) $html = $error_msg . $html;
unset($html);
}
}
// Add sort message to every value if inside field group
$sortable_msg = $sortable ? '<div style="display: inline-block; vertical-align: middle; padding: 0px 4px 0px 8px;"><span class="icon-info hasTooltip" title="'.JText::_('FLEXI_FIELD_ALLOW_SORTABLE_INFO').'"></span>' . JText::_('FLEXI_ORDER') . '</div> ' : '';
if ( !empty($sortable_msg) )
{
if (!$use_ingroup) {
$field->html = $sortable_msg . $field->html;
} else {
foreach($field->html as & $html) $html = $sortable_msg . $html;
unset($html);
}
}
}
function & getLimitedProps($field, $item, $cascade_prompt=null, $ajax=false, $i=0, $row_values = array())
{
// some parameter shortcuts
$sql_mode = $field->parameters->get( 'sql_mode', 0 ) ;
$field_elements = $field->parameters->get( 'field_elements' ) ;
$cascade_after = (int)$field->parameters->get('cascade_after', 0);
$display_as_select = static::$isDropDown || (int) $field->parameters->get( 'display_as_select', 0 );
if ($cascade_after)
{
$_fields = FlexicontentFields::getFieldsByIds(array($cascade_after), array($item->id));
if (!isset($_fields[$cascade_after]))
{
return array('Master field not found');
}
$master_field = $_fields[$cascade_after];
FlexicontentFields::loadFieldConfig($master_field, $item);
$cascade_prompt = $cascade_prompt ?: JText::_('FLEXI_PLEASE_SELECT') . ' ' . JText::_('FLEXI_ABOVE');
$single_master = ! $master_field->parameters->get('use_ingroup', 0) && !$master_field->parameters->get('multiple', 0);
$valgrps = $ajax || $single_master ? $field->valgrps : (isset($field->valgrps[$i]) ? $field->valgrps[$i] : null);
// If using a multi-value per value field (checkbox / multi-select) then account for the fact that every of its values can be an array
if ($valgrps)
{
$_valgrps = array();
foreach($valgrps as $vg)
{
$_valgrps[] = is_array($vg) ? reset($vg) : $vg;
}
if ($_valgrps && !strlen($_valgrps[0]))
{
unset($_valgrps[0]);
}
$valgrps = $_valgrps;
}
if (empty($valgrps))
{
$elements = array();
if (!$ajax)
{
//$prompt = JHtml::_('select.option', (static::$valueIsArr ? '_field_selection_prompt_' : ''), $cascade_prompt, 'value', 'text', (static::$valueIsArr ? 'disabled' : null));
$prompt = (object) array(
'value' => (static::$valueIsArr ? '_field_selection_prompt_' : ''),
'text' => $cascade_prompt,
'disable' => (static::$valueIsArr ? true : null),
'isprompt' => 'fcpadded alert alert-info fc_input_set_prompt'
);
$elements = array('_field_selection_prompt_' => $prompt);
}
return $elements;
}
}
// ***
// *** Get elements, either via SQL query or via parsing the elements string
// ***
if ($sql_mode) // SQL query mode
{
$and_clause = false;
if ($cascade_after)
{
// Filter out values not in the the value group, this is done by modifying the SQL query
$db = JFactory::getDbo();
$_elements = array();
foreach($valgrps as & $vg) $vg = $db->Quote($vg);
unset($vg);
// Parse query to find column expressions used to create field's elements
$element_cols = FlexicontentFields::indexedField_getColsExprs($field, $item, $field_elements);
$and_clause = !isset($element_cols['valgrp'])
? ' 0 '
: $element_cols['valgrp'] . ' IN ('.implode(',', $valgrps).')';
}
$item_pros = true;
$elements = FlexicontentFields::indexedField_getElements($field, $item, static::$extra_props, $item_pros, false, $and_clause);
if ( !is_array($elements) )
{
//$prompt = JHtml::_('select.option', (static::$valueIsArr ? '_field_selection_prompt_' : ''), JText::_('FLEXI_FIELD_INVALID_QUERY'), 'value', 'text', (static::$valueIsArr ? 'disabled' : null));
$prompt = (object) array(
'value' => (static::$valueIsArr ? '_field_selection_prompt_' : ''),
'text' => JText::_('FLEXI_FIELD_INVALID_QUERY'),
'disable' => (static::$valueIsArr ? true : null),
'isprompt' => 'fcpadded alert alert-important'
);
$elements = array('_field_selection_prompt_' => $prompt);
return $elements;
}
}
else // Elements mode
{
$elements = FlexicontentFields::indexedField_getElements($field, $item, static::$extra_props);
if ( !is_array($elements) )
{
//$prompt = JHtml::_('select.option', (static::$valueIsArr ? '_field_selection_prompt_' : ''), JText::_('FLEXI_FIELD_INVALID_ELEMENTS'), 'value', 'text', (static::$valueIsArr ? 'disabled' : null));
$prompt = (object) array(
'value' => (static::$valueIsArr ? '_field_selection_prompt_' : ''),
'text' => JText::_('FLEXI_FIELD_INVALID_ELEMENTS'),
'disable' => (static::$valueIsArr ? true : null),
'isprompt' => 'fcpadded alert alert-important'
);
$elements = array('_field_selection_prompt_' => $prompt);
return $elements;
}
if ($cascade_after)
{
// Filter out values not in the the value group, this is done after the elements text is parsed
$_elements = array();
$_valgrps = array_flip($valgrps);
foreach($elements as $element)
{
if (isset($_valgrps[$element->valgrp]))
{
$_elements[$element->value] = $element;
}
}
$elements = $_elements;
}
}
// Filter field values according to visible elements and store them to calculate the "default" cascaded values
foreach($field->value as $v)
{
$v = is_array($v) ? reset($v) : $v;
if (isset($elements[$v]))
{
static::$cascaded_values[$field->id][] = $v;
}
}
// ***
// *** Handle element states, cloning the element objects if setting 'disable flag'
// ***
if ($field->parameters->get('use_elements_state', 0) && !empty($elements))
{
$values = array_flip($row_values);
$_elements = array();
foreach($elements as $i => $element)
{
$element->state = isset($element->state) ? $element->state : 1;
switch ($element->state)
{
case -2: // Trashed
break;
case 0: // Unpublished
case 2: // Archived
if (isset($values[$element->value]))
{
$_elements[$i] = $element;
}
break;
case 9: // Expired
if (!isset($values[$element->value]))
{
$_elements[$i] = clone($element);
$_elements[$i]->disable = true;
break;
}
case 1: // Published
default:
$_elements[$i] = $element;
break;
}
}
$elements = $_elements;
}
// ***
// *** Terminate if no useable values found
// ***
if (empty($elements))
{
//$prompt = JHtml::_('select.option', (static::$valueIsArr ? '_field_selection_prompt_' : ''), 'No data found', 'value', 'text', (static::$valueIsArr ? 'disabled' : null));
$prompt = (object) array(
'value' => (static::$valueIsArr ? '_field_selection_prompt_' : ''),
'text' => JText::_('FLEXI_FIELD_NO_DATA_FOUND'),
'disable' => (static::$valueIsArr ? true : null),
'isprompt' => 'fcpadded alert alert-warning'
);
$elements = array('_field_selection_prompt_' => $prompt);
return $elements;
}
// ***
// *** Add prompt / empty option prompt
// ***
$display_label_form = (int) $field->parameters->get( 'display_label_form', 1 ) ;
$usefirstoption = $display_label_form==-1 ? 1 : $field->parameters->get( 'usefirstoption', $display_as_select ? 1 : 0 );
$firstoptiontext = $display_label_form==-1 ? $field->label : JText::_($field->parameters->get( 'firstoptiontext', 'FLEXI_SELECT' ));
if ($usefirstoption) // Add selection prompt
{
//prompt = JHtml::_('select.option', (static::$valueIsArr ? '_field_selection_prompt_' : ''), $firstoptiontext, 'value', 'text', (static::$valueIsArr ? 'disabled' : null));
$prompt = (object) array(
'value' => (static::$valueIsArr ? '_field_selection_prompt_' : ''),
'text' => $firstoptiontext,
'disable' => (static::$valueIsArr ? true : null),
'isprompt' => 'fcpadded alert alert-info'
);
$elements = array('_field_selection_prompt_' => $prompt) + $elements;
}
// ***
// *** Handle fields that use images, like radioimage / checkboximage
// ***
if (static::$usesImages)
{
// image specific variables
$form_vals_display = $field->parameters->get( 'form_vals_display', 1 ) ; // this field includes image but it can be more convenient/compact not to be display image in item form
$image_type = (int)$field->parameters->get( 'image_type', 0 );
if ($image_type==0)
{
$imagedir = preg_replace('#^(/)*#', '', $field->parameters->get( 'imagedir' ) );
$imgpath = JUri::root(true) .'/'. $imagedir;
$imgfolder = JPATH_SITE .DS. $imagedir;
}
else {
$icon_size = (int)$field->parameters->get( 'icon_size_form' ) ;
$icon_color = $field->parameters->get( 'icon_color_form' ) ;
}
foreach ($elements as $element)
{
if ($form_vals_display > 0 && !isset($element->image_html) && empty($element->isprompt))
{
if (!$image_type)
$element->image_html = file_exists($imgfolder . $element->image) ?
'<img style="vertical-align:unset!important;" src="'.$imgpath . $element->image .'" alt="'.$element->text.'" />' :
'[NOT found]: '. $imgpath . $element->image;
else
$element->image_html = '<span style="vertical-align:unset!important; '.($icon_color ? 'color: '.$icon_color.';' : '').'" class="fcfield_radiocheck_icon '. $element->image . ($icon_size ? ' fc-icon-'.$icon_size : '').'"></span>';
}
if (!isset($element->label_tip))
$element->label_tip = flexicontent_html::getToolTip(null, $element->text, 0, 1);
}
}
return $elements;
}
// Method called via AJAX to get dependent values
function getCascadedField()
{
$jinput = JFactory::getApplication()->input;
$field_id = $jinput->getInt('field_id', 0);
$item_id = $jinput->getInt('item_id', 0);
$valgrps = $jinput->getVar('valgrps', '');
$valindex = $jinput->getInt('valindex', 0);
// Load field
$_fields = FlexicontentFields::getFieldsByIds(array($field_id), array($item_id));
$field = $_fields[$field_id];
$field->item_id = $item_id;
$field->valgrps = $valgrps;
$field->valindex = $valindex;
// Load item
$item = JTable::getInstance( $_type = 'flexicontent_items', $_prefix = '', $_config = array() );
$item->load( $item_id );
// Get field configuration
FlexicontentFields::loadFieldConfig($field, $item);
// Get field values
//$_fieldvalues = FlexicontentFields::getFieldValsById(array($field_id), array($item_id));
$field->value = null; //isset($_fieldvalues[$item_id][$field_id]) ? $_fieldvalues[$item_id][$field_id] : array();
// Render field
$field->isAjax = 1;
$this->onDisplayField($field, $item);
// Output the field
echo $field->html;
exit;
}
// Method to create field's HTML display for frontend views
public function onDisplayFieldValue(&$field, $item, $values=null, $prop='display')
{
if ( !in_array($field->field_type, static::$field_types) ) return;
$field->label = JText::_($field->label);
// Set field and item objects
$this->setField($field);
$this->setItem($item);
$field->isIndexedfield = true;
/**
* One time initialization
*/
static $initialized = null;
static $app, $document, $option, $format, $realview;
if ($initialized === null)
{
$initialized = 1;
$app = JFactory::getApplication();
$document = JFactory::getDocument();
$option = $app->input->getCmd('option', '');
$format = $app->input->getCmd('format', 'html');
$realview = $app->input->getCmd('view', '');
}
// The current view is a full item view of the item
$isMatchedItemView = static::$itemViewId === (int) $item->id;
// Current view variable
$view = $app->input->getCmd('flexi_callview', ($realview ?: 'item'));
$sfx = $view === 'item' ? '' : '_cat';
// Check if field should be rendered according to configuration
if (!$this->checkRenderConds($prop, $view))
{
return;
}
// Some variables
$is_ingroup = !empty($field->ingroup);
$use_ingroup = $field->parameters->get('use_ingroup', 0);
$multiple = $use_ingroup || (int) $field->parameters->get( 'allow_multiple', 0 ) ;
// Check for no values and not displaying ALL elements
$display_all = $field->parameters->get( 'display_all', 0 ) && !$is_ingroup; // NOT supported inside fielgroup yet
$display_all = $prop === 'csv_export' || $realview === 'itemcompare' ? 0 : $display_all;
/**
* Get field values
*/
$values = $values ? $values : $field->value;
if (empty($values) && !$display_all)
{
// Default value
$values = $this->getDefaultValues($isform = false);
if (!count($values))
{
$field->{$prop} = $is_ingroup ? array() : '';
$field->display_index = $is_ingroup ? array() : '';
return;
}
}
// Value creation
$sql_mode = $field->parameters->get( 'sql_mode', 0 ) ;
$field_elements = $field->parameters->get( 'field_elements', '' ) ;
$text_or_value = (int) $field->parameters->get( 'text_or_value', (static::$usesImages ? 2 : 1) ) ;
$text_or_value = $realview === 'itemcompare' ? 1 : $text_or_value;
$tooltip_class = 'hasTooltip';
// image specific or image related variables
if (static::$usesImages)
{
$imagedir = preg_replace('#^(/)*#', '', $field->parameters->get( 'imagedir' ) );
$imgpath = JUri::root(true) .'/'. $imagedir;
$image_type = (int)$field->parameters->get( 'image_type', 0 ) ;
$icon_size = (int)$field->parameters->get( 'icon_size', $field->parameters->get( 'icon_size_form') ) ;
$icon_color = $field->parameters->get( 'icon_color', $field->parameters->get( 'icon_color_form') ) ;
}
// Cleaner output for CSV export
if ($prop === 'csv_export')
{
$separatorf = ', ';
$itemprop = false;
}
// Get indexed element values
$elements = FlexicontentFields::indexedField_getElements($field, $item, static::$extra_props);
// Allow access to elements into layouts
$field->elements = & $elements;
// Check for no elements found
if (!$elements)
{
$error_text = $sql_mode
? JText::_('FLEXI_FIELD_INVALID_QUERY')
: JText::_('FLEXI_FIELD_INVALID_ELEMENTS');
$field->{$prop} = $is_ingroup ? array($error_text) : $error_text;
$field->display_index = $is_ingroup ? array() : '';
return;
}
/**
* Handle case of FORM fields that each value is an array of values
* (e.g. selectmultiple, checkbox), and that multi-value input is also enabled
* we make sure that values should be an array of arrays
*/
$is_2lvl_arr = false;
if (is_array($values))
{
$v = reset($values);
$is_2lvl_arr = is_array($v);
}
$values = ($multiple && static::$valueIsArr) || $is_2lvl_arr
? $values
: array($values);
if (!$values)
{
$values = array();
}
/**
* Get common parameters like: itemprop, value's prefix (pretext), suffix (posttext), separator, value list open/close text (opentag, closetag)
* This will also replacing other field values if such replacing text for field values is found
*/
$common_params_array = $this->getCommonParams();
extract($common_params_array);
// Get layout name
$viewlayout = $field->parameters->get('viewlayout', '');
$viewlayout = $viewlayout ? 'value_'.$viewlayout : 'value_default';
// Create field's viewing HTML, using layout file
$field->{$prop} = array();
$display_index = array();
include(self::getViewPath($field->field_type, $viewlayout));
// Add microdata to every group of values if field -- is -- in a field group
if ($is_ingroup && $itemprop && $prop !== 'csv_export')
{
foreach($field->{$prop} as $n => $disp_html)
{
$field->{$prop}[$n] = '<div style="display:inline" itemprop="'.$itemprop.'" >' .$field->{$prop}[$n]. '</div>';
}
}
// Do not convert the array to string if field is in a group, and do not add: FIELD's opentag, closetag, value separator
if (!$is_ingroup)
{
// Values separator, field 's opening / closing texts, were already applied for every array of values
if ($multiple && static::$valueIsArr)
{
$sep = $prop !== 'csv_export' ? '' : ' -- ';
$field->{$prop} = implode($sep, $field->{$prop});
$field->display_index = implode($sep, $display_index);
}
// Apply values separator, and field 's opening / closing texts
else
{
$field->{$prop} = !count($field->{$prop}) ? '' : $opentag . implode($separatorf, $field->{$prop}) . $closetag;
$field->display_index = !count($display_index) ? '' : $opentag . implode($separatorf, $display_index) . $closetag;
}
// Add microdata once for all values, if field -- is NOT -- in a field group
if ( $field->{$prop}!=='' && $itemprop )
{
$field->{$prop} = '<div style="display:inline" itemprop="'.$itemprop.'" >' .$field->{$prop}. '</div>';
}
}
}
// ***
// *** METHODS HANDLING before & after saving / deleting field events
// ***
// Method to handle field's values before they are saved into the DB
public function onBeforeSaveField( &$field, &$post, &$file, &$item )
{
if ( !in_array($field->field_type, static::$field_types) ) return;
$use_ingroup = $field->parameters->get('use_ingroup', 0);
if ( !is_array($post) && !strlen($post) && !$use_ingroup ) return;
$max_values = $use_ingroup ? 0 : (int) $field->parameters->get( 'max_values', 0 ) ;
$multiple = $use_ingroup || (int) $field->parameters->get( 'allow_multiple', 0 ) ;
$is_importcsv = JFactory::getApplication()->get('task', '', 'cmd') == 'importcsv';
$field->use_suborder = $multiple && static::$valueIsArr;
// Make sure posted data is an array
$post = !is_array($post) ? array($post) : $post;
// Make sure every value is an array (for multi-value per value fields)
if (static::$valueIsArr)
{
$v = reset($post); // Get first value to examine it below (by attempting unserialize) and forcing an array
if (!is_array($v))
{
// An array of arrays
$array = $this->unserialize_array($v, $force_array=false, $force_value=false);
$post = $array===false ? array($post) : $post;
}
}
// Account for fact that ARRAY form elements are not submitted if they do not have a value
if ( $use_ingroup )
{
$empty_value = static::$valueIsArr ? array() : null;
$custom = JFactory::getApplication()->input->get('custom', array(), 'array');
if (isset($custom['_fcfield_valueholder_'][$field->name]))
{
$holders = $custom['_fcfield_valueholder_'][$field->name];
$vals = array();
foreach($holders as $i => $v)
{
$vals[] = isset($post[(int)$i])
? $post[(int)$i]
: $empty_value;
}
$post = $vals;
}
}
// Reformat the posted data
$newpost = array();
$new = 0;
$elements = FlexicontentFields::indexedField_getElements($field, $item, static::$extra_props);
foreach ($post as $n => $v)
{
// Non multi-value per value fields, have only 1 value, convert it to single record array to use same code below
if (!static::$valueIsArr)
{
$v = array($v);
}
// Support for serialized user data, e.g. basic CSV import / export. (Safety concern: objects code will abort unserialization!)
elseif ($is_importcsv && !is_array($v))
{
$v = $this->unserialize_array($v, $force_array=true, $force_value=true);
}
// Do server-side validation and skip empty/invalid values
$vals = array();
foreach ($v as $i => $nv)
{
$element = !strlen($nv) ? false : @$elements[$nv];
if ( $element ) $vals[] = $nv; // include only valid value
}
// Skip empty value, but if in group increment the value position
if (!count($vals))
{
if ($use_ingroup) $newpost[$new++] = static::$valueIsArr ? array() : null;
continue;
}
// If multiple disabled, use 1st value ARRAY only (for multi-value per value fields)
if (static::$valueIsArr && !$multiple)
{
$newpost = $vals;
break;
}
$newpost[$new] = static::$valueIsArr ? $vals : reset($vals);
$new++;
// If multiple disabled, do not add more values
if (!static::$valueIsArr && !$multiple) break;
// max values limitation (*if in group, this was zeroed above)
if ($max_values && $new >= $max_values) continue;
}
$post = $newpost;
//if ($use_ingroup) JFactory::getApplication()->enqueueMessage( print_r($post, true), 'warning');
}
/**
* Method to do extra handling of field's values after all fields have validated their posted data, and are ready to be saved
*
* $item->fields['fieldname']->postdata contains values of other fields
* $item->fields['fieldname']->filedata contains files of other fields (normally this is empty due to using AJAX for file uploading)
*/
public function onAllFieldsPostDataValidated(&$field, &$item)
{
if ( !in_array($field->field_type, static::$field_types) ) return;
/**
* Check if using 'auto_value_code', clear 'auto_value', if function not set
*/
$auto_value = (int) $field->parameters->get('auto_value', 0);
if ($auto_value === 2)
{
$auto_value_code = $field->parameters->get('auto_value_code', '');
$auto_value_code = preg_replace('/^<\?php(.*)(\?>)?$/s', '$1', $auto_value_code);
}
$auto_value = $auto_value === 2 && !$auto_value_code ? 0 : $auto_value;
if (!$auto_value)
{
return;
}
if (!self::$fcProPlg)
{
JFactory::getApplication()->enqueueMessage('Automatic field value for field \'' . $field->label . '\' is only supported by FLEXIcontent PRO version, please disable this feature in field configuration', 'notice');
return;
}
// Create automatic value
return self::$fcProPlg->onAllFieldsPostDataValidated($field, $item);
}
// Method to take any actions/cleanups needed after field's values are saved into the DB
public function onAfterSaveField( &$field, &$post, &$file, &$item )
{
if ( !in_array($field->field_type, static::$field_types) ) return;
}
// Method called just before the item is deleted to remove custom item data related to the field
public function onBeforeDeleteField(&$field, &$item)
{
if ( !in_array($field->field_type, static::$field_types) ) return;
}
// ***
// *** CATEGORY/SEARCH FILTERING METHODS
// ***
// Method to display a search filter for the advanced search view
public function onAdvSearchDisplayFilter(&$filter, $value='', $formName='searchForm')
{
if ( !in_array($filter->field_type, static::$field_types) ) return;
$this->onDisplayFilter($filter, $value, $formName, $isSearchView=1);
}
// Method to display a category filter for the category view
function onDisplayFilter(&$filter, $value='', $formName='adminForm', $isSearchView=0)
{
if ( !in_array($filter->field_type, static::$field_types) ) return;
// Get indexed element values
$item_pros = false;
$elements = FlexicontentFields::indexedField_getElements($filter, $item=null, static::$extra_props, $item_pros, $is_filter=true);
// ***
// *** Handle display for fields that use images, like radioimage / checkboximage
// ***
if (static::$usesImages)
{
$_s = $isSearchView ? '_s' : '';
$filter_vals_display = $filter->parameters->get( 'filter_vals_display'.$_s, 0 );
$filter_as_images = in_array($filter_vals_display, array(1,2)) ;
$image_type = (int)$filter->parameters->get( 'image_type', 0 );
if ($filter_as_images && $elements && !$image_type)
{
// image specific variables
$imagedir = preg_replace('#^(/)*#', '', $filter->parameters->get( 'imagedir' ) );
$imgpath = JUri::root(true) .'/'. $imagedir;
foreach($elements as $element) {
$element->image_url = $imgpath . $element->image;
}
}
}
// Check for error during getting indexed field elements
if ( !$elements ) {
$filter->html = '';
$sql_mode = $filter->parameters->get( 'sql_mode', 0 ); // must retrieve variable here, and not before retrieving elements !
if ($sql_mode && $item_pros > 0)
$filter->html = sprintf( JText::_('FLEXI_FIELD_ITEM_SPECIFIC_AS_FILTERABLE'), $filter->label );
else if ($sql_mode)
$filter->html = JText::_('FLEXI_FIELD_INVALID_QUERY');
else
$filter->html = JText::_('FLEXI_FIELD_INVALID_ELEMENTS');
return;
}
FlexicontentFields::createFilter($filter, $value, $formName, $elements);
}
// Method to get the active filter result (an array of item ids matching field filter, or subquery returning item ids)
// This is for content lists e.g. category view, and not for search view
public function getFiltered(&$filter, $value, $return_sql = true)
{
if ( !in_array($filter->field_type, static::$field_types) ) return;
return FlexicontentFields::getFiltered($filter, $value, $return_sql);
}
// Method to get the active filter result (an array of item ids matching field filter, or subquery returning item ids)
// This is for search view
public function getFilteredSearch(&$filter, $value, $return_sql = true)
{
if ( !in_array($filter->field_type, static::$field_types) ) return;
$filter->isindexed = true;
return FlexicontentFields::getFilteredSearch($filter, $value, $return_sql);
}
// ***
// *** SEARCH / INDEXING METHODS
// ***
// Method to create (insert) advanced search index DB records for the field values
public function onIndexAdvSearch(&$field, &$post, &$item)
{
if ( !in_array($field->field_type, static::$field_types) ) return;
if ( !$field->isadvsearch && !$field->isadvfilter ) return;
$field->isindexed = true;
$field->extra_props = static::$extra_props;
FlexicontentFields::onIndexAdvSearch($field, $post, $item, $required_properties=array(), $search_properties=array('text'), $properties_spacer=' ', $filter_func=null);
return true;
}
// Method to create basic search index (added as the property field->search)
public function onIndexSearch(&$field, &$post, &$item)
{
if ( !in_array($field->field_type, static::$field_types) ) return;
if ( !$field->issearch ) return;
$field->isindexed = true;
$field->extra_props = static::$extra_props;
FlexicontentFields::onIndexSearch($field, $post, $item, $required_properties=array(), $search_properties=array('text'), $properties_spacer=' ', $filter_func=null);
return true;
}
// ***
// *** VARIOUS HELPER METHODS
// ***
// Method to get default values of an indexed field
protected function getDefaultValues($isform = true, $translate = false, $split = ',')
{
$class_name = 'plgflexicontent_fields' . ucfirst($this->field->field_type);
if (!class_exists($class_name))
{
JPluginHelper::getPlugin('flexicontent_fields', $this->field->field_type);
}
$value_usage = (int) $this->field->parameters->get('default_value_use', 0);
$split = $class_name::$valueIsArr ? $split : '';
$translate = false;
return parent::getDefaultValues($isform, $translate, $split);
}
}