Animal
22 Jan 2010, 12:38 PM
It seemed easy after Dave (forum poster Xantus) showed the way, so...
I took Dave's code and tweaked it to conform to recommendations about subclassing Ext Components: http://www.extjs.com/learn/Tutorial:Creating_new_UI_controls
I also encapsulated the creation of a preview Tooltip within the class. The updating of the preview to create the appearance of a little moving video is provided by Ext.TaskMgr.
Ext.ns('Ext.ux');
/* -NOTICE-
* For HTML5 video to work, your server must
* send the right content type, for more info see:
* https://developer.mozilla.org/En/HTML/Element/Video
*/
Ext.ux.HTML5VideoPanel = Ext.extend(Ext.Panel, {
// Provide defaults for configurable tip sizes.
tipWidth: 160,
tipHeight: 96,
autoHidePreview: false,
constructor: function(config) {
Ext.ux.HTML5VideoPanel.superclass.constructor.call(this, Ext.applyIf(config, {
autoplay : false,
controls : true,
bodyStyle: 'background-color:#000;color:#fff',
suggestChromeFrame: false
}));
},
onRender: function() {
var fallback = '';
if (this.fallbackHTML) {
fallback = this.fallbackHTML;
} else {
fallback = "Your browser doesn't support html5 video. ";
if (Ext.isIE && this.suggestChromeFrame) {
/* chromeframe requires that your site have a special tag in the header
* see http://code.google.com/chrome/chromeframe/ for details
*/
fallback += '<a>Get Google Chrome Frame for IE</a>';
} else if (Ext.isChrome) {
fallback += '<a>Upgrade Chrome</a>';
} else if (Ext.isGecko) {
fallback += '<a>Upgrade to Firefox 3.5</a>';
} else {
fallback += '<a>Get Firefox 3.5</a>';
}
}
// Configure the body element to be a <video> element
this.bodyCfg = Ext.copyTo({
tag : 'video',
children: []
},
this, 'poster,start,loopstart,loopend,playcount,autobuffer,loop');
// Truthy params enables them
if (this.autoplay) this.bodyCfg.autoplay = 1;
if (this.controls) this.bodyCfg.controls = 1;
// Handle multiple sources
if (Ext.isArray(this.src)) {
for (var i = 0, len = this.src.length; i < len; i++) {
if (!Ext.isObject(this.src[i])) {
throw "source list passed to html5video panel must be an array of objects";
}
this.bodyCfg.children.push(
Ext.applyIf({tag: 'source'}, this.src[i])
);
}
this.bodyCfg.children.push({
html: fallback
});
} else {
this.bodyCfg.src = this.src;
this.bodyCfg.html = fallback;
}
Ext.ux.HTML5VideoPanel.superclass.onRender.apply(this, arguments);
this.video = this.body;
},
onResize: function() {
Ext.ux.HTML5VideoPanel.superclass.onResize.apply(this, arguments);
Ext.apply(this.body.dom, this.body.getSize());
},
onDestroy: function() {
Ext.ux.HTML5VideoPanel.superclass.onDestroy.apply(this, arguments);
if (this.tooltip) {
delete this.tipCtx;
this.tooltip.destroy();
Ext.TaskMgr.stop(this.tipUpdateTask);
}
},
getPreviewer: function() {
if (!this.tooltip) {
this.tooltip = new Ext.ToolTip({
anchor : 'bottom',
autoHide : this.autoHidePreview,
hideDelay: Ext.num(this.hidePreviewDelay, Number.MAX_VALUE),
height : this.tipHeight,
width : this.tipWidth,
bodyCfg : {
tag : 'canvas',
width : this.tipWidth,
height : this.tipHeight
},
listeners: {
render: this.onTipRender,
show: this.onTipShow,
hide: this.onTipHide,
scope: this
}
});
// Task to keep the tip updated while it is visible
this.tipUpdateTask = {
run: this.updatePreview,
interval: 20,
scope: this
};
}
return this.tooltip;
},
onTipRender: function() {
this.tipCtx = this.tooltip.body.dom.getContext('2d');
},
onTipShow: function() {
Ext.TaskMgr.start(this.tipUpdateTask);
},
onTipHide: function() {
Ext.TaskMgr.stop(this.tipUpdateTask);
},
updatePreview: function() {
if (this.tipCtx) {
this.tipCtx.drawImage(this.body.dom, 0, 0, this.tipWidth, this.tipHeight);
}
}
});
Ext.reg('html5video', Ext.ux.HTML5VideoPanel);
This means that to get it working in a desktop, all you do is add the line in red:
getModules : function(){
return [
new MyDesktop.GridWindow(),
new MyDesktop.TabWindow(),
new MyDesktop.AccordionWindow(),
new MyDesktop.BogusMenuModule(),
new MyDesktop.BogusModule(),
new MyDesktop.VideoWindow()
];
},
And create the module:
MyDesktop.VideoWindow = Ext.extend(Ext.app.Module, {
id: 'video-win',
init: function () {
this.launcher = {
text: 'Video Window',
iconCls: 'icon-grid',
handler: this.createWindow,
scope: this
};
},
createWindow: function () {
/* createWindow uses renderTo, so it is immediately rendered */
win = this.app.getDesktop().createWindow({
animCollapse: false,
constrainHeader: true,
title: 'Video Window',
width: 740,
height: 480,
iconCls: 'icon-grid',
shim: false,
border: false,
layout: 'fit',
items: {
xtype: 'html5video',
ref: 'videoPanel', // put a reference in the Window
src: [{ // firefox (ogg theora)
src: 'http://xant.us/files/google_main.ogv',
type: 'video/ogg'
}, { // chrome and webkit-nightly (h.264)
src: 'http://xant.us/files/google_main.mgv',
type: 'video/mp4'
}],
autobuffer: true,
autoplay: true,
controls: true
}
});
win.show();
// Hook up the provided preview tooltip to our TaskBar button
win.videoPanel.getPreviewer().initTarget(win.taskButton.el);
}
});
I took Dave's code and tweaked it to conform to recommendations about subclassing Ext Components: http://www.extjs.com/learn/Tutorial:Creating_new_UI_controls
I also encapsulated the creation of a preview Tooltip within the class. The updating of the preview to create the appearance of a little moving video is provided by Ext.TaskMgr.
Ext.ns('Ext.ux');
/* -NOTICE-
* For HTML5 video to work, your server must
* send the right content type, for more info see:
* https://developer.mozilla.org/En/HTML/Element/Video
*/
Ext.ux.HTML5VideoPanel = Ext.extend(Ext.Panel, {
// Provide defaults for configurable tip sizes.
tipWidth: 160,
tipHeight: 96,
autoHidePreview: false,
constructor: function(config) {
Ext.ux.HTML5VideoPanel.superclass.constructor.call(this, Ext.applyIf(config, {
autoplay : false,
controls : true,
bodyStyle: 'background-color:#000;color:#fff',
suggestChromeFrame: false
}));
},
onRender: function() {
var fallback = '';
if (this.fallbackHTML) {
fallback = this.fallbackHTML;
} else {
fallback = "Your browser doesn't support html5 video. ";
if (Ext.isIE && this.suggestChromeFrame) {
/* chromeframe requires that your site have a special tag in the header
* see http://code.google.com/chrome/chromeframe/ for details
*/
fallback += '<a>Get Google Chrome Frame for IE</a>';
} else if (Ext.isChrome) {
fallback += '<a>Upgrade Chrome</a>';
} else if (Ext.isGecko) {
fallback += '<a>Upgrade to Firefox 3.5</a>';
} else {
fallback += '<a>Get Firefox 3.5</a>';
}
}
// Configure the body element to be a <video> element
this.bodyCfg = Ext.copyTo({
tag : 'video',
children: []
},
this, 'poster,start,loopstart,loopend,playcount,autobuffer,loop');
// Truthy params enables them
if (this.autoplay) this.bodyCfg.autoplay = 1;
if (this.controls) this.bodyCfg.controls = 1;
// Handle multiple sources
if (Ext.isArray(this.src)) {
for (var i = 0, len = this.src.length; i < len; i++) {
if (!Ext.isObject(this.src[i])) {
throw "source list passed to html5video panel must be an array of objects";
}
this.bodyCfg.children.push(
Ext.applyIf({tag: 'source'}, this.src[i])
);
}
this.bodyCfg.children.push({
html: fallback
});
} else {
this.bodyCfg.src = this.src;
this.bodyCfg.html = fallback;
}
Ext.ux.HTML5VideoPanel.superclass.onRender.apply(this, arguments);
this.video = this.body;
},
onResize: function() {
Ext.ux.HTML5VideoPanel.superclass.onResize.apply(this, arguments);
Ext.apply(this.body.dom, this.body.getSize());
},
onDestroy: function() {
Ext.ux.HTML5VideoPanel.superclass.onDestroy.apply(this, arguments);
if (this.tooltip) {
delete this.tipCtx;
this.tooltip.destroy();
Ext.TaskMgr.stop(this.tipUpdateTask);
}
},
getPreviewer: function() {
if (!this.tooltip) {
this.tooltip = new Ext.ToolTip({
anchor : 'bottom',
autoHide : this.autoHidePreview,
hideDelay: Ext.num(this.hidePreviewDelay, Number.MAX_VALUE),
height : this.tipHeight,
width : this.tipWidth,
bodyCfg : {
tag : 'canvas',
width : this.tipWidth,
height : this.tipHeight
},
listeners: {
render: this.onTipRender,
show: this.onTipShow,
hide: this.onTipHide,
scope: this
}
});
// Task to keep the tip updated while it is visible
this.tipUpdateTask = {
run: this.updatePreview,
interval: 20,
scope: this
};
}
return this.tooltip;
},
onTipRender: function() {
this.tipCtx = this.tooltip.body.dom.getContext('2d');
},
onTipShow: function() {
Ext.TaskMgr.start(this.tipUpdateTask);
},
onTipHide: function() {
Ext.TaskMgr.stop(this.tipUpdateTask);
},
updatePreview: function() {
if (this.tipCtx) {
this.tipCtx.drawImage(this.body.dom, 0, 0, this.tipWidth, this.tipHeight);
}
}
});
Ext.reg('html5video', Ext.ux.HTML5VideoPanel);
This means that to get it working in a desktop, all you do is add the line in red:
getModules : function(){
return [
new MyDesktop.GridWindow(),
new MyDesktop.TabWindow(),
new MyDesktop.AccordionWindow(),
new MyDesktop.BogusMenuModule(),
new MyDesktop.BogusModule(),
new MyDesktop.VideoWindow()
];
},
And create the module:
MyDesktop.VideoWindow = Ext.extend(Ext.app.Module, {
id: 'video-win',
init: function () {
this.launcher = {
text: 'Video Window',
iconCls: 'icon-grid',
handler: this.createWindow,
scope: this
};
},
createWindow: function () {
/* createWindow uses renderTo, so it is immediately rendered */
win = this.app.getDesktop().createWindow({
animCollapse: false,
constrainHeader: true,
title: 'Video Window',
width: 740,
height: 480,
iconCls: 'icon-grid',
shim: false,
border: false,
layout: 'fit',
items: {
xtype: 'html5video',
ref: 'videoPanel', // put a reference in the Window
src: [{ // firefox (ogg theora)
src: 'http://xant.us/files/google_main.ogv',
type: 'video/ogg'
}, { // chrome and webkit-nightly (h.264)
src: 'http://xant.us/files/google_main.mgv',
type: 'video/mp4'
}],
autobuffer: true,
autoplay: true,
controls: true
}
});
win.show();
// Hook up the provided preview tooltip to our TaskBar button
win.videoPanel.getPreviewer().initTarget(win.taskButton.el);
}
});