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 = ' | '; break; case 3: $separator = ', '; break; case 4: $separator = $closetag . $opentag; break; default: $separator = ' '; 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 " $elementid_n , $elementid_no , $fieldname_n , 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>'; } } } }
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>'; } } } }