update interface (fixes issue #6)

This commit is contained in:
Georg Fischer
2015-12-23 23:09:12 +01:00
parent af20f1e045
commit f2e76ee1f3
124 changed files with 10878 additions and 2600 deletions
+128
View File
@@ -0,0 +1,128 @@
/*global define*/
define(
[ 'util/object' ],
function ( objectHelper ) {
// adds publishers to an object that
// other objects can subscribe to.
// only the trigger object can
// publish new messages
// eg: trigger = addPublushers( obj1, 'test' );
// obj1.on( 'test', obj2.doStuff );
// trigger.test.dispatch( 'YOLO' );
function addPublishers () {
var publishers = { };
var allowedKeys = [ ];
var args = Array.prototype.slice.call( arguments );
var obj = args.shift();
if ( obj && args.length ) {
args.forEach( addKey );
}
allowedKeys.forEach( function ( key ) {
if ( ! obj[key] ) {
obj[key] = { };
}
obj[key].dispatch = function () {
dispatch.apply( dispatch, [ key ].concat( Array.prototype.slice.call( arguments ) ) );
};
if ( ! publishers[key] ) {
publishers[key] = [ ];
}
publishers[key].dispatch = function () {
dispatch.apply( dispatch, [ key ].concat( Array.prototype.slice.call( arguments ) ) );
};
} );
function addKey ( newItem ) {
var newKeys = [ ];
var existingKeys = Object.keys( obj );
if ( typeof newItem === 'string' ) {
newKeys = newKeys.concat( newItem.split( ' ' ) );
}
if ( Array.isArray( newItem ) ) {
newKeys = newKeys.concat( newItem );
}
newKeys = newKeys.filter( function ( key ) {
if (
existingKeys.indexOf( key ) === -1 &&
allowedKeys.indexOf( key ) === -1
) {
return true;
} else {
return false;
}
} );
allowedKeys = allowedKeys.concat( newKeys );
}
function on ( key, fn ) {
// on( 'my.sub.ev' ) -> obj.my.sub.on( 'ev' );
if ( typeof key === 'string' && key.indexOf( '.' ) !== -1 ) {
var keyArr = key.split( '.' );
var key = keyArr.pop();
var subObj = objectHelper.getObjectByString( keyArr.join( '.' ), obj );
if ( subObj && typeof subObj.on === 'function' ) {
subObj.on( key, fn );
}
} else {
if ( isKeyAllowed( key ) && typeof fn === 'function' ) {
publishers[key].push( fn );
}
}
return obj;
}
function off ( key, fn ) {
if (
typeof key === 'string' &&
typeof fn === 'function' &&
publishers[key]
) {
for ( var i = publishers[key].length; i >= 0; i-- ) {
if ( publishers[key][i] === fn ) {
publishers[key].splice( i, 1 );
}
}
}
return obj;
}
function dispatch ( key ) {
// http://debuggable.com/posts/turning-javascript-s-arguments-object-into-an-array:4ac50ef8-3bd0-4a2d-8c2e-535ccbdd56cb
var args = Array.prototype.slice.call( arguments ).slice( 1 );
if ( Array.isArray( publishers[key] ) ) {
publishers[key].forEach( function ( fn ) {
fn.apply( fn, args );
} );
}
return obj;
}
function isKeyAllowed ( key ) {
return allowedKeys ? allowedKeys.indexOf( key ) > -1 : true;
}
publishers.dispatch = dispatch;
obj.on = on;
obj.off = off;
return publishers;
}
return addPublishers;
}
);
+80
View File
@@ -0,0 +1,80 @@
/*global define*/
define(
[ 'util/string' ],
function ( strUtil ) {
var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
var results = { };
var tests = {
getusermedia: function () {
return navigator.getUserMedia = (
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia
);
},
fullscreen: function () {
return !! (
getFeature( document, 'fullScreenEnabled' ) ||
getFeature( document, 'fullscreenEnabled' )
);
},
browserdb: function() {
return (
getFeature( window, 'indexedDB' ) ||
getFeature( window, 'openDatabase' )
);
},
browserstorage: function() {
return (
test( 'browserdb' ) ||
getFeature( window, 'localStorage' )
);
},
draganddrop: function () { return 'draggable' in document.createElement( 'span' ); },
touch: function () { return !!( 'ontouchstart' in window ); },
webworker: function () { return !! ( 'Worker' in window ); },
promise: function () { return !! ( 'Promise' in window ); },
localforage: function () {
return ( test( 'promise' ) && test( 'browserstorage' ) );
},
safari: function () { return /^((?!chrome|android).)*safari/i.test( navigator.userAgent ); }
};
function test ( featureName ) {
if ( typeof results[featureName] !== 'undefined' ) {
return results[featureName];
} else {
results[featureName] = tests[featureName] ? tests[featureName]() : false;
return results[featureName];
}
}
function getFeature ( obj, propertyName ) {
var result = testProperty( obj, propertyName );
if ( ! result ) {
for ( var i = 0, len = prefixes.length; i < len; i++ ) {
if ( ! result ) {
result = testProperty( obj, strUtil.toCamelCase( prefixes[i] + '-' + propertyName ) );
} else {
break;
}
}
}
return result;
}
function testProperty ( obj, propertyName ) {
return obj[propertyName];
}
return {
getFeature: getFeature,
test: test
};
}
);
+71 -24
View File
@@ -1,38 +1,85 @@
/*global define*/
define(
function()
{
var update = false;
function () {
var canvas = document.createElement( 'canvas' );
var ctx = canvas.getContext( '2d' );
function resize( canvas, size )
{
function resizeImage ( content, size, callback, returnType ) {
var image = new Image();
var scale = 1;
var isImageData = false;
var isString = false;
if ( canvas.width !== size.width )
{
canvas.width = size.width;
update = true;
image.addEventListener( 'load', imageLoaded );
// url
if ( typeof content === 'string' ) {
isString = true;
image.src = content;
}
if ( canvas.height !== size.height )
{
canvas.height = size.height;
update = true;
// imagedata
if ( content.width && content.height && content.data && content.data.length ) {
isImageData = true;
canvas.width = content.width;
canvas.height = content.height;
scale = Math.min(
size.width / content.width,
size.height / content.height
);
ctx.putImageData( content, 0, 0 );
image.src = canvas.toDataURL( 'image/png', 1 );
}
if ( update )
{
canvas.width = size.width;
canvas.height = size.height;
if ( ! isString && ! isImageData ) {
callback( false );
}
update = false;
function imageLoaded () {
if ( isString && image.src === content ) {
// src loaded
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
scale = Math.min(
size.width / image.naturalWidth,
size.height / image.naturalHeight
);
ctx.drawImage( image, 0, 0 );
image.src = canvas.toDataURL( 'image/png', 1 );
} else {
// imageData loaded
canvas.width = size.width;
canvas.height = size.height;
ctx.scale( scale, scale );
ctx.drawImage( image, 0, 0 );
if ( returnType === 'both' ) {
callback( {
dataURL: canvas.toDataURL( 'image/png', 1 ),
imageData: ctx.getImageData( 0, 0, canvas.width, canvas.height )
} );
} else {
if ( isString || returnType === 'asDataURL' ) {
callback( canvas.toDataURL( 'image/png', 1 ) );
} else {
if ( isImageData || returnType === 'asImageData' ) {
callback( ctx.getImageData( 0, 0, canvas.width, canvas.height ) );
} else {
callback();
}
}
}
}
}
}
function clear( canvas, ctx )
{
ctx.clearRect( ctx, 0, 0, canvas.width, canvas.height );
}
return { resize: resize, clear: clear };
return {
resizeImage: resizeImage
};
}
);
+43
View File
@@ -0,0 +1,43 @@
/*global define*/
define(
function () {
function getCSSMatrix ( el ) {
var style = window.getComputedStyle( el );
return style.getPropertyValue( '-webkit-transform' ) ||
style.getPropertyValue( '-moz-transform' ) ||
style.getPropertyValue( '-ms-transform' ) ||
style.getPropertyValue( '-o-transform' ) ||
style.getPropertyValue( 'transform' );
}
function cssMatrixToTransformObj ( matrix ) {
// this happens when there was no rotation yet in CSS
if ( matrix === 'none' ) {
matrix = 'matrix(0,0,0,0,0)';
}
var obj = { };
var values = matrix.match( /([-+]?[\d\.]+)/g );
obj.rotate = ( Math.round(
Math.atan2(
parseFloat( values[1] ),
parseFloat( values[0] ) ) * ( 180 / Math.PI )
) || 0
).toString() + 'deg';
obj.translateStr = values[5] ? values[4] + 'px, ' + values[5] + 'px' : ( values[4] ? values[4] + 'px' : '' );
obj.translateX = parseFloat( values[4] );
obj.translateY = values[5] ? parseFloat( values[5] ) : 0;
return obj;
}
return {
getCSSMatrix: getCSSMatrix,
cssMatrixToTransformObj: cssMatrixToTransformObj
}
}
);
+37
View File
@@ -0,0 +1,37 @@
/*global define*/
define(
function () {
function setTransform ( el, transformStr ) {
el.style.transform = el.style.webkitTransform = el.style.msTransform = transformStr;
}
// http://stackoverflow.com/a/2234986/229189
function isDescendant ( parent, child ) {
var node = child.parentNode;
while ( node != null ) {
if ( node == parent ) {
return true;
}
node = node.parentNode;
}
return false;
}
// http://stackoverflow.com/a/384380/229189
function isElement ( obj ) {
return (
typeof HTMLElement === 'object' ? obj instanceof HTMLElement :
obj && typeof obj === 'object' && obj !== null && obj.nodeType === 1 && typeof obj.nodeName === 'string'
);
}
return {
setTransform: setTransform,
isDescendant: isDescendant,
isElement: isElement
};
}
);
+107
View File
@@ -0,0 +1,107 @@
/*global define*/
define(
[ 'util/dom', 'util/localizeText' ],
function ( domHelper, loc ) {
var svgEls = [ 'g', 'svg', 'rect' ];
var svgNameSpace = 'http://www.w3.org/2000/svg';
function createEl ( elementStr, cssClasses, parentEl ) {
var hasNameSpace = svgEls.indexOf( elementStr ) !== -1;
var el = hasNameSpace ? document.createElementNS( svgNameSpace, elementStr ) : document.createElement( elementStr );
if ( hasNameSpace ) {
document.createElementNS( 'http://www.w3.org/2000/svg', 'rect' );
}
cssClasses = typeof cssClasses === 'string' ? [ ].concat( cssClasses.split( ' ' ) ) : cssClasses;
if ( Array.isArray( cssClasses ) ) {
cssClasses.forEach( function ( cssClass ) {
el.classList.add( cssClass );
} );
}
if ( parentEl && parentEl.appendChild ) {
parentEl.appendChild( el );
}
return el;
}
function createButton ( content, title, cssClasses, parentEl, onClick ) {
var btnEl = createEl( 'button', cssClasses, parentEl );
if ( typeof content === 'string' ) {
// btnEl.textContent = content;
loc( btnEl, 'textContent', content );
} else {
if ( domHelper.isElement( content ) ) {
btnEl.appendChild( content );
}
}
// btnEl.title = title;
loc( btnEl, 'title', title );
if ( typeof onClick === 'function' ) {
btnEl.addEventListener( 'click', onClick );
}
return btnEl;
}
function createLink ( content, title, href, target, cssClasses, parentEl ) {
var linkEl = createEl( 'a', cssClasses, parentEl );
if ( typeof content === 'string' ) {
// linkEl.textContent = content;
loc( linkEl, 'textContent', content );
} else {
if ( domHelper.isElement( content ) ) {
linkEl.appendChild( content );
}
}
if ( title ) {
// linkEl.title = title;
loc( linkEl, 'title', title );
}
if ( href ) {
linkEl.href = href;
}
if ( target ) {
linkEl.target = target;
}
return linkEl;
}
function createLabel ( content, forId, cssClasses, parentEl ) {
var labelEl = createEl( 'label', cssClasses, parentEl );
if ( typeof content === 'string' ) {
// labelEl.textContent = content;
loc( labelEl, 'textContent', content );
} else {
if ( domHelper.isElement( content ) ) {
labelEl.appendChild( content );
}
}
if ( forId ) {
labelEl.setAttribute( 'for', forId );
}
return labelEl;
}
return {
createEl: createEl,
createButton: createButton,
createLink: createLink,
createLabel: createLabel
}
}
);
-48
View File
@@ -1,48 +0,0 @@
/*global define*/
define(
function()
{
var tests = {
'canvas': { required: true, test: function(){ return !! document.createElement('canvas').getContext; } },
'query-selector-all': { required: false, test: function(){ return !! document.querySelectorAll; } },
'drag-drop': { required: false, test: function(){ return 'draggable' in document.createElement('span'); } },
'file-api': { required: false, test: function(){ return typeof FileReader !== 'undefined'; } }
};
function test( success, error )
{
var required_supported = true;
var results = { };
var required_features_missing = [ ];
for ( var key in tests )
{
var result = tests[key].test();
if ( ! result )
{
if ( tests[key].required )
{
required_supported = false;
required_features_missing.push( key );
}
}
results[key] = result;
}
if ( required_supported )
{
success( results );
}
else
{
error( required_features_missing, results );
}
}
return test;
}
);
+11
View File
@@ -0,0 +1,11 @@
/*global define*/
define(
[ 'models/localisationmodel' ],
function ( LocalisationModel ) {
function loc () {
return LocalisationModel.sharedInstance.localizeText.apply( LocalisationModel.sharedInstance, arguments );
}
return loc;
}
);
+22
View File
@@ -0,0 +1,22 @@
/*global define*/
define(
function () {
function mapRange ( value, inMin, inMax, outMin, outMax, clampResult ) {
var result = ( ( value - inMin ) / ( inMax - inMin ) * ( outMax - outMin ) + outMin );
if ( clampResult ) {
if ( outMin > outMax ) {
result = Math.min( Math.max( result, outMax ), outMin );
} else {
result = Math.min( Math.max( result, outMin ), outMax );
}
}
return result;
}
return {
mapRange: mapRange
};
}
);
+24
View File
@@ -0,0 +1,24 @@
/*global define*/
define(
function () {
// http://stackoverflow.com/a/11646945
var MediaStream = window.MediaStream;
if ( typeof MediaStream === 'undefined' && typeof webkitMediaStream !== 'undefined' ) {
MediaStream = webkitMediaStream;
}
/*global MediaStream:true */
if ( typeof MediaStream !== 'undefined' && !( 'stop' in MediaStream.prototype ) ) {
MediaStream.prototype.stop = function () {
this.getAudioTracks().forEach( function ( track ) {
track.stop();
} );
this.getVideoTracks().forEach( function ( track ) {
track.stop();
} );
};
}
}
)
+35
View File
@@ -0,0 +1,35 @@
/*global define*/
define(
function () {
// http://stackoverflow.com/a/6491621/229189
function getObjectByString ( str, obj ) {
if ( typeof str === 'string' ) {
str = str.replace( /\[(\w+)\]/g, '.$1' ); // convert indexes to properties
str = str.replace( /^\./, '' ); // strip a leading dot
var keys = str.split( '.' );
for ( var i = 0, len = keys.length; i < len; ++i ) {
var key = keys[i];
if ( key in obj ) {
obj = obj[key];
} else {
return;
}
}
}
return obj;
}
function getCopy ( obj ) {
return JSON.parse( JSON.stringify( obj ) );
}
return {
getObjectByString: getObjectByString,
getCopy: getCopy
};
}
);
+79
View File
@@ -0,0 +1,79 @@
/*global define*/
define(
function () {
function toCamelCase ( str ) {
// if array was passed
if ( str && Array.isArray( str ) ) {
str = str.join( ' ' );
}
var parts = str.split( /(-|\s|_)/gmi );
var result = '';
parts.forEach( function ( item, index ) {
if ( ! item.match( /(-|\s|_)/gmi ) ) {
if ( index > 0 && item.length > 1 ) {
result += item.charAt( 0 ).toUpperCase() + item.slice( 1 );
} else {
result += item;
}
}
} );
return result;
}
function markdownToHtml ( str, options ) {
return autop(
markdownLinksToHtml( str, options.links ),
options.autop
);
}
function markdownLinksToHtml ( str, options ) {
var attributes = [ ];
var attributeStr = '';
if ( options ) {
if ( options.newTab ) {
attributes.push( 'target="_blank"' );
}
if ( options.cssClasses ) {
attributes.push( 'class="' + cssClasses + '"' );
}
}
attributeStr = attributes.length ? ' ' + attributes.join( ' ' ) : '';
var linkHTML = '<a href="$2"' + attributeStr + '>$1</a>';
return str
.replace( /\\n/gm, '\n')
.replace( /\[(.*?)\]\((.+?)\)/g, linkHTML );
}
function autop ( str, options ) {
var tag = ( options && options.tag ) ? options.tag : 'p';
var lineBreakTag = ( options && options.linebreak ) ? '<' + options.linebreak + '>' : '<br />';
var startTag = '<' + tag + '>';
var endTag = '</' + tag + '>';
if ( options && options.cssClasses && typeof options.cssClasses === 'string' ) {
startTag = '<' + tag + ' class="' + options.cssClasses + '">';
}
return startTag + str
.replace( /\n{2}/g, '&nbsp;' + endTag + startTag )
.replace(/\n/g, '&nbsp;' + lineBreakTag ) +
endTag;
}
return {
toCamelCase: toCamelCase,
autop: autop,
markdownToHtml: markdownToHtml,
markdownLinksToHtml: markdownLinksToHtml
};
}
)
+82
View File
@@ -0,0 +1,82 @@
/*global define*/
define(
function () {
var lang = navigator.language || navigator.userLanguage || 'en-us';
var intlIsSupported = !! window.Intl;
function dateToStr ( date ) {
return date.toISOString();
}
function timestampToDate ( str ) {
return new Date( parseInt( str, 10 ) );
}
function dateTimeToLocalStr ( date ) {
if (
intlIsSupported &&
Intl.DateTimeFormat.supportedLocalesOf( [ lang ] ).length &&
date.toLocaleDateString &&
date.toLocaleTimeString
) {
return date.toLocaleDateString( lang ) + ' ' + date.toLocaleTimeString( lang );
} else {
return dateToLocalStr( date ) + ' ' + timeToLocalStr( date );
}
}
function dateToLocalStr ( date ) {
if (
intlIsSupported &&
Intl.DateTimeFormat.supportedLocalesOf( [ lang ] ).length &&
date.toLocaleDateString
) {
return date.toLocaleDateString( lang );
} else {
if ( navigator.language.toLowerCase() === 'en-us' ) {
return ( date.getMonth() + 1 ) + '/' + date.getDate() + '/' + date.getFullYear();
} else {
return ( date.getDate() + '.' + date.getMonth() + 1 ) + '.' + date.getFullYear();
}
}
}
function timeToLocalStr ( date ) {
if (
intlIsSupported &&
Intl.DateTimeFormat.supportedLocalesOf( [ lang ] ).length &&
date.toLocaleTimeString
) {
return date.toLocaleTimeString( lang );
} else {
var hours = date.getHours();
var minutes = date.getMinutes();
if ( hours < 10 ) { hours = '0' + hours; }
if ( minutes < 10 ) { minutes = '0' + minutes; }
if ( navigator.language.toLowerCase().indexOf( 'en' ) >= 0 ) {
var amPm = 'AM';
if ( hours > 12 ) {
hours -= 12;
amPm = 'PM';
}
return hours + ':' + minutes + ' ' + amPm;
} else {
return hours + ':' + minutes;
}
}
}
return {
dateToStr: dateToStr,
dateToLocalStr: dateToLocalStr,
timeToLocalStr: timeToLocalStr,
dateTimeToLocalStr: dateTimeToLocalStr,
timestampToDate: timestampToDate
};
}
);
-71
View File
@@ -1,71 +0,0 @@
/*global define*/
define(
function()
{
// http://stackoverflow.com/a/2381862/229189
function triggerEvent( node, event_name )
{
var doc;
if ( node.ownerDocument )
{
doc = node.ownerDocument;
}
else if ( node.nodeType === 9 )
{
doc = node;
}
else
{
throw new Error('Invalid node passed to fireEvent: ' + node.id);
}
if ( node.fireEvent )
{
// IE-style
var event = doc.createEventObject();
event.synthetic = true;
node.fireEvent( 'on' + event_name, event );
}
else if ( node.dispatchEvent )
{
var event_class = '';
switch ( event_name )
{
case 'click':
case 'mousedown':
case 'mouseup':
event_class = 'MouseEvents';
break;
case 'focus':
case 'change':
case 'blur':
case 'select':
event_class = 'HTMLEvents';
break;
default:
throw 'triggerEvent: Couldnt find an event class for event ' + event_name + '.';
break;
}
var event = doc.createEvent( event_class );
var bubbles = event_name == 'change' ? false : true;
event.initEvent( event_name, bubbles, true );
event.synthetic = true;
node.dispatchEvent( event );
}
}
return triggerEvent;
}
);