Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
192
gaia/distros/spark/apps/studio/js/autotheme.js
Executable file
192
gaia/distros/spark/apps/studio/js/autotheme.js
Executable file
|
|
@ -0,0 +1,192 @@
|
|||
/*global
|
||||
Color,
|
||||
ColorThief,
|
||||
Defer,
|
||||
MozActivity
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @exports AutoTheme
|
||||
* @event AutoTheme:palette This is emitted when a new palete has been generated
|
||||
* from an image.
|
||||
*/
|
||||
|
||||
(function(exports) {
|
||||
// is autotheming active
|
||||
var active;
|
||||
|
||||
function loadImage(src) {
|
||||
var defer = new Defer();
|
||||
|
||||
var img = new Image();
|
||||
img.src = src;
|
||||
|
||||
if (img.complete) {
|
||||
defer.resolve(img);
|
||||
} else {
|
||||
img.onload = () => defer.resolve(img);
|
||||
img.onerror = defer.reject;
|
||||
}
|
||||
|
||||
return defer.promise;
|
||||
}
|
||||
|
||||
function blobFromURL(src) {
|
||||
var defer = new Defer();
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.addEventListener('load', () => {
|
||||
defer.resolve(xhr.response);
|
||||
});
|
||||
xhr.addEventListener('error', defer.reject);
|
||||
|
||||
xhr.open('GET', src);
|
||||
xhr.responseType = 'blob';
|
||||
xhr.send();
|
||||
|
||||
return defer.promise;
|
||||
}
|
||||
|
||||
var AutoTheme = exports.AutoTheme = {
|
||||
get active() {
|
||||
return active;
|
||||
},
|
||||
set active(bool) {
|
||||
active = bool;
|
||||
document.body.classList.toggle('has-autotheme', bool);
|
||||
},
|
||||
elts: {
|
||||
commandCreate: document.querySelectorAll('.autotheme-command-create'),
|
||||
commandCancel: document.querySelectorAll('.autotheme-command-cancel')
|
||||
},
|
||||
|
||||
handleEvent(e) {
|
||||
switch(e.type) {
|
||||
case 'click':
|
||||
this.pickImage()
|
||||
.then(this.getPalette.bind(this))
|
||||
.then(this.storePalette.bind(this));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/* called from activity */
|
||||
load(blob) {
|
||||
return this.getPalette(blob)
|
||||
.then(this.storePalette.bind(this));
|
||||
},
|
||||
|
||||
pickImage() {
|
||||
var defer = new Defer();
|
||||
|
||||
if (window.MozActivity) {
|
||||
var activity = new MozActivity({
|
||||
name: 'pick',
|
||||
data: { type: 'image/*' }
|
||||
});
|
||||
|
||||
activity.onsuccess = () => defer.resolve(activity.result.blob);
|
||||
activity.onerror = defer.reject;
|
||||
} else {
|
||||
defer.resolve(blobFromURL('img/default_image.jpg'));
|
||||
}
|
||||
|
||||
return defer.promise;
|
||||
},
|
||||
|
||||
getPalette(blob) {
|
||||
function imageFromBlob(blob) {
|
||||
var blobUrl = window.URL.createObjectURL(blob);
|
||||
return loadImage(blobUrl).then((image) => {
|
||||
window.URL.revokeObjectURL(image.src);
|
||||
return image;
|
||||
});
|
||||
}
|
||||
|
||||
this.image = blob;
|
||||
|
||||
var defer = new Defer();
|
||||
|
||||
imageFromBlob(blob).then((image) => {
|
||||
var colorThief = new ColorThief();
|
||||
var palette = colorThief.getPalette(image, 10);
|
||||
defer.resolve(palette);
|
||||
});
|
||||
|
||||
return defer.promise;
|
||||
},
|
||||
|
||||
storePalette(palette) {
|
||||
if (palette === null) {
|
||||
this.clean();
|
||||
} else {
|
||||
this.palette = palette.map(Color);
|
||||
this.active = true;
|
||||
}
|
||||
this.emit('palette');
|
||||
},
|
||||
|
||||
showPalette(where) {
|
||||
if (!where) {
|
||||
return;
|
||||
}
|
||||
|
||||
where.textContent = '';
|
||||
|
||||
if (!this.palette) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.palette.forEach((color) => {
|
||||
var elt = document.createElement('div');
|
||||
elt.className = 'palette-item';
|
||||
elt.style.backgroundColor = color.toCSS();
|
||||
elt.dataset.color = color.toJSONString();
|
||||
where.appendChild(elt);
|
||||
});
|
||||
},
|
||||
|
||||
clean() {
|
||||
this.active = false;
|
||||
this.palette = null;
|
||||
this.image = null;
|
||||
},
|
||||
|
||||
asStorable() {
|
||||
if (!this.active) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
palette: this.palette.map((color) => color.toStorable()),
|
||||
image: this.image
|
||||
};
|
||||
},
|
||||
|
||||
fromStorable(stored) {
|
||||
if (stored === null) {
|
||||
this.clean();
|
||||
return;
|
||||
}
|
||||
|
||||
this.palette = stored.palette.map(Color.fromStorable);
|
||||
this.image = stored.image;
|
||||
this.active = true;
|
||||
this.emit('palette');
|
||||
},
|
||||
|
||||
emit(name) {
|
||||
var event = new CustomEvent('AutoTheme:' + name);
|
||||
window.dispatchEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
Array.from(AutoTheme.elts.commandCreate).forEach(
|
||||
elt => elt.addEventListener('click', AutoTheme)
|
||||
);
|
||||
Array.from(AutoTheme.elts.commandCancel).forEach(
|
||||
elt => elt.addEventListener('click', () => AutoTheme.storePalette(null))
|
||||
);
|
||||
})(window);
|
||||
Loading…
Reference in a new issue