Committer: dpetrov
LJSUP-9126: Friends times. Hiding users, filtersA trunk/htdocs/js/jquery/jquery.lj.basicWidget.js A trunk/htdocs/js/jquery/jquery.lj.sidePane.js
Added: trunk/htdocs/js/jquery/jquery.lj.basicWidget.js =================================================================== --- trunk/htdocs/js/jquery/jquery.lj.basicWidget.js (rev 0) +++ trunk/htdocs/js/jquery/jquery.lj.basicWidget.js 2011-08-02 10:33:11 UTC (rev 10789) @@ -0,0 +1,118 @@ +/*! + * LiveJournal basic widget + * + * Copyright 2011, dmitry.petrov@sup.com + * + * http://docs.jquery.com/UI + * + * + * @overview Base widget for all livejournal widgets. + * + * Basic widget adds pub/sub system to the widget hierarchy. By convention widgets add prefix equal + * to the widget name of the most parent element who fires it. E.g. if someWidget and subSomeWidget + * that extends someWidget do fire open event, it should be prefixed with someWidget - someWidget/open + */ +( function( $ ) { + + var __callbacks = {}, + + //these events we set once and for all widget instances + globalEvents = { + documentClick: false + } + + $.widget( 'lj.basicWidget', { + + /** + * Bind common events for the widget + */ + _bindControls: function() { + var widget = this; + + /** + * documentClick + */ + if( !globalEvents.documentClick ) { + $( document ).click( function( ev ) { + widget._fire( 'documentClick', [], true ); + } ); + + globalEvents.documentClick = true; + } + }, + + /** + * Subscribe to the event with the callback. + * + * @param {String} type Event type. + * @param {Function} callback Function that should be fired on the event. + */ + _on: function( type, callback ) { + if( !( type in __callbacks ) ) { + __callbacks[ type ] = []; + } + + __callbacks[ type ].push( { + fn: callback, + owner: this + } ); + }, + + /** + * Remove subscription on the event. + * + * @param {String} type Event type. + * @param {Function=} callback Callback function. If parameter is omitted, function will remove all + * callbacks of this instance from the subscription on this type of event. + */ + _off: function( type, callback ) { + if( !( type in __callbacks ) ) { return; } + + var cbs = __callbacks[ type ]; + for( var i = 0; i < cbs.length; ++i ) { + if( ( callback && cbs[ i ].fn === callback ) || ( cbs[i].owner === this ) ) { + cbs.splice( i, 1 ); + } + } + }, + + /** + * Dispatch event. + * + * @param {String} type Event type. + * @param {Array=[]} args array with arguments that will be passed to the callback functions. + * @param {Boolean=False} includeOwner If false the message is not recieved by + * the object that dispatched it. + */ + _fire: function( type, args, includeOwner ) { + args = args || []; + includeOwner = includeOwner || false; + if( type in __callbacks ) { + var cbs = __callbacks[ type ], + i = -1; + + while( cbs[ ++i ] ) { + if( !includeOwner && cbs[ i ].owner === this ) { continue; } + cbs[ i ].fn.apply( null, args ); + } + } + }, + + /** + * Remove all subscriptions on widget distruction. If overriden, this method should be + * also caled. + */ + _destroy: function() { + var cbs; + for( var type in __callbacks ) { + cbs = __callbacks[ type ]; + for( var i = 0; i < cbs.length; ++i ) { + if( cbs[i].owner === this ) { + cbs.splice( i, 1 ) + } + } + } + } + + } ); +} )( jQuery ); Added: trunk/htdocs/js/jquery/jquery.lj.sidePane.js =================================================================== --- trunk/htdocs/js/jquery/jquery.lj.sidePane.js (rev 0) +++ trunk/htdocs/js/jquery/jquery.lj.sidePane.js 2011-08-02 10:33:11 UTC (rev 10789) @@ -0,0 +1,162 @@ +(function( $ ) { + + var transitionsSupported = function() { + var div = document.createElement('div'); + + div.setAttribute('style', 'transition:top 1s ease;-webkit-transition:top 1s ease;-moz-transition:top 1s ease;'); + cssTransitionsSupported = !!(div.style.transition || div.style.webkitTransition || div.style.MozTransition || div.style.OTransitionDuration ); + delete div; + + return cssTransitionsSupported; + }(); + + var panes = jQuery(); + + $.widget( 'lj.sidePane', $.lj.basicWidget, { + options: { + selectors: { + inner: '.w-friendstimes-inner', + toggle: '.b-friendstimes-hidden-comments-icon' + }, + classNames: { + open: 'w-friendstimes-opened' + }, + visibility: 'visible', + state: 'closed' + }, + + _create: function() { + $.lj.basicWidget.prototype._create.call( this ); + this._inner = this.element.find( this.options.selectors.inner ); + this._setOptions( this.options ); + this._preventClose = false; + + this._bindControls(); + + var widget = this; + this._on( 'sidePane/close', function() { widget.close() } ); + this._on( 'documentClick', function() { + if( widget._preventClose ) { + widget._preventClose = false; + return; + } + + widget.close() + } ); + }, + + _bindControls: function() { + $.lj.basicWidget.prototype._bindControls.apply( this ); + + var self = this, + options = this.options; + + this.element.find( this.options.selectors.toggle ).click( function( ev ) { + if( options.state === 'closed' ) { + self.open(); + } else { + self.close(); + } + + ev.preventDefault(); + ev.stopPropagation(); + } ); + + this.element.click( function( ev ) { + self._preventClose = true; + } ); + }, + + _setOption: function( name, val ) { + switch( name ) { + case 'visibility': + if( val === 'hidden' ) { + this.hide(); + } else if( val === 'visible' ) { + this.show(); + } else { + return; + } + break; + + case 'state': + if( val === 'closed' ) { + this.close(); + } else if( val === 'open' ) { + this.open(); + } else { + return; + } + break; + + default: return; + } + }, + + show: function() { + this.element.show(); + this.options.visibility = 'visible'; + }, + + hide: function() { + this.element.hide(); + this.options.visibility = 'hidden'; + }, + + open: function() { + var widget = this; + this.show(); + if( transitionsSupported ) { + this.element.addClass( this.options.classNames.open ); + } else { + this.element.css( { + overflow: 'visible', + zoom: 1, + zIndex: 10 + } ); + this._inner.animate( { + left: "1%", + marginLeft: "0px" + }, { + duration: 300, + queue: true, + complete: function() { + widget.element + .addClass( widget.options.classNames.open ); + + widget.element.removeAttr( 'style' ); + } + } ); + } + this.options.state = 'open'; + + this._fire( 'sidePane/close' ); + }, + + close: function() { + var widget = this; + + if( !this.element.hasClass( this.options.classNames.open ) ) { + return; + } + + if( transitionsSupported ) { + this.element.removeClass( this.options.classNames.open ); + } else { + this._inner.animate( { + left: "100%", + marginLeft: "-47px" + }, { + duration: 300, + complete: function() { + widget.element + .removeClass( widget.options.classNames.open ); + + widget.element.removeAttr( 'style' ); + } + } ); + } + this.options.state = 'closed'; + } + } ); +} )( jQuery );