/home/arranoyd/magicraft/wp-content/plugins/note/assets/js/note-tinymce-background.js
/**
 * Note TinyMCE Background Plugin
 */

tinymce.PluginManager.add( 'note_background', function( editor ) {
	'use strict';

	var DOM = tinymce.DOM,
		$ = jQuery,
		api = wp.customize, // Customizer API
		NotePreview = api.NotePreview, // NotePreview
		$el = $( editor.getElement() ),
		$note_widget = $el.parents( '.note-widget' ),
		$note_wrapper = $note_widget.find( '.note-wrapper' ),
		has_background_attachment = false,
		background_attachment = {},
		background_attachment_id,
		background_attachment_size = 'full', // Default to 'full'
		note_widget_data,
		//add_background_button,
		//remove_background_button,
		frame,
		state,
		selection;


	/*
	 * TinyMCE Editor Events
	 */

	// Init event
	editor.on( 'init', function() {
		var widget_number = editor.note.widget_number,
			widget_settings = note.widgets.settings[widget_number];

		// Clone the original Note Widget data (deep copy; used throughout this plugin to "reset" the data when necessary)
		note_widget_data = $.extend( true, {}, editor.note.widget_data );

		// If we have an initial background image attachment ID
		if ( widget_settings.extras && widget_settings.extras.background_image_attachment_id ) {
			has_background_attachment = true; // Set the background image flag
			background_attachment_id = widget_settings.extras.background_image_attachment_id; // Store a reference to the initial background image attachment ID
			background_attachment = wp.media.model.Attachment.get( background_attachment_id ); // Store a reference to the initial background image
		}

		// Store global references to the add/remove background buttons
		//add_background_button = getNoteInsertToolbarButton( 'note_background' );
		//remove_background_button = getNoteInsertToolbarButton( 'note_background_remove' );

		/*
		 * Send the initial note-widget-update command to the Customizer. The current way that
		 * Note logic is implemented, expects that the data should be different on subsequent updates,
		 * however the initial data is populated with the first note-widget-update command data.
		 */
		// TODO: See function docs below for revamp notes
		noteUpdateBackgroundImage( {
			attachment_id: background_attachment_id
		} );
	} );


	/*******************
	 * Note Background *
	 *******************/

	// Note Background
	editor.addButton( 'note_background', {
		// id: 'note_background', TODO: Not currently used; TinyMCE doesn't add the tooltips on multiple editors when this is set
		tooltip: 'Edit Background Image', // TODO: i18n, l10n
		icon: 'format-image dashicons-format-image',
		onclick: function() {
			var library, library_comparator;

			// If we don't have focus
			if ( ! DOM.hasClass( editor.getBody(), 'mce-edit-focus' ) ) {
				// Focus the editor (skip focusing and just set the active editor)
				editor.focus( true );

				// Since we're skipping the DOM focusing, we need to set the global wpActiveEditor ID, which is used as a fallback when WordPress is determining the active TinyMCE editor (@see https://github.com/WordPress/WordPress/blob/4.5-branch/wp-includes/js/tinymce/plugins/wordpress/plugin.js#L89)
				window.wpActiveEditor = editor.id;
			}

			// If we don't have a frame, attach a media frame to the editor now
			if ( ! frame ) {
				// Create the media frame
				editor.note.media.frame = frame = wp.media.editor.add( editor.id, {
					id: 'note-background', // Unique ID for this frame
					state: 'note-background', // Custom Note state
					frame: 'select', // Select state for frame
					// States attached to this frame
					states: [
						// Note Background state
						new wp.media.controller.Library( {
							id: 'note-background',
							title: 'Select a Background Image', // TODO: I18n & l10n
							priority: 10,
							filterable: 'all',
							library: wp.media.query( { type: 'image' } ),
							multiple: false, // Only allow one selection
							editable: false,
							sidebar: false,
							displaySettings: false,
							displayUserSettings: false,
							syncSelection: true,
							has_background_attachment: has_background_attachment
						 } )
					],
					// Frame button configuration
					button: {
						text: 'Save', // Button label // TODO: I18n & l10n
						event: 'select', // Trigger the select event on click
						reset: false, // Don't reset the selection upon closing
						requires: {
							selection: false // This button does not require a selection to be made in order to be active
						}
					}
				} );

				// Store a reference to the library and the library comparator
				library = frame.state().get( 'library' );
				library_comparator = library.comparator;

				// Adjust the comparator to ensure that items that are not in the current query are pushed to the top of the list (i.e. the selected background image)
				// https://github.com/WordPress/WordPress/blob/8dd2a31c389795c3f3c84fa4f812e19aac183392/wp-includes/js/media-views.js#L690
				// TODO: WordPress attribution
				library.comparator = function( a, b ) {
					var aInQuery = !! this.mirroring.get( a.cid ),
						bInQuery = !! this.mirroring.get( b.cid );

					if ( ! aInQuery && bInQuery ) {
						return -1;
					}
					else if ( aInQuery && ! bInQuery ) {
						return 1;
					}
					else {
						return library_comparator.apply( this, arguments );
					}
				};

				// Observe the selection and ensure that the background image is loaded initially (even if it is not in the current query)
				// https://github.com/WordPress/WordPress/blob/8dd2a31c389795c3f3c84fa4f812e19aac183392/wp-includes/js/media-views.js#L705
				library.observe( frame.state().get('selection') ); // TODO: Not loading the image properly

				// Store references to the frame state and selection
				state = frame.state();
				selection = state.get( 'selection' );


				/*******************************
				 * Media Frame Event Listeners *
				 *******************************/

				// Frame Open (Once)
				frame.once( 'open', function() {
					// Initial open event, if we have a background image attachment ID
					if ( selection && has_background_attachment ) {
						// Reset the selection
						selection.reset( [ background_attachment ] );
					}
				} );

				// Frame Open (ensure the the background image data is always fetched if we have one set)
				frame.on( 'open', function() {
					// If we have an attachment
					if ( has_background_attachment && ! _.isEmpty( background_attachment ) ) {
						// Fetch the data
						background_attachment.fetch();

						selection.reset( background_attachment ? [ background_attachment ] : [] );
					}
				} );

				// Frame Escape (clicking on the "close" button)
				frame.on( 'escape', function() {
					// If we have an attachment selected and an initial background image attachment ID
					if ( has_background_attachment ) {
						// Reset the selection
						selection.reset( [ background_attachment ] );
					}
					else {
						// Reset the selection
						selection.reset();
					}
				} );

				// Frame Select, when a selection is made
				frame.on( 'select', function() {
					var attachment = selection.first();

					// Attachment details
					if ( attachment ) {
						has_background_attachment = true; // Set the background image flag
						background_attachment = attachment; // Store a reference to the background image attachment
						background_attachment_id = attachment.get( 'id' ); // Store a reference to the background image attachment ID

						// Add the background image to the editor
						$note_wrapper.css( 'background', 'url(' + attachment.get( 'sizes' )[background_attachment_size].url + ') ' + editor.note.background_image_css );
					}
					else {
						has_background_attachment = false; // Reset the background image flag
						background_attachment = {}; // Reset the background image attachment
						background_attachment_id = false; // Reset the background image attachment ID

						// Remove any background images from the editor
						$note_wrapper.css( 'background', '' );

						// Remove any existing <style> blocks (exist after the wrapper element) TODO: Use jQuery.next() here instead?
						$note_wrapper.parent().find( 'style.note-background-css' ).remove();
					}

					// TODO: Only send this data if the data has changed from the widget settings
					// Send the note-widget-update command to the Customizer with updated background data
					noteUpdateBackgroundImage( {
						attachment_id: background_attachment_id
					} );
				} );

				// Selection Change Sizes (Once)
				/*selection.once( 'change:sizes', function( event ) {
					var content = frame.views.get( frame.content.selector )[0], // We get an array from the frame
						sidebar = content.sidebar,
						display = sidebar.get( 'display' );

					// Re-render the sidebar attachment display view to ensure the display attachment details are populated correctly
					display.render();
				} );*/

				// If the frame is not attached
				if ( ! frame.modal.views.attached ) {
					// Attach the frame (fixes a bug in FireFox and IE where the $el is initially visible so the rendering process is never completed @see https://github.com/WordPress/WordPress/blob/4.5-branch/wp-includes/js/media-views.js#L6764)
					frame.attach();
				}
			}

			// Open the frame for this editor (wp.media.editor.open() fixes a bug where images could be inserted into the wrong editor due to the active editor reference being incorrect; @see https://github.com/WordPress/WordPress/blob/703d5bdc8deb17781e9c6d8f0dd7e2c6b6353885/wp-includes/js/media-editor.js#L1062)
			wp.media.editor.open( editor.id );

			// Fire an event on the editor (pass an empty array of data and the frame)
			editor.fire( 'wpLoadImageForm', { data : [], frame: frame } );
		}
	} );

	// Note Background Remove
	/*editor.addButton( 'note_background_remove', {
		id: 'note_background_remove',
		tooltip: 'Remove Background Image', // TODO: i18n, l10n
		icon: 'dashicons-format-image dashicons-no note-remove-background',
		onclick: function () {
			// Reset all of the global flags
			has_background_attachment = false; // Reset the background image flag
			background_attachment = {}; // Reset the background image attachment
			background_attachment_id = false; // Reset the background image attachment ID
			background_attachment_size = 'full'; // Reset the background image attachment size (defaults to 'full' on sanitization)

			// Remove any background images from the editor (also overrides <style> block output from widget)
			$note_wrapper.css( 'background', 'transparent' );

			// Reset the selection
			selection.reset();

			// Disable the remove background button
			setToolbarButtonDisabledState( remove_background_button, true );

			// Send the note-widget-update command to the Customizer with updated background data
			noteUpdateBackgroundImage( {
				attachment_id: background_attachment_id,
				attachment_size: background_attachment_size
			} );
		}
	} );*/


	/**********************
	 * Internal Functions *
	 **********************/

	/**
	 * This function uses Note Widgets as a transport to send background image data over to the Customizer.
	 */
	// TODO: Optimize logic in Note to allow for a more robust transport layer (i.e. to send this data in one call, not having to reset data, etc...)
	function noteUpdateBackgroundImage( background_data ) {
		// Set the local focused flag
		NotePreview.is_widget_focused = true;

		// Send the note-widget-focus event
		NotePreview.preview.send( 'note-widget-focus', editor.note.widget_data );


		/*
		 * Background Image Attachment ID
		 */
		// Adjust the editor Note Widget data
		editor.note.widget_data.widget.content = background_data.attachment_id;
		editor.note.widget_data.selectors.widget_content = '.note-background-image-id';
		editor.note.widget_data.selectors.widget_content_data = 'note-background-image-id';

		// Send data to the Customizer
		NotePreview.preview.send( 'note-widget-update', editor.note.widget_data );


		// Reset the editor Note Widget data (global note_widget_data; clone deep)
		editor.note.widget_data = $.extend( true, {},  note_widget_data );

		// Reset the local focused flag
		NotePreview.is_widget_focused = false;

		// Send the note-widget-blur event
		NotePreview.preview.send( 'note-widget-blur', editor.note.widget_data );
	}

	/**
	 * This function returns toolbar buttons from the Note insert panel.
	 */
	function getNoteInsertToolbarButton( id ) {
		var insert_panel = editor.note.insert_panel,
			items = insert_panel.items(),
			panel_items, the_item = false;

		// Note/TinyMCE return a toolbar in the first item set
		if ( items && items[0] ) {
			// Fetch the individual panel items
			panel_items = items[0].items();
		}

		// If we have panel items
		if ( panel_items ) {
			// Loop through items
			tinymce.each( panel_items, function( item ) {
				// If this setting ID matches the passed in ID or the icon class names
				if ( ( item.settings.id && item.settings.id === id ) || ( item.settings.icon && item.settings.icon.indexOf( id ) ) ) {
					the_item = item;
				}
			} );
		}

		return the_item;
	}

	/**
	 * This function sets the disabled state on buttons based on parameters
	 */
	function setToolbarButtonDisabledState( button, state ) {
		// Disable/enable the button
		button.disabled( state );

		// Adjust the tab index
		DOM.setAttrib( button.getEl(), 'tabindex', ( state ) ? '0' : '-1' );
	}
} );