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:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,118 @@
;;(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.bridge=f()}})(function(){var define,module,exports;return(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){var bridge=module.exports=self['bridge']||{};bridge['client']=require('../src/client');if((typeof define)[0]!='u')define([],()=>bridge);else self['bridge']=bridge;},{"../src/client":2}],2:[function(require,module,exports){'use strict';var createPort=require('./message/port-adaptors');var Emitter=require('./emitter');var message=require('./message');var uuid=require('./utils').uuid;module.exports=Client;var debug={0:()=>{},1:arg=>performance.mark(`[${self.constructor.name}][Client] - ${arg}`),2:(arg1,...args)=>{var type=`[${self.constructor.name}][${location.pathname}]`;console.log(`[Client]${type} - "${arg1}"`,...args);}}[0];var env=constructor.name
function Client(service,endpoint,timeout){if(!(this instanceof Client))return new Client(service,endpoint,timeout);if(typeof service=='object'){endpoint=service.endpoint;timeout=service.timeout;service=service.service;}
this.id=uuid();this.service=service;this.timeout=timeout;this.endpoint=endpoint||this.endpoint;if(!this.endpoint)throw error(1);this.setPort(this.endpoint);this.pending=new Set();this.receiver=message.receiver(this.id).on('_push',this.onPush.bind(this));debug('initialized',service);}
Client.prototype={connect(){debug('connect');if(this.connected)return this.connected;debug('connecting...',this.service);var mc=new MessageChannel();this.channel=mc.port1;this.channel.start();var data={clientId:this.id,service:this.service,originEnv:env};return this.connected=this.message('_connect').set('transfer',[mc.port2]).set('data',data).listen(mc.port1).send().then(response=>{debug('connected',response);var usingChannel=response.event.target===this.channel;if(usingChannel)this.setPort(this.channel);else{this.channel.close();delete this.channel;}
this.receiver.listen(this.port);}).catch(err=>{var msg=err&&err.message;if(msg=='timeout'){err=error(2,this.service);console.error(err.message);}
throw err;});},disconnect(options){if(!this.connected)return Promise.resolve();debug('disconnecting ...');var config={noRespond:options&&options.noRespond,data:this.id};this.cancelPending();return this.message('_disconnect').set(config).send().then(()=>this.onDisconnected());},method(name,...args){return this.connect().then(()=>{debug('method',name);return this.message('_method').set({recipient:this.service,data:{name:name,args:args}}).send();}).then(response=>response.value).catch(err=>{var msg=err&&err.message;if(msg=='timeout'){err=error(3,name);console.error(err.message);}
throw err;});},plugin(fn){fn(this,{'Emitter':Emitter,'uuid':uuid});return this;},message(type){debug('create message',type);var msg=message(type).set('port',this.port).set('timeout',this.timeout).on('response',()=>this.pending.delete(msg)).on('cancel',()=>this.pending.delete(msg));this.pending.add(msg);return msg;},cancelPending(){debug('cancel pending');this.pending.forEach(msg=>{msg.cancel();});this.pending.clear();},pendingResponded(){var responded=[];this.pending.forEach(msg=>responded.push(msg.responded));return Promise.all(responded);},onPush(message){debug('on push',message.data);this._emit(message.data.type,message.data.data);},onDisconnected(){delete this.connected;this.pendingResponded().then(()=>{debug('disconnected');if(this.channel)this.channel.close();this._emit('disconnected');});},setPort(endpoint){debug('set port');this.port=createPort(endpoint);},destroy:function(){return this.disconnect().then(()=>{if(this.destroyed)return;debug('destroy');this.destroyed=true;this.receiver.destroy();this._off();this.port=this.endpoint=this.receiver=null;});},_on:Emitter.prototype.on,_off:Emitter.prototype.off,_emit:Emitter.prototype.emit};Client.prototype.on=function(name,fn){this.connect().then(()=>{debug('bind on',name);Emitter.prototype.on.call(this,name,fn);this.message('_on').set('noRespond',true).set('data',{name:name,clientId:this.id}).send(this.port);});return this;};Client.prototype.off=function(name,fn){this.connect().then(()=>{Emitter.prototype.off.call(this,name,fn);this.message('_off').set('noRespond',true).set('data',{name:name,clientId:this.id}).send(this.port);});return this;};function error(id,...args){var help='Either the target endpoint is not alive or the Service is not `.listen()`ing.';return new Error({1:'an endpoint must be defined',2:`Unable to establish a connection with "${args[0]}". ${help}`,3:`Method "${args[0]}" didn't get a response. ${help}`}[id]);}},{"./emitter":3,"./message":4,"./message/port-adaptors":5,"./utils":6}],3:[function(require,module,exports){'use strict';module.exports=Emitter;var debug=0?console.log.bind(console,'[Emitter]'):()=>{};function Emitter(host){if(host)return Object.assign(host,Emitter.prototype);}
Emitter.prototype={on:function(type,callback){debug('on',type,callback);if(!this._callbacks)this._callbacks={};if(!this._callbacks[type])this._callbacks[type]=[];this._callbacks[type].push(callback);return this;},off:function(type,callback){debug('off',type,callback);if(this._callbacks){switch(arguments.length){case 0:this._callbacks={};break;case 1:delete this._callbacks[type];break;default:var typeListeners=this._callbacks[type];if(!typeListeners)return;var i=typeListeners.indexOf(callback);if(~i)typeListeners.splice(i,1);}}
return this;},emit:function(type,data){debug('emit',type,data);if(this._callbacks){var fns=this._callbacks[type]||[];fns=fns.concat(this._callbacks['*']||[]);for(var i=0;i<fns.length;i++)fns[i].call(this,data,type);}
return this;}};var p=Emitter.prototype;p['off']=p.off;p['on']=p.on;},{}],4:[function(require,module,exports){'use strict';var createPort=require('./port-adaptors');var Emitter=require('../emitter');var utils=require('../utils');var defer=utils.deferred;var uuid=utils.uuid;exports=module.exports=type=>new Message(type);exports.receiver=(id,n)=>new Receiver(id,n);exports.Receiver=Receiver;exports.Message=Message;var debug={0:()=>{},1:arg=>performance.mark(`[${self.constructor.name}][Message] - ${arg}`),2:(arg1,...args)=>{var type=`[${self.constructor.name}][${location.pathname}]`;console.log(`[Message]${type} - "${arg1}"`,...args);}}[0];var TIMEOUT=1000;function Message(type){this.cancelled=false;this.listeners=[];this.deferred=defer();this.onMessage=this.onMessage.bind(this);this.onTimeout=this.onTimeout.bind(this);if(typeof type==='object')this.setupInbound(type);else this.setupOutbound(type);debug('initialized',type);}
Message.prototype={setupOutbound(type){this.id=uuid();this.type=type;this.sent=false;this.recipient='*';},setupInbound(e){debug('inbound');this.hasResponded=false;this.setSourcePort(e.source||e.target);this.event=e;Object.assign(this,e.data);},setSourcePort(endpoint){debug('set source',endpoint.constructor.name);this.sourcePort=createPort(endpoint,{ready:true});return this;},set(key,value){debug('set',key,value);if(typeof key=='object')Object.assign(this,key);else this[key]=value;return this;},serialize(){return{id:this.id,type:this.type,data:this.data,recipient:this.recipient,noRespond:this.noRespond};},preventDefault(){debug('prevent default');this.defaultPrevented=true;},send(endpoint){debug('send',this.type);if(this.sent)throw error(1);var serialized=this.serialize();var expectsResponse=!this.noRespond;this.port=endpoint?createPort(endpoint):this.port;if(!this.port)throw error(3);if(expectsResponse){this.listen(this.port);this.setResponseTimeout();}else this.deferred.resolve();this.port.postMessage(serialized,this.getTransfer());debug('sent',serialized);return this.deferred.promise;},setResponseTimeout(){if(this.timeout===false)return;var ms=this.timeout||TIMEOUT;this._timer=setTimeout(this.onTimeout,ms);},clearResponseTimeout(){clearTimeout(this._timer);},getTransfer(){return this.transfer||this.event&&this.event.ports;},onMessage(e){var valid=!!e.data.response&&e.data.id===this.id&&!this.cancelled;if(valid)this.onResponse(e);},onTimeout(){debug('response timeout',this.type);if(!this.silentTimeout)this.deferred.reject(error(4));this.teardown();},listen(thing){debug('add response listener',thing);var port=createPort(thing);port.addListener(this.onMessage);this.listeners.push(port);return this;},unlisten(){debug('remove response listeners');this.listeners.forEach(port=>port.removeListener(this.onMessage));this.listeners=[];},cancel(){this.teardown();this.cancelled=true;this.emit('cancel');},teardown(){this.clearResponseTimeout();this.unlisten();},respond(result){debug('respond',result);if(this.hasResponded)throw error(2);if(!this.sourcePort)return;if(this.noRespond)return;var self=this;this.hasResponded=true;if(result instanceof Error)reject(result);Promise.resolve(result).then(resolve,reject).catch(reject);function resolve(value){debug('resolve',value);respond({type:'resolve',value:value});}
function reject(err){var msg=err&&err.message||err;debug('reject',msg);respond({type:'reject',value:msg});}
function respond(response){self.response=response;self.sourcePort.postMessage({id:self.id,response:response},self.transfer);debug('responded with:',response);}},forward(endpoint){debug('forward');return this.set('silentTimeout',true).send(endpoint).then(result=>this.respond(result.value));},onResponse(e){debug('on response',e.data);var response=e.data.response;var type=response.type;var value=type=='reject'?response.value:response;response.event=e;this.response=response;this.teardown();this.deferred[this.response.type](value);this.emit('response',response);}};Emitter(Message.prototype);function Receiver(name){this.name=name;this.ports=new Set();this.onMessage=this.onMessage.bind(this);this['listen']=this['listen'].bind(this);this['unlisten']=this['unlisten'].bind(this);debug('receiver initialized',name);}
Receiver.prototype={listen(thing){debug('listen');var _port=createPort(thing||self,{receiver:true});if(this.ports.has(_port))return;_port.addListener(this.onMessage,this.listen);this.ports.add(_port);return this;},unlisten(){debug('unlisten');this.ports.forEach(port=>{port.removeListener(this.onMessage,this.unlisten);});},onMessage(e){if(!e.data.id)return;if(!e.data.type)return;if(!this.isRecipient(e.data.recipient))return;debug('receiver on message',e.data);var message=new Message(e);this.emit('message',message);if(message.defaultPrevented)return;try{this.emit(message.type,message);}
catch(e){message.respond(e);throw e;}},isRecipient(recipient){return recipient==this.name||recipient=='*'||this.name=='*';},destroy:function(){this.unlisten();delete this.name;return this;}};Emitter(Receiver.prototype);function error(id,...args){return new Error({1:'.send() can only be called once',2:'response already sent for this message',3:'a port must be defined',4:'timeout'}[id]);}},{"../emitter":3,"../utils":6,"./port-adaptors":5}],5:[function(require,module,exports){'use strict';var deferred=require('../utils').deferred;const MSG='message';var debug=0?function(arg1,...args){var type=`[${self.constructor.name}][${location.pathname}]`;console.log(`[PortAdaptor]${type} - "${arg1}"`,...args);}:()=>{};module.exports=function create(target,options){if(!target)throw error(1);if(isEndpoint(target))return target;var type=target.constructor.name;var CustomAdaptor=adaptors[type];debug('creating port adaptor for',type);if(CustomAdaptor)return CustomAdaptor(target,options);return new PortAdaptor(target,options);};function PortAdaptor(target){debug('PortAdaptor');this.target=target;}
var PortAdaptorProto=PortAdaptor.prototype={constructor:PortAdaptor,addListener(callback){on(this.target,MSG,callback);},removeListener(callback){off(this.target,MSG,callback);},postMessage(data,transfer){this.target.postMessage(data,transfer);}};var adaptors={'HTMLIFrameElement':function(iframe){debug('HTMLIFrameElement');var ready=windowReady(iframe);return{addListener(callback,listen){on(window,MSG,callback);},removeListener(callback,listen){off(window,MSG,callback);},postMessage(data,transfer){ready.then(()=>postMessageSync(iframe.contentWindow,data,transfer));}};},'BroadcastChannel':function(channel,options){debug('BroadcastChannel',channel.name);var receiver=options&&options.receiver;var ready=options&&options.ready;var sendReady=()=>{channel.postMessage('ready');debug('sent ready');};ready=ready||receiver?Promise.resolve():setupSender();if(receiver){sendReady();on(channel,MSG,e=>{if(e.data!='ready?')return;sendReady();});}
function setupSender(){debug('setup sender');var promise=deferred();channel.postMessage('ready?');on(channel,MSG,function fn(e){if(e.data!='ready')return;off(channel,MSG,fn);debug('BroadcastChannel: ready');promise.resolve();});return promise.promise;}
return{target:channel,addListener:PortAdaptorProto.addListener,removeListener:PortAdaptorProto.removeListener,postMessage(data,transfer){ready.then(()=>channel.postMessage(data,transfer));}};},'Window':function(win,options){debug('Window');var ready=options&&options.ready||win===parent||win===self;ready=ready?Promise.resolve():windowReady(win);return{addListener(callback,listen){on(window,MSG,callback);},removeListener(callback,listen){off(window,MSG,callback);},postMessage(data,transfer){ready.then(()=>postMessageSync(win,data,transfer));}};},'SharedWorker':function(worker){worker.port.start();return new PortAdaptor(worker.port);},'SharedWorkerGlobalScope':function(){var ports=[];return{postMessage(){},addListener(callback,listen){this.onconnect=e=>{var port=e.ports[0];ports.push(port);port.start();listen(port);};on(self,'connect',this.onconnect);},removeListener(callback,unlisten){off(self,'connect',this.onconnect);ports.forEach(port=>{port.close();unlisten(port);});}};}};var windowReady=(function(){if(typeof window=='undefined')return;var parent=window.opener||window.parent;var domReady='DOMContentLoaded';var windows=new WeakSet();if(parent!=self){on(window,domReady,function fn(){off(window,domReady,fn);postMessageSync(parent,'load');});}
on(self,'message',e=>e.data=='load'&&windows.add(e.source));return target=>{var win=target.contentWindow||target;if(windows.has(win))return Promise.resolve();if(win==window.parent)return Promise.resolve();var def=deferred();debug('waiting for Window to be ready ...');on(window,'message',function fn(e){if(e.data=='load'&&e.source==win){debug('Window ready');off(window,'message',fn);def.resolve();}});return def.promise;};})();function isEndpoint(thing){return!!(thing&&thing.addListener);}
function on(target,name,fn){target.addEventListener(name,fn);}
function off(target,name,fn){target.removeEventListener(name,fn);}
function postMessageSync(win,data,transfer){try{void win.document;}catch(_){win.postMessage(data,location.origin,transfer||[]);return;}var event={data:data,source:self};if(transfer)event.ports=transfer;win.dispatchEvent(new MessageEvent('message',event));}
function error(id){return new Error({1:'target is undefined'}[id]);}},{"../utils":6}],6:[function(require,module,exports){'use strict';exports.uuid=function(){return'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function(c){var r=Math.random()*16|0,v=c=='x'?r:(r&0x3|0x8);return v.toString(16);});};exports.deferred=function(){var promise={};promise.promise=new Promise((resolve,reject)=>{promise.resolve=resolve;promise.reject=reject;});return promise;};},{}]},{},[1])(1)});;;;;var _createClass=(function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||false;descriptor.configurable=true;if('value'in descriptor)descriptor.writable=true;Object.defineProperty(target,descriptor.key,descriptor);}}return function(Constructor,protoProps,staticProps){if(protoProps)defineProperties(Constructor.prototype,protoProps);if(staticProps)defineProperties(Constructor,staticProps);return Constructor;};})();function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError('Cannot call a class as a function');}}
(function(){'use strict';const Client=bridge.client;const channel=new BroadcastChannel('l20n-channel');const observerConfig={attributes:true,characterData:false,childList:true,subtree:true,attributeFilter:['data-l10n-id','data-l10n-args']};const observers=new WeakMap();function initMutationObserver(view){observers.set(view,{roots:new Set(),observer:new MutationObserver(mutations=>translateMutations(view,mutations))});}
function translateRoots(view){return Promise.all([...observers.get(view).roots].map(root=>_translateFragment(view,root)));}
function observe(view,root){const obs=observers.get(view);if(obs){obs.roots.add(root);obs.observer.observe(root,observerConfig);}}
function disconnect(view,root,allRoots){const obs=observers.get(view);if(obs){obs.observer.disconnect();if(allRoots){return;}
obs.roots.delete(root);obs.roots.forEach(other=>obs.observer.observe(other,observerConfig));}}
function reconnect(view){const obs=observers.get(view);if(obs){obs.roots.forEach(root=>obs.observer.observe(root,observerConfig));}}
const reOverlay=/<|&#?\w+;/;const allowed={elements:['a','em','strong','small','s','cite','q','dfn','abbr','data','time','code','var','samp','kbd','sub','sup','i','b','u','mark','ruby','rt','rp','bdi','bdo','span','br','wbr'],attributes:{global:['title','aria-label','aria-valuetext','aria-moz-hint'],a:['download'],area:['download','alt'],input:['alt','placeholder'],menuitem:['label'],menu:['label'],optgroup:['label'],option:['label'],track:['label'],img:['alt'],textarea:['placeholder'],th:['abbr']}};function overlayElement(element,translation){const value=translation.value;if(typeof value==='string'){if(!reOverlay.test(value)){element.textContent=value;}else{const tmpl=element.ownerDocument.createElement('template');tmpl.innerHTML=value;overlay(element,tmpl.content);}}
for(let key in translation.attrs){const attrName=camelCaseToDashed(key);if(isAttrAllowed({name:attrName},element)){element.setAttribute(attrName,translation.attrs[key]);}}}
function overlay(sourceElement,translationElement){const result=translationElement.ownerDocument.createDocumentFragment();let k,attr;let childElement;while(childElement=translationElement.childNodes[0]){translationElement.removeChild(childElement);if(childElement.nodeType===childElement.TEXT_NODE){result.appendChild(childElement);continue;}
const index=getIndexOfType(childElement);const sourceChild=getNthElementOfType(sourceElement,childElement,index);if(sourceChild){overlay(sourceChild,childElement);result.appendChild(sourceChild);continue;}
if(isElementAllowed(childElement)){const sanitizedChild=childElement.ownerDocument.createElement(childElement.nodeName);overlay(sanitizedChild,childElement);result.appendChild(sanitizedChild);continue;}
result.appendChild(translationElement.ownerDocument.createTextNode(childElement.textContent));}
sourceElement.textContent='';sourceElement.appendChild(result);if(translationElement.attributes){for(k=0,attr;attr=translationElement.attributes[k];k++){if(isAttrAllowed(attr,sourceElement)){sourceElement.setAttribute(attr.name,attr.value);}}}}
function isElementAllowed(element){return allowed.elements.indexOf(element.tagName.toLowerCase())!==-1;}
function isAttrAllowed(attr,element){const attrName=attr.name.toLowerCase();const tagName=element.tagName.toLowerCase();if(allowed.attributes.global.indexOf(attrName)!==-1){return true;}
if(!allowed.attributes[tagName]){return false;}
if(allowed.attributes[tagName].indexOf(attrName)!==-1){return true;}
if(tagName==='input'&&attrName==='value'){const type=element.type.toLowerCase();if(type==='submit'||type==='button'||type==='reset'){return true;}}
return false;}
function getNthElementOfType(context,element,index){let nthOfType=0;for(let i=0,child;child=context.children[i];i++){if(child.nodeType===child.ELEMENT_NODE&&child.tagName===element.tagName){if(nthOfType===index){return child;}
nthOfType++;}}
return null;}
function getIndexOfType(element){let index=0;let child;while(child=element.previousElementSibling){if(child.tagName===element.tagName){index++;}}
return index;}
function camelCaseToDashed(string){if(string==='ariaValueText'){return'aria-valuetext';}
return string.replace(/[A-Z]/g,function(match){return'-'+match.toLowerCase();}).replace(/^-/,'');}
const reHtml=/[&<>]/g;const htmlEntities={'&':'&amp;','<':'&lt;','>':'&gt;'};function setAttributes(element,id,args){element.setAttribute('data-l10n-id',id);if(args){element.setAttribute('data-l10n-args',JSON.stringify(args));}}
function getAttributes(element){return{id:element.getAttribute('data-l10n-id'),args:JSON.parse(element.getAttribute('data-l10n-args'))};}
function getTranslatables(element){const nodes=Array.from(element.querySelectorAll('[data-l10n-id]'));if(typeof element.hasAttribute==='function'&&element.hasAttribute('data-l10n-id')){nodes.push(element);}
return nodes;}
function translateMutations(view,mutations){const targets=new Set();for(let mutation of mutations){switch(mutation.type){case'attributes':targets.add(mutation.target);break;case'childList':for(let addedNode of mutation.addedNodes){if(addedNode.nodeType===addedNode.ELEMENT_NODE){if(addedNode.childElementCount){getTranslatables(addedNode).forEach(targets.add.bind(targets));}else{if(addedNode.hasAttribute('data-l10n-id')){targets.add(addedNode);}}}}
break;}}
if(targets.size===0){return;}
translateElements(view,Array.from(targets));}
function _translateFragment(view,frag){return translateElements(view,getTranslatables(frag));}
function getElementsTranslation(view,elems){const keys=elems.map(elem=>{const id=elem.getAttribute('data-l10n-id');const args=elem.getAttribute('data-l10n-args');return args?[id,JSON.parse(args.replace(reHtml,match=>htmlEntities[match]))]:id;});return view.formatEntities(...keys);}
function translateElements(view,elements){return getElementsTranslation(view,elements).then(translations=>applyTranslations(view,elements,translations));}
function applyTranslations(view,elems,translations){disconnect(view,null,true);for(let i=0;i<elems.length;i++){overlayElement(elems[i],translations[i]);}
reconnect(view);}
if(typeof NodeList==='function'&&!NodeList.prototype[Symbol.iterator]){NodeList.prototype[Symbol.iterator]=Array.prototype[Symbol.iterator];}
function documentReady(){if(document.readyState!=='loading'){return Promise.resolve();}
return new Promise(resolve=>{document.addEventListener('readystatechange',function onrsc(){document.removeEventListener('readystatechange',onrsc);resolve();});});}
function getDirection(code){const tag=code.split('-')[0];return['ar','he','fa','ps','ur'].indexOf(tag)>=0?'rtl':'ltr';}
if(navigator.languages===undefined){navigator.languages=[navigator.language];}
function getResourceLinks(head){return Array.prototype.map.call(head.querySelectorAll('link[rel="localization"]'),el=>el.getAttribute('href'));}
function getMeta(head){let availableLangs=Object.create(null);let defaultLang=null;let appVersion=null;const metas=Array.from(head.querySelectorAll('meta[name="availableLanguages"],'+'meta[name="defaultLanguage"],'+'meta[name="appVersion"]'));for(let meta of metas){const name=meta.getAttribute('name');const content=meta.getAttribute('content').trim();switch(name){case'availableLanguages':availableLangs=getLangRevisionMap(availableLangs,content);break;case'defaultLanguage':const[lang,rev]=getLangRevisionTuple(content);defaultLang=lang;if(!(lang in availableLangs)){availableLangs[lang]=rev;}
break;case'appVersion':appVersion=content;}}
return{defaultLang,availableLangs,appVersion};}
function getLangRevisionMap(seq,str){return str.split(',').reduce((seq,cur)=>{const[lang,rev]=getLangRevisionTuple(cur);seq[lang]=rev;return seq;},seq);}
function getLangRevisionTuple(str){const[lang,rev]=str.trim().split(':');return[lang,parseInt(rev)];}
const viewProps=new WeakMap();let View=(function(){function View(client,doc){_classCallCheck(this,View);this.pseudo={'fr-x-psaccent':createPseudo(this,'fr-x-psaccent'),'ar-x-psbidi':createPseudo(this,'ar-x-psbidi')};const initialized=documentReady().then(()=>init(this,client));this._interactive=initialized.then(()=>client);this.ready=initialized.then(langs=>translateView(this,langs));initMutationObserver(this);viewProps.set(this,{doc:doc,ready:false});client.on('languageschangerequest',requestedLangs=>this.requestLanguages(requestedLangs));}
_createClass(View,[{key:'requestLanguages',value:function requestLanguages(requestedLangs,isGlobal){const method=isGlobal?client=>client.method('requestLanguages',requestedLangs):client=>changeLanguages(this,client,requestedLangs);return this._interactive.then(method);}},{key:'handleEvent',value:function handleEvent(){return this.requestLanguages(navigator.languages);}},{key:'formatEntities',value:function formatEntities(...keys){return this._interactive.then(client=>client.method('formatEntities',client.id,keys));}},{key:'formatValue',value:function formatValue(id,args){return this._interactive.then(client=>client.method('formatValues',client.id,[[id,args]])).then(values=>values[0]);}},{key:'formatValues',value:function formatValues(...keys){return this._interactive.then(client=>client.method('formatValues',client.id,keys));}},{key:'translateFragment',value:function translateFragment(frag){return _translateFragment(this,frag);}},{key:'observeRoot',value:function observeRoot(root){observe(this,root);}},{key:'disconnectRoot',value:function disconnectRoot(root){disconnect(this,root);}}]);return View;})();View.prototype.setAttributes=setAttributes;View.prototype.getAttributes=getAttributes;function createPseudo(view,code){return{getName:()=>view._interactive.then(client=>client.method('getName',code)),processString:str=>view._interactive.then(client=>client.method('processString',code,str))};}
function init(view,client){const doc=viewProps.get(view).doc;const resources=getResourceLinks(doc.head);const meta=getMeta(doc.head);view.observeRoot(doc.documentElement);return getAdditionalLanguages().then(additionalLangs=>client.method('registerView',client.id,resources,meta,additionalLangs,navigator.languages));}
function changeLanguages(view,client,requestedLangs){const doc=viewProps.get(view).doc;const meta=getMeta(doc.head);return getAdditionalLanguages().then(additionalLangs=>client.method('changeLanguages',client.id,meta,additionalLangs,requestedLangs)).then(({langs,haveChanged})=>haveChanged?translateView(view,langs):undefined);}
function getAdditionalLanguages(){if(navigator.mozApps&&navigator.mozApps.getAdditionalLanguages){return navigator.mozApps.getAdditionalLanguages().catch(()=>Object.create(null));}
return Promise.resolve(Object.create(null));}
function translateView(view,langs){const props=viewProps.get(view);const html=props.doc.documentElement;if(props.ready){return translateRoots(view).then(()=>setAllAndEmit(html,langs));}
const translated=langs[0].code===html.getAttribute('lang')?Promise.resolve():translateRoots(view).then(()=>setLangDir(html,langs));return translated.then(()=>{setLangs(html,langs);props.ready=true;});}
function setLangs(html,langs){const codes=langs.map(lang=>lang.code);html.setAttribute('langs',codes.join(' '));}
function setLangDir(html,langs){const code=langs[0].code;html.setAttribute('lang',code);html.setAttribute('dir',getDirection(code));}
function setAllAndEmit(html,langs){setLangDir(html,langs);setLangs(html,langs);html.parentNode.dispatchEvent(new CustomEvent('DOMRetranslated',{bubbles:false,cancelable:false}));}
const client=new Client({service:'l20n',endpoint:channel,timeout:false});document.l10n=new View(client,document);window.addEventListener('pageshow',()=>client.connect());window.addEventListener('pagehide',()=>client.disconnect());window.addEventListener('languagechange',document.l10n);document.addEventListener('additionallanguageschange',document.l10n);navigator.mozL10n={setAttributes:document.l10n.setAttributes,getAttributes:document.l10n.getAttributes,formatValue:(...args)=>document.l10n.formatValue(...args),translateFragment:(...args)=>document.l10n.translateFragment(...args),once:cb=>document.l10n.ready.then(cb),ready:cb=>document.l10n.ready.then(()=>{document.addEventListener('DOMRetranslated',cb);cb();})};})();;(function(root,factory){'use strict';if(typeof define==='function'&&define.amd){define(factory);}else if(typeof exports==='object'){module.exports=factory();}else{root.Sanitizer=factory();}}(this,function(){'use strict';var Sanitizer={_entity:/[&<>"'/]/g,_entities:{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;','\'':'&apos;','/':'&#x2F;'},getEntity:function(s){return Sanitizer._entities[s];},escapeHTML:function(strings,...values){var result='';for(var i=0;i<strings.length;i++){result+=strings[i];if(i<values.length){result+=String(values[i]).replace(Sanitizer._entity,Sanitizer.getEntity);}}
return result;},createSafeHTML:function(strings,...values){var escaped=Sanitizer.escapeHTML(strings,...values);return{__html:escaped,toString:function(){return'[object WrappedHTMLObject]';},info:'This is a wrapped HTML object. See https://developer.mozilla.or'+'g/en-US/Firefox_OS/Security/Security_Automation for more.'};},unwrapSafeHTML:function(...htmlObjects){var markupList=htmlObjects.map(function(obj){return obj.__html;});return markupList.join('');}};return Sanitizer;}));;;;'use strict';var LazyLoader=(function(){function LazyLoader(){this._loaded={};this._isLoading={};}
LazyLoader.prototype={_js:function(file,callback){var script=document.createElement('script');script.src=file;script.async=false;script.addEventListener('load',callback);document.head.appendChild(script);this._isLoading[file]=script;},_css:function(file,callback){var style=document.createElement('link');style.type='text/css';style.rel='stylesheet';style.href=file;document.head.appendChild(style);callback();},_html:function(domNode,callback){if(domNode.getAttribute('is')){this.load(['/shared/js/html_imports.js'],function(){HtmlImports.populate(callback);}.bind(this));return;}
for(var i=0;i<domNode.childNodes.length;i++){if(domNode.childNodes[i].nodeType==document.COMMENT_NODE){domNode.innerHTML=domNode.childNodes[i].nodeValue;break;}}
window.dispatchEvent(new CustomEvent('lazyload',{detail:domNode}));callback();},getJSON:function(file,mozSystem){return new Promise(function(resolve,reject){var xhr;if(mozSystem){xhr=new XMLHttpRequest({mozSystem:true});}else{xhr=new XMLHttpRequest();}
xhr.open('GET',file,true);xhr.responseType='json';xhr.onerror=function(error){reject(error);};xhr.onload=function(){if(xhr.response!==null){resolve(xhr.response);}else{reject(new Error('No valid JSON object was found ('+
xhr.status+' '+xhr.statusText+')'));}};xhr.send();});},load:function(files,callback){var deferred={};deferred.promise=new Promise(resolve=>{deferred.resolve=resolve;});if(!Array.isArray(files)){files=[files];}
var loadsRemaining=files.length,self=this;function perFileCallback(file){if(self._isLoading[file]){delete self._isLoading[file];}
self._loaded[file]=true;if(--loadsRemaining===0){deferred.resolve();if(callback){callback();}}}
for(var i=0;i<files.length;i++){var file=files[i];if(this._loaded[file.id||file]){perFileCallback(file);}else if(this._isLoading[file]){this._isLoading[file].addEventListener('load',perFileCallback.bind(null,file));}else{var method,idx;if(typeof file==='string'){method=file.match(/\.([^.]+)$/)[1];idx=file;}else{method='html';idx=file.id;}
this['_'+method](file,perFileCallback.bind(null,idx));}}
return deferred.promise;}};return new LazyLoader();}());;;;;var SERVICE_WORKERS=false;;;window.View=(function(){'use strict';var debug=0?(...args)=>console.log('[View]',...args):()=>{};if(!SERVICE_WORKERS)(function(){window.ROUTES={'/api/activities/share/:filePath':'share','/api/albums/list':'getAlbums','/api/albums/info/:filePath':'getAlbum','/api/artists/list':'getArtists','/api/artists/info/:filePath':'getArtist','/api/artwork/original/:filePath':'getSongArtwork','/api/artwork/thumbnail/:filePath':'getSongThumbnail','/api/artwork/url/original/:filePath':'getSongArtworkURL','/api/artwork/url/thumbnail/:filePath':'getSongThumbnailURL','/api/audio/play':'play','/api/audio/pause':'pause','/api/audio/seek/:time':'seek','/api/audio/fastseek/start/:direction':'startFastSeek','/api/audio/fastseek/stop':'stopFastSeek','/api/audio/status':'getPlaybackStatus','/api/database/status':'getDatabaseStatus','/api/playlists/list':'getPlaylists','/api/playlists/info/:id':'getPlaylist','/api/queue/current':'currentSong','/api/queue/previous':'previousSong','/api/queue/next':'nextSong','/api/queue/album/:filePath':'queueAlbum','/api/queue/artist/:filePath':'queueArtist','/api/queue/playlist/:id/shuffle':'queuePlaylist','/api/queue/playlist/:id/song/:filePath':'queuePlaylist','/api/queue/song/:filePath':'queueSong','/api/queue/repeat/:repeat':'setRepeatSetting','/api/queue/shuffle/:shuffle':'setShuffleSetting','/api/songs/list':'getSongs','/api/songs/count':'getSongCount','/api/songs/info/:filePath':'getSong','/api/songs/rating/:rating/:filePath':'setSongRating','/api/search/:key/':'search','/api/search/:key/:query':'search'};for(var path in window.ROUTES){var method=window.ROUTES[path];window.ROUTES[path]=parseSimplePath(path);window.ROUTES[path].method=method;}})();function View(){this.client=bridge.client({service:'music-service',endpoint:window.parent,timeout:false});this.params={};var parts=window.parent.location.href.split('?');parts.shift();var query=parts.join('?');query.split('&').forEach((param)=>{var parts=param.split('=');this.params[parts[0]]=parts[1];});window.addEventListener('click',(evt)=>{var link=evt.target.closest('a');if(link){evt.preventDefault();this.client.method('navigate',link.getAttribute('href'));}});window.addEventListener('viewdestroy',()=>this.destroy());document.addEventListener('DOMRetranslated',()=>{this.title=document.title;});}
View.prototype.setupSearch=function(params){this.searchBox.addEventListener('search',(evt)=>this.search(evt.detail));this.searchResults.addEventListener('open',()=>{this.client.method('searchOpen');});this.searchResults.addEventListener('close',()=>{this.client.method('searchClose');this.list.scrollTop=this.searchBox.HEIGHT;});this.searchResults.addEventListener('resultclick',(evt)=>{var link=evt.detail;if(link){this.client.method('navigate',link.getAttribute('href'));}});this.searchResults.getItemImageSrc=(item)=>this.getThumbnail(item.name);};View.prototype.setupList=function(){this.list.minScrollHeight=`calc(100% + ${this.searchBox.HEIGHT}px)`;this.list.offset=this.searchBox.HEIGHT;this.list.configure({getItemImageSrc:(item)=>this.getThumbnail(item.name)});this.list.rendered.then(()=>document.body.hidden=false);this.list.scrollTo(this.searchBox.HEIGHT);};View.prototype.destroy=function(){Object.getOwnPropertyNames(this).forEach(prop=>this[prop]=null);debug('Destroyed');};View.prototype.render=function(){};View.prototype.onRenderDone=function(){if(window.frameElement){window.frameElement.dispatchEvent(new CustomEvent('rendered'));}
debug('Rendered');};View.prototype.fetch=SERVICE_WORKERS?function(url){return window.fetch(encodeURI(url));}:function(url){for(var path in window.ROUTES){var route=window.ROUTES[path];var match=url.match(route.regexp);if(match){return new Promise((resolve)=>{setTimeout(()=>{var args=[route.method].concat(match.splice(1));this.client.method.apply(this.client,args).then((result)=>{resolve({blob:()=>Promise.resolve(result),json:()=>Promise.resolve(result)});});});});}}
return Promise.reject();};Object.defineProperty(View.prototype,'title',{get:function(){return document.title;},set:function(value){document.title=value;window.frameElement.dispatchEvent(new CustomEvent('titlechange',{detail:document.title}));}});View.extend=function(subclass){subclass.prototype=Object.create(View.prototype,{constructor:{value:subclass,enumerable:false,writable:true,configurable:true}});return subclass;};function parseSimplePath(path){if(/\:[a-zA-Z0-9]+\:[a-zA-Z0-9]+/g.test(path)){throw new Error('Invalid usage of named placeholders');}
var mixedPlaceHolders=/(\*\:[a-zA-Z0-9]+)|(\:[a-zA-Z0-9]+\:[a-zA-Z0-9]+)|(\:[a-zA-Z0-9]+\*)/g;if(mixedPlaceHolders.test(path.replace(/\\\*/g,''))){throw new Error('Invalid usage of named placeholders');}
try{path=path.replace(/(.|^)[*]+/g,function(m,escape){return escape==='\\'?'\\*':(escape+'(?:.*?)');});var tags=[];path=path.replace(/(.|^)\:([a-zA-Z0-9]+)/g,function(m,escape,tag){if(escape==='\\'){return':'+tag;}
tags.push(tag);return escape+'(.+?)';});return{regexp:RegExp(path+'$'),tags:tags};}
catch(ex){throw new Error('Invalid path specified');}}
return View;})();;'use strict';var HomeView=View.extend(function HomeView(){View.call(this);this.thumbnailCache={};this.tiles=document.getElementById('tiles');this.tiles.addEventListener('click',(evt)=>{var link=evt.target.closest('a[data-file-path]');if(link){this.queueAlbum(link.dataset.filePath);}});this.onScroll=debounce(this.loadVisibleImages.bind(this),500);window.addEventListener('scroll',()=>this.onScroll());this.client.on('databaseChange',()=>this.update());this.update().then(()=>this.lazyLoadScripts());});HomeView.prototype.nonCriticalScripts=['/components/dom-scheduler/lib/dom-scheduler.js','/components/fast-list/fast-list.js','/components/poplar/poplar.js','/components/gaia-component/gaia-component.js','/components/gaia-text-input/gaia-text-input.js','/components/gaia-fast-list/gaia-fast-list.js','/components/gaia-sub-header/gaia-sub-header.js','/elements/music-search-box.js','/elements/music-search-results.js'];HomeView.prototype.lazyLoadScripts=function(){return new Promise((resolve)=>{setTimeout(()=>{LazyLoader.load(this.nonCriticalScripts).then(()=>{this.setupSearch();resolve();});},500);});};HomeView.prototype.setupSearch=function(){this.searchBox=document.getElementById('search-box');this.searchResults=document.getElementById('search-results');this.searchBoxHeight=this.searchBox.HEIGHT+11;this.searchBox.addEventListener('search',(evt)=>this.search(evt.detail));this.searchResults.addEventListener('open',()=>{this.client.method('searchOpen');document.body.dataset.search=true;document.body.classList.add('search-open');});this.searchResults.addEventListener('close',()=>{this.client.method('searchClose');document.body.dataset.search=false;document.body.classList.remove('search-open');window.scrollTo(0,this.searchBoxHeight);});this.searchResults.addEventListener('resultclick',(evt)=>{var link=evt.detail;if(link){if(link.dataset.section==='songs'){this.queueSong(link.dataset.filePath);}
this.client.method('navigate',link.getAttribute('href'));}});this.searchResults.getItemImageSrc=(item)=>this.getThumbnail(item.name);this.searchBox.hidden=false;window.scrollTo(0,this.searchBoxHeight);};HomeView.prototype.update=function(){return this.getAlbums().then((albums)=>{this.albums=albums;return this.render();});};HomeView.prototype.loadVisibleImages=function(){var scrollTop=window.scrollY;var scrollBottom=scrollTop+window.innerHeight;var promises=[];var tiles=this.tiles.querySelectorAll('.tile');var lastTileVisible=false;var tile,tileOffset;for(var i=0,length=tiles.length;i<length;i++){tile=tiles[i];tileOffset=tile.offsetTop;if(scrollTop<=tileOffset&&tileOffset<=scrollBottom){lastTileVisible=true;promises.push(this.loadTile(tile));}
else if(lastTileVisible){break;}}
return Promise.all(promises);};HomeView.prototype.loadTile=function(tile){return new Promise((resolve)=>{if(tile.dataset.loaded){return;}
this.getThumbnail(tile.dataset.filePath).then((url)=>{var img=tile.querySelector('img');img.src=url;tile.dataset.loaded=true;img.onload=()=>{setTimeout(()=>{requestAnimationFrame(()=>{tile.classList.add('loaded');resolve();});});};});});};HomeView.prototype.destroy=function(){this.client.destroy();View.prototype.destroy.call(this);};HomeView.prototype.render=function(){return document.l10n.formatValues('unknownArtist','unknownAlbum').then(([unknownArtist,unknownAlbum])=>{var html=[];this.albums.forEach((album)=>{var template=Sanitizer.createSafeHTML`
<a class="${album.metadata.picture ? 'tile' : 'tile show-title'}" dir="auto"
href="/player"
data-artist="${album.metadata.artist || unknownArtist}"
data-album="${album.metadata.album || unknownAlbum}"
data-file-path="${album.name}">
<img>
</a>`;html.push(template);});this.tiles.innerHTML=Sanitizer.unwrapSafeHTML(...html);return Promise.all([this.loadVisibleImages(),document.l10n.ready]);}).then(this.onRenderDone);};HomeView.prototype.getAlbums=function(){return this.fetch('/api/albums/list').then(response=>response.json());};HomeView.prototype.getThumbnail=function(filePath){if(!filePath)return;if(this.thumbnailCache[filePath]){return Promise.resolve(this.thumbnailCache[filePath]);}
return this.fetch('/api/artwork/url/thumbnail/'+filePath).then((response)=>response.json()).then((url)=>{this.thumbnailCache[filePath]=url;return url;});};HomeView.prototype.queueAlbum=function(filePath){this.fetch('/api/queue/album/'+filePath);};HomeView.prototype.queueSong=function(filePath){this.fetch('/api/queue/song/'+filePath);};HomeView.prototype.search=function(query){if(!query){return Promise.resolve(this.searchResults.clearResults());}
var results=[];return document.l10n.formatValues('unknownTitle','unknownArtist','unknownAlbum').then(([unknownTitle,unknownArtist,unknownAlbum])=>{var albumResults=this.fetch('/api/search/album/'+query).then(response=>response.json()).then((albums)=>{var albumResults=albums.map((album)=>{return{name:album.name,title:album.metadata.album||unknownAlbum,subtitle:album.metadata.artist||unknownArtist,section:'albums',url:'/album-detail?id='+encodeURIComponent(album.name)};});results=results.concat(albumResults);this.searchResults.setResults(results);return albumResults;});var artistResults=this.fetch('/api/search/artist/'+query).then(response=>response.json()).then((artists)=>{var artistResults=artists.map((artist)=>{return{name:artist.name,title:artist.metadata.artist||unknownArtist,subtitle:'',section:'artists',url:'/artist-detail?id='+encodeURIComponent(artist.name)};});results=results.concat(artistResults);this.searchResults.setResults(results);return artistResults;});var songResults=this.fetch('/api/search/title/'+query).then(response=>response.json()).then((songs)=>{var songResults=songs.map((song)=>{return{name:song.name,title:song.metadata.title||unknownTitle,subtitle:song.metadata.artist||unknownArtist,section:'songs',url:'/player'};});results=results.concat(songResults);this.searchResults.setResults(results);return songResults;});return Promise.all([albumResults,artistResults,songResults]).then(()=>{return results;});});};function debounce(fn,ms){var timeout;return(...args)=>{clearTimeout(timeout);timeout=setTimeout(()=>fn.apply(this,args),ms);};}
window.view=new HomeView();

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en-US" class="theme-media" dir="ltr">
<head>
<meta charset="utf-8">
<title data-l10n-id="music">Music</title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<!-- Localization -->
<meta name="defaultLanguage" content="en-US">
<meta name="availableLanguages" content="ar:201601260729, bg:201601260729, bn-BD:201601260729, ca:201601260729, cs:201601260729, da:201601260729, de:201601260729, el:201601260729, en-US:201601260729, es:201601260729, eu:201601260729, fr:201601260729, gl:201601260729, hr:201601260729, hu:201601260729, it:201601260729, ja:201601260729, km:201601260729, ko:201601260729, lt:201601260729, mk:201601260729, ms:201601260729, ne-NP:201601260729, nl:201601260729, pa:201601260729, pl:201601260729, pt-BR:201601260729, ro:201601260729, ru:201601260729, sk:201601260729, sq:201601260729, sr-Cyrl:201601260729, sr-Latn:201601260729, sv-SE:201601260729, tr:201601260729, zh-CN:201601260729, zh-TW:201601260729">
<link rel="localization" href="/locales-obj/views.home.index.{locale}.json">
<!-- Stylesheets -->
<link rel="stylesheet" href="/components/gaia-icons/gaia-icons.css">
<link rel="stylesheet" href="/components/gaia-theme/gaia-theme.css">
<link rel="stylesheet" href="/css/view.css">
<link rel="stylesheet" href="view.css">
<!-- Deferred Scripts -->
<!-- <script defer="" src="/components/bridge/client.js"></script> -->
<!-- <script defer="" src="/shared/js/intl/l20n-client.js"></script> -->
<!-- <script defer="" src="/shared/js/sanitizer.js"></script> -->
<!-- <script defer="" src="/shared/js/lazy_loader.js"></script> -->
<!-- <script defer="" src="/js/config.js"></script> -->
<!-- <script defer="" src="/js/view.js"></script> -->
<!-- <script defer="" src="view.js"></script> --><script src="./gaia_build_defer_index.js" defer="" type="text/javascript"></script>
<meta content="2.5" name="appVersion"></head>
<body role="application">
<music-search-box id="search-box" results="#search-results" hidden=""></music-search-box>
<section id="tiles"></section>
<music-search-results id="search-results"></music-search-results>
</body>
</html>

View file

@ -0,0 +1,116 @@
body {
overflow-x: hidden;
overflow-y: auto;
}
body[data-search="true"] {
overflow: hidden;
}
music-search-box {
padding: 0 16px 10px;
border-bottom: solid 1px var(--border-color);
box-sizing: border-box;
}
music-search-box[hidden] {
display: none;
}
#tiles {
min-height: 100%;
}
.search-open #tiles {
display: none;
}
.tile {
border-bottom: solid 0.1rem var(--background);
box-sizing: border-box;
display: block;
float: inline-start;
text-align: match-parent;
position: relative;
width: 33.333vw;
height: 33.333vw;
overflow: hidden;
text-decoration: none;
}
.tile:nth-child(3n+1) {
width: 66.666vw;
height: 66.666vw;
}
.tile:nth-child(6n+4),
.tile:nth-child(6n+5),
.tile:nth-child(6n+6) {
float: inline-end;
}
.tile:nth-child(1),
.tile:nth-child(2) {
border-top: solid 0.1rem var(--background);
}
.tile:nth-child(6n+1) {
border-right: solid 0.1rem var(--background);
}
.tile:nth-child(6n+4) {
border-left: solid 0.1rem var(--background);
}
.tile:before,
.tile:after {
background-color: rgba(0, 0, 0, 0.5);
text-shadow: 0 0.1rem rgba(0, 0, 0, 0.5);
position: absolute;
display: block;
box-sizing: border-box;
padding: 0.15rem 1rem;
left: 0;
width: 100%;
height: 2.8rem;
z-index: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
opacity: 1;
transition: opacity 250ms;
}
.tile.loaded:not(.show-title):before,
.tile.loaded:not(.show-title):after {
opacity: 0;
}
.tile:before {
content: attr(data-artist);
color: #fff;
font-size: 1.9rem;
line-height: 2.8rem;
top: 0;
}
.tile:after {
content: attr(data-album);
color: rgba(255, 255, 255, 0.65);
font-size: 1.4rem;
line-height: 2.2rem;
top: 2.8rem;
}
.tile > img {
position: relative;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
transition: opacity 250ms;
}
.tile.loaded > img {
opacity: 1;
}

View file

@ -0,0 +1,15 @@
;'use strict';var HomeView=View.extend(function HomeView(){View.call(this);this.thumbnailCache={};this.tiles=document.getElementById('tiles');this.tiles.addEventListener('click',(evt)=>{var link=evt.target.closest('a[data-file-path]');if(link){this.queueAlbum(link.dataset.filePath);}});this.onScroll=debounce(this.loadVisibleImages.bind(this),500);window.addEventListener('scroll',()=>this.onScroll());this.client.on('databaseChange',()=>this.update());this.update().then(()=>this.lazyLoadScripts());});HomeView.prototype.nonCriticalScripts=['/components/dom-scheduler/lib/dom-scheduler.js','/components/fast-list/fast-list.js','/components/poplar/poplar.js','/components/gaia-component/gaia-component.js','/components/gaia-text-input/gaia-text-input.js','/components/gaia-fast-list/gaia-fast-list.js','/components/gaia-sub-header/gaia-sub-header.js','/elements/music-search-box.js','/elements/music-search-results.js'];HomeView.prototype.lazyLoadScripts=function(){return new Promise((resolve)=>{setTimeout(()=>{LazyLoader.load(this.nonCriticalScripts).then(()=>{this.setupSearch();resolve();});},500);});};HomeView.prototype.setupSearch=function(){this.searchBox=document.getElementById('search-box');this.searchResults=document.getElementById('search-results');this.searchBoxHeight=this.searchBox.HEIGHT+11;this.searchBox.addEventListener('search',(evt)=>this.search(evt.detail));this.searchResults.addEventListener('open',()=>{this.client.method('searchOpen');document.body.dataset.search=true;document.body.classList.add('search-open');});this.searchResults.addEventListener('close',()=>{this.client.method('searchClose');document.body.dataset.search=false;document.body.classList.remove('search-open');window.scrollTo(0,this.searchBoxHeight);});this.searchResults.addEventListener('resultclick',(evt)=>{var link=evt.detail;if(link){if(link.dataset.section==='songs'){this.queueSong(link.dataset.filePath);}
this.client.method('navigate',link.getAttribute('href'));}});this.searchResults.getItemImageSrc=(item)=>this.getThumbnail(item.name);this.searchBox.hidden=false;window.scrollTo(0,this.searchBoxHeight);};HomeView.prototype.update=function(){return this.getAlbums().then((albums)=>{this.albums=albums;return this.render();});};HomeView.prototype.loadVisibleImages=function(){var scrollTop=window.scrollY;var scrollBottom=scrollTop+window.innerHeight;var promises=[];var tiles=this.tiles.querySelectorAll('.tile');var lastTileVisible=false;var tile,tileOffset;for(var i=0,length=tiles.length;i<length;i++){tile=tiles[i];tileOffset=tile.offsetTop;if(scrollTop<=tileOffset&&tileOffset<=scrollBottom){lastTileVisible=true;promises.push(this.loadTile(tile));}
else if(lastTileVisible){break;}}
return Promise.all(promises);};HomeView.prototype.loadTile=function(tile){return new Promise((resolve)=>{if(tile.dataset.loaded){return;}
this.getThumbnail(tile.dataset.filePath).then((url)=>{var img=tile.querySelector('img');img.src=url;tile.dataset.loaded=true;img.onload=()=>{setTimeout(()=>{requestAnimationFrame(()=>{tile.classList.add('loaded');resolve();});});};});});};HomeView.prototype.destroy=function(){this.client.destroy();View.prototype.destroy.call(this);};HomeView.prototype.render=function(){return document.l10n.formatValues('unknownArtist','unknownAlbum').then(([unknownArtist,unknownAlbum])=>{var html=[];this.albums.forEach((album)=>{var template=Sanitizer.createSafeHTML`
<a class="${album.metadata.picture ? 'tile' : 'tile show-title'}" dir="auto"
href="/player"
data-artist="${album.metadata.artist || unknownArtist}"
data-album="${album.metadata.album || unknownAlbum}"
data-file-path="${album.name}">
<img>
</a>`;html.push(template);});this.tiles.innerHTML=Sanitizer.unwrapSafeHTML(...html);return Promise.all([this.loadVisibleImages(),document.l10n.ready]);}).then(this.onRenderDone);};HomeView.prototype.getAlbums=function(){return this.fetch('/api/albums/list').then(response=>response.json());};HomeView.prototype.getThumbnail=function(filePath){if(!filePath)return;if(this.thumbnailCache[filePath]){return Promise.resolve(this.thumbnailCache[filePath]);}
return this.fetch('/api/artwork/url/thumbnail/'+filePath).then((response)=>response.json()).then((url)=>{this.thumbnailCache[filePath]=url;return url;});};HomeView.prototype.queueAlbum=function(filePath){this.fetch('/api/queue/album/'+filePath);};HomeView.prototype.queueSong=function(filePath){this.fetch('/api/queue/song/'+filePath);};HomeView.prototype.search=function(query){if(!query){return Promise.resolve(this.searchResults.clearResults());}
var results=[];return document.l10n.formatValues('unknownTitle','unknownArtist','unknownAlbum').then(([unknownTitle,unknownArtist,unknownAlbum])=>{var albumResults=this.fetch('/api/search/album/'+query).then(response=>response.json()).then((albums)=>{var albumResults=albums.map((album)=>{return{name:album.name,title:album.metadata.album||unknownAlbum,subtitle:album.metadata.artist||unknownArtist,section:'albums',url:'/album-detail?id='+encodeURIComponent(album.name)};});results=results.concat(albumResults);this.searchResults.setResults(results);return albumResults;});var artistResults=this.fetch('/api/search/artist/'+query).then(response=>response.json()).then((artists)=>{var artistResults=artists.map((artist)=>{return{name:artist.name,title:artist.metadata.artist||unknownArtist,subtitle:'',section:'artists',url:'/artist-detail?id='+encodeURIComponent(artist.name)};});results=results.concat(artistResults);this.searchResults.setResults(results);return artistResults;});var songResults=this.fetch('/api/search/title/'+query).then(response=>response.json()).then((songs)=>{var songResults=songs.map((song)=>{return{name:song.name,title:song.metadata.title||unknownTitle,subtitle:song.metadata.artist||unknownArtist,section:'songs',url:'/player'};});results=results.concat(songResults);this.searchResults.setResults(results);return songResults;});return Promise.all([albumResults,artistResults,songResults]).then(()=>{return results;});});};function debounce(fn,ms){var timeout;return(...args)=>{clearTimeout(timeout);timeout=setTimeout(()=>fn.apply(this,args),ms);};}
window.view=new HomeView();