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
+109
View File
@@ -0,0 +1,109 @@
/*global define*/
define(
[ 'util/object', 'util/addpublishers' ],
function ( objectHelper, addPublishers ) {
// the controlsmodel stores and manages all
// values of the input sliders
function ControlsModel ( initialValues ) {
if ( ! ( this instanceof ControlsModel ) ) {
return new ControlsModel( initialValues );
}
var self = this;
var publishers = addPublishers( self, [ 'update' ] );
var limits = getLimits( initialValues ) || { };
var values = getValues( initialValues ) || { };
function updateValues ( newValues ) {
if ( newValues ) {
newValues = objectHelper.getCopy( newValues );
var referenceValue;
var newValue;
for ( var key in newValues ) {
limit = limits[key];
newValue = newValues[key];
if (
typeof limit !== 'undefined' &&
typeof newValue === 'number' &&
! isNaN( newValue ) &&
newValue >= limit.min &&
newValue <= limit.max &&
values[key] !== newValue
) {
values[key] = newValue;
publishers.update.dispatch( key, values[key] );
}
}
}
return self;
}
function setValue ( key, newValue ) {
if (
typeof values[key] === 'number' &&
typeof newValue === 'number' &&
! isNaN( newValue )
) {
values[key] = newValue;
publishers.update.dispatch( key, values[key] );
}
return self;
}
function randomizeValues () {
var randomValues = { };
for ( var key in limits ) {
randomValues[key] = parseInt(
Math.random() * ( limits[key].max - limits[key].min ) + limits[key].min,
10
);
}
updateValues( randomValues );
return self;
}
function getValues ( vals ) {
var result = { };
vals = vals || values;
for ( var key in vals ) {
if ( typeof vals[key].value === 'number' ) {
result[key] = vals[key].value;
} else {
result[key] = vals[key];
}
}
return objectHelper.getCopy( result );
}
function getLimits ( vals ) {
var result = { };
for ( var key in vals ) {
result[key] = {
min: vals[key].min,
max: vals[key].max
};
}
return objectHelper.getCopy( result );
}
self.randomizeValues = randomizeValues;
self.setValue = setValue;
self.getValues = getValues;
}
return ControlsModel;
}
);
+81
View File
@@ -0,0 +1,81 @@
/*global define*/
define(
[ 'config', 'lib/glitch-canvas-with-worker', 'util/addpublishers', 'util/canvas' ],
function ( config, canvasGlitcher, addPublishers, canvasHelper ) {
// the glitchModel takes care of glitching the image and passing it along as imageData
function GlitchModel () {
if ( ! ( this instanceof GlitchModel ) ) {
return new GlitchModel();
}
var self = this;
var publishers = addPublishers( self, 'glitch' );
var params = { };
var originalImageData;
var glitchedImageData;
var thumbnailCanvas = document.createElement( 'canvas' );
var thumbnailImg = new Image();
var glitchTimeoutId = NaN;
var glitcher = canvasGlitcher( config.workers.glitch ).init();
function updateGlitch () {
if ( params && originalImageData ) {
glitcher.glitch( originalImageData, params, glitchComplete );
}
}
function glitchComplete ( glitchData ) {
glitchedImageData = glitchData;
publishers.glitch.dispatch( glitchData );
}
function setValue ( key, newValue ) {
if ( params[key] !== newValue ) {
params[key] = newValue;
glitchTimeoutId = setTimeout( updateGlitch, 10 );
}
}
function setImageData ( newImageData ) {
originalImageData = newImageData;
updateGlitch()
}
function generateImageURL ( callback, size, args ) {
if ( originalImageData ) {
size = size || { width: 50, height: 50 };
if ( typeof size === 'string' && size === 'original' ) {
size = {
width: glitchedImageData.width,
height: glitchedImageData.height
};
}
canvasHelper.resizeImage( glitchedImageData, size, function ( imageUrl ) {
args = Array.prototype.slice.call( args || [ ] );
args.unshift( imageUrl );
callback.apply( callback, args );
}, 'asDataURL' );
}
return self;
}
function getImageGenerationFn ( callback, size ) {
return function () {
generateImageURL( callback, size, arguments )
};
}
self.setValue = setValue;
self.setImageData = setImageData;
self.generateImageURL = generateImageURL;
self.getImageGenerationFn = getImageGenerationFn;
}
return GlitchModel;
}
)
+169
View File
@@ -0,0 +1,169 @@
/*global define*/
define(
[ 'util/browser', 'util/addpublishers', 'util/time', 'util/canvas', 'util/localizetext' ],
function ( browser, addPublishers , timeHelper, canvasHelper, loc ) {
// the imageModel loads and stores the latest open image file
// (the original, not the glitched version) and converts it into
// a imageData object
function ImageModel () {
if ( ! ( this instanceof ImageModel ) ) {
return new ImageModel();
}
var self = this;
var publishers = addPublishers( self, [ 'load', 'update', 'error', 'statusmessage' ] );
var canvasEl = document.createElement( 'canvas' );
var ctx = canvasEl.getContext( '2d' );
var imageEl = new Image();
var fileReader;
var canHandleFileImport = false;
var lastImageSrc;
var lastFileName;
// max image import filesize in megabytes.
// because of not 100% clear base64 url size constraints
// if the uploaded image is bigger, resize
// var maxFileSize = Math.pow(1024, 2) * 1.5;
var maxFileSize = 0.8 * Math.pow( 1000, 2 );
var isScalingDown = true;
if ( fileReader = browser.getFeature( window, 'FileReader' ) ) {
fileReader = new fileReader();
canHandleFileImport = true;
fileReader.addEventListener( 'load', fileLoaded );
fileReader.addEventListener( 'error', fileLoadFailed );
}
imageEl.addEventListener( 'load', imageLoaded );
imageEl.addEventListener( 'error', imageLoadFailed );
function loadFromFile ( file ) {
if ( canHandleFileImport ) {
lastFileName = file.name;
fileReader.readAsDataURL( file );
}
return self;
}
function loadFromVideo ( videoEl ) {
clearCanvas();
canvasEl.width = videoEl.width || videoEl.videoWidth || videoEl.clientWidth;
canvasEl.height = videoEl.height || videoEl.videoHeight || videoEl.clientHeight;
ctx.translate( canvasEl.width, 0 );
ctx.scale( -1, 1 );
ctx.drawImage( videoEl, 0, 0 );
lastImageSrc = canvasEl.toDataURL( 'image/png' );
lastFileName = loc( 'webcam.picture', timeHelper.dateTimeToLocalStr( new Date() ) );
checkImageData( ctx.getImageData( 0, 0, canvasEl.width, canvasEl.height ), publishers.load.dispatch );
return self;
}
function loadFromURL ( url, fileName ) {
if ( fileName ) {
lastFileName = fileName;
}
url = decodeURIComponent( url );
publishers.update.dispatch( 'img', url, fileName );
if ( url && imageEl.src !== url ) {
imageEl.src = '';
lastImageSrc = url;
imageEl.src = url;
} else {
imageLoaded();
}
return self;
}
function clearCanvas () {
ctx.clearRect( 0, 0, canvasEl.width, canvasEl.height );
}
function imageLoaded () {
var imageData = getImageData( imageEl );
checkImageData( imageData, publishers.load.dispatch );
}
function imageLoadFailed ( err ) {
publishers.error.dispatch( 'file.error.openimage', imageEl.src );
}
function fileLoaded ( event ) {
loadFromURL( event.target.result );
}
function fileLoadFailed ( error ) {
publishers.error.dispatch( 'file.error.openfile' );
}
function checkImageData ( imageData, callback ) {
if ( isScalingDown && imageData.data && imageData.data.length / 4 > maxFileSize ) {
var widthToHeightRatio = imageData.width / imageData.height;
var heightTiWidthRatio = imageData.height / imageData.width;
var newWidth = Math.round( Math.sqrt( maxFileSize / widthToHeightRatio ) );
var newHeight = Math.round( newWidth * heightTiWidthRatio );
var newSize = {
width: newWidth,
height: newHeight
};
publishers.statusmessage.dispatch( 'file.message.resize' );
canvasHelper.resizeImage( imageData, newSize, function ( result ) {
callback( result.imageData );
if ( typeof result.dataURL === 'string' ) {
lastImageSrc = result.dataURL;
}
}, 'both' );
} else {
callback( imageData );
}
}
function settingUpdated ( key, value ) {
if ( key === 'resizeUploadedImages' && typeof value === 'boolean' ) {
isScalingDown = value;
}
}
function getImageData ( img ) {
clearCanvas();
canvasEl.width = img.naturalWidth;
canvasEl.height = img.naturalHeight;
ctx.drawImage( img, 0, 0, img.naturalWidth, img.naturalHeight );
return ctx.getImageData( 0, 0, img.naturalWidth, img.naturalHeight );
}
function getLastImageSRC ( img ) {
return lastImageSrc;
}
function getLastFileName ( img ) {
return lastFileName;
}
self.loadFromFile = loadFromFile;
self.loadFromVideo = loadFromVideo;
self.getLastImageSRC = getLastImageSRC;
self.getLastFileName = getLastFileName;
self.loadFromURL = loadFromURL;
self.settingUpdated = settingUpdated;
}
return ImageModel;
}
);
+159
View File
@@ -0,0 +1,159 @@
/*global define*/
define(
[ 'config', 'util/dom', 'util/object', 'util/string', 'util/addpublishers', 'lib/reqwest' ],
function ( config, domHelper, objectHelper, stringHelper, addPublishers, reqwest ) {
function LocalisationModel () {
if ( ! ( this instanceof LocalisationModel ) ) {
return new LocalisationModel();
}
var self = this;
var publishers = addPublishers( self, 'error' );
var textElData = [ ];
var texts = '';
var currentLanguage = '';
var animationFrameId = NaN;
var languageWasLoaded = false;
var linkOptions = { links: { newTab: true } };
function setLanguage ( newLanguage ) {
if ( newLanguage !== currentLanguage && newLanguage in config.availableLanguages ) {
loadLanguage( newLanguage );
}
}
function loadLanguage ( languageName ) {
languageWasLoaded = false;
reqwest( {
url: config.language.dir + '/' + languageName + '.json',
type: 'json',
method: 'get',
error: function ( err, one, two ) {
// if this is the first language to load, that's really bad.
languageWasLoaded = true;
publishers.error.dispatch( 'I\'m really sorry. I failed to load the language file for ' + languageName + '. This is a serious error that makes the app very hard to use. Maybe you can try reloading?' );
},
success: function ( res ) {
languageLoaded( languageName, res );
}
} );
}
function languageLoaded ( newLanguageName, newTexts ) {
currentLanguage = newLanguageName;
languageWasLoaded = true;
texts = newTexts;
resetAllTexts();
updateAllTexts();
}
function updateAllTexts () {
if ( languageWasLoaded ) {
cancelAnimationFrame( animationFrameId );
animationFrameId = requestAnimationFrame( function () {
var item;
var args;
for ( var i = textElData.length - 1; i >= 0; i-- ) {
item = textElData[i];
if ( domHelper.isElement( item.el ) ) {
if ( ! item.wasUpdated ) {
if ( item.attribute === 'innerHTML' ) {
item.el.innerHTML = stringHelper.markdownToHtml( getTextForKey( item.key, item.args ), linkOptions );
} else {
item.el[item.attribute] = getTextForKey( item.key, item.args );
}
item.wasUpdated = true;
}
}
else {
textElData.splice( i, 1 );
}
}
} );
}
}
function resetAllTexts () {
textElData.forEach( function ( item ) {
item.wasUpdated = false;
} );
}
function getTextForKey ( key, args ) {
var result = '';
try {
result = objectHelper.getObjectByString( key, texts );
} catch ( e ) {
if ( languageWasLoaded ) {
result = key
}
};
if ( args && args.length ) {
var regex;
args.forEach( function ( arg, index ) {
regex = new RegExp( '{\\$' + ( index + 1 ) + '}' );
result = result.replace( regex, arg );
} );
}
return result;
}
// http://mzl.la/1RDxjVO
function getArgs ( args, firstIndex ) {
firstIndex = firstIndex || 3;
var result;
if ( args.length > firstIndex ) {
result = [ ];
}
for ( var i = firstIndex, len = args.length; i < len; i++ ) {
result[result.length] = args[i];
}
return result;
}
function settingUpdated ( name, value ) {
if ( name === 'language' && value !== currentLanguage ) {
loadLanguage( value );
}
}
function localizeText ( el, attribute, key ) {
if ( el && attribute && key ) {
textElData.push( { el: el, attribute: attribute, key: key, wasUpdated: false, args: getArgs( arguments ) } );
} else {
if ( typeof el === 'string' ) {
return getTextForKey( el, getArgs( arguments, 1 ) );
}
}
updateAllTexts();
}
self.setLanguage = setLanguage;
self.localizeText = localizeText;
self.settingUpdated = settingUpdated;
self.randomNumber = ~~( Math.random() * 1000 );
}
LocalisationModel.sharedInstance = LocalisationModel();
return LocalisationModel;
}
);
+39
View File
@@ -0,0 +1,39 @@
/*global define*/
define(
[ 'util/addpublishers' ],
function ( addPublishers ) {
// the NetworkModel updates the app if the device connectivity changed
function NetworkModel () {
if ( ! ( this instanceof NetworkModel ) ) {
return new NetworkModel();
}
var self = this;
var publishers = addPublishers( self, 'connectivitychange', 'disconnect', 'connect' );
var isConnected;
window.addEventListener( 'online', checkConnectivity );
window.addEventListener( 'offline', checkConnectivity );
function checkConnectivity () {
if ( navigator.onLine !== isConnected ) {
isConnected = navigator.onLine;
publishers.connectivitychange.dispatch( isConnected );
if ( isConnected ) {
publishers.connect.dispatch();
} else {
publishers.disconnect.dispatch();
}
}
return self;
}
self.checkConnectivity = checkConnectivity;
}
return NetworkModel;
}
);
+178
View File
@@ -0,0 +1,178 @@
/*global define*/
define(
[ 'config', 'util/browser', 'util/object', 'util/addpublishers', 'lib/localforage.nopromises' ],
function ( config, browser, objectHelper, addPublishers, localforage ) {
function SettingsModel ( storageKey ) {
if ( ! ( this instanceof SettingsModel ) ) {
return new SettingsModel( storageKey );
}
var self = this;
var publisherNames = [ 'update', 'error' ];
var publishers = addPublishers( self, publisherNames );
var useLocalForage = browser.test( 'localforage' ) && localforage;
var worker;
var defaultSettings = config.settings;
var userLanguage = ( navigator.language || navigator.userLanguage || '' ).toLowerCase();
if ( userLanguage !== '' && defaultSettings.language.options.indexOf( userLanguage ) > -1 ) {
defaultSettings.language.value = userLanguage;
}
var settings = { };
storageKey = storageKey || 'settings';
if ( useLocalForage && browser.test( 'webworker' ) && browser.test( 'browserdb' ) && ! browser.test( 'safari' ) ) {
worker = new Worker( config.workers.settings );
worker.addEventListener( 'message', workerResponded, false );
sendMessageToWorker( 'setStorageKey', storageKey );
sendMessageToWorker( 'setDefaultSettings', defaultSettings );
} else {
settingsUpdated( defaultSettings );
}
function getSetting ( key ) {
return settings[key];
}
function getSettingValue ( key ) {
var setting = getSetting( key );
if ( setting ) {
return setting.value;
} else {
return;
}
}
function getSettings () {
return objectHelper.getCopy( settings );
}
function setValue ( key, value ) {
var wasUpdated = false;
if (
typeof key === 'string' &&
typeof settings[key] !== 'undefined' &&
typeof value === typeof settings[key].value &&
value !== settings[key].value
) {
settings[key].value = value;
wasUpdated = true;
}
if ( wasUpdated ) {
if ( useLocalForage ) {
save( settings );
} else {
settingsUpdated( settings );
}
}
return self;
}
function save ( newSettings ) {
if ( useLocalForage ) {
if ( worker ) {
sendMessageToWorker( 'save', newSettings );
} else {
localforage.setItem( storageKey, newSettings, function ( err, savedSettings ) {
if ( err ) {
sendError( 'settings.error.save' );
console && console.log( 'localforage error', err );
} else {
if ( savedSettings ) {
settingsUpdated( savedSettings );
} else {
console && console.log( 'no data was saved', savedSettings );
}
}
} );
}
}
}
function load () {
if ( useLocalForage ) {
if ( worker ) {
sendMessageToWorker( 'load' );
} else {
localforage.getItem( storageKey, function ( err, loadedSettings ) {
if ( err ) {
sendError( 'settings.error.load' );
console && console.log( 'localforage error', err );
} else {
settingsUpdated( loadedSettings );
}
} );
}
} else {
settingsUpdated( settings || defaultSettings );
}
}
function sendMessageToWorker ( type, data ) {
if ( typeof type === 'string' ) {
if ( typeof data === 'undefined' ) {
data = type;
}
var message = { };
message[type] = data;
worker.postMessage( message );
}
}
function workerResponded ( event ) {
if ( event && event.data ) {
publisherNames.forEach( function ( type ) {
if ( typeof event.data[type] !== 'undefined' ) {
if ( type === 'update' ) {
settingsUpdated( event.data[type] );
} else {
if ( publishers[type] === type ) {
publishers[type].dispatch()
} else {
publishers[type].dispatch( event.data[type] )
}
}
}
} );
}
}
function settingsUpdated ( newSettings ) {
if ( newSettings ) {
settings = newSettings || defaultSettings;
if ( settings !== defaultSettings ) {
for ( var name in defaultSettings ) {
if ( ! settings[name] ) {
settings[name] = defaultSettings[name];
}
}
}
for ( var name in settings ) {
publishers.update.dispatch( name, settings[name].value, settings[name].options );
}
} else {
settings = defaultSettings;
save( settings );
}
}
self.getSetting = getSetting;
self.getSettingValue = getSettingValue;
self.getSettings = getSettings;
self.setValue = setValue;
self.load = load;
}
return SettingsModel;
}
);
+107
View File
@@ -0,0 +1,107 @@
/*global define*/
define(
[ 'config', 'lib/reqwest', 'util/addpublishers' ],
function ( config, reqwest, addPublishers ) {
// the ShareModel uploads and removes images from Imgur
function ShareModel () {
if ( ! ( this instanceof ShareModel ) ) {
return new ShareModel();
}
var self = this;
var base64Url;
var publishers = addPublishers( self,
'uploadstart', 'uploadend', 'uploadcomplete',
'removestart', 'removeend', 'removecomplete',
'error', 'statusmessage'
);
// http://stackoverflow.com/questions/17805456/upload-a-canvas-image-to-imgur-api-v3-with-javascript
function upload () {
if ( base64Url ) {
publishers.uploadstart.dispatch();
reqwest( {
url: 'https://api.imgur.com/3/image.json',
method: 'POST',
headers: {
Authorization: 'Client-ID ' + config.keys.imgur
},
data: {
image: base64Url.split( ',' )[1],
type: 'base64'
},
type: 'json',
crossOrigin: true,
success: uploadSuceeded,
error: uploadFailed
} );
} else {
uploadFailed( new Error( 'share.error.base64' ) );
}
return self;
}
function uploadSuceeded ( res ) {
publishers.uploadend.dispatch();
if ( res.status === 200 && res.data && res.data.link ) {
var link = res.data.link.replace( 'http://', 'https://' );
publishers.uploadcomplete.dispatch( link, res.data.id, res.data.deletehash );
publishers.statusmessage.dispatch( 'share.message.upload', { innerHTML: true, args: [ link ] } );
}
}
function uploadFailed ( err ) {
publishers.uploadend.dispatch();
publishers.error.dispatch( 'share.error.upload', { type: 'imguruploadfail' } );
console && console.log( err.message || err );
}
function updateUrl ( url ) {
base64Url = url;
return self;
}
function remove ( uid, deleteHash ) {
if ( deleteHash ) {
publishers.removestart.dispatch( uid );
reqwest( {
url: 'https://api.imgur.com/3/image/' + deleteHash,
method: 'DELETE',
headers: {
Authorization: 'Client-ID ' + config.keys.imgur
},
crossOrigin: true,
success: function () { removeSucceeded( uid ); },
error: function ( err ) { removeFailed( uid, err ); }
} );
}
return self;
}
function removeSucceeded ( uid ) {
publishers.removeend.dispatch( uid );
publishers.removecomplete.dispatch( uid );
publishers.statusmessage.dispatch( 'share.message.del' );
}
function removeFailed ( uid, err ) {
publishers.removeend.dispatch( uid );
publishers.error.dispatch( 'share.error.del', { type: 'imgurremovefail', uid: uid } );
console && console.log( err.message || err );
}
self.upload = upload;
self.updateUrl = updateUrl;
self.remove = remove
}
return ShareModel;
}
);
+300
View File
@@ -0,0 +1,300 @@
/*global define*/
define(
[ 'config', 'util/browser', 'util/addpublishers', 'lib/md5', 'lib/localforage.nopromises', 'models/localisationmodel' ],
function ( config, browser, addPublishers, md5, localforage, LocalisationModel ) {
// the StorageModel takes care of loading and saving data to localStorage.
// It stores the used glitch values as well as the imgur address if the
// image was shared.
// It generares a UID for each image to avoid having to save the
// same image multiple times.
// If an image was updated (shared/deleted), it updates the corresponding
// object in localstorage
function StorageModel () {
if ( ! ( this instanceof StorageModel ) ) {
return new StorageModel();
}
var self = this;
var isFirstVisit = false;
var entries = { };
var useLocalForage = browser.test( 'localforage' ) && localforage;
var worker;
var publisherNames = [
'update', 'save', 'loaditem',
'removeall', 'removelocaldata', 'removeimgurdata',
'firstvisit', 'error', 'statusmessage'
];
var publishers = addPublishers( self, publisherNames );
storageKey = config.keys.storage;
if ( useLocalForage && browser.test( 'webworker' ) && browser.test( 'browserdb' ) && ! browser.test( 'safari' ) ) {
worker = new Worker( config.workers.storage );
worker.addEventListener( 'message', workerResponded, false );
sendMessageToWorker( 'setStorageKey', storageKey );
}
function add ( item ) {
if ( useLocalForage && item ) {
if ( worker ) {
sendMessageToWorker( 'add', item );
} else {
var uid = createUID( item );
if (
entries[uid] &&
entries[uid].deleteHash === item.deleteHash &&
entries[uid].publicUrl === item.publicUrl &&
entries[uid].imgurID === item.imgurID
) {
publishers.statusmessage.dispatch( 'file.message.before' );
} else {
item.timestamp = Date.now();
entries[uid] = item;
save( function () {
publishers.statusmessage.dispatch( 'file.message.save' );
} );
}
}
}
return self;
}
function removeCompletely ( uid ) {
if ( useLocalForage && uid ) {
if ( worker ) {
sendMessageToWorker( 'removeCompletely', uid );
} else {
if (
entries[uid] &&
(
entries[uid].deleteHash ||
entries[uid].publicUrl ||
entries[uid].imgurID ||
entries[uid].values ||
entries[uid].src
)
) {
console && console.log( 'cant delete storage item because theres still some data left', entries[uid] );
} else {
publishers.removeall.dispatch( entries[uid] );
delete entries[uid];
save( function () {
publishers.statusmessage.dispatch( 'file.message.del' );
} );
}
}
}
}
function removeLocalData ( uid ) {
if ( useLocalForage && uid ) {
if ( worker ) {
sendMessageToWorker( 'removeLocalData', uid );
} else {
if ( entries[uid] ) {
if ( entries[uid].src ) {
delete entries[uid].src;
publishers.removelocaldata.dispatch( entries[uid] );
}
if ( entries[uid].values ) {
delete entries[uid].values;
}
if ( ! ( entries[uid].deleteHash || entries[uid].publicUrl || entries[uid].imgurID ) ) {
removeCompletely( uid );
}
save();
}
}
}
return self;
}
function removeImgurData ( uid ) {
if ( useLocalForage && uid ) {
if ( worker ) {
sendMessageToWorker( 'removeImgurData', uid );
} else {
if ( entries[uid] ) {
if ( entries[uid].deleteHash ) {
publishers.removeimgurdata.dispatch( entries[uid] );
delete entries[uid].deleteHash;
}
if ( entries[uid].publicUrl ) {
delete entries[uid].publicUrl;
}
if ( entries[uid].imgurID ) {
delete entries[uid].imgurID;
}
if ( ! ( entries[uid].src || entries[uid].values ) ) {
removeCompletely( uid );
}
save();
}
}
}
return self;
}
function load ( callback ) {
if ( useLocalForage ) {
if ( worker ) {
sendMessageToWorker( 'load' );
} else {
localforage.getItem( storageKey, function ( err, loadedData ) {
if ( err ) {
publishers.error.dispatch( 'file.error.load' );
console && console.log( 'localforage error', err );
} else {
entries = loadedData && loadedData.entries ? loadedData.entries : { };
publishers.update.dispatch( entries );
isFirstVisit = ( loadedData && loadedData.lastVisit ) ? false : true;
if ( isFirstVisit ) {
publishers.firstvisit.dispatch();
save();
}
if ( typeof callback === 'function' ) {
callback();
}
}
} );
}
}
return self;
}
function save ( callback ) {
if ( useLocalForage ) {
if ( worker ) {
sendMessageToWorker( 'save' );
} else {
localforage.setItem( storageKey, { entries: entries, lastVisit: Date.now() }, function ( err, savedData ) {
if ( err ) {
publishers.error.dispatch( 'file.error.save' );
console && console.log( 'localforage error', err );
} else {
if ( savedData ) {
entries = savedData.entries;
publishers.update.dispatch( entries );
publishers.save.dispatch();
if ( typeof callback === 'function' ) {
callback();
}
} else {
console && console.log( 'no data was saved', savedData );
}
}
} );
}
}
return self;
}
function loadItem ( uid ) {
if ( useLocalForage ) {
if ( worker ) {
sendMessageToWorker( 'loadItem', uid );
} else {
if ( entries[uid] ) {
publishers.loaditem.dispatch( uid, entries[uid] );
}
}
}
return self;
}
function workerResponded ( event ) {
if ( event && event.data ) {
publisherNames.forEach( function ( type ) {
if ( typeof event.data[type] !== 'undefined' ) {
if ( type === 'loaditem' ) {
publishers[type].dispatch( event.data[type].uid, event.data[type].entries );
} else {
if ( publishers[type] === type ) {
// if message is empty, the worker sends the type as data.
publishers[type].dispatch()
} else {
publishers[type].dispatch( event.data[type] )
}
}
}
} );
}
}
function sendMessageToWorker ( type, data ) {
if ( typeof type === 'string' ) {
if ( typeof data === 'undefined' ) {
data = type;
}
var message = { };
message[type] = data;
worker.postMessage( message );
}
}
function createUID ( item ) {
var inputStr = 'N' + item.name + 'S' + item.src + 'L' + item.thumbnail.length || 0 + 'V';
for ( var key in item.values ) {
inputStr += key.substr( 0, 2 );
inputStr += item.values[key];
}
return md5( inputStr );
}
function getLatestUID () {
var latestUid;
var latestTimestamp;
var timestamp;
for ( var uid in entries ) {
timestamp = entries[uid].timestamp;
if ( timestamp ) {
if ( ! latestUid || timestamp > latestTimestamp ) {
latestUid = uid;
latestTimestamp = timestamp;
}
}
}
return latestUid;
}
self.add = add;
self.removeImgurData = removeImgurData;
self.removeLocalData = removeLocalData;
self.load = load;
self.loadItem = loadItem;
self.removeImgurData = removeImgurData;
self.getLatestUID = getLatestUID;
}
return StorageModel;
}
);