+// This is the view that controls each theme item
+// that will be displayed on the screen
+themes.view.Theme = wp.Backbone.View.extend({
+
+ // Wrap theme data on a div.theme element
+ className: 'theme',
+
+ // Reflects which theme view we have
+ // 'grid' (default) or 'detail'
+ state: 'grid',
+
+ // The HTML template for each element to be rendered
+ html: themes.template( 'theme' ),
+
+ events: {
+ 'click': 'expand',
+ 'touchend': 'expand',
+ 'touchmove': 'preventExpand'
+ },
+
+ touchDrag: false,
+
+ render: function() {
+ var data = this.model.toJSON();
+ // Render themes using the html template
+ this.$el.html( this.html( data ) );
+ // Renders active theme styles
+ this.activeTheme();
+
+ if ( this.model.get( 'displayAuthor' ) ) {
+ this.$el.addClass( 'display-author' );
+ }
+ },
+
+ // Adds a class to the currently active theme
+ // and to the overlay in detailed view mode
+ activeTheme: function() {
+ if ( this.model.get( 'active' ) ) {
+ this.$el.addClass( 'active' );
+ }
+ },
+
+ // Single theme overlay screen
+ // It's shown when clicking a theme
+ expand: function( event ) {
+ var self = this;
+
+ // Bail if the user scrolled on a touch device
+ if ( this.touchDrag === true ) {
+ return this.touchDrag = false;
+ }
+
+ event = event || window.event;
+
+ // Prevent the modal from showing when the user clicks
+ // one of the direct action buttons
+ if ( $( event.target ).is( '.theme-actions a' ) ) {
+ return;
+ }
+
+ this.trigger( 'theme:expand', self.model.cid );
+ },
+
+ preventExpand: function() {
+ this.touchDrag = true;
+ }
+});
+
+// Theme Details view
+// Set ups a modal overlay with the expanded theme data
+themes.view.Details = wp.Backbone.View.extend({
+
+ // Wrap theme data on a div.theme element
+ className: 'theme-overlay',
+
+ events: {
+ 'click': 'collapse',
+ 'click .delete-theme': 'deleteTheme',
+ 'click .left': 'previousTheme',
+ 'click .right': 'nextTheme'
+ },
+
+ // The HTML template for the theme overlay
+ html: themes.template( 'theme-single' ),
+
+ render: function() {
+ var data = this.model.toJSON();
+ this.$el.html( this.html( data ) );
+ // Renders active theme styles
+ this.activeTheme();
+ // Set up navigation events
+ this.navigation();
+ // Checks screenshot size
+ this.screenshotCheck( this.$el );
+ },
+
+ // Adds a class to the currently active theme
+ // and to the overlay in detailed view mode
+ activeTheme: function() {
+ // Check the model has the active property
+ this.$el.toggleClass( 'active', this.model.get( 'active' ) );
+ },
+
+ // Single theme overlay screen
+ // It's shown when clicking a theme
+ collapse: function( event ) {
+ var self = this,
+ scroll;
+
+ event = event || window.event;
+
+ // Prevent collapsing detailed view when there is only one theme available
+ if ( themes.data.themes.length === 1 ) {
+ return;
+ }
+
+ // Detect if the click is inside the overlay
+ // and don't close it unless the target was
+ // the div.back button
+ if ( $( event.target ).is( '.theme-backdrop' ) || $( event.target ).is( 'div.close' ) || event.keyCode === 27 ) {
+
+ // Add a temporary closing class while overlay fades out
+ $( 'body' ).addClass( 'closing-overlay' );
+
+ // With a quick fade out animation
+ this.$el.fadeOut( 130, function() {
+ // Clicking outside the modal box closes the overlay
+ $( 'body' ).removeClass( 'theme-overlay-open closing-overlay' );
+ // Handle event cleanup
+ self.closeOverlay();
+
+ // Get scroll position to avoid jumping to the top
+ scroll = document.body.scrollTop;
+
+ // Clean the url structure
+ themes.router.navigate( themes.router.baseUrl( '' ), { replace: true } );
+
+ // Restore scroll position
+ document.body.scrollTop = scroll;
+ });
+ }
+ },
+
+ // Handles .disabled classes for next/previous buttons
+ navigation: function() {
+
+ // Disable Left/Right when at the start or end of the collection
+ if ( this.model.cid === this.model.collection.at(0).cid ) {
+ this.$el.find( '.left' ).addClass( 'disabled' );
+ }
+ if ( this.model.cid === this.model.collection.at( this.model.collection.length - 1 ).cid ) {
+ this.$el.find( '.right' ).addClass( 'disabled' );
+ }
+ },
+
+ // Performs the actions to effectively close
+ // the theme details overlay
+ closeOverlay: function() {
+ this.remove();
+ this.unbind();
+ this.trigger( 'theme:collapse' );
+ },
+
+ // Confirmation dialoge for deleting a theme
+ deleteTheme: function() {
+ return confirm( themes.data.settings.confirmDelete );
+ },
+
+ nextTheme: function() {
+ var self = this;
+ self.trigger( 'theme:next', self.model.cid );
+ },
+
+ previousTheme: function() {
+ var self = this;
+ self.trigger( 'theme:previous', self.model.cid );
+ },
+
+ // Checks if the theme screenshot is the old 300px width version
+ // and adds a corresponding class if it's true
+ screenshotCheck: function( el ) {
+ var screenshot, image;
+
+ screenshot = el.find( '.screenshot img' );
+ image = new Image();
+ image.src = screenshot.attr( 'src' );
+
+ // Width check
+ if ( image.width && image.width <= 300 ) {
+ el.addClass( 'small-screenshot' );
+ }
+ }
+});
+
+// Controls the rendering of div.themes,
+// a wrapper that will hold all the theme elements
+themes.view.Themes = wp.Backbone.View.extend({
+
+ className: 'themes',
+ $overlay: $( 'div.theme-overlay' ),
+
+ // Number to keep track of scroll position
+ // while in theme-overlay mode
+ index: 0,
+
+ // The theme count element
+ count: $( '.theme-count' ),
+
+ initialize: function( options ) {
+ var self = this;
+
+ // Set up parent
+ this.parent = options.parent;
+
+ // Set current view to [grid]
+ this.setView( 'grid' );
+
+ // Move the active theme to the beginning of the collection
+ self.currentTheme();
+
+ // When the collection is updated by user input...
+ this.listenTo( self.collection, 'update', function() {
+ self.parent.page = 0;
+ self.currentTheme();
+ self.render( this );