diff options
Diffstat (limited to 'plugins/jetpack/modules/videopress/js/videopress-admin.js')
-rw-r--r-- | plugins/jetpack/modules/videopress/js/videopress-admin.js | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/plugins/jetpack/modules/videopress/js/videopress-admin.js b/plugins/jetpack/modules/videopress/js/videopress-admin.js new file mode 100644 index 00000000..c7851117 --- /dev/null +++ b/plugins/jetpack/modules/videopress/js/videopress-admin.js @@ -0,0 +1,502 @@ +/* jshint onevar: false, smarttabs: true, devel: true */ +/* global VideoPressAdminSettings, setUserSetting */ + +/** + * VideoPress Admin + * + * @todo i18n + */ +(function($) { + var media = wp.media; + var VideoPress = VideoPress || {}; + + VideoPress.caps = VideoPressAdminSettings.caps; + VideoPress.l10n = VideoPressAdminSettings.l10n; + + /** + * Create a new controller that simply adds a videopress key + * to the library query + */ + media.controller.VideoPress = media.controller.Library.extend({ + defaults: _.defaults({ + id: 'videopress', + router: 'videopress', + toolbar: 'videopress-toolbar', + title: 'VideoPress', + priority: 200, + searchable: true, + sortable: false + }, media.controller.Library.prototype.defaults ), + + initialize: function() { + if ( ! this.get('library') ) { + this.set( 'library', media.query({ videopress: true }) ); + } + + media.controller.Library.prototype.initialize.apply( this, arguments ); + }, + + /** + * The original function saves content for the browse router only, + * so we hi-jack it a little bit. + */ + saveContentMode: function() { + if ( 'videopress' !== this.get('router') ) { + return; + } + + var mode = this.frame.content.mode(), + view = this.frame.router.get(); + + if ( view && view.get( mode ) ) { + + // Map the Upload a Video back to the regular Upload Files. + if ( 'upload_videopress' === mode ) { + mode = 'upload'; + } + + setUserSetting( 'libraryContent', mode ); + } + } + }); + + /** + * VideoPress Uploader + */ + media.view.VideoPressUploader = media.View.extend({ + tagName: 'div', + className: 'uploader-videopress', + template: media.template('videopress-uploader'), + + events: { + 'submit .videopress-upload-form': 'submitForm' + }, + + initialize: function() { + var that = this; + + if ( ! window.addEventListener ) { + window.attachEvent( 'onmessage', function() { return that.messageHandler.apply( that, arguments ); } ); + } else { + window.addEventListener( 'message', function() { return that.messageHandler.apply( that, arguments ); }, false ); + } + + return media.View.prototype.initialize.apply( this, arguments ); + }, + + submitForm: function() { + var data = false; + + this.clearErrors(); + + if ( this.$( 'input[name="videopress_file"]').val().length < 1 ) { + this.error( VideoPress.l10n.selectVideoFile ); + return false; + } + + // Prevent multiple submissions. + this.$( '.videopress-upload-form .button' ).prop( 'disabled', true ); + + // A non-async request for an upload token. + media.ajax( 'videopress-get-upload-token', { async: false } ).done( function( response ) { + data = response; + data.success = true; + }).fail( function( response ) { + data = response; + data.success = false; + }); + + if ( ! data.success ) { + // Re-enable form elements. + this.$( '.videopress-upload-form .button' ).prop( 'disabled', false ); + + // Display an error message and cancel form submission. + this.error( data.message ); + return false; + } + + this.error( VideoPress.l10n.videoUploading, 'updated' ); + + // Set the form token. + this.$( 'input[name="videopress_blog_id"]' ).val( data.videopress_blog_id ); + this.$( 'input[name="videopress_token"]' ).val( data.videopress_token ); + this.$( '.videopress-upload-form' ).attr( 'action', data.videopress_action_url ); + return true; + }, + + error: function( message, type ) { + type = type || 'error'; + var div = $( '<div />' ).html( $( '<p />' ).text( message ) ).addClass( type ); + this.$( '.videopress-errors' ).html( div ); + return this; + }, + + success: function( message ) { + return this.error( message, 'updated' ); + }, + + clearErrors: function() { + this.$( '.videopress-errors' ).html(''); + return this; + }, + + messageHandler: function( event ) { + if ( ! event.origin.match( /\.wordpress\.com$/ ) ) { + return; + } + + if ( event.data.indexOf && event.data.indexOf( 'vpUploadResult::' ) === 0 ) { + var result = JSON.parse( event.data.substr( 16 ) ); + + if ( ! result || ! result.code ) { + this.error( VideoPress.l10n.unknownError ); + this.$( '.videopress-upload-form .button' ).prop( 'disabled', false ); + return; + } + + if ( 'success' === result.code && result.data ) { + var that = this, controller = this.controller, + state = controller.states.get( 'videopress' ); + + // Our new video has been added, so we need to reset the library. + // Since the Media API caches all queries, we add a random attribute + // to avoid the cache, then call more() to actually fetch the data. + + state.set( 'library', media.query({ videopress:true, vp_random:Math.random() }) ); + state.get( 'library' ).more().done(function(){ + var model = state.get( 'library' ).get( result.data.attachment_id ); + + // Clear errors and select the uploaded item. + that.clearErrors(); + state.get( 'selection' ).reset([ model ]); + controller.content.mode( 'browse' ); + }); + } else { + this.error( result.code ); + + // Re-enable form elements. + this.$( '.videopress-upload-form .button' ).prop( 'disabled', false ); + } + } + } + }); + + /** + * Add a custom sync function that would add a few extra + * options for models which are VideoPress videos. + */ + var attachmentSync = media.model.Attachment.prototype.sync; + media.model.Attachment.prototype.sync = function( method, model, options ) { + if ( model.get( 'vp_isVideoPress' ) ) { + console.log( 'syncing ' + model.get( 'vp_guid' ) ); + options.data = _.extend( options.data || {}, { + is_videopress: true, + vp_nonces: model.get( 'vp_nonces' ) + } ); + } + + // Call the original sync routine. + return attachmentSync.apply( this, arguments ); + }; + + /** + * Extend the default Attachment Details view. Check for vp_isVideoPress before + * adding anything to these methods. + */ + var AttachmentDetails = media.view.Attachment.Details; + media.view.Attachment.Details = AttachmentDetails.extend({ + + initialize: function() { + if ( this.model.get( 'vp_isVideoPress' ) ) { + _.extend( this.events, { + 'click a.videopress-preview': 'vpPreview', + 'change .vp-radio': 'vpRadioChange', + 'change .vp-checkbox': 'vpCheckboxChange' + }); + } + return AttachmentDetails.prototype.initialize.apply( this, arguments ); + }, + + render: function() { + var r = AttachmentDetails.prototype.render.apply( this, arguments ); + if ( this.model.get( 'vp_isVideoPress' ) ) { + var template = media.template( 'videopress-attachment' ); + var options = this.model.toJSON(); + + options.can = {}; + options.can.save = !! options.nonces.update; + + this.$el.append( template( options ) ); + } + return r; + }, + + // Handle radio buttons + vpRadioChange: function(e) { + $( e.target ).parents( '.vp-setting' ).find( '.vp-radio-text' ).val( e.target.value ).change(); + }, + + // And checkboxes + vpCheckboxChange: function(e) { + $( e.target ).parents( '.vp-setting' ).find( '.vp-checkbox-text' ).val( Number( e.target.checked ) ).change(); + }, + + vpPreview: function() { + VideoPressModal.render( this ); + return this; + } + }); + + /** + * Don't display the uploader dropzone for the VideoPress router. + */ + var UploaderWindow = media.view.UploaderWindow; + media.view.UploaderWindow = UploaderWindow.extend({ + show: function() { + if ( 'videopress' !== this.controller.state().get('id') ) { + UploaderWindow.prototype.show.apply( this, arguments ); + } + + return this; + } + }); + + /** + * Don't display the uploader in the attachments browser. + */ + var AttachmentsBrowser = media.view.AttachmentsBrowser; + media.view.AttachmentsBrowser = AttachmentsBrowser.extend({ + /** + * Snag the Core 3.9.2 versions as a quick fix to avoid + * the breakage introduced by r29364-core + */ + updateContent: function() { + var view = this; + + if( ! this.attachments ) { + this.createAttachments(); + } + + if ( ! this.collection.length ) { + this.toolbar.get( 'spinner' ).show(); + this.collection.more().done(function() { + if ( ! view.collection.length ) { + view.createUploader(); + } + view.toolbar.get( 'spinner' ).hide(); + }); + } else { + view.toolbar.get( 'spinner' ).hide(); + } + }, + /** + * Empty out to avoid breakage. + */ + toggleUploader: function() {}, + createUploader: function() { + if ( 'videopress' !== this.controller.state().get('id') ) { + return AttachmentsBrowser.prototype.createUploader.apply( this, arguments ); + } + } + }); + + /** + * Add VideoPress-specific methods for all frames. + */ + _.extend( media.view.MediaFrame.prototype, { VideoPress: { // this.VideoPress.method() + + // When the VideoPress router is activated. + activate: function() { + var view = _.first( this.views.get( '.media-frame-router' ) ), + viewSettings = {}; + + if ( VideoPress.caps.read_videos ) { + viewSettings.browse = { text: VideoPress.l10n.VideoPressLibraryRouter, priority: 40 }; + } + + if ( VideoPress.caps.upload_videos ) { + viewSettings.upload_videopress = { text: VideoPress.l10n.uploadVideoRouter, priority: 20 }; + } + + view.set( viewSettings ); + + // Intercept and clear all incoming uploads + wp.Uploader.queue.on( 'add', this.VideoPress.disableUpload, this ); + + // Map the Upload Files view to the Upload a Video one (upload_videopress vs. upload) + if ( 'upload' === this.content.mode() && VideoPress.caps.upload_videos ) { + this.content.mode( 'upload_videopress' ); + } else { + this.content.mode( 'browse' ); + } + }, + + // When navigated away from the VideoPress router. + deactivate: function( /*view*/ ) { + wp.Uploader.queue.off( 'add', this.VideoPress.disableUpload ); + }, + + // Disable dragdrop uploads in the VideoPress router. + disableUpload: function( attachment ) { + var uploader = this.uploader.uploader.uploader; + uploader.stop(); + uploader.splice(); + attachment.destroy(); + }, + + // Runs on videopress:insert event fired by our custom toolbar + insert: function( selection ) { + var guid = selection.models[0].get( 'vp_guid' ).replace( /[^a-zA-Z0-9]+/, '' ); + media.editor.insert( '[wpvideo ' + guid + ']' ); + return this; + }, + + // Triggered by the upload_videopress router item. + uploadVideo: function() { + this.content.set( new media.view.VideoPressUploader({ + controller: this + }) ); + return this; + }, + + // Create a custom toolbar + createToolbar: function( /*toolbar*/ ) { + // Alow an option to hide the toolbar. + if ( this.options.VideoPress && this.options.VideoPress.hideToolbar ) { + return this; + } + + var controller = this; + this.toolbar.set( new media.view.Toolbar({ + controller: this, + items: { + insert: { + style: 'primary', + text: VideoPress.l10n.insertVideoButton, + priority: 80, + requires: { + library: true, + selection: true + }, + + click: function() { + var state = controller.state(), + selection = state.get('selection'); + + controller.close(); + state.trigger( 'videopress:insert', selection ).reset(); + } + } + } + }) ); + } + }}); + + var MediaFrame = {}; + + /** + * Extend the selection media frame + */ + MediaFrame.Select = media.view.MediaFrame.Select; + media.view.MediaFrame.Select = MediaFrame.Select.extend({ + bindHandlers: function() { + MediaFrame.Select.prototype.bindHandlers.apply( this, arguments ); + + this.on( 'router:create:videopress', this.createRouter, this ); + this.on( 'router:activate:videopress', this.VideoPress.activate, this ); + this.on( 'router:deactivate:videopress', this.VideoPress.deactivate, this ); + + this.on( 'content:render:upload_videopress', this.VideoPress.uploadVideo, this ); + this.on( 'toolbar:create:videopress-toolbar', this.VideoPress.createToolbar, this ); + this.on( 'videopress:insert', this.VideoPress.insert, this ); + } + }); + + /** + * Extend the post editor media frame with our own + */ + MediaFrame.Post = media.view.MediaFrame.Post; + media.view.MediaFrame.Post = MediaFrame.Post.extend({ + createStates: function() { + MediaFrame.Post.prototype.createStates.apply( this, arguments ); + this.states.add([ new media.controller.VideoPress() ]); + } + }); + + /** + * A VideoPress Modal view that we can use to preview videos. + * Expects a controller object on render. + */ + var VideoPressModalView = Backbone.View.extend({ + 'className': 'videopress-modal-container', + 'template': wp.media.template( 'videopress-media-modal' ), + + // Render the VideoPress modal with a video object by guid. + render: function( controller ) { + this.delegateEvents( { + 'click .videopress-modal-close': 'closeModal', + 'click .videopress-modal-backdrop': 'closeModal' + } ); + + this.model = controller.model; + this.guid = this.model.get( 'vp_guid' ); + + if ( ! this.$frame ) { + this.$frame = $( '.media-frame-content' ); + } + + this.$el.html( this.template( { 'video' : this.model.get( 'vp_embed' ) } ) ); + this.$modal = this.$( '.videopress-modal' ); + this.$modal.hide(); + + this.$frame.append( this.$el ); + this.$modal.slideDown( 'fast' ); + + return this; + }, + + closeModal: function() { + var view = this; + this.$modal.slideUp( 'fast', function() { view.remove(); } ); + return this; + } + }); + + var VideoPressModal = new VideoPressModalView(); + + // Configuration screen behavior + $(document).on( 'ready', function() { + var $form = $( '#videopress-settings' ); + + // Not on a configuration screen + if ( ! $form.length ) { + return; + } + + var $access = $form.find( 'input[name="videopress-access"]' ), + $upload = $form.find( 'input[name="videopress-upload"]' ); + + $access.on( 'change', function() { + var access = $access.filter( ':checked' ).val(); + $upload.attr( 'disabled', ! access ); + + if ( ! access ) { + $upload.attr( 'checked', false ); + } + }); + + $access.trigger( 'change' ); + }); + + // Media -> VideoPress menu + $(document).on( 'click', '#videopress-browse', function() { + + wp.media({ + state: 'videopress', + states: [ new media.controller.VideoPress() ], + VideoPress: { hideToolbar: true } + }).open(); + + return false; + }); +})(jQuery); |