1. #1
    Sencha User Rodolfo's Avatar
    Join Date
    Feb 2008
    Posts
    15
    Vote Rating
    1
    Rodolfo is on a distinguished road

      0  

    Default trying a multitracker Slider

    trying a multitracker Slider


    Hi, this a simple copy of the Ext.Slider with the particularity that you can define n numbers of "trackers"...

    Im using this widget specificly for get and set alpha values of multiple layers in OpenLayers (Map Framework), but Im sure could be useful for some body else in a complete different context.

    example

    Code:
    var tracks = [
            {name: 'track_1', value: 100},
            {name: 'track_2', value: 50},
            {name: 'track_3', value: 60},
            {name: 'track_4', value: 10}
        ]
        
        /* tip plugin */
        var tip = new Ext.ux.SliderTip();
        
        var slider = new Ext.ux.Slider({
            renderTo: 'horizontal-slider',
            width: 400,
            increment: 10,
            minValue: 0,
            maxValue: 200,
            tracks: tracks,
            overlap: false,
            plugins: tip
        });

    http://github.com/warfares/Ext.ux.Slider

    TODO: get tracker focus
    TODO: move trackers with keys

    testing on: Safari 4.0, FireFox 3.5, Chrome 2.0, IE 8.0
    PD: take care with IE, the sample code use the console for testing events.


    Grettings.
    Rodolfo B.
    rbarriga.blogspot.com

    Ext.ux.Slider
    PHP Code:
    /**
    * multiple track slider
    *
    * @author Rodolfo Barriga S.
    * @class Ext.ux.Slider
    * @extends Ext.BoxComponent
    *
    */

    Ext.ux.Slider Ext.extend(Ext.BoxComponent, {

        
    /**
        * @cfg {Array} array with track object
        */
        
    tracks: [],
        
    /**
        * @cfg {Boolean} overlap prevent overlap of the sliders, Defaults to true
        */
        
    overlaptrue,
        
    /**
         * @cfg {Boolean} vertical Orient the Slider vertically rather than horizontally, defaults to false.
         */
        
    verticalfalse,
        
    /**
         * @cfg {Number} minValue The minimum value for the Slider. Defaults to 0.
         */
        
    minValue0,
        
    /**
         * @cfg {Number} maxValue The maximum value for the Slider. Defaults to 100.
         */
        
    maxValue100,
        
    /**
         * @cfg {Number/Boolean} decimalPrecision.
         * <p>The number of decimal places to which to round the Slider's value. Defaults to 0.</p>
         * <p>To disable rounding, configure as <tt><b>false</b></tt>.</p>
         */
        
    decimalPrecision0,
        
    /**
         * @cfg {Number} keyIncrement How many units to change the Slider when adjusting with keyboard navigation. Defaults to 1. If the increment config is larger, it will be used instead.
         */
        
    keyIncrement1,
        
    /**
         * @cfg {Number} increment How many units to change the slider when adjusting by drag and drop. Use this option to enable 'snapping'.
         */
        
    increment0,
        
    //private
        
    clickRange: [515],
        
    /**
         * @cfg {Boolean} clickToChange Determines whether or not clicking on the Slider axis will change the slider. Defaults to true
         */
        
    clickToChangetrue,
        
    /**
         * @cfg {Boolean} animate Turn on or off animation. Defaults to true
         */
        
    animatetrue,
        
    /**
         * True while the thumb is in a drag operation
         * @type boolean
         */
        
    draggingfalse,

        
    // private override
        
    initComponent: function() {

            
    Ext.ux.Slider.superclass.initComponent.call(this);
            
    this.keyIncrement Math.max(this.incrementthis.keyIncrement);

            
    this.addEvents(
                
    'beforechange',
                
    'change',
                
    'changecomplete',
                
    'dragstart',
                
    'drag',
                
    'dragend'
            
    );

            if (
    this.vertical) {
                
    Ext.apply(thisExt.ux.Slider.Vertical);
            }
        },

        
    // private override
        
    onRender: function() {
            
    this.autoEl = {
                
    cls'x-slider ' + (this.vertical 'x-slider-vert' 'x-slider-horz'),
                
    cn: {
                    
    cls'x-slider-end',
                    
    cn: { tag'div'cls'x-slider-inner' }
                }
            };

            
    Ext.ux.Slider.superclass.onRender.apply(thisarguments);

            
    this.endEl this.el.first();
            
    this.innerEl this.endEl.first();

            
    //default value 
            
    if (this.tracks.length === 0)
                
    this.tracks.push({name:'',value:this.minValue});
                
            
    this.length this.tracks.length;
            
            
    this.thumbs = [];
            for (var 
    0this.lengthi++) {
                var 
    thumb this.innerEl.createChild({ tag'div'cls'x-slider-thumb' });
                
    this.thumbs.push(thumb);
            };

            var 
    thumb this.thumbs[0];
            
    this.halfThumb = (this.vertical thumb.getHeight() : thumb.getWidth()) / 2;
            
    this.initEvents();
        },
        
    // private override
        
    initEvents: function() {
            
    this.mon(this.el, {
                
    scopethis,
                
    mousedownthis.onMouseDown,
                
    keydownthis.onKeyDown
            
    });

            for (var 
    0this.lengthi++) {
                var 
    thumb this.thumbs[i];
                
    thumb.addClassOnOver('x-slider-thumb-over');

                var 
    tracker = new Ext.dd.DragTracker({
                    
    onBeforeStartthis.onBeforeDragStart.createDelegate(this),
                    
    onStartthis.onDragStart.createDelegate(thisitrue),
                    
    onDragthis.onDrag.createDelegate(thisitrue),
                    
    onEndthis.onDragEnd.createDelegate(thisitrue),
                    
    tolerance3,
                    
    autoStart300
                
    });
                
    tracker.initEl(thumb);
            };
            
    //TODO destroy trackers
            //this.on('beforedestroy', this.thumbs.destroy, this.thumbs);
        
    },
        
    // private override
        
    onMouseDown: function(e) {
            if (
    this.disabled) { return; }
            for (var 
    0this.lengthi++) {
                var 
    thumb this.thumbs[i];
                if (
    e.target == thumb.dom)
                    return
            };
            if (
    this.clickToChange) {
                var 
    local this.innerEl.translatePoints(e.getXY());
                
    this.onClickChange(local);
            }
            
    this.focus();
        }
        ,
        
    // private
        
    onClickChange: function(local) {
            if (
    local.top this.clickRange[0] && local.top this.clickRange[1]) {
                var 
    Ext.util.Format.round(this.reverseValue(local.left), this.decimalPrecision);
                
    this.setValue(this.getIndexByMinDist(v), vundefinedtrue);
            }
        },
        
    //private
        
    getIndexByMinDist: function(v) {
            var 
    dist Math.abs(this.tracks[0].value v);
            var 
    index 0;

            for (var 
    1this.lengthi++) {
                var 
    tr this.tracks[i];
                if (
    dist Math.abs(tr.value v)) {
                    var 
    dist Math.abs(tr.value v);
                    
    index i;
                }
            };
            return 
    index;
        },
        
    //private   
        
    getIndexArraySortByValue: function() {
            var 
    indexs = [];
            for (var 
    0this.lengthi++) {
                var 
    tr this.tracks[i];
                
    indexs.push({ indexivaluetr.value });
            };

            var 
    fc = function(ab) { return a.value b.value; }
            return 
    indexs.sort(fc);
        },
        
    //private    
        
    getIndexNeighborhood: function(index) {
            var 
    indexs this.getIndexArraySortByValue();
                    
            if (
    this.length 1) {
                var 
    max this.length 1;

                if (
    indexs[0].index === index) {
                    var 
    tIndex indexs[1].index;
                    return { 
    dIndexnulltIndex:tIndex};
                }

                if (
    indexs[max].index === index) {
                    var 
    dIndex indexs[(max 1)].index;
                    return { 
    dIndex:dIndextIndexnull };
                }

                for (var 
    1maxi++) {
                    if (
    indexs[i].index === index) {
                        var 
    dIndex indexs[1].index;
                        var 
    tIndex indexs[1].index;
                        return { 
    dIndex:dIndextIndex:tIndex};                
                    }                
                };
            };
        },
        
    //private
        
    checkOverlap: function(indexv) {
            var 
    nb this.getIndexNeighborhood(index);
            var 
    tValue nb.tIndex !== null this.getValue(nb.tIndex) : this.maxValue 1;
            var 
    dValue nb.dIndex !== null this.getValue(nb.dIndex) : this.minValue 1;
            if (
    dValue >= || >= tValue)
                return 
    false;
                
            return 
    true;
        }
        ,
        
    // private //TODO
        
    onKeyDown: function(e) {
            if (
    this.disabled) { e.preventDefault(); return; }
            var 
    e.getKey();
            switch (
    k) {
                case 
    e.UP:
                case 
    e.RIGHT:
                    break;
                case 
    e.DOWN:
                case 
    e.LEFT:
                    break;
                default:
                    
    e.preventDefault();
            }
        },
        
    // private
        
    doSnap: function(value) {
            if (!
    this.increment || this.increment == || !value) {
                return 
    value;
            }
            var 
    newValue valueinc this.increment;
            var 
    value inc;
            if (
    != 0) {
                
    newValue -= m;
                if (
    inc) {
                    
    newValue += inc;
                } else if (
    < -inc) {
                    
    newValue -= inc;
                }
            }
            return 
    newValue.constrain(this.minValuethis.maxValue);
        },
        
    // private override
        
    afterRender: function() {
            
    Ext.ux.Slider.superclass.afterRender.apply(thisarguments);
            for (var 
    0this.lengthi++) {
                var 
    tr this.tracks[i];
                var 
    value tr.value;
                if (
    value !== undefined) {
                    var 
    this.normalizeValue(value);
                    if (
    !== value) {
                        
    this.setValue(ivfalse);
                    } else {
                        
    this.moveThumb(ithis.translateValue(v), false);
                    }
                }
            }
        },
        
    // private
        
    getRatio: function() {
            var 
    this.innerEl.getWidth();
            var 
    this.maxValue this.minValue;
            return 
    == : (v);
        },

        
    // private
        
    normalizeValue: function(v) {
            
    this.doSnap(v);
            
    Ext.util.Format.round(vthis.decimalPrecision);
            
    v.constrain(this.minValuethis.maxValue);
            return 
    v;
        },

        
    setValue: function(indexvanimatechangeComplete) {
            
    this.normalizeValue(v);

            if (
    this.length && !this.overlap && !this.checkOverlap(indexv))
                return;

            var 
    tr this.tracks[index];
            if (
    !== tr.value && this.fireEvent('beforechange'thisindex) !== false) {
                
    tr.value v;
                
    this.moveThumb(indexthis.translateValue(v), animate !== false);
                
    this.fireEvent('change'thisindex);
                if (
    changeComplete) {
                    
    this.fireEvent('changecomplete'thisindex);
                }
            }
        },
        
    // private
        
    translateValue: function(v) {
            var 
    ratio this.getRatio();
            return (
    ratio) - (this.minValue ratio) - this.halfThumb;
        },
        
    // private
        
    reverseValue: function(pos) {
            var 
    ratio this.getRatio();
            return (
    pos this.halfThumb + (this.minValue ratio)) / ratio;
        },

        
    // private
        
    moveThumb: function(indexvanimate) {
            var 
    thumb this.thumbs[index];
            if (!
    animate || this.animate === false) {
                
    thumb.setLeft(v);
            } else {
                
    thumb.shift({ leftvstopFxtrueduration.35 });
            }
        },
        
    // private //TODO
        
    focus: function() {
            
    //this.focusEl.focus(10);
        
    },
        
    // private
        
    onBeforeDragStart: function(e) {
            return !
    this.disabled;
        },
        
    // private
        
    onDragStart: function(ei) {
            var 
    tr this.tracks[i];
            var 
    thumb this.thumbs[i];
            
    thumb.addClass('x-slider-thumb-drag');
            
    this.dragging true;
            
    this.dragStartValue tr.value;
            
    this.fireEvent('dragstart'thisei);
        },

        
    // private
        
    onDrag: function(ei) {
            var 
    pos this.innerEl.translatePoints(e.getXY());
            
    this.setValue(iExt.util.Format.round(this.reverseValue(pos.left), this.decimalPrecision), false);
            
    this.fireEvent('drag'thisei);
        },

        
    // private
        
    onDragEnd: function(ei) {
            var 
    tr this.tracks[i];
            var 
    thumb this.thumbs[i];
            
    thumb.removeClass('x-slider-thumb-drag');

            
    this.dragging false;
            
    this.fireEvent('dragend'thisei);
            if (
    this.dragStartValue != tr.value) {
                
    this.fireEvent('changecomplete'thisi);
            }
        },

        
    onResize: function(wh) {
            
    this.innerEl.setWidth(- (this.el.getPadding('l') + this.endEl.getPadding('r')));
            
    this.syncThumb();
        },

        
    //private
        
    onDisable: function() {
            
    Ext.ux.Slider.superclass.onDisable.call(this);
            for (var 
    0this.lengthi++) {
                var 
    thumb this.thumbs[i];
                
    thumb.addClass(this.disabledClass);

                if (
    Ext.isIE) {
                    
    //IE breaks when using overflow visible and opacity other than 1.
                    //Create a place holder for the thumb and display it.
                    
    var xy thumb.getXY();
                    
    thumb.hide();
                    
    this.innerEl.addClass(this.disabledClass).dom.disabled true;
                    if (!
    this.thumbHolder) {
                        
    this.thumbHolder this.endEl.createChild({ cls'x-slider-thumb ' this.disabledClass });
                    }
                    
    this.thumbHolder.show().setXY(xy);
                }
            }
        },
        
    //private
        
    onEnable: function() {
            
    Ext.Slider.superclass.onEnable.call(this);
            for (var 
    0this.lengthi++) {
                var 
    thumb this.thumbs[i];
                
    thumb.removeClass(this.disabledClass);
                if (
    Ext.isIE) {
                    
    this.innerEl.removeClass(this.disabledClass).dom.disabled false;
                    if (
    this.thumbHolder) {
                        
    this.thumbHolder.hide();
                    }
                    
    thumb.show();
                    
    this.syncThumb();
                }
            }
        },
        
    syncThumb: function() {
            if (
    this.rendered) {
                for (var 
    0this.lengthi++) {
                    var 
    tr this.tracks[i];
                    
    this.moveThumb(ithis.translateValue(tr.value), true);
                }
            }
        },
        
    getValue: function(i) {       
            var 
    tr this.tracks[i];
            return 
    tr.value;

        },    
        
    getName: function(i) {
            var 
    tr this.tracks[i];
            return 
    tr.name;
        },
        
    getTrack: function(i) {    
            return 
    this.tracks[i];
        }
    });
    Ext.reg('ux.silder'Ext.ux.Slider);


    // private class to support vertical sliders
    Ext.ux.Slider.Vertical = {
        
    onResize: function(wh) {
            
    this.innerEl.setHeight(- (this.el.getPadding('t') + this.endEl.getPadding('b')));
            
    this.syncThumb();
        },
        
    getRatio: function() {
            var 
    this.innerEl.getHeight();
            var 
    this.maxValue this.minValue;
            return 
    v;
        },
        
    moveThumb: function(indexvanimate) {
            var 
    thumb this.thumbs[index];
            if (!
    animate || this.animate === false) {
                
    thumb.setBottom(v);
            } else {
                
    thumb.shift({ bottomvstopFxtrueduration.35 });
            }
        },
        
    onDrag: function(e,index) {        
            var 
    pos this.innerEl.translatePoints(e.getXY());            
            var 
    bottom this.innerEl.getHeight() - pos.top;
            
    this.setValue(indexthis.minValue Ext.util.Format.round(bottom this.getRatio(), this.decimalPrecision), false);
            
    this.fireEvent('drag'thise,index);            
        },    
        
    onClickChange: function(local) {
            if (
    local.left this.clickRange[0] && local.left this.clickRange[1]) {
                var 
    bottom this.innerEl.getHeight() - local.top;
                var 
    this.minValue Math.round(bottom this.getRatio());            
                
    this.setValue(this.getIndexByMinDist(v), vundefinedtrue);
            }
        }                
    }; 

    Ext.ux.SliderTip
    PHP Code:
    /**
     * Ext.ux.SliderTip Plugin for tips
     * @author Rodolfo Barriga
     * @class Ext.ux.SliderTip
     * @extends Ext.Tip
     *
     */
        
    Ext.ux.SliderTip Ext.extend(Ext.Tip, {
        
    minWidth10,
        
    offsets: [0, -10],
        
    init: function(slider) {
            
    slider.on('dragstart'this.onSlidethis);
            
    slider.on('drag'this.onSlidethis);
            
    slider.on('dragend'this.hidethis);
            
    slider.on('destroy'this.destroythis);
        },
        
    onSlide: function(sliderei) {
            
    this.show();
            
    this.body.update(this.getText(slideri));
            
    this.doAutoWidth();
            
            var 
    thumb slider.thumbs[i];
            
    this.el.alignTo(thumb'b-t?'this.offsets);
        },
        
    getText: function(slideri) {        
            return 
    slider.getValue(i) + '';
        }
    }); 

    Sample code
    HTML Code:
    <html>
    <head>
    	<title>Sample</title>
    	<!-- ExtJS Style -->
        <link rel="stylesheet" type="text/css" href="ext-3.0.0/resources/css/ext-all.css"/>        
        
        <!-- ExtJS 3.0.0 -->  
    	<script type="text/javascript" src="ext-3.0.0/adapter/ext/ext-base.js" ></script>  
    	 
        <!-- ExtJS 3.0.0 Build -->  
    	<script type="text/javascript" src="ext-3.0.0/ext-all.js" ></script> 
    	
    	<!-- Slider -->          
        <script type="text/javascript" src="Ext.ux.Slider.js" ></script>
        <script type="text/javascript" src="Ext.ux.SliderTip.js" ></script>
        
        <!-- Custom Slider Style -->    
        <link href="ext-3.0.0/examples/slider/slider.css" rel="stylesheet" type="text/css" />
        
        <!-- Common Styles for the examples -->    
        <link href="ext-3.0.0/examples/shared/examples.css" rel="stylesheet" type="text/css" />        
    </head>
    
    <body>
    
    <script>
    
    Ext.BLANK_IMAGE_URL = 'ext-3.0.0/resources/images/default/s.gif';
    
    // application main entry point
    Ext.onReady(function() {
        Ext.QuickTips.init();
    
        /* horizontal demo */
        var tracks = [
            {name: 'track_1', value: 100},
            {name: 'track_2', value: 50},
            {name: 'track_3', value: 60},
            {name: 'track_4', value: 10}
        ]
        
        /* tip plugin */
        var tip = new Ext.ux.SliderTip();
        
        var slider = new Ext.ux.Slider({
            renderTo: 'horizontal-slider',
            width: 400,
            increment: 10,
            minValue: 0,
            maxValue: 200,
            tracks: tracks,
            overlap: false,
            plugins: tip
        });
    
        slider.on('change', function(s, i) { console.log('changed[' + slider.getName(i) + ']: ' + slider.getValue(i)); });
    
    
        /* vertical demo */    
        var tracks_1 = [
            { name: 'track_1', value: 0},
            { name: 'track_2', value: 100},
            { name: 'track_3', value: 200}
        ]
    
        /* custom tip plugin*/
        var tip_1 = new Ext.ux.SliderTip({
            getText: function(slider, i) {
                return String.format('<b>{1} <br/> value : {0}</b>', slider.getValue(i), slider.getName(i));
            }
        });
            
        var sliderVertical = new Ext.ux.Slider({
            renderTo: 'vertical-slider',
            vertical: true,
            increment: 10,
            minValue: 0,
            maxValue: 200,
            height: 200,
            tracks: tracks_1,
            plugins: tip_1
        });
    
        sliderVertical.on('change', function(slider, i) { console.log('changed[' + slider.getName(i) + ']: ' + slider.getValue(i)); });
        
        /* custom style demo */
        var tracks_2 = [
            { name: 'A', value: 10},
            { name: 'B', value: 90}
        ]
    
        var sliderCustomCss = new Ext.ux.Slider({
            renderTo: 'custom-slider',
            width: 214,
            increment: 10,
            minValue: 0,
            maxValue: 100,
            tracks: tracks_2, 
            overlap:false
        });
                                                             
    }); 
    // eo function onReady
    </script>
    
    <h1>Ext ux Slider Example</h1>
    <p>Sliders support multiple trackers</p>
    
    <h3>Horizontal Slider</h3>
    <div id="horizontal-slider"></div>
    <br/>
    
    <h3>Vertical Slider</h3>
    <div id="vertical-slider"></div>
    <br/>
    
    <h3>CSS Customized Slider</h3>
    <div id="custom-slider"></div>       
    </html>
    Attached Images
    Attached Files
    Last edited by Rodolfo; 14 Feb 2010 at 6:37 AM. Reason: GitHub reference

  2. #2
    Sencha - Ext JS Dev Team Animal's Avatar
    Join Date
    Mar 2007
    Location
    Notts/Redwood City
    Posts
    30,483
    Vote Rating
    35
    Animal has a spectacular aura about Animal has a spectacular aura about

      0  

    Default


    Nice work.

    I think that this should be integrated into the main Ext Slider. A bit like the outstanding Feature Request suggestion for TriggerField to be able to have any number of Triggers, but defaulting to 1.

    Ext.Slider should be able to handle multiple trackers.

  3. #3
    Sencha User Rodolfo's Avatar
    Join Date
    Feb 2008
    Posts
    15
    Vote Rating
    1
    Rodolfo is on a distinguished road

      0  

    Default


    Thanks

    - update: added overlap property: for prevent overlap of the trackers. (default : true).

  4. #4
    Sencha User steffenk's Avatar
    Join Date
    Jul 2007
    Location
    Haan, Germany
    Posts
    2,649
    Vote Rating
    6
    steffenk has a spectacular aura about steffenk has a spectacular aura about steffenk has a spectacular aura about

      0  

    Default


    Nice extension! Really useful for coloring things.
    vg Steffen
    --------------------------------------
    Release Manager of TYPO3 4.5

  5. #5
    Ext User
    Join Date
    Aug 2009
    Posts
    13
    Vote Rating
    0
    hankin is on a distinguished road

      0  

    Default 2 way slider

    2 way slider


    I think I may have found a potential defect. It could also be my code. Is anybody else experiencing this functionality. I am testing in IE 7 and I am seeing both track points on top of each other no matter what values I put in. Any help would be greatly appreciated.

    var tracks = [
    {name: 'track_1', value: 10},
    {name: 'track_2', value: 100}
    ]

    /* tip plugin */
    var tip = new Ext.ux.SliderTip();

    var slider = new Ext.ux.Slider({
    renderTo: 'custom-slider',
    width: 400,
    increment: 10,
    minValue: 0,
    maxValue: 200,
    tracks: tracks,
    overlap: false,
    plugins: tip
    });

  6. #6
    Sencha User aw1zard2's Avatar
    Join Date
    Sep 2009
    Location
    Dallas, Texas
    Posts
    561
    Vote Rating
    28
    aw1zard2 has a spectacular aura about aw1zard2 has a spectacular aura about

      0  

    Default


    Quote Originally Posted by hankin View Post
    I think I may have found a potential defect. It could also be my code. Is anybody else experiencing this functionality. I am testing in IE 7 and I am seeing both track points on top of each other no matter what values I put in. Any help would be greatly appreciated.
    Code:
    var tracks = [
            {name: 'track_1', value: 10},
            {name: 'track_2', value: 100}
        ]
        
        /* tip plugin */
        var tip = new Ext.ux.SliderTip();
        
        var slider = new Ext.ux.Slider({
            renderTo: 'custom-slider',
            width: 400,
            increment: 10,
            minValue: 0,
            maxValue: 200,
            tracks: tracks,
            overlap: false,
            plugins: tip
        });
    Are you using the sample code above or just the Example code. Cause the sample code with the EXTJS includes does a lot more then just the example code. If you are using the sample code you need to paste a bit more then just that little code piece. Since the custom-slider uses the css file. And to be helpful use the CODE tags around code.


  7. #7
    Ext User
    Join Date
    Aug 2009
    Posts
    13
    Vote Rating
    0
    hankin is on a distinguished road

      0  

    Default My Bad :(

    My Bad :(


    Sorry, I had a mis-linked path that was causing my issues. The code worked fine once i got it linked properly.

  8. #8
    Ext User
    Join Date
    Sep 2009
    Posts
    18
    Vote Rating
    0
    t800t8 is on a distinguished road

      0  

    Default


    Very nice plugin. I'm looking for it. Thanks :-)

  9. #9
    Ext User
    Join Date
    Aug 2009
    Posts
    2
    Vote Rating
    0
    NikNik77771 is on a distinguished road

      0  

    Default


    Very useful plugin. I am looking for same in ext-gwt? Does somebody know this stuff?

film izle

hd film izle

film sitesi

takipci kazanma sitesi

takipci kazanma sitesi

güzel olan herşey

takipci alma sitesi

komik eğlenceli videolar