remember first pass

This commit is contained in:
George Michael Brower 2014-09-15 23:44:07 -04:00
parent 637b9e5da3
commit bc0cb2bdb9
12 changed files with 494 additions and 233 deletions

42
TODO.md
View File

@ -3,33 +3,32 @@ PARITY
- [ ] folders - [ ] folders
- [ ] function controller - [ ] function controller
- [ ] color controller - [ ] color controller
- [x] string controller
- [x] boolean controller
- [ ] remember - [ ] remember
- [ ] remember option controller
- [ ] remember gui.vars
- [ ] debounce save
- [ ] presets - [ ] presets
NEW FEATURES NEW FEATURES
- [ ] dividers - [ ] dividers
- [ ] save server !! - [ ] save server !!
- [ ] acknowledges save
- [ ] * disable * listen - [ ] * disable * listen
- [ ] override gui.var initialValues with url.js - [ ] override gui.var initialValues with url.js
- [x] docked container
BUILD BUILD
- [x] single import - [ ] gulp breaks on invalid js save
- [x] browsersync - [ ] marked needs to pipe down.
- [x] remove platform, dependent on fix of bug in gulp-vulcanize
REFACTOR REFACTOR
- [x] gui.define* => gui.var* - [ ] dat-gui-base => dat-gui-controller
- [x] Gui.js => gui-panel => dat-gui
- [x] controller-* => dat-gui-*
- [x] kill strict
- [x] Reorg gulpfile and add standardized formatting
DOCS DOCS
@ -37,9 +36,6 @@ DOCS
- [ ] Auto generatated polymer docs - [ ] Auto generatated polymer docs
STYLE STYLE
- [x] touch styles: bigger please!
- [x] kill hover behavior if touch
- [x] sharing more styles
NICE TO HAVES NICE TO HAVES
@ -47,3 +43,21 @@ NICE TO HAVES
- [ ] css linter? - [ ] css linter?
- [ ] strip component-slider from number-controller, for use in custom components - [ ] strip component-slider from number-controller, for use in custom components
- [ ] strip component-input from number-controller, unify with string-controller - [ ] strip component-input from number-controller, unify with string-controller
BONEYARD
- [x] gui.define* => gui.var*
- [x] Gui.js => gui-panel => dat-gui
- [x] controller-* => dat-gui-*
- [x] kill strict
- [x] Reorg gulpfile and add standardized formatting
- [x] string controller
- [x] docked container
- [x] boolean controller
- [x] single import
- [x] browsersync
- [x] touch styles: bigger please!
- [x] kill hover behavior if touch
- [x] sharing more styles
- [x] remove platform, dependent on fix of bug in gulp-vulcanize

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,5 @@
<!-- TODO: move this into dat-gui.html --> <!-- main -->
<!-- <script src="elements/Gui.js"></script> -->
<!-- base elements -->
<link rel="import" href="elements/dat-gui/dat-gui.html"> <link rel="import" href="elements/dat-gui/dat-gui.html">
<link rel="import" href="elements/gui-row/gui-row.html">
<!-- controllers --> <!-- controllers -->
<link rel="import" href="elements/dat-gui-number/dat-gui-number.html"> <link rel="import" href="elements/dat-gui-number/dat-gui-number.html">

View File

@ -1,8 +1,5 @@
/* globals Gui, Polymer, PathObserver */ /* globals Gui, Polymer, PathObserver */
// [ ] onFinishChange()
Polymer( 'dat-gui-base', { Polymer( 'dat-gui-base', {
ready: function() { ready: function() {
@ -11,14 +8,40 @@ Polymer( 'dat-gui-base', {
}, },
// Overrides
// -------------------------------
// Update the UI
update: function() {}, update: function() {},
// Process arguments from gui.add
init: function() {}, init: function() {},
// Return a valid JSON representation of value
serialize: function() {
return JSON.stringify( this.value );
},
// Parse and set JSON representation of value;
unserialize: function( obj ) {
this.value = JSON.parse( obj );
},
// Observers // Observers
// ------------------------------- // -------------------------------
ignore: function() {
// todo: makes the data binding one way
},
watch: function( object, path ) { watch: function( object, path ) {
this.object = object; this.object = object;
@ -40,12 +63,16 @@ Polymer( 'dat-gui-base', {
// ------------------------------- // -------------------------------
on: function( event, listener ) { on: function( event, listener ) {
this.addEventListener( event, listener ); this.addEventListener( event, listener );
return this; return this;
}, },
map: function( x, a, b, c, d ) { map: function( x, a, b, c, d ) {
return ( x - a ) / ( b - a ) * ( d - c ) + c; return ( x - a ) / ( b - a ) * ( d - c ) + c;
}, },
@ -85,4 +112,10 @@ Polymer( 'dat-gui-base', {
}, },
onFinishChange: function( v ) {
return this.onChange( v );
},
} ); } );

View File

@ -29,6 +29,20 @@ Polymer( 'dat-gui-option', {
}, },
// Return a valid JSON representation of value
serialize: function() {
return JSON.stringify( this.key );
},
// Parse and set JSON representation of value;
unserialize: function( obj ) {
this.value = this.options[ JSON.parse( obj ) ];
},
valueChanged: function() { valueChanged: function() {
for ( var i in this.options ) { for ( var i in this.options ) {

View File

@ -7,4 +7,4 @@
padding-left padding padding-left padding
select select
outline: none outline none

View File

@ -4,7 +4,7 @@
<polymer-element <polymer-element
name="dat-gui" name="dat-gui"
attributes="docked autoplace open"> attributes="docked autoplace open localStorage">
<template> <template>
@ -12,10 +12,7 @@
<div id="container" class="docked-{{ docked }} autoplace-{{ autoPlace }} open-{{ open }} touch-{{ touch }}" > <div id="container" class="docked-{{ docked }} autoplace-{{ autoPlace }} open-{{ open }} touch-{{ touch }}" >
<div id="dockedContent"> <div id="dockedContent"></div>
</div>
<div id="panel"> <div id="panel">
@ -33,6 +30,7 @@
</template> </template>
<script src="static.js"></script>
<script src="dat-gui.js"></script> <script src="dat-gui.js"></script>
</polymer-element> </polymer-element>

View File

@ -7,16 +7,20 @@ Polymer( 'dat-gui', {
docked: false, docked: false,
open: true, open: true,
localStorage: false,
touch: ( 'ontouchstart' in window ) || ( !!window.DocumentTouch && document instanceof window.DocumentTouch ), touch: ( 'ontouchstart' in window ) || ( !!window.DocumentTouch && document instanceof window.DocumentTouch ),
ready: function() { ready: function() {
this.vars = {}; this.vars = {};
this._controllersByObject = {};
this.domElement = this; // legacy this.domElement = this; // legacy
}, },
// "Public" API //
// ------------------------------- // -------------------------------
add: function( object, path ) { add: function( object, path ) {
@ -45,7 +49,7 @@ Polymer( 'dat-gui', {
controller.watch( object, path ); controller.watch( object, path );
controller.init.apply( controller, args ); controller.init.apply( controller, args );
// Make row // Make row ( todo: put row in controllers )
var row = document.createElement( 'gui-row' ); var row = document.createElement( 'gui-row' );
row.name = path; row.name = path;
@ -63,23 +67,43 @@ Polymer( 'dat-gui', {
row.appendChild( controller ); row.appendChild( controller );
this.appendChild( row ); this.appendChild( row );
// Remember
if ( object !== this.vars ) {
var objectKey = Gui.serialize( object );
var objectControllers = this._controllersByObject[ objectKey ];
if ( !objectControllers ) {
objectControllers = {};
this._controllersByObject[ objectKey ] = objectControllers;
}
objectControllers[ controller.path ] = controller;
}
return controller; return controller;
}, },
var: function() { remove: function( controller ) {
var name, initialValue, args; this.removeChild( controller );
if ( arguments.length == 1 ) { // Forget
name = arguments[ 0 ];
return this.vars[ name ];
}
initialValue = arguments[ 1 ]; var objectKey = Gui.serialize( controller.object );
name = arguments[ 0 ]; controller.objectKey = objectKey;
args = [ this.vars, name ]; var objectControllers = this._controllersByObject[ objectKey ];
objectControllers.splice( objectControllers.indexOf( controller ), 1 );
},
var: function( name, initialValue ) {
var args = [ this.vars, name ];
args = args.concat( Array.prototype.slice.call( arguments, 2 ) ); args = args.concat( Array.prototype.slice.call( arguments, 2 ) );
this.vars[ name ] = initialValue; this.vars[ name ] = initialValue;
@ -88,19 +112,74 @@ Polymer( 'dat-gui', {
}, },
remember: function( object ) { save: function() {
// todo if ( this.localStorage && window.localStorage ) {
var data = JSON.stringify( this.serialize() );
localStorage.setItem( Gui.LOCAL_STORAGE_KEY, data );
} else {
// todo: success
Gui.postJSON( this.savePath, this.serialize(), function() {}, Gui.error );
}
}, },
unserialize: function( data ) {
for ( var objectKey in this._controllersByObject ) {
for ( var path in data.values[ objectKey ] ) {
var value = data.values[ objectKey ][ path ];
this._controllersByObject[ objectKey ][ path ].unserialize( value );
}
}
},
serialize: function() {
// todo: return json of every controller's serialize.
var data = {
values: {},
vars: {}, // todo
};
for ( var objectKey in this._controllersByObject ) {
data.values[ objectKey ] = {};
var controllers = this._controllersByObject[ objectKey ];
for ( var path in controllers ) {
data.values[ objectKey ][ path ] = controllers[ path ].serialize();
}
}
return data;
},
// Legacy // Legacy
// ------------------------------- // -------------------------------
listAll: function() { remember: function( object ) {
Gui.warn( 'controller.listenAll() is deprecated. All controllers are listened for free.' ); Gui.warn( 'gui.remember() is deprecated. You don\'t need to do it anymore. See Gui.serialize.' );
},
listenAll: function() {
Gui.warn( 'gui.listenAll() is deprecated. All controllers are listened for free.' );
}, },
@ -148,175 +227,3 @@ Polymer( 'dat-gui', {
} }
} ); } );
( function( scope ) {
/* globals Path */
var Gui = function( params ) {
if ( !ready ) {
Gui.error( 'Gui not ready. Put your code inside Gui.ready()' );
}
params = params || {};
// Properties
this.localStorage = params.localStorage || false;
// Make domElement
var panel = document.createElement( 'dat-gui' );
panel.autoPlace = params.autoPlace !== false;
if ( panel.autoPlace ) {
document.body.appendChild( panel );
}
return panel;
};
// Register custom controllers
// -------------------------------
var controllers = {};
Gui.register = function( elementName, test ) {
controllers[ elementName ] = test;
};
// Returns a controller based on a value
// -------------------------------
Gui.getController = function( value ) {
for ( var type in controllers ) {
var test = controllers[ type ];
if ( test( value ) ) {
return document.createElement( type );
}
}
};
// Gui ready handler ... * shakes fist at polymer *
// -------------------------------
var ready = false;
var readyHandlers = [];
var readyPromise;
function readyResolve( resolve ) {
readyHandlers.forEach( function( fnc ) {
fnc();
} );
if ( resolve !== undefined ) {
resolve();
}
}
document.addEventListener( 'polymer-ready', function() {
ready = true;
if ( !readyPromise ) {
readyResolve();
}
} );
Gui.ready = function( fnc ) {
if ( window.Promise && arguments.length === 0 ) {
readyPromise = new Promise( readyResolve );
return readyPromise;
}
if ( ready ) {
fnc();
} else {
readyHandlers.push( fnc );
}
};
// Console
// -------------------------------
Gui.error = function() {
var args = Array.prototype.slice.apply( arguments );
args.unshift( 'dat-gui ::' );
console.error.apply( console, args );
};
Gui.warn = function() {
var args = Array.prototype.slice.apply( arguments );
args.unshift( 'dat-gui ::' );
console.warn.apply( console, args );
};
// Old namespaces
// -------------------------------
var dat = {};
dat.gui = {};
dat.gui.GUI = Gui;
dat.GUI = dat.gui.GUI;
dat.color = {};
dat.color.Color = function() {};
dat.dom = {};
dat.dom.dom = function() {};
dat.controllers = {};
dat.controllers.Controller = constructor( 'dat-gui-base' );
dat.controllers.NumberController = constructor( 'dat-gui-number' );
dat.controllers.FunctionController = constructor( 'dat-gui-function' );
dat.controllers.ColorController = constructor( 'dat-gui-color' );
dat.controllers.BooleanController = constructor( 'dat-gui-boolean' );
dat.controllers.OptionController = constructor( 'dat-gui-option' );
dat.controllers.NumberControllerBox = dat.controllers.NumberController;
dat.controllers.NumberControllerSlider = dat.controllers.NumberController;
function constructor( elementName ) {
return function( object, path ) {
var el = document.createElement( elementName );
el.watch( object, path );
return el;
};
}
// Export
// -------------------------------
scope.dat = dat;
scope.Gui = Gui;
})( this );

301
elements/dat-gui/static.js Normal file
View File

@ -0,0 +1,301 @@
( function( scope ) {
// {
// autoPlace: true,
// localStorage: false,
// autoSave: false,
// savePath: Gui.DEFAULT_SAVE_PATH,
// load: {},
// }
var Gui = function( params ) {
if ( !ready ) {
Gui.error( 'Gui not ready. Use Gui.ready( callback )' );
}
var panel = document.createElement( 'dat-gui' );
Gui.constructor.call( panel, params );
return panel;
};
Gui.constructor = function( params ) {
params = params || {};
// Saving
this.localStorage = scope.localStorage && ( params.localStorage || false );
this.autoSave = params.autoSave || this.localStorage;
this.savePath = params.savePath || Gui.DEFAULT_SAVE_PATH;
if ( this.autoSave ) {
this.addEventListener( 'change', Gui.debounce( this.save, this, 50 ) );
}
if ( params.autoSave && !this.localStorage ) {
Gui.getJSON( this.savePath, this.unserialize, this );
}
if ( this.localStorage && scope.localStorage ) {
var _this = this;
setTimeout( function() {
var data = localStorage.getItem( Gui.LOCAL_STORAGE_KEY );
_this.unserialize( JSON.parse( data ) );
}, 0 );
}
// Autoplace
this.autoPlace = params.autoPlace !== false;
if ( this.autoPlace ) {
document.body.appendChild( this );
}
// Load
if ( params.load ) {
this.load( params.load );
}
};
// Saving
// -------------------------------
Gui.DEFAULT_SAVE_PATH = 'http://localhost:7999/';
Gui.serialize = function( object ) {
// "shallow" stringify
var data = {};
for ( var i in object ) {
var val;
try {
val = JSON.stringify( object[ i ] );
val = object[ i ];
} catch (e) {}
if ( val !== undefined ) {
data[ i ] = val;
}
}
return JSON.stringify( data );
};
Gui.getJSON = function( path, callback, scope ) {
var xhr = new XMLHttpRequest();
xhr.open( 'GET', path, true );
xhr.onreadystatechange = function() {
if ( xhr.readyState == 4 && xhr.status == 200 ) {
callback.call( scope, JSON.parse( xhr.responseText ) );
}
};
xhr.send( null );
};
Gui.postJSON = function( path, data, callback, scope ) {
var xhr = new XMLHttpRequest();
xhr.open( 'POST', path, true );
xhr.onreadystatechange = function() {
if ( xhr.readyState == 4 && xhr.status == 200 ) {
callback.call( scope, xhr.responseText );
}
};
xhr.send( JSON.stringify( data ) );
};
Gui.debounce = function( func, scope, wait ) {
var timeout;
return function() {
var args = arguments;
clearTimeout( timeout );
timeout = setTimeout( function() {
timeout = null;
func.apply( scope, args );
}, wait );
};
};
// Register custom controllers
// -------------------------------
var controllers = {};
Gui.register = function( elementName, test ) {
controllers[ elementName ] = test;
};
// Returns a controller based on a value
// -------------------------------
Gui.getController = function( value ) {
for ( var type in controllers ) {
var test = controllers[ type ];
if ( test( value ) ) {
return document.createElement( type );
}
}
};
// Gui ready handler ... * shakes fist at polymer *
// -------------------------------
var ready = false;
var readyHandlers = [];
var readyPromise;
document.addEventListener( 'polymer-ready', function() {
ready = true;
if ( !readyPromise ) {
readyResolve();
}
} );
Gui.ready = function( fnc ) {
if ( window.Promise && arguments.length === 0 ) {
readyPromise = new Promise( readyResolve );
return readyPromise;
}
if ( ready ) {
fnc();
} else {
readyHandlers.push( fnc );
}
};
function readyResolve( resolve ) {
readyHandlers.forEach( function( fnc ) {
fnc();
} );
if ( resolve !== undefined ) {
resolve();
}
}
// Console
// -------------------------------
Gui.error = function() {
var args = Array.prototype.slice.apply( arguments );
args.unshift( 'dat-gui ::' );
console.error.apply( console, args );
};
Gui.warn = function() {
var args = Array.prototype.slice.apply( arguments );
args.unshift( 'dat-gui ::' );
console.warn.apply( console, args );
};
// Old namespaces
// -------------------------------
var dat = {};
dat.gui = {};
dat.gui.GUI = Gui;
dat.GUI = dat.gui.GUI;
dat.color = {};
dat.color.Color = function() {};
dat.dom = {};
dat.dom.dom = function() {};
dat.controllers = {};
dat.controllers.Controller = constructor( 'dat-gui-base' );
dat.controllers.NumberController = constructor( 'dat-gui-number' );
dat.controllers.FunctionController = constructor( 'dat-gui-function' );
dat.controllers.ColorController = constructor( 'dat-gui-color' );
dat.controllers.BooleanController = constructor( 'dat-gui-boolean' );
dat.controllers.OptionController = constructor( 'dat-gui-option' );
dat.controllers.NumberControllerBox = dat.controllers.NumberController;
dat.controllers.NumberControllerSlider = dat.controllers.NumberController;
function constructor( elementName ) {
return function( object, path ) {
var el = document.createElement( elementName );
el.watch( object, path );
return el;
};
}
// Export
// -------------------------------
scope.dat = dat;
scope.Gui = Gui;
})( this );

View File

@ -6,8 +6,7 @@
<title>dat-gui kitchen sink</title> <title>dat-gui kitchen sink</title>
<!-- // <script src="../build/dat-gui.js"></script> --> <!-- // <script src="../build/dat-gui.js"></script> -->
// <script src="../../platform/platform.js"></script>
<script src="../../platform/platform.js"></script>
<link rel="import" href="../dat-gui.html"> <link rel="import" href="../dat-gui.html">
@ -25,7 +24,8 @@
body content. body content.
<script> <script>
/* globals Gui */
var gui;
var object = { var object = {
"boolean": false, "boolean": false,
@ -41,14 +41,14 @@
// How do we kill polymer-ready ... // How do we kill polymer-ready ...
Gui.ready( function() { Gui.ready( function() {
var gui = new Gui(); gui = new Gui( { localStorage: true } );
gui.docked = true; gui.docked = true;
gui.add( gui, 'docked' ); // gui.add( gui, 'docked' );
var r = gui.add( gui, 'open' ); // var r = gui.add( gui, 'open' );
gui.add( r.row, 'name' ); // gui.add( r.row, 'name' );
gui.add( object, 'boolean' ); gui.add( object, 'boolean' );

View File

@ -15,15 +15,15 @@ http.createServer(function (req, res) {
res.end(); res.end();
return return
} }
res.writeHead(200, {'Content-Type': 'application/json'}); res.writeHead(200, {'Content-Type': 'application/json', 'Access-Control-Allow-Origin': 'http://localhost'});
res.end(fs.readFileSync(filename, 'utf8')); res.end(fs.readFileSync(filename, 'utf8'));
break; break;
case 'POST': case 'POST':
var data = ''; var data = '';
req.on('data', function(d) {data += d;}) req.on('data', function(d) {data += d;})
req.on('end', function() { req.on('end', function() {
res.writeHead(200, {'Access-Control-Allow-Origin': 'http://localhost'});
fs.writeFileSync(filename, data); fs.writeFileSync(filename, data);
res.writeHead(200);
res.end(); res.end();
}) })
break; break;
@ -31,4 +31,4 @@ http.createServer(function (req, res) {
res.writeHead(404); res.writeHead(404);
res.end(); res.end();
} }
}).listen(8080); }).listen(7999);