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.