r38687 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r38686‎ | r38687 | r38688 >
Date:05:57, 6 August 2008
Author:tstarling
Status:old
Tags:
Comment:
Fixes for all the browsers that broke themselves since I wrote this extension:
* IE7: Use fully qualified .jar URL to avoid total failure to load applet
* Opera 9.5: Don't use iframes for Java, it's now broken. Revamped the whole detection system to deal with its terrible navigator.mimeTypes behaviour.
* Konqueror: Blacklisted the totally broken VLC and Java plugins. Added support for Kaffeine and KMPlayer which kind of work. Also benefits from new mimeTypes stuff.

Also:
* Added explicit player selection for Totem
* Use less technical language in the player selection list for <video> elements and generic plugins, since soon the whole web will be using <video> in Firefox 3.1
* Faster, less hackish method for detecting <video> element support: look for the standard JS class name.
Modified paths:
  • /trunk/extensions/OggHandler/OggHandler.i18n.php (modified) (history)
  • /trunk/extensions/OggHandler/OggHandler.php (modified) (history)
  • /trunk/extensions/OggHandler/OggHandler_body.php (modified) (history)
  • /trunk/extensions/OggHandler/OggPlayer.js (modified) (history)

Diff [purge]

Index: trunk/extensions/OggHandler/OggHandler.php
@@ -17,7 +17,7 @@
1818 ini_get( 'include_path' ) );
1919
2020 // Bump this when updating OggPlayer.js to help update caches
21 -$wgOggScriptVersion = '7';
 21+$wgOggScriptVersion = '8';
2222
2323 $wgExtensionMessagesFiles['OggHandler'] = "$oggDir/OggHandler.i18n.php";
2424 $wgParserOutputHooks['OggHandler'] = array( 'OggHandler', 'outputHook' );
Index: trunk/extensions/OggHandler/OggPlayer.js
@@ -4,19 +4,34 @@
55 'msie': false,
66 'safari' : false,
77 'opera' : false,
 8+ 'mozilla': false,
89
910 // List of players in order of preference
1011 // Downpreffed VLC because it crashes my browser all the damn time -- TS
11 - 'players': ['cortado', 'quicktime-mozilla', 'quicktime-activex', 'vlc-mozilla', 'vlc-activex', 'oggPlugin', 'videoElement'],
 12+ 'players': ['cortado', 'quicktime-mozilla', 'quicktime-activex', 'vlc-mozilla', 'vlc-activex', 'totem', 'kmplayer', 'kaffeine', 'oggPlugin', 'videoElement'],
1213
 14+ // Client support table
1315 'clientSupports': { 'thumbnail' : true },
 16+
 17+ // MIME type to be used to invoke a given plugin with <object>
 18+ // May be changed by detect()
 19+ 'mimeTypes' : {
 20+ 'quicktime-mozilla': 'video/quicktime',
 21+ 'quicktime-activex': 'video/quicktime',
 22+ 'vlc-mozilla': 'application/x-vlc-plugin',
 23+ 'oggPlugin': 'application/ogg',
 24+ 'totem': 'application/ogg',
 25+ 'kmplayer': 'application/ogg',
 26+ 'kaffeine': 'application/ogg'
 27+ },
 28+
1429 'savedThumbs': {},
1530 'qtTimers' : {},
1631 // Text for new messages, to support cached HTML invocation
17 - 'defaultMsg' : {
18 - 'ogg-no-xiphqt': 'You do not appear to have the XiphQT component for QuickTime. QuickTime cannot play ' +
19 - 'Ogg files without this component. Please ' +
20 - '<a href="http://www.mediawiki.org/wiki/Extension:OggHandler/Client_download">download XiphQT</a> or choose another player.'
 32+ 'defaultMsg' : {
 33+ 'ogg-player-totem': 'Totem',
 34+ 'ogg-player-kmplayer': 'KMPlayer',
 35+ 'ogg-player-kaffeine': 'Kaffeine'
2136 },
2237
2338 // Configuration from MW
@@ -44,7 +59,7 @@
4560 this.savedThumbs[params.id] = thumb;
4661 }
4762
48 - this.detect( elt );
 63+ this.detect();
4964
5065 if ( !player ) {
5166 // See if there is a cookie specifying a preferred player
@@ -73,7 +88,10 @@
7489 this.embedVideoElement( elt, params );
7590 break;
7691 case 'oggPlugin':
77 - this.embedOggPlugin( elt, params );
 92+ case 'kaffeine':
 93+ case 'totem':
 94+ case 'kmplayer':
 95+ this.embedOggPlugin( elt, params, player );
7896 break;
7997 case 'vlc-mozilla':
8098 this.embedVlcPlugin( elt, params );
@@ -114,8 +132,12 @@
115133 }
116134 },
117135
 136+ 'debug': function( s ) {
 137+ //alert(s);
 138+ },
 139+
118140 // Detect client capabilities
119 - 'detect': function( elt ) {
 141+ 'detect': function() {
120142 if (this.detectionDone) {
121143 return;
122144 }
@@ -123,16 +145,16 @@
124146
125147 // First some browser detection
126148 this.msie = ( navigator.appName == "Microsoft Internet Explorer" );
 149+ this.mozilla = ( navigator.appName == "Netscape" );
127150 this.opera = ( navigator.appName == 'Opera' );
128151 this.safari = ( navigator.vendor && navigator.vendor.substr( 0, 5 ) == 'Apple' );
 152+ this.konqueror = ( navigator.appName == 'Konqueror' );
129153
130154 // In Mozilla, navigator.javaEnabled() only tells us about preferences, we need to
131155 // search navigator.mimeTypes to see if it's installed
132156 var javaEnabled = navigator.javaEnabled();
133157 // In Opera, navigator.javaEnabled() is all there is
134158 var invisibleJava = this.opera;
135 - // Some browsers filter out duplicate mime types, hiding some plugins
136 - var uniqueMimesOnly = this.opera || this.safari;
137159
138160 // Opera will switch off javaEnabled in preferences if java can't be found.
139161 // And it doesn't register an application/x-java-applet mime type like Mozilla does.
@@ -140,6 +162,12 @@
141163 this.clientSupports['cortado'] = true;
142164 }
143165
 166+ if ( this.konqueror ) {
 167+ // Bugged as of 3.5.9
 168+ // Applet freezes shortly after starting
 169+ javaEnabled = false;
 170+ }
 171+
144172 // ActiveX plugins
145173 // VLC
146174 if ( this.testActiveX( 'VideoLAN.VLCPlugin.2' ) ) {
@@ -155,64 +183,119 @@
156184 }
157185
158186 // <video> element
159 - elt.innerHTML = '<video id="testvideo"></video>\n';
160 - var testvideo = document.getElementById('testvideo');
161 - if (testvideo && testvideo.play) {
 187+ if ( typeof HTMLVideoElement == 'object' ) {
162188 this.clientSupports['videoElement'] = true;
163189 }
164190
 191+ if (!navigator.mimeTypes || navigator.mimeTypes.length == 0) {
 192+ // No Mozilla plugins, all done
 193+ return;
 194+ }
 195+
165196 // Mozilla plugins
166 -
167 - if(navigator.mimeTypes && navigator.mimeTypes.length > 0) {
168 - for ( var i = 0; i < navigator.mimeTypes.length; i++) {
169 - var entry = navigator.mimeTypes[i];
170 - var type = entry.type;
171 - var semicolonPos = type.indexOf( ';' );
172 - if ( semicolonPos > -1 ) {
173 - type = type.substr( 0, semicolonPos );
 197+ var typesByPlayer = {};
 198+ var playersByType = {};
 199+ var numPlayersByType = {};
 200+ var player;
 201+ var i;
 202+ for ( i = 0; i < navigator.mimeTypes.length; i++) {
 203+ var entry = navigator.mimeTypes[i];
 204+ var type = entry.type;
 205+ var semicolonPos = type.indexOf( ';' );
 206+ if ( semicolonPos > -1 ) {
 207+ type = type.substr( 0, semicolonPos );
 208+ }
 209+
 210+ var plugin = entry.enabledPlugin;
 211+ // In case it is null or undefined
 212+ var pluginName = plugin && plugin.name ? plugin.name : '';
 213+ var pluginFilename = plugin && plugin.filename ? plugin.filename : '';
 214+ player = '';
 215+
 216+ if ( javaEnabled && type == 'application/x-java-applet' ) {
 217+ // We use <applet> so we don't have to worry about unique types
 218+ this.clientSupports['cortado'] = true;
 219+ // But it could conflict with another plugin
 220+ // Set player='' to avoid double registration of cortado
 221+ player = '';
 222+ } else if ( pluginFilename.indexOf( 'libtotem' ) > -1 ) {
 223+ // Totem
 224+ player = 'totem';
 225+ } else if ( pluginFilename.indexOf( 'libkmplayerpart' ) > -1 ) {
 226+ // KMPlayer is fussy about what type you give it
 227+ if ( pluginName == 'Windows Media Player Plugin'
 228+ || pluginName == 'QuickTime Plug-in' )
 229+ {
 230+ player = 'kmplayer';
174231 }
 232+ } else if ( pluginFilename.indexOf( 'kaffeineplugin' ) > -1 ) {
 233+ // Kaffeine
 234+ player = 'kaffeine';
 235+ } else if ( pluginName.indexOf( 'QuickTime Plug-in' ) > -1 ) {
 236+ // Note: Totem and KMPlayer also use this pluginName, which is
 237+ // why we check for them first
 238+ player = 'quicktime-mozilla';
 239+ } else if ( pluginName.toLowerCase() == 'vlc multimedia plugin' ) {
 240+ player = 'vlc-mozilla';
 241+ } else if ( type == 'application/ogg' ) {
 242+ player = 'oggPlugin';
 243+ }
175244
176 - var plugin = entry.enabledPlugin;
177 - // In case it is null or undefined
178 - var pluginName = plugin && plugin.name ? plugin.name : '';
179 - var pluginFilename = plugin && plugin.filename ? plugin.filename : '';
180 -
181 - if ( javaEnabled && type == 'application/x-java-applet' ) {
182 - this.clientSupports['cortado'] = true;
183 - continue;
 245+ if ( this.konqueror && player == 'vlc-mozilla' ) {
 246+ // In Konqueror 3.5.9, VLC is not scriptable, has no controls, and crashes the browser
 247+ player = '';
 248+ }
 249+
 250+ // Update some hashtables to track unique type assignment
 251+ // Slightly complicated because players can and do conflict with themselves
 252+ if ( !( player in typesByPlayer ) ) {
 253+ typesByPlayer[player] = {};
 254+ }
 255+ typesByPlayer[player][type] = true;
 256+ if ( !( type in playersByType ) ) {
 257+ playersByType[type] = {};
 258+ numPlayersByType[type] = 0;
 259+ }
 260+ if ( !( player in playersByType[type] ) ) {
 261+ playersByType[type][player] = true;
 262+ numPlayersByType[type]++;
 263+ }
 264+ }
 265+
 266+ // Determine a unique MIME type for each player found
 267+ for ( i = 0; i < this.players.length; i++ ) {
 268+ player = this.players[i];
 269+ if ( !( player in typesByPlayer ) ) {
 270+ continue;
 271+ }
 272+ // Is the default OK?
 273+ var defaultType = this.mimeTypes[player];
 274+ if ( defaultType in numPlayersByType
 275+ && numPlayersByType[defaultType] == 1
 276+ && defaultType in typesByPlayer[player] )
 277+ {
 278+ // Yes, use it
 279+ this.debug( player + " -> " + defaultType );
 280+ this.clientSupports[player] = true;
 281+ continue;
 282+ }
 283+ // Search for a unique type
 284+ for ( var type in typesByPlayer[player] ) {
 285+ if ( numPlayersByType[type] == 1 ) {
 286+ // Found a unique type
 287+ this.mimeTypes[player] = type;
 288+ this.clientSupports[player] = true;
 289+ this.debug( player + " => " + type );
 290+ break;
184291 }
185 - if ( type == 'application/ogg' ) {
186 - if ( pluginName.toLowerCase() == 'vlc multimedia plugin' ) {
187 - this.clientSupports['vlc-mozilla'] = true;
188 - } else if ( pluginName.indexOf( 'QuickTime' ) > -1 ) {
189 - this.clientSupports['quicktime-mozilla'] = true;
190 - } else {
191 - this.clientSupports['oggPlugin'] = true;
192 - }
193 - continue;
194 - } else if ( uniqueMimesOnly ) {
195 - // Could cause false positives if codecs are missing...
196 - if ( type == 'application/x-vlc-player' ) {
197 - this.clientSupports['vlc-mozilla'] = true;
198 - continue;
199 - } else if ( type == 'video/quicktime' ) {
200 - this.clientSupports['quicktime-mozilla'] = true;
201 - continue;
202 - }
 292+ }
 293+ if ( !(player in this.clientSupports ) ) {
 294+ if ( typesByPlayer[player].length > 0 ) {
 295+ this.debug( "No unique MIME type for " + player );
 296+ } else {
 297+ this.debug( "No types for player " + player );
203298 }
204 -
205 - if ( type == 'video/quicktime' ) {
206 - if ( pluginFilename.indexOf( 'libtotem' ) > -1 ) {
207 - // Totem plugin on *nix...
208 - // Will in fact play oggs, but we'll have a native
209 - // plugin alongside it. Skip the entry.
210 - } else {
211 - this.clientSupports['quicktime-mozilla'] = true;
212 - continue;
213 - }
214 - }
215299 }
216 -
217300 }
218301 },
219302
@@ -321,13 +404,13 @@
322405 if ( player == selectedPlayer ) {
323406 var strong = document.createElement( 'strong' );
324407 strong.appendChild( document.createTextNode(
325 - this.msg[playerMsg] + ' ' + this.msg['ogg-player-selected'] ) );
 408+ this.getMsg(playerMsg) + ' ' + this.msg['ogg-player-selected'] ) );
326409 li.appendChild( strong );
327410 } else {
328411 a = document.createElement( 'a' );
329412 a.href = 'javascript:void("' + player + '")';
330413 a.onclick = this.makePlayerFunction( player, params );
331 - a.appendChild( document.createTextNode( this.msg[playerMsg] ) );
 414+ a.appendChild( document.createTextNode( this.getMsg(playerMsg) ) );
332415 li.appendChild( a );
333416 }
334417 ul.appendChild( li );
@@ -443,11 +526,11 @@
444527 }
445528 },
446529
447 - 'embedOggPlugin': function ( elt, params ) {
 530+ 'embedOggPlugin': function ( elt, params, player ) {
448531 var id = elt.id + "_obj";
449532 elt.innerHTML +=
450533 "<div><object id=" + this.hq( id ) +
451 - " type='application/ogg'" +
 534+ " type='" + this.mimeTypes[player] + "'" +
452535 " width=" + this.hq( params.width ) +
453536 " height=" + this.hq( params.height + this.controlsHeightGuess ) +
454537 " data=" + this.hq( params.videoUrl ) + "></object></div>";
@@ -457,7 +540,7 @@
458541 var id = elt.id + "_obj";
459542 elt.innerHTML +=
460543 "<div><object id=" + this.hq( id ) +
461 - " type='application/x-vlc-plugin'" +
 544+ " type='" + this.mimeTypes['vlc-mozilla'] + "'" +
462545 " width=" + this.hq( params.width ) +
463546 " height=" + this.hq( params.height ) +
464547 " data=" + this.hq( params.videoUrl ) + "></object></div>";
@@ -522,12 +605,13 @@
523606 ' <param name="autoPlay" value="true"/>' +
524607 ' <param name="showStatus" value="show"/>' +
525608 ' <param name="showSpeaker" value="false"/>' +
 609+ ' <param name="debug" value="4"/>' +
526610 ' <param name="statusHeight" value="' + statusHeight + '"/>' +
527611 '</applet>';
528612
529613 // Wrap it in an iframe to avoid hanging the rendering thread in FF 2.0 and similar
530 - // Doesn't work in Safari/Mac
531 - if ( !this.msie && !this.safari ) {
 614+ // Doesn't work in MSIE or Safari/Mac or Opera 9.5
 615+ if ( this.mozilla ) {
532616 var iframeHtml = '<html><body>' + html + '</body></html>';
533617 var iframeJs = 'parent.wgOggPlayer.writeApplet(self, "' + iframeHtml.replace( /"/g, '\\"' ) + '");';
534618 var iframeUrl = 'javascript:' + encodeURIComponent( iframeJs );
@@ -542,7 +626,7 @@
543627
544628 'writeApplet' : function ( win, html ) {
545629 win.document.write( html );
546 - win.stop();
 630+ if ( win.stop ) win.stop();
547631 // Disable autoplay on back button
548632 this_ = this;
549633 win.setTimeout(
@@ -563,7 +647,7 @@
564648
565649 elt.innerHTML +=
566650 "<div><object id=" + this.hq( id ) +
567 - " type='video/quicktime'" +
 651+ " type='" + this.mimeTypes[player] + "'" +
568652 " width=" + this.hq( params.width ) +
569653 " height=" + this.hq( params.height + controllerHeight ) +
570654
Index: trunk/extensions/OggHandler/OggHandler_body.php
@@ -390,7 +390,7 @@
391391 }
392392
393393 function setHeaders( $out ) {
394 - global $wgOggScriptVersion, $wgCortadoJarFile;
 394+ global $wgOggScriptVersion, $wgCortadoJarFile, $wgServer;
395395 if ( $out->hasHeadItem( 'OggHandler' ) ) {
396396 return;
397397 }
@@ -400,6 +400,7 @@
401401 $msgNames = array( 'ogg-play', 'ogg-pause', 'ogg-stop', 'ogg-no-player',
402402 'ogg-player-videoElement', 'ogg-player-oggPlugin', 'ogg-player-cortado', 'ogg-player-vlc-mozilla',
403403 'ogg-player-vlc-activex', 'ogg-player-quicktime-mozilla', 'ogg-player-quicktime-activex',
 404+ 'ogg-player-totem', 'ogg-player-kaffeine', 'ogg-player-kmplayer',
404405 'ogg-player-thumbnail', 'ogg-player-selected', 'ogg-use-player', 'ogg-more', 'ogg-download',
405406 'ogg-desc-link', 'ogg-dismiss', 'ogg-player-soundthumb', 'ogg-no-xiphqt' );
406407 $msgValues = array_map( 'wfMsg', $msgNames );
@@ -408,7 +409,7 @@
409410 $scriptPath = self::getMyScriptPath();
410411 if( substr( $cortadoUrl, 0, 1 ) != '/'
411412 && substr( $cortadoUrl, 0, 4 ) != 'http' ) {
412 - $cortadoUrl = "$scriptPath/$cortadoUrl";
 413+ $cortadoUrl = "$wgServer$scriptPath/$cortadoUrl";
413414 }
414415 $encCortadoUrl = Xml::encodeJsVar( $cortadoUrl );
415416 $encExtPathUrl = Xml::encodeJsVar( $scriptPath );
Index: trunk/extensions/OggHandler/OggHandler.i18n.php
@@ -31,13 +31,16 @@
3232 QuickTime cannot play Ogg files without this component.
3333 Please <a href="http://www.mediawiki.org/wiki/Extension:OggHandler/Client_download">download XiphQT</a> or choose another player.',
3434
35 - 'ogg-player-videoElement' => '<video> element',
36 - 'ogg-player-oggPlugin' => 'Ogg plugin',
 35+ 'ogg-player-videoElement' => 'Native browser support',
 36+ 'ogg-player-oggPlugin' => 'Browser plugin',
3737 'ogg-player-cortado' => 'Cortado (Java)', # only translate this message to other languages if you have to change it
3838 'ogg-player-vlc-mozilla' => 'VLC', # only translate this message to other languages if you have to change it
3939 'ogg-player-vlc-activex' => 'VLC (ActiveX)', # only translate this message to other languages if you have to change it
4040 'ogg-player-quicktime-mozilla' => 'QuickTime', # only translate this message to other languages if you have to change it
4141 'ogg-player-quicktime-activex' => 'QuickTime (ActiveX)', # only translate this message to other languages if you have to change it
 42+ 'ogg-player-totem' => 'Totem', # only translate this message to other languages if you have to change it
 43+ 'ogg-player-kmplayer' => 'KMPlayer', # only translate this message to other languages if you have to change it
 44+ 'ogg-player-kaffeine' => 'Kaffeine', # only translate this message to other languages if you have to change it
4245 'ogg-player-thumbnail' => 'Still image only',
4346 'ogg-player-soundthumb' => 'No player',
4447 'ogg-player-selected' => '(selected)',

Follow-up revisions

RevisionCommit summaryAuthorDate
r38689Per r38687 make some messages optional.raymond07:17, 6 August 2008

Status & tagging log