Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: brianchirls/butter
base: 18f8c26ed1
...
head fork: brianchirls/butter
compare: fcdffbf8f0
Checking mergeability… Don't worry, you can still create the pull request.
  • 16 commits
  • 24 files changed
  • 0 commit comments
  • 6 contributors
Commits on Apr 11, 2012
@secretrobotron secretrobotron [t672] butter-main.js -> main.js
Renamed butter-main to main and swapped references.
f339c40
@jbuck jbuck Use Stylus for server-side CSS [#664] 9e963d7
Commits on Apr 12, 2012
@secretrobotron secretrobotron [t672] - butter-main -> main
Changed `butter-main` to `main` in build profiles.
ca8377d
@dseif dseif Merge pull request #197 from secretrobotron/t672
Change `butter-main.js` to just `main.js`
7118fc7
@jbuck jbuck Add stylus compilation to make [#664] 3897d5f
@butterbot butterbot Merge pull request #198 from jbuck/t664
Use Stylus for server-side CSS
3a6cc3e
Commits on Apr 13, 2012
@dseif dseif [#612] Added a callback function on connect that would catch any erro…
…rs and notify the user that it could not connect to mongodb
3d4060a
Commits on Apr 16, 2012
@secretrobotron secretrobotron [t663] - html snapshotting for export
1. Added _page to butter to expose functions
2. Added data-butter-exclude to dialog modal container
3. Added snapshotHTML/eraseSnapshot functions in Page class
4. Added test for html snapshotting
58b0af7
@secretrobotron secretrobotron [t663] HTML Snapshotting
Added some comments specifically to the snapshotting code region.
40eed32
@secretrobotron secretrobotron [t663] HTML snapshotting
A bit more explanation in the comments.
d550614
@secretrobotron secretrobotron [t667] - popcorn scripts and callback
WIP: config passthrough to generatePopcornString
19de92b
@secretrobotron secretrobotron [t667] - export Popcorn callback and script insert
1. Finished WIP
2. Scripts can be urls or elements (denoted by #)
3. Added tests
261beba
@secretrobotron secretrobotron [t667] Fixed references to other callback types b091c4e
@secretrobotron secretrobotron [t667] rebase and merge
Needed to rebase and fix a couple of problems to land t667.
5ffce58
@secretrobotron secretrobotron Merge pull request #207 from dseif/t612
[#612] Added a callback function on connect that would catch any errors ...
77ecd09
@brianchirls Merge branch 'master' of https://github.com/mozilla/butter fcdffbf
View
1  .gitignore
@@ -14,3 +14,4 @@ dist
*.mp3
node_modules
cornfield/view
+css/butter.ui.css
View
13 config/default.conf
@@ -1,5 +1,6 @@
{
"name": "default-butter-test",
+ "snapshotHTMLOnReady": true,
"editor": {
"default": "../editors/default-editor.html"
},
@@ -41,6 +42,18 @@
},
"mediaDefaults": {
"frameAnimation": true
+ },
+ "popcorn": {
+ "scripts": {
+ "init": "test-init.js",
+ "beforeEvents": "test-before.js",
+ "afterEvents": "test-after.js"
+ },
+ "callbacks": {
+ "init": "_testInitCallback",
+ "beforeEvents": "_testBeforeCallback",
+ "afterEvents": "_testAfterCallback"
+ }
}
}
View
12 config/test.conf
@@ -35,6 +35,18 @@
},
"dirs": {
"popcorn-js": "../external/popcorn-js/"
+ },
+ "popcorn": {
+ "scripts": {
+ "init": "#init-script",
+ "beforeEvents": "test-before.js",
+ "afterEvents": "test-after.js"
+ },
+ "callbacks": {
+ "init": "_testInitCallback",
+ "beforeEvents": "_testBeforeCallback",
+ "afterEvents": "_testAfterCallback"
+ }
}
}
View
11 cornfield/app.js
@@ -4,6 +4,7 @@ const express = require('express'),
fs = require('fs'),
path = require('path'),
app = express.createServer(),
+ stylus = require('stylus'),
CONFIG = require('config'),
TEMPLATES_DIR = CONFIG.dirs.templates,
PUBLISH_DIR = CONFIG.dirs.publish,
@@ -24,7 +25,12 @@ console.log( "Templates Dir:", TEMPLATES_DIR );
console.log( "Publish Dir:", PUBLISH_DIR );
var mongoose = require('mongoose'),
- db = mongoose.connect('mongodb://localhost/test'),
+ db = mongoose.connect('mongodb://localhost/test', function( err ) {
+ if ( err ) {
+ console.log( "COULD NOT CONNECT TO MONGODB! Make sure it is running!" );
+ throw err;
+ }
+ });
Schema = mongoose.Schema,
Project = new Schema({
@@ -49,6 +55,9 @@ app.use(express.logger(CONFIG.logger))
.use(express.bodyParser())
.use(express.cookieParser())
.use(express.session(CONFIG.session))
+ .use(stylus.middleware({
+ src: WWW_ROOT
+ }))
.use(express.static( WWW_ROOT ))
.use(express.static( PUBLISH_DIR ))
.use(express.directory( WWW_ROOT, { icons: true } ) );
View
0  css/butter.ui.css → css/butter.ui.deprecated.css
File renamed without changes
View
1  css/butter.ui.styl
@@ -0,0 +1 @@
+@import "butter.ui.deprecated.css"
View
7 make.js
@@ -1,7 +1,8 @@
#!/usr/bin/env node
var JSLINT = './node_modules/jshint/bin/hint',
- RJS = './node_modules/requirejs/bin/r.js';
+ RJS = './node_modules/requirejs/bin/r.js',
+ STYLUS = './node_modules/stylus/bin/stylus';
require('shelljs/make');
@@ -36,8 +37,12 @@ target.build = function() {
rm('-rf', 'dist');
mkdir('-p', 'dist');
+
exec(RJS + ' -o tools/build.js');
exec(RJS + ' -o tools/build.optimized.js');
+
+ exec(STYLUS + ' css');
+ cp('css/*.css', 'dist');
};
target.server = function() {
View
3  package.json
@@ -52,7 +52,8 @@
"express": "*",
"express-browserid": "*",
"config": "*",
- "mongoose": "*"
+ "mongoose": "*",
+ "stylus": "*"
},
"license": "MIT",
"engine": {
View
2  src/butter.js
@@ -59,7 +59,7 @@
// Paths are relative to baseUrl; Notice the commas!
'}' +
'});' +
- 'ctx(["butter-main"])' +
+ 'ctx(["main"])' +
'})()' +
'</script>');
}
View
17 src/core/media.js
@@ -91,6 +91,9 @@
}),
_this = this;
+ this.popcornCallbacks = null;
+ this.popcornScripts = null;
+
this.createView = function(){
_view = new MediaView( this, {
onDropped: onDroppedOnView
@@ -209,7 +212,7 @@
function setupContent(){
if( _url && _target ){
- _popcornWrapper.prepare( _url, _target, _popcornOptions );
+ _popcornWrapper.prepare( _url, _target, _popcornOptions, _this.popcornCallbacks, _this.popcornScripts );
} //if
if( _view ){
_view.update();
@@ -239,6 +242,12 @@
_popcornWrapper.play();
};
+ this.generatePopcornString = function( callbacks, scripts ){
+ callbacks = callbacks || _this.popcornCallbacks;
+ scripts = scripts || _this.popcornScripts;
+ return _popcornWrapper.generatePopcornString( _popcornOptions, _url, _target, null, callbacks, scripts );
+ };
+
Object.defineProperties( this, {
ended: {
enumerable: true,
@@ -427,12 +436,6 @@
_em.dispatch( "mediapopcornsettingschanged", _this );
setupContent();
}
- },
- popcornString: {
- enumerable: true,
- get: function(){
- return _popcornWrapper.generatePopcornString( _popcornOptions, _url, _target );
- }
}
});
View
39 src/core/page.js
@@ -11,7 +11,8 @@ define( [ "core/logger", "core/eventmanager" ], function( Logger, EventManager )
PLAYER_URL = POPCORN_BASE_URL + "modules/player/popcorn.player.js",
PLAYER_TYPE_URL = POPCORN_BASE_URL + "players/{type}/popcorn.{type}.js";
- var _eventManager = new EventManager( this );
+ var _eventManager = new EventManager( this ),
+ _snapshot;
this.scrape = function() {
var rootNode = document.body,
@@ -80,10 +81,20 @@ define( [ "core/logger", "core/eventmanager" ], function( Logger, EventManager )
};
this.getHTML = function( popcornStrings ){
- var html = document.createElement( "html" ),
- head = document.getElementsByTagName( "head" )[ 0 ].cloneNode( true ),
- body = document.getElementsByTagName( "body" )[ 0 ].cloneNode( true ),
- i, toClean, toExclude, node;
+ var html, head, body, i, toClean, toExclude, node;
+
+ //html tag to which body and head are appended below
+ html = document.createElement( "html" );
+
+ // if there is already a snapshot, clone it instead of cloning the current dom
+ if( !_snapshot ){
+ head = document.getElementsByTagName( "head" )[ 0 ].cloneNode( true );
+ body = document.getElementsByTagName( "body" )[ 0 ].cloneNode( true );
+ }
+ else{
+ head = _snapshot.head.cloneNode( true );
+ body = _snapshot.body.cloneNode( true );
+ }
toExclude = Array.prototype.slice.call( head.querySelectorAll( "*[data-butter-exclude]" ) );
toExclude = toExclude.concat( Array.prototype.slice.call( head.querySelectorAll( "*[data-requiremodule]" ) ) );
@@ -97,6 +108,7 @@ define( [ "core/logger", "core/eventmanager" ], function( Logger, EventManager )
node = toClean[ i ];
node.removeAttribute( "butter-clean" );
node.removeAttribute( "data-butter" );
+ node.removeAttribute( "data-butter-default" );
// obviously, classList is preferred (https://developer.mozilla.org/en/DOM/element.classList)
if( node.classList ){
@@ -128,5 +140,22 @@ define( [ "core/logger", "core/eventmanager" ], function( Logger, EventManager )
return "<html>" + html.innerHTML + "</html>";
}; //getHTML
+ /* Take a snapshot of the current DOM and store it.
+ * Mainly for use with generatePopcornString() so as to not export unwanted DOM objects,
+ * a snapshot can be taken at any time (usually up to the template author).
+ */
+ this.snapshotHTML = function(){
+ _snapshot = {
+ head: document.getElementsByTagName( "head" )[ 0 ].cloneNode( true ),
+ body: document.getElementsByTagName( "body" )[ 0 ].cloneNode( true )
+ };
+ };
+
+ /* Forget DOM snapshots previously taken
+ */
+ this.eraseSnapshot = function(){
+ _snapshot = null;
+ };
+
}; // page
});
View
31 src/core/popcorn-wrapper.js
@@ -135,7 +135,7 @@ define( [ "core/logger", "core/eventmanager" ], function( Logger, EventManager )
* before we actually create the Popcorn instance and notify the
* user.
*/
- this.prepare = function( url, target, popcornOptions ){
+ this.prepare = function( url, target, popcornOptions, callbacks, scripts ){
// called when timeout occurs preparing popcorn or the media
function timeoutWrapper( e ){
@@ -167,7 +167,7 @@ define( [ "core/logger", "core/eventmanager" ], function( Logger, EventManager )
// construct the correct dom infrastructure if required
constructPlayer( target );
// generate a function which will create a popcorn instance when entered into the page
- createPopcorn( generatePopcornString( popcornOptions, url, target ) );
+ createPopcorn( generatePopcornString( popcornOptions, url, target, null, callbacks, scripts ) );
// once popcorn is created, attach listeners to it to detect state
addPopcornHandlers();
// wait for the media to become available and notify the user, or timeout
@@ -225,7 +225,11 @@ define( [ "core/logger", "core/eventmanager" ], function( Logger, EventManager )
* and create a stringified representation of the Popcorn constructor (usually to
* insert in a script tag).
*/
- var generatePopcornString = this.generatePopcornString = function( popcornOptions, url, target, method ){
+ var generatePopcornString = this.generatePopcornString = function( popcornOptions, url, target, method, callbacks, scripts ){
+
+ callbacks = callbacks || {};
+ scripts = scripts || {};
+
var popcornString = "";
// prepare popcornOptions as a string
@@ -250,6 +254,13 @@ define( [ "core/logger", "core/eventmanager" ], function( Logger, EventManager )
throw new Error( "Media type not generated yet. Please specify a url for media objects before generating a popcorn string." );
}
+ if( scripts.init ){
+ popcornString += scripts.init + "\n";
+ }
+ if( callbacks.init ){
+ popcornString += callbacks.init + "();\n";
+ }
+
// special case for basePlayer, since it doesn't require as much of a harness
if( _mediaType === "baseplayer" ) {
popcornString += "Popcorn.player( 'baseplayer' );\n" +
@@ -260,6 +271,13 @@ define( [ "core/logger", "core/eventmanager" ], function( Logger, EventManager )
popcornString += "var popcorn = Popcorn.smart( '#" + target + "', '" + url + "'" + popcornOptions + " );\n";
}
+ if( scripts.beforeEvents ){
+ popcornString += scripts.beforeEvents + "\n";
+ }
+ if( callbacks.beforeEvents ){
+ popcornString += callbacks.beforeEvents + "( popcorn );\n";
+ }
+
// if popcorn was built successful
if ( _popcorn ) {
@@ -283,6 +301,13 @@ define( [ "core/logger", "core/eventmanager" ], function( Logger, EventManager )
}
+ if( scripts.afterEvents ){
+ popcornString += scripts.afterEvents + "\n";
+ }
+ if( callbacks.afterEvents ){
+ popcornString += callbacks.afterEvents + "( popcorn );\n";
+ }
+
// if the `method` var is blank, the user probably just wanted an inline function without an onLoad wrapper
method = method || "inline";
View
1  src/dialog/modal.js
@@ -11,6 +11,7 @@ define( [], function(){
if( !__container ){
__container = document.createElement( "div" );
__container.id = "butter-modal-container";
+ __container.setAttribute( "data-butter-exclude", true );
document.body.appendChild( __container );
} //if
View
97 src/butter-main.js → src/main.js
@@ -13,7 +13,8 @@
"./core/target",
"./core/media",
"./core/page",
- "./modules"
+ "./modules",
+ "util/xhr"
],
function(
Logger,
@@ -21,7 +22,8 @@
Target,
Media,
Page,
- Modules
+ Modules,
+ XHR
){
var __guid = 0,
@@ -50,7 +52,9 @@
},
_defaultTarget,
_this = this,
- _selectedEvents = [];
+ _selectedEvents = [],
+ _defaultPopcornScripts = {},
+ _defaultPopcornCallbacks = {};
if ( butterOptions.debug !== undefined ) {
Logger.debug( butterOptions.debug );
@@ -78,7 +82,7 @@
this.getHTML = function(){
var media = [];
for( var i=0; i<_media.length; ++i ){
- media.push( _media[ i ].popcornString );
+ media.push( _media[ i ].generatePopcornString() );
} //for
return _page.getHTML( media );
}; //getHTML
@@ -299,6 +303,9 @@
media = new Media( media );
} //if
+ media.popcornCallbacks = _defaultPopcornCallbacks;
+ media.popcornScripts = _defaultPopcornScripts;
+
var mediaName = media.name;
_media.push( media );
@@ -538,6 +545,73 @@
});
} //if
+ var preparePopcornScriptsAndCallbacks = this.preparePopcornScriptsAndCallbacks = function( readyCallback ){
+ var popcornConfig = _config.popcorn || {},
+ callbacks = popcornConfig.callbacks,
+ scripts = popcornConfig.scripts,
+ toLoad = [],
+ loaded = 0;
+
+ // wrap the load function to remember the script
+ function genLoadFunction( script ){
+ return function( e ){
+ // this = XMLHttpRequest object
+ if( this.readyState === 4 ){
+
+ // if the server sent back a bad response, record empty string and log error
+ if( this.status !== 200 ){
+ _defaultPopcornScripts[ script ] = "";
+ _logger.log( "WARNING: Trouble loading Popcorn script: " + this.response );
+ }
+ else{
+ // otherwise, store the response as text
+ _defaultPopcornScripts[ script ] = this.response;
+ }
+
+ // see if we can call the readyCallback yet
+ ++loaded;
+ if( loaded === toLoad.length && readyCallback ){
+ readyCallback();
+ }
+
+ }
+ }
+ }
+
+ _defaultPopcornCallbacks = callbacks;
+
+ for( var script in scripts ){
+ if( scripts.hasOwnProperty( script ) ){
+ var url = scripts[ script ],
+ probableElement = document.getElementById( url.substring( 1 ) );
+ // check to see if an element on the page contains the script we want
+ if( url.indexOf( "#" ) === 0 ){
+ if( probableElement ){
+ _defaultPopcornScripts[ script ] = probableElement.innerHTML;
+ }
+ }
+ else{
+ // if not, treat it as a url and try to load it
+ toLoad.push({
+ url: url,
+ onLoad: genLoadFunction( script )
+ });
+ }
+ }
+ }
+
+ // if there are scripts to load, load them
+ if( toLoad ){
+ for( var i = 0; i < toLoad.length; ++i ){
+ XHR.get( toLoad[ i ].url, toLoad[ i ].onLoad );
+ }
+ }
+ else{
+ // otherwise, call the ready callback right away
+ readyCallback();
+ }
+ }
+
function readConfig(){
var icons = _config.icons,
img,
@@ -564,10 +638,15 @@
_page = new Page( _config );
//prepare the page next
- preparePage(function(){
- moduleCollection.ready(function(){
- //fire the ready event
- _em.dispatch( "ready", _this );
+ preparePopcornScriptsAndCallbacks(function(){
+ preparePage(function(){
+ moduleCollection.ready(function(){
+ if( _config.snapshotHTMLOnReady ){
+ _page.snapshotHTML();
+ }
+ //fire the ready event
+ _em.dispatch( "ready", _this );
+ });
});
});
@@ -600,6 +679,8 @@
readConfig();
} //if
+ this.page = _page;
+
}
Butter.instances = __instances;
View
5 templates/test-after.js
@@ -0,0 +1,5 @@
+/* Note: This code is just for testing script functionality on Butter init.
+ * Disregard unless you want advanced functionality. */
+(function(){
+ console.log( "inline test after", popcorn );
+}());
View
5 templates/test-before.js
@@ -0,0 +1,5 @@
+/* Note: This code is just for testing script functionality on Butter init.
+ * Disregard unless you want advanced functionality. */
+(function(){
+ console.log( "inline test before", popcorn );
+}());
View
5 templates/test-init.js
@@ -0,0 +1,5 @@
+/* Note: This code is just for testing script functionality on Butter init.
+ * Disregard unless you want advanced functionality. */
+(function(){
+ console.log( "inline test init" );
+}());
View
13 templates/test.js
@@ -37,3 +37,16 @@ document.addEventListener( "DOMContentLoaded", function( e ){
}
}); //Butter
}, false );
+
+_testInitCallback = function(){
+ console.log( "init callback" );
+};
+
+_testBeforeCallback = function( popcorn ){
+ console.log( "before callback", popcorn );
+};
+
+_testAfterCallback = function( popcorn ){
+ console.log( "after callback", popcorn );
+};
+
View
70 test/core.js
@@ -9,6 +9,10 @@
QUnit.config.testTimeout = 20000;
QUnit.config.reorder = false;
+ window._testInitCallback = function(){};
+ window._testBeforeCallback = function(){};
+ window._testAfterCallback = function(){};
+
function createButter( callback ){
stop();
@@ -583,11 +587,11 @@
foo: 2
}
});
- ok( m.popcornString.indexOf( "{\"foo\":2}" ) > -1, "Popcorn string contained specified popcornOptions." );
+ ok( m.generatePopcornString().indexOf( "{\"foo\":2}" ) > -1, "Popcorn string contained specified popcornOptions." );
m.popcornOptions = {
bar: 3
};
- ok( m.popcornString.indexOf( "{\"bar\":3}" ) > -1, "Popcorn string contained specified popcornOptions again." );
+ ok( m.generatePopcornString().indexOf( "{\"bar\":3}" ) > -1, "Popcorn string contained specified popcornOptions again." );
});
});
@@ -603,7 +607,7 @@
te1 = t1.addTrackEvent( { popcornOptions: { start: 0, end: 6, text: messedUpString, target: "stringSanity" }, type: "footnote" } );
butter.addTarget( { name: "beep" } );
- var func = Function( "", m1.popcornString );
+ var func = Function( "", m1.generatePopcornString() );
pop = func();
equals( document.getElementById( "stringSanity" ).children[ 0 ].innerHTML, messedUpString, "String escaping in exported HTML is fine" );
@@ -612,6 +616,30 @@
});
});
+ asyncTest( "Export HTML snapshotting", function() {
+ expect( 1 );
+ createButter( function( butter ){
+ var m1 = butter.addMedia( { url:"../external/popcorn-js/test/trailer.ogv", target:"mediaDiv" } );
+
+ butter.listen( "mediaready", function( e ) {
+ butter.page.snapshotHTML();
+
+ t1 = m1.addTrack();
+ te1 = t1.addTrackEvent({
+ popcornOptions: {
+ start: 0,
+ end: 6,
+ text: "OBVIOUS",
+ target: "stringSanity"
+ },
+ type: "footnote"
+ });
+
+ equals( butter.getHTML().match( "OBVIOUS" ).length, 1, "TrackEvent wasn't exported" );
+ start();
+ });
+ });
+ });
module( "Debug functionality" );
asyncTest( "Debug enables/disables logging", 4, function() {
createButter(function( butter ) {
@@ -638,4 +666,40 @@
butter.addMedia({ url: "../external/popcorn-js/test/trailer.ogv", target: "mediaDiv" });
});
});
+
+ module( "Popcorn scripts and callbacks");
+ asyncTest( "Existence and execution", function(){
+ expect( 6 );
+
+ createButter( function( butter ){
+
+ var theZONE = "";
+
+ window._testInitCallback = function(){ theZONE += "i"; };
+ window._testBeforeCallback = function(){ theZONE += "b"; };
+ window._testAfterCallback = function(){ theZONE += "a" };
+
+ var initScript = document.createElement( "script" );
+ initScript.innerHTML = '"inline test init from element"';
+ initScript.id = "init-script";
+ document.head.appendChild( initScript );
+
+ var m1 = butter.addMedia( { name: "Media 1", target: "audio-test", url: "../external/popcorn-js/test/trailer.ogv" } );
+
+ m1.onReady(function(){
+ butter.preparePopcornScriptsAndCallbacks(function(){
+ document.head.removeChild( initScript );
+ var exported = butter.getHTML();
+ ok( exported.indexOf( "inline test init from element" ) > -1, "found init script" );
+ ok( exported.indexOf( "inline test before" ) > -1, "found before script" );
+ ok( exported.indexOf( "inline test after" ) > -1, "found after script" );
+ ok( theZONE.indexOf( "i" ) > -1, "init callback called" );
+ ok( theZONE.indexOf( "b" ) > -1, "before callback called" );
+ ok( theZONE.indexOf( "a" ) > -1, "after callback called" );
+ start();
+ });
+ });
+
+ });
+ });
})(window, window.document );
View
5 test/test-after.js
@@ -0,0 +1,5 @@
+/* Note: This code is just for testing script functionality on Butter init.
+ * Disregard unless you want advanced functionality. */
+(function(){
+ "inline test after";
+}());
View
5 test/test-before.js
@@ -0,0 +1,5 @@
+/* Note: This code is just for testing script functionality on Butter init.
+ * Disregard unless you want advanced functionality. */
+(function(){
+ "inline test before";
+}());
View
5 test/test-init.js
@@ -0,0 +1,5 @@
+/* Note: This code is just for testing script functionality on Butter init.
+ * Disregard unless you want advanced functionality. */
+(function(){
+ "inline test init";
+}());
View
2  tools/build.js
@@ -26,7 +26,7 @@
// not be found by the AST analysis done in the optimizer.
include: [
'butter',
- 'butter-main'
+ 'main'
],
// Wraps Butter in a closure and adds license information
View
2  tools/build.optimized.js
@@ -26,7 +26,7 @@
// not be found by the AST analysis done in the optimizer.
include: [
'butter',
- 'butter-main'
+ 'main'
],
// Wraps Butter in a closure and adds license information

No commit comments for this range

Something went wrong with that request. Please try again.