コード例 #1
0
    function onDisplayField(&$field, &$item)
    {
        if (!in_array($field->field_type, self::$field_types)) {
            return;
        }
        $field->label = JText::_($field->label);
        $use_ingroup = $field->parameters->get('use_ingroup', 0);
        $ajax = !empty($field->isAjax);
        if ($use_ingroup) {
            $field->formhidden = 3;
        }
        if ($use_ingroup && empty($field->ingroup) && !$ajax) {
            return;
        }
        // initialize framework objects and other variables
        $document = JFactory::getDocument();
        // 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);
        // ****************
        // Number of values
        // ****************
        $multiple = $use_ingroup || (int) $field->parameters->get('allow_multiple', 0);
        $max_values = $use_ingroup ? 0 : (int) $field->parameters->get('max_values', 0);
        $required = $field->parameters->get('required', 0);
        $required = $required ? ' required' : '';
        $add_position = (int) $field->parameters->get('add_position', 3);
        // **************
        // Value handling
        // **************
        // Default value
        $value_usage = $field->parameters->get('default_value_use', 0);
        $default_value = $item->version == 0 || $value_usage > 0 ? trim($field->parameters->get('default_value', '')) : '';
        // *************************
        // Input field configuration
        // *************************
        // DISPLAY using prettyCheckable JS
        $use_jslib = $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');
        }
        // Display text label, use checkbox/radio image field for more
        $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
        // when field is displayed as drop-down select (item edit form only)
        $firstoptiontext = $field->parameters->get('firstoptiontext', 'FLEXI_SELECT');
        $usefirstoption = $field->parameters->get('usefirstoption', 1);
        // 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);
        $opentag = $field->parameters->get('opentag_form', '');
        $closetag = $field->parameters->get('closetag_form', '');
        switch ($separator) {
            case 0:
                $separator = ' ';
                break;
            case 1:
                $separator = '<br />';
                break;
            case 2:
                $separator = '&nbsp;|&nbsp;';
                break;
            case 3:
                $separator = ',&nbsp;';
                break;
            case 4:
                $separator = $closetag . $opentag;
                break;
            default:
                $separator = '&nbsp;';
                break;
        }
        // Initialise property with default value
        if (!$field->value) {
            $field->value = array($default_value);
        }
        // CSS classes of value container
        $value_classes = 'fcfieldval_container valuebox fcfieldval_container_' . $field->id;
        // 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;
        $js = "";
        $css = "";
        // *********************************************************************************************
        // Handle adding the needed JS code to CASCADE (listen to) changes of the dependent master field
        // *********************************************************************************************
        if ($cascade_after && !$ajax) {
            $byIds = FlexicontentFields::indexFieldsByIds($item->fields);
            if (isset($byIds[$cascade_after])) {
                $cascade_prompt = $field->parameters->get('cascade_prompt', '');
                $cascade_prompt = $cascade_prompt ? JText::_($cascade_prompt) : JText::_('FLEXI_PLEASE_SELECT') . ': ' . $byIds[$cascade_after]->label;
                $srcELid = 'custom_' . $byIds[$cascade_after]->name;
                $trgELid = $elementid;
                // Get values of cascade (on) source field
                $field->valgrps = $byIds[$cascade_after]->value ? $byIds[$cascade_after]->value : array();
                foreach ($field->valgrps as &$vg) {
                    if (is_array($vg)) {
                    } else {
                        if (@unserialize($vg) !== false || $vg === 'b:0;') {
                            $vg = unserialize($vg);
                        } else {
                            $vg = array($vg);
                        }
                    }
                }
                unset($vg);
            } else {
                $cascade_after = 0;
                echo 'Error in field ' . $field->label . ' [' . $field->id . ']' . ' cannot cascaded after field no: ' . $cascade_after . ', field was not found <br/>';
            }
        } 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 (!$use_ingroup) {
                $js .= "\n\t\t\tjQuery(document).ready(function(){\n\t\t\t\tjQuery('#sortables_" . $field->id . "').sortable({\n\t\t\t\t\thandle: '.fcfield-drag-handle',\n\t\t\t\t\tcontainment: 'parent',\n\t\t\t\t\ttolerance: 'pointer'\n\t\t\t\t});\n\t\t\t});\n\t\t\t";
            }
            if ($max_values) {
                JText::script("FLEXI_FIELD_MAX_ALLOWED_VALUES_REACHED", true);
            }
            $js .= "\n\t\t\tvar uniqueRowNum" . $field->id . "\t= " . count($field->value) . ";  // Unique row number incremented only\n\t\t\tvar rowCount" . $field->id . "\t= " . count($field->value) . ";      // Counts existing rows to be able to limit a max number of values\n\t\t\tvar maxValues" . $field->id . " = " . $max_values . ";\n\t\t\t\n\t\t\tfunction addField" . $field->id . "(el, groupval_box, fieldval_box, params)\n\t\t\t{\n\t\t\t\tvar insert_before   = (typeof params!== 'undefined' && typeof params.insert_before   !== 'undefined') ? params.insert_before   : 0;\n\t\t\t\tvar remove_previous = (typeof params!== 'undefined' && typeof params.remove_previous !== 'undefined') ? params.remove_previous : 0;\n\t\t\t\tvar scroll_visible  = (typeof params!== 'undefined' && typeof params.scroll_visible  !== 'undefined') ? params.scroll_visible  : 1;\n\t\t\t\tvar animate_visible = (typeof params!== 'undefined' && typeof params.animate_visible !== 'undefined') ? params.animate_visible : 1;\n\t\t\t\t\n\t\t\t\tif((rowCount" . $field->id . " >= maxValues" . $field->id . ") && (maxValues" . $field->id . " != 0)) {\n\t\t\t\t\talert(Joomla.JText._('FLEXI_FIELD_MAX_ALLOWED_VALUES_REACHED') + maxValues" . $field->id . ");\n\t\t\t\t\treturn 'cancel';\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Find last container of fields and clone it to create a new container of fields\n\t\t\t\tvar lastField = fieldval_box ? fieldval_box : jQuery(el).prev().children().last();\n\t\t\t\tvar newField  = lastField.clone();\n\t\t\t\t\n\t\t\t\t// Remove HTML added by prettyCheckable JS, from the dupicate new INPUT SET\n\t\t\t\tvar prettyContainers = newField.find('.prettyradio, .prettycheckbox');\n\t\t\t\tprettyContainers.find('input, label').each(function() {\n\t\t\t\t\tvar el = jQuery(this);\n\t\t\t\t\tel.insertAfter(el.parent());\n\t\t\t\t});\n\t\t\t\tprettyContainers.remove();\n\t\t\t\t\n\t\t\t\t// Update value holder\n\t\t\t\tnewField.find('.fcfield_value_holder')\n\t\t\t\t\t.attr('id', '" . $valueholder_id . "_'+uniqueRowNum" . $field->id . ")\n\t\t\t\t\t.attr('name', '" . $valueholder_nm . "['+uniqueRowNum" . $field->id . "+']');\n\t\t\t\t\n\t\t\t\t// Update INPUT SET container id\n\t\t\t\tnewField.find('.fc_input_set').attr('id', '" . $elementid . "_'+uniqueRowNum" . $field->id . ");\n\t\t\t\tvar js_class = '" . ($use_prettycheckable && $prettycheckable_added ? ' use_prettycheckable' : '') . "';\n\t\t\t\t\n\t\t\t\t// Update the new INPUT SET\n\t\t\t\tvar theSet = newField.find('input:radio, input:checkbox');\n\t\t\t\t//if(window.console) window.console.log('theSet.length: ' + theSet.length);\n\t\t\t\tvar nr = 0;\n\t\t\t\ttheSet.each(function() {\n\t\t\t\t\tvar elem = jQuery(this);\n\t\t\t\t\telem.attr('name', '" . $fieldname . "['+uniqueRowNum" . $field->id . "+']" . (self::$valueIsArr ? '[]' : '') . "');\n\t\t\t\t\telem.attr('id', '" . $elementid . "_'+uniqueRowNum" . $field->id . "+'_'+nr);\n\t\t\t\t\telem.attr('class', '" . $elementid . "_'+uniqueRowNum" . $field->id . " + js_class);\n\t\t\t\t\telem.removeAttr('checked');\n\t\t\t\t\t" . ($use_prettycheckable && $prettycheckable_added ? "elem.attr('data-element-grpid', '" . $elementid . "_'+uniqueRowNum" . $field->id . ");" : "elem.attr('data-element-grpid', '" . $elementid . "_'+uniqueRowNum" . $field->id . ");") . "\n\t\t\t\t\t" . ($use_prettycheckable && $prettycheckable_added ? "elem.prev('label').attr('for', '" . $elementid . "_'+uniqueRowNum" . $field->id . "+'_'+nr);" : "elem.next('label').attr('for', '" . $elementid . "_'+uniqueRowNum" . $field->id . "+'_'+nr);") . "\n\t\t\t\t\tnr++;\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\t// Reapply prettyCheckable JS \n\t\t\t\tnewField.find('.use_prettycheckable').each(function() {\n\t\t\t\t\tvar elem = jQuery(this);\n\t\t\t\t\tvar lbl = elem.prev('label');\n\t\t\t\t\tvar lbl_html = lbl.html();\n\t\t\t\t\tlbl.remove();\n\t\t\t\t\telem.prettyCheckable({ label: lbl_html });\n\t\t\t\t});\n\t\t\t\t";
            // Add new field to DOM
            $js .= "\n\t\t\t\tlastField ?\n\t\t\t\t\t(insert_before ? newField.insertBefore( lastField ) : newField.insertAfter( lastField ) ) :\n\t\t\t\t\tnewField.appendTo( jQuery('#sortables_" . $field->id . "') ) ;\n\t\t\t\tif (remove_previous) lastField.remove();\n\t\t\t\t";
            // Listen to the changes of cascade-after field
            if ($cascade_after) {
                $js .= "\n\t\t\t\tfc_cascade_field_funcs['" . $srcELid . "_'+uniqueRowNum" . $field->id . "] = function(rowNo){\n\t\t\t\t\treturn function () {\n\t\t\t\t\t\tfcCascadedField(" . $field->id . ", '" . $item->id . "', '" . $field->field_type . "', 'select#" . $srcELid . "_'+rowNo+', input." . $srcELid . "_'+rowNo, '" . $trgELid . "_'+rowNo, '" . $cascade_prompt . "', " . self::$promptEnabled . ", rowNo);\n\t\t\t\t\t}\n\t\t\t\t}(uniqueRowNum" . $field->id . ");\n\t\t\t\tfc_cascade_field_funcs['" . $srcELid . "_'+uniqueRowNum" . $field->id . "]();\n\t\t\t\t";
            }
            // Add new element to sortable objects (if field not in group)
            if (!$use_ingroup) {
                $js .= "\n\t\t\t\t//jQuery('#sortables_" . $field->id . "').sortable('refresh');  // Refresh was done appendTo ?\n\t\t\t\t";
            }
            // Show new field, increment counters
            $js .= "\n\t\t\t\t//newField.fadeOut({ duration: 400, easing: 'swing' }).fadeIn({ duration: 200, easing: 'swing' });\n\t\t\t\tif (scroll_visible) fc_scrollIntoView(newField, 1);\n\t\t\t\tif (animate_visible) newField.css({opacity: 0.1}).animate({ opacity: 1 }, 800);\n\t\t\t\t\n\t\t\t\t// Enable tooltips on new element\n\t\t\t\tnewField.find('.hasTooltip').tooltip({'html': true,'container': newField});\n\t\t\t\t\n\t\t\t\trowCount" . $field->id . "++;       // incremented / decremented\n\t\t\t\tuniqueRowNum" . $field->id . "++;   // incremented only\n\t\t\t}\n\n\t\t\tfunction deleteField" . $field->id . "(el, groupval_box, fieldval_box)\n\t\t\t{\n\t\t\t\t// Find field value container\n\t\t\t\tvar row = fieldval_box ? fieldval_box : jQuery(el).closest('li');\n\t\t\t\t\n\t\t\t\t// Add empty container if last element, instantly removing the given field value container\n\t\t\t\tif(rowCount" . $field->id . " == 1)\n\t\t\t\t\taddField" . $field->id . "(null, groupval_box, row, {remove_previous: 1, scroll_visible: 0, animate_visible: 0});\n\t\t\t\t\n\t\t\t\t// Remove if not last one, if it is last one, we issued a replace (copy,empty new,delete old) above\n\t\t\t\tif(rowCount" . $field->id . " > 1) {\n\t\t\t\t\t// Destroy the remove/add/etc buttons, so that they are not reclicked, while we do the hide effect (before DOM removal of field value)\n\t\t\t\t\trow.find('.fcfield-delvalue').remove();\n\t\t\t\t\trow.find('.fcfield-insertvalue').remove();\n\t\t\t\t\trow.find('.fcfield-drag-handle').remove();\n\t\t\t\t\t// Do hide effect then remove from DOM\n\t\t\t\t\trow.slideUp(400, function(){ jQuery(this).remove(); });\n\t\t\t\t\trowCount" . $field->id . "--;\n\t\t\t\t}\n\t\t\t}\n\t\t\t";
            $css .= '';
            $remove_button = '<span class="fcfield-delvalue' . (JComponentHelper::getParams('com_flexicontent')->get('form_font_icons', 1) ? ' fcfont-icon' : '') . '" title="' . JText::_('FLEXI_REMOVE_VALUE') . '" onclick="deleteField' . $field->id . '(this);"></span>';
            $move2 = '<span class="fcfield-drag-handle' . (JComponentHelper::getParams('com_flexicontent')->get('form_font_icons', 1) ? ' fcfont-icon' : '') . '" title="' . JText::_('FLEXI_CLICK_TO_DRAG') . '"></span>';
            $add_here = '';
            $add_here .= $add_position == 2 || $add_position == 3 ? '<span class="fcfield-insertvalue fc_before' . (JComponentHelper::getParams('com_flexicontent')->get('form_font_icons', 1) ? ' fcfont-icon' : '') . '" 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="fcfield-insertvalue fc_after' . (JComponentHelper::getParams('com_flexicontent')->get('form_font_icons', 1) ? ' fcfont-icon' : '') . '"  onclick="addField' . $field->id . '(null, jQuery(this).closest(\'ul\'), jQuery(this).closest(\'li\'), {insert_before: 0});" title="' . JText::_('FLEXI_ADD_AFTER') . '"></span> ' : '';
        } else {
            $remove_button = '';
            $move2 = '';
            $add_here = '';
            $js .= '';
            $css .= '';
        }
        // Added field's custom CSS / JS
        if (!$ajax && $js) {
            $document->addScriptDeclaration($js);
        }
        if (!$ajax && $css) {
            $document->addStyleDeclaration($css);
        }
        // **************************
        // Get indexed element values
        // **************************
        // If cascading we will get it inside the value loop for every value, thus supporting field grouping properly
        $elements = !$cascade_after ? $this->getLimitedProps($field, $item) : array();
        if (!is_array($elements)) {
            $field->html = $elements;
            return;
        }
        // *****************************************
        // Create field's HTML display for item form
        // *****************************************
        // Alternative form field display as drop-down select to save space
        if ($field->parameters->get('display_as_select', 0)) {
            $options = array();
            if ($usefirstoption) {
                $options[] = JHTML::_('select.option', '', JText::_($firstoptiontext));
            }
            foreach ($elements as $element) {
                $options[] = JHTML::_('select.option', $element->value, $element->text);
            }
            $field->html = JHTML::_('select.genericlist', $options, $fieldname, 'class="' . $required . '"', 'value', 'text', $field->value, $elementid);
            return;
        }
        // Create the attributes of the form field
        $fftype = 'radio';
        $display_as_radioset = 1;
        if ($display_as_radioset) {
            $classes = $use_prettycheckable && $prettycheckable_added ? ' use_prettycheckable ' : '';
            $classes .= $required;
            $onchange = '';
            // Extra properties
            $attribs = '';
            if ($required) {
                $classes .= ' validate-radio ';
            }
            // if required then set appropriate validate-* CSS class (*=handler name)
            if ($onchange) {
                $attribs .= ' onchange="' . $onchange . '" ';
            }
        }
        $label_class = 'fccheckradio_lbl' . (FLEXI_J30GE ? ' hasTooltip' : ' hasTip');
        $label_style = 'vertical-align: unset!important;';
        // 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 = self::$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 (self::$valueIsArr) {
                if (is_array($value)) {
                } else {
                    if (@unserialize($value) !== false || $value === 'b:0;') {
                        $value = unserialize($value);
                    }
                }
            }
            // 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;
            }
            // Get options according to cascading, this is here so that it works with field grouping too
            if ($cascade_after) {
                $elements = $this->getLimitedProps($field, $item, !$ajax ? $cascade_prompt : null, $ajax, $n);
            }
            if (1) {
                $fieldname_n = $fieldname . '[' . $n . ']' . (self::$valueIsArr ? '[]' : '');
                $elementid_n = $elementid . '_' . $n;
                // Create form field options
                $i = 0;
                $options = array();
                foreach ($elements as $element) {
                    if (!empty($element->isprompt)) {
                        $options[] = '<span style="float: left;" class="' . $element->isprompt . '">' . $element->text . '</span>';
                        continue;
                    }
                    $checked = in_array($element->value, $value) ? ' checked="checked"' : '';
                    $elementid_no = $elementid_n . '_' . $i;
                    //echo " &nbsp; &nbsp; $elementid_n , $elementid_no , $fieldname_n  , &nbsp; value: {$element->value} <br/>\n";
                    $input_attribs = $use_prettycheckable && $prettycheckable_added ? ' data-customClass="fcradiocheckimage"' : '';
                    $input_attribs .= ' class="' . @$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 . ($use_prettycheckable && $prettycheckable_added ? $input_fld : '') . '<label for="' . $elementid_no . '" class="' . $label_class . '" style="' . $label_style . '" title="' . $element->label_tip . '">' . (!$use_prettycheckable || !$prettycheckable_added ? $input_fld : '') . ($form_vals_display != 1 ? $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;
            }
            if (!$ajax) {
                $field->html[] = '
					' . '<div id="' . $elementid_n . '" class="fc_input_set">' . $form_field . '</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="-">' : '') . '
					' . ($use_ingroup ? '' : $move2) . '
					' . ($use_ingroup ? '' : $remove_button) . '
					' . ($use_ingroup || !$add_position ? '' : $add_here) . '
					';
                // Listen to the changes of cascade-after field
                if ($cascade_after && !$ajax) {
                    $per_val_js .= "\n\t\t\t\t\tfc_cascade_field_funcs['" . $srcELid . '_' . $n . "'] = function(){\n\t\t\t\t\t\tfcCascadedField(" . $field->id . ", '" . $item->id . "', '" . $field->field_type . "', 'select#" . $srcELid . '_' . $n . ", input." . $srcELid . '_' . $n . "', '" . $trgELid . '_' . $n . "', '" . $cascade_prompt . "', " . self::$promptEnabled . ", " . $n . ");\n\t\t\t\t\t}\n\t\t\t\t\tfc_cascade_field_funcs['" . $srcELid . '_' . $n . "']();\n\t\t\t\t";
                }
            } else {
                $field->html = $form_field;
            }
            $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) {
            return;
            // Done
        } else {
            if ($use_ingroup) {
                // do not convert the array to string if field is in a group
            } else {
                if ($multiple) {
                    // handle multiple records
                    $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 .= '<span class="fcfield-addvalue ' . (JComponentHelper::getParams('com_flexicontent')->get('form_font_icons', 1) ? ' fcfont-icon' : '') . '" onclick="addField' . $field->id . '(this);" title="' . JText::_('FLEXI_ADD_TO_BOTTOM') . '">' . JText::_('FLEXI_ADD_VALUE') . '</span>';
                    }
                } else {
                    // handle single values
                    $field->html = '<div class="fcfieldval_container valuebox fcfieldval_container_' . $field->id . '">' . $field->html[0] . '</div>';
                }
            }
        }
    }
コード例 #2
0
    function onDisplayField(&$field, &$item)
    {
        if (!in_array($field->field_type, self::$field_types)) {
            return;
        }
        $field->label = JText::_($field->label);
        $use_ingroup = $field->parameters->get('use_ingroup', 0);
        $ajax = !empty($field->isAjax);
        if ($use_ingroup) {
            $field->formhidden = 3;
        }
        if ($use_ingroup && empty($field->ingroup) && !$ajax) {
            return;
        }
        // initialize framework objects and other variables
        $document = JFactory::getDocument();
        // 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);
        // ****************
        // Number of values
        // ****************
        $multiple = $use_ingroup || (int) $field->parameters->get('allow_multiple', 0);
        $max_values = $use_ingroup ? 0 : (int) $field->parameters->get('max_values', 0);
        $required = $field->parameters->get('required', 0);
        $required = $required ? ' required' : '';
        $add_position = (int) $field->parameters->get('add_position', 3);
        // **************
        // Value handling
        // **************
        // Default value
        $value_usage = $field->parameters->get('default_value_use', 0);
        $default_value = $item->version == 0 || $value_usage > 0 ? trim($field->parameters->get('default_value', '')) : '';
        // *************************
        // Input field configuration
        // *************************
        // DISPLAY using select2 JS
        $use_jslib = $field->parameters->get('use_jslib', 1);
        $use_select2 = $use_jslib == 1;
        static $select2_added = null;
        if ($use_select2 && $select2_added === null) {
            $select2_added = flexicontent_html::loadFramework('select2');
        }
        // Parameters for DISPLAY with / without using select2 JS
        // ... none such parameters
        // Custom HTML placed before / after form field
        $opentag = $field->parameters->get('opentag_form', '');
        $closetag = $field->parameters->get('closetag_form', '');
        // Initialise property with default value
        if (!$field->value) {
            $field->value = array($default_value);
        }
        // CSS classes of value container
        $value_classes = 'fcfieldval_container valuebox fcfieldval_container_' . $field->id;
        // 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;
        $js = "";
        $css = "";
        // *********************************************************************************************
        // Handle adding the needed JS code to CASCADE (listen to) changes of the dependent master field
        // *********************************************************************************************
        if ($cascade_after && !$ajax) {
            $byIds = FlexicontentFields::indexFieldsByIds($item->fields);
            if (isset($byIds[$cascade_after])) {
                $cascade_prompt = $field->parameters->get('cascade_prompt', '');
                $cascade_prompt = $cascade_prompt ? JText::_($cascade_prompt) : JText::_('FLEXI_PLEASE_SELECT') . ': ' . $byIds[$cascade_after]->label;
                $srcELid = 'custom_' . $byIds[$cascade_after]->name;
                $trgELid = $elementid;
                // Get values of cascade (on) source field
                $field->valgrps = $byIds[$cascade_after]->value ? $byIds[$cascade_after]->value : array();
                foreach ($field->valgrps as &$vg) {
                    if (is_array($vg)) {
                    } else {
                        if (@unserialize($vg) !== false || $vg === 'b:0;') {
                            $vg = unserialize($vg);
                        } else {
                            $vg = array($vg);
                        }
                    }
                }
                unset($vg);
            } else {
                $cascade_after = 0;
                echo 'Error in field ' . $field->label . ' [' . $field->id . ']' . ' cannot cascaded after field no: ' . $cascade_after . ', field was not found <br/>';
            }
        } 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 (!$use_ingroup) {
                $js .= "\n\t\t\tjQuery(document).ready(function(){\n\t\t\t\tjQuery('#sortables_" . $field->id . "').sortable({\n\t\t\t\t\thandle: '.fcfield-drag-handle',\n\t\t\t\t\tcontainment: 'parent',\n\t\t\t\t\ttolerance: 'pointer'\n\t\t\t\t});\n\t\t\t});\n\t\t\t";
            }
            if ($max_values) {
                JText::script("FLEXI_FIELD_MAX_ALLOWED_VALUES_REACHED", true);
            }
            $js .= "\n\t\t\tvar uniqueRowNum" . $field->id . "\t= " . count($field->value) . ";  // Unique row number incremented only\n\t\t\tvar rowCount" . $field->id . "\t= " . count($field->value) . ";      // Counts existing rows to be able to limit a max number of values\n\t\t\tvar maxValues" . $field->id . " = " . $max_values . ";\n\t\t\t\n\t\t\tfunction addField" . $field->id . "(el, groupval_box, fieldval_box, params)\n\t\t\t{\n\t\t\t\tvar insert_before   = (typeof params!== 'undefined' && typeof params.insert_before   !== 'undefined') ? params.insert_before   : 0;\n\t\t\t\tvar remove_previous = (typeof params!== 'undefined' && typeof params.remove_previous !== 'undefined') ? params.remove_previous : 0;\n\t\t\t\tvar scroll_visible  = (typeof params!== 'undefined' && typeof params.scroll_visible  !== 'undefined') ? params.scroll_visible  : 1;\n\t\t\t\tvar animate_visible = (typeof params!== 'undefined' && typeof params.animate_visible !== 'undefined') ? params.animate_visible : 1;\n\t\t\t\t\n\t\t\t\tif((rowCount" . $field->id . " >= maxValues" . $field->id . ") && (maxValues" . $field->id . " != 0)) {\n\t\t\t\t\talert(Joomla.JText._('FLEXI_FIELD_MAX_ALLOWED_VALUES_REACHED') + maxValues" . $field->id . ");\n\t\t\t\t\treturn 'cancel';\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Find last container of fields and clone it to create a new container of fields\n\t\t\t\tvar lastField = fieldval_box ? fieldval_box : jQuery(el).prev().children().last();\n\t\t\t\tvar newField  = lastField.clone();\n\t\t\t\t\n\t\t\t\t// Update value holder\n\t\t\t\tnewField.find('.fcfield_value_holder')\n\t\t\t\t\t.attr('id', '" . $valueholder_id . "_'+uniqueRowNum" . $field->id . ")\n\t\t\t\t\t.attr('name', '" . $valueholder_nm . "['+uniqueRowNum" . $field->id . "+']');\n\t\t\t\t\n\t\t\t\t// Update the new select field\n\t\t\t\tvar elem= newField.find('select.fcfield_textselval').first();\n\t\t\t\telem.val('');\n\t\t\t\telem.attr('name', '" . $fieldname . "['+uniqueRowNum" . $field->id . "+']" . (self::$valueIsArr ? '[]' : '') . "');\n\t\t\t\telem.attr('id', '" . $elementid . "_'+uniqueRowNum" . $field->id . ");\n\t\t\t\telem.attr('data-uniqueRowNum', uniqueRowNum" . $field->id . ");\n\t\t\t\t\n\t\t\t\t// Re-init any select2 elements\n\t\t\t\tvar has_select2 = newField.find('div.select2-container').length != 0;\n\t\t\t\tif (has_select2) {\n\t\t\t\t\tnewField.find('div.select2-container').remove();\n\t\t\t\t\tnewField.find('select.use_select2_lib').select2('destroy').show().select2();\n\t\t\t\t}\n\t\t\t\t";
            // Add new field to DOM
            $js .= "\n\t\t\t\tlastField ?\n\t\t\t\t\t(insert_before ? newField.insertBefore( lastField ) : newField.insertAfter( lastField ) ) :\n\t\t\t\t\tnewField.appendTo( jQuery('#sortables_" . $field->id . "') ) ;\n\t\t\t\tif (remove_previous) lastField.remove();\n\t\t\t\t";
            // Listen to the changes of cascade-after field
            if ($cascade_after) {
                $js .= "\n\t\t\t\tfc_cascade_field_funcs['" . $srcELid . "_'+uniqueRowNum" . $field->id . "] = function(rowNo){\n\t\t\t\t\treturn function () {\n\t\t\t\t\t\tfcCascadedField(" . $field->id . ", '" . $item->id . "', '" . $field->field_type . "', 'select#" . $srcELid . "_'+rowNo+', input." . $srcELid . "_'+rowNo, '" . $trgELid . "_'+rowNo, '" . $cascade_prompt . "', " . self::$promptEnabled . ", rowNo);\n\t\t\t\t\t}\n\t\t\t\t}(uniqueRowNum" . $field->id . ");\n\t\t\t\tfc_cascade_field_funcs['" . $srcELid . "_'+uniqueRowNum" . $field->id . "]();\n\t\t\t\t";
            }
            // Add new element to sortable objects (if field not in group)
            if (!$use_ingroup) {
                $js .= "\n\t\t\t\t//jQuery('#sortables_" . $field->id . "').sortable('refresh');  // Refresh was done appendTo ?\n\t\t\t\t";
            }
            // Show new field, increment counters
            $js .= "\n\t\t\t\t//newField.fadeOut({ duration: 400, easing: 'swing' }).fadeIn({ duration: 200, easing: 'swing' });\n\t\t\t\tif (scroll_visible) fc_scrollIntoView(newField, 1);\n\t\t\t\tif (animate_visible) newField.css({opacity: 0.1}).animate({ opacity: 1 }, 800);\n\t\t\t\t\n\t\t\t\t// Enable tooltips on new element\n\t\t\t\tnewField.find('.hasTooltip').tooltip({'html': true,'container': newField});\n\t\t\t\t\n\t\t\t\trowCount" . $field->id . "++;       // incremented / decremented\n\t\t\t\tuniqueRowNum" . $field->id . "++;   // incremented only\n\t\t\t}\n\n\t\t\tfunction deleteField" . $field->id . "(el, groupval_box, fieldval_box)\n\t\t\t{\n\t\t\t\t// Find field value container\n\t\t\t\tvar row = fieldval_box ? fieldval_box : jQuery(el).closest('li');\n\t\t\t\t\n\t\t\t\t// Add empty container if last element, instantly removing the given field value container\n\t\t\t\tif(rowCount" . $field->id . " == 1)\n\t\t\t\t\taddField" . $field->id . "(null, groupval_box, row, {remove_previous: 1, scroll_visible: 0, animate_visible: 0});\n\t\t\t\t\n\t\t\t\t// Remove if not last one, if it is last one, we issued a replace (copy,empty new,delete old) above\n\t\t\t\tif(rowCount" . $field->id . " > 1) {\n\t\t\t\t\t// Destroy the remove/add/etc buttons, so that they are not reclicked, while we do the hide effect (before DOM removal of field value)\n\t\t\t\t\trow.find('.fcfield-delvalue').remove();\n\t\t\t\t\trow.find('.fcfield-insertvalue').remove();\n\t\t\t\t\trow.find('.fcfield-drag-handle').remove();\n\t\t\t\t\t// Do hide effect then remove from DOM\n\t\t\t\t\trow.slideUp(400, function(){ jQuery(this).remove(); });\n\t\t\t\t\trowCount" . $field->id . "--;\n\t\t\t\t}\n\t\t\t}\n\t\t\t";
            $css .= '';
            $remove_button = '<span class="fcfield-delvalue' . (JComponentHelper::getParams('com_flexicontent')->get('form_font_icons', 1) ? ' fcfont-icon' : '') . '" title="' . JText::_('FLEXI_REMOVE_VALUE') . '" onclick="deleteField' . $field->id . '(this);"></span>';
            $move2 = '<span class="fcfield-drag-handle' . (JComponentHelper::getParams('com_flexicontent')->get('form_font_icons', 1) ? ' fcfont-icon' : '') . '" title="' . JText::_('FLEXI_CLICK_TO_DRAG') . '"></span>';
            $add_here = '';
            $add_here .= $add_position == 2 || $add_position == 3 ? '<span class="fcfield-insertvalue fc_before' . (JComponentHelper::getParams('com_flexicontent')->get('form_font_icons', 1) ? ' fcfont-icon' : '') . '" 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="fcfield-insertvalue fc_after' . (JComponentHelper::getParams('com_flexicontent')->get('form_font_icons', 1) ? ' fcfont-icon' : '') . '"  onclick="addField' . $field->id . '(null, jQuery(this).closest(\'ul\'), jQuery(this).closest(\'li\'), {insert_before: 0});" title="' . JText::_('FLEXI_ADD_AFTER') . '"></span> ' : '';
        } else {
            $remove_button = '';
            $move2 = '';
            $add_here = '';
            $js .= '';
            $css .= '';
        }
        // Added field's custom CSS / JS
        if (!$ajax && $js) {
            $document->addScriptDeclaration($js);
        }
        if (!$ajax && $css) {
            $document->addStyleDeclaration($css);
        }
        // **************************
        // Get indexed element values
        // **************************
        // If cascading we will get it inside the value loop for every value, thus supporting field grouping properly
        $elements = !$cascade_after ? $this->getLimitedProps($field, $item) : array();
        if (!is_array($elements)) {
            $field->html = $elements;
            return;
        }
        // *****************************************
        // Create field's HTML display for item form
        // *****************************************
        // Create form field options
        $options = array();
        foreach ($elements as $element) {
            $options[] = JHTML::_('select.option', $element->value, $element->text);
        }
        // Create the attributes of the form field
        $display_as_select = 1;
        if ($display_as_select) {
            $classes = 'fcfield_textselval' . ($use_jslib && $select2_added ? ' use_select2_lib' : '');
            $classes .= $required;
            $onchange = '';
            // Extra properties
            $attribs = '';
            if ($classes) {
                $attribs .= ' class="' . $classes . '" ';
            }
            if ($onchange) {
                $attribs .= ' onchange="' . $onchange . '" ';
            }
        }
        // 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 = self::$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 (self::$valueIsArr) {
                if (is_array($value)) {
                } else {
                    if (@unserialize($value) !== false || $value === 'b:0;') {
                        $value = unserialize($value);
                    }
                }
            }
            // 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;
            }
            // Get options according to cascading, this is here so that it works with field grouping too
            if ($cascade_after) {
                $elements = $this->getLimitedProps($field, $item, !$ajax ? $cascade_prompt : null, $ajax, $n);
                $options =& $elements;
            }
            if (!$ajax) {
                $fieldname_n = $fieldname . '[' . $n . ']' . (self::$valueIsArr ? '[]' : '');
                $elementid_n = $elementid . '_' . $n;
                $form_field = $opentag . JHTML::_('select.genericlist', $options, $fieldname_n, $attribs . ' data-uniqueRowNum="' . $n . '"', 'value', 'text', $value, $elementid_n) . $closetag;
                $field->html[] = '
					' . $form_field . '
					' . ($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="-">' : '') . '
					' . ($use_ingroup ? '' : $move2) . '
					' . ($use_ingroup ? '' : $remove_button) . '
					' . ($use_ingroup || !$add_position ? '' : $add_here) . '
					';
                // Listen to the changes of cascade-after field
                if ($cascade_after && !$ajax) {
                    $per_val_js .= "\n\t\t\t\t\tfc_cascade_field_funcs['" . $srcELid . '_' . $n . "'] = function(){\n\t\t\t\t\t\tfcCascadedField(" . $field->id . ", '" . $item->id . "', '" . $field->field_type . "', 'select#" . $srcELid . '_' . $n . ", input." . $srcELid . '_' . $n . "', '" . $trgELid . '_' . $n . "', '" . $cascade_prompt . "', " . self::$promptEnabled . ", " . $n . ");\n\t\t\t\t\t}\n\t\t\t\t\tfc_cascade_field_funcs['" . $srcELid . '_' . $n . "']();\n\t\t\t\t";
                }
            } else {
                $field->html = 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) {
            return;
            // Done
        } else {
            if ($use_ingroup) {
                // do not convert the array to string if field is in a group
            } else {
                if ($multiple) {
                    // handle multiple records
                    $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 .= '<span class="fcfield-addvalue ' . (JComponentHelper::getParams('com_flexicontent')->get('form_font_icons', 1) ? ' fcfont-icon' : '') . '" onclick="addField' . $field->id . '(this);" title="' . JText::_('FLEXI_ADD_TO_BOTTOM') . '">' . JText::_('FLEXI_ADD_VALUE') . '</span>';
                    }
                } else {
                    // handle single values
                    $field->html = '<div class="fcfieldval_container valuebox fcfieldval_container_' . $field->id . '">' . $field->html[0] . '</div>';
                }
            }
        }
    }