Attached Files |
smart_filters_core.patch [^] (33,057 bytes) 2011-12-20 10:23
[Show Content]
Index: admin_templates/incs/form_blocks.tpl
===================================================================
--- admin_templates/incs/form_blocks.tpl (revision 14888)
+++ admin_templates/incs/form_blocks.tpl (working copy)
@@ -930,6 +930,22 @@
</inp2:m_if>
</inp2:m_DefineElement>
+<inp2:m_DefineElement name="toolbar_button" icon="" title="" short_title="" toolbar="a_toolbar">
+ <inp2:m_Param name="toolbar"/>.AddButton(
+ new ToolBarButton(
+ '<inp2:m_Param name="icon"/>',
+ <inp2:m_if check="m_Param" name="short_title">
+ '<inp2:m_Phrase label="$title" escape="1"/>::<inp2:m_phrase label="$short_title" escape="1"/>',
+ <inp2:m_else/>
+ '<inp2:m_Phrase label="$title" escape="1"/>',
+ </inp2:m_if>
+ function() {
+ <inp2:m_Param name="content"/>
+ }
+ )
+ );
+</inp2:m_DefineElement>
+
<inp2:m_DefineElement name="tabs_container" tabs_render_as="">
<table cellpadding="0" cellspacing="0" style="width: 100%;">
<tr>
Index: admin_templates/item_filters/item_filter_edit.tpl
===================================================================
--- admin_templates/item_filters/item_filter_edit.tpl (revision 0)
+++ admin_templates/item_filters/item_filter_edit.tpl (revision 0)
@@ -0,0 +1,81 @@
+<inp2:adm_SetPopupSize width="550" height="400"/>
+
+<inp2:m_include t="incs/header"/>
+<inp2:m_RenderElement name="combined_header" section="in-portal:item_filters" prefix="item-filter" title_preset="item_filter_edit"/>
+
+<!-- ToolBar -->
+<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
+<tbody>
+ <tr>
+ <td>
+ <script type="text/javascript">
+ a_toolbar = new ToolBar();
+
+ <inp2:m_RenderElement design="toolbar_button" icon="select" title="la_ToolTip_Save">
+ submit_event('item-filter', '<inp2:item-filter_SaveEvent/>');
+ </inp2:m_RenderElement>
+
+ <inp2:m_RenderElement design="toolbar_button" icon="cancel" title="la_ToolTip_Cancel">
+ cancel_edit('item-filter', 'OnCancelEdit', '<inp2:item-filter_SaveEvent/>', '<inp2:m_Phrase label="la_FormCancelConfirmation" js_escape="1"/>');
+ </inp2:m_RenderElement>
+
+ <inp2:m_RenderElement design="toolbar_button" icon="reset_edit" title="la_ToolTip_Reset">
+ reset_form('item-filter', 'OnReset', '<inp2:m_Phrase label="la_FormResetConfirmation" escape="1"/>');
+ </inp2:m_RenderElement>
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep1') );
+
+ <inp2:m_RenderElement design="toolbar_button" icon="prev" title="la_ToolTip_Prev">
+ go_to_id('item-filter', '<inp2:item-filter_PrevId/>');
+ </inp2:m_RenderElement>
+
+ <inp2:m_RenderElement design="toolbar_button" icon="next" title="la_ToolTip_Next">
+ go_to_id('item-filter', '<inp2:item-filter_NextId/>');
+ </inp2:m_RenderElement>
+
+ a_toolbar.Render();
+
+ <inp2:m_if check="item-filter_IsSingle">
+ a_toolbar.HideButton('prev');
+ a_toolbar.HideButton('next');
+ a_toolbar.HideButton('sep1');
+ <inp2:m_else/>
+ <inp2:m_if check="item-filter_IsLast">a_toolbar.DisableButton('next');</inp2:m_if>
+ <inp2:m_if check="item-filter_IsFirst">a_toolbar.DisableButton('prev');</inp2:m_if>
+ </inp2:m_if>
+ </script>
+ </td>
+ </tr>
+</tbody>
+</table>
+
+<inp2:item-filter_SaveWarning name="grid_save_warning"/>
+<inp2:item-filter_ErrorWarning name="form_error_warning"/>
+
+<div id="scroll_container">
+ <table class="edit-form">
+ <inp2:m_RenderElement name="inp_id_label" prefix="item-filter" field="FilterId" title="la_fld_Id"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="item-filter" field="ItemPrefix"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="item-filter" field="FilterField"/>
+ <inp2:m_RenderElement name="inp_edit_options" prefix="item-filter" field="FilterType" has_empty="1"/>
+ <inp2:m_RenderElement name="inp_edit_radio" prefix="item-filter" field="Enabled"/>
+ <inp2:m_RenderElement name="inp_edit_box" prefix="item-filter" field="RangeCount" style="width: 50px;"/>
+ <inp2:m_RenderElement name="inp_edit_filler"/>
+ </table>
+</div>
+
+<script type="text/javascript">
+ $(document).ready(
+ function () {
+ var $field_mask = '<inp2:item-filter_InputName name="#FIELD_NAME#" js_escape="1"/>';
+
+ $( get_control($field_mask, 'FilterType') ).change(
+ function ($e) {
+ $( get_control($field_mask, 'RangeCount', 'row') ).toggle( $(this).val() == 'range' );
+ }
+ ).change();
+ }
+ )
+</script>
+
+<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: admin_templates/item_filters/item_filter_list.tpl
===================================================================
--- admin_templates/item_filters/item_filter_list.tpl (revision 0)
+++ admin_templates/item_filters/item_filter_list.tpl (revision 0)
@@ -0,0 +1,59 @@
+<inp2:m_include t="incs/header"/>
+<inp2:m_RenderElement name="combined_header" section="in-portal:item_filters" prefix="item-filter" title_preset="item_filter_list" pagination="1"/>
+
+<!-- ToolBar -->
+<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
+<tbody>
+ <tr>
+ <td>
+ <script type="text/javascript">
+ //do not rename - this function is used in default grid for double click!
+ function edit() {
+ std_edit_item('item-filter', 'item_filters/item_filter_edit');
+ }
+
+ var a_toolbar = new ToolBar();
+
+ <inp2:m_RenderElement design="toolbar_button" icon="new_item" title="la_ToolTip_NewItemFilter" short_title="la_ToolTip_Add">
+ std_precreate_item('item-filter', 'item_filters/item_filter_edit');
+ </inp2:m_RenderElement>
+
+ <inp2:m_RenderElement design="toolbar_button" icon="edit" title="la_ToolTip_Edit" short_title="la_ShortToolTip_Edit">
+ edit();
+ </inp2:m_RenderElement>
+
+ <inp2:m_RenderElement design="toolbar_button" icon="delete" title="la_ToolTip_Delete">
+ std_delete_items('item-filter');
+ </inp2:m_RenderElement>
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep1') );
+
+ <inp2:m_RenderElement design="toolbar_button" icon="approve" title="la_ToolTip_Enable">
+ submit_event('item-filter', 'OnMassApprove');
+ </inp2:m_RenderElement>
+
+ <inp2:m_RenderElement design="toolbar_button" icon="decline" title="la_ToolTip_Disable">
+ submit_event('item-filter', 'OnMassDecline');
+ </inp2:m_RenderElement>
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep2') );
+
+ <inp2:m_RenderElement design="toolbar_button" icon="view" title="la_ToolTip_View">
+ show_viewmenu(a_toolbar,'view');
+ </inp2:m_RenderElement>
+
+ a_toolbar.Render();
+ </script>
+ </td>
+
+ <inp2:m_RenderElement name="search_main_toolbar" prefix="item-filter" grid="Default"/>
+ </tr>
+</tbody>
+</table>
+
+<inp2:m_RenderElement name="grid" PrefixSpecial="item-filter" IdField="FilterId" grid="Default"/>
+<script type="text/javascript">
+ Grids['item-filter'].SetDependantToolbarButtons( new Array('edit', 'delete', 'approve', 'decline') );
+</script>
+
+<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: install/install_schema.sql
===================================================================
--- install/install_schema.sql (revision 14888)
+++ install/install_schema.sql (working copy)
@@ -817,6 +817,18 @@
KEY `Status` (`Status`)
);
+CREATE TABLE ItemFilters (
+ FilterId int(11) NOT NULL AUTO_INCREMENT,
+ ItemPrefix varchar(255) NOT NULL,
+ FilterField varchar(255) NOT NULL,
+ FilterType varchar(100) NOT NULL,
+ Enabled tinyint(4) NOT NULL DEFAULT '1',
+ RangeCount int(11) DEFAULT NULL,
+ PRIMARY KEY (FilterId),
+ KEY ItemPrefix (ItemPrefix),
+ KEY Enabled (Enabled)
+);
+
CREATE TABLE SpamReports (
ReportId int(11) NOT NULL AUTO_INCREMENT,
ItemPrefix varchar(255) NOT NULL,
Index: install/remove_schema.sql
===================================================================
--- install/remove_schema.sql (revision 14888)
+++ install/remove_schema.sql (working copy)
@@ -43,6 +43,7 @@
DROP TABLE Images;
DROP TABLE ItemRating;
DROP TABLE ItemReview;
+DROP TABLE ItemFilters;
DROP TABLE SpamReports;
DROP TABLE ItemTypes;
DROP TABLE ItemFiles;
Index: install/upgrades.sql
===================================================================
--- install/upgrades.sql (revision 14888)
+++ install/upgrades.sql (working copy)
@@ -2412,4 +2412,16 @@
UPDATE ConfigurationValues
SET VariableName = 'RunScheduledTasksFromCron'
-WHERE VariableName = 'UseCronForRegularEvent';
\ No newline at end of file
+WHERE VariableName = 'UseCronForRegularEvent';
+
+CREATE TABLE ItemFilters (
+ FilterId int(11) NOT NULL AUTO_INCREMENT,
+ ItemPrefix varchar(255) NOT NULL,
+ FilterField varchar(255) NOT NULL,
+ FilterType varchar(100) NOT NULL,
+ Enabled tinyint(4) NOT NULL DEFAULT '1',
+ RangeCount int(11) DEFAULT NULL,
+ PRIMARY KEY (FilterId),
+ KEY ItemPrefix (ItemPrefix),
+ KEY Enabled (Enabled)
+);
Index: kernel/db/db_event_handler.php
===================================================================
--- kernel/db/db_event_handler.php (revision 14888)
+++ kernel/db/db_event_handler.php (working copy)
@@ -215,6 +215,10 @@
return $list_helper->getNavigationResource($object, $event->getEventParam('list'), $event->Special == 'next', $select_clause);
}
+ elseif ( $event->Special == 'filter' ) {
+ // temporary object, used to print filter options only
+ return 0;
+ }
if (preg_match('/^auto-(.*)/', $event->Special, $regs) && $this->Application->prefixRegistred($regs[1])) {
// <inp2:lang.auto-phrase_Field name="DateFormat"/> - returns field DateFormat value from language (LanguageId is extracted from current phrase object)
@@ -1178,6 +1182,7 @@
}
}
+ // add view filter
$view_filter = $this->Application->RecallVar($event->getPrefixSpecial() . '_view_filter');
if ( $view_filter ) {
@@ -1209,9 +1214,75 @@
$group_key++;
}
}
+
+ // add item filter
+ if ( $object->isMainList() ) {
+ $this->applyItemFilters($event);
+ }
}
/**
+ * Applies item filters
+ *
+ * @param kEvent $event
+ * @return void
+ * @access protected
+ */
+ protected function applyItemFilters(&$event)
+ {
+ $filter_values = $this->Application->GetVar('filters', Array ());
+
+ if ( !$filter_values ) {
+ return;
+ }
+
+ $object =& $event->getObject();
+ /* @var $object kDBList */
+
+ $where_clause = Array (
+ 'ItemPrefix = ' . $this->Conn->qstr($object->Prefix),
+ 'FilterField IN (' . implode(',', $this->Conn->qstrArray(array_keys($filter_values))) . ')',
+ 'Enabled = 1',
+ );
+
+ $sql = 'SELECT *
+ FROM ' . $this->Application->getUnitOption('item-filter', 'TableName') . '
+ WHERE (' . implode(') AND (', $where_clause) . ')';
+ $filters = $this->Conn->Query($sql, 'FilterField');
+
+ foreach ($filters as $filter_field => $filter_data) {
+ $filter_value = $filter_values[$filter_field];
+
+ if ( "$filter_value" === '' ) {
+ // ListManager don't pass empty values, but check here just in case
+ continue;
+ }
+
+ $table_name = $object->isVirtualField($filter_field) ? '' : '%1$s.';
+
+ switch ($filter_data['FilterType']) {
+ case 'radio':
+ $filter_value = $table_name . '`' . $filter_field . '` = ' . $this->Conn->qstr($filter_value);
+ break;
+
+ case 'checkbox':
+ $filter_value = explode('|', substr($filter_value, 1, -1));
+ $filter_value = $this->Conn->qstrArray($filter_value, 'escape');
+
+ if ( $object->GetFieldOption($filter_field, 'multiple') ) {
+ $filter_value = $table_name . '`' . $filter_field . '` LIKE "%|' . implode('|%" OR ' . $table_name . '`' . $filter_field . '` LIKE "%|', $filter_value) . '|%"';
+ }
+ else {
+ $filter_value = $table_name . '`' . $filter_field . '` IN (' . implode(',', $filter_value) . ')';
+ }
+ break;
+ }
+
+ $object->addFilter('item_filter_' . $filter_field, $filter_value);
+ }
+ }
+
+ /**
* Set's new sorting for list
*
* @param kEvent $event
Index: kernel/db/db_tag_processor.php
===================================================================
--- kernel/db/db_tag_processor.php (revision 14888)
+++ kernel/db/db_tag_processor.php (working copy)
@@ -761,7 +761,7 @@
}
/**
- * Depricated
+ * Deprecated
*
* @param array $params
* @return int
@@ -1419,8 +1419,8 @@
$separator_params['name'] = $this->SelectParam($params, 'separator_render_as,block_separator');
for ($i = $split_start; $i <= $split_end; $i++) {
- $from_record = ($i - 1) * $list->GetPerPage(true);
- $to_record = $from_record + $list->GetPerPage(true);
+ $from_record = ($i - 1) * $list->GetPerPage();
+ $to_record = $from_record + $list->GetPerPage();
if ( $to_record > $total_records ) {
$to_record = $total_records;
@@ -3003,4 +3003,21 @@
return $object->getFormName();
}
+
+ /**
+ * Just reloads the object using given parameters
+ *
+ * @param Array $params
+ * @return string
+ * @access protected
+ */
+ protected function ReloadItem($params)
+ {
+ $params['requery'] = 1;
+
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ return '';
+ }
}
\ No newline at end of file
Index: kernel/db/dblist.php
===================================================================
--- kernel/db/dblist.php (revision 14888)
+++ kernel/db/dblist.php (working copy)
@@ -683,10 +683,11 @@
*
* @param bool $for_counting
* @param bool $system_filters_only
+ * @param string $keep_clause
* @return string
* @access public
*/
- public function GetSelectSQL($for_counting=false,$system_filters_only=false)
+ public function GetSelectSQL($for_counting = false, $system_filters_only = false, $keep_clause = '')
{
$q = parent::GetSelectSQL($this->SelectClause);
$q = !$for_counting ? $this->addCalculatedFields($q, 0) : str_replace('%2$s', '', $q);
@@ -697,7 +698,7 @@
$group = $this->GetGroupClause();
if ( $for_counting ) {
- $optimizer = new LeftJoinOptimizer($q, $where . '|' . $having . '|' . $order . '|' . $group);
+ $optimizer = new LeftJoinOptimizer($q, $where . '|' . $having . '|' . $order . '|' . $group . '|' . $keep_clause);
$q = $optimizer->simplify();
}
@@ -1171,17 +1172,26 @@
}
/**
- * Returns total page count based on list per-page
- *
- * @param string
- * @access public
- */
+ * Returns total page count based on list per-page
+ *
+ * @return int
+ * @access public
+ */
public function GetTotalPages()
{
- if (!$this->Counted) $this->CountRecs();
- if ($this->PerPage == -1) return 1;
- $this->TotalPages = (($this->RecordsCount - ($this->RecordsCount % $this->PerPage)) / $this->PerPage) // integer part of division
- + (($this->RecordsCount % $this->PerPage) != 0); // adds 1 if there is a reminder
+ if ( !$this->Counted ) {
+ $this->CountRecs();
+ }
+
+ if ( $this->PerPage == -1 ) {
+ return 1;
+ }
+
+ $integer_part = ($this->RecordsCount - ($this->RecordsCount % $this->PerPage)) / $this->PerPage;
+ $reminder = ($this->RecordsCount % $this->PerPage) != 0; // adds 1 if there is a reminder
+
+ $this->TotalPages = $integer_part + $reminder;
+
return $this->TotalPages;
}
Index: units/filters/filters_config.php
===================================================================
--- units/filters/filters_config.php (revision 0)
+++ units/filters/filters_config.php (revision 0)
@@ -0,0 +1,130 @@
+<?php
+/**
+* @version $Id$
+* @package In-Portal
+* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
+* @license GNU/GPL
+* In-Portal is Open Source software.
+* This means that this software may have been modified pursuant
+* the GNU General Public License, and as distributed it includes
+* or is derivative of works licensed under the GNU General Public License
+* or other free or open source software licenses.
+* See http://www.in-portal.org/license for copyright notices and details.
+*/
+
+defined('FULL_PATH') or die('restricted access!');
+
+$config = Array (
+ 'Prefix' => 'item-filter',
+ 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
+ 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
+ 'EventHandlerClass' => Array ('class' => 'ItemFilterEventHandler', 'file' => 'item_filter_eh.php', 'build_event' => 'OnBuild'),
+ 'TagProcessorClass' => Array ('class' => 'ItemFilterTagProcessor', 'file' => 'item_filter_tp.php', 'build_event' => 'OnBuild'),
+
+ 'AutoLoad' => true,
+
+ 'QueryString' => Array (
+ 1 => 'id',
+ 2 => 'Page',
+ 3 => 'PerPage',
+ 4 => 'event',
+ 5 => 'mode',
+ ),
+
+ 'IDField' => 'FilterId',
+
+ 'TableName' => TABLE_PREFIX . 'ItemFilters',
+
+ 'TitleField' => 'FilterField',
+ 'StatusField' => Array ('Enabled'),
+
+ 'TitlePresets' => Array (
+ 'default' => Array (
+ 'new_status_labels' => Array ('item-filter' => '!la_title_AddingItemFilter!'),
+ 'edit_status_labels' => Array ('item-filter' => '!la_title_EditingItemFilter!'),
+ ),
+
+ 'item_filter_list' => Array (
+ 'prefixes' => Array ('item-filter_List'), 'format' => "!la_title_ItemFilters!",
+ 'toolbar_buttons' => Array ('new_item', 'edit', 'delete', 'approve', 'decline', 'view', 'dbl-click'),
+ ),
+
+ 'item_filter_edit' => Array (
+ 'prefixes' => Array ('item-filter'), 'format' => "#item-filter_status# '#item-filter_titlefield#'",
+ 'toolbar_buttons' => Array ('select', 'cancel', 'reset_edit', 'prev', 'next'),
+ ),
+ ),
+
+ 'PermSection' => Array('main' => 'in-portal:item_filters'),
+
+ 'Sections' => Array (
+ 'in-portal:item_filters' => Array (
+ 'parent' => 'in-portal:website_setting_folder',
+ 'icon' => 'conf_filters',
+ 'label' => 'la_title_ItemFilters',
+ 'url' => Array('t' => 'item_filters/item_filter_list', 'pass' => 'm'),
+ 'permissions' => Array('view', 'add', 'edit', 'delete'),
+ 'priority' => 14,
+ 'type' => stTREE,
+ ),
+ ),
+
+ 'ListSQLs' => Array (
+ '' => ' SELECT %1$s.* %2$s FROM %1$s',
+ ),
+
+ 'CalculatedFields' => Array (
+ '' => Array (
+ 'FilterKey' => 'CONCAT(%1$s.ItemPrefix, "_", %1$s.FilterField)',
+ ),
+ ),
+
+ 'ListSortings' => Array (
+ '' => Array (
+ 'Sorting' => Array ('FilterId' => 'asc'),
+ )
+ ),
+
+ 'Fields' => Array (
+ 'FilterId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'ItemPrefix' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'error_msgs' => Array ('not_registered' => '!la_error_InvalidItemPrefix!'),
+ 'not_null' => 1, 'required' => 1, 'default' => ''
+ ),
+ 'FilterField' => Array (
+ 'type' => 'string', 'max_len' => 255,
+ 'error_msgs' => Array ('non_existing' => '!la_error_InvalidFieldName!'),
+ 'not_null' => 1, 'required' => 1, 'default' => ''
+ ),
+ 'FilterType' => Array (
+ 'type' => 'string', 'max_len' => 100,
+ 'formatter' => 'kOptionsFormatter', 'options' => Array ('text' => 'la_type_text', 'select' => 'la_type_select', 'radio' => 'la_type_radio', 'checkbox' => 'la_type_checkbox', 'range' => 'la_type_RangeSlider'), 'use_phrases' => 1,
+ 'not_null' => 1, 'required' => 1, 'default' => ''
+ ),
+ 'Enabled' => Array (
+ 'type' => 'int',
+ 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 1
+ ),
+ 'RangeCount' => Array ('type' => 'int', 'default' => NULL),
+ ),
+
+ 'VirtualFields' => Array (
+ 'FilterKey' => Array ('type' => 'string', 'default' => ''),
+ ),
+
+ 'Grids' => Array (
+ 'Default' => Array (
+ 'Icons' => Array ('default' => 'icon16_item.png', 0 => 'icon16_disabled.png'),
+ 'Fields' => Array (
+ 'FilterId' => Array ('title' => 'column:la_fld_Id', 'filter_block' => 'grid_range_filter'),
+ 'ItemPrefix' => Array ('filter_block' => 'grid_like_filter'),
+ 'FilterField' => Array ('filter_block' => 'grid_like_filter'),
+ 'FilterType' => Array ('filter_block' => 'grid_options_filter'),
+ 'Enabled' => Array ('filter_block' => 'grid_options_filter'),
+ 'RangeCount' => Array ('filter_block' => 'grid_range_filter'),
+ )
+ )
+ )
+);
\ No newline at end of file
Index: units/filters/item_filter_eh.php
===================================================================
--- units/filters/item_filter_eh.php (revision 0)
+++ units/filters/item_filter_eh.php (revision 0)
@@ -0,0 +1,149 @@
+<?php
+/**
+* @version $Id$
+* @package In-Portal
+* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
+* @license GNU/GPL
+* In-Portal is Open Source software.
+* This means that this software may have been modified pursuant
+* the GNU General Public License, and as distributed it includes
+* or is derivative of works licensed under the GNU General Public License
+* or other free or open source software licenses.
+* See http://www.in-portal.org/license for copyright notices and details.
+*/
+
+defined('FULL_PATH') or die('restricted access!');
+
+class ItemFilterEventHandler extends kDBEventHandler {
+
+ /**
+ * Allows to override standard permission mapping
+ *
+ */
+ function mapPermissions()
+ {
+ parent::mapPermissions();
+
+ $permissions = Array (
+ 'OnItemBuild' => Array ('self' => true),
+ );
+
+ $this->permMapping = array_merge($this->permMapping, $permissions);
+ }
+
+ /**
+ * Apply any custom changes to list's sql query
+ *
+ * @param kEvent $event
+ * @return void
+ * @access protected
+ * @see kDBEventHandler::OnListBuild()
+ */
+ protected function SetCustomQuery(&$event)
+ {
+ parent::SetCustomQuery($event);
+
+ if ( !$this->Application->isAdmin ) {
+ $object =& $event->getObject();
+ /* @var $object kDBList */
+
+ $prefix_info = $this->Application->processPrefix( $event->getEventParam('prefix') );
+
+ $object->addFilter('prefix_filter', '%1$s.ItemPrefix = ' . $this->Conn->qstr($prefix_info['prefix']));
+ $object->addFilter('status_filter', '%1$s.Enabled = 1');
+
+ if ($event->Special == 'used') {
+ $filters = array_keys($this->Application->GetVar('filters', Array ()));
+
+ if ( $filters ) {
+ $filters = $this->Conn->qstrArray($filters);
+ $object->addFilter('field_filter', '%1$s.FilterField IN (' . implode(',', $filters) . ')');
+ }
+ else {
+ $object->addFilter('field_filter', 'FALSE');
+ }
+ }
+
+ if ( $event->getEventParam('per_page') === false ) {
+ $event->setEventParam('per_page', -1);
+ }
+ }
+ }
+
+ /**
+ * Validates filter settings
+ *
+ * @param kEvent $event
+ * @return void
+ * @access protected
+ */
+ protected function OnBeforeItemValidate(kEvent &$event)
+ {
+ parent::OnBeforeItemValidate($event);
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ $prefix = $object->GetDBField('ItemPrefix');
+
+ if ( $prefix ) {
+ if ( !$this->Application->prefixRegistred($prefix) ) {
+ $object->SetError('ItemPrefix', 'not_registered');
+ }
+
+ $field = $object->GetDBField('FilterField');
+
+ if ( $field ) {
+ $fields = $this->Application->getUnitOption($prefix, 'Fields');
+ $virtual_fields = $this->Application->getUnitOption($prefix, 'VirtualFields');
+
+ if ( !isset($fields[$field]) && !isset($virtual_fields[$field]) ) {
+ $object->SetError('FilterField', 'non_existing', null, Array ($prefix));
+ }
+ }
+ }
+
+ $object->setRequired('RangeCount', $object->GetDBField('FilterType') == 'range');
+ }
+
+ /**
+ * Load item if id is available
+ *
+ * @param kEvent $event
+ * @return void
+ * @access protected
+ */
+ protected function LoadItem(&$event)
+ {
+ static $cache = null;
+
+ if ( $this->Application->isAdmin ) {
+ parent::LoadItem($event);
+
+ return;
+ }
+
+ $object =& $event->getObject();
+ /* @var $object kDBItem */
+
+ if ( !isset($cache) ) {
+ $cache = $this->Conn->Query($object->GetSelectSQL(), 'FilterKey');
+ }
+
+ $filter_key = $event->getEventParam('prefix') . '_' . $event->getEventParam('field');
+
+ if ( isset($cache[$filter_key]) ) {
+ $object->LoadFromHash($cache[$filter_key]);
+ }
+
+ if ( $object->isLoaded() ) {
+ $actions =& $this->Application->recallObject('kActions');
+ /* @var $actions Params */
+
+ $actions->Set($event->getPrefixSpecial() . '_id', $object->GetID());
+ }
+ else {
+ $object->setID(false);
+ }
+ }
+}
Index: units/filters/item_filter_tp.php
===================================================================
--- units/filters/item_filter_tp.php (revision 0)
+++ units/filters/item_filter_tp.php (revision 0)
@@ -0,0 +1,230 @@
+<?php
+/**
+* @version $Id$
+* @package In-Portal
+* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
+* @license GNU/GPL
+* In-Portal is Open Source software.
+* This means that this software may have been modified pursuant
+* the GNU General Public License, and as distributed it includes
+* or is derivative of works licensed under the GNU General Public License
+* or other free or open source software licenses.
+* See http://www.in-portal.org/license for copyright notices and details.
+*/
+
+defined('FULL_PATH') or die('restricted access!');
+
+class ItemFilterTagProcessor extends kDBTagProcessor {
+
+ /**
+ * Allows to modify block params & current list record before PrintList parses record
+ *
+ * @param kDBList $object
+ * @param Array $block_params
+ * @return void
+ * @access protected
+ */
+ protected function PrepareListElementParams(&$object, &$block_params)
+ {
+ if ( $this->Application->isAdmin ) {
+ return ;
+ }
+
+ $block_params['filter_field'] = $object->GetDBField('FilterField');
+ $block_params['filter_type'] = $object->GetDBField('FilterType');
+ }
+
+ /**
+ * Lists filter options
+ *
+ * @param Array $params
+ * @return string
+ * @access protected
+ */
+ protected function ListFilterOptions($params)
+ {
+ static $cache = Array ();
+
+ $object =& $this->getObject($params);
+ /* @var $object kDBItem */
+
+ // get item list to be filtered
+ $this->Application->ProcessParsedTag($params['prefix'], 'InitList', $params);
+ $tag_processor =& $this->Application->recallTagProcessor( $params['prefix'] );
+ $item_list = $tag_processor->GetList($params);
+
+ $filter_type = $object->GetDBField('FilterType');
+ $filter_field = $object->GetDBField('FilterField');
+ $cache_key = $filter_field . '_' . $filter_type;
+
+ if ( !isset($cache[$cache_key]) ) {
+ $cache[$cache_key] = Array ('counts' => Array (), 'options' => Array ());
+
+ $field_sql = $item_list->isCalculatedField($filter_field) ? $item_list->extractCalculatedFields('`' . $filter_field . '`', 1, true) : '`' . $item_list->TableName . '`.`' . $filter_field . '`';
+ $sql = $item_list->getCountSQL( $item_list->GetSelectSQL(true, false, $field_sql) );
+
+ if ( in_array($filter_type, Array ('select', 'radio', 'checkbox')) ) {
+ $options = $item_list->GetFieldOption($filter_field, 'options', false, Array ());
+
+ if ( $item_list->GetFieldOption($filter_field, 'use_phrases') ) {
+ $options = array_map(Array (&$this->Application, 'Phrase'), $options);
+ }
+
+ $cache[$cache_key]['options'] = $options;
+
+ $count_sql = str_replace('COUNT(*) AS count', 'COUNT(*), ' . $field_sql . ' AS GroupField', $sql) . ' GROUP BY GroupField';
+ $cache[$cache_key]['counts'] = $this->Conn->GetCol($count_sql, 'GroupField');
+ }
+ elseif ( $filter_type == 'range' ) {
+ // TODO: auto-scalable range alghoritm (used here) has several problems:
+ // 1. range values has meaningless values, e.g. 32, 56 and not 100, 200 as in original design
+ // 2. count of items from last range is displayed below filter scale
+ // 3. filter scale has fixed image background that allows only 10 positions
+
+ $range_sql = str_replace('COUNT(*) AS count', 'MIN(' . $field_sql . ') AS MinValue, MAX(' . $field_sql . ') AS MaxValue', $sql);
+ $range_values = $this->Conn->GetRow($range_sql);
+
+ if ( !$range_values['MinValue'] && !$range_values['MaxValue'] ) {
+ return '';
+ }
+
+ $range_start = $range_values['MinValue'];
+ $range_count = $object->GetDBField('RangeCount');
+ $range_size = ceil( ($range_values['MaxValue'] - $range_values['MinValue']) / ($range_count /*+ 1*/) );
+ $formatter_class = $item_list->GetFieldOption($filter_field, 'formatter');
+
+ $options = Array ();
+ $count_clause = '';
+ $if_clause_mask = 'IF(%s BETWEEN %s AND %s, %s, %%s)';
+
+ if ( $formatter_class ) {
+ $formatter =& $this->Application->recallObject($formatter_class);
+ /* @var $formatter kFormatter */
+
+ for ($range_number = 0; $range_number < $range_count; $range_number++) {
+ $range_end = $range_start + $range_size;
+ $option_key = sprintf('%01.2f', $range_start) . '-' . sprintf('%01.2f', $range_end);
+ $options[$option_key] = $formatter->Format($range_start, $filter_field, $item_list)/* . ' - ' . $formatter->Format($range_end, $filter_field, $item_list)*/;
+
+ $sql_part = sprintf($if_clause_mask, $field_sql, $range_start, $range_end, $this->Conn->qstr($option_key));
+ $count_clause = $count_clause ? sprintf($count_clause, $sql_part) : $sql_part;
+ $range_start = $range_end;
+ }
+ }
+ else {
+ for ($range_number = 0; $range_number < $range_count; $range_number++) {
+ $range_end = $range_start + $range_size;
+ $option_key = sprintf('%01.2f', $range_start) . '-' . sprintf('%01.2f', $range_end);
+ $options[$option_key] = $range_start . ' - ' . $range_end;
+
+ $sql_part = sprintf($if_clause_mask, $field_sql, $range_start, $range_end, $this->Conn->qstr($option_key));
+ $count_clause = $count_clause ? sprintf($count_clause, $sql_part) : $sql_part;
+ $range_start = $range_end;
+ }
+ }
+
+
+ $cache[$cache_key]['range_values'] = $range_values;
+ $cache[$cache_key]['options'] = $options;
+
+ $count_clause = sprintf($count_clause, $this->Conn->qstr($option_key));
+ $count_sql = str_replace('COUNT(*) AS count', 'COUNT(*), ' . $count_clause . ' AS GroupField', $sql) . ' GROUP BY GroupField';
+ $cache[$cache_key]['counts'] = $this->Conn->GetCol($count_sql, 'GroupField');
+ }
+ }
+
+ $options = $cache[$cache_key]['options'];
+ $counts = $cache[$cache_key]['counts'];
+
+ if ( !$options ) {
+ return '';
+ }
+
+ if ( $filter_type != 'range' ) {
+ $counts[''] = array_sum($counts);
+ $options = kUtil::array_merge_recursive(Array ('' => 'All'), $options);
+ }
+
+ $ret = '';
+ $block_params = $this->prepareTagParams($params);
+ $block_params['name'] = $params['render_as'];
+ $selected_value = $this->getFilterValue($filter_field);
+
+ foreach ($options as $option_key => $option_title) {
+ $block_params['key'] = $option_key;
+ $block_params['title'] = $option_title;
+ $block_params['count'] = isset($counts[$option_key]) ? $counts[$option_key] : 0;
+
+ if ( strpos($selected_value, '|') === false ) {
+ $block_params['selected'] = "$selected_value" === "$option_key";
+ }
+ else {
+ $block_params['selected'] = strpos($selected_value, '|' . $option_key . '|') !== false;
+ }
+
+ $ret .= $this->Application->ParseBlock($block_params);
+ }
+
+ // set global vars to be used by jQuery UI slider
+ if ( $filter_type == 'range' ) {
+ $range_count = $object->GetDBField('RangeCount');
+ $range_values = $cache[$cache_key]['range_values'];
+
+ $this->Application->SetVar('min_range_value', $range_values['MinValue']);
+ $this->Application->SetVar('max_range_value', $range_values['MaxValue']);
+
+ $range_size = ceil( ($range_values['MaxValue'] - $range_values['MinValue']) / ($range_count + 1) );
+ $this->Application->SetVar('range_step', $range_size);
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Filter input name
+ *
+ * @param Array $params
+ * @return string
+ * @access protected
+ */
+ protected function FilterInputName($params)
+ {
+ $field = $this->Application->Parser->GetParam('filter_field');
+
+ $ret = 'filters[' . $field . ']';
+
+ if (array_key_exists('as_preg', $params) && $params['as_preg']) {
+ $ret = preg_quote($ret, '/');
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Returns filter value
+ *
+ * @param Array $params
+ * @return string
+ * @access protected
+ */
+ protected function FilterField($params)
+ {
+ $field = $this->Application->Parser->GetParam('filter_field');
+
+ return $this->getFilterValue($field);
+ }
+
+ /**
+ * Returns filter value
+ *
+ * @param string $field
+ * @return string
+ * @access protected
+ */
+ protected function getFilterValue($field)
+ {
+ $filters = $this->Application->GetVar('filters', Array ());
+
+ return array_key_exists($field, $filters) ? $filters[$field] : '';
+ }
+}
smart_filters_modules.patch [^] (1,465 bytes) 2011-12-20 10:23
[Show Content]
Index: install/install_data.sql
===================================================================
--- install/install_data.sql (revision 14888)
+++ install/install_data.sql (working copy)
@@ -471,4 +471,9 @@
INSERT INTO ImportScripts VALUES (DEFAULT, 'Products from CSV file [In-Commerce]', '', 'p', 'In-Commerce', '', 'CSV', '1');
+INSERT INTO ItemFilters VALUES
+ (DEFAULT, 'p', 'ManufacturerId', 'checkbox', 1, NULL),
+ (DEFAULT, 'p', 'Price', 'range', 1, 11),
+ (DEFAULT, 'p', 'EditorsPick', 'radio', 1, NULL);
+
INSERT INTO Modules VALUES ('In-Commerce', 'modules/in-commerce/', 'p', DEFAULT, 1, 4, 'in-commerce/', 2, NULL, NULL);
Index: install/upgrades.sql
===================================================================
--- install/upgrades.sql (revision 14888)
+++ install/upgrades.sql (working copy)
@@ -233,4 +233,9 @@
INSERT INTO ConfigurationValues VALUES(DEFAULT, 'OrderVATIncluded', '0', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_config_OrderVATIncluded', 'checkbox', NULL, NULL, 10.12, '0', '0', NULL);
-ALTER TABLE Orders ADD VATIncluded TINYINT(1) UNSIGNED NOT NULL DEFAULT '0';
\ No newline at end of file
+ALTER TABLE Orders ADD VATIncluded TINYINT(1) UNSIGNED NOT NULL DEFAULT '0';
+
+INSERT INTO ItemFilters VALUES
+ (DEFAULT, 'p', 'ManufacturerId', 'checkbox', 1, NULL),
+ (DEFAULT, 'p', 'Price', 'range', 1, 11),
+ (DEFAULT, 'p', 'EditorsPick', 'radio', 1, NULL);
\ No newline at end of file
smart_filters_themes.patch [^] (24,058 bytes) 2011-12-20 10:23
[Show Content]
Index: designs/section.tpl
===================================================================
--- designs/section.tpl (revision 14888)
+++ designs/section.tpl (working copy)
@@ -13,9 +13,14 @@
<inp2:m_DefineElement name="sidebar">
<inp2:m_Include template="elements/side_boxes/categories.elm" data_exists="1"/>
- <inp2:m_Include template="elements/side_boxes/filter_range.elm"/>
- <inp2:m_Include template="elements/side_boxes/filter_dropdown.elm"/>
- <inp2:m_Include template="elements/side_boxes/filter_checkboxes.elm"/>
+
+ <inp2:m_include template="elements/filters.elm"/>
+ <inp2:item-filter_PrintList render_as="filter_element" prefix="p" list_name="products_in_category" is_list="1"/>
+
+ <!--<inp2:m_RenderElement name="filter_element" prefix="p" list_name="products_in_category" filter_field="ManufacturerId" filter_type="checkbox"/>
+ <inp2:m_RenderElement name="filter_element" prefix="p" list_name="products_in_category" filter_field="EditorsPick" filter_type="radio"/>
+ <inp2:m_RenderElement name="filter_element" prefix="p" list_name="products_in_category" filter_field="Price" filter_type="range"/>-->
+
<inp2:m_Include template="elements/side_boxes/subscribe.elm"/>
</inp2:m_DefineElement>
@@ -34,7 +39,12 @@
<!--## /MAIN CONTENT ##-->
<inp2:m_DefineElement name="add_to_head">
+ <script src="<inp2:m_TemplatesBase/>inc/js/list_manager.js" type="text/javascript"></script>
+
<script type="text/javascript">
+ ListManager.containerSelector = '#products';
+ ListManager.url = '<inp2:m_Link render_template="elements/content_boxes/products.elm" list_name="products_in_category" list_prefix="p" js_escape="1" no_amp="1"/>';
+
$(document).ready(
function() {
// js that works for "Shop All" menu and "Categories sidebox": begin
@@ -51,38 +61,10 @@
autoHeight: false,
event: 'mouseover'
});
- }
- );
- function ListManager() {}
-
- ListManager.containerSelector = '#products';
- ListManager.url = '<inp2:m_Link render_template="elements/content_boxes/products.elm" list_name="products_in_category" list_prefix="p" js_escape="1" no_amp="1"/>';
- ListManager.urlParams = {layout: 'list'};
-
- ListManager.getUrl = function () {
- var $url = this.url;
- }
-
- ListManager.reload = function () {
- $(this.containerSelector)
- .fadeTo('fast', 0.7)
- .load(
- this.url,
- this.urlParams,
- function () {
- $(this).fadeTo('fast', 1.0);
- }
- );
- }
-
- ListManager.setParam = function ($name, $value, $reload) {
- this.urlParams[$name] = $value;
-
- if ( $reload === true ) {
- this.reload();
+ ListManager.init();
}
- }
+ );
</script>
</inp2:m_DefineElement>
Index: elements/content_boxes/products.elm.tpl
===================================================================
--- elements/content_boxes/products.elm.tpl (revision 14888)
+++ elements/content_boxes/products.elm.tpl (working copy)
@@ -1,6 +1,7 @@
<inp2:m_DefaultParam prefix="" list_name="" layout="list"/>
<inp2:m_if check="m_Get" name="ajax" equals_to="yes">
+ <inp2:m_NoDebug/>
<inp2:m_Get name="list_prefix" result_to_var="prefix"/>
<inp2:m_Get name="list_name" result_to_var="list_name"/>
<inp2:m_Get name="layout" result_to_var="layout"/>
@@ -10,13 +11,26 @@
<inp2:m_Include template="elements/content_boxes.elm" strip_nl="2"/>
<inp2:m_Include template="elements/product_elements.elm" strip_nl="2"/>
-<inp2:m_Include template="elements/sorting.elm" list_name="$list_name" prefix="$prefix" layout="$layout" ajax="1"/>
-<div class="items <inp2:m_if check='m_Param' name='layout' equals_to='list'>border-radius<inp2:m_else/>items-alt</inp2:m_if>">
- <ul class="display<inp2:m_if check='m_Param' name='layout' equals_to='grid'> thumb_view</inp2:m_if>">
- <inp2:$prefix_ListProducts list_name="$list_name" render_as="product_list_element"/>
- </ul>
- <div class="clear"></div>
+<inp2:m_if check="{$prefix}_TotalRecords" list_name="$list_name">
+ <inp2:m_Include template="elements/sorting.elm" list_name="$list_name" prefix="$prefix" layout="$layout" ajax="1"/>
- <inp2:m_Include template="elements/pagination.elm" list_name="$list_name" prefix="$prefix" ajax="1"/>
-</div>
\ No newline at end of file
+ <div class="items <inp2:m_if check='m_Param' name='layout' equals_to='list'>border-radius<inp2:m_else/>items-alt</inp2:m_if>">
+ <ul class="display<inp2:m_if check='m_Param' name='layout' equals_to='grid'> thumb_view</inp2:m_if>">
+ <inp2:$prefix_ListProducts list_name="$list_name" render_as="product_list_element"/>
+ </ul>
+ <div class="clear"></div>
+
+ <inp2:m_Include template="elements/pagination.elm" list_name="$list_name" prefix="$prefix" ajax="1"/>
+ </div>
+<inp2:m_else/>
+ No Products
+</inp2:m_if>
+
+<inp2:m_if check="m_Get" name="filters">
+ <inp2:m_include template="elements/filters.elm"/>
+
+ <script type="text/javascript">
+ <inp2:item-filter.used_PrintList render_as="used_filter_element" list_name="$list_name" prefix="$prefix" is_list="1"/>
+ </script>
+</inp2:m_if>
\ No newline at end of file
Index: elements/filters.elm.tpl
===================================================================
--- elements/filters.elm.tpl (revision 0)
+++ elements/filters.elm.tpl (revision 0)
@@ -0,0 +1,115 @@
+<inp2:m_DefineElement name="filter_text_block" PrefixSpecial="item-filter" filter_type="text" is_list="0">
+ <input type="text" name="<inp2:FilterInputName/>" id="<inp2:FilterInputName/>" value="<inp2:FilterField/>"/>
+</inp2:m_DefineElement>
+
+
+<inp2:m_DefineElement name="filter_select_block" PrefixSpecial="item-filter" filter_type="select" is_list="0">
+ <select name="<inp2:FilterInputName/>" id="<inp2:FilterInputName/>">
+
+ </select>
+</inp2:m_DefineElement>
+
+
+<inp2:m_DefineElement name="filter_radio_element">
+ <dt<inp2:m_if check="m_Param" name="selected"> class="active"</inp2:m_if>>
+ <input type="radio"<inp2:m_if check="m_Param" name="selected"> checked</inp2:m_if> name="<inp2:FilterInputName/>" id="<inp2:FilterInputName/>_<inp2:m_param name='key'/>" value="<inp2:m_param name='key'/>"/> <label for="<inp2:FilterInputName/>_<inp2:m_param name='key'/>"><inp2:m_Param name="title"/></label>
+ </dt>
+ <dd<inp2:m_if check="m_Param" name="selected"> class="active"</inp2:m_if>>(<inp2:m_Param name="count"/>)</dd>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="filter_radio_block" PrefixSpecial="item-filter" filter_type="radio" is_list="0">
+ <dl class="manufacturer">
+ <inp2:ListFilterOptions render_as="filter_radio_element" pass_params="1"/>
+ </dl>
+ <div class="clear"></div>
+</inp2:m_DefineElement>
+
+
+<inp2:m_DefineElement name="filter_checkbox_element" form_id="">
+ <dt<inp2:m_if check="m_Param" name="selected"> class="active"</inp2:m_if>>
+ <input type="checkbox"<inp2:m_if check="m_Param" name="selected"> checked</inp2:m_if> id="<inp2:FilterInputName/>_<inp2:m_param name='key'/>" value="<inp2:m_param name='key'/>"/> <label for="<inp2:FilterInputName/>_<inp2:m_param name='key'/>"><inp2:m_Param name="title"/></label>
+ </dt>
+ <dd<inp2:m_if check="m_Param" name="selected"> class="active"</inp2:m_if>>(<inp2:m_Param name="count"/>)</dd>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="filter_checkbox_block" PrefixSpecial="item-filter" filter_type="checkbox" is_list="0">
+ <dl class="manufacturer">
+ <inp2:ListFilterOptions render_as="filter_checkbox_element" form_id="filter-form-{$filter_field}" pass_params="1"/>
+ </dl>
+ <div class="clear"></div>
+
+ <input type="hidden" name="<inp2:FilterInputName/>" id="<inp2:FilterInputName/>" value="<inp2:FilterField/>"/>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="filter_range_value_element">
+ <li>
+ <!--##<inp2:m_param name='key'/>; ##--><inp2:m_Param name="title"/>
+ </li>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="filter_range_count_element">
+ <li>(<inp2:m_Param name="count"/>)</li>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="filter_range_block" PrefixSpecial="item-filter" filter_type="range" is_list="0">
+ <div class="range-block">
+ <ul class="range">
+ <inp2:ListFilterOptions render_as="filter_range_value_element" pass_params="1"/>
+ </ul>
+ <div id="slider-vertical" style="height:260px;"></div>
+ <ul class="range2">
+ <inp2:ListFilterOptions render_as="filter_range_count_element" pass_params="1"/>
+ </ul>
+ <div class="clear"></div>
+ </div>
+
+ <script type="text/javascript">
+ $(document).ready(
+ function() {
+ $( '#slider-vertical' ).slider({
+ orientation: 'vertical',
+ range: true,
+ min: <inp2:m_Get name="min_range_value"/>,
+ max: <inp2:m_Get name="max_range_value"/>,
+ step: <inp2:m_Get name="range_step"/>,
+ values: [<inp2:m_Get name="min_range_value"/>, <inp2:m_Get name="max_range_value"/>],
+ change: function(event, ui) {
+ $('#' + jq('<inp2:FilterInputName/>')).val(ui.values[0] + '-' + ui.values[1]);
+
+ ListManager.scheduleReload();
+ }
+ });
+ }
+ );
+ </script>
+
+ <input type="hidden" name="<inp2:FilterInputName/>" id="<inp2:FilterInputName/>" value="<inp2:FilterField/>"/>
+</inp2:m_DefineElement>
+
+
+<inp2:m_DefineElement name="filter_element" PrefixSpecial="item-filter" prefix="" filter_field="" filter_type="" is_list="0">
+ <inp2:m_ifnot check="m_Param" name="is_list">
+ <inp2:ReloadItem prefix="$prefix" field="$filter_field"/>
+ </inp2:m_ifnot>
+
+ <form action="<inp2:m_FormAction/>" id="filter-form-<inp2:m_Param name='filter_field'/>" method="post" class="filter-form" filter_field="<inp2:m_Param name='filter_field'/>" filter_type="<inp2:m_Param name='filter_type'/>">
+ <div class="block alt-block">
+ <h2 class="active"><a href="#">Filter by <inp2:m_Phrase name="lu_fld_{$filter_field}"/></a></h2>
+ <div class="block-content">
+ <inp2:m_RenderElement name="filter_{$filter_type}_block" pass_params="1"/>
+ </div>
+ </div>
+
+ <script type="text/javascript">
+ $(document).ready(
+ function () {
+ ListManager.registerFilter('filter-form-<inp2:m_Param name="filter_field"/>');
+ }
+ );
+ </script>
+ </form>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="used_filter_element">
+ ListManager.replaceFilter('filter-form-<inp2:m_Param name="filter_field"/>', '<inp2:m_RenderElement name="filter_element" pass_params="1" js_escape="1"/>');
+</inp2:m_DefineElement>
\ No newline at end of file
Index: elements/side_boxes/filter_range.elm.tpl
===================================================================
--- elements/side_boxes/filter_range.elm.tpl (revision 14888)
+++ elements/side_boxes/filter_range.elm.tpl (working copy)
@@ -31,4 +31,19 @@
<div class="clear"></div>
</div>
</div>
-</div>
\ No newline at end of file
+</div>
+
+<script type="text/javascript">
+ $(document).ready(
+ function() {
+ $( '#slider-vertical' ).slider({
+ orientation: 'vertical',
+ range: true,
+ min: 0,
+ max: 1000,
+ step: 100,
+ values: [ 0, 400 ]
+ });
+ }
+ );
+</script>
\ No newline at end of file
Index: elements/sorting.elm.tpl
===================================================================
--- elements/sorting.elm.tpl (revision 14888)
+++ elements/sorting.elm.tpl (working copy)
@@ -1,27 +1,24 @@
<inp2:m_DefaultParam prefix="" list_name="" layout="list" ajax="0"/>
<div class="filter-block">
+ <div class="paginate">
+ <a href="#prev" class="prev"><img src="<inp2:m_TemplatesBase/>img/arrow-left.png" width="7" height="13" alt="" /></a>
+ Products
+ <select id="paginate">
+ <inp2:m_DefineElement name="option_page_current">
+ <option value="<inp2:m_param name='page'/>" selected><inp2:m_param name="from_record"/> - <inp2:m_param name="to_record"/></a>
+ </inp2:m_DefineElement>
- <inp2:m_if check="{$prefix}_GridInfo" type="needs_pagination" list_name="$list_name">
- <div class="paginate">
- <a href="#prev" class="prev"><img src="<inp2:m_TemplatesBase/>img/arrow-left.png" width="7" height="13" alt="" /></a>
- Products
- <select id="paginate">
- <inp2:m_DefineElement name="option_page_current">
- <option value="<inp2:m_param name='page'/>" selected><inp2:m_param name="from_record"/> - <inp2:m_param name="to_record"/></a>
- </inp2:m_DefineElement>
+ <inp2:m_DefineElement name="option_page_link">
+ <option value="<inp2:m_param name='page'/>"><inp2:m_param name="from_record"/> - <inp2:m_param name="to_record"/></a>
+ </inp2:m_DefineElement>
- <inp2:m_DefineElement name="option_page_link">
- <option value="<inp2:m_param name='page'/>"><inp2:m_param name="from_record"/> - <inp2:m_param name="to_record"/></a>
- </inp2:m_DefineElement>
+ <inp2:$prefix_PaginationBar list_name="$list_name" current_render_as="option_page_current" link_render_as="option_page_link"/>
+ </select>
+ out of <inp2:p_TotalRecords/>
+ <a href="#next" class="next"><img src="<inp2:m_TemplatesBase/>img/arrow-right.png" width="7" height="13" alt="" /></a>
+ </div>
- <inp2:$prefix_PaginationBar list_name="$list_name" current_render_as="option_page_current" link_render_as="option_page_link"/>
- </select>
- out of <inp2:p_TotalRecords/>
- <a href="#next" class="next"><img src="<inp2:m_TemplatesBase/>img/arrow-right.png" width="7" height="13" alt="" /></a>
- </div>
- </inp2:m_if>
-
<div class="sortby">
<form method="post" action="<inp2:m_FormAction/>">
Sort by:
@@ -88,26 +85,24 @@
}
);
- <inp2:m_if check="{$prefix}_GridInfo" type="needs_pagination" list_name="$list_name">
- $('#paginate').change(
- function () {
- ListManager.setParam('page', $(this).val(), true);
- }
- );
+ $('#paginate').change(
+ function () {
+ ListManager.setParam('page', $(this).val(), true);
+ }
+ );
- $('.prev, .next', '.paginate').click(
- function ($e) {
- var $option = $('option:selected', '#paginate')[ $(this).attr('class') ]();
+ $('.prev, .next', '.paginate').click(
+ function ($e) {
+ var $option = $('option:selected', '#paginate')[ $(this).attr('class') ]();
- if ( $option.length ) {
- $('#paginate').val( $option.attr('value') ).change();
- }
-
- return false;
+ if ( $option.length ) {
+ $('#paginate').val( $option.attr('value') ).change();
}
- );
- </inp2:m_if>
+ return false;
+ }
+ );
+
$('#sorting').change(
function ($e) {
ListManager.setParam('sort_by', $(this).val().replace('|', ','), true);
@@ -116,7 +111,13 @@
$('#per-page').change(
function ($e) {
- ListManager.setParam('per_page', $(this).val(), true);
+ var $per_page = $(this).val();
+
+ if ( $per_page == -1 ) {
+ ListManager.setParam('page', '');
+ }
+
+ ListManager.setParam('per_page', $per_page, true);
}
);
Index: inc/js/jquery.scripts.js
===================================================================
--- inc/js/jquery.scripts.js (revision 14888)
+++ inc/js/jquery.scripts.js (working copy)
@@ -1,6 +1,6 @@
/* === General usage functions === */
-function jq($selector) {
- return $selector.replace(/(\[|\]|\.)/g, '\\$1');
+function jq($selector, $delimiter) {
+ return ($selector + '').replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + ($delimiter || '') + '-]', 'g'), '\\$&');
}
function in_array(needle, haystack)
@@ -32,10 +32,10 @@
return document.getElementById( $prepend + $mask.replace('#FIELD_NAME#', $field) + $append );
}
-function update_checkbox_options($cb_mask, $hidden_id, $form_id)
+function update_checkbox_options($cb_mask, $hidden_id, $form_selector)
{
var $tmp = '',
- $kf = document.getElementById($form_id !== undefined ? $form_id : $form_name);
+ $kf = $($form_selector !== undefined ? $form_selector : '#' + $form_name).get(0);
for (var i = 0; i < $kf.elements.length; i++) {
if ( $kf.elements[i].id.match($cb_mask) ) {
@@ -52,6 +52,40 @@
document.getElementById($hidden_id).value = $tmp.replace(/,$/, '');
}
+function watch_anchor () {
+ var $last_anchor = '';
+
+ setInterval(
+ function () {
+ if (window.location.hash != $last_anchor) {
+ $last_anchor = window.location.hash;
+ var $new_anchor = $last_anchor ? $last_anchor.substring(1) : '';
+
+ $('body').trigger('anchorchanged', [$new_anchor]);
+ }
+ }, 100
+ );
+}
+
+function sort_object($object) {
+ // Setup Arrays
+ var $sorted_keys = [], $sorted_object = {};
+
+ for (var $property_name in $object) {
+ $sorted_keys.push($property_name);
+ }
+
+ $sorted_keys.sort();
+
+ $($sorted_keys).each(
+ function () {
+ $sorted_object[this] = $object[this];
+ }
+ );
+
+ return $sorted_object;
+}
+
/* === DBlocks class === */
function DBlocks() {
var $me = this;
@@ -137,59 +171,63 @@
)
}
-$(document).ready(function()
-{
- $('#change-password').click(
- function($e) {
- $('#password-show').hide();
- $('#password-block').fadeIn();
+/* === Startup === */
+$(document).ready(
+ function() {
+ watch_anchor();
- return false;
- }
- );
+ $('#change-password').click(
+ function($e) {
+ $('#password-show').hide();
+ $('#password-block').fadeIn();
+ return false;
+ }
+ );
- $('.addtocart, .button-addtocart').click(
- function () {
- var $me = $(this),
- $qty = $me.attr('qty_id') !== undefined ? parseInt($('#' + $me.attr('qty_id')).val()) : 1;
+ $('.addtocart, .button-addtocart').click(
+ function () {
+ var $me = $(this),
+ $qty = $me.attr('qty_id') !== undefined ? parseInt($('#' + $me.attr('qty_id')).val()) : 1;
- if ( $me.hasClass('addedtocart') ) {
- // disabled button
- return false;
- }
- if ( isNaN($qty) ) {
- $qty = 1;
- }
+ if ( $me.hasClass('addedtocart') ) {
+ // disabled button
+ return false;
+ }
- var $bubble = $('.basketStatus'),
- $timer_id = $bubble.data('hide_timer');
+ if ( isNaN($qty) ) {
+ $qty = 1;
+ }
- clearTimeout($timer_id);
+ var $bubble = $('.basketStatus'),
+ $timer_id = $bubble.data('hide_timer');
- $.get(
- $me.attr('href') + '&qty=' + $qty,
- function ($bubble_content) {
- $('.basketContent', $bubble).html( $bubble_content.replace(/#QTY#/g, $qty) );
- $bubble
- .stop(true, true)
- .fadeIn(
- 'slow',
- function () {
- var $timer = setTimeout(function(){ $bubble.fadeOut('slow'); }, 2000);
- $bubble.data('hide_timer', $timer);
+ clearTimeout($timer_id);
+
+ $.get(
+ $me.attr('href') + '&qty=' + $qty,
+ function ($bubble_content) {
+ $('.basketContent', $bubble).html( $bubble_content.replace(/#QTY#/g, $qty) );
+ $bubble
+ .stop(true, true)
+ .fadeIn(
+ 'slow',
+ function () {
+ var $timer = setTimeout(function(){ $bubble.fadeOut('slow'); }, 2000);
+ $bubble.data('hide_timer', $timer);
+ }
+ );
+
+ if ( $me.hasClass('addtocart') ) {
+ $me.removeClass('addtocart').addClass('addedtocart').html('Added to Cart');
}
- );
-
- if ( $me.hasClass('addtocart') ) {
- $me.removeClass('addtocart').addClass('addedtocart').html('Added to Cart');
}
- }
- );
+ );
- return false;
- }
- );
-});
\ No newline at end of file
+ return false;
+ }
+ );
+ }
+);
\ No newline at end of file
Index: inc/js/list_manager.js
===================================================================
--- inc/js/list_manager.js (revision 0)
+++ inc/js/list_manager.js (revision 0)
@@ -0,0 +1,187 @@
+function ListManager() {}
+
+ListManager.containerSelector = ''; // selector id of container
+ListManager.url = ''; // url to template with list contents
+ListManager.urlParams = {layout: 'list'};
+ListManager.filters = {};
+ListManager.xhrRequests = [];
+ListManager.reloadTimer = null;
+ListManager.reloadTimeout = 1000;
+
+ListManager.getUrl = function () {
+ var $url = this.url;
+}
+
+ListManager.cancelXHRRequests = function () {
+ while ( this.xhrRequests.length > 0 ) {
+ this.xhrRequests.shift().abort();
+ }
+}
+
+ListManager.reload = function ($now) {
+ this.cancelXHRRequests();
+
+ if ( $now === undefined || $now === false ) {
+ this.updateAnchor();
+
+ return;
+ }
+
+ var $container = $(this.containerSelector);
+
+ $container.fadeTo('fast', 0.7);
+
+ var $request = $.post(
+ this.url,
+ this.urlParams,
+ function ($data) {
+ $container.html($data).fadeTo('fast', 1.0);
+ }
+ );
+
+ this.xhrRequests.push($request);
+}
+
+ListManager.scheduleReload = function () {
+ var $me = this;
+
+ clearTimeout(this.reloadTimer);
+
+ this.reloadTimer = setTimeout(function() { $me.reload(); }, this.reloadTimeout);
+}
+
+ListManager.setParam = function ($name, $value, $reload) {
+ if ( $value === undefined || $value === '' ) {
+ // don't pass empty parameters
+ delete this.urlParams[$name];
+ }
+ else {
+ this.urlParams[$name] = $value;
+ }
+
+ if ( $reload === true ) {
+ this.reload();
+ }
+}
+
+ListManager.updateAnchor = function () {
+ var $query_string = [],
+ $url_params = sort_object(this.urlParams);
+
+ for (var $param_name in $url_params) {
+ $query_string.push( $param_name + '=' + encodeURIComponent(this.urlParams[$param_name]) );
+ }
+
+ window.location.hash = '#' + $query_string.join('&');
+}
+
+ListManager.parseAnchor = function ($anchor) {
+ var $query_string = {};
+
+ $anchor.replace(
+ new RegExp('([^?=&]+)(=([^&]*))?', 'g'),
+ function($0, $1, $2, $3) {
+ $query_string[$1] = decodeURIComponent($3);
+ }
+ );
+
+ this.urlParams = $query_string;
+ this.reload(true);
+}
+
+ListManager.replaceFilter = function ($form_id, $form_html) {
+ $('#' + $form_id).replaceWith($form_html);
+}
+
+ListManager.registerFilter = function ($form_id) {
+ var $manager = this,
+ $form = $('#' + $form_id),
+ $field = $form.attr('filter_field');
+
+ $manager.filters[$field] = {'type': $form.attr('filter_type')};
+
+ $('h2:first a', $form).click(
+ function ($e) {
+ var $header = $(this).parent(),
+ $active = $header.hasClass('active');
+
+ $header.toggleClass('active', !$active);
+ $header.next().toggleClass('noactive', $active);
+
+ return false;
+ }
+ );
+
+ switch( $manager.filters[$field].type ) {
+ case 'radio':
+ $("input[type='radio']", $form).click(
+ function ($e) {
+ $manager.updateFilterParams();
+ }
+ );
+ break;
+
+ case 'checkbox':
+ $("input[type='checkbox']", $form).click(
+ function ($e) {
+ var $checkbox = $(this),
+ $hidden_id = $checkbox.attr('id').replace(/_([\d\w-=]|)+$/, ''),
+ $regexp = new RegExp(jq($hidden_id) + '_([\\d\\w-=]+)');
+
+ if ( $checkbox.val() == '' ) {
+ // "All" checkbox
+ $("input[type='checkbox']", $form).not($checkbox).attr('checked', false);
+ }
+ else if ( $checkbox.is(':checked') ) {
+ $("input[type='checkbox'][value='']", $form).attr('checked', false);
+ }
+
+ update_checkbox_options($regexp, $hidden_id, $form);
+
+ $manager.updateFilterParams();
+ }
+ );
+ break;
+ }
+}
+
+ListManager.syncChecked = function ($checkboxes) {
+ $checkboxes.each(
+ function () {
+ var $me = $(this),
+ $checked = $me.is(':checked'),
+ $dt = $me.parent(),
+ $dd = $dt.next();
+
+ $dt.toggleClass('active', $checked);
+ $dd.toggleClass('active', $checked);
+ }
+ );
+}
+
+ListManager.updateFilterParams = function () {
+ var $form_fields;
+
+ for (var $field in this.filters) {
+ $form_fields = $('#filter-form-' + $field).serializeArray();
+
+ for (var $i = 0; $i < $form_fields.length; $i++) {
+ this.setParam($form_fields[$i].name, $form_fields[$i].value);
+ }
+
+ this.syncChecked( $("input[type=checkbox], input[type=radio]", '#filter-form-' + $field) );
+ }
+
+ this.scheduleReload();
+}
+
+ListManager.init = function () {
+ var $manager = this;
+
+ $('body').bind(
+ 'anchorchanged',
+ function ($e, $anchor) {
+ $manager.parseAnchor($anchor);
+ }
+ );
+}
\ No newline at end of file
missing_smart_filter_phrases.patch [^] (4,393 bytes) 2011-12-27 10:05
[Show Content]
Index: english.lang
===================================================================
--- english.lang (revision 14924)
+++ english.lang (working copy)
@@ -247,7 +247,9 @@
<PHRASE Label="la_error_CustomExists" Module="Core" Type="1">Q3VzdG9tIGZpZWxkIHdpdGggaWRlbnRpY2FsIG5hbWUgYWxyZWFkeSBleGlzdHM=</PHRASE>
<PHRASE Label="la_error_FileTooLarge" Module="Core" Type="1">RmlsZSBpcyB0b28gbGFyZ2U=</PHRASE>
<PHRASE Label="la_error_GroupNotFound" Module="Core" Type="1">Z3JvdXAgbm90IGZvdW5k</PHRASE>
+ <PHRASE Label="la_error_InvalidFieldName" Module="Core" Type="1">RmllbGQgZG9lc24ndCBleGlzdCBpbiAiJXMiIHVuaXQgY29uZmln</PHRASE>
<PHRASE Label="la_error_InvalidFileFormat" Module="Core" Type="1">SW52YWxpZCBGaWxlIEZvcm1hdA==</PHRASE>
+ <PHRASE Label="la_error_InvalidItemPrefix" Module="Core" Type="1">VW5pdCBjb25maWcgcHJlZml4IG5vdCBmb3VuZA==</PHRASE>
<PHRASE Label="la_error_invalidoption" Module="Core" Type="1">aW52YWxpZCBvcHRpb24=</PHRASE>
<PHRASE Label="la_error_LoginFailed" Module="Core" Type="1">TG9naW4gRmFpbGVk</PHRASE>
<PHRASE Label="la_error_MessagesListReceivingFailed" Module="Core" Type="1">UmVjZWl2aW5nIGxpc3Qgb2YgbWVzc2FnZXMgZnJvbSB0aGUgU2VydmVyIGhhcyBmYWlsZWQ=</PHRASE>
@@ -407,6 +409,8 @@
<PHRASE Label="la_fld_Filename" Module="Core" Type="1" Column="RmlsZW5hbWU=">RmlsZW5hbWU=</PHRASE>
<PHRASE Label="la_fld_FilenameReplacements" Module="Core" Type="1">RmlsZW5hbWUgUmVwbGFjZW1lbnRz</PHRASE>
<PHRASE Label="la_fld_FilePath" Module="Core" Type="1" Column="UGF0aA==">UGF0aA==</PHRASE>
+ <PHRASE Label="la_fld_FilterField" Module="Core" Type="1" Hint="RmllbGQgbmFtZSwgdG8gYmUgdXNlZCBpbiBmaWx0ZXI=" Column="RmlsdGVyIEZpZWxk">RmlsdGVyIEZpZWxk</PHRASE>
+ <PHRASE Label="la_fld_FilterType" Module="Core" Type="1" Hint="VGhlIHdheSwgaG93IHRoaXMgZmlsdGVyIHdpbGwgYmUgZGlzcGxheWVkIG9uIEZyb250LUVuZA==" Column="RmlsdGVyIFR5cGU=">RmlsdGVyIFR5cGU=</PHRASE>
<PHRASE Label="la_fld_FirstName" Module="Core" Type="1" Column="Rmlyc3QgTmFtZQ==">Rmlyc3QgTmFtZQ==</PHRASE>
<PHRASE Label="la_fld_Font" Module="Core" Type="1">Rm9udA==</PHRASE>
<PHRASE Label="la_fld_FontColor" Module="Core" Type="1">Rm9udCBDb2xvcg==</PHRASE>
@@ -1220,6 +1224,7 @@
<PHRASE Label="la_title_AddingCountryState" Module="Core" Type="1">QWRkaW5nIENvdW50cnkvU3RhdGU=</PHRASE>
<PHRASE Label="la_title_addingCustom" Module="Core" Type="1">QWRkaW5nIEN1c3RvbSBGaWVsZA==</PHRASE>
<PHRASE Label="la_title_AddingFile" Module="Core" Type="1">QWRkaW5nIEZpbGU=</PHRASE>
+ <PHRASE Label="la_title_AddingItemFilter" Module="Core" Type="1">QWRkaW5nIEl0ZW0gRmlsdGVy</PHRASE>
<PHRASE Label="la_title_AddingMailingList" Module="Core" Type="1">QWRkaW5nIE1haWxpbmcgTGlzdA==</PHRASE>
<PHRASE Label="la_title_AddingPermissionType" Module="Core" Type="1">QWRkaW5nIFBlcm1pc3Npb24gVHlwZQ==</PHRASE>
<PHRASE Label="la_title_AddingPromoBlock" Module="Core" Type="1">QWRkaW5nIFByb21vIEJsb2Nr</PHRASE>
@@ -1271,6 +1276,7 @@
<PHRASE Label="la_title_EditingDraft" Module="Core" Type="1">RWRpdGluZyBEcmFmdCAoJTIkcyk=</PHRASE>
<PHRASE Label="la_title_EditingEmailEvent" Module="Core" Type="1">RWRpdGluZyBFbWFpbCBFdmVudA==</PHRASE>
<PHRASE Label="la_title_EditingFile" Module="Core" Type="1">RWRpdGluZyBGaWxl</PHRASE>
+ <PHRASE Label="la_title_EditingItemFilter" Module="Core" Type="1">RWRpdGluZyBJdGVtIEZpbHRlcg==</PHRASE>
<PHRASE Label="la_title_EditingMembership" Module="Core" Type="1">RWRpdGluZyBNZW1iZXJzaGlw</PHRASE>
<PHRASE Label="la_title_EditingPermissionType" Module="Core" Type="1">RWRpdGluZyBQZXJtaXNzaW9uIFR5cGU=</PHRASE>
<PHRASE Label="la_title_EditingPromoBlock" Module="Core" Type="1">RWRpdGluZyBQcm9tbyBCbG9jaw==</PHRASE>
@@ -1316,6 +1322,7 @@
<PHRASE Label="la_title_Images" Module="Core" Type="1">SW1hZ2Vz</PHRASE>
<PHRASE Label="la_title_InstallLanguagePackStep1" Module="Core" Type="1">SW5zdGFsbCBMYW5ndWFnZSBQYWNrIC0gU3RlcCAx</PHRASE>
<PHRASE Label="la_title_InstallLanguagePackStep2" Module="Core" Type="1">SW5zdGFsbCBMYW5ndWFnZSBQYWNrIC0gU3RlcCAy</PHRASE>
+ <PHRASE Label="la_title_ItemFilters" Module="Core" Type="1">SXRlbSBGaWx0ZXJz</PHRASE>
<PHRASE Label="la_title_Items" Module="Core" Type="1">SXRlbXM=</PHRASE>
<PHRASE Label="la_title_Labels" Module="Core" Type="1">TGFiZWxz</PHRASE>
<PHRASE Label="la_title_LangManagement" Module="Core" Type="1">TGFuZy4gTWFuYWdlbWVudA==</PHRASE>
|