From d7d550d53fb2e0518510344746f15a9491e6a9aa Mon Sep 17 00:00:00 2001 From: Paolo Date: Thu, 3 Aug 2017 15:20:32 +0200 Subject: [PATCH] - Multipledropdown: fixed problem to see and to save more selected elements - Dropdown: reset selected element to null --- application/libraries/WidgetLib.php | 2287 ++++++++++++++------------- application/widgets/UDFWidget.php | 4 + 2 files changed, 1148 insertions(+), 1143 deletions(-) diff --git a/application/libraries/WidgetLib.php b/application/libraries/WidgetLib.php index f9480d6c5..9996ce684 100644 --- a/application/libraries/WidgetLib.php +++ b/application/libraries/WidgetLib.php @@ -1,1144 +1,1145 @@ -_ci = & get_instance(); - - // set the default widget path with APPPATH - $this->_widget_path = APPPATH . 'widgets/'; - - if (!empty($config)) - $this->initialize($config); - - log_message('debug', 'Template library initialized'); - } - - /** - * Initialize with configuration array - * @param array $config - * @return Template - */ - public function initialize($config = array()) - { - foreach ($config as $key => $val) - $this->{'_' . $key} = $val; - - if ($this->_widget_path == '') - $this->_widget_path = APPPATH . 'widgets/'; - - if ($this->_parser && !class_exists('CI_Parser')) - $this->_ci->load->library('parser'); - } - - /** - * Set a partial's content. This will create a new partial when not existing - * @param string $index - * @param mixed $value - */ - public function __set($name, $value) - { - $this->partial($name)->set($value); - } - - /** - * Access to partials for method chaining - * @param string $name - * @return mixed - */ - public function __get($name) - { - return $this->partial($name); - } - - /** - * Check if a partial exists - * @param string $index - * @return boolean - */ - public function exists($index) - { - return array_key_exists($index, $this->_partials); - } - - /** - * Set the template file - * @param string $template - */ - public function set_template($template) - { - $this->_template = $template; - } - - /** - * Publish the template with the current partials - * You can manually pass a template file with extra data, or use the default template from the config file - * @param string $template - * @param array $data - */ - public function publish($template = FALSE, $data = array()) { - if (is_array($template) || is_object($template)) { - $data = $template; - } else if ($template) { - $this->_template = $template; - } - - if (!$this->_template) { - show_error('There was no template file selected for the current template'); - } - - if (is_array($data) || is_object($data)) { - foreach ($data as $name => $content) { - $this->partial($name)->set($content); - } - } - - unset($data); - - if ($this->_parser) { - $this->_ci->parser->parse($this->_template, $this->_partials); - } else { - $this->_ci->load->view($this->_template, $this->_partials); - } - } - - /** - * Create a partial object with an optional default content - * Can be usefull to use straight from the template file - * @param string $name - * @param string $default - * @return Partial - */ - public function partial($name, $default = FALSE) { - if ($this->exists($name)) { - $partial = $this->_partials[$name]; - } else { - // create new partial - $partial = new Partial($name); - if ($this->_cache_ttl) { - $partial->cache($this->_cache_ttl); - } - - // detect local triggers - if (method_exists($this, 'trigger_' . $name)) { - $partial->bind($this, 'trigger_' . $name); - } - - $this->_partials[$name] = $partial; - } - - if (!$partial->content() && $default) { - $partial->set($default); - } - - return $partial; - } - - /** - * Create a widget object with optional parameters - * Can be usefull to use straight from the template file - * @param string $name - * @param array $data - * @param array $htmlArgs - * @return Widget - */ - public function widget($name, $data = array(), $htmlArgs = array()) - { - $class = str_replace('.php', '', trim($name, '/')); - - // determine path and widget class name - $path = $this->_widget_path; - if (($last_slash = strrpos($class, '/')) !== FALSE) { - $path += substr($class, 0, $last_slash); - $class = substr($class, $last_slash + 1); - } - - // new widget - if (!class_exists($class)) { - // try both lowercase and capitalized versions - foreach (array(ucfirst($class), strtolower($class)) as $class) { - if (file_exists($path . $class . '.php')) { - include_once ($path . $class . '.php'); - - // found the file, stop looking - break; - } - } - } - - if (!class_exists($class)) { - show_error("Widget '" . $class . "' was not found."); - } - - return new $class($class, $data, $htmlArgs); - } - - /** - * - */ - public function UDFWidget($args, $htmlArgs = array()) - { - if (!empty($args[UDFWidgetTpl::SCHEMA_ARG_NAME]) && !empty($args[UDFWidgetTpl::TABLE_ARG_NAME])) - { - // - if (empty($args[UDFWidgetTpl::FIELD_ARG_NAME]) && !isset($htmlArgs[Widget::HTML_ARG_NAME][Widget::EXTERNAL_BLOCK])) - { - $htmlArgs[Widget::HTML_ARG_NAME][Widget::EXTERNAL_BLOCK] = true; - } - - return $this->widget( - UDFWidgetTpl::WIDGET_NAME, - $args, - $htmlArgs - ); - } - else - { - if (empty($args[UDFWidgetTpl::SCHEMA_ARG_NAME])) - { - show_error(UDFWidgetTpl::SCHEMA_ARG_NAME.' parameter is missing!'); - } - if (empty($args[UDFWidgetTpl::TABLE_ARG_NAME])) - { - show_error(UDFWidgetTpl::TABLE_ARG_NAME.' parameter is missing!'); - } - } - } - - /** - * Enable cache for all partials with TTL, default TTL is 60 - * @param int $ttl - * @param mixed $identifier - */ - public function cache($ttl = 60, $identifier = '') { - foreach ($this->_partials as $partial) { - $partial->cache($ttl, $identifier); - } - - $this->_cache_ttl = $ttl; - } - - // ---- TRIGGERS ----------------------------------------------------------------- - - /** - * Stylesheet trigger - * @param string $source - */ - public function trigger_stylesheet($url, $attributes = FALSE) { - // array support - if (is_array($url)) { - $return = ''; - foreach ($url as $u) { - $return .= $this->trigger_stylesheet($u, $attributes); - } - return $return; - } - - if (!stristr($url, 'http://') && !stristr($url, 'https://') && substr($url, 0, 2) != '//') { - $url = $this->_ci->config->item('base_url') . $url; - } - - // legacy support for media - if (is_string($attributes)) { - $attributes = array('media' => $attributes); - } - - if (is_array($attributes)) { - $attributeString = ""; - - foreach ($attributes as $key => $value) { - $attributeString .= $key . '="' . $value . '" '; - } - - return '' . "\n\t"; - } else { - return '' . "\n\t"; - } - } - - /** - * Javascript trigger - * @param string $source - */ - public function trigger_javascript($url) { - // array support - if (is_array($url)) { - $return = ''; - foreach ($url as $u) { - $return .= $this->trigger_javascript($u); - } - return $return; - } - - if (!stristr($url, 'http://') && !stristr($url, 'https://') && substr($url, 0, 2) != '//') { - $url = $this->_ci->config->item('base_url') . $url; - } - - return '' . "\n\t"; - } - - /** - * Meta trigger - * @param string $name - * @param mixed $value - * @param enum $type - */ - public function trigger_meta($name, $value, $type = 'meta') { - $name = htmlspecialchars(strip_tags($name)); - $value = htmlspecialchars(strip_tags($value)); - - if ($name == 'keywords' and !strpos($value, ',')) { - $content = preg_replace('/[\s]+/', ', ', trim($value)); - } - - switch ($type) { - case 'meta' : - $content = '' . "\n\t"; - break; - case 'link' : - $content = '' . "\n\t"; - break; - } - - return $content; - } - - /** - * Title trigger, keeps it clean - * @param string $name - * @param mixed $value - * @param enum $type - */ - public function trigger_title($title) { - return htmlspecialchars(strip_tags($title)); - } - - /** - * Title trigger, keeps it clean - * @param string $name - * @param mixed $value - * @param enum $type - */ - public function trigger_description($description) { - return htmlspecialchars(strip_tags($description)); - } - -} - -class Partial -{ - protected $_ci, $_content, $_name, $_cache_ttl = 0, $_cached = false, $_identifier, $_trigger; - protected $_args = array(); - - /** - * Construct with optional parameters - * @param array $args - */ - public function __construct($name, $args = array()) - { - $this->_ci = &get_instance(); - $this->_args = $args; - $this->_name = $name; - } - - /** - * Gives access to codeigniter's functions from this class if needed - * This will be handy in extending classes - * @param string $index - */ - function __get($name) { - return $this->_ci->$name; - } - - /** - * Alias methods - */ - function __call($name, $args) { - switch ($name) { - case 'default' : - return call_user_func_array(array($this, 'set_default'), $args); - break; - case 'add' : - return call_user_func_array(array($this, 'append'), $args); - break; - } - } - - /** - * Returns the content when converted to a string - * @return string - */ - public function __toString() { - return (string) $this->content(); - } - - /** - * Returns the content - * @return string - */ - public function content() { - if ($this->_cache_ttl && !$this->_cached) { - $this->cache->save($this->cache_id(), $this->_content, $this->_cache_ttl); - } - - return $this->_content; - } - - /** - * Overwrite the content - * @param mixed $content - * @return Partial - */ - public function set() { - if (!$this->_cached) { - $this->_content = (string) $this->trigger(func_get_args()); - } - - return $this; - } - - /** - * Append something to the content - * @param mixed $content - * @return Partial - */ - public function append() { - if (!$this->_cached) { - $this->_content .= (string) $this->trigger(func_get_args()); - } - - return $this; - } - - /** - * Prepend something to the content - * @param mixed $content - * @return Partial - */ - public function prepend() { - if (!$this->_cached) { - $this->_content = (string) $this->trigger(func_get_args()) . $this->_content; - } - - return $this; - } - - /** - * Set content if partial is empty - * @param mixed $default - * @return Partial - */ - public function set_default($default) { - if (!$this->_cached) { - if (!$this->_content) { - $this->_content = $default; - } - } - - return $this; - } - - /** - * Load a view inside this partial, overwrite if wanted - * @param string $view - * @param array $data - * @param bool $overwrite - * @return Partial - */ - public function view($view, $data = array(), $overwrite = false) { - if (!$this->_cached) { - - // better object to array - if (is_object($data)) { - $array = array(); - foreach ($data as $k => $v) { - $array[$k] = $v; - } - $data = $array; - } - - $content = $this->_ci->load->view($view, $data, true); - - if ($overwrite) { - $this->set($content); - } else { - $this->append($content); - } - } - return $this; - } - - /** - * Parses a view inside this partial, overwrite if wanted - * @param string $view - * @param array $data - * @param bool $overwrite - * @return Partial - */ - public function parse($view, $data = array(), $overwrite = false) { - if (!$this->_cached) { - if (!class_exists('CI_Parser')) { - $this->_ci->load->library('parser'); - } - - // better object to array - if (is_object($data)) { - $array = array(); - foreach ($data as $k => $v) { - $array[$k] = $v; - } - $data = $array; - } - - $content = $this->_ci->parser->parse($view, $data, true); - - if ($overwrite) { - $this->set($content); - } else { - $this->append($content); - } - } - - return $this; - } - - /** - * Loads a widget inside this partial, overwrite if wanted - * @param string $name - * @param array $data - * @param bool $overwrite - * @return Partial - */ - public function widget($name, $data = array(), $overwrite = false) { - if (!$this->_cached) { - $widget = $this->template->widget($name, $data); - - if ($overwrite) { - $this->set($widget->content()); - } else { - $this->append($widget->content()); - } - } - return $this; - } - - /** - * Enable cache with TTL, default TTL is 60 - * @param int $ttl - * @param mixed $identifier - */ - public function cache($ttl = 60, $identifier = '') { - if (!class_exists('CI_Cache')) { - $this->_ci->load->driver('cache', array('adapter' => 'file')); - } - - $this->_cache_ttl = $ttl; - $this->_identifier = $identifier; - - if ($cached = $this->_ci->cache->get($this->cache_id())) { - $this->_cached = true; - $this->_content = $cached; - } - return $this; - } - - /** - * Used for cache identification - * @return string - */ - private function cache_id() { - if ($this->_identifier) { - return $this->_name . '_' . $this->_identifier . '_' . md5(get_class($this) . implode('', $this->_args)); - } else { - return $this->_name . '_' . md5(get_class($this) . implode('', $this->_args)); - } - } - - /** - * Trigger returns the result if a trigger is set - * @param array $args - * @return string - */ - public function trigger($args) { - if (!$this->_trigger) { - return implode('', $args); - } else { - return call_user_func_array($this->_trigger, $args); - } - } - - /** - * Bind a trigger function - * Can be used like bind($this, "function") or bind("function") - * @param mixed $arg - */ - public function bind() { - if ($count = func_num_args()) { - if ($count >= 2) { - $args = func_get_args(); - $obj = array_shift($args); - $func = array_pop($args); - - foreach ($args as $trigger) { - $obj = $obj->$trigger; - } - - $this->_trigger = array($obj, $func); - } else { - $args = func_get_args(); - $this->_trigger = reset($args); - } - } else { - $this->_trigger = FALSE; - } - } -} - -/** - * The mother of all widgets - * it represent a generic HTML element - */ -class Widget extends Partial -{ - // The name of the array present in the data array given to the view that will render this widget - const HTML_ARG_NAME = 'HTML'; - const HTML_DEFAULT_VALUE = ''; // Default value of the html element - const HTML_NAME = 'name'; // HTML name attribute - const HTML_ID = 'id'; // HTML id attribute - - const EXTERNAL_BLOCK = 'externalBlock'; // - const EXTERNAL_START_BLOCK_HTML_TAG = '
'; // - const EXTERNAL_END_BLOCK_HTML_TAG = '
'; // - - /** - * It gets also the htmlArgs array as parameter, it will be used to set the HTML properties - */ - public function __construct($name, $args, $htmlArgs = array()) - { - parent::__construct($name, $args); - - // Initialising HTML properties - $this->_setHtmlProperties($htmlArgs); - - // Loads helper message to manage returning messages - $this->load->helper('message'); - } - - /** - * (non-PHPdoc) - * @see Partial::content() - */ - public function content() - { - if (!$this->_cached) - { - if (method_exists($this, 'display')) - { - // capture output - ob_start(); - $this->display($this->_args); - $buffer = ob_get_clean(); - - // if no content is produced but there was direct ouput we set - // that output as content - if (!$this->_content && $buffer) - { - $this->set($buffer); - } - } - } - - return parent::content(); - } - - /** - * Initialising html properties, such as the id and name attributes of the HTML element - */ - private function _setHtmlProperties($htmlArgs) - { - // If $htmlArgs wasn't already stored in $this->_args - if (!isset($this->_args[Widget::HTML_ARG_NAME])) - { - $this->_args[Widget::HTML_ARG_NAME] = array(); - - // Avoids that elements in a HTML page have the same name or id - $randomIdentifier = uniqid(rand(0, 1000)); - $this->_args[Widget::HTML_ARG_NAME][Widget::HTML_ID] = $randomIdentifier; - $this->_args[Widget::HTML_ARG_NAME][Widget::HTML_NAME] = $randomIdentifier; - - foreach($htmlArgs as $argName => $argValue) - { - $this->_args[Widget::HTML_ARG_NAME][$argName] = $argValue; - } - } - } - - /** - * - */ - public static function printAttribute($htmlArgs, $attribute, $isValuePresent = true) - { - if ($attribute != null) - { - if (isset($htmlArgs[$attribute])) - { - if ($isValuePresent === true) - { - $value = $htmlArgs[$attribute]; - - if (is_bool($value)) - { - $value = $value ? 'true' : 'false'; - } - - echo sprintf('%s="%s"', $attribute, $value); - } - else - { - echo $attribute; - } - } - } - } - - /** - * - */ - public static function printStartBlock($htmlArgs) - { - if (isset($htmlArgs[Widget::HTML_ARG_NAME][Widget::EXTERNAL_BLOCK]) - && $htmlArgs[Widget::HTML_ARG_NAME][Widget::EXTERNAL_BLOCK] === true) - { - echo Widget::EXTERNAL_START_BLOCK_HTML_TAG; - } - } - - /** - * - */ - public static function printEndBlock($htmlArgs) - { - if (isset($htmlArgs[Widget::HTML_ARG_NAME][Widget::EXTERNAL_BLOCK]) - && $htmlArgs[Widget::HTML_ARG_NAME][Widget::EXTERNAL_BLOCK] === true) - { - echo Widget::EXTERNAL_END_BLOCK_HTML_TAG; - } - } -} - -/** - * It exends the Widget class to represent an HTML dropdown - */ -class DropdownWidget extends Widget -{ - // The name of the element of the data array given to the view - // this element is an array of elements to be place inside the dropdown - const WIDGET_DATA_ELEMENTS_ARRAY_NAME = 'ELEMENTS_ARRAY'; - // Name of the property that will be used to store the value attribute of the option tag - const ID_FIELD = 'id'; - // Name of the property that will be used to store the value between the option tags - const DESCRIPTION_FIELD = 'description'; - // The name of the element of the data array given to the view - // this element is used to tell what element of the dropdown is selected - const SELECTED_ELEMENT = 'selectedElement'; - // - const HTML_DEFAULT_VALUE = 'null'; - - const SIZE = 'size'; // - const MULTIPLE = 'multiple'; // - - /** - * - */ - public function __construct($name, $args, $htmlArgs = array()) - { - parent::__construct($name, $args, $htmlArgs); - - // - if (!isset($this->_args[DropdownWidget::SELECTED_ELEMENT])) - { - $this->_args[DropdownWidget::SELECTED_ELEMENT] = DropdownWidget::HTML_DEFAULT_VALUE; - } - } - - /** - * - */ - public function setMultiple() - { - $this->_args[Widget::HTML_ARG_NAME][DropdownWidget::MULTIPLE] = DropdownWidget::MULTIPLE; - } - - /** - * - */ - public function isMultipleDropdown() - { - $isMultipleDropdown = false; - - if (isset($this->_args[Widget::HTML_ARG_NAME][DropdownWidget::MULTIPLE]) - && $this->_args[Widget::HTML_ARG_NAME][DropdownWidget::MULTIPLE] == DropdownWidget::MULTIPLE) - { - $isMultipleDropdown = true; - } - - return $isMultipleDropdown; - } - - /** - * Add the correct select to the model used to load a list of elemets for this dropdown - * @param model $model the model used to load elements - * @param string $idName the name of the field that will used to be the value of the option tag - * @param string $descriptionName the name of the field that will used to be displayed in the dropdown - */ - protected function addSelectToModel($model, $idName, $descriptionName) - { - $model->addSelect( - sprintf( - '%s AS %s, %s AS %s', - $idName, - DropdownWidget::ID_FIELD, - $descriptionName, - DropdownWidget::DESCRIPTION_FIELD - ) - ); - } - - /** - * Set the array used to populate the dropdown - * @param array $elements list used to populate this dropdown - * @param boolean $emptyElement if an empty element must be added at the beginning of the dropdown - * @param string $stdDescription description of the empty element - * @param string $noDataDescription description if no data are found - * @param string $id value of the attribute value of the empty element - */ - protected function setElementsArray( - $elements, $emptyElement = false, $stdDescription = '' , $noDataDescription = 'No data found' , $id = DropdownWidget::HTML_DEFAULT_VALUE - ) - { - $tmpElements = array(); - - if (isError($elements)) - { - if (is_object($elements) && isset($elements->retval)) - { - show_error($elements->retval); - } - else if (is_string($elements)) - { - show_error($elements); - } - else - { - show_error('Generic error occurred'); - } - } - else - { - if ($emptyElement === true && $this->isMultipleDropdown() == false) - { - $tmpElements = $this->addElementAtBeginning( - $elements, - $stdDescription, - $noDataDescription, - $id - ); - } - else - { - $tmpElements = $elements->retval; - } - - $this->_args[DropdownWidget::WIDGET_DATA_ELEMENTS_ARRAY_NAME] = $tmpElements; - } - } - - /** - * Adds an element to the beginning of the array - */ - protected function addElementAtBeginning($elements, $stdDescription, $noDataDescription, $id) - { - $element = new stdClass(); - $element->{DropdownWidget::ID_FIELD} = $id; - $element->{DropdownWidget::DESCRIPTION_FIELD} = $stdDescription; - - if (!hasData($elements)) - { - $element->{DropdownWidget::DESCRIPTION_FIELD} = $noDataDescription; - } - - array_unshift($elements->retval, $element); - - return $elements->retval; - } - - /** - * Loads the dropdown view with all the elements to be displayed - */ - protected function loadDropDownView() - { - $this->view('widgets/dropdown', $this->_args); - } -} - -/** - * - */ -class DropdownWidgetUDF extends DropdownWidget -{ - /** - * - */ - public function render($parameters) - { - $tmpElements = array(); - - // - foreach($parameters as $parameter) - { - // - if ((is_array($parameter) && count($parameter) == 2) - || (is_string($parameter) || is_numeric($parameter)) - || (is_object($parameter) && isset($parameter->{PARENT::ID_FIELD}) && isset($parameter->{PARENT::DESCRIPTION_FIELD}))) - { - $element = new stdClass(); // - // - if (is_array($parameter) && count($parameter) == 2) - { - $element->{PARENT::ID_FIELD} = $parameter[0]; // - $element->{PARENT::DESCRIPTION_FIELD} = $parameter[1]; // - } - // - else if (is_string($parameter) || is_numeric($parameter)) - { - $element->{PARENT::ID_FIELD} = $parameter; // - $element->{PARENT::DESCRIPTION_FIELD} = $parameter; // - } - // - else if (is_object($parameter) && isset($parameter->{PARENT::ID_FIELD}) && isset($parameter->{PARENT::DESCRIPTION_FIELD})) - { - $element->{PARENT::ID_FIELD} = $parameter->{PARENT::ID_FIELD}; // - $element->{PARENT::DESCRIPTION_FIELD} = $parameter->{PARENT::DESCRIPTION_FIELD}; // - } - - array_push($tmpElements, $element); // - } - } - - $this->setElementsArray( - success($tmpElements), - true, - $this->_args[Widget::HTML_ARG_NAME][UDFWidgetTpl::PLACEHOLDER], - 'No data found for this UDF' - ); - - $this->loadDropDownView(); - - echo $this->content(); - } -} - -/** - * It exends the Widget class to represent an HTML textarea - */ -class TextareaWidget extends Widget -{ - const TEXT = 'text'; // - const ROWS = 'rows'; // - const COLS = 'cols'; // - - /** - * - */ - protected function setText($text) - { - $this->_args[TextareaWidget::TEXT] = $text; - } - - /** - * - */ - protected function loadTextareaView() - { - $this->view('widgets/textarea', $this->_args); - } -} - -/** - * - */ -class TextareaWidgetUDF extends TextareaWidget -{ - /** - * - */ - public function render($parameters) - { - if ($parameters != null) - { - $this->setText($parameters); - } - else - { - $this->setText(''); - } - - $this->loadTextareaView(); - - echo $this->content(); - } -} - -/** - * It exends the Widget class to represent an HTML textarea - */ -class TextfieldWidget extends Widget -{ - const VALUE = 'text'; // - const SIZE = 'size'; // - - /** - * - */ - protected function setValue($value) - { - $this->_args[TextfieldWidget::VALUE] = $value; - } - - /** - * - */ - protected function loadTextfieldView() - { - $this->view('widgets/textfield', $this->_args); - } -} - -/** - * - */ -class TextfieldWidgetUDF extends TextfieldWidget -{ - /** - * - */ - public function render($parameters) - { - if ($parameters != null) - { - $this->setValue($parameters); - } - else - { - $this->setValue(''); - } - - $this->loadTextfieldView(); - - echo $this->content(); - } -} - -/** - * It exends the Widget class to represent an HTML dropdown - */ -class CheckboxWidget extends Widget -{ - // Name of the property that will be used to store the value attribute of the option tag - const VALUE_FIELD = 'value'; - // Name of the property that will be used to store the value between the option tags - const DESCRIPTION_FIELD = 'description'; - // Value of value attribute of the checkbox - const CHECKBOX_VALUE = 'true'; - - /** - * - */ - protected function loadCheckboxView() - { - $this->view('widgets/checkbox', $this->_args); - } -} - -/** - * - */ -class CheckboxWidgetUDF extends CheckboxWidget -{ - /** - * - */ - public function render() - { - $this->loadCheckboxView(); - - echo $this->content(); - } -} - -/** - * Defined here because these constants can be used - * in the views also - */ -abstract class UDFWidgetTpl extends Widget -{ - const WIDGET_NAME = 'UDFWidget'; - const SCHEMA_ARG_NAME = 'schema'; - const TABLE_ARG_NAME = 'table'; - const FIELD_ARG_NAME = 'field'; - const UDFS_ARG_NAME = 'udfs'; - - // HTML components - const TITLE = 'description'; - const LABEL = 'title'; - const PLACEHOLDER = 'placeholder'; - const DEFAULT_VALUE = 'defaultValue'; - - // Validation attributes - const REGEX = 'regex'; - const REQUIRED = 'required'; - const MAX_VALUE = 'max-value'; - const MIN_VALUE = 'min-value'; - const MAX_LENGTH = 'max-length'; - const MIN_LENGTH = 'min-length'; +_ci = & get_instance(); + + // set the default widget path with APPPATH + $this->_widget_path = APPPATH . 'widgets/'; + + if (!empty($config)) + $this->initialize($config); + + log_message('debug', 'Template library initialized'); + } + + /** + * Initialize with configuration array + * @param array $config + * @return Template + */ + public function initialize($config = array()) + { + foreach ($config as $key => $val) + $this->{'_' . $key} = $val; + + if ($this->_widget_path == '') + $this->_widget_path = APPPATH . 'widgets/'; + + if ($this->_parser && !class_exists('CI_Parser')) + $this->_ci->load->library('parser'); + } + + /** + * Set a partial's content. This will create a new partial when not existing + * @param string $index + * @param mixed $value + */ + public function __set($name, $value) + { + $this->partial($name)->set($value); + } + + /** + * Access to partials for method chaining + * @param string $name + * @return mixed + */ + public function __get($name) + { + return $this->partial($name); + } + + /** + * Check if a partial exists + * @param string $index + * @return boolean + */ + public function exists($index) + { + return array_key_exists($index, $this->_partials); + } + + /** + * Set the template file + * @param string $template + */ + public function set_template($template) + { + $this->_template = $template; + } + + /** + * Publish the template with the current partials + * You can manually pass a template file with extra data, or use the default template from the config file + * @param string $template + * @param array $data + */ + public function publish($template = FALSE, $data = array()) { + if (is_array($template) || is_object($template)) { + $data = $template; + } else if ($template) { + $this->_template = $template; + } + + if (!$this->_template) { + show_error('There was no template file selected for the current template'); + } + + if (is_array($data) || is_object($data)) { + foreach ($data as $name => $content) { + $this->partial($name)->set($content); + } + } + + unset($data); + + if ($this->_parser) { + $this->_ci->parser->parse($this->_template, $this->_partials); + } else { + $this->_ci->load->view($this->_template, $this->_partials); + } + } + + /** + * Create a partial object with an optional default content + * Can be usefull to use straight from the template file + * @param string $name + * @param string $default + * @return Partial + */ + public function partial($name, $default = FALSE) { + if ($this->exists($name)) { + $partial = $this->_partials[$name]; + } else { + // create new partial + $partial = new Partial($name); + if ($this->_cache_ttl) { + $partial->cache($this->_cache_ttl); + } + + // detect local triggers + if (method_exists($this, 'trigger_' . $name)) { + $partial->bind($this, 'trigger_' . $name); + } + + $this->_partials[$name] = $partial; + } + + if (!$partial->content() && $default) { + $partial->set($default); + } + + return $partial; + } + + /** + * Create a widget object with optional parameters + * Can be usefull to use straight from the template file + * @param string $name + * @param array $data + * @param array $htmlArgs + * @return Widget + */ + public function widget($name, $data = array(), $htmlArgs = array()) + { + $class = str_replace('.php', '', trim($name, '/')); + + // determine path and widget class name + $path = $this->_widget_path; + if (($last_slash = strrpos($class, '/')) !== FALSE) { + $path += substr($class, 0, $last_slash); + $class = substr($class, $last_slash + 1); + } + + // new widget + if (!class_exists($class)) { + // try both lowercase and capitalized versions + foreach (array(ucfirst($class), strtolower($class)) as $class) { + if (file_exists($path . $class . '.php')) { + include_once ($path . $class . '.php'); + + // found the file, stop looking + break; + } + } + } + + if (!class_exists($class)) { + show_error("Widget '" . $class . "' was not found."); + } + + return new $class($class, $data, $htmlArgs); + } + + /** + * + */ + public function UDFWidget($args, $htmlArgs = array()) + { + if (!empty($args[UDFWidgetTpl::SCHEMA_ARG_NAME]) && !empty($args[UDFWidgetTpl::TABLE_ARG_NAME])) + { + // + if (empty($args[UDFWidgetTpl::FIELD_ARG_NAME]) && !isset($htmlArgs[Widget::EXTERNAL_BLOCK])) + { + $htmlArgs[Widget::EXTERNAL_BLOCK] = true; + } + + return $this->widget( + UDFWidgetTpl::WIDGET_NAME, + $args, + $htmlArgs + ); + } + else + { + if (empty($args[UDFWidgetTpl::SCHEMA_ARG_NAME])) + { + show_error(UDFWidgetTpl::SCHEMA_ARG_NAME.' parameter is missing!'); + } + if (empty($args[UDFWidgetTpl::TABLE_ARG_NAME])) + { + show_error(UDFWidgetTpl::TABLE_ARG_NAME.' parameter is missing!'); + } + } + } + + /** + * Enable cache for all partials with TTL, default TTL is 60 + * @param int $ttl + * @param mixed $identifier + */ + public function cache($ttl = 60, $identifier = '') { + foreach ($this->_partials as $partial) { + $partial->cache($ttl, $identifier); + } + + $this->_cache_ttl = $ttl; + } + + // ---- TRIGGERS ----------------------------------------------------------------- + + /** + * Stylesheet trigger + * @param string $source + */ + public function trigger_stylesheet($url, $attributes = FALSE) { + // array support + if (is_array($url)) { + $return = ''; + foreach ($url as $u) { + $return .= $this->trigger_stylesheet($u, $attributes); + } + return $return; + } + + if (!stristr($url, 'http://') && !stristr($url, 'https://') && substr($url, 0, 2) != '//') { + $url = $this->_ci->config->item('base_url') . $url; + } + + // legacy support for media + if (is_string($attributes)) { + $attributes = array('media' => $attributes); + } + + if (is_array($attributes)) { + $attributeString = ""; + + foreach ($attributes as $key => $value) { + $attributeString .= $key . '="' . $value . '" '; + } + + return '' . "\n\t"; + } else { + return '' . "\n\t"; + } + } + + /** + * Javascript trigger + * @param string $source + */ + public function trigger_javascript($url) { + // array support + if (is_array($url)) { + $return = ''; + foreach ($url as $u) { + $return .= $this->trigger_javascript($u); + } + return $return; + } + + if (!stristr($url, 'http://') && !stristr($url, 'https://') && substr($url, 0, 2) != '//') { + $url = $this->_ci->config->item('base_url') . $url; + } + + return '' . "\n\t"; + } + + /** + * Meta trigger + * @param string $name + * @param mixed $value + * @param enum $type + */ + public function trigger_meta($name, $value, $type = 'meta') { + $name = htmlspecialchars(strip_tags($name)); + $value = htmlspecialchars(strip_tags($value)); + + if ($name == 'keywords' and !strpos($value, ',')) { + $content = preg_replace('/[\s]+/', ', ', trim($value)); + } + + switch ($type) { + case 'meta' : + $content = '' . "\n\t"; + break; + case 'link' : + $content = '' . "\n\t"; + break; + } + + return $content; + } + + /** + * Title trigger, keeps it clean + * @param string $name + * @param mixed $value + * @param enum $type + */ + public function trigger_title($title) { + return htmlspecialchars(strip_tags($title)); + } + + /** + * Title trigger, keeps it clean + * @param string $name + * @param mixed $value + * @param enum $type + */ + public function trigger_description($description) { + return htmlspecialchars(strip_tags($description)); + } + +} + +class Partial +{ + protected $_ci, $_content, $_name, $_cache_ttl = 0, $_cached = false, $_identifier, $_trigger; + protected $_args = array(); + + /** + * Construct with optional parameters + * @param array $args + */ + public function __construct($name, $args = array()) + { + $this->_ci = &get_instance(); + $this->_args = $args; + $this->_name = $name; + } + + /** + * Gives access to codeigniter's functions from this class if needed + * This will be handy in extending classes + * @param string $index + */ + function __get($name) { + return $this->_ci->$name; + } + + /** + * Alias methods + */ + function __call($name, $args) { + switch ($name) { + case 'default' : + return call_user_func_array(array($this, 'set_default'), $args); + break; + case 'add' : + return call_user_func_array(array($this, 'append'), $args); + break; + } + } + + /** + * Returns the content when converted to a string + * @return string + */ + public function __toString() { + return (string) $this->content(); + } + + /** + * Returns the content + * @return string + */ + public function content() { + if ($this->_cache_ttl && !$this->_cached) { + $this->cache->save($this->cache_id(), $this->_content, $this->_cache_ttl); + } + + return $this->_content; + } + + /** + * Overwrite the content + * @param mixed $content + * @return Partial + */ + public function set() { + if (!$this->_cached) { + $this->_content = (string) $this->trigger(func_get_args()); + } + + return $this; + } + + /** + * Append something to the content + * @param mixed $content + * @return Partial + */ + public function append() { + if (!$this->_cached) { + $this->_content .= (string) $this->trigger(func_get_args()); + } + + return $this; + } + + /** + * Prepend something to the content + * @param mixed $content + * @return Partial + */ + public function prepend() { + if (!$this->_cached) { + $this->_content = (string) $this->trigger(func_get_args()) . $this->_content; + } + + return $this; + } + + /** + * Set content if partial is empty + * @param mixed $default + * @return Partial + */ + public function set_default($default) { + if (!$this->_cached) { + if (!$this->_content) { + $this->_content = $default; + } + } + + return $this; + } + + /** + * Load a view inside this partial, overwrite if wanted + * @param string $view + * @param array $data + * @param bool $overwrite + * @return Partial + */ + public function view($view, $data = array(), $overwrite = false) { + if (!$this->_cached) { + + // better object to array + if (is_object($data)) { + $array = array(); + foreach ($data as $k => $v) { + $array[$k] = $v; + } + $data = $array; + } + + $content = $this->_ci->load->view($view, $data, true); + + if ($overwrite) { + $this->set($content); + } else { + $this->append($content); + } + } + return $this; + } + + /** + * Parses a view inside this partial, overwrite if wanted + * @param string $view + * @param array $data + * @param bool $overwrite + * @return Partial + */ + public function parse($view, $data = array(), $overwrite = false) { + if (!$this->_cached) { + if (!class_exists('CI_Parser')) { + $this->_ci->load->library('parser'); + } + + // better object to array + if (is_object($data)) { + $array = array(); + foreach ($data as $k => $v) { + $array[$k] = $v; + } + $data = $array; + } + + $content = $this->_ci->parser->parse($view, $data, true); + + if ($overwrite) { + $this->set($content); + } else { + $this->append($content); + } + } + + return $this; + } + + /** + * Loads a widget inside this partial, overwrite if wanted + * @param string $name + * @param array $data + * @param bool $overwrite + * @return Partial + */ + public function widget($name, $data = array(), $overwrite = false) { + if (!$this->_cached) { + $widget = $this->template->widget($name, $data); + + if ($overwrite) { + $this->set($widget->content()); + } else { + $this->append($widget->content()); + } + } + return $this; + } + + /** + * Enable cache with TTL, default TTL is 60 + * @param int $ttl + * @param mixed $identifier + */ + public function cache($ttl = 60, $identifier = '') { + if (!class_exists('CI_Cache')) { + $this->_ci->load->driver('cache', array('adapter' => 'file')); + } + + $this->_cache_ttl = $ttl; + $this->_identifier = $identifier; + + if ($cached = $this->_ci->cache->get($this->cache_id())) { + $this->_cached = true; + $this->_content = $cached; + } + return $this; + } + + /** + * Used for cache identification + * @return string + */ + private function cache_id() { + if ($this->_identifier) { + return $this->_name . '_' . $this->_identifier . '_' . md5(get_class($this) . implode('', $this->_args)); + } else { + return $this->_name . '_' . md5(get_class($this) . implode('', $this->_args)); + } + } + + /** + * Trigger returns the result if a trigger is set + * @param array $args + * @return string + */ + public function trigger($args) { + if (!$this->_trigger) { + return implode('', $args); + } else { + return call_user_func_array($this->_trigger, $args); + } + } + + /** + * Bind a trigger function + * Can be used like bind($this, "function") or bind("function") + * @param mixed $arg + */ + public function bind() { + if ($count = func_num_args()) { + if ($count >= 2) { + $args = func_get_args(); + $obj = array_shift($args); + $func = array_pop($args); + + foreach ($args as $trigger) { + $obj = $obj->$trigger; + } + + $this->_trigger = array($obj, $func); + } else { + $args = func_get_args(); + $this->_trigger = reset($args); + } + } else { + $this->_trigger = FALSE; + } + } +} + +/** + * The mother of all widgets + * it represent a generic HTML element + */ +class Widget extends Partial +{ + // The name of the array present in the data array given to the view that will render this widget + const HTML_ARG_NAME = 'HTML'; + const HTML_DEFAULT_VALUE = ''; // Default value of the html element + const HTML_NAME = 'name'; // HTML name attribute + const HTML_ID = 'id'; // HTML id attribute + + const EXTERNAL_BLOCK = 'externalBlock'; // + const EXTERNAL_START_BLOCK_HTML_TAG = '
'; // + const EXTERNAL_END_BLOCK_HTML_TAG = '
'; // + + /** + * It gets also the htmlArgs array as parameter, it will be used to set the HTML properties + */ + public function __construct($name, $args = array(), $htmlArgs = array()) + { + parent::__construct($name, $args); + + // Initialising HTML properties + $this->_setHtmlProperties($htmlArgs); + + // Loads helper message to manage returning messages + $this->load->helper('message'); + } + + /** + * (non-PHPdoc) + * @see Partial::content() + */ + public function content() + { + if (!$this->_cached) + { + if (method_exists($this, 'display')) + { + // capture output + ob_start(); + $this->display($this->_args); + $buffer = ob_get_clean(); + + // if no content is produced but there was direct ouput we set + // that output as content + if (!$this->_content && $buffer) + { + $this->set($buffer); + } + } + } + + return parent::content(); + } + + /** + * Initialising html properties, such as the id and name attributes of the HTML element + */ + private function _setHtmlProperties($htmlArgs) + { + // If $htmlArgs wasn't already stored in $this->_args + if (!isset($this->_args[Widget::HTML_ARG_NAME])) + { + $this->_args[Widget::HTML_ARG_NAME] = array(); + + // Avoids that elements in a HTML page have the same name or id + $randomIdentifier = uniqid(rand(0, 1000)); + $this->_args[Widget::HTML_ARG_NAME][Widget::HTML_ID] = $randomIdentifier; + $this->_args[Widget::HTML_ARG_NAME][Widget::HTML_NAME] = $randomIdentifier; + + foreach($htmlArgs as $argName => $argValue) + { + $this->_args[Widget::HTML_ARG_NAME][$argName] = $argValue; + } + } + } + + /** + * + */ + public static function printAttribute($htmlArgs, $attribute, $isValuePresent = true) + { + if ($attribute != null) + { + if (isset($htmlArgs[$attribute])) + { + if ($isValuePresent === true) + { + $value = $htmlArgs[$attribute]; + + if (is_bool($value)) + { + $value = $value ? 'true' : 'false'; + } + + echo sprintf('%s="%s"', $attribute, $value); + } + else + { + echo $attribute; + } + } + } + } + + /** + * + */ + public static function printStartBlock($htmlArgs) + { + if (isset($htmlArgs[Widget::EXTERNAL_BLOCK]) + && $htmlArgs[Widget::EXTERNAL_BLOCK] === true) + { + echo Widget::EXTERNAL_START_BLOCK_HTML_TAG; + } + } + + /** + * + */ + public static function printEndBlock($htmlArgs) + { + if (isset($htmlArgs[Widget::EXTERNAL_BLOCK]) + && $htmlArgs[Widget::EXTERNAL_BLOCK] === true) + { + echo Widget::EXTERNAL_END_BLOCK_HTML_TAG; + } + } +} + +/** + * It exends the Widget class to represent an HTML dropdown + */ +class DropdownWidget extends Widget +{ + // The name of the element of the data array given to the view + // this element is an array of elements to be place inside the dropdown + const WIDGET_DATA_ELEMENTS_ARRAY_NAME = 'ELEMENTS_ARRAY'; + // Name of the property that will be used to store the value attribute of the option tag + const ID_FIELD = 'id'; + // Name of the property that will be used to store the value between the option tags + const DESCRIPTION_FIELD = 'description'; + // The name of the element of the data array given to the view + // this element is used to tell what element of the dropdown is selected + const SELECTED_ELEMENT = 'selectedElement'; + // + const HTML_DEFAULT_VALUE = 'null'; + + const SIZE = 'size'; // + const MULTIPLE = 'multiple'; // + + /** + * + */ + public function __construct($name, $args = array(), $htmlArgs = array()) + { + parent::__construct($name, $args, $htmlArgs); + + // + if (!isset($this->_args[DropdownWidget::SELECTED_ELEMENT])) + { + $this->_args[DropdownWidget::SELECTED_ELEMENT] = DropdownWidget::HTML_DEFAULT_VALUE; + } + } + + /** + * + */ + public function setMultiple() + { + $this->_args[Widget::HTML_ARG_NAME][DropdownWidget::MULTIPLE] = DropdownWidget::MULTIPLE; + $this->_args[Widget::HTML_ARG_NAME][Widget::HTML_NAME] .= '[]'; + } + + /** + * + */ + public function isMultipleDropdown() + { + $isMultipleDropdown = false; + + if (isset($this->_args[Widget::HTML_ARG_NAME][DropdownWidget::MULTIPLE]) + && $this->_args[Widget::HTML_ARG_NAME][DropdownWidget::MULTIPLE] == DropdownWidget::MULTIPLE) + { + $isMultipleDropdown = true; + } + + return $isMultipleDropdown; + } + + /** + * Add the correct select to the model used to load a list of elemets for this dropdown + * @param model $model the model used to load elements + * @param string $idName the name of the field that will used to be the value of the option tag + * @param string $descriptionName the name of the field that will used to be displayed in the dropdown + */ + protected function addSelectToModel($model, $idName, $descriptionName) + { + $model->addSelect( + sprintf( + '%s AS %s, %s AS %s', + $idName, + DropdownWidget::ID_FIELD, + $descriptionName, + DropdownWidget::DESCRIPTION_FIELD + ) + ); + } + + /** + * Set the array used to populate the dropdown + * @param array $elements list used to populate this dropdown + * @param boolean $emptyElement if an empty element must be added at the beginning of the dropdown + * @param string $stdDescription description of the empty element + * @param string $noDataDescription description if no data are found + * @param string $id value of the attribute value of the empty element + */ + protected function setElementsArray( + $elements, $emptyElement = false, $stdDescription = '' , $noDataDescription = 'No data found' , $id = DropdownWidget::HTML_DEFAULT_VALUE + ) + { + $tmpElements = array(); + + if (isError($elements)) + { + if (is_object($elements) && isset($elements->retval)) + { + show_error($elements->retval); + } + else if (is_string($elements)) + { + show_error($elements); + } + else + { + show_error('Generic error occurred'); + } + } + else + { + if ($emptyElement === true && $this->isMultipleDropdown() == false) + { + $tmpElements = $this->addElementAtBeginning( + $elements, + $stdDescription, + $noDataDescription, + $id + ); + } + else + { + $tmpElements = $elements->retval; + } + + $this->_args[DropdownWidget::WIDGET_DATA_ELEMENTS_ARRAY_NAME] = $tmpElements; + } + } + + /** + * Adds an element to the beginning of the array + */ + protected function addElementAtBeginning($elements, $stdDescription, $noDataDescription, $id) + { + $element = new stdClass(); + $element->{DropdownWidget::ID_FIELD} = $id; + $element->{DropdownWidget::DESCRIPTION_FIELD} = $stdDescription; + + if (!hasData($elements)) + { + $element->{DropdownWidget::DESCRIPTION_FIELD} = $noDataDescription; + } + + array_unshift($elements->retval, $element); + + return $elements->retval; + } + + /** + * Loads the dropdown view with all the elements to be displayed + */ + protected function loadDropDownView() + { + $this->view('widgets/dropdown', $this->_args); + } +} + +/** + * + */ +class DropdownWidgetUDF extends DropdownWidget +{ + /** + * + */ + public function render($parameters) + { + $tmpElements = array(); + + // + foreach($parameters as $parameter) + { + // + if ((is_array($parameter) && count($parameter) == 2) + || (is_string($parameter) || is_numeric($parameter)) + || (is_object($parameter) && isset($parameter->{PARENT::ID_FIELD}) && isset($parameter->{PARENT::DESCRIPTION_FIELD}))) + { + $element = new stdClass(); // + // + if (is_array($parameter) && count($parameter) == 2) + { + $element->{PARENT::ID_FIELD} = $parameter[0]; // + $element->{PARENT::DESCRIPTION_FIELD} = $parameter[1]; // + } + // + else if (is_string($parameter) || is_numeric($parameter)) + { + $element->{PARENT::ID_FIELD} = $parameter; // + $element->{PARENT::DESCRIPTION_FIELD} = $parameter; // + } + // + else if (is_object($parameter) && isset($parameter->{PARENT::ID_FIELD}) && isset($parameter->{PARENT::DESCRIPTION_FIELD})) + { + $element->{PARENT::ID_FIELD} = $parameter->{PARENT::ID_FIELD}; // + $element->{PARENT::DESCRIPTION_FIELD} = $parameter->{PARENT::DESCRIPTION_FIELD}; // + } + + array_push($tmpElements, $element); // + } + } + + $this->setElementsArray( + success($tmpElements), + true, + $this->_args[Widget::HTML_ARG_NAME][UDFWidgetTpl::PLACEHOLDER], + 'No data found for this UDF' + ); + + $this->loadDropDownView(); + + echo $this->content(); + } +} + +/** + * It exends the Widget class to represent an HTML textarea + */ +class TextareaWidget extends Widget +{ + const TEXT = 'text'; // + const ROWS = 'rows'; // + const COLS = 'cols'; // + + /** + * + */ + protected function setText($text) + { + $this->_args[TextareaWidget::TEXT] = $text; + } + + /** + * + */ + protected function loadTextareaView() + { + $this->view('widgets/textarea', $this->_args); + } +} + +/** + * + */ +class TextareaWidgetUDF extends TextareaWidget +{ + /** + * + */ + public function render($parameters) + { + if ($parameters != null) + { + $this->setText($parameters); + } + else + { + $this->setText(''); + } + + $this->loadTextareaView(); + + echo $this->content(); + } +} + +/** + * It exends the Widget class to represent an HTML textarea + */ +class TextfieldWidget extends Widget +{ + const VALUE = 'text'; // + const SIZE = 'size'; // + + /** + * + */ + protected function setValue($value) + { + $this->_args[TextfieldWidget::VALUE] = $value; + } + + /** + * + */ + protected function loadTextfieldView() + { + $this->view('widgets/textfield', $this->_args); + } +} + +/** + * + */ +class TextfieldWidgetUDF extends TextfieldWidget +{ + /** + * + */ + public function render($parameters) + { + if ($parameters != null) + { + $this->setValue($parameters); + } + else + { + $this->setValue(''); + } + + $this->loadTextfieldView(); + + echo $this->content(); + } +} + +/** + * It exends the Widget class to represent an HTML dropdown + */ +class CheckboxWidget extends Widget +{ + // Name of the property that will be used to store the value attribute of the option tag + const VALUE_FIELD = 'value'; + // Name of the property that will be used to store the value between the option tags + const DESCRIPTION_FIELD = 'description'; + // Value of value attribute of the checkbox + const CHECKBOX_VALUE = 'true'; + + /** + * + */ + protected function loadCheckboxView() + { + $this->view('widgets/checkbox', $this->_args); + } +} + +/** + * + */ +class CheckboxWidgetUDF extends CheckboxWidget +{ + /** + * + */ + public function render() + { + $this->loadCheckboxView(); + + echo $this->content(); + } +} + +/** + * Defined here because these constants can be used + * in the views also + */ +abstract class UDFWidgetTpl extends Widget +{ + const WIDGET_NAME = 'UDFWidget'; + const SCHEMA_ARG_NAME = 'schema'; + const TABLE_ARG_NAME = 'table'; + const FIELD_ARG_NAME = 'field'; + const UDFS_ARG_NAME = 'udfs'; + + // HTML components + const TITLE = 'description'; + const LABEL = 'title'; + const PLACEHOLDER = 'placeholder'; + const DEFAULT_VALUE = 'defaultValue'; + + // Validation attributes + const REGEX = 'regex'; + const REQUIRED = 'required'; + const MAX_VALUE = 'max-value'; + const MIN_VALUE = 'min-value'; + const MAX_LENGTH = 'max-length'; + const MIN_LENGTH = 'min-length'; } \ No newline at end of file diff --git a/application/widgets/UDFWidget.php b/application/widgets/UDFWidget.php index e9f7ff97f..4f847c023 100644 --- a/application/widgets/UDFWidget.php +++ b/application/widgets/UDFWidget.php @@ -215,6 +215,10 @@ class UDFWidget extends UDFWidgetTpl { $this->_args[DropdownWidget::SELECTED_ELEMENT] = $this->_args[UDFWidgetTpl::UDFS_ARG_NAME][$jsonSchema->{UDFWidget::NAME}]; } + else + { + $this->_args[DropdownWidget::SELECTED_ELEMENT] = null; + } $dropdownWidgetUDF = new DropdownWidgetUDF($this->_name, $this->_args); $parameters = array();