Commits

Joachim Werner committed 562c70a

Initial commit

  • Participants

Comments (0)

Files changed (9)

+# generic files to ignore
+# backup files (*~) and vim swap file (.swp), MacOS dir file (.DS_Store)
+*~
+*.lock
+*.DS_Store
+*.swp
+*.swo
+*.out
+.htaccess
+assets/*
+# Directories
+# Dont't ignore:
+!.yii
+!.gitignore
+!.gitkeep

File DDAutoFilterDataColumn.php

+<?php
+class DDAutoFilterDataColumn extends TbDataColumn
+{
+    public $columnType='text';
+    // {{{ renderFilterCell
+    /**
+     * Renders the filter cell.
+     */
+    public function renderFilterCell()
+    {
+        $filterValues = array();
+        echo '<td nowrap="nowrap"><div class="filter-container">';
+
+        // See zii/widgets/grid/CDataColumn.php:
+        if(is_string($this->filter))
+        {
+            // DEBUG 
+            echo 'string';
+            echo $this->filter;
+        }
+        elseif($this->filter!==false && $this->grid->filter!==null && $this->name!==null && strpos($this->name,'.')===false)
+        {
+            echo CHtml::activeHiddenField($this->grid->filter, $this->name, array('id'=>false));
+            if(is_array($this->filter)) {
+                // DEBUG echo 'array';
+                //echo CHtml::activeDropDownList($this->grid->filter, $this->name, $this->filter, array('id'=>false,'prompt'=>''));
+                $filterValues = CJSON::encode($this->filter);
+            } elseif($this->filter===null) {
+                // DEBUG echo 'null';
+                //echo $this->grid->filter->{$this->name};
+            }
+            echo $this->getFilterText($this->grid->filter->{$this->name});
+        }
+        else
+            parent::renderFilterCellContent();
+
+        if($this->name !== null) {
+            if( $this->grid->filter->{$this->name}=='' )
+                $icon = 'arrow-down';
+            else
+                $icon = 'filter';
+            echo '&nbsp;<i class="icon-'.$icon.' autofilter" style="cursor:pointer" '
+                .'data-column-type="'.$this->columnType.'" '
+                .'data-grid="'.$this->grid->id.'" '
+                .'data-model-name="'.get_class($this->grid->filter).'" '
+                .'data-attribute="'.$this->name.'" '
+                .'data-label="'.CHtml::encode($this->grid->dataProvider->model->getAttributeLabel($this->name)).'" ';
+            if(count($filterValues)>0) 
+                echo 'data-filter-values=\''.$filterValues.'\' ';
+            
+            $sort = $this->grid->dataProvider->getSort();
+            if ($sort->resolveAttribute($this->name) !== false)
+                echo 'data-sort="true" ';
+            else
+                echo 'data-sort="false" ';
+            if($this->filter!==false && $this->grid->filter!==null && $this->name!==null && $this->grid->filter->{$this->name} !=='')
+               echo 'data-value="'.base64_encode($this->grid->filter->{$this->name}).'" ';
+            echo '></i>';
+        }
+        echo '</div></td>';
+    } // }}} 
+    // {{{ getFilterText
+    /**
+     * Prettify filter settings
+     *
+     * @return string
+     */
+    public function getFilterText($filter)
+    {
+        // Array of operators => replacement, prefix, postfix
+        $operators = array(
+            'EQUALS' => array('', '', ''),
+            'NOT-EQUALS' => array('<>', '', ''),
+            'GT' => array('>', '', ''),
+            'GTE' => array('>=', '', ''),
+            'LT' => array('<', '', ''),
+            'LTE' => array('<=', '', ''),
+            'STARTS-WITH' => array('', '', '*'),
+            'ENDS-WITH' => array('', '*', ''),
+            'CONTAINS' => array('', '*', '*'),
+            'NOT-CONTAINS' => array('', '! *', '*'),
+            'IN'=>array('', '(', ')'),
+        );
+
+        $result = array();
+        if(preg_match('/\[\{(.*)\}\]/', $filter, $matches))
+        {
+            $filters = CJSON::decode($filter);
+            foreach($filters as $n=>$filter2) {
+                $operator = array_key_exists($filter2['operator'], $operators) ? $operators[$filter2['operator']][0] : $filter2['operator'];
+                $result[$n][] = $operator;
+                $prefix = array_key_exists($filter2['operator'], $operators) ? $operators[$filter2['operator']][1] : '';
+                if(is_array($filter2['value']))
+                    $result[$n][] = join(";",$filter2['value']);
+                else
+                    $result[$n][] = $filter2['value'];
+                $postfix = array_key_exists($filter2['operator'], $operators) ? $operators[$filter2['operator']][2] : '';
+                if(isset($filter2['join']))
+                    $result[$n][] = str_replace( array('AND', 'OR'), array(' & ', ' | '), $filter2['join']);
+                
+                $result[$n] = join('', $result[$n]);
+                $result[$n] = $prefix.$result[$n].$postfix;
+            }
+        } else {
+            $result = array($filter);
+        }
+        $final = join(' ', $result);
+        if(strlen($final)>10)
+            $final = '<span title="'.$final.'">'.substr($final,0,10).'...'.'</span>';
+        return $final;
+    } // }}} 
+}

File DDAutoFilterSearchBehavior.php

+<?php
+/**
+ * DDAutoFilterSearchBehavior class file
+ *
+ * @author Joachim Werner <joachim.werner@diggin-data.de> 
+ */
+Yii::import('ext.diggindata.ddautofilter.DDDateHelper');
+
+/**
+ * This model behavior builds search conditions for the DDAutoFilter widget
+ *
+ * @author Joachim Werner <joachim.werner@diggin-data.de> 
+ */
+class DDAutoFilterSearchBehavior extends CActiveRecordBehavior
+{
+    // {{{ dateSearchCriteria
+    /*
+     * Date range search criteria
+     * public $attribute name of the date attribute
+     * public $value value of the date attribute
+     * @return instance of CDbCriteria for the model's search() method
+     */
+    public function dateSearchCriteria($attribute, $value, $dateFormat='Y-m-d')
+    {
+        // Create a new db criteria instance
+        $criteria = new CDbCriteria;
+
+        // DEBUG var_dump($attribute, $value);
+        if(is_null($value) or trim($value)=='')
+            return $criteria;
+        if(substr($value,0,1)=='[' and substr($value,-1)==']') {
+        } else {
+            $value = '[{"operator": "EQUALS", "value": "'.$value.'"}]';
+            $this->getOwner()->$attribute = $value;
+        }
+        $filters = CJSON::decode($value);
+        // DEBUG var_dump($filters);
+
+        foreach($filters as $i=>$filter) 
+        { 
+            $op = '';
+            $join = isset($filter['join']) ? $filter['join'] : 'AND';
+            switch(trim($filter['operator']))
+            {
+                case 'EQUALS':
+                case 'NOT-EQUALS':
+                case 'GT':
+                case 'GTE':
+                case 'LT':
+                case 'LTE':
+                case 'STARTS-WITH':
+                case 'ENDS-WITH':
+                case 'CONTAINS':
+                case 'NOT-CONTAINS':
+                    if(preg_match('/^(?:\s*(<>|<=|>=|<|>|=))?(.*)$/',$filter['value'], $matches)) {
+                        $filter['value'] = date("Y-m-d", CDateTimeParser::parse( $matches[2], CLocale::getInstance(Yii::app()->language)->getDateFormat('medium') ));
+                        $op = $matches[1];
+                    }
+                    break;
+            }
+            switch(trim($filter['operator']))
+            {
+                // {{{ Date Ranges
+                // {{{ Day
+                // {{{ Yesterday
+                case '_DAY_LAST_':
+                    $criteria->compare($attribute,date($dateFormat, DDDateHelper::DayYesterday()));
+                    break;
+                // }}}
+                // {{{ Today
+                case '_DAY_THIS_':
+                    $criteria->compare($attribute, date($dateFormat));
+                    break;
+                // }}}
+                // {{{ Tomorrow
+                case '_DAY_NEXT_':
+                    $criteria->compare($attribute, date($dateFormat, DDDateHelper::DayTomorrow()));
+                    break;
+                // }}}
+                // }}}
+                // {{{ Week
+                // {{{ Last Week
+                case '_WEEK_LAST_':
+                    $fromTo = DDDateHelper::WeekRelative(null,-1);
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // {{{ This Week
+                case '_WEEK_THIS_':
+                    $fromTo = DDDateHelper::WeekThis();
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // {{{ Next Week
+                case '_WEEK_NEXT_':
+                    $fromTo = DDDateHelper::WeekRelative(null,1);
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // }}}
+                // {{{ Month
+                // {{{ Last Month
+                case '_MONTH_LAST_':
+                    $fromTo = DDDateHelper::MonthRelative(null,-1);
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // {{{ This Month
+                case '_MONTH_THIS_':
+                    $fromTo = DDDateHelper::MonthThis();
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // {{{ Next Month
+                case '_MONTH_NEXT_':
+                    $fromTo = DDDateHelper::MonthRelative(null,1);
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // }}}
+                // {{{ Quarter
+                // {{{ Last Quarter
+                case '_QUARTER_LAST_':
+                    $fromTo = DDDateHelper::QuarterRelative(null,-1);
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // {{{ This Quarter
+                case '_QUARTER_THIS_':
+                    $fromTo = DDDateHelper::QuarterThis();
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // {{{ Next Quarter
+                case '_QUARTER_NEXT_':
+                    $fromTo = DDDateHelper::QuarterRelative(null,1);
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // }}}
+                // {{{ Year
+                // {{{ Last Year
+                case '_YEAR_LAST_':
+                    $fromTo = DDDateHelper::YearRelative(null,-1);
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // {{{ This Year
+                case '_YEAR_THIS_':
+                    $fromTo = DDDateHelper::YearThis();
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // {{{ Next Year
+                case '_YEAR_NEXT_':
+                    $fromTo = DDDateHelper::YearRelative(null,1);
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}
+                // {{{ Year Todate
+                case '_YEAR_TODATE_':
+                    $fromTo = DDDateHelper::YearToDate(null,1);
+                    $criteria->addCondition(
+                        sprintf(
+                            "t.%s BETWEEN '%s' AND '%s'",
+                            $attribute,
+                            date($dateFormat, $fromTo[0]),
+                            date($dateFormat, $fromTo[1])
+                        )
+                    );
+                    break;
+                // }}}                // }}}
+                // }}} 
+                case 'EQUALS':
+                    $criteria->compare($attribute, $op.$value, false, $join );
+                    //$this->owner->$attribute = $value;
+                    break;
+                case 'NOT-EQUALS':
+                    $criteria->addCondition("$attribute<>'{$filter['value']}'", $join);
+                    break;
+                case 'GT':
+                    $criteria->addCondition("$attribute>'{$filter['value']}'", $join);
+                    break;
+                case 'GTE':
+                    $criteria->addCondition("$attribute>='{$filter['value']}'", $join);
+                    break;
+                case 'LT':
+                    $criteria->addCondition("$attribute<'{$filter['value']}'", $join);
+                    break;
+                case 'LTE':
+                    $criteria->addCondition("$attribute<='{$filter['value']}'", $join);
+                    break;
+                case 'STARTS-WITH':
+                    $criteria->addCondition("$attribute LIKE '{$filter['value']}%'", $join);
+                    break;
+                case 'ENDS-WITH':
+                    $criteria->addCondition("$attribute LIKE '%{$filter['value']}'", $join);
+                    break;
+                case 'CONTAINS':
+                    $criteria->addCondition("$attribute LIKE '%{$filter['value']}%'", $join);
+                    break;
+                case 'NOT-CONTAINS':
+                    $criteria->addCondition("$attribute NOT LIKE '%{$filter['value']}%'", $join);
+                    break;
+            } 
+        }
+        // Return the search criteria to merge with the model's search() method
+        return $criteria;
+    } // }}} 
+    // {{{ textSearchCriteria
+    public function textSearchCriteria($attribute, $value)
+    {
+        // Create a new db criteria instance
+        $criteria = new CDbCriteria;
+
+        // DEBUG var_dump($attribute, $value);
+        if(is_null($value) or trim($value)=='')
+            return $criteria;
+        if(substr($value,0,1)=='[' and substr($value,-1)==']') {
+        } else {
+            $value = '[{"operator": "EQUALS", "value": "'.$value.'"}]';
+            $this->getOwner()->$attribute = $value;
+        }
+        $filters = CJSON::decode($value);
+        // DEBUG var_dump($filters);
+        foreach($filters as $i=>$filter) 
+        {
+            $join = isset($filter['join']) ? $filter['join'] : 'AND';
+            // DEBUG var_dump($filter, $filter['value']);
+
+            switch($filter['operator'])
+            {
+                case 'EQUALS':
+                    $criteria->compare($attribute, $filter['value'], false, $join );
+                    break;
+                case 'NOT-EQUALS':
+                    $criteria->addCondition("$attribute<>'{$filter['value']}'", $join);
+                    break;
+                case 'GT':
+                    $criteria->addCondition("$attribute>'{$filter['value']}'", $join);
+                    break;
+                case 'GTE':
+                    $criteria->addCondition("$attribute>='{$filter['value']}'", $join);
+                    break;
+                case 'LT':
+                    $criteria->addCondition("$attribute<'{$filter['value']}'", $join);
+                    break;
+                case 'LTE':
+                    $criteria->addCondition("$attribute<='{$filter['value']}'", $join);
+                    break;
+                case 'STARTS-WITH':
+                    $criteria->addCondition("$attribute LIKE '{$filter['value']}%'", $join);
+                    break;
+                case 'ENDS-WITH':
+                    $criteria->addCondition("$attribute LIKE '%{$filter['value']}'", $join);
+                    break;
+                case 'CONTAINS':
+                    $criteria->addCondition("$attribute LIKE '%{$filter['value']}%'", $join);
+                    break;
+                case 'NOT-CONTAINS':
+                    $criteria->addCondition("$attribute NOT LIKE '%{$filter['value']}%'", $join);
+                    break;
+                case 'BETWEEN':
+                    list($valueStart, $valueEnd) = preg_split('/[\s]+AND|OR[\s]+/', $filter['value'], -1, PREG_SPLIT_NO_EMPTY);
+                    $criteria->addBetweenCondition($attribute, $valueStart, $valueEnd, $join);
+                    break;
+                case 'IN':
+                    $criteria->addInCondition($attribute, $filter['value'], $join);
+                    break;
+            }
+        }
+        // DEBUG var_dump($criteria);
+        return $criteria;
+    } // }}} 
+}

File DDAutoFilterWidget.php

+<?php
+/**
+ * DDAutoFilterWidget Class File
+ * 
+ * @author Joachim Werner <joachim.werner@diggin-data.de>
+ * @link http://www.diggin-data.de
+ */
+
+/**
+ * DDAutoFilterWidget creates an auto-filter popup to filter  a CGridView
+ *
+ * @author  Joachim Werner <joachim.werner@diggin-data.de>
+ * @version 0.1
+ */
+class DDAutoFilterWidget extends CWidget
+{
+    public $gridId;
+
+    // {{{ run
+    /**
+     * Runs the widget 
+     * 
+     * @access public
+     * @return void
+     */
+    public function run()
+    {
+        $this->registerClientScripts();
+        echo $this->createMarkup();
+    } // }}} 
+    // {{{ registerClientScripts
+    /**
+     * Registers the clientside widget files (css & js)
+     */
+    private function registerClientScripts() {
+        // Get the resources path
+        $resources = dirname(__FILE__).'/resources';
+
+        $cs = Yii::app()->clientScript;
+        // publish the files
+        $baseUrl = Yii::app()->assetManager->publish($resources);
+        // Stylesheet
+        if(is_file($resources.'/styles.css')) {
+            $cs->registerCssFile($baseUrl.'/styles.css');
+        }
+        // JavaScript
+        if(is_file($resources.'/ddautofilter.js')) {
+            $cs->registerScriptFile($baseUrl.'/ddautofilter.js');
+        }
+   } // }}}     
+    // {{{ createMarkup
+    /**
+     * Creates the widget's markup 
+     * 
+     * @access public
+     * @return void
+     */
+    public function createMarkup()
+    {
+        $this->render(
+            'widget',
+            array(
+                'gridId'=>$this->gridId,
+            )
+        );
+    } // }}} 
+}

File DDDateHelper.php

+<?php
+/*
+ * DDDateHelper class file
+ *
+ * @author Joachim Werner <joachim.werner@diggin-data.de> 
+
+/**
+ * Some date functions
+ *
+ * @author Joachim Werner <joachim.werner@diggin-data.de>
+ */
+
+class DDDateHelper
+{
+// {{{ *** Date Methods ***
+// {{{ Days
+// {{{ DayTomorrow
+function DayTomorrow($ts=null)
+{
+    if($ts==null) 
+        $ts=mktime();
+    return strtotime("+1 day", $ts);
+}
+// }}} 
+// {{{ DayYesterday
+function DayYesterday($ts=null)
+{
+    if($ts==null) 
+        $ts=mktime();
+    return strtotime("-1 day", $ts);
+} // }}} 
+// {{{ DaysRange
+function DaysRange($start, $end, $workingDaysOnly=false)
+{
+    list($year,$month,$day) = explode('-',$start);
+    $start = mktime(0,0,0,$month,$day,$year);
+    list($year,$month,$day) = explode('-',$end);
+    $end = mktime(23,59,59,$month,$day,$year);
+    $tmp = array();
+    $current = $start;
+    while($current<=$end) {
+        if($workingDaysOnly==true and in_array(date("w",$current),array(1,2,3,4,5)))
+            $tmp[] = strtotime(date("Y-m-d",$current));
+        $current = $current + +60*60*24;
+    }
+    return $tmp;
+} // }}} 
+// }}} 
+// {{{ Weeks
+function WeekFirstDay($ts=null)
+{
+    if($ts==null) 
+        $ts=mktime();
+    $day = date("w",$ts);
+    if($day==1) 
+        return strtotime(date("Y-m-d",$ts));
+    else
+        return strtotime(date("Y-m-d",strtotime("last monday",$ts)));
+}
+function WeekLastDay($ts=null)
+{
+    if($ts==null) 
+        $ts=mktime();
+    $day = date("w",$ts);
+    if($day==6) 
+        return strtotime(date("Y-m-d",$ts));
+    else
+        return strtotime(date("Y-m-d",strtotime("sunday",$ts)));
+}
+function WeekThis($ts=null)
+{
+    if($ts==null) 
+        $ts=mktime();
+    return array(self::WeekFirstDay($ts),self::WeekLastDay($ts));
+}
+function WeekRelative($ts=null,$relative=0)
+{
+    if($ts==null) 
+        $ts=mktime();
+    $tsDiff = $relative*86400*7;
+    return self::WeekThis($ts+$tsDiff);
+}
+// }}} 
+// {{{ Months
+function MonthFirstDay($ts=null)
+{
+    if($ts==null) 
+        $ts=mktime();
+    if(date("j",$ts)==1 )
+        return strtotime(date("Y-m-d",$ts));
+    else
+        return strtotime(date("Y-m-d",mktime(0,0,0,date("n",$ts),1,date("Y",$ts))));    
+}
+function MonthLastDay($ts=null)
+{
+    if($ts==null) 
+        $ts=mktime();
+    $nextMonth = mktime(0,0,0,date("n",$ts)+1,1,date("Y",$ts));
+    return strtotime(date("Y-m-d", strtotime("-1 day", $nextMonth)));
+}
+function MonthThis($ts=null)
+{
+    if($ts==null) 
+        $ts=mktime();
+    return array(self::MonthFirstDay($ts),self::MonthLastDay($ts));
+}
+function MonthRelative($ts=null,$relative=0)
+{
+    if($ts==null) 
+        $ts=mktime();
+    $tsNew = mktime(0, 0, 0, date("n",$ts)+$relative,1,date("Y",$ts));
+    return self::MonthThis($tsNew);
+}
+// }}} 
+// {{{ Quarters
+function QuarterFirstDay($ts=null)
+{
+    if($ts==null) 
+        $ts=mktime();
+    $month = date("n", $ts);
+    if($month>=1 and $month<=3)
+        return strtotime(date("Y-m-d", mktime(0,0,0,1,1,date("Y",$ts))));
+    elseif($month>=4 and $month<=6)
+        return strtotime(date("Y-m-d", mktime(0,0,0,4,1,date("Y",$ts))));
+    elseif($month>=7 and $month<=9)
+        return strtotime(date("Y-m-d", mktime(0,0,0,7,1,date("Y",$ts))));
+    else
+        return strtotime(date("Y-m-d", mktime(0,0,0,10,1,date("Y",$ts))));
+}
+function QuarterLastDay($ts=null)
+{
+    $month = date("n", $ts);
+    if($month>=1 and $month<=3)
+        return strtotime(date("Y-m-d", mktime(0,0,0,3,31,date("Y",$ts))));
+    elseif($month>=4 and $month<=6)
+        return strtotime(date("Y-m-d", mktime(0,0,0,6,30,date("Y",$ts))));
+    elseif($month>=7 and $month<=9)
+        return strtotime(date("Y-m-d", mktime(0,0,0,9,30,date("Y",$ts))));
+    else
+        return strtotime(date("Y-m-d", mktime(0,0,0,12,31,date("Y",$ts))));
+}
+function QuarterThis($ts=null)
+{
+    if($ts==null) 
+        $ts=mktime();
+    return array(self::QuarterFirstDay($ts),self::QuarterLastDay($ts));
+}
+function QuarterRelative($ts=null,$relative=0)
+{
+    if($ts==null) 
+        $ts=mktime();
+    $month = date("n", $ts)+$relative*3;
+    return self::QuarterThis(mktime(0,0,0,$month,1,date("Y",$ts)));
+}
+// }}} 
+// {{{ Years
+function YearFirstDay($ts=null)
+{
+    if($ts==null)
+        $ts=mktime();
+    return strtotime(date("Y-m-d",mktime(0,0,0,1,1,date("Y",$ts))));
+}
+function YearLastDay($ts=null)
+{
+    if($ts==null)
+        $ts=mktime();
+    return strtotime(date("Y-m-d H:i:s",mktime(23,59,59,12,31,date("Y",$ts))));
+}
+function YearThis($ts=null)
+{
+    if($ts==null)
+        $ts=mktime();
+    return array(self::YearFirstDay($ts),self::YearLastDay($ts));
+}
+function YearToDate($ts=null)
+{
+    if($ts==null)
+        $ts=mktime();
+    return array(strtotime(date("Y-m-d H:i:s", mktime(0,0,0,1,1,date("Y")))),strtotime(date("Y-m-d H:i:s",$ts)));
+}
+function YearRelative($ts=null,$relative=0)
+{
+    if($ts==null)
+        $ts=mktime();
+    $tsNew = mktime(0,0,0,date("n",$ts),date("j",$ts),date("Y",$ts)+$relative);
+    return self::YearThis($tsNew);
+}
+// }}} 
+// }}} 
+
+}
+
+/* vim: set ai expandtab tabstop=4 shiftwidth=4 softtabstop=4 fdm=marker fdc=4: */ 
+?>
+DDAutoFilter
+============
+
+Installation
+------------
+
+Extract the extension file under `protected/extensions/diggindata`.
+
+Setup
+-----
+
+### Model / _search_ Method
+
+In your CActiveReord model's `search()` method, for each column that shall be displayed 
+using auto-filters, change the `$criteria` line.
+
+~~~
+// Replace:
+$criteria->compare('title',$this->title,true);
+// ... with:
+$criteria->mergeWith($this->textSearchCriteria('title', $this->title));
+~~~
+
+#### Grid View
+
+##### Grid View Properties
+
+Add some code to the CGridView `afterAjaxUpdate` property:
+
+~~~
+<?php $this->widget('ext.bootstrap.widgets.TbGridView', array(
+    'id'=>'your-model-grid', // see below
+    ...
+    'afterAjaxUpdate'=>'function(){jQuery("i.autofilter").click(showAutofilterDialog)}',
+    ...
+    )); ?>
+~~~
+
+##### Grid View Columns
+
+~~~
+    'columns' => array(
+        ...
+        array(
+            'name'=>'level',
+            'class'=>'ext.diggindata.ddautofilter.DDAutoFilterDataColumn',
+            'columnType'=>'number', // or 'text' or 'date' or 'bool'
+            'filter => array(1=>1, 2=>2, 3=>3), // will be displayed in values select multiple control
+        ),
+        ...
+~~~
+
+##### Auto-Filter Widget
+
+After the CGridView widget code, add:
+
+~~~
+<?php $this->widget('ext.diggindata.ddautofilter.DDAutoFilterWidget', array('gridId' => 'your-model-grid')); ?>
+~~~
+
+
+If you like this extension, please consider donating a bit:
+
+[Donate with PayPal][paypal]
+
+
+[paypal]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DDZUYNDEJ6XDY

File resources/ddautofilter.js

+var grid;
+var columnType;
+var modelName;
+var attribute;
+var label;
+var value;
+var sort;
+var filterValues;
+var moreFiltersShown=false;
+var filterCellName;
+var sorting = false;
+
+function showAutofilterDialog() // {{{ 
+{
+    var valueObj={};
+    grid = $(this).attr('data-grid');
+    columnType = $(this).attr('data-column-type');
+    modelName = $(this).attr('data-model-name');
+    attribute = $(this).attr('data-attribute');
+    label = $(this).attr('data-label');
+    value = $(this).attr('data-value');
+    if(typeof value=='undefined') 
+        value = '';
+    if(value.replace(/^\s+|\s+$/g, '')!='')
+        value = decode64($(this).attr('data-value'));
+    // DEBUG alert('>'+value+'<');
+    // DEBUG alert(typeof value);
+    var suche = /^\[\{(.*)\}\]$/;
+    if(value.match(suche)) {
+        valueObj = JSON.parse(value);
+    } else if(value!=='') {
+        value = '[{"operator":"EQUALS","value":"'+value+'"}]';
+        valueObj = JSON.parse(value);
+    }
+
+    console.log(valueObj);
+    filterValues = $(this).attr('data-filter-values');
+    if(typeof filterValues=='undefined') 
+        filterValues = '';
+    if(filterValues.replace(/^\s+|\s+$/g, '')!='')
+        filterValues = JSON.parse(filterValues);
+    else
+        filterValues = {};
+    // DEBUG alert(filterValues);
+    // DEBUG alert(attribute);
+    // DEBUG alert('>'+value+'<');
+
+    // Add select values
+    $('select[name=values]')
+        .find('option[value!=__ALL__]')
+        .remove();
+    if(filterValues!={}) { 
+        $('select[name=values]').show();
+    }
+
+    $.each(filterValues, function(key, value) {   
+         $('select[name=values]')
+            .append($('<option>', { value : key })
+            .text(value)); 
+    });
+
+    var form = jQuery('#'+grid+'-autofilter');
+    var textfilter = form.find('.textfilter');
+    if(value.replace(/^\s+|\s+$/g, '')=='')
+        textfilter.val('');
+    else if(valueObj.length==1 && valueObj[0].operator=='EQUALS')
+        textfilter.val(valueObj[0].value);
+    else
+        textfilter.val(value);
+    
+    if(valueObj[0]) {
+        if(valueObj[0].operator=='IN') {
+            $('select[name=values]').val(valueObj[0].value);
+            $('.textfilter').val('');
+        }
+    }
+    
+    console.log(filterValues);
+    sort = $(this).attr('data-sort');
+
+    var posLeft=$(this).position().left+10;
+    var posTop=$(this).position().top-50;
+    
+    var sort1 = form.find('input[name=sort1]');
+    sort1.attr('name',modelName+'_sort');
+    
+    var sort2 = form.find('input[name=sort2]');
+    sort2.attr('name',modelName+'_sort');
+    
+    // Rename textfield?
+    // textfilter.attr('name', modelName+'['+attribute+']');
+    filterCellName = modelName+'\\['+attribute+'\\]';
+
+
+    jQuery('.attributeLabel').html(label);
+
+    jQuery('.textfilters, .numberfilters, .boolfilters, .datefilters').hide();
+    if(columnType=='text') {
+        jQuery('.filters-more').html('Text Filters...');
+        jQuery('.textfilters').show();
+    } else if(columnType=='number') {
+        jQuery('.filters-more').html('Number Filters...');
+        jQuery('.numberfilters').show();
+    } else if(columnType=='boolean') {
+        jQuery('.filters-more').html('Yes/No Filters...');
+        jQuery('.boolfilters').show();
+    } else if(columnType=='date') {
+        jQuery('.filters-more').html('Date Filters...');
+        jQuery('.datefilters').show();
+    }
+
+    jQuery('.clear-filter').click(function() {
+        jQuery('select[name=values]').val([]);
+        jQuery('#'+grid+'-autofilter .textfilter').val('');
+        submitAutofilterForm();
+    });
+
+
+    // jQuery('.dialogtest .autofilter-sort').click( doSort /*function() {  } */ );
+
+    jQuery('.udf-equals').click(function() { showUserDefinedFilter('EQUALS'); } );
+    jQuery('.udf-not-equals').click(function() { showUserDefinedFilter('NOT-EQUALS'); } );
+    jQuery('.udf-starts-with').click(function() { showUserDefinedFilter('STARTS-WITH'); } );
+    jQuery('.udf-ends-with').click(function() { showUserDefinedFilter('ENDS-WITH'); } );
+    jQuery('.udf-contains').click(function() { showUserDefinedFilter('CONTAINS'); } );
+    jQuery('.udf-not-contains').click(function() { showUserDefinedFilter('NOT-CONTAINS'); } );
+    jQuery('.udf-between').click(function() { showUserDefinedFilter('BETWEEN'); } );
+    jQuery('.udf-gt').click(function() { showUserDefinedFilter('GT'); } );
+    jQuery('.udf-gte').click(function() { showUserDefinedFilter('GTE'); } );
+    jQuery('.udf-lt').click(function() { showUserDefinedFilter('LT'); } );
+    jQuery('.udf-lte').click(function() { showUserDefinedFilter('LTE'); } );
+    jQuery('.udf-bool-yes').click(function() { $('.textfilter').val(1); submitAutofilterForm(); } );
+    jQuery('.udf-bool-no').click(function() { $('.textfilter').val(0); submitAutofilterForm(); } );
+    
+    jQuery('.udf-date-before').click(function() { showUserDefinedFilter('LT'); } );
+    jQuery('.udf-date-after').click(function() { showUserDefinedFilter('GT'); } );
+    // Days
+    jQuery('.udf-date-day-next').click(function() { setDateFilter('_DAY_NEXT_'); } );
+    jQuery('.udf-date-day-this').click(function() { setDateFilter('_DAY_THIS_'); } );
+    jQuery('.udf-date-day-last').click(function() { setDateFilter('_DAY_LAST_'); } );
+    // Weeks
+    jQuery('.udf-date-week-next').click(function() { setDateFilter('_WEEK_NEXT'); } );
+    jQuery('.udf-date-week-this').click(function() { setDateFilter('_WEEK_THIS_'); } );
+    jQuery('.udf-date-week-last').click(function() { setDateFilter('_WEEK_LAST_'); } );
+    // Months
+    jQuery('.udf-date-month-next').click(function() { setDateFilter('_MONTH_NEXT'); } );
+    jQuery('.udf-date-month-this').click(function() { setDateFilter('_MONTH_THIS_'); } );
+    jQuery('.udf-date-month-last').click(function() { setDateFilter('_MONTH_LAST_'); } );
+    // Quarters
+    jQuery('.udf-date-quarter-next').click(function() { setDateFilter('_QUARTER_NEXT'); } );
+    jQuery('.udf-date-quarter-this').click(function() { setDateFilter('_QUARTER_THIS_'); } );
+    jQuery('.udf-date-quarter-last').click(function() { setDateFilter('_QUARTER_LAST_'); } );
+    // Years
+    jQuery('.udf-date-year-next').click(function() { setDateFilter('_YEAR_NEXT'); } );
+    jQuery('.udf-date-year-this').click(function() { setDateFilter('_YEAR_THIS_'); } );
+    jQuery('.udf-date-year-last').click(function() { setDateFilter('_YEAR_LAST_'); } );
+    
+    jQuery('.udf-default').click(function() { showUserDefinedFilter('default'); } );
+
+    $('.dialogtest').dialog({autoOpen: false,
+        title: label,
+        modal: true,
+        //position:[posLeft,posTop],
+        buttons:{ 
+            'OK':function(){
+                submitAutofilterForm();
+            },
+            'Cancel':function(){
+                jQuery('.moreFilters').hide(400);
+                moreFiltersShown = false;
+                $(this).dialog('close');
+            }
+        }
+    });
+    $('.dialogtest').dialog('open');
+    $('.dialogtest').keypress(function(e) {
+        if (e.keyCode == $.ui.keyCode.ENTER) {
+            e.preventDefault();
+            //Close dialog and/or submit here...
+            submitAutofilterForm();
+        }
+    });
+    $('.textfilter').focus().select();
+} // }}} 
+function submitAutofilterForm() // {{{ 
+{
+    jQuery('.moreFilters').hide(400);
+    moreFiltersShown = false;
+    if($('select[name=values]').val()) {
+        var selectedValues = $('select[name=values]').val();
+        console.log(selectedValues[0]==['__ALL__']);
+        // All selected?
+        if(selectedValues[0]==['__ALL__']) {
+            console.log('__ALL__');
+            jQuery('select[name=values]').val([]);
+            jQuery('#'+grid+'-autofilter .textfilter').val('');
+        } else {
+            result = [{operator: "IN", value:[]}];
+            $("select[name=values] option:selected").each(function () {
+                result[0].value[result[0].value.length] = $(this).val();
+            });
+            $('.textfilter').val(JSON.stringify(result));
+        }
+    }
+    // Update (hidden) filter field
+    $('input[name='+filterCellName+']').val($('.textfilter').val());
+    // OLD:
+    // $.fn.yiiGridView.update(grid,{data: $('#'+grid+'-autofilter').serialize()} );
+    // Trigger Enter keypress on hidden field
+    var press = jQuery.Event("keydown", {keyCode: 13 } );
+    $('input[name='+filterCellName+']').trigger(press);
+
+    $('i.autofilter').on('click',showAutofilterDialog);
+ 
+    $('.dialogtest').dialog('close');
+} // }}} 
+function showUserDefinedFilter(mode) // {{{ 
+{
+    if(mode=='BETWEEN') {
+        jQuery('select[name=operator1]').val('GTE');
+        jQuery('input[name=andOr]').val('AND');
+        jQuery('select[name=operator2]').val('LTE');
+    } else if(mode=='default') {
+
+    } else {
+        jQuery('select[name=operator1]').val(mode);
+    }
+    $('.userDefinedFilter').dialog({autoOpen: false,
+        title: label,
+        modal: true,
+        buttons:{ 
+            'OK':function(){
+                var result = [];
+                var op1 = $('select[name=operator1]').val();
+                var text1 = jQuery('input[name=udftext1]').val();
+                result[result.length] = {operator: op1, value: text1};
+                console.log(result);
+                
+                var op2 = $('select[name=operator2]').val();
+                var text2 = jQuery('input[name=udftext2]').val();
+                var andOr = $('input[name=andOr]:checked').val();
+                console.log('andOr: '+andOr);
+                
+                if(text2!='') {
+                    result[0]['join'] = andOr;
+                    result[result.length] = {operator: op2, value: text2};
+                }
+                console.log(result);
+                $('input.textfilter').val(JSON.stringify(result));
+                // De-select multiple values dropdown
+                $('select[name=values]').val([]);
+                
+                // reset fields
+                $('select[name=operator1], select[name=operator2]').val('');
+                jQuery('input[name=udftext1], input[name=udftext2]').val('');
+
+                $(this).dialog('close');
+                submitAutofilterForm();
+            },
+            'Cancel':function(){
+                $(this).dialog('close');
+            }
+        }
+    });
+    $('.userDefinedFilter').dialog('open');
+    $('input[name=udftext1]').focus().select();
+} // }}}
+function setDateFilter(filter) { // {{{ 
+    $('.textfilter').val(JSON.stringify([{operator: filter,value:""}]));
+    submitAutofilterForm();
+} // }}} 
+function doSort(order) { // {{{ 
+    if(sorting) return;
+    alert(order); 
+    sorting = true;
+    var sort = attribute;
+    if(order=='desc') {
+        sort += '.desc';
+    }
+    $('input[name='+filterCellName+']').parent().find('input[name='+modelName+'_sort]').remove();
+    $('input[name='+filterCellName+']').parent().append('<input type="hidden" name="'+modelName+'_sort" value="'+sort+'" />'); 
+    submitAutofilterForm(); 
+    sorting=false;
+} // }}} 
+// {{{ *** BASE64 Functions ***
+var keyStr = "ABCDEFGHIJKLMNOP" +
+               "QRSTUVWXYZabcdef" +
+               "ghijklmnopqrstuv" +
+               "wxyz0123456789+/" +
+               "=";
+// {{{ encode64
+function encode64(input) {
+     input = escape(input);
+     var output = "";
+     var chr1, chr2, chr3 = "";
+     var enc1, enc2, enc3, enc4 = "";
+     var i = 0;
+
+     do {
+        chr1 = input.charCodeAt(i++);
+        chr2 = input.charCodeAt(i++);
+        chr3 = input.charCodeAt(i++);
+
+        enc1 = chr1 >> 2;
+        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+        enc4 = chr3 & 63;
+
+        if (isNaN(chr2)) {
+           enc3 = enc4 = 64;
+        } else if (isNaN(chr3)) {
+           enc4 = 64;
+        }
+
+        output = output +
+           keyStr.charAt(enc1) +
+           keyStr.charAt(enc2) +
+           keyStr.charAt(enc3) +
+           keyStr.charAt(enc4);
+        chr1 = chr2 = chr3 = "";
+        enc1 = enc2 = enc3 = enc4 = "";
+     } while (i < input.length);
+
+     return output;
+} // }}} 
+// {{{ decode64
+function decode64(input) {
+     var output = "";
+     var chr1, chr2, chr3 = "";
+     var enc1, enc2, enc3, enc4 = "";
+     var i = 0;
+
+     // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
+     var base64test = /[^A-Za-z0-9\+\/\=]/g;
+     if (base64test.exec(input)) {
+        alert("There were invalid base64 characters in the input text.\n" +
+              "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
+              "Expect errors in decoding.");
+     }
+     input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+     do {
+        enc1 = keyStr.indexOf(input.charAt(i++));
+        enc2 = keyStr.indexOf(input.charAt(i++));
+        enc3 = keyStr.indexOf(input.charAt(i++));
+        enc4 = keyStr.indexOf(input.charAt(i++));
+
+        chr1 = (enc1 << 2) | (enc2 >> 4);
+        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+        chr3 = ((enc3 & 3) << 6) | enc4;
+
+        output = output + String.fromCharCode(chr1);
+
+        if (enc3 != 64) {
+           output = output + String.fromCharCode(chr2);
+        }
+        if (enc4 != 64) {
+           output = output + String.fromCharCode(chr3);
+        }
+
+        chr1 = chr2 = chr3 = "";
+        enc1 = enc2 = enc3 = enc4 = "";
+
+     } while (i < input.length);
+
+     return unescape(output);
+} // }}} 
+// }}} End BASE&$ functions
+
+// vim: set fdm=marker:

File resources/styles.css

+.dialogtest, .userDefinedFilter {
+    font-size: smaller;
+    padding: 3px; 
+}
+.dialogtest hr {
+    margin: 5px 0;
+    border: 0;
+    border-top: 1px solid #aaa;
+    border-bottom: 1px solid #ffffff;
+}
+.clear-filter, .filters-more { 
+    cursor:pointer;
+}

File views/widget.php

+<!-- Dialog I -->
+<div class="dialogtest" style=display:none><!-- {{{ -->
+<form style="font-size:1em;" id="<?php echo $gridId; ?>-autofilter">
+<input type="hidden" name="ajax" value="site-page-grid" />
+<a href="#" name="sort1" class="autofilter-sort asc" value="" onclick="doSort('asc');" /><i class="icon-arrow-down"></i><?php echo CHtml::encode(_('Ascending (A-Z)')); ?></a><br />
+<a href="#" name="sort2" class="autofilter-sort desc" value=".desc"  onclick="doSort('desc');" /><i class="icon-arrow-up"></i><?php echo CHtml::encode(_('Descending (Z-A)')) ?></a><hr />
+<span class="clear-filter"><i class="icon-remove"></i> Remove Filter (<span class="attributeLabel"></span>)</span><hr />
+<span class="filters-more">Textfilter</span><br />
+<div class="moreFilters" style="display:none;max-height:100px;overflow:auto;">
+<ul>
+
+<li><a href="#" class="udf-equals"><?php echo CHtml::encode(_('Equals...')) ?></a></li>
+<li><a href="#" class="udf-not-equals"><?php echo CHtml::encode(_('Not Equals...')) ?></a></li>
+
+<li class="textfilters"><a href="#" class="udf-starts-with"><?php echo CHtml::encode(_('Starts with...')); ?></a></li>
+<li class="textfilters"><a href="#" class="udf-ends-with"><?php echo CHtml::encode(_('Ends with...')); ?></a></li>
+
+<li class="textfilters"><a href="#" class="udf-contains"><?php echo CHtml::encode(_('Contains...')) ?></a></li>
+<li class="textfilters"><a href="#" class="udf-not-contains"><?php echo CHtml::encode(_("Doesn't contain...")) ?></a></li>
+
+<li class="numberfilters"><a href="#" class="udf-gt"><?php echo CHtml::encode(_('Greater than...')) ?></a></li>
+<li class="numberfilters"><a href="#" class="udf-gte"><?php echo CHtml::encode(_('Greater or equal...')) ?></a></li>
+<li class="numberfilters"><a href="#" class="udf-lt"><?php echo CHtml::encode(_('Lower than...')) ?></a></li>
+<li class="numberfilters"><a href="#" class="udf-lte"><?php echo CHtml::encode(_('Lower or equal...')) ?></a></li>
+<li class="numberfilters"><a href="#" class="udf-between"><?php echo CHtml::encode(_('Between...')) ?></a></li>
+
+<li class="boolfilters"><a href="#" class="udf-bool-yes"><?php echo CHtml::encode(_('Yes')) ?></a></li>
+<li class="boolfilters"><a href="#" class="udf-bool-no"><?php echo CHtml::encode(_('No')) ?></a></li>
+
+<li class="datefilters"><a href="#" class="udf-between"><?php echo CHtml::encode(_('Between...')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-before"><?php echo CHtml::encode(_('Before...')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-after"><?php echo CHtml::encode(_('After...')) ?></a></li>
+
+<li class="datefilters"><a href="#" class="udf-date-day-next"><?php echo CHtml::encode(_('Tomorrow')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-day-this"><?php echo CHtml::encode(_('Today')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-day-last"><?php echo CHtml::encode(_('Yesterday')) ?></a></li>
+
+<li class="datefilters"><a href="#" class="udf-date-week-next"><?php echo CHtml::encode(_('Next Week')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-week-this"><?php echo CHtml::encode(_('This Week')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-week-last"><?php echo CHtml::encode(_('Last Week')) ?></a></li>
+
+<li class="datefilters"><a href="#" class="udf-date-month-next"><?php echo CHtml::encode(_('Next Month')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-month-this"><?php echo CHtml::encode(_('This Month')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-month-last"><?php echo CHtml::encode(_('Last Month')) ?></a></li>
+
+<li class="datefilters"><a href="#" class="udf-date-quarter-next"><?php echo CHtml::encode(_('Next Quarter')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-quarter-this"><?php echo CHtml::encode(_('This Quarter')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-quarter-last"><?php echo CHtml::encode(_('Last Quarter')) ?></a></li>
+
+<li class="datefilters"><a href="#" class="udf-date-year-next"><?php echo CHtml::encode(_('Next Year')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-year-this"><?php echo CHtml::encode(_('This Year')) ?></a></li>
+<li class="datefilters"><a href="#" class="udf-date-year-last"><?php echo CHtml::encode(_('Last Year')) ?></a></li>
+
+<li><a href="#" class="udf-default"><?php echo CHtml::encode(_('User-defined Filter...')) ?></a></li>
+</ul>
+</div>
+<hr />
+<input type="text" name="textfilter" class="textfilter" />
+
+<select name="values" multiple="multiple" style="display:none;">
+<option value="__ALL__"><?php echo CHtml::encode(_('All')); ?></option>
+</select>
+
+</form>
+</div><!-- }}} -->
+
+<!-- Dialog II -->
+<div class="userDefinedFilter" style="display:none"><!-- {{{ -->
+<span class="attributeLabel"></span><br />
+<select name="operator1"><!-- {{{ -->
+    <option value="EQUALS"><?php echo CHtml::encode(_('Equals')) ?></option>
+    <option value="NOT-EQUALS"><?php echo CHtml::encode(_("Doesn't equal")) ?></option>
+    <option value="GT"><?php echo CHtml::encode(_('Greater than')) ?></option>
+    <option value="GTE"><?php echo CHtml::encode(_('Greater or equal')) ?></option>
+    <option value="LT"><?php echo CHtml::encode(_('Lower than')) ?></option>
+    <option value="LTE"><?php echo CHtml::encode(_('Lower or equal')) ?></option>
+    <option value="STARTS-WITH"><?php echo CHtml::encode(_('Starts with')) ?></option>
+    <option value="ENDS-WITH"><?php echo CHtml::encode(_('Ends with')) ?></option>
+    <option value="CONTAINS"><?php echo CHtml::encode(_('Contains')) ?></option>
+    <option value="NOT-CONTAINS"><?php echo CHtml::encode(_("Doesn't contain")) ?></option>
+</select>&nbsp;<!-- }}} -->
+<input type="text" name="udftext1" value="" /><br />
+<input type="radio" name="andOr" value="AND" />&nbsp;<?php echo CHtml::encode(_('And')) ?>&nbsp;
+<input type="radio" name="andOr" value="OR" />&nbsp;<?php echo CHtml::encode(_('Or')) ?>&nbsp;
+<select name="operator2"><!-- {{{ -->
+    <option value="EQUALS"><?php echo CHtml::encode(_('Equals')) ?></option>
+    <option value="NOT-EQUALS"><?php echo CHtml::encode(_("Doesn't equal")) ?></option>
+    <option value="GT"><?php echo CHtml::encode(_('Greater than')) ?></option>
+    <option value="GTE"><?php echo CHtml::encode(_('Greater or equal')) ?></option>
+    <option value="LT"><?php echo CHtml::encode(_('Lower than')) ?></option>
+    <option value="LTE"><?php echo CHtml::encode(_('Lower or equal')) ?></option>
+    <option value="STARTS-WITH"><?php echo CHtml::encode(_('Starts with')) ?></option>
+    <option value="ENDS-WITH"><?php echo CHtml::encode(_('Ends with')) ?></option>
+    <option value="CONTAINS"><?php echo CHtml::encode(_('Contains')) ?></option>
+    <option value="NOT-CONTAINS"><?php echo CHtml::encode(_("Doesn't contain")) ?></option>
+</select><!-- }}} -->
+<input type="text" name="udftext2" value="" /><br />
+</div><!-- }}} -->
+
+<?php Yii::app()->clientScript->registerScript('autofilterClickHandler', "
+    //jQuery('i.autofilter').on('click',function(event) { showAutofilterDialog();});
+    jQuery('i.autofilter').on('click',showAutofilterDialog);
+    jQuery('.filters-more').click(function(e){
+        e.preventDefault();
+        if(moreFiltersShown==false) {
+            jQuery('.moreFilters').show(400);
+            moreFiltersShown = true;
+        } else {
+            jQuery('.moreFilters').hide(400);
+            moreFiltersShown = false;
+        }
+    });
+"); ?>
+<!-- vim: set fdm=marker: -->