diff --git a/extension.meta.xml b/extension.meta.xml index a33f64a..f0ec4da 100644 --- a/extension.meta.xml +++ b/extension.meta.xml @@ -18,6 +18,13 @@ + + - General Code cleanup + - Added validation and error messages for the field's configuration settings + - Added (dynamic) default values for configuration parameters "Start value" and "Increment value" + - Updated Settings Layout + - Removed tables from readme, outsourced the chapter "Filtering syntax" to github wiki + - Moved from jQuery UI to noUislider - Refactored, fixed and extended filtering functions diff --git a/fields/field.slider.php b/fields/field.slider.php index 390fb33..65b1781 100644 --- a/fields/field.slider.php +++ b/fields/field.slider.php @@ -1,17 +1,48 @@ Symphony Error

You cannot directly access this file

'); + Class fieldSlider extends Field { - + + /** * * Constructor for the Field object */ public function __construct() { - // call the parent constructor parent::__construct(); - // set the name of the field $this->_name = __('Slider'); + $this->set('location', 'sidebar'); + } + + + + /*------------------------------------------------------------------------------------------------- + SETUP + -------------------------------------------------------------------------------------------------*/ + + + public function createTable() { + try { + Symphony::Database()->query(sprintf(" + CREATE TABLE IF NOT EXISTS `tbl_entries_data_%d` ( + `id` int(11) unsigned NOT NULL auto_increment, + `entry_id` int(11) unsigned NOT NULL, + `value` varchar(255) default NULL, + `value_from` varchar(255) default NULL, + `value_to` varchar(255) default NULL, + PRIMARY KEY (`id`), + KEY `entry_id` (`entry_id`), + KEY `value` (`value`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + ", $this->get('id') + )); + return true; + } + catch (Exception $ex) { + return false; + } } @@ -20,6 +51,133 @@ public function canFilter(){ } + + /*------------------------------------------------------------------------------------------------- + SETTINGS + -------------------------------------------------------------------------------------------------*/ + + + /** + * Displays settings panel in section editor. + * + * @param XMLElement $wrapper - parent element wrapping the field + * @param array $errors - array with field errors, $errors['name-of-field-element'] + */ + + public function displaySettingsPanel(&$wrapper, $errors = null) { + + parent::displaySettingsPanel($wrapper, $errors); + + /* Fieldset & Group */ + $fieldset = new XMLElement('fieldset'); + $group = new XMLElement('div', NULL, array('class' => 'two columns')); + + /* Minimum Value */ + $min_label = Widget::Label(__('Minimum value')); + $min_label->setAttribute('class', 'column'); + $min_label->appendChild(Widget::Input('fields['.$this->get('sortorder').'][min_value]', $this->get('min_range'))); + if (isset($errors['min_value'])) { + $group->appendChild(Widget::Error($min_label, $errors['min_value'])); + } else { + $group->appendChild($min_label); + } + + /* Maximum Value */ + $max_label = Widget::Label(__('Maximum value')); + $max_label->setAttribute('class', 'column'); + $max_label->appendChild(Widget::Input('fields['.$this->get('sortorder').'][max_value]', $this->get('max_range'))); + if (isset($errors['max_value'])) { + $group->appendChild(Widget::Error($max_label, $errors['max_value'])); + } else { + $group->appendChild($max_label); + } + + /* Start Value */ + $start_label = Widget::Label(__('Start Value')); + $start_label->setAttribute('class', 'column'); + $start_label->appendChild(Widget::Input('fields['.$this->get('sortorder').'][start_value]', $this->get('start_value'))); + if (isset($errors['start_value'])) { + $group->appendChild(Widget::Error($start_label, $errors['start_value'])); + } else { + $group->appendChild($start_label); + } + + /* Incremental Value */ + $inc_label = Widget::Label(__('Incremental value')); + $inc_label->setAttribute('class', 'column'); + $inc_label->appendChild(Widget::Input('fields['.$this->get('sortorder').'][increment_value]', $this->get('increment_value'))); + if (isset($errors['increment_value'])) { + $group->appendChild(Widget::Error($inc_label, $errors['increment_value'])); + } else { + $group->appendChild($inc_label); + } + + /* Enable Range Mode */ + $range_label = Widget::Label(); + $range_label->setAttribute('class', 'column'); + $attributes = array('type'=>'checkbox', 'name'=>'fields['.$this->get('sortorder').'][range]', 'value'=>'yes'); + if($this->get('range') == 1) {$attributes['checked'] = 'checked';} + $range_checkbox = new XMLElement('input', ' '.__('Enable range mode (Adds a second handle for selecting a value range)'), $attributes); + $range_label->appendChild($range_checkbox); + $group->appendChild($range_label); + + $fieldset->appendChild($group); + $wrapper->appendChild($fieldset); + + /* Fieldset (Default Settings) */ + + $fieldset = new XMLElement('fieldset'); + $this->appendShowColumnCheckbox($fieldset); + $wrapper->appendChild($fieldset); + + } + + + /** + * + * Validate the fields settings and return errors if wrong or missing input is detected + * + * @param array $errors + * @param boolean $checkForDuplicates + */ + + public function checkFields(&$errors, $checkForDuplicates=true) { + + if(!is_array($errors)) $errors = array(); + + $check['min_value'] = $this->get('min_value'); + $check['max_value'] = $this->get('max_value'); + $check['start_value'] = $this->get('start_value'); + $check['increment_value'] = $this->get('increment_value'); + + // Validate Minimum Value + if($check['min_value'] == '') { + $errors['min_value'] = __('Minimum Value must not be empty. Please fill in a natural number.'); + } else if (!preg_match('/^[0-9]+$/', $check['min_value'])) { + $errors['min_value'] = __('Minimum Value must be a natural number.'); + } + + // Validate Maximum Value + if($check['max_value'] == '') { + $errors['max_value'] = __('Maximum Value must not be empty. Please fill in a natural number.'); + } else if (!preg_match('/^[0-9]+$/', $check['max_value'])) { + $errors['max_value'] = __('Maximum Value must be a natural number.'); + } + + // Validate Start Value + if($check['start_value'] != '' && !preg_match('/^[0-9]+$/', $check['start_value'])) { + $errors['start_value'] = __('Start Value must be a natural number.'); + } + + // Validate Increment Value + if($check['increment_value'] != '' && !preg_match('/^[0-9]+$/', $check['increment_value'])) { + $errors['increment_value'] = __('Incremental Value must be a natural number.'); + } + + return Field::checkFields($errors, $checkForDuplicates); + } + + /** * * Save field settings into the field's table @@ -37,8 +195,8 @@ public function commit() { $fields['range'] = $this->get('range') == false ? 0 : 1; $fields['min_range'] = $this->get('min_value'); $fields['max_range'] = $this->get('max_value'); - $fields['start_value'] = $this->get('start_value'); - $fields['increment_value'] = $this->get('increment_value'); + $fields['start_value'] = $this->get('start_value') == '' ? $this->get('min_value') : $this->get('start_value'); + $fields['increment_value'] = $this->get('increment_value') == '' ? '0' : $this->get('increment_value'); Symphony::Database()->query("DELETE FROM `tbl_fields_".$this->handle()."` WHERE `field_id` = '$id' LIMIT 1"); @@ -46,6 +204,48 @@ public function commit() { } + + /*------------------------------------------------------------------------------------------------- + INPUT + -------------------------------------------------------------------------------------------------*/ + + + /** + * + * Build the UI for the publish page + * + * @param XMLElement $wrapper + * @param mixed $data + * @param mixed $flagWithError + * @param string $fieldnamePrefix + * @param string $fieldnamePostfix + */ + + public function displayPublishPanel(&$wrapper, $data=NULL, $flagWithError=NULL, $fieldnamePrefix=NULL, $fieldnamePostfix=NULL){ + + $value = General::sanitize($data['value']); + if(empty($value)) + { + $value = $this->get('start_value'); + } + + $label = Widget::Label($this->get('label')); + $label->appendChild(new XMLElement('i', 'Value', array('class'=>'slider-field-label-value'))); + $label->appendChild(Widget::Input('fields'.$fieldnamePrefix.'['.$this->get('element_name').']'.$fieldnamePostfix, (strlen($value) != 0 ? $value : NULL), 'text', array( + 'readonly'=>'readonly', + 'data-min-range'=>$this->get('min_range'), + 'data-max-range'=>$this->get('max_range'), + 'data-range'=>$this->get('range'), + 'data-increment-value'=>$this->get('increment_value') + ))); + $label->appendChild(new XMLElement('div', '', array('id'=>'noUi-slider-'.$this->get('id')))); + + // In case of an error: + if($flagWithError != NULL) $wrapper->appendChild(Widget::wrapFormElementWithError($label, $flagWithError)); + else $wrapper->appendChild($label); + } + + /** * * Process data before saving into database. @@ -56,7 +256,7 @@ public function commit() { * @param boolean $simulate * @param int $entry_id * - * @return Array - data to be inserted into DB + * @return array - data to be inserted into DB */ public function processRawFieldData($data, &$status, &$message=null, $simulate = false, $entry_id = null) { @@ -78,11 +278,38 @@ public function processRawFieldData($data, &$status, &$message=null, $simulate = return $result; } - - - /* ******* DATA SOURCE ******* */ - + + /*------------------------------------------------------------------------------------------------- + OUTPUT + -------------------------------------------------------------------------------------------------*/ + + + /** + * Append the field's data into the XML tree of a Data Source + * + * @param $wrapper + * @param $data + * @param $encode + */ + + public function appendFormattedElement(&$wrapper, $data, $encode=false) { + $value = $data['value']; + if($this->get('range') == 1) { + $element = new XMLElement($this->get('element_name'), null, array('range'=>'yes', 'from'=>$data['value_from'], 'to'=>$data['value_to'])); + } else { + $element = new XMLElement($this->get('element_name'), $data['value'], array('range'=>'no')); + } + $wrapper->appendChild($element); + } + + + + /*------------------------------------------------------------------------------------------------- + FILTERING + -------------------------------------------------------------------------------------------------*/ + + /** * Build SQL for fetching the data from the DB * @@ -229,134 +456,4 @@ public function buildDSRetrievalSQL($data, &$joins, &$where, $andOperation = fal return true; } - - - /** - * Appends data into the XML tree of a Data Source - * - * @param $wrapper - * @param $data - */ - - public function appendFormattedElement(&$wrapper, $data, $encode=false) { - $value = $data['value']; - if($this->get('range') == 1) { - $element = new XMLElement($this->get('element_name'), null, array('range'=>'yes', 'from'=>$data['value_from'], 'to'=>$data['value_to'])); - } else { - $element = new XMLElement($this->get('element_name'), $data['value'], array('range'=>'no')); - } - $wrapper->appendChild($element); - } - - - - /* ********* UI *********** */ - - - /** - * - * Builds the UI for the publish page - * - * @param XMLElement $wrapper - * @param mixed $data - * @param mixed $flagWithError - * @param string $fieldnamePrefix - * @param string $fieldnamePostfix - */ - - public function displayPublishPanel(&$wrapper, $data=NULL, $flagWithError=NULL, $fieldnamePrefix=NULL, $fieldnamePostfix=NULL){ - - $value = General::sanitize($data['value']); - if(empty($value)) - { - $value = $this->get('start_value'); - } - - $label = Widget::Label($this->get('label')); - $label->appendChild(new XMLElement('i', 'Value', array('class'=>'slider-field-label-value'))); - $label->appendChild(Widget::Input('fields'.$fieldnamePrefix.'['.$this->get('element_name').']'.$fieldnamePostfix, (strlen($value) != 0 ? $value : NULL), 'text', array( - 'readonly'=>'readonly', - 'data-min-range'=>$this->get('min_range'), - 'data-max-range'=>$this->get('max_range'), - 'data-range'=>$this->get('range'), - 'data-increment-value'=>$this->get('increment_value') - ))); - $label->appendChild(new XMLElement('div', '', array('id'=>'noUi-slider-'.$this->get('id')))); - - // In case of an error: - if($flagWithError != NULL) $wrapper->appendChild(Widget::wrapFormElementWithError($label, $flagWithError)); - else $wrapper->appendChild($label); - } - - - - /** - * - * Builds the UI for the field's settings when creating/editing a section - * - * @param XMLElement $wrapper - * @param array $errors - */ - - public function displaySettingsPanel(&$wrapper, $errors = null) { - - parent::displaySettingsPanel($wrapper, $errors); - - $div = new XMLElement('div', NULL, array('class' => 'group')); - $label = Widget::Label(__('Minimum value')); - $label->appendChild(Widget::Input('fields['.$this->get('sortorder').'][min_value]', $this->get('min_range'))); - $div->appendChild($label); - - $label = Widget::Label(__('Maximum value')); - $label->appendChild(Widget::Input('fields['.$this->get('sortorder').'][max_value]', $this->get('max_range'))); - $div->appendChild($label); - - $wrapper->appendChild($div); - - $div = new XMLElement('div', NULL, array('class' => 'group')); - $label = Widget::Label(__('Start Value')); - $label->appendChild(Widget::Input('fields['.$this->get('sortorder').'][start_value]', $this->get('start_value'))); - $div->appendChild($label); - - $label = Widget::Label(__('Incremental value')); - $label->appendChild(Widget::Input('fields['.$this->get('sortorder').'][increment_value]', $this->get('increment_value'))); - $div->appendChild($label); - - $wrapper->appendChild($div); - - $label = Widget::Label(); - $attributes = array('type'=>'checkbox', 'name'=>'fields['.$this->get('sortorder').'][range]', 'value'=>'yes'); - if($this->get('range') == 1) - { - $attributes['checked'] = 'checked'; - } - $checkbox = new XMLElement('input', ' Define a range', $attributes); - $label->appendChild($checkbox); - $wrapper->appendChild($label); - $this->appendShowColumnCheckbox($wrapper); - } - - - - /** - * - * Create Table - * - */ - public function createTable(){ - return Symphony::Database()->query( - "CREATE TABLE IF NOT EXISTS `tbl_entries_data_" . $this->get('id') . "` ( - `id` int(11) unsigned NOT NULL auto_increment, - `entry_id` int(11) unsigned NOT NULL, - `value` varchar(255) default NULL, - `value_from` varchar(255) default NULL, - `value_to` varchar(255) default NULL, - PRIMARY KEY (`id`), - KEY `entry_id` (`entry_id`), - KEY `value` (`value`) - ) ENGINE=MyISAM;" - ); - } - - } diff --git a/readme.md b/readme.md index 87fb0e3..add6bda 100644 --- a/readme.md +++ b/readme.md @@ -15,29 +15,25 @@ A slider with a configurable value range (minimum – maximum, e.g. `0`–`100`) ### Parameters -| Parameter | Default | Description | -| :--- | :--- | :--- | -| **Minimum Value** | – | Determines the lower end of the sliders number range. | -| **Maximum Value** | – | Determines the upper end of the sliders number range. | -| **Start Value** | – | Determines the initial value of the slider and therefore the position of the (first) handle. 1 | -| **Incremental Value** | `1` | Determines the amount/interval the slider changes on movement. 2 | -| **Define a Range** | `No` | Determines whether the slider will use one or two handles. 3 | +* **Minimum value** * : Determines the lower end of the sliders number range. +* **Maximum value** * : Determines the upper end of the sliders number range. +* **Start value** * : Determines the initial value of the slider and therefore the position of the (first) handle. 1 +* **Incremental value** : Determines the amount/interval the slider changes on movement. 2 +* **Enable range mode** : Determines whether the slider will use one or two handles. 3 - 1) It goes without saying that this value should be in the range defined by the first two configuration parameters. -
- 2) The full specified value range of the slider (minimum – maximum) should be evenly divisible by this value. -
+ * Mandatory parameters.
+ 1) It goes without saying that this value should be in the range defined by the first two configuration parameters.
+ 2) The full specified value range of the slider (minimum – maximum) should be evenly divisible by this value. Default is `0`.
3) One handle allows for selecting and storing a single value. Two handles allow for selecting and storing a range of values.
### Limitations ### -* The field currently only supports _natural numbers_ (`0`,`1`,`2`,`3`,…) as values for '**Minimum Value**', '**Maximum Value**' and '**Start Value**. -* The field currently only supports _counting numbers_ (`1`,`2`,`3`,…) as value for '**Incremental Value**'. -* There is no parameter to set a default '**End Value**' when using the slider in _range mode_. The predefined range will consist of the '**Start Value**' and a second value that's automatically calculated by adding the '**Incremental Value**' to the '**Start Value**'. +* The field currently only supports _natural numbers_ (`0`,`1`,`2`,`3`,…) as values for '**Minimum value**', '**Maximum value**', '**Start value** and '**Incremental value**'. +* There is no parameter to set a default '**End value**' when using the slider in _range mode_. The predefined range will consist of the '**Start value**' and a second value that's automatically calculated by adding the '**Incremental value**' to the '**Start value**'. ## 3. Filtering ## @@ -55,31 +51,14 @@ A slider with a configurable value range (minimum – maximum, e.g. `0`–`100`) ### Filtering Syntax -The above mentioned filter modes can be used in the following ways: - -| Filter Mode | Filter String (Example) | -| :--- | :--- | -| **is** | `0` | -| **is** | `1, 2` | -| **is** | `{$param}` | -| **is** | `{$param-a}, {$param-b}` | -| **less than** | `less than 10` **or** `< 10` | -| **less than** | `less than {$param}` **or** `< {$param}` | -| **greater than** | `greater than 0` **or** `> 0` | -| **greater than** | `greater than {$param}` **or** `> {$param}` | -| **between** | `0 to 100`**or** `0-100` | -| **between** | `{$param} to 100` **or** `{$param}-100` | -| **between** | `{$param-a} to {$param-b}` **or** `{$param-a}-{$param-b}` | +Documentation and examples regarding the filtering syntax can be found in the extension's [github wiki](https://github.com/twiro/slider/wiki/filtering#2-filtering-syntax). - - Tip: You can give your parameters a default fallback value by using `{$param:XY}`-syntax. - ### Filtering Logic Entries filtered by slider field will be returned as result … -* ... if the slider defines a **single value** and a **single filter value** is **equal** to that value. -* ... if the slider defines a **single value** that lies **within** a **range of filter values**. -* ... if the slider defines a **value range** and a **single filter value** is **within** that range. -* ... if the slider defines a **value range** that lies **within** a **range of filter values**. +* ... if the entry's slider defines a **single value** and a **single filter value** is **equal** to that value. +* ... if the entry's slider defines a **single value** that lies **within** a **range of filter values**. +* ... if the entry's slider defines a **value range** and a **single filter value** is **within** that range. +* ... if the entry's slider defines a **value range** that lies **within** a **range of filter values**. diff --git a/tests.md b/tests.md index 2071f91..6363aa3 100644 --- a/tests.md +++ b/tests.md @@ -1,4 +1,4 @@ -# Slider Field +# Slider Field – Filtering Tests - [Github Repo](https://github.com/twiro/slider) - [Symphony Extensions](http://symphonyextensions.com/extensions/slider) @@ -23,7 +23,7 @@ ## Tests – Single Values -###### Performed with Symphony CMS 2.3.1 + 2.4.0 and Slider Field 1.0 +###### Performed with Slider Field 1.1 and Symphony CMS 2.3.1 and 2.4.0 | Nr. | Filter Mode | Filter Value | Expected Result | DF | PF | | :--- | :--- | :--- | :--- | :--- | :--- | @@ -38,10 +38,12 @@ | 3.1 | **greater than** | `greater than 0` | **2**, **3**, **4**, **5** | :white_check_mark: | … | | 3.2 | **greater than** | `greater than 10` | **4**, **5** | :white_check_mark: | … | | 3.3 | **greater than** | `> 100` | – | :white_check_mark: | … | +| 3.4 | **greater than** + **less than** | `> 1 + < 100` | **3**, **4** | :white_check_mark: | … | | 4.1 | **between** | `0 to 1` | **1**, **2** | :white_check_mark: | … | | 4.2 | **between** | `0 to 10` | **1**, **2**, **3** | :white_check_mark: | … | | 4.3 | **between** | `0 to 100` | **1**, **2**, **3**, **4**, **5** | :white_check_mark: | … | | 4.3 | **between** | `1-99` | **2**, **3**, **4** | :white_check_mark: | … | +| 4.4 | **between** | `0-1, 99-100` | **1**, **2**, **4**, **5** | :white_check_mark: | … | DF = Datasource Filtering @@ -61,7 +63,7 @@ ## Tests – Value Range -###### Performed with Symphony CMS 2.3.1 + 2.4.0 and Slider Field 1.0 +###### Performed with Slider Field 1.1 and Symphony CMS 2.3.1 and 2.4.0 | Nr. | Filter Mode | Filter Value | Expected Result | DF | PF | | :--- | :--- | :--- | :--- | :--- | :--- | @@ -76,11 +78,14 @@ | 3.1 | **greater than** | `greater than 0` | **2**, **3**, **4**, **5** | :white_check_mark: | … | | 3.2 | **greater than** | `greater than 10` | **4**, **5** | :white_check_mark: | … | | 3.3 | **greater than** | `> 100` | – | :white_check_mark: | … | +| 3.4 | **greater than** + **less than** | `> 1 + < 100` | **3** | :white_check_mark: | … | | 4.1 | **between** | `0 to 1` | **1** | :white_check_mark: | … | | 4.2 | **between** | `0 to 10` | – | :white_check_mark: | … | | 4.3 | **between** | `9 to 10` | **2**, **3** | :white_check_mark: | … | | 4.4 | **between** | `50-75` | **3**, **4** | :white_check_mark: | … | | 4.4 | **between** | `0-100` | – | :white_check_mark: | … | +| 4.5 | **between** | `0-1, 50-75` | **1**, **3**, **4** | :white_check_mark: | … | +| 4.6 | **between** | `50-75 + 80-90` | **3**, **4** | :white_check_mark: | … | DF = Datasource Filtering