pepebe
5/14/2013 - 7:37 PM

Slider TV for MODX Revo

Slider TV for MODX Revo

<?php
/*  singleSlider plugin 
    Create a plugin in MODX manager and activate events.
   
    * OnTVInputRenderList
    * OnTVOutputRenderList
    * OnTVInputPropertiesList
    * OnTVOutputRenderPropertiesList
    * OnDocFormPrerender   
   
*/


$corePath = $modx->getOption('core_path',null,MODX_CORE_PATH).'components/singleSlider/';
switch ($modx->event->name) {
    case 'OnTVInputRenderList':
        // For rendering the actual TV input in the backend
        $modx->event->output($corePath.'tv/input/');
        break;
    case 'OnTVOutputRenderList':
        // For rendering the TV output in the frontend
        $modx->event->output($corePath.'tv/output/');
        break;
    case 'OnTVInputPropertiesList':
        // For loading any custom properties for the input render in the manager
        $modx->event->output($corePath.'tv/inputoptions/');
        break;
    case 'OnTVOutputRenderPropertiesList':
        // For loading any custom properties for the output render (front-end) of the TV
        $modx->event->output($corePath.'tv/properties/');
        break;
    case 'OnManagerPageBeforeRender':
        // Why isn't this OnDocFormPrerender?
        break;
}
<!--
Frankensteined from MODX number TV
Copy to: core/components/singleSlider/tv/inputoptions/tpl/ AND rename it to singleSlider.tpl
-->

<div id="tv-input-properties-form{$tv}"></div>
{literal}

<script type="text/javascript">
// <![CDATA[
var params = {
{/literal}{foreach from=$params key=k item=v name='p'}
 '{$k}': '{$v|escape:"javascript"}'{if NOT $smarty.foreach.p.last},{/if}
{/foreach}{literal}
};
var oc = {'change':{fn:function(){Ext.getCmp('modx-panel-tv').markDirty();},scope:this}};
MODx.load({
    xtype: 'panel'
    ,layout: 'form'
    ,autoHeight: true
    ,cls: 'form-with-labels'
    ,labelAlign: 'top'
    ,border: false
    ,items: [{
        xtype: 'combo-boolean'
        ,fieldLabel: _('required')
        ,description: MODx.expandHelp ? '' : _('required_desc')
        ,name: 'inopt_allowBlank'
        ,hiddenName: 'inopt_allowBlank'
        ,id: 'inopt_allowBlank{/literal}{$tv}{literal}'
        ,value: params['allowBlank'] == 0 || params['allowBlank'] == 'false' ? false : true
        ,width: 200
        ,listeners: oc
    },{
        xtype: MODx.expandHelp ? 'label' : 'hidden'
        ,forId: 'inopt_allowBlank{/literal}{$tv}{literal}'
        ,html: _('required_desc')
        ,cls: 'desc-under'
    },{
        xtype: 'combo-boolean'
        ,fieldLabel: _('number_allowdecimals')
        ,name: 'inopt_allowDecimals'
        ,id: 'inopt_allowDecimals{/literal}{$tv}{literal}'
        ,value: params['allowDecimals'] || true
        ,width: 200
        ,listeners: oc
    },{
        xtype: MODx.expandHelp ? 'label' : 'hidden'
        ,forId: 'inopt_allowDecimals{/literal}{$tv}{literal}'
        ,html: _('allowdecimals_desc')
        ,cls: 'desc-under'
    },{
        xtype: 'combo-boolean'
        ,fieldLabel: _('number_allownegative')
        ,name: 'inopt_allowNegative'
        ,id: 'inopt_allowNegative{/literal}{$tv}{literal}'
        ,value: params['allowNegative'] || true
        ,width: 200
        ,listeners: oc
    },{
        xtype: MODx.expandHelp ? 'label' : 'hidden'
        ,forId: 'inopt_allowNegative{/literal}{$tv}{literal}'
        ,html: _('allownegative_desc')
        ,cls: 'desc-under'
    },{
        xtype: 'numberfield'
        ,fieldLabel: _('number_decimalprecision')
        ,name: 'inopt_decimalPrecision'
        ,id: 'inopt_decimalPrecision{/literal}{$tv}{literal}'
        ,value: params['decimalPrecision'] || 2
        ,width: 100
        ,listeners: oc
    },{
        xtype: MODx.expandHelp ? 'label' : 'hidden'
        ,forId: 'inopt_decimalPrecision{/literal}{$tv}{literal}'
        ,html: _('decimalprecision_desc')
        ,cls: 'desc-under'
    },{
        xtype: 'textfield'
        ,fieldLabel: _('number_decimalseparator')
        ,name: 'inopt_decimalSeparator'
        ,id: 'inopt_decimalSeparator{/literal}{$tv}{literal}'
        ,value: params['decimalSeparator'] || '.'
        ,width: 100
        ,listeners: oc
    },{
        xtype: MODx.expandHelp ? 'label' : 'hidden'
        ,forId: 'inopt_decimalSeparator{/literal}{$tv}{literal}'
        ,html: _('decimalseparator_desc')
        ,cls: 'desc-under'
    },{
        xtype: 'textfield'
        ,fieldLabel: _('number_maxvalue')
        ,name: 'inopt_maxValue'
        ,id: 'inopt_maxValue{/literal}{$tv}{literal}'
        ,value: params['maxValue'] || ''
        ,width: 300
        ,listeners: oc
    },{
        xtype: MODx.expandHelp ? 'label' : 'hidden'
        ,forId: 'inopt_maxValue{/literal}{$tv}{literal}'
        ,html: _('maxvalue_desc')
        ,cls: 'desc-under'
    },{
        xtype: 'textfield'
        ,fieldLabel: _('number_minvalue')
        ,name: 'inopt_minValue'
        ,id: 'inopt_minValue{/literal}{$tv}{literal}'
        ,value: params['minValue'] || ''
        ,width: 300
        ,listeners: oc
    },{
        xtype: MODx.expandHelp ? 'label' : 'hidden'
        ,forId: 'inopt_minValue{/literal}{$tv}{literal}'
        ,html: _('minvalue_desc')
        ,cls: 'desc-under'
    },{
        xtype: 'textfield'
        ,fieldLabel: _('singleSlider_custom_tip')
        ,name: 'custom_tip'
        ,id: 'custom_tip{/literal}{$tv}{literal}'
        ,value: params['tip'] || ''
        ,width: 300
        ,listeners: oc
    },{
        xtype: MODx.expandHelp ? 'label' : 'hidden'
        ,forId: 'custom_tip{/literal}{$tv}{literal}'
        ,html: _('tip_desc')
        ,cls: 'desc-under'
    }]
    ,renderTo: 'tv-input-properties-form{/literal}{$tv}{literal}'
});
// ]]>
</script>
{/literal}
<?php
/*
Copy to: core/components/singleSlider/tv/inputoptions/ AND rename it to singleSlider.php
*/

$corePath = $modx->getOption('core_path',null,MODX_CORE_PATH);

$root = $corePath.'components/singleSlider/';

return $modx->smarty->fetch($root.'tv/inputoptions/tpl/singleSlider.tpl');
<!--
First part stolen from MODX number TV
Copy to: core/components/singleSlider/tv/input/tpl/ AND rename it to singleSlider.tpl
-->

<div class="singleSlider">
<style>
    .singleSlider {
        overflow: hidden;
    }
    .singleSlider input,
    .singleSlider div.sliderWidget {
        float: left;
    }
    .singleSlider div.sliderWidget {
        padding: 5px 10px;
    }
    
    .singleSlider input {
        text-align: center;
    }
    
    label {
        clear: both;
    }
</style>
<input id="tv{$tv->id}" name="tv{$tv->id}"
    type="text" class="textfield"
  value="{$tv->get('value')|escape}"
	{$style}
	tvtype="{$tv->type}"
    onchange="MODx.fireResourceFormChange();"
/>
<div id="slider_{$tv->id}" class="sliderWidget"></div>

<script type="text/javascript">
// <![CDATA[
{literal}
Ext.onReady(function() {
    var fld = MODx.load({
    {/literal}
         xtype: 'numberfield'
        ,id: 'number{$tv->id}'
        ,fieldClass: 'test'
        ,readOnly: true
        ,applyTo: 'tv{$tv->id}'
        ,width: '20px'
        ,enableKeyEvents: true
        ,autoStripChars: true
        ,allowBlank: {if $params.allowBlank == 1 || $params.allowBlank == 'true'}true{else}false{/if}
        ,allowDecimals: {if $params.allowDecimals && $params.allowDecimals != 'false'}true{else}false{/if}
        ,allowNegative: {if $params.allowNegative && $params.allowNegative != 'false'}true{else}false{/if}
        ,decimalPrecision: {if $params.decimalPrecision}{$params.decimalPrecision}{else}2{/if}
        ,decimalSeparator: {if $params.decimalSeparator}'{$params.decimalSeparator}'{else}'.'{/if}
        {if $params.maxValue},maxValue: {$params.maxValue}{/if}
        {if $params.minValue},minValue: {$params.minValue}{/if}
        ,msgTarget: 'under'
    {literal}
        ,listeners: { 'keydown': { fn:MODx.fireResourceFormChange, scope:this}}
    });
    {/literal}

    {literal}
    
    
    var slider = new Ext.Slider({
    {/literal}      
         xtype: 'sliderfield'
        ,renderTo: 'slider_{$tv->id}'
        {if $tv->get('value')} ,value: {$tv->get('value')}
        {else} ,value: 0 {/if}         
        ,width: 214
        {if $params.maxValue},maxValue: {$params.maxValue}
        {else} ,maxValue: 12 {/if}
        {if $params.minValue},minValue: {$params.minValue}
        {else} ,minValue: 0 {/if}
        ,increment: 1
        ,plugins: new Ext.slider.Tip()
    {literal}
        ,listeners: {
            change: function (slider, thumb, newValue, oldValue) {
    {/literal}                
                
                number{$tv->id} = Ext.getCmp('number{$tv->id}');
                
                test = slider.getValue();
                
                number{$tv->id}.setValue(test);
                
                MODx.fireResourceFormChange();
                
    {literal}
            }
        }
    {/literal}
    {literal}        
    });
    {/literal}    
    
    
    MODx.makeDroppable(fld);
    Ext.getCmp('modx-panel-resource').getForm().add(fld);
{literal}     
});
{/literal}
// ]]>
</script>
</div>
<?php
/*
Copy to: core/components/singleSlider/tv/input/ AND rename it to singleSlider.class.php
*/


if(!class_exists('singleSliderInputRender')) {
    class singleSliderInputRender extends modTemplateVarInputRender {
        public function getTemplate() {
            return $this->modx->getOption('core_path')
            .'components/singleSlider/tv/input/tpl/singleSlider.tpl';
        }
        // public function process($value,array $params = array()) {}
    }
}
return 'singleSliderInputRender';
A "slider with tip" like one shown here:

http://dev.sencha.com/deploy/ext-4.0.0/examples/slider/slider.html

Read: http://rtfm.modx.com/display/revolution20/Adding+a+Custom+TV+Type+-+MODX+2.2

-------------------------------------------------

What it CAN do: 

* Create a textfield followed by a slider.
* Changeing the value of the slider changes the value of the textfield.
* Slider position is updated at the beginning
* Changing the slider value will activate the save button

2do for the future:

* Add lexicon for multiple langiage support
* Add option for custom tip (label above the handle)
* Add option for custom increment
* Add optinal labels before and after the slider.

-------------------------------------------------

1. Create a namespace and set paths for the new tv:

Name: singleSLider
Core Path: {core_path}components/singleSlider/
Assets Path: {assets_path}components/singleSlider/

2. Add the singleSlider Plugin (see below) and activate the necessary events:
* OnTVInputRenderList
* OnTVOutputRenderList
* OnTVInputPropertiesList
* OnTVOutputRenderPropertiesList
* OnDocFormPrerender - For loading any custom JS/CSS for our TV (2do: find the best way to actually do that).

3. Add directories to core/components/singleSlider
* tv/input
* tv/input/tpl
* tv/inputoptions
* tv/inputoptions/tpl

* tv/output
* tv/properties

4. Add and rename input.class.php, input.tpl, inputoptions.php and inputoptijns.tpl your server.

5. Create a singleSlider TV and set a minimum and maximum value. Ignore the other optional fields for now. They will be used at a later point.