Make WordPress Core

Opened 11 years ago

Closed 10 years ago

#28190 closed defect (bug) (fixed)

Support for mediaelement.js YouTube sources in the video shortcode does not work in TinyMce

Reported by: fab1en's profile Fab1en Owned by:
Milestone: 4.0 Priority: normal
Severity: normal Version: 3.9
Component: Media Keywords: has-patch
Focuses: javascript, administration Cc:

Description

When using a youtube URL within a video shortcode, the mediaelement.js player does not work inside TinyMce. It does work on the front end, or when the "Edit" button of the mceView is clicked.

 [video src="http://www.youtube.com/watch?v=yeJYVzLFLhk"]

Inside TinyMce, it shows the row URL, as if the URL was not recognized as a video one.

Attachments (5)

patch.diff (1.3 KB) - added by lukecarbis 11 years ago.
28190.diff (1.7 KB) - added by wonderboymusic 11 years ago.
28190-2.diff (4.5 KB) - added by Fab1en 10 years ago.
Make YouTube video play inside tinymce
28190.2.diff (5.2 KB) - added by wonderboymusic 10 years ago.
28190.3.diff (5.2 KB) - added by lukecarbis 10 years ago.

Download all attachments as: .zip

Change History (17)

#1 @Fab1en
11 years ago

I think the wp.media.mixin.isCompatible function is the one to blame here. It returns false when using a youtube video url, and that is why the mediaelement.js player is not loaded in tinymce. Is his behavior intended ?

#2 @wonderboymusic
11 years ago

  • Keywords needs-patch added
  • Milestone changed from Awaiting Review to 4.0

will fix

#3 @lukecarbis
11 years ago

So the problem here is that youtube isn't assigned to the compat var as a compatible video type for any of the browsers. The diff I uploaded fixes that.

I was initially concerned about specifying youtube and not any other video services, but I noticed that the same thing is done on the front end. See line 1803 in wp-includes/media.php. YouTube is specified separately to other video mime types, as it is all over wp-includes/media-template.php.

At this point the problem was resolved, but I did notice a display error in the way the media element was being rendered inside tinymce. I managed to track this down to a bug in wp-includes/media-template.php. Line 63 was using the variable h before it had been assigned. This is also included in the diff.

That fixed a display issue, but YouTube embeds still looked wrong (they displayed the YouTube video controls, instead of the mediaelement video controls). I believe that this is related to a Javascript error that now occurs:
ReferenceError: Can't find variable: mejs

Unfortunately this error is not linked to a javascript file (maybe it's being done via eval?), and I've searched for hours but have been unable to fix it.

@lukecarbis
11 years ago

#4 @Fab1en
11 years ago

Thanks lukecarbis for this patch. Detecting youtube video using the mime type is cleaner than parsing the url, this should be the way to do it in all other places, and would allow easier addition for other providers (Vimeo, Dailymotion, ...).

I have also seen the Javascript error you mentioned. I managed to understand from where it comes from : the javascript code is executed by the MediaElementJS flash bridge to create a javascript event. (see line 1020 in src/flash/FlashMediaElement.as https://github.com/johndyer/mediaelement/blob/master/src/flash/FlashMediaElement.as#L1020 of MediaElementJS source code). The flash code assumes that mejs is a global var holding the library, but inside TinyMce iframe this global var is not defined. You can remove the javascript error by executing the following code in the console before inserting the shortcode :

window.frames[0].mejs = mejs


But this will not remove the youtube video display issue. This issue is caused by something else. You can see by inspecting the generated DOM that MEJS control bar is present but empty. Something must prevent controls from being generated, but I could not determine what. Perhaps nesting iframes raise an issue ? Or perhaps it is a race condition between youtube iframe loading and tinyMce iframe ?

The youtube video play control is displayed by the youtube iframe, so it cannot be removed. It is also present in the well generated mejs player that shows when you click on the edit button of the video shortcode.

#5 @wonderboymusic
11 years ago

window.frames[0].mejs = mejs is clever, but TinyMCE doesn't seem to let <embed>s play. So, you can get the YouTube via <embed> to display, but that's it.

We don't have to solve this immediately, let's keep working at it.

28190.diff combines all the info we currently have.

#6 @Fab1en
10 years ago

I dug a little bit more into the JS code, and I found that the YouTube embedded player inside MediaElementJS is not playing because the MediaElementJS controls are not built. And MediaElementJS controls are not built, because success callback is not called.

success callback is called here in MediaElementJS :

// when Flash/Silverlight is ready, it calls out to this method
initPlugin: function (id) {

	var pluginMediaElement = this.pluginMediaElements[id],
		htmlMediaElement = this.htmlMediaElements[id];

	if (pluginMediaElement) {
		// find the javascript bridge
		switch (pluginMediaElement.pluginType) {
			case "flash":
				pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(id);
				break;
			case "silverlight":
				pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id);
				pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS;
				break;
		}

		if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) {
			pluginMediaElement.success(pluginMediaElement, htmlMediaElement);
		}
	}
},

The buggy part is here : document.getElementById(id); document is a global var that points to the main window document instead of the iframe one. That's why the id is not found and therefore the callback cannot be executed.

If I replace
document.getElementById(id);
by
window.frames['content_ifr'].document.getElementById(id)
then the player works fine inside TinyMce

Now I need to figure out how to do this properly.

#7 @Fab1en
10 years ago

  • Keywords has-patch added; needs-patch removed

I finally understood the root cause of the issue : the mediaelementjs javascript must be loaded inside the tinymce iframe to make it work properly (just like mediaelement css is already loaded inside the iframe).

Several scripts must be loaded, with respects for dependencies, so we must must wait for a script to be fully loaded before proceeding with the next one.

I have modified the patch to take this into account. I would appreciate to have your opinion.

@Fab1en
10 years ago

Make YouTube video play inside tinymce

#8 @wonderboymusic
10 years ago

In 28807:

Use the proper height property when calculating video size in wp_underscore_video_template().

Props Fab1en.
See #28190.

#9 @wonderboymusic
10 years ago

28190.2.diff retools some of this. I can imagine @azaozz will hate every bit of it, but the loading of MEjs in the TinyMCE iframe would allow us to ditch tons of compat checking code. Also, makes [video] work with YouTube as the source.

#10 @Fab1en
10 years ago

I can confirm the new patch is working great.

@lukecarbis
10 years ago

#11 @lukecarbis
10 years ago

28190.3.diff only makes some small spacing changes, to meet the coding standards.

#12 @wonderboymusic
10 years ago

  • Resolution set to fixed
  • Status changed from new to closed

Fixed in [29179].

Note: See TracTickets for help on using tickets.