<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Responsive presentation and behavior for HTML data panels
//>>label: Panel
//>>group: Widgets
//>>css.structure: ../css/structure/jquery.mobile.panel.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "../jquery.mobile.widget", "./page", "./page.sections" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.panel", $.mobile.widget, {
	options: {
		classes: {
			panel: "ui-panel",
			panelOpen: "ui-panel-open",
			panelClosed: "ui-panel-closed",
			modal: "ui-panel-dismiss",
			modalOpen: "ui-panel-dismiss-open",
			openComplete: "ui-panel-open-complete",
			contentWrap: "ui-panel-content-wrap",
			contentWrapOpen: "ui-panel-content-wrap-open",
			contentWrapClosed: "ui-panel-content-wrap-closed",
			panelUnfixed: "ui-panel-unfixed",
			contentWrapOpenComplete: "ui-panel-content-wrap-open-complete",
			pageBlock: "ui-panel-page-block",
			pagePanel: "ui-page-panel",
			pageChildAnimations: "ui-page-panel-animate"
		},
		animate: true,
		theme: null,
		position: "left",
		dismissible: true,
		display: "overlay", //accepts reveal, push, overlay
		initSelector: ":jqmData(role='panel')"
	},

	_panelID: null,
	_closeLink: null,
	_page: null,
	_modal: null,
	_wrapper: null,

	_create: function() {
		var self = this,
			$el = self.element,
			_getWrapper = function(){
				var $wrapper = self._page.find( "." + self.options.classes.contentWrap );
				if( $wrapper.length === 0 ){
					$wrapper = self._page.find( ".ui-header, .ui-content, .ui-footer" ).wrapAll( '
' ).parent();
				}
				return $wrapper;
			};

		// expose some private props to other methods
		self._panelID = $el.attr( "id" );
		self._closeLink = $el.find( ":jqmData(rel='close')" );
		self._page = $el.closest( ":jqmData(role='page')" );
		self._wrapper = _getWrapper();
		self._addPanelClasses();
		self._wrapper.addClass( this.options.classes.contentWrapClosed );

		// if animating, add the class to do so
		if ( $.support.cssTransitions && self.options.animate ) {
			this.element.add( self._wrapper ).addClass( "ui-panel-animate" );
			self._page.addClass( this.options.classes.pageChildAnimations );
		}

		self._bindCloseEvents();
		self._bindLinkListeners();
		self._bindPageEvents();

		if( self.options.dismissible ){
			self._createModal();
		}

	},

	_createModal: function( options ){
		var self = this;
		self._modal = $( "

" )
			.on( "mousedown" , function(){
				self.close();
			})
			.appendTo( this._page );
	},

	_getPosDisplayClasses: function( prefix ){
		return prefix + "-position-" + this.options.position + " " + prefix + "-display-" + this.options.display;
	},

	_addPanelClasses: function(){
		var panelClasses = this.options.classes.panel +
						" " + this._getPosDisplayClasses( this.options.classes.panel ) +
						" " + this.options.classes.panelClosed;

		if( this.options.theme ){
			panelClasses += " ui-body-" + this.options.theme;
		}

		if( $.support.cssTransform3d ){
			panelClasses += " ui-panel-3dtransforms";
		}

		this.element.addClass( panelClasses );
	},

	_bindCloseEvents: function(){
		var self = this;
		self._closeLink.on( "click" , function( e ){
			e.preventDefault();
			self.close();
			return false;
		});
	},

	_positionPanel: function(){
		if( this.element.height() > $.mobile.getScreenHeight() ){
			this._unfixPanel();
			this._scrollIntoView();
		}
		else {
			this._fixPanel();
		}
	},

	_scrollIntoView: function(){
		if( $(window).scrollTop() > $.mobile.getScreenHeight() ){
			window.scrollTo( 0, 0);
		}
	},

	_bindFixListener: function(){
		var self = this;
		$( window ).on( "throttledresize.panel", function(){
			self._positionPanel();
		} );
	},

	_unbindFixListener: function(){
		$( window ).off( "throttledresize.panel" );
	},

	_unfixPanel: function(){
		this.element.addClass( this.options.classes.panelUnfixed );
	},

	_fixPanel: function(){
		this.element.removeClass( this.options.classes.panelUnfixed );
	},

	_bindLinkListeners: function(){
		var self = this;

		this._page.on( "click" , "a", function( e ) {
			if( this.href.split( "#" )[ 1 ] === self._panelID ){
				e.preventDefault();
				var $link = $( this );
				$link.addClass( $.mobile.activeBtnClass );
				self.element.one( "panelopen panelclose", function(){
					$link.removeClass( $.mobile.activeBtnClass );
				});
				self.toggle();
				return false;
			}
		});
	},

	_bindPageEvents: function(){
		var self = this;

		self.element
			// on swipe, close the panel (should swipe open too?)
			.on( "swipe" , function( e ){
				self.close( true );
			});

		self._page
			// Close immediately if another panel on the page opens
			.on( "panelbeforeopen", function( e ){
				if( self._open && e.target !== self.element[ 0 ] ){
					self.close( true );
				}
			})
			// clean up open panels after page hide
			.on(  "pagebeforehide", function( e ) {
				if( self._open ){
					self.close( true );
				}
			})
			// on escape, close? might need to have a target check too...
			.on( "keyup", function( e ) {
				if( e.keyCode === 27 && self._open ){
					self.close( true );
				}
			});
	},

	// state storage of open or closed
	_open: false,

	_contentWrapOpenClasses: null,
	_modalOpenClasses: null,

	open: function( options ){
		var self = this,
			o = self.options,
			complete = function(){
				self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
				self.element.addClass( o.classes.openComplete );
				self._wrapper.addClass( o.classes.contentWrapOpenComplete );
				self._positionPanel();
				self._bindFixListener();
				self._trigger( "open" );
			};

		self._trigger( "beforeopen" );

		if ( $.support.cssTransitions && o.animate ) {
			self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
		} else{
			setTimeout( complete , 0 );
		}
		self._page.addClass( self.options.classes.pageBlock );
		self.element.removeClass( o.classes.panelClosed );
		self.element.addClass( o.classes.panelOpen );
		self._contentWrapOpenClasses = self._getPosDisplayClasses( o.classes.contentWrap );
		self._wrapper.removeClass( o.classes.contentWrapClosed );
		self._wrapper.addClass( self._contentWrapOpenClasses + " " + o.classes.contentWrapOpen );
		self._modalOpenClasses = self._getPosDisplayClasses( o.classes.modal ) + " " + o.classes.modalOpen;
		self._modal.addClass( self._modalOpenClasses );

		self._open = true;

	},

	close: function( immediate ){
		var o = this.options,
			self = this,
			complete = function(){
				self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
				self.element.addClass( o.classes.panelClosed );
				self._wrapper.removeClass( self._contentWrapOpenClasses );
				self._wrapper.addClass( o.classes.contentWrapClosed );
				self._page.removeClass( self.options.classes.pageBlock );
				self._fixPanel();
				self._unbindFixListener();
				self._trigger( "close" );
			};

		self._trigger( "beforeclose" );

		if ( $.support.cssTransitions && o.animate ) {
			self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
		} else{
			setTimeout( complete , 0 );
		}

		self.element.removeClass( o.classes.panelOpen + " " + o.classes.openComplete );
		self._modal.removeClass( self._modalOpenClasses );
		self._wrapper.removeClass( o.classes.contentWrapOpen + " " + o.classes.contentWrapOpenComplete );

		self._open = false;
	},

	toggle: function( options ){
		this[ this._open ? "close" : "open" ]();
	},

	_transitionEndEvents: "webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",

	destroy: function(){
		// unbind events, remove generated elements, remove classes, remove data
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ) {
	$.mobile.panel.prototype.enhanceWithin( e.target );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");

<commit_msg>qualify transitions to 3d support<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Responsive presentation and behavior for HTML data panels
//>>label: Panel
//>>group: Widgets
//>>css.structure: ../css/structure/jquery.mobile.panel.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "../jquery.mobile.widget", "./page", "./page.sections" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.panel", $.mobile.widget, {
	options: {
		classes: {
			panel: "ui-panel",
			panelOpen: "ui-panel-open",
			panelClosed: "ui-panel-closed",
			modal: "ui-panel-dismiss",
			modalOpen: "ui-panel-dismiss-open",
			openComplete: "ui-panel-open-complete",
			contentWrap: "ui-panel-content-wrap",
			contentWrapOpen: "ui-panel-content-wrap-open",
			contentWrapClosed: "ui-panel-content-wrap-closed",
			panelUnfixed: "ui-panel-unfixed",
			contentWrapOpenComplete: "ui-panel-content-wrap-open-complete",
			pageBlock: "ui-panel-page-block",
			pagePanel: "ui-page-panel",
			pageChildAnimations: "ui-page-panel-animate"
		},
		animate: true,
		theme: null,
		position: "left",
		dismissible: true,
		display: "overlay", //accepts reveal, push, overlay
		initSelector: ":jqmData(role='panel')"
	},

	_panelID: null,
	_closeLink: null,
	_page: null,
	_modal: null,
	_wrapper: null,

	_create: function() {
		var self = this,
			$el = self.element,
			_getWrapper = function(){
				var $wrapper = self._page.find( "." + self.options.classes.contentWrap );
				if( $wrapper.length === 0 ){
					$wrapper = self._page.find( ".ui-header, .ui-content, .ui-footer" ).wrapAll( '
' ).parent();
				}
				return $wrapper;
			};

		// expose some private props to other methods
		self._panelID = $el.attr( "id" );
		self._closeLink = $el.find( ":jqmData(rel='close')" );
		self._page = $el.closest( ":jqmData(role='page')" );
		self._wrapper = _getWrapper();
		self._addPanelClasses();
		self._wrapper.addClass( this.options.classes.contentWrapClosed );

		// if animating, add the class to do so
		if ( $.support.cssTransform3d && self.options.animate ) {
			this.element.add( self._wrapper ).addClass( "ui-panel-animate" );
			self._page.addClass( this.options.classes.pageChildAnimations );
		}

		self._bindCloseEvents();
		self._bindLinkListeners();
		self._bindPageEvents();

		if( self.options.dismissible ){
			self._createModal();
		}

	},

	_createModal: function( options ){
		var self = this;
		self._modal = $( "

" )
			.on( "mousedown" , function(){
				self.close();
			})
			.appendTo( this._page );
	},

	_getPosDisplayClasses: function( prefix ){
		return prefix + "-position-" + this.options.position + " " + prefix + "-display-" + this.options.display;
	},

	_addPanelClasses: function(){
		var panelClasses = this.options.classes.panel +
						" " + this._getPosDisplayClasses( this.options.classes.panel ) +
						" " + this.options.classes.panelClosed;

		if( this.options.theme ){
			panelClasses += " ui-body-" + this.options.theme;
		}

		if( $.support.cssTransform3d ){
			panelClasses += " ui-panel-3dtransforms";
		}

		this.element.addClass( panelClasses );
	},

	_bindCloseEvents: function(){
		var self = this;
		self._closeLink.on( "click" , function( e ){
			e.preventDefault();
			self.close();
			return false;
		});
	},

	_positionPanel: function(){
		if( this.element.height() > $.mobile.getScreenHeight() ){
			this._unfixPanel();
			this._scrollIntoView();
		}
		else {
			this._fixPanel();
		}
	},

	_scrollIntoView: function(){
		if( $(window).scrollTop() > $.mobile.getScreenHeight() ){
			window.scrollTo( 0, 0);
		}
	},

	_bindFixListener: function(){
		var self = this;
		$( window ).on( "throttledresize.panel", function(){
			self._positionPanel();
		} );
	},

	_unbindFixListener: function(){
		$( window ).off( "throttledresize.panel" );
	},

	_unfixPanel: function(){
		this.element.addClass( this.options.classes.panelUnfixed );
	},

	_fixPanel: function(){
		this.element.removeClass( this.options.classes.panelUnfixed );
	},

	_bindLinkListeners: function(){
		var self = this;

		this._page.on( "click" , "a", function( e ) {
			if( this.href.split( "#" )[ 1 ] === self._panelID ){
				e.preventDefault();
				var $link = $( this );
				$link.addClass( $.mobile.activeBtnClass );
				self.element.one( "panelopen panelclose", function(){
					$link.removeClass( $.mobile.activeBtnClass );
				});
				self.toggle();
				return false;
			}
		});
	},

	_bindPageEvents: function(){
		var self = this;

		self.element
			// on swipe, close the panel (should swipe open too?)
			.on( "swipe" , function( e ){
				self.close( true );
			});

		self._page
			// Close immediately if another panel on the page opens
			.on( "panelbeforeopen", function( e ){
				if( self._open && e.target !== self.element[ 0 ] ){
					self.close( true );
				}
			})
			// clean up open panels after page hide
			.on(  "pagebeforehide", function( e ) {
				if( self._open ){
					self.close( true );
				}
			})
			// on escape, close? might need to have a target check too...
			.on( "keyup", function( e ) {
				if( e.keyCode === 27 && self._open ){
					self.close( true );
				}
			});
	},

	// state storage of open or closed
	_open: false,

	_contentWrapOpenClasses: null,
	_modalOpenClasses: null,

	open: function( options ){
		var self = this,
			o = self.options,
			complete = function(){
				self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
				self.element.addClass( o.classes.openComplete );
				self._wrapper.addClass( o.classes.contentWrapOpenComplete );
				self._positionPanel();
				self._bindFixListener();
				self._trigger( "open" );
			};

		self._trigger( "beforeopen" );

		if ( $.support.cssTransitions && o.animate ) {
			self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
		} else{
			setTimeout( complete , 0 );
		}
		self._page.addClass( self.options.classes.pageBlock );
		self.element.removeClass( o.classes.panelClosed );
		self.element.addClass( o.classes.panelOpen );
		self._contentWrapOpenClasses = self._getPosDisplayClasses( o.classes.contentWrap );
		self._wrapper.removeClass( o.classes.contentWrapClosed );
		self._wrapper.addClass( self._contentWrapOpenClasses + " " + o.classes.contentWrapOpen );
		self._modalOpenClasses = self._getPosDisplayClasses( o.classes.modal ) + " " + o.classes.modalOpen;
		self._modal.addClass( self._modalOpenClasses );

		self._open = true;

	},

	close: function( immediate ){
		var o = this.options,
			self = this,
			complete = function(){
				self.element.add( self._wrapper ).unbind( self._transitionEndEvents , complete );
				self.element.addClass( o.classes.panelClosed );
				self._wrapper.removeClass( self._contentWrapOpenClasses );
				self._wrapper.addClass( o.classes.contentWrapClosed );
				self._page.removeClass( self.options.classes.pageBlock );
				self._fixPanel();
				self._unbindFixListener();
				self._trigger( "close" );
			};

		self._trigger( "beforeclose" );

		if ( $.support.cssTransform3d && o.animate ) {
			self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
		} else{
			setTimeout( complete , 0 );
		}

		self.element.removeClass( o.classes.panelOpen + " " + o.classes.openComplete );
		self._modal.removeClass( self._modalOpenClasses );
		self._wrapper.removeClass( o.classes.contentWrapOpen + " " + o.classes.contentWrapOpenComplete );

		self._open = false;
	},

	toggle: function( options ){
		this[ this._open ? "close" : "open" ]();
	},

	_transitionEndEvents: "webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",

	_destroy: function(){
		// unbind events, remove generated elements, remove classes, remove data
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ) {
	$.mobile.panel.prototype.enhanceWithin( e.target );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");

<|endoftext|>


<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Responsive presentation and behavior for HTML data panels
//>>label: Panel
//>>group: Widgets
//>>css.structure: ../css/structure/jquery.mobile.panel.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "../jquery.mobile.widget", "./page", "./page.sections" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.panel", $.mobile.widget, {
	options: {
		classes: {
			panel: "ui-panel",
			panelOpen: "ui-panel-open",
			panelClosed: "ui-panel-closed",
			modal: "ui-panel-dismiss",
			modalOpen: "ui-panel-dismiss-open",
			openComplete: "ui-panel-open-complete",
			contentWrap: "ui-panel-content-wrap",
			contentWrapOpen: "ui-panel-content-wrap-open",
			contentWrapClosed: "ui-panel-content-wrap-closed",
			panelUnfixed: "ui-panel-unfixed",
			contentWrapOpenComplete: "ui-panel-content-wrap-open-complete",
			pageBlock: "ui-panel-page-block",
			pagePanel: "ui-page-panel",
			cssTransform3d: "ui-panel-3dtransforms"
		},
		animate: true,
		theme: null,
		position: "left",
		dismissible: true,
		display: "overlay", //accepts reveal, push, overlay
		initSelector: ":jqmData(role='panel')",
		swipeClose: true,
		positionFixed: true
	},

	_panelID: null,
	_closeLink: null,
	_page: null,
	_modal: null,
	_wrapper: null,

	_create: function() {
		var self = this,
			$el = self.element,
			_getWrapper = function(){
				var $wrapper = self._page.find( "." + self.options.classes.contentWrap );
				if( $wrapper.length === 0 ){
					$wrapper = self._page.find( ".ui-header, .ui-content, .ui-footer" ).wrapAll( '
' ).parent();
					if( $.support.cssTransform3d && !!self.options.positionFixed ) {
						$wrapper.addClass( self.options.classes.cssTransform3d );
					}
				}
				return $wrapper;
			};

		// expose some private props to other methods
		self._panelID = $el.attr( "id" );
		self._closeLink = $el.find( ":jqmData(rel='close')" );
		self._page = $el.closest( ":jqmData(role='page')" );
		self._wrapper = _getWrapper();
		self._addPanelClasses();
		self._wrapper.addClass( this.options.classes.contentWrapClosed );

		// if animating, add the class to do so
		if ( $.support.cssTransform3d && self.options.animate ) {
			this.element.add( self._wrapper ).addClass( "ui-panel-animate" );
		}

		self._bindCloseEvents();
		self._bindLinkListeners();
		self._bindPageEvents();

		if( self.options.dismissible ){
			self._createModal();
		}

	},

	_createModal: function( options ){
		var self = this;
		self._modal = $( "

" )
			.on( "mousedown" , function(){
				self.close();
			})
			.appendTo( this._page );
	},

	_getPosDisplayClasses: function( prefix ){
		return prefix + "-position-" + this.options.position + " " + prefix + "-display-" + this.options.display;
	},

	_getPanelClasses: function(){
		var panelClasses = this.options.classes.panel +
						" " + this._getPosDisplayClasses( this.options.classes.panel ) +
						" " + this.options.classes.panelClosed;

		if( this.options.theme ){
			panelClasses += " ui-body-" + this.options.theme;
		}

		if( $.support.cssTransform3d && !!this.options.positionFixed ) {
			panelClasses += " " + this.options.classes.cssTransform3d;
		}
		return panelClasses;
	},

	_addPanelClasses: function(){
		this.element.addClass( this._getPanelClasses() );
	},

	_bindCloseEvents: function(){
		var self = this;
		self._closeLink.on( "click.panel" , function( e ){
			e.preventDefault();
			self.close();
			return false;
		});
	},

	_positionPanel: function(){
		if ( this.element.height() > $.mobile.getScreenHeight() ) {
			this._unfixPanel();
			this._scrollIntoView();
		}
		else {
			this._fixPanel();
		}
	},

	_scrollIntoView: function(){
		if( $(window).scrollTop() > $.mobile.getScreenHeight() ){
			window.scrollTo( 0, 0);
		}
	},

	_bindFixListener: function(){
		this._on( $( window ), { "throttledresize": "_positionPanel" });
	},

	_unbindFixListener: function(){
		this._off( $( window ), "throttledresize" );
	},

	_unfixPanel: function(){
		this.element.addClass( this.options.classes.panelUnfixed );
	},

	_fixPanel: function(){
		this.element.removeClass( this.options.classes.panelUnfixed );
	},

	_bindLinkListeners: function(){
		var self = this;

		this._page.on( "click.panel" , "a", function( e ) {
			if( this.href.split( "#" )[ 1 ] === self._panelID ){
				e.preventDefault();
				var $link = $( this );
				$link.addClass( $.mobile.activeBtnClass );
				self.element.one( "panelopen panelclose", function(){
					$link.removeClass( $.mobile.activeBtnClass );
				});
				self.toggle();
				return false;
			}
		});
	},

	_bindPageEvents: function(){
		var self = this;
		if( !!this.options.swipeClose ){
			self.element
				// on swipe, close the panel (should swipe open too?)
				.on( "swipe.panel" , function( e ){
					self.close( );
				});
		}
		self._page
			// Close immediately if another panel on the page opens
			.on( "panelbeforeopen", function( e ){
				if( self._open && e.target !== self.element[ 0 ] ){
					self.close( true );
				}
			})
			// clean up open panels after page hide
			.on(  "pagebeforehide", function( e ) {
				if( self._open ){
					self.close( true );
				}
			})
			// on escape, close? might need to have a target check too...
			.on( "keyup.panel", function( e ) {
				if( e.keyCode === 27 && self._open ){
					self.close( );
				}
			});
	},

	// state storage of open or closed
	_open: false,

	_contentWrapOpenClasses: null,
	_modalOpenClasses: null,

	open: function( immediate ){
		if( !this._open ){
			var self = this,
				o = self.options,
				complete = function(){
					self.element.add( self._wrapper ).unbind( self._transitionEndEvents, complete );
					self.element.addClass( o.classes.openComplete );
					self._wrapper.addClass( o.classes.contentWrapOpenComplete );
					self._page.addClass( o.classes.pageBlock );
					self._positionPanel();
					self._bindFixListener();
					self._trigger( "open" );
				};

			if( this.element.closest( ".ui-page-active" ).length < 0 ){
				immediate = true;
			}
			self._trigger( "beforeopen" );

			if ( !immediate && $.support.cssTransform3d && o.animate ) {
				self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
			} else{
				setTimeout( complete , 0 );
			}
			self.element.removeClass( o.classes.panelClosed );
			self.element.addClass( o.classes.panelOpen );
			self._contentWrapOpenClasses = self._getPosDisplayClasses( o.classes.contentWrap );
			self._wrapper.removeClass( o.classes.contentWrapClosed );
			self._wrapper.addClass( self._contentWrapOpenClasses + " " + o.classes.contentWrapOpen );
			self._modalOpenClasses = self._getPosDisplayClasses( o.classes.modal ) + " " + o.classes.modalOpen;
			if( this._modal ) {
				self._modal.addClass( self._modalOpenClasses );
			}
			self._open = true;
		}
	},

	close: function( immediate ){
		if( this._open ){
			var o = this.options,
				self = this,
				complete = function(){
					self.element.add( self._wrapper ).off( self._transitionEndEvents , complete );
					self.element.addClass( o.classes.panelClosed );
					self._wrapper.removeClass( self._contentWrapOpenClasses );
					self._wrapper.addClass( o.classes.contentWrapClosed );
					self._page.removeClass( o.classes.pageBlock );
					self._fixPanel();
					self._unbindFixListener();
					self._trigger( "close" );
				};
			if( this.element.closest( ".ui-page-active" ).length < 0 ){
				immediate = true;
			}
			self._trigger( "beforeclose" );

			if ( !immediate && $.support.cssTransform3d && o.animate ) {
				self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
			} else{
				setTimeout( complete , 0 );
			}

			self.element.removeClass( o.classes.panelOpen + " " + o.classes.openComplete );
			if( this._modal ) {
				self._modal.removeClass( self._modalOpenClasses );
			}
			self._wrapper.removeClass( o.classes.contentWrapOpen + " " + o.classes.contentWrapOpenComplete );

			self._open = false;
		}
	},

	toggle: function( options ){
		this[ this._open ? "close" : "open" ]();
	},

	_transitionEndEvents: "webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",

	_destroy: function(){
		var classes = this.options.classes,
			hasOtherSiblingPanels = this.element.siblings( "." + classes.panel ).length;

		// create
		if( !hasOtherSiblingPanels ) {
			this._wrapper.children().unwrap();
			this._page.find( "a" ).unbind( "panelopen panelclose" );
		} else if( this._open ) {
			this._wrapper.removeClass( [ classes.contentWrapOpen, classes.contentWrapOpenComplete ].join( " " ) );
		}

		this.element.removeClass( [ this._getPanelClasses(), classes.panelAnimate ].join( " " ) )
			.off( "swipe.panel" )
			.off( "panelbeforeopen" )
			.off( "panelbeforehide" )
			.off( "keyup.panel" );

		this._closeLink.off( "click.panel" );

		if( this._modal ) {
			this._modal.remove();
		}

		// open and close
		this.element.off( this._transitionEndEvents )
			.removeClass( [ classes.openComplete, classes.panelUnfixed, classes.panelClosed, classes.panelOpen ].join( " " ) );
		this._page.removeClass( classes.pageBlock );
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ) {
	$.mobile.panel.prototype.enhanceWithin( e.target );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");

<commit_msg>Prevents panels without IDs from being triggered by unrelated links.<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Responsive presentation and behavior for HTML data panels
//>>label: Panel
//>>group: Widgets
//>>css.structure: ../css/structure/jquery.mobile.panel.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "../jquery.mobile.widget", "./page", "./page.sections" ], function( $ ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.widget( "mobile.panel", $.mobile.widget, {
	options: {
		classes: {
			panel: "ui-panel",
			panelOpen: "ui-panel-open",
			panelClosed: "ui-panel-closed",
			modal: "ui-panel-dismiss",
			modalOpen: "ui-panel-dismiss-open",
			openComplete: "ui-panel-open-complete",
			contentWrap: "ui-panel-content-wrap",
			contentWrapOpen: "ui-panel-content-wrap-open",
			contentWrapClosed: "ui-panel-content-wrap-closed",
			panelUnfixed: "ui-panel-unfixed",
			contentWrapOpenComplete: "ui-panel-content-wrap-open-complete",
			pageBlock: "ui-panel-page-block",
			pagePanel: "ui-page-panel",
			cssTransform3d: "ui-panel-3dtransforms"
		},
		animate: true,
		theme: null,
		position: "left",
		dismissible: true,
		display: "overlay", //accepts reveal, push, overlay
		initSelector: ":jqmData(role='panel')",
		swipeClose: true,
		positionFixed: true
	},

	_panelID: null,
	_closeLink: null,
	_page: null,
	_modal: null,
	_wrapper: null,

	_create: function() {
		var self = this,
			$el = self.element,
			_getWrapper = function(){
				var $wrapper = self._page.find( "." + self.options.classes.contentWrap );
				if( $wrapper.length === 0 ){
					$wrapper = self._page.find( ".ui-header, .ui-content, .ui-footer" ).wrapAll( '
' ).parent();
					if( $.support.cssTransform3d && !!self.options.positionFixed ) {
						$wrapper.addClass( self.options.classes.cssTransform3d );
					}
				}
				return $wrapper;
			};

		// expose some private props to other methods
		self._panelID = $el.attr( "id" );
		self._closeLink = $el.find( ":jqmData(rel='close')" );
		self._page = $el.closest( ":jqmData(role='page')" );
		self._wrapper = _getWrapper();
		self._addPanelClasses();
		self._wrapper.addClass( this.options.classes.contentWrapClosed );

		// if animating, add the class to do so
		if ( $.support.cssTransform3d && self.options.animate ) {
			this.element.add( self._wrapper ).addClass( "ui-panel-animate" );
		}

		self._bindCloseEvents();
		self._bindLinkListeners();
		self._bindPageEvents();

		if( self.options.dismissible ){
			self._createModal();
		}

	},

	_createModal: function( options ){
		var self = this;
		self._modal = $( "

" )
			.on( "mousedown" , function(){
				self.close();
			})
			.appendTo( this._page );
	},

	_getPosDisplayClasses: function( prefix ){
		return prefix + "-position-" + this.options.position + " " + prefix + "-display-" + this.options.display;
	},

	_getPanelClasses: function(){
		var panelClasses = this.options.classes.panel +
						" " + this._getPosDisplayClasses( this.options.classes.panel ) +
						" " + this.options.classes.panelClosed;

		if( this.options.theme ){
			panelClasses += " ui-body-" + this.options.theme;
		}

		if( $.support.cssTransform3d && !!this.options.positionFixed ) {
			panelClasses += " " + this.options.classes.cssTransform3d;
		}
		return panelClasses;
	},

	_addPanelClasses: function(){
		this.element.addClass( this._getPanelClasses() );
	},

	_bindCloseEvents: function(){
		var self = this;
		self._closeLink.on( "click.panel" , function( e ){
			e.preventDefault();
			self.close();
			return false;
		});
	},

	_positionPanel: function(){
		if ( this.element.height() > $.mobile.getScreenHeight() ) {
			this._unfixPanel();
			this._scrollIntoView();
		}
		else {
			this._fixPanel();
		}
	},

	_scrollIntoView: function(){
		if( $(window).scrollTop() > $.mobile.getScreenHeight() ){
			window.scrollTo( 0, 0);
		}
	},

	_bindFixListener: function(){
		this._on( $( window ), { "throttledresize": "_positionPanel" });
	},

	_unbindFixListener: function(){
		this._off( $( window ), "throttledresize" );
	},

	_unfixPanel: function(){
		this.element.addClass( this.options.classes.panelUnfixed );
	},

	_fixPanel: function(){
		this.element.removeClass( this.options.classes.panelUnfixed );
	},

	_bindLinkListeners: function(){
		var self = this;

		this._page.on( "click.panel" , "a", function( e ) {
			if( this.href.split( "#" )[ 1 ] === self._panelID && self._panelID !== undefined ){
				e.preventDefault();
				var $link = $( this );
				$link.addClass( $.mobile.activeBtnClass );
				self.element.one( "panelopen panelclose", function(){
					$link.removeClass( $.mobile.activeBtnClass );
				});
				self.toggle();
				return false;
			}
		});
	},

	_bindPageEvents: function(){
		var self = this;
		if( !!this.options.swipeClose ){
			self.element
				// on swipe, close the panel (should swipe open too?)
				.on( "swipe.panel" , function( e ){
					self.close( );
				});
		}
		self._page
			// Close immediately if another panel on the page opens
			.on( "panelbeforeopen", function( e ){
				if( self._open && e.target !== self.element[ 0 ] ){
					self.close( true );
				}
			})
			// clean up open panels after page hide
			.on(  "pagebeforehide", function( e ) {
				if( self._open ){
					self.close( true );
				}
			})
			// on escape, close? might need to have a target check too...
			.on( "keyup.panel", function( e ) {
				if( e.keyCode === 27 && self._open ){
					self.close( );
				}
			});
	},

	// state storage of open or closed
	_open: false,

	_contentWrapOpenClasses: null,
	_modalOpenClasses: null,

	open: function( immediate ){
		if( !this._open ){
			var self = this,
				o = self.options,
				complete = function(){
					self.element.add( self._wrapper ).unbind( self._transitionEndEvents, complete );
					self.element.addClass( o.classes.openComplete );
					self._wrapper.addClass( o.classes.contentWrapOpenComplete );
					self._page.addClass( o.classes.pageBlock );
					self._positionPanel();
					self._bindFixListener();
					self._trigger( "open" );
				};

			if( this.element.closest( ".ui-page-active" ).length < 0 ){
				immediate = true;
			}
			self._trigger( "beforeopen" );

			if ( !immediate && $.support.cssTransform3d && o.animate ) {
				self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
			} else{
				setTimeout( complete , 0 );
			}
			self.element.removeClass( o.classes.panelClosed );
			self.element.addClass( o.classes.panelOpen );
			self._contentWrapOpenClasses = self._getPosDisplayClasses( o.classes.contentWrap );
			self._wrapper.removeClass( o.classes.contentWrapClosed );
			self._wrapper.addClass( self._contentWrapOpenClasses + " " + o.classes.contentWrapOpen );
			self._modalOpenClasses = self._getPosDisplayClasses( o.classes.modal ) + " " + o.classes.modalOpen;
			if( this._modal ) {
				self._modal.addClass( self._modalOpenClasses );
			}
			self._open = true;
		}
	},

	close: function( immediate ){
		if( this._open ){
			var o = this.options,
				self = this,
				complete = function(){
					self.element.add( self._wrapper ).off( self._transitionEndEvents , complete );
					self.element.addClass( o.classes.panelClosed );
					self._wrapper.removeClass( self._contentWrapOpenClasses );
					self._wrapper.addClass( o.classes.contentWrapClosed );
					self._page.removeClass( o.classes.pageBlock );
					self._fixPanel();
					self._unbindFixListener();
					self._trigger( "close" );
				};
			if( this.element.closest( ".ui-page-active" ).length < 0 ){
				immediate = true;
			}
			self._trigger( "beforeclose" );

			if ( !immediate && $.support.cssTransform3d && o.animate ) {
				self.element.add( self._wrapper ).on( self._transitionEndEvents , complete );
			} else{
				setTimeout( complete , 0 );
			}

			self.element.removeClass( o.classes.panelOpen + " " + o.classes.openComplete );
			if( this._modal ) {
				self._modal.removeClass( self._modalOpenClasses );
			}
			self._wrapper.removeClass( o.classes.contentWrapOpen + " " + o.classes.contentWrapOpenComplete );

			self._open = false;
		}
	},

	toggle: function( options ){
		this[ this._open ? "close" : "open" ]();
	},

	_transitionEndEvents: "webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",

	_destroy: function(){
		var classes = this.options.classes,
			hasOtherSiblingPanels = this.element.siblings( "." + classes.panel ).length;

		// create
		if( !hasOtherSiblingPanels ) {
			this._wrapper.children().unwrap();
			this._page.find( "a" ).unbind( "panelopen panelclose" );
		} else if( this._open ) {
			this._wrapper.removeClass( [ classes.contentWrapOpen, classes.contentWrapOpenComplete ].join( " " ) );
		}

		this.element.removeClass( [ this._getPanelClasses(), classes.panelAnimate ].join( " " ) )
			.off( "swipe.panel" )
			.off( "panelbeforeopen" )
			.off( "panelbeforehide" )
			.off( "keyup.panel" );

		this._closeLink.off( "click.panel" );

		if( this._modal ) {
			this._modal.remove();
		}

		// open and close
		this.element.off( this._transitionEndEvents )
			.removeClass( [ classes.openComplete, classes.panelUnfixed, classes.panelClosed, classes.panelOpen ].join( " " ) );
		this._page.removeClass( classes.pageBlock );
	}
});

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ) {
	$.mobile.panel.prototype.enhanceWithin( e.target );
});

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");

<|endoftext|>


<commit_before>var _ = require('lodash');
var AWS = require('aws-sdk');
var events = require('events');
var moment = require('moment');
var dateRange = require('moment-range');
var path = require('path');
var async = require('async');
var util = require('util');

var Uploader = require('s3-streaming-upload').Uploader;

var ReadableStream = require('./readable-stream');

function DynamoBackup(options) {
    options = options || {};
    this.excludedTables = options.excludedTables || [];
    this.includedTables = options.includedTables;
    this.readPercentage = options.readPercentage || .25;
    this.backupPath = options.backupPath;
    this.bucket = options.bucket;
    this.stopOnFailure = options.stopOnFailure || false;
    this.base64Binary = options.base64Binary || false;
    this.saveDataPipelineFormat = options.saveDataPipelineFormat || false;
    this.awsAccessKey = options.awsAccessKey || process.env.AWS_ACCESS_KEY_ID;
    this.awsSecretKey = options.awsSecretKey || process.env.AWS_SECRET_ACCESS_KEY;
    this.awsRegion = options.awsRegion || process.env.AWS_DEFAULT_REGION || 'us-east-1';
    this.debug = Boolean(options.debug);

    AWS.config.update({
        accessKeyId: this.awsAccessKey,
        secretAccessKey: this.secretAccessKey,
        region: this.awsRegion
    });
}

util.inherits(DynamoBackup, events.EventEmitter);

DynamoBackup.prototype.listTables = function (callback) {
    var self = this;
    self._fetchTables(null, [], callback);
}

DynamoBackup.prototype.backupTable = function (tableName, backupPath, callback) {
    var self = this;
    var stream = new ReadableStream();

    if (callback === undefined) {
        callback = backupPath;
        backupPath = self._getBackupPath();
    }

    var upload = new Uploader({
        accessKey: self.awsAccessKey,
        secretKey: self.awsSecretKey,
        region: self.awsRegion,
        bucket: self.bucket,
        objectName: path.join(backupPath, tableName + '.json'),
        stream: stream,
        debug: self.debug
    });

    var startTime = moment.utc();
    self.emit('start-backup', tableName, startTime);
    upload.send(function (err) {
        if (err) {
            self.emit('error', {
                table: tableName,
                err: err
            });
        }
        var endTime = moment.utc();
        var backupDuration = new dateRange(startTime, endTime);
        self.emit('end-backup', tableName, backupDuration);
        return callback(err);
    });

    self._copyTable(
        tableName,
        function (items) {
            items.forEach(function (item) {
                if (self.base64Binary) {
                    _.each(item, function (value, key) {
                        if (value && value.B) {
                            value.B = new Buffer(value.B).toString('base64');
                        }
                    });
                }

                if (self.saveDataPipelineFormat) {
                    stream.append(self._formatForDataPipeline(item));
                } else {
                    stream.append(JSON.stringify(item));
                }
                stream.append('\n');
            });
        },
        function (err) {
            stream.end();
            if (err) {
                self.emit('error', {
                    table: tableName,
                    err: err
                });
            }
        }
        );
}

DynamoBackup.prototype.backupAllTables = function (callback) {
    var self = this;
    var backupPath = self._getBackupPath();

    self.listTables(function (err, tables) {
        if (err) {
            return callback(err);
        }
        var includedTables = self.includedTables || tables;
        tables = _.difference(tables, self.excludedTables);
        tables = _.intersection(tables, includedTables);

        async.each(tables,
            function (tableName, done) {
                self.backupTable(tableName, backupPath, function (err) {
                    if (err) {
                        if (self.stopOnFailure) {
                            return done(err);
                        }
                    }
                    done();
                })
            },
            callback
            );
    });
}

DynamoBackup.prototype._getBackupPath = function () {
    var self = this;
    var now = moment.utc();
    return self.backupPath || ('DynamoDB-backup-' + now.format('YYYY-MM-DD-HH-mm-ss'));
}

DynamoBackup.prototype._copyTable = function (tableName, itemsReceived, callback) {
    var self = this;
    var ddb = new AWS.DynamoDB();
    ddb.describeTable({ TableName: tableName }, function (err, data) {
        if (err) {
            return callback(err);
        }

        var readPercentage = self.readPercentage;
        var limit = Math.max((data.Table.ProvisionedThroughput.ReadCapacityUnits * readPercentage) | 0, 1);

        self._streamItems(tableName, null, limit, itemsReceived, callback);
    });
}

DynamoBackup.prototype._streamItems = function fetchItems(tableName, startKey, limit, itemsReceived, callback) {
    var self = this;
    var ddb = new AWS.DynamoDB();
    var params = {
        Limit: limit,
        ReturnConsumedCapacity: 'NONE',
        TableName: tableName
    };
    if (startKey) {
        params.ExclusiveStartKey = startKey;
    }
    ddb.scan(params, function (err, data) {
        if (err) {
            return callback(err);
        }

        if (data.Items.length > 0) {
            itemsReceived(data.Items);
        }

        if (!data.LastEvaluatedKey || _.keys(data.LastEvaluatedKey).length === 0) {
            return callback();
        }
        self._streamItems(tableName, data.LastEvaluatedKey, limit, itemsReceived, callback);
    });
}

DynamoBackup.prototype._fetchTables = function (lastTable, tables, callback) {
    var self = this;
    var ddb = new AWS.DynamoDB();
    var params = {};
    if (lastTable) {
        params.ExclusiveStartTableName = lastTable;
    }
    ddb.listTables(params, function (err, data) {
        if (err) {
            return callback(err, null);
        }
        tables = tables.concat(data.TableNames);
        if (data.LastEvaluatedTableName) {
            self._fetchTables(data.LastEvaluatedTableName, tables, callback);
        } else {
            callback(null, tables);
        }
    });
};

/**
 * AWS Data Pipeline import requires that each key in the Attribute list
 * be lower-cased and for sets start with a lower-case character followed
 * by an 'S'.
 *
 * Go through each attribute and create a new entry with the correct case
 */
DynamoBackup.prototype._formatForDataPipeline = function (item) {
    var self = this;
    _.each(item, function (value, key) {
        //value will be of the form: {S: 'xxx'}. Convert the key
        _.each(value, function (v, k) {
            var dataPipelineValueKey = self._getDataPipelineAttributeValueKey(k);
            value[dataPipelineValueKey] = v;
            value[k] = undefined;
        });
    });
    return JSON.stringify(item);
};

DynamoBackup.prototype._getDataPipelineAttributeValueKey = function (type) {
    switch (type) {
        case 'S':
        case 'N':
        case 'B':
        case 'M':
        case 'L':
        case 'NULL':
        case 'BOOL':
            return type.toLowerCase();
        case 'SS':
            return 'sS';
        case 'NS':
            return 'nS';
        case 'BS':
            return 'bS';
        default:
            throw new Error('Unknown AttributeValue key: ' + type);
    }
}

module.exports = DynamoBackup;<commit_msg>When the -d option is used, for Maps and Lists, the keys of individual items are now converted to lower case.<commit_after>var _ = require('lodash');
var AWS = require('aws-sdk');
var events = require('events');
var moment = require('moment');
var dateRange = require('moment-range');
var path = require('path');
var async = require('async');
var util = require('util');

var Uploader = require('s3-streaming-upload').Uploader;

var ReadableStream = require('./readable-stream');

function DynamoBackup(options) {
    options = options || {};
    this.excludedTables = options.excludedTables || [];
    this.includedTables = options.includedTables;
    this.readPercentage = options.readPercentage || .25;
    this.backupPath = options.backupPath;
    this.bucket = options.bucket;
    this.stopOnFailure = options.stopOnFailure || false;
    this.base64Binary = options.base64Binary || false;
    this.saveDataPipelineFormat = options.saveDataPipelineFormat || false;
    this.awsAccessKey = options.awsAccessKey || process.env.AWS_ACCESS_KEY_ID;
    this.awsSecretKey = options.awsSecretKey || process.env.AWS_SECRET_ACCESS_KEY;
    this.awsRegion = options.awsRegion || process.env.AWS_DEFAULT_REGION || 'us-east-1';
    this.debug = Boolean(options.debug);

    AWS.config.update({
        accessKeyId: this.awsAccessKey,
        secretAccessKey: this.secretAccessKey,
        region: this.awsRegion
    });
}

util.inherits(DynamoBackup, events.EventEmitter);

DynamoBackup.prototype.listTables = function (callback) {
    var self = this;
    self._fetchTables(null, [], callback);
};

DynamoBackup.prototype.backupTable = function (tableName, backupPath, callback) {
    var self = this;
    var stream = new ReadableStream();

    if (callback === undefined) {
        callback = backupPath;
        backupPath = self._getBackupPath();
    }

    var upload = new Uploader({
        accessKey: self.awsAccessKey,
        secretKey: self.awsSecretKey,
        region: self.awsRegion,
        bucket: self.bucket,
        objectName: path.join(backupPath, tableName + '.json'),
        stream: stream,
        debug: self.debug
    });

    var startTime = moment.utc();
    self.emit('start-backup', tableName, startTime);
    upload.send(function (err) {
        if (err) {
            self.emit('error', {
                table: tableName,
                err: err
            });
        }
        var endTime = moment.utc();
        var backupDuration = new dateRange(startTime, endTime);
        self.emit('end-backup', tableName, backupDuration);
        return callback(err);
    });

    self._copyTable(
        tableName,
        function (items) {
            items.forEach(function (item) {
                if (self.base64Binary) {
                    _.each(item, function (value, key) {
                        if (value && value.B) {
                            value.B = new Buffer(value.B).toString('base64');
                        }
                    });
                }

                if (self.saveDataPipelineFormat) {
                    stream.append(self._formatForDataPipeline(item));
                } else {
                    stream.append(JSON.stringify(item));
                }
                stream.append('\n');
            });
        },
        function (err) {
            stream.end();
            if (err) {
                self.emit('error', {
                    table: tableName,
                    err: err
                });
            }
        }
        );
};

DynamoBackup.prototype.backupAllTables = function (callback) {
    var self = this;
    var backupPath = self._getBackupPath();

    self.listTables(function (err, tables) {
        if (err) {
            return callback(err);
        }
        var includedTables = self.includedTables || tables;
        tables = _.difference(tables, self.excludedTables);
        tables = _.intersection(tables, includedTables);

        async.each(tables,
            function (tableName, done) {
                self.backupTable(tableName, backupPath, function (err) {
                    if (err) {
                        if (self.stopOnFailure) {
                            return done(err);
                        }
                    }
                    done();
                })
            },
            callback
            );
    });
};

DynamoBackup.prototype._getBackupPath = function () {
    var self = this;
    var now = moment.utc();
    return self.backupPath || ('DynamoDB-backup-' + now.format('YYYY-MM-DD-HH-mm-ss'));
};

DynamoBackup.prototype._copyTable = function (tableName, itemsReceived, callback) {
    var self = this;
    var ddb = new AWS.DynamoDB();
    ddb.describeTable({ TableName: tableName }, function (err, data) {
        if (err) {
            return callback(err);
        }

        var readPercentage = self.readPercentage;
        var limit = Math.max((data.Table.ProvisionedThroughput.ReadCapacityUnits * readPercentage) | 0, 1);

        self._streamItems(tableName, null, limit, itemsReceived, callback);
    });
};

DynamoBackup.prototype._streamItems = function fetchItems(tableName, startKey, limit, itemsReceived, callback) {
    var self = this;
    var ddb = new AWS.DynamoDB();
    var params = {
        Limit: limit,
        ReturnConsumedCapacity: 'NONE',
        TableName: tableName
    };
    if (startKey) {
        params.ExclusiveStartKey = startKey;
    }
    ddb.scan(params, function (err, data) {
        if (err) {
            return callback(err);
        }

        if (data.Items.length > 0) {
            itemsReceived(data.Items);
        }

        if (!data.LastEvaluatedKey || _.keys(data.LastEvaluatedKey).length === 0) {
            return callback();
        }
        self._streamItems(tableName, data.LastEvaluatedKey, limit, itemsReceived, callback);
    });
};

DynamoBackup.prototype._fetchTables = function (lastTable, tables, callback) {
    var self = this;
    var ddb = new AWS.DynamoDB();
    var params = {};
    if (lastTable) {
        params.ExclusiveStartTableName = lastTable;
    }
    ddb.listTables(params, function (err, data) {
        if (err) {
            return callback(err, null);
        }
        tables = tables.concat(data.TableNames);
        if (data.LastEvaluatedTableName) {
            self._fetchTables(data.LastEvaluatedTableName, tables, callback);
        } else {
            callback(null, tables);
        }
    });
};

/**
 * AWS Data Pipeline import requires that each key in the Attribute list
 * be lower-cased and for sets start with a lower-case character followed
 * by an 'S'.
 *
 * Go through each attribute and create a new entry with the correct case
 */
DynamoBackup.prototype._formatForDataPipeline = function (item) {
    var self = this;
    _.each(item, function (value, key) {
        //value will be of the form: {S: 'xxx'}. Convert the key
        _.each(value, function (v, k) {
            var dataPipelineValueKey = self._getDataPipelineAttributeValueKey(k);
            value[dataPipelineValueKey] = v;
            value[k] = undefined;
            // for MAps and Lists, recurse until the elements are created with the correct case
            if(k === 'M' || k === 'L') {
              self._formatForDataPipeline(v);
            }
        });
    });
    return JSON.stringify(item);
};

DynamoBackup.prototype._getDataPipelineAttributeValueKey = function (type) {
    switch (type) {
        case 'S':
        case 'N':
        case 'B':
        case 'M':
        case 'L':
        case 'NULL':
        case 'BOOL':
            return type.toLowerCase();
        case 'SS':
            return 'sS';
        case 'NS':
            return 'nS';
        case 'BS':
            return 'bS';
        default:
            throw new Error('Unknown AttributeValue key: ' + type);
    }
};

module.exports = DynamoBackup;<|endoftext|>


<commit_before>'use babel';

import fs from 'fs';
import path from 'path';
import ElmNavigatorView from './elm-navigator-view';
import { CompositeDisposable } from 'atom';
import { foldOverDirectoryTree } from './atom-util';
import regexes from './regexes';

Array.prototype.extend = function (other_array) {
    other_array.forEach(function(v) {this.push(v)}, this);
}

var nextNavigatorUpdate = null;

export default {

  elmNavigatorView: null,
  modalPanel: null,
  subscriptions: null,

  activate(state) {
    var project = atom.project;
    var projectDirectory = project.getDirectories()[0];

    this.elmNavigatorView = new ElmNavigatorView(
      state.elmNavigatorViewState,
    );

    var elm = this.elmNavigatorView.elm;
    this.elm = elm;
    elm.ports.goToLineInFile.subscribe(function({uri, lineNumber}) {
      atom.workspace.open(uri, { initialLine: lineNumber });
    })

    this.modalPanel = atom.workspace.addRightPanel({
      item: this.elmNavigatorView.getElement(),
      visible: false
    });
    this.modalPanel.show();

    // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    this.subscriptions = new CompositeDisposable();

    atom.workspace.observeActivePaneItem(function(activePaneItem) {
      if (typeof(activePaneItem) !== 'undefined') {
        if (typeof(activePaneItem.onDidChange) !== 'undefined') {

          const filePath = activePaneItem.getPath();
          elm.ports.activeFileChanged.send({filePath});

          activePaneItem.onDidChange(function() {
            nextNavigatorUpdate = {
              when: "IN_TWO_TICKS",
              paneItem: activePaneItem
            }
          });
        } else {
            nextNavigatorUpdate = null;
        }
      }
    });

    //TODO: remove interval when deactivated

    (function() {
      const UPDATE_INTERVAL_SECONDS = 0.5;
      setInterval(function() {

        if (nextNavigatorUpdate != null) {
          if (nextNavigatorUpdate.when == "NEXT_TICK") {
            const editorText = nextNavigatorUpdate.paneItem.buffer.cachedText;
            if (editorText != null && typeof(editorText) !== 'unedfined') {
              const filePath = nextNavigatorUpdate.paneItem.getPath();
              const rawTags = editorTextToRawTags(editorText, filePath);
              const payload = { filePath, rawTags };
              elm.ports.fileUpdated.send(payload);
            }
            nextNavigatorUpdate = null;
          } else if (nextNavigatorUpdate.when == "IN_TWO_TICKS") {
            nextNavigatorUpdate.when = "NEXT_TICK"; // it will update in the next tick
          }
        } else {
          // console.log("no navigator update queued");
        }
      }, UPDATE_INTERVAL_SECONDS * 1000);
    })();

    setTimeout(function() {
      // setTimeout is an awful hack to delay this expensive synchronous code
      // until after the sidebar has rendered.The better solution is to use
      // async when traversing the directory, which also frees up the UI to
      // do things like display a spinner
      const data = foldOverDirectoryTree(
        {
          directory: projectDirectory,
          func: ({file, contents, acc}) => {
            const filePath = file.path;
            const rawTags = editorTextToRawTags(contents, filePath);
            acc.extend(rawTags);
            return acc;
          },
          initial: [],
          fileTypes: ['.elm'],
          exclude: ['node_modules', 'elm-stuff']
        }
      );
      elm.ports.filesUpdated.send(data);
    }, 0);
  },

  deactivate() {
    this.modalPanel.destroy();
    this.subscriptions.dispose();
    this.elmNavigatorView.destroy();
  },

  serialize() {
    return {
      elmNavigatorViewState: this.elmNavigatorView.serialize()
    };
  },
};

function editorTextToRawTags(text, filePath) {
  const lines = text.split("\n");
  const numLines = lines.length;

  const output = [];

  for (var lineNumber = 0; lineNumber < numLines; lineNumber++) {
    const line = lines[lineNumber];
    const lineType = determineLineType(line);
    if (lineType) {
      output.push({
        type_: lineType.type_,
        context: lineType.context,
        symbol: lineType.symbol,
        filePath: filePath,
        lineNumber: lineNumber,
      });
    }
  }

  return output;
}

function determineLineType(line) {
  for (const regex of regexes) {
    const matches = line.match(regex.regex);
    if (matches) {
      const context = matches[0];
      const symbol = matches[1];
      return {
          type_: regex.type,
          context,
          symbol,
      }
    }
  }
}
<commit_msg>fix JS exception raised after user opens "new window"<commit_after>'use babel';

import fs from 'fs';
import path from 'path';
import ElmNavigatorView from './elm-navigator-view';
import { CompositeDisposable } from 'atom';
import { foldOverDirectoryTree } from './atom-util';
import regexes from './regexes';

Array.prototype.extend = function (other_array) {
    other_array.forEach(function(v) {this.push(v)}, this);
}

var nextNavigatorUpdate = null;

export default {

  elmNavigatorView: null,
  modalPanel: null,
  subscriptions: null,

  activate(state) {
    var project = atom.project;
    var directories = project.getDirectories();
    var projectDirectory = null;
    if (directories.length > 0) {
      projectDirectory = directories[0];
    }

    this.elmNavigatorView = new ElmNavigatorView(
      state.elmNavigatorViewState,
    );

    var elm = this.elmNavigatorView.elm;
    this.elm = elm;
    elm.ports.goToLineInFile.subscribe(function({uri, lineNumber}) {
      atom.workspace.open(uri, { initialLine: lineNumber });
    })

    this.modalPanel = atom.workspace.addRightPanel({
      item: this.elmNavigatorView.getElement(),
      visible: false
    });
    this.modalPanel.show();

    // Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
    this.subscriptions = new CompositeDisposable();

    atom.workspace.observeActivePaneItem(function(activePaneItem) {
      if (typeof(activePaneItem) !== 'undefined') {
        if (typeof(activePaneItem.onDidChange) !== 'undefined') {

          const filePath = activePaneItem.getPath();
          console.log('filePath', filePath);
          if (typeof(filePath) !== 'undefined' && filePath != null) {
            elm.ports.activeFileChanged.send({filePath});
          }

          activePaneItem.onDidChange(function() {
            nextNavigatorUpdate = {
              when: "IN_TWO_TICKS",
              paneItem: activePaneItem
            }
          });
        } else {
            nextNavigatorUpdate = null;
        }
      }
    });

    //TODO: remove interval when deactivated

    (function() {
      const UPDATE_INTERVAL_SECONDS = 0.5;
      setInterval(function() {

        if (nextNavigatorUpdate != null) {
          if (nextNavigatorUpdate.when == "NEXT_TICK") {
            const editorText = nextNavigatorUpdate.paneItem.buffer.cachedText;
            if (editorText != null && typeof(editorText) !== 'unedfined') {
              const filePath = nextNavigatorUpdate.paneItem.getPath();
              const rawTags = editorTextToRawTags(editorText, filePath);
              const payload = { filePath, rawTags };
              elm.ports.fileUpdated.send(payload);
            }
            nextNavigatorUpdate = null;
          } else if (nextNavigatorUpdate.when == "IN_TWO_TICKS") {
            nextNavigatorUpdate.when = "NEXT_TICK"; // it will update in the next tick
          }
        } else {
          // console.log("no navigator update queued");
        }
      }, UPDATE_INTERVAL_SECONDS * 1000);
    })();

    if (projectDirectory != null) {
      setTimeout(function() {
        // setTimeout is an awful hack to delay this expensive synchronous code
        // until after the sidebar has rendered.The better solution is to use
        // async when traversing the directory, which also frees up the UI to
        // do things like display a spinner
        const data = foldOverDirectoryTree(
          {
            directory: projectDirectory,
            func: ({file, contents, acc}) => {
              const filePath = file.path;
              const rawTags = editorTextToRawTags(contents, filePath);
              acc.extend(rawTags);
              return acc;
            },
            initial: [],
            fileTypes: ['.elm'],
            exclude: ['node_modules', 'elm-stuff']
          }
        );
        elm.ports.filesUpdated.send(data);
      }, 0);
    }
  },

  deactivate() {
    this.modalPanel.destroy();
    this.subscriptions.dispose();
    this.elmNavigatorView.destroy();
  },

  serialize() {
    return {
      elmNavigatorViewState: this.elmNavigatorView.serialize()
    };
  },
};

function editorTextToRawTags(text, filePath) {
  const lines = text.split("\n");
  const numLines = lines.length;

  const output = [];

  for (var lineNumber = 0; lineNumber < numLines; lineNumber++) {
    const line = lines[lineNumber];
    const lineType = determineLineType(line);
    if (lineType) {
      output.push({
        type_: lineType.type_,
        context: lineType.context,
        symbol: lineType.symbol,
        filePath: filePath,
        lineNumber: lineNumber,
      });
    }
  }

  return output;
}

function determineLineType(line) {
  for (const regex of regexes) {
    const matches = line.match(regex.regex);
    if (matches) {
      const context = matches[0];
      const symbol = matches[1];
      return {
          type_: regex.type,
          context,
          symbol,
      }
    }
  }
}
<|endoftext|>


<commit_before>'use babel';
'use strict';

var fs = require('fs');
var path = require('path');
var XRegExp = require('xregexp').XRegExp;
var GoogleAnalytics = require('./google-analytics');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var _ = require('lodash');

module.exports = (function () {

  function ErrorMatcher() {
    this.regex = null;
    this.cwd = null;
    this.stdout = null;
    this.stderr = null;
    this.currentMatch = [];
    this.firstMatchId = null;

    atom.commands.add('atom-workspace', 'build:error-match', this.match.bind(this));
    atom.commands.add('atom-workspace', 'build:error-match-first', this.matchFirst.bind(this));
  }

  util.inherits(ErrorMatcher, EventEmitter);

  ErrorMatcher.prototype._gotoNext = function () {
    if (0 === this.currentMatch.length) {
      return;
    }

    this._goto(this.currentMatch[0].id);
  };

  ErrorMatcher.prototype._goto = function (id) {
    var match = _.findWhere(this.currentMatch, { id: id });
    if (!match) {
      throw new Error('Can\'t find match with id ' + id);
    }

    // rotate to next match
    while (this.currentMatch[0] !== match) {
      this.currentMatch.push(this.currentMatch.shift());
    }
    this.currentMatch.push(this.currentMatch.shift());

    if (!match.file) {
      return this.emit('error', 'Did not match any file. Don\'t know what to open.');
    }

    if (!path.isAbsolute(match.file)) {
      match.file = this.cwd + path.sep + match.file;
    }

    var row = match.line ? match.line - 1 : 0; /* Because atom is zero-based */
    var col =  match.col ? match.col - 1 : 0; /* Because atom is zero-based */

    fs.exists(match.file, function (exists) {
      if (!exists) {
        return this.emit('error', 'Matched file does not exist: ' + match.file);
      }
      atom.workspace.open(match.file, {
        initialLine: row,
        initialColumn: col,
        searchAllPanes: true
      });
      this.emit('scroll', match.type, match.id);
    }.bind(this));
  };

  ErrorMatcher.prototype._parse = function () {
    this.currentMatch = [];
    var matchFunction = function (match, i) {
      match.type = 'error';
      match.id = 'error-' + regexIndex + '-' + i;
      this.push(match);
    };
    for (var regexIndex in this.regex) {
      XRegExp.forEach(this.output, this.regex[regexIndex], matchFunction, this.currentMatch);
    }

    this.currentMatch.sort(function(a, b) {
      return a.index - b.index;
    });

    this.firstMatchId = (this.currentMatch.length > 0) ? this.currentMatch[0].id : null;

    var output = '';
    var lastEnd = 0;
    for (var matchIndex in this.currentMatch) {
      var match = this.currentMatch[matchIndex];

      if (match.index < lastEnd) {
        // overlapping matches, only highlight first
        continue;
      }

      output += _.escape(this.output.substr(lastEnd, match.index - lastEnd));
      output += util.format('%s', match.type, match.id, _.escape(match[0]));
      lastEnd = match.index + match[0].length;
    }
    output += _.escape(this.output.substr(lastEnd));

    this.emit('replace', output, this._goto.bind(this));
  };

  ErrorMatcher.prototype.set = function (regex, cwd, output) {
    if (!regex) {
      regex = [];
    }
    regex = (regex instanceof Array) ? regex : [ regex ];

    this.regex = _.compact(regex.map(function(r) {
      try {
        return XRegExp(r);
      } catch (err) {
        this.emit('error', 'Error parsing regex. ' + err.message);
        return null;
      }
    }.bind(this)));

    this.cwd = cwd;
    this.output = output;
    this.currentMatch = [];

    this._parse();
  };

  ErrorMatcher.prototype.match = function () {
    GoogleAnalytics.sendEvent('errorMatch', 'match');

    this._gotoNext();
  };

  ErrorMatcher.prototype.matchFirst = function () {
    GoogleAnalytics.sendEvent('errorMatch', 'first');

    if (this.firstMatchId) {
      this._goto(this.firstMatchId);
    }
  };

  return ErrorMatcher;
})();
<commit_msg>emit instead of throw<commit_after>'use babel';
'use strict';

var fs = require('fs');
var path = require('path');
var XRegExp = require('xregexp').XRegExp;
var GoogleAnalytics = require('./google-analytics');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var _ = require('lodash');

module.exports = (function () {

  function ErrorMatcher() {
    this.regex = null;
    this.cwd = null;
    this.stdout = null;
    this.stderr = null;
    this.currentMatch = [];
    this.firstMatchId = null;

    atom.commands.add('atom-workspace', 'build:error-match', this.match.bind(this));
    atom.commands.add('atom-workspace', 'build:error-match-first', this.matchFirst.bind(this));
  }

  util.inherits(ErrorMatcher, EventEmitter);

  ErrorMatcher.prototype._gotoNext = function () {
    if (0 === this.currentMatch.length) {
      return;
    }

    this._goto(this.currentMatch[0].id);
  };

  ErrorMatcher.prototype._goto = function (id) {
    var match = _.findWhere(this.currentMatch, { id: id });
    if (!match) {
      return this.emit('error', 'Can\'t find match with id ' + id);
    }

    // rotate to next match
    while (this.currentMatch[0] !== match) {
      this.currentMatch.push(this.currentMatch.shift());
    }
    this.currentMatch.push(this.currentMatch.shift());

    if (!match.file) {
      return this.emit('error', 'Did not match any file. Don\'t know what to open.');
    }

    if (!path.isAbsolute(match.file)) {
      match.file = this.cwd + path.sep + match.file;
    }

    var row = match.line ? match.line - 1 : 0; /* Because atom is zero-based */
    var col =  match.col ? match.col - 1 : 0; /* Because atom is zero-based */

    fs.exists(match.file, function (exists) {
      if (!exists) {
        return this.emit('error', 'Matched file does not exist: ' + match.file);
      }
      atom.workspace.open(match.file, {
        initialLine: row,
        initialColumn: col,
        searchAllPanes: true
      });
      this.emit('scroll', match.type, match.id);
    }.bind(this));
  };

  ErrorMatcher.prototype._parse = function () {
    this.currentMatch = [];
    var matchFunction = function (match, i) {
      match.type = 'error';
      match.id = 'error-' + regexIndex + '-' + i;
      this.push(match);
    };
    for (var regexIndex in this.regex) {
      XRegExp.forEach(this.output, this.regex[regexIndex], matchFunction, this.currentMatch);
    }

    this.currentMatch.sort(function(a, b) {
      return a.index - b.index;
    });

    this.firstMatchId = (this.currentMatch.length > 0) ? this.currentMatch[0].id : null;

    var output = '';
    var lastEnd = 0;
    for (var matchIndex in this.currentMatch) {
      var match = this.currentMatch[matchIndex];

      if (match.index < lastEnd) {
        // overlapping matches, only highlight first
        continue;
      }

      output += _.escape(this.output.substr(lastEnd, match.index - lastEnd));
      output += util.format('%s', match.type, match.id, _.escape(match[0]));
      lastEnd = match.index + match[0].length;
    }
    output += _.escape(this.output.substr(lastEnd));

    this.emit('replace', output, this._goto.bind(this));
  };

  ErrorMatcher.prototype.set = function (regex, cwd, output) {
    if (!regex) {
      regex = [];
    }
    regex = (regex instanceof Array) ? regex : [ regex ];

    this.regex = _.compact(regex.map(function(r) {
      try {
        return XRegExp(r);
      } catch (err) {
        this.emit('error', 'Error parsing regex. ' + err.message);
        return null;
      }
    }.bind(this)));

    this.cwd = cwd;
    this.output = output;
    this.currentMatch = [];

    this._parse();
  };

  ErrorMatcher.prototype.match = function () {
    GoogleAnalytics.sendEvent('errorMatch', 'match');

    this._gotoNext();
  };

  ErrorMatcher.prototype.matchFirst = function () {
    GoogleAnalytics.sendEvent('errorMatch', 'first');

    if (this.firstMatchId) {
      this._goto(this.firstMatchId);
    }
  };

  return ErrorMatcher;
})();
<|endoftext|>