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,28 @@
;'use strict';var BlobView=(function(){function fail(msg){throw Error(msg);}
var decoderCache={};function getDecoder(encoding){if(encoding in decoderCache){return decoderCache[encoding];}
var decoder=decoderCache[encoding]=new TextDecoder(encoding);return decoder;}
function BlobView(blob,sliceOffset,sliceLength,slice,viewOffset,viewLength,littleEndian)
{this.blob=blob;this.sliceOffset=sliceOffset;this.sliceLength=sliceLength;this.slice=slice;this.viewOffset=viewOffset;this.viewLength=viewLength;this.littleEndian=littleEndian;this.view=new DataView(slice,viewOffset,viewLength);this.buffer=slice;this.byteLength=viewLength;this.byteOffset=viewOffset;this.index=0;}
BlobView.get=function(blob,offset,length,callback,littleEndian){if(offset<0){fail('negative offset');}
if(length<0){fail('negative length');}
if(offset>blob.size){fail('offset larger than blob size');}
if(offset+length>blob.size){length=blob.size-offset;}
var slice=blob.slice(offset,offset+length);var reader=new FileReader();reader.readAsArrayBuffer(slice);reader.onloadend=function(){var result=null;if(reader.result){result=new BlobView(blob,offset,length,reader.result,0,length,littleEndian||false);}
callback(result,reader.error);};};BlobView.getFromArrayBuffer=function(buffer,offset,length,littleEndian){return new BlobView(null,offset,length,buffer,offset,length,littleEndian);};BlobView.prototype={constructor:BlobView,getMore:function(offset,length,callback){if(!this.blob){fail('no blob backing this BlobView');}
if(offset>=this.sliceOffset&&offset+length<=this.sliceOffset+this.sliceLength){callback(new BlobView(this.blob,this.sliceOffset,this.sliceLength,this.slice,offset-this.sliceOffset,length,this.littleEndian));}
else{BlobView.get(this.blob,offset,length,callback,this.littleEndian);}},littleEndian:function(){this.littleEndian=true;},bigEndian:function(){this.littleEndian=false;},getUint8:function(offset){return this.view.getUint8(offset);},getInt8:function(offset){return this.view.getInt8(offset);},getUint16:function(offset,le){return this.view.getUint16(offset,le!==undefined?le:this.littleEndian);},getInt16:function(offset,le){return this.view.getInt16(offset,le!==undefined?le:this.littleEndian);},getUint32:function(offset,le){return this.view.getUint32(offset,le!==undefined?le:this.littleEndian);},getInt32:function(offset,le){return this.view.getInt32(offset,le!==undefined?le:this.littleEndian);},getFloat32:function(offset,le){return this.view.getFloat32(offset,le!==undefined?le:this.littleEndian);},getFloat64:function(offset,le){return this.view.getFloat64(offset,le!==undefined?le:this.littleEndian);},readByte:function(){return this.view.getInt8(this.index++);},readUnsignedByte:function(){return this.view.getUint8(this.index++);},readShort:function(le){var val=this.view.getInt16(this.index,le!==undefined?le:this.littleEndian);this.index+=2;return val;},readUnsignedShort:function(le){var val=this.view.getUint16(this.index,le!==undefined?le:this.littleEndian);this.index+=2;return val;},readInt:function(le){var val=this.view.getInt32(this.index,le!==undefined?le:this.littleEndian);this.index+=4;return val;},readUnsignedInt:function(le){var val=this.view.getUint32(this.index,le!==undefined?le:this.littleEndian);this.index+=4;return val;},readFloat:function(le){var val=this.view.getFloat32(this.index,le!==undefined?le:this.littleEndian);this.index+=4;return val;},readDouble:function(le){var val=this.view.getFloat64(this.index,le!==undefined?le:this.littleEndian);this.index+=8;return val;},tell:function(){return this.index;},remaining:function(){return this.byteLength-this.index;},seek:function(index){if(index<0){fail('negative index');}
if(index>this.byteLength){fail('index greater than buffer size');}
this.index=index;},advance:function(n){var index=this.index+n;if(index<0){fail('advance past beginning of buffer');}
if(index>this.byteLength){fail('advance past end of buffer');}
this.index=index;},getUnsignedByteArray:function(offset,n){return new Uint8Array(this.buffer,offset+this.viewOffset,n);},readUnsignedByteArray:function(n){var val=new Uint8Array(this.buffer,this.index+this.viewOffset,n);this.index+=n;return val;},getBit:function(offset,bit){var byte=this.view.getUint8(offset);return(byte&(1<<bit))!==0;},getUint24:function(offset,le){var b1,b2,b3;if(le!==undefined?le:this.littleEndian){b1=this.view.getUint8(offset);b2=this.view.getUint8(offset+1);b3=this.view.getUint8(offset+2);}
else{b3=this.view.getUint8(offset);b2=this.view.getUint8(offset+1);b1=this.view.getUint8(offset+2);}
return(b3<<16)+(b2<<8)+b1;},readUint24:function(le){var value=this.getUint24(this.index,le);this.index+=3;return value;},getBinaryText:function(offset,len){var bytes=new Uint8Array(this.buffer,offset+this.viewOffset,len);return String.fromCharCode.apply(String,bytes);},readBinaryText:function(len){var s=this.getBinaryText(this.index,len);this.index+=len;return s;},getLatin1Text:function(offset,len){var bytes=new Uint8Array(this.buffer,offset+this.viewOffset,len);return getDecoder('latin1').decode(bytes);},readLatin1Text:function(len){var s=this.getLatin1Text(this.index,len);this.index+=len;return s;},getUTF8Text:function(offset,len){var bytes=new Uint8Array(this.buffer,offset+this.viewOffset,len);return getDecoder('utf-8').decode(bytes);},readUTF8Text:function(len){var s=this.getUTF8Text(this.index,len);this.index+=len;return s;},getUTF16Text:function(offset,len,le){if(len%2){fail('len must be a multiple of two');}
var bytes=new Uint8Array(this.buffer,offset+this.viewOffset,len);if(le===null||le===undefined){var BOM=(bytes[0]<<8)+bytes[1];if(BOM===0xFEFF){bytes=bytes.subarray(2);le=false;}else if(BOM===0xFFFE){bytes=bytes.subarray(2);le=true;}else{le=true;}}
var encoding=le?'utf-16le':'utf-16be';return getDecoder(encoding).decode(bytes);},readUTF16Text:function(len,le){var s=this.getUTF16Text(this.index,len,le);this.index+=len;return s;},getID3Uint28BE:function(offset){var b1=this.view.getUint8(offset)&0x7f;var b2=this.view.getUint8(offset+1)&0x7f;var b3=this.view.getUint8(offset+2)&0x7f;var b4=this.view.getUint8(offset+3)&0x7f;return(b1<<21)|(b2<<14)|(b3<<7)|b4;},readID3Uint28BE:function(){var value=this.getID3Uint28BE(this.index);this.index+=4;return value;},readNullTerminatedLatin1Text:function(size,advance_by_size=false){var bytes=new Uint8Array(this.buffer,this.viewOffset+this.index,size);var nil=bytes.indexOf(0);if(nil!==-1){bytes=bytes.subarray(0,nil);}
var s=getDecoder('latin1').decode(bytes);if(nil===-1||advance_by_size){this.index+=size;}else{this.index+=nil+1;}
return s;},readNullTerminatedUTF8Text:function(size,advance_by_size=false){var bytes=new Uint8Array(this.buffer,this.viewOffset+this.index,size);var nil=bytes.indexOf(0);if(nil!==-1){bytes=bytes.subarray(0,nil);}
var s=getDecoder('utf-8').decode(bytes);if(nil===-1||advance_by_size){this.index+=size;}else{this.index+=nil+1;}
return s;},readNullTerminatedUTF16Text:function(size,le,advance_by_size=false){if(size%2){fail('size must be a multiple of two');}
for(var len=0;len<size;len+=2){if(this.getUint16(this.index+len,le)===0){break;}}
var s=this.getUTF16Text(this.index,len,le);if(len===size||advance_by_size){this.index+=size;}else{this.index+=len+2;}
return s;}};return{get:BlobView.get,getFromArrayBuffer:BlobView.getFromArrayBuffer};}());

View file

@ -0,0 +1,45 @@
(function(exports) {
'use strict';
/**
* ComponentUtils is a utility which allows us to use web components earlier
* than we should be able to by polyfilling and fixing platform deficiencies.
*/
exports.ComponentUtils = {
/**
* Injects a style.css into both the shadow root and outside the shadow
* root so we can style projected content. Bug 992249.
*/
style: function(baseUrl) { if (window.VulpesCompat) { window.VulpesCompat.componentStyle(this, baseUrl).catch(console.error); return; }
var style = document.createElement('style');
var url = baseUrl + 'style.css';
var self = this;
style.setAttribute('scoped', '');
style.innerHTML = '@import url(' + url + ');';
this.appendChild(style);
this.style.visibility = 'hidden';
// Wait for the stylesheet to load before injecting
// it into the shadow-dom. This is to work around
// bug 1003294, let's review once landed.
style.addEventListener('load', function() {
// Put a clone of the stylesheet into the shadow-dom.
// We have to use two <style> nodes, to work around
// the lack of `:host` (bug 992245) and `:content`
// (bug 992249) selectors. Once we have those we
// can do all our styling from a single style-sheet
// within the shadow-dom.
if (self.shadowRoot) {
self.shadowRoot.appendChild(style.cloneNode(true));
}
self.style.visibility = '';
});
}
};
}(window));

View file

@ -0,0 +1,3 @@
;'use strict';function getStorageIfAvailable(kind,size,success,error){var storage=navigator.getDeviceStorage(kind);storage.available().onsuccess=function(e){if(e.target.result!=='available'){if(error){error(e.target.result);}}
else{storage.freeSpace().onsuccess=function(e){if(e.target.result<size){if(error){error(e.target.result);}}
else{success(storage);}};}};}

View file

@ -0,0 +1,3 @@
;'use strict';function getUnusedFilename(storage,name,callback){var getreq=storage.get(name);getreq.onerror=function(){callback(name);};getreq.onsuccess=function(){var version=0;var p=name.lastIndexOf('/');var dir=name.substring(0,p+1);var file=name.substring(p+1);p=file.lastIndexOf('.');if(p===-1){p=file.length;}
var ext=file.substring(p);var base=file.substring(0,p);var parts=base.match(/^(.*)_(\d{1,2})$/);if(parts){base=parts[1];version=parseInt(parts[2]);}
var newname=dir+base+'_'+(version+1)+ext;getUnusedFilename(storage,newname,callback);};}

View file

@ -0,0 +1,9 @@
;'use strict';var Dialogs={confirm:function(options,onConfirm,onCancel){LazyLoader.load('shared/style/confirm.css',function(){var dialog=$('confirm-dialog');var msgEle=$('confirm-msg');var cancelButton=$('confirm-cancel');var confirmButton=$('confirm-ok');var addText=function(element,prefix,defaultId){if(options[prefix+'Id']){document.l10n.setAttributes(element,options[prefix+'Id'],options[prefix+'Args']);}
else if(options[prefix]||options[prefix+'Text']){var textOption=options[prefix]||options[prefix+'Text'];element.textContent=textOption;}
else if(defaultId){element.setAttribute('data-l10n-id',defaultId);}};addText(msgEle,'message');addText(cancelButton,'cancel','cancel');addText(confirmButton,'confirm','ok');if(options.danger){confirmButton.classList.add('danger');}else{confirmButton.classList.remove('danger');}
if(options.bodyClass){document.body.classList.add(options.bodyClass);}
dialog.classList.remove('hidden');function close(ev){if(options.bodyClass){document.body.classList.remove(options.bodyClass);}
dialog.classList.add('hidden');cancelButton.removeEventListener('click',onCancelClick);confirmButton.removeEventListener('click',onConfirmClick);ev.preventDefault();ev.stopPropagation();return false;}
var onCancelClick=function(ev){close(ev);if(onCancel){onCancel();}
return false;};var onConfirmClick=function(ev){close(ev);if(onConfirm){onConfirm();}
return false;};cancelButton.addEventListener('click',onCancelClick);confirmButton.addEventListener('click',onConfirmClick);});}};

View file

@ -0,0 +1,33 @@
;'use strict';var GestureDetector=(function(){function GD(e,options){this.element=e;this.options=options||{};this.options.panThreshold=this.options.panThreshold||GD.PAN_THRESHOLD;this.state=initialState;this.timers={};}
GD.prototype.startDetecting=function(){var self=this;eventtypes.forEach(function(t){self.element.addEventListener(t,self);});};GD.prototype.stopDetecting=function(){var self=this;eventtypes.forEach(function(t){self.element.removeEventListener(t,self);});};GD.prototype.handleEvent=function(e){var handler=this.state[e.type];if(!handler){return;}
if(e.changedTouches){for(var i=0;i<e.changedTouches.length;i++){handler(this,e,e.changedTouches[i]);handler=this.state[e.type];if(!handler){return;}}}
else{handler(this,e);}};GD.prototype.startTimer=function(type,time){this.clearTimer(type);var self=this;this.timers[type]=setTimeout(function(){self.timers[type]=null;var handler=self.state[type];if(handler){handler(self,type);}},time);};GD.prototype.clearTimer=function(type){if(this.timers[type]){clearTimeout(this.timers[type]);this.timers[type]=null;}};GD.prototype.switchTo=function(state,event,touch){this.state=state;if(state.init){state.init(this,event,touch);}};GD.prototype.emitEvent=function(type,detail){if(!this.target){console.error('Attempt to emit event with no target');return;}
var event=this.element.ownerDocument.createEvent('CustomEvent');event.initCustomEvent(type,true,true,detail);this.target.dispatchEvent(event);};GD.HOLD_INTERVAL=1000;GD.PAN_THRESHOLD=20;GD.DOUBLE_TAP_DISTANCE=50;GD.DOUBLE_TAP_TIME=500;GD.VELOCITY_SMOOTHING=0.5;GD.SCALE_THRESHOLD=20;GD.ROTATE_THRESHOLD=22.5;GD.THRESHOLD_SMOOTHING=0.9;var abs=Math.abs,floor=Math.floor,sqrt=Math.sqrt,atan2=Math.atan2;var PI=Math.PI;var eventtypes=['touchstart','touchmove','touchend'];function eventTime(e){var ts=e.timeStamp;if(ts>2*Date.now()){return Math.floor(ts/1000);}else{return ts;}}
function coordinates(e,t){return Object.freeze({screenX:t.screenX,screenY:t.screenY,clientX:t.clientX,clientY:t.clientY,timeStamp:eventTime(e)});}
function midpoints(e,t1,t2){return Object.freeze({screenX:floor((t1.screenX+t2.screenX)/2),screenY:floor((t1.screenY+t2.screenY)/2),clientX:floor((t1.clientX+t2.clientX)/2),clientY:floor((t1.clientY+t2.clientY)/2),timeStamp:eventTime(e)});}
function between(c1,c2){var r=GD.THRESHOLD_SMOOTHING;return Object.freeze({screenX:floor(c1.screenX+r*(c2.screenX-c1.screenX)),screenY:floor(c1.screenY+r*(c2.screenY-c1.screenY)),clientX:floor(c1.clientX+r*(c2.clientX-c1.clientX)),clientY:floor(c1.clientY+r*(c2.clientY-c1.clientY)),timeStamp:floor(c1.timeStamp+r*(c2.timeStamp-c1.timeStamp))});}
function touchDistance(t1,t2){var dx=t2.screenX-t1.screenX;var dy=t2.screenY-t1.screenY;return sqrt(dx*dx+dy*dy);}
function touchDirection(t1,t2){return atan2(t2.screenY-t1.screenY,t2.screenX-t1.screenX)*180/PI;}
function touchRotation(d1,d2){var angle=d2-d1;if(angle>180){angle-=360;}else if(angle<=-180){angle+=360;}
return angle;}
function isDoubleTap(lastTap,thisTap){var dx=abs(thisTap.screenX-lastTap.screenX);var dy=abs(thisTap.screenY-lastTap.screenY);var dt=thisTap.timeStamp-lastTap.timeStamp;return(dx<GD.DOUBLE_TAP_DISTANCE&&dy<GD.DOUBLE_TAP_DISTANCE&&dt<GD.DOUBLE_TAP_TIME);}
var initialState={name:'initialState',init:function(d,e,t){d.target=null;d.start=d.last=null;d.touch1=d.touch2=null;d.vx=d.vy=null;d.startDistance=d.lastDistance=null;d.startDirection=d.lastDirection=null;d.lastMidpoint=null;d.scaled=d.rotated=null;if(e&&t&&e.type==='touchstart'){initialState.touchstart(d,e,t);}},touchstart:function(d,e,t){d.switchTo(touchStartedState,e,t);}};var touchStartedState={name:'touchStartedState',init:function(d,e,t){d.target=e.target;d.touch1=t.identifier;d.start=d.last=coordinates(e,t);if(d.options.holdEvents){d.startTimer('holdtimeout',GD.HOLD_INTERVAL);}},touchstart:function(d,e,t){d.clearTimer('holdtimeout');if(e.touches.length>1){d.switchTo(transformState,e,t);}
else{console.warn('Ignoring missing touchend event. See bug 1162771.');d.switchTo(initialState,e,t);}},touchmove:function(d,e,t){if(t.identifier!==d.touch1){return;}
if(abs(t.screenX-d.start.screenX)>d.options.panThreshold||abs(t.screenY-d.start.screenY)>d.options.panThreshold){d.clearTimer('holdtimeout');d.switchTo(panStartedState,e,t);}},touchend:function(d,e,t){if(t.identifier!==d.touch1){return;}
if(d.lastTap&&isDoubleTap(d.lastTap,d.start)){d.emitEvent('tap',d.start);d.emitEvent('dbltap',d.start);d.lastTap=null;}
else{d.emitEvent('tap',d.start);d.lastTap=coordinates(e,t);}
d.clearTimer('holdtimeout');d.switchTo(initialState);},holdtimeout:function(d){d.switchTo(holdState);}};var panStartedState={name:'panStartedState',init:function(d,e,t){d.start=d.last=between(d.start,coordinates(e,t));if(e.type==='touchmove'){panStartedState.touchmove(d,e,t);}},touchmove:function(d,e,t){if(t.identifier!==d.touch1){return;}
var current=coordinates(e,t);d.emitEvent('pan',{absolute:{dx:current.screenX-d.start.screenX,dy:current.screenY-d.start.screenY},relative:{dx:current.screenX-d.last.screenX,dy:current.screenY-d.last.screenY},position:current});var dt=current.timeStamp-d.last.timeStamp;var vx=(current.screenX-d.last.screenX)/dt;var vy=(current.screenY-d.last.screenY)/dt;if(d.vx==null){d.vx=vx;d.vy=vy;}
else{d.vx=d.vx*GD.VELOCITY_SMOOTHING+
vx*(1-GD.VELOCITY_SMOOTHING);d.vy=d.vy*GD.VELOCITY_SMOOTHING+
vy*(1-GD.VELOCITY_SMOOTHING);}
d.last=current;},touchend:function(d,e,t){if(t.identifier!==d.touch1){return;}
var current=coordinates(e,t);var dx=current.screenX-d.start.screenX;var dy=current.screenY-d.start.screenY;var angle=atan2(dy,dx)*180/PI;if(angle<0){angle+=360;}
var direction;if(angle>=315||angle<45){direction='right';}else if(angle>=45&&angle<135){direction='down';}else if(angle>=135&&angle<225){direction='left';}else if(angle>=225&&angle<315){direction='up';}
d.emitEvent('swipe',{start:d.start,end:current,dx:dx,dy:dy,dt:e.timeStamp-d.start.timeStamp,vx:d.vx,vy:d.vy,direction:direction,angle:angle});d.switchTo(initialState);}};var holdState={name:'holdState',init:function(d){d.emitEvent('holdstart',d.start);},touchmove:function(d,e,t){var current=coordinates(e,t);d.emitEvent('holdmove',{absolute:{dx:current.screenX-d.start.screenX,dy:current.screenY-d.start.screenY},relative:{dx:current.screenX-d.last.screenX,dy:current.screenY-d.last.screenY},position:current});d.last=current;},touchend:function(d,e,t){var current=coordinates(e,t);d.emitEvent('holdend',{start:d.start,end:current,dx:current.screenX-d.start.screenX,dy:current.screenY-d.start.screenY});d.switchTo(initialState);}};var transformState={name:'transformState',init:function(d,e,t){d.touch2=t.identifier;var t1=e.touches.identifiedTouch(d.touch1);var t2=e.touches.identifiedTouch(d.touch2);d.startDistance=d.lastDistance=touchDistance(t1,t2);d.startDirection=d.lastDirection=touchDirection(t1,t2);d.scaled=d.rotated=false;},touchmove:function(d,e,t){if(t.identifier!==d.touch1&&t.identifier!==d.touch2){return;}
var t1=e.touches.identifiedTouch(d.touch1);var t2=e.touches.identifiedTouch(d.touch2);var midpoint=midpoints(e,t1,t2);var distance=touchDistance(t1,t2);var direction=touchDirection(t1,t2);var rotation=touchRotation(d.startDirection,direction);if(!d.scaled){if(abs(distance-d.startDistance)>GD.SCALE_THRESHOLD){d.scaled=true;d.startDistance=d.lastDistance=floor(d.startDistance+
GD.THRESHOLD_SMOOTHING*(distance-d.startDistance));}else{distance=d.startDistance;}}
if(!d.rotated){if(abs(rotation)>GD.ROTATE_THRESHOLD){d.rotated=true;}else{direction=d.startDirection;}}
if(d.scaled||d.rotated){d.emitEvent('transform',{absolute:{scale:distance/d.startDistance,rotate:touchRotation(d.startDirection,direction)},relative:{scale:distance/d.lastDistance,rotate:touchRotation(d.lastDirection,direction)},midpoint:midpoint});d.lastDistance=distance;d.lastDirection=direction;d.lastMidpoint=midpoint;}},touchend:function(d,e,t){if(t.identifier===d.touch2){d.touch2=null;}else if(t.identifier===d.touch1){d.touch1=d.touch2;d.touch2=null;}else{return;}
if(d.scaled||d.rotated){d.emitEvent('transformend',{absolute:{scale:d.lastDistance/d.startDistance,rotate:touchRotation(d.startDirection,d.lastDirection)},relative:{scale:1,rotate:0},midpoint:d.lastMidpoint});}
d.switchTo(afterTransformState);}};var afterTransformState={name:'afterTransformState',touchstart:function(d,e,t){d.switchTo(transformState,e,t);},touchend:function(d,e,t){if(t.identifier===d.touch1){d.switchTo(initialState);}}};return GD;}());

View file

@ -0,0 +1,280 @@
;;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';function emit(listeners,...args){const type=args.shift();if(listeners['*']){listeners['*'].slice().forEach(listener=>listener.apply(this,args));}
if(listeners[type]){listeners[type].slice().forEach(listener=>listener.apply(this,args));}}
function addEventListener(listeners,type,listener){if(!(type in listeners)){listeners[type]=[];}
listeners[type].push(listener);}
function removeEventListener(listeners,type,listener){const typeListeners=listeners[type];const pos=typeListeners.indexOf(listener);if(pos===-1){return;}
typeListeners.splice(pos,1);}
let Client=(function(){function Client(remote){_classCallCheck(this,Client);this.id=this;this.remote=remote;const listeners={};this.on=(...args)=>addEventListener(listeners,...args);this.emit=(...args)=>emit(listeners,...args);}
_createClass(Client,[{key:'method',value:function method(name,...args){return this.remote[name](...args);}}]);return Client;})();function broadcast(type,data){Array.from(this.ctxs.keys()).forEach(client=>client.emit(type,data));}
function L10nError(message,id,lang){this.name='L10nError';this.message=message;this.id=id;this.lang=lang;}
L10nError.prototype=Object.create(Error.prototype);L10nError.prototype.constructor=L10nError;function load(type,url){return new Promise(function(resolve,reject){const xhr=new XMLHttpRequest();if(xhr.overrideMimeType){xhr.overrideMimeType(type);}
xhr.open('GET',url,true);if(type==='application/json'){xhr.responseType='json';}
xhr.addEventListener('load',function io_onload(e){if(e.target.status===200||e.target.status===0){resolve(e.target.response||e.target.responseText);}else{reject(new L10nError('Not found: '+url));}});xhr.addEventListener('error',reject);xhr.addEventListener('timeout',reject);try{xhr.send(null);}catch(e){if(e.name==='NS_ERROR_FILE_NOT_FOUND'){reject(new L10nError('Not found: '+url));}else{throw e;}}});}
const io={extra:function(code,ver,path,type){return navigator.mozApps.getLocalizationResource(code,ver,path,type);},app:function(code,ver,path,type){switch(type){case'text':return load('text/plain',path);case'json':return load('application/json',path);default:throw new L10nError('Unknown file type: '+type);}}};function fetchResource(res,{code,src,ver}){const url=res.replace('{locale}',code);const type=res.endsWith('.json')?'json':'text';return io[src](code,ver,url,type);}
const KNOWN_MACROS=['plural'];const MAX_PLACEABLE_LENGTH=2500;const FSI='⁨';const PDI='⁩';const resolutionChain=new WeakSet();function format(ctx,lang,args,entity){if(typeof entity==='string'){return[{},entity];}
if(resolutionChain.has(entity)){throw new L10nError('Cyclic reference detected');}
resolutionChain.add(entity);let rv;try{rv=resolveValue({},ctx,lang,args,entity.value,entity.index);}finally{resolutionChain.delete(entity);}
return rv;}
function resolveIdentifier(ctx,lang,args,id){if(KNOWN_MACROS.indexOf(id)>-1){return[{},ctx._getMacro(lang,id)];}
if(args&&args.hasOwnProperty(id)){if(typeof args[id]==='string'||typeof args[id]==='number'&&!isNaN(args[id])){return[{},args[id]];}else{throw new L10nError('Arg must be a string or a number: '+id);}}
if(id==='__proto__'){throw new L10nError('Illegal id: '+id);}
const entity=ctx._getEntity(lang,id);if(entity){return format(ctx,lang,args,entity);}
throw new L10nError('Unknown reference: '+id);}
function subPlaceable(locals,ctx,lang,args,id){let newLocals,value;try{[newLocals,value]=resolveIdentifier(ctx,lang,args,id);}catch(err){return[{error:err},FSI+'{{ '+id+' }}'+PDI];}
if(typeof value==='number'){const formatter=ctx._getNumberFormatter(lang);return[newLocals,formatter.format(value)];}
if(typeof value==='string'){if(value.length>=MAX_PLACEABLE_LENGTH){throw new L10nError('Too many characters in placeable ('+value.length+', max allowed is '+MAX_PLACEABLE_LENGTH+')');}
return[newLocals,FSI+value+PDI];}
return[{},FSI+'{{ '+id+' }}'+PDI];}
function interpolate(locals,ctx,lang,args,arr){return arr.reduce(function([localsSeq,valueSeq],cur){if(typeof cur==='string'){return[localsSeq,valueSeq+cur];}else{const[,value]=subPlaceable(locals,ctx,lang,args,cur.name);return[localsSeq,valueSeq+value];}},[locals,'']);}
function resolveSelector(ctx,lang,args,expr,index){let selectorName;if(index[0].type==='call'&&index[0].expr.type==='prop'&&index[0].expr.expr.name==='cldr'){selectorName='plural';}else{selectorName=index[0].name;}
const selector=resolveIdentifier(ctx,lang,args,selectorName)[1];if(typeof selector!=='function'){return selector;}
const argValue=index[0].args?resolveIdentifier(ctx,lang,args,index[0].args[0].name)[1]:undefined;if(selectorName==='plural'){if(argValue===0&&'zero'in expr){return'zero';}
if(argValue===1&&'one'in expr){return'one';}
if(argValue===2&&'two'in expr){return'two';}}
return selector(argValue);}
function resolveValue(locals,ctx,lang,args,expr,index){if(!expr){return[locals,expr];}
if(typeof expr==='string'||typeof expr==='boolean'||typeof expr==='number'){return[locals,expr];}
if(Array.isArray(expr)){return interpolate(locals,ctx,lang,args,expr);}
if(index){const selector=resolveSelector(ctx,lang,args,expr,index);if(selector in expr){return resolveValue(locals,ctx,lang,args,expr[selector]);}}
const defaultKey=expr.__default||'other';if(defaultKey in expr){return resolveValue(locals,ctx,lang,args,expr[defaultKey]);}
throw new L10nError('Unresolvable value');}
const locales2rules={'af':3,'ak':4,'am':4,'ar':1,'asa':3,'az':0,'be':11,'bem':3,'bez':3,'bg':3,'bh':4,'bm':0,'bn':3,'bo':0,'br':20,'brx':3,'bs':11,'ca':3,'cgg':3,'chr':3,'cs':12,'cy':17,'da':3,'de':3,'dv':3,'dz':0,'ee':3,'el':3,'en':3,'eo':3,'es':3,'et':3,'eu':3,'fa':0,'ff':5,'fi':3,'fil':4,'fo':3,'fr':5,'fur':3,'fy':3,'ga':8,'gd':24,'gl':3,'gsw':3,'gu':3,'guw':4,'gv':23,'ha':3,'haw':3,'he':2,'hi':4,'hr':11,'hu':0,'id':0,'ig':0,'ii':0,'is':3,'it':3,'iu':7,'ja':0,'jmc':3,'jv':0,'ka':0,'kab':5,'kaj':3,'kcg':3,'kde':0,'kea':0,'kk':3,'kl':3,'km':0,'kn':0,'ko':0,'ksb':3,'ksh':21,'ku':3,'kw':7,'lag':18,'lb':3,'lg':3,'ln':4,'lo':0,'lt':10,'lv':6,'mas':3,'mg':4,'mk':16,'ml':3,'mn':3,'mo':9,'mr':3,'ms':0,'mt':15,'my':0,'nah':3,'naq':7,'nb':3,'nd':3,'ne':3,'nl':3,'nn':3,'no':3,'nr':3,'nso':4,'ny':3,'nyn':3,'om':3,'or':3,'pa':3,'pap':3,'pl':13,'ps':3,'pt':3,'rm':3,'ro':9,'rof':3,'ru':11,'rwk':3,'sah':0,'saq':3,'se':7,'seh':3,'ses':0,'sg':0,'sh':11,'shi':19,'sk':12,'sl':14,'sma':7,'smi':7,'smj':7,'smn':7,'sms':7,'sn':3,'so':3,'sq':3,'sr':11,'ss':3,'ssy':3,'st':3,'sv':3,'sw':3,'syr':3,'ta':3,'te':3,'teo':3,'th':0,'ti':4,'tig':3,'tk':3,'tl':4,'tn':3,'to':0,'tr':0,'ts':3,'tzm':22,'uk':11,'ur':3,'ve':3,'vi':0,'vun':3,'wa':4,'wae':3,'wo':0,'xh':3,'xog':3,'yo':0,'zh':0,'zu':3};function isIn(n,list){return list.indexOf(n)!==-1;}
function isBetween(n,start,end){return typeof n===typeof start&&start<=n&&n<=end;}
const pluralRules={'0':function(){return'other';},'1':function(n){if(isBetween(n%100,3,10)){return'few';}
if(n===0){return'zero';}
if(isBetween(n%100,11,99)){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'2':function(n){if(n!==0&&n%10===0){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'3':function(n){if(n===1){return'one';}
return'other';},'4':function(n){if(isBetween(n,0,1)){return'one';}
return'other';},'5':function(n){if(isBetween(n,0,2)&&n!==2){return'one';}
return'other';},'6':function(n){if(n===0){return'zero';}
if(n%10===1&&n%100!==11){return'one';}
return'other';},'7':function(n){if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'8':function(n){if(isBetween(n,3,6)){return'few';}
if(isBetween(n,7,10)){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'9':function(n){if(n===0||n!==1&&isBetween(n%100,1,19)){return'few';}
if(n===1){return'one';}
return'other';},'10':function(n){if(isBetween(n%10,2,9)&&!isBetween(n%100,11,19)){return'few';}
if(n%10===1&&!isBetween(n%100,11,19)){return'one';}
return'other';},'11':function(n){if(isBetween(n%10,2,4)&&!isBetween(n%100,12,14)){return'few';}
if(n%10===0||isBetween(n%10,5,9)||isBetween(n%100,11,14)){return'many';}
if(n%10===1&&n%100!==11){return'one';}
return'other';},'12':function(n){if(isBetween(n,2,4)){return'few';}
if(n===1){return'one';}
return'other';},'13':function(n){if(isBetween(n%10,2,4)&&!isBetween(n%100,12,14)){return'few';}
if(n!==1&&isBetween(n%10,0,1)||isBetween(n%10,5,9)||isBetween(n%100,12,14)){return'many';}
if(n===1){return'one';}
return'other';},'14':function(n){if(isBetween(n%100,3,4)){return'few';}
if(n%100===2){return'two';}
if(n%100===1){return'one';}
return'other';},'15':function(n){if(n===0||isBetween(n%100,2,10)){return'few';}
if(isBetween(n%100,11,19)){return'many';}
if(n===1){return'one';}
return'other';},'16':function(n){if(n%10===1&&n!==11){return'one';}
return'other';},'17':function(n){if(n===3){return'few';}
if(n===0){return'zero';}
if(n===6){return'many';}
if(n===2){return'two';}
if(n===1){return'one';}
return'other';},'18':function(n){if(n===0){return'zero';}
if(isBetween(n,0,2)&&n!==0&&n!==2){return'one';}
return'other';},'19':function(n){if(isBetween(n,2,10)){return'few';}
if(isBetween(n,0,1)){return'one';}
return'other';},'20':function(n){if((isBetween(n%10,3,4)||n%10===9)&&!(isBetween(n%100,10,19)||isBetween(n%100,70,79)||isBetween(n%100,90,99))){return'few';}
if(n%1000000===0&&n!==0){return'many';}
if(n%10===2&&!isIn(n%100,[12,72,92])){return'two';}
if(n%10===1&&!isIn(n%100,[11,71,91])){return'one';}
return'other';},'21':function(n){if(n===0){return'zero';}
if(n===1){return'one';}
return'other';},'22':function(n){if(isBetween(n,0,1)||isBetween(n,11,99)){return'one';}
return'other';},'23':function(n){if(isBetween(n%10,1,2)||n%20===0){return'one';}
return'other';},'24':function(n){if(isBetween(n,3,10)||isBetween(n,13,19)){return'few';}
if(isIn(n,[2,12])){return'two';}
if(isIn(n,[1,11])){return'one';}
return'other';}};function getPluralRule(code){const index=locales2rules[code.replace(/-.*$/,'')];if(!(index in pluralRules)){return function(){return'other';};}
return pluralRules[index];}
const L20nIntl=typeof Intl!=='undefined'?Intl:{NumberFormat:function(){return{format:function(v){return v;}};}};let Context=(function(){function Context(env,langs,resIds){_classCallCheck(this,Context);this.langs=langs;this.resIds=resIds;this.env=env;this.emit=(type,evt)=>env.emit(type,evt,this);}
_createClass(Context,[{key:'_formatTuple',value:function _formatTuple(lang,args,entity,id,key){try{return format(this,lang,args,entity);}catch(err){err.id=key?id+'::'+key:id;err.lang=lang;this.emit('resolveerror',err);return[{error:err},err.id];}}},{key:'_formatEntity',value:function _formatEntity(lang,args,entity,id){const[,value]=this._formatTuple(lang,args,entity,id);const formatted={value,attrs:null};if(entity.attrs){formatted.attrs=Object.create(null);for(let key in entity.attrs){const[,attrValue]=this._formatTuple(lang,args,entity.attrs[key],id,key);formatted.attrs[key]=attrValue;}}
return formatted;}},{key:'_formatValue',value:function _formatValue(lang,args,entity,id){return this._formatTuple(lang,args,entity,id)[1];}},{key:'fetch',value:function fetch(langs=this.langs){if(langs.length===0){return Promise.resolve(langs);}
return Promise.all(this.resIds.map(resId=>this.env._getResource(langs[0],resId))).then(()=>langs);}},{key:'_resolve',value:function _resolve(langs,keys,formatter,prevResolved){const lang=langs[0];if(!lang){return reportMissing.call(this,keys,formatter,prevResolved);}
let hasUnresolved=false;const resolved=keys.map((key,i)=>{if(prevResolved&&prevResolved[i]!==undefined){return prevResolved[i];}
const[id,args]=Array.isArray(key)?key:[key,undefined];const entity=this._getEntity(lang,id);if(entity){return formatter.call(this,lang,args,entity,id);}
this.emit('notfounderror',new L10nError('"'+id+'"'+' not found in '+lang.code,id,lang));hasUnresolved=true;});if(!hasUnresolved){return resolved;}
return this.fetch(langs.slice(1)).then(nextLangs=>this._resolve(nextLangs,keys,formatter,resolved));}},{key:'formatEntities',value:function formatEntities(...keys){return this.fetch().then(langs=>this._resolve(langs,keys,this._formatEntity));}},{key:'formatValues',value:function formatValues(...keys){return this.fetch().then(langs=>this._resolve(langs,keys,this._formatValue));}},{key:'_getEntity',value:function _getEntity(lang,id){const cache=this.env.resCache;for(let i=0,resId;resId=this.resIds[i];i++){const resource=cache.get(resId+lang.code+lang.src);if(resource instanceof L10nError){continue;}
if(id in resource){return resource[id];}}
return undefined;}},{key:'_getNumberFormatter',value:function _getNumberFormatter(lang){if(!this.env.numberFormatters){this.env.numberFormatters=new Map();}
if(!this.env.numberFormatters.has(lang)){const formatter=L20nIntl.NumberFormat(lang);this.env.numberFormatters.set(lang,formatter);return formatter;}
return this.env.numberFormatters.get(lang);}},{key:'_getMacro',value:function _getMacro(lang,id){switch(id){case'plural':return getPluralRule(lang.code);default:return undefined;}}}]);return Context;})();function reportMissing(keys,formatter,resolved){const missingIds=new Set();keys.forEach((key,i)=>{if(resolved&&resolved[i]!==undefined){return;}
const id=Array.isArray(key)?key[0]:key;missingIds.add(id);resolved[i]=formatter===this._formatValue?id:{value:id,attrs:null};});this.emit('notfounderror',new L10nError('"'+Array.from(missingIds).join(', ')+'"'+' not found in any language',missingIds));return resolved;}
var MAX_PLACEABLES=100;var PropertiesParser={patterns:null,entryIds:null,emit:null,init:function(){this.patterns={comment:/^\s*#|^\s*$/,entity:/^([^=\s]+)\s*=\s*(.*)$/,multiline:/[^\\]\\$/,index:/\{\[\s*(\w+)(?:\(([^\)]*)\))?\s*\]\}/i,unicode:/\\u([0-9a-fA-F]{1,4})/g,entries:/[^\r\n]+/g,controlChars:/\\([\\\n\r\t\b\f\{\}\"\'])/g,placeables:/\{\{\s*([^\s]*?)\s*\}\}/};},parse:function(emit,source){if(!this.patterns){this.init();}
this.emit=emit;var entries={};var lines=source.match(this.patterns.entries);if(!lines){return entries;}
for(var i=0;i<lines.length;i++){var line=lines[i];if(this.patterns.comment.test(line)){continue;}
while(this.patterns.multiline.test(line)&&i<lines.length){line=line.slice(0,-1)+lines[++i].trim();}
var entityMatch=line.match(this.patterns.entity);if(entityMatch){try{this.parseEntity(entityMatch[1],entityMatch[2],entries);}catch(e){if(!this.emit){throw e;}}}}
return entries;},parseEntity:function(id,value,entries){var name,key;var pos=id.indexOf('[');if(pos!==-1){name=id.substr(0,pos);key=id.substring(pos+1,id.length-1);}else{name=id;key=null;}
var nameElements=name.split('.');if(nameElements.length>2){throw this.error('Error in ID: "'+name+'".'+' Nested attributes are not supported.');}
var attr;if(nameElements.length>1){name=nameElements[0];attr=nameElements[1];if(attr[0]==='$'){throw this.error('Attribute can\'t start with "$"');}}else{attr=null;}
this.setEntityValue(name,attr,key,this.unescapeString(value),entries);},setEntityValue:function(id,attr,key,rawValue,entries){var value=rawValue.indexOf('{{')>-1?this.parseString(rawValue):rawValue;var isSimpleValue=typeof value==='string';var root=entries;var isSimpleNode=typeof entries[id]==='string';if(!entries[id]&&(attr||key||!isSimpleValue)){entries[id]=Object.create(null);isSimpleNode=false;}
if(attr){if(isSimpleNode){const val=entries[id];entries[id]=Object.create(null);entries[id].value=val;}
if(!entries[id].attrs){entries[id].attrs=Object.create(null);}
if(!entries[id].attrs&&!isSimpleValue){entries[id].attrs[attr]=Object.create(null);}
root=entries[id].attrs;id=attr;}
if(key){isSimpleNode=false;if(typeof root[id]==='string'){const val=root[id];root[id]=Object.create(null);root[id].index=this.parseIndex(val);root[id].value=Object.create(null);}
root=root[id].value;id=key;isSimpleValue=true;}
if(isSimpleValue){if(id in root){throw this.error('Duplicated id: '+id);}
root[id]=value;}else{if(!root[id]){root[id]=Object.create(null);}
root[id].value=value;}},parseString:function(str){var chunks=str.split(this.patterns.placeables);var complexStr=[];var len=chunks.length;var placeablesCount=(len-1)/2;if(placeablesCount>=MAX_PLACEABLES){throw this.error('Too many placeables ('+placeablesCount+', max allowed is '+MAX_PLACEABLES+')');}
for(var i=0;i<chunks.length;i++){if(chunks[i].length===0){continue;}
if(i%2===1){complexStr.push({type:'idOrVar',name:chunks[i]});}else{complexStr.push(chunks[i]);}}
return complexStr;},unescapeString:function(str){if(str.lastIndexOf('\\')!==-1){str=str.replace(this.patterns.controlChars,'$1');}
return str.replace(this.patterns.unicode,function(match,token){return String.fromCodePoint(parseInt(token,16));});},parseIndex:function(str){var match=str.match(this.patterns.index);if(!match){throw new L10nError('Malformed index');}
if(match[2]){return[{type:'call',expr:{type:'prop',expr:{type:'glob',name:'cldr'},prop:'plural',cmpt:false},args:[{type:'idOrVar',name:match[2]}]}];}else{return[{type:'idOrVar',name:match[1]}];}},error:function(msg,type='parsererror'){const err=new L10nError(msg);if(this.emit){this.emit(type,err);}
return err;}};const MAX_PLACEABLES$1=100;var L20nParser={parse:function(emit,string){this._source=string;this._index=0;this._length=string.length;this.entries=Object.create(null);this.emit=emit;return this.getResource();},getResource:function(){this.getWS();while(this._index<this._length){try{this.getEntry();}catch(e){if(e instanceof L10nError){this.getJunkEntry();if(!this.emit){throw e;}}else{throw e;}}
if(this._index<this._length){this.getWS();}}
return this.entries;},getEntry:function(){if(this._source[this._index]==='<'){++this._index;const id=this.getIdentifier();if(this._source[this._index]==='['){++this._index;return this.getEntity(id,this.getItemList(this.getExpression,']'));}
return this.getEntity(id);}
if(this._source.startsWith('/*',this._index)){return this.getComment();}
throw this.error('Invalid entry');},getEntity:function(id,index){if(!this.getRequiredWS()){throw this.error('Expected white space');}
const ch=this._source[this._index];const hasIndex=index!==undefined;const value=this.getValue(ch,hasIndex,hasIndex);let attrs;if(value===undefined){if(ch==='>'){throw this.error('Expected ">"');}
attrs=this.getAttributes();}else{const ws1=this.getRequiredWS();if(this._source[this._index]!=='>'){if(!ws1){throw this.error('Expected ">"');}
attrs=this.getAttributes();}}
++this._index;if(id in this.entries){throw this.error('Duplicate entry ID "'+id,'duplicateerror');}
if(!attrs&&!index&&typeof value==='string'){this.entries[id]=value;}else{this.entries[id]={value,attrs,index};}},getValue:function(ch=this._source[this._index],index=false,required=true){switch(ch){case'\'':case'"':return this.getString(ch,1);case'{':return this.getHash(index);}
if(required){throw this.error('Unknown value type');}
return;},getWS:function(){let cc=this._source.charCodeAt(this._index);while(cc===32||cc===10||cc===9||cc===13){cc=this._source.charCodeAt(++this._index);}},getRequiredWS:function(){const pos=this._index;let cc=this._source.charCodeAt(pos);while(cc===32||cc===10||cc===9||cc===13){cc=this._source.charCodeAt(++this._index);}
return this._index!==pos;},getIdentifier:function(){const start=this._index;let cc=this._source.charCodeAt(this._index);if(cc>=97&&cc<=122||cc>=65&&cc<=90||cc===95){cc=this._source.charCodeAt(++this._index);}else{throw this.error('Identifier has to start with [a-zA-Z_]');}
while(cc>=97&&cc<=122||cc>=65&&cc<=90||cc>=48&&cc<=57||cc===95){cc=this._source.charCodeAt(++this._index);}
return this._source.slice(start,this._index);},getUnicodeChar:function(){for(let i=0;i<4;i++){let cc=this._source.charCodeAt(++this._index);if(cc>96&&cc<103||cc>64&&cc<71||cc>47&&cc<58){continue;}
throw this.error('Illegal unicode escape sequence');}
this._index++;return String.fromCharCode(parseInt(this._source.slice(this._index-4,this._index),16));},stringRe:/"|'|{{|\\/g,getString:function(opchar,opcharLen){const body=[];let placeables=0;this._index+=opcharLen;const start=this._index;let bufStart=start;let buf='';while(true){this.stringRe.lastIndex=this._index;const match=this.stringRe.exec(this._source);if(!match){throw this.error('Unclosed string literal');}
if(match[0]==='"'||match[0]==='\''){if(match[0]!==opchar){this._index+=opcharLen;continue;}
this._index=match.index+opcharLen;break;}
if(match[0]==='{{'){if(placeables>MAX_PLACEABLES$1-1){throw this.error('Too many placeables, maximum allowed is '+MAX_PLACEABLES$1);}
placeables++;if(match.index>bufStart||buf.length>0){body.push(buf+this._source.slice(bufStart,match.index));buf='';}
this._index=match.index+2;this.getWS();body.push(this.getExpression());this.getWS();this._index+=2;bufStart=this._index;continue;}
if(match[0]==='\\'){this._index=match.index+1;const ch2=this._source[this._index];if(ch2==='u'){buf+=this._source.slice(bufStart,match.index)+this.getUnicodeChar();}else if(ch2===opchar||ch2==='\\'){buf+=this._source.slice(bufStart,match.index)+ch2;this._index++;}else if(this._source.startsWith('{{',this._index)){buf+=this._source.slice(bufStart,match.index)+'{{';this._index+=2;}else{throw this.error('Illegal escape sequence');}
bufStart=this._index;}}
if(body.length===0){return buf+this._source.slice(bufStart,this._index-opcharLen);}
if(this._index-opcharLen>bufStart||buf.length>0){body.push(buf+this._source.slice(bufStart,this._index-opcharLen));}
return body;},getAttributes:function(){const attrs=Object.create(null);while(true){this.getAttribute(attrs);const ws1=this.getRequiredWS();const ch=this._source.charAt(this._index);if(ch==='>'){break;}else if(!ws1){throw this.error('Expected ">"');}}
return attrs;},getAttribute:function(attrs){const key=this.getIdentifier();let index;if(this._source[this._index]==='['){++this._index;this.getWS();index=this.getItemList(this.getExpression,']');}
this.getWS();if(this._source[this._index]!==':'){throw this.error('Expected ":"');}
++this._index;this.getWS();const hasIndex=index!==undefined;const value=this.getValue(undefined,hasIndex);if(key in attrs){throw this.error('Duplicate attribute "'+key,'duplicateerror');}
if(!index&&typeof value==='string'){attrs[key]=value;}else{attrs[key]={value,index};}},getHash:function(index){const items=Object.create(null);++this._index;this.getWS();let defKey;while(true){const[key,value,def]=this.getHashItem();items[key]=value;if(def){if(defKey){throw this.error('Default item redefinition forbidden');}
defKey=key;}
this.getWS();const comma=this._source[this._index]===',';if(comma){++this._index;this.getWS();}
if(this._source[this._index]==='}'){++this._index;break;}
if(!comma){throw this.error('Expected "}"');}}
if(defKey){items.__default=defKey;}else if(!index){throw this.error('Unresolvable Hash Value');}
return items;},getHashItem:function(){let defItem=false;if(this._source[this._index]==='*'){++this._index;defItem=true;}
const key=this.getIdentifier();this.getWS();if(this._source[this._index]!==':'){throw this.error('Expected ":"');}
++this._index;this.getWS();return[key,this.getValue(),defItem];},getComment:function(){this._index+=2;const start=this._index;const end=this._source.indexOf('*/',start);if(end===-1){throw this.error('Comment without a closing tag');}
this._index=end+2;},getExpression:function(){let exp=this.getPrimaryExpression();while(true){let ch=this._source[this._index];if(ch==='.'||ch==='['){++this._index;exp=this.getPropertyExpression(exp,ch==='[');}else if(ch==='('){++this._index;exp=this.getCallExpression(exp);}else{break;}}
return exp;},getPropertyExpression:function(idref,computed){let exp;if(computed){this.getWS();exp=this.getExpression();this.getWS();if(this._source[this._index]!==']'){throw this.error('Expected "]"');}
++this._index;}else{exp=this.getIdentifier();}
return{type:'prop',expr:idref,prop:exp,cmpt:computed};},getCallExpression:function(callee){this.getWS();return{type:'call',expr:callee,args:this.getItemList(this.getExpression,')')};},getPrimaryExpression:function(){const ch=this._source[this._index];switch(ch){case'$':++this._index;return{type:'var',name:this.getIdentifier()};case'@':++this._index;return{type:'glob',name:this.getIdentifier()};default:return{type:'id',name:this.getIdentifier()};}},getItemList:function(callback,closeChar){const items=[];let closed=false;this.getWS();if(this._source[this._index]===closeChar){++this._index;closed=true;}
while(!closed){items.push(callback.call(this));this.getWS();let ch=this._source.charAt(this._index);switch(ch){case',':++this._index;this.getWS();break;case closeChar:++this._index;closed=true;break;default:throw this.error('Expected "," or "'+closeChar+'"');}}
return items;},getJunkEntry:function(){const pos=this._index;let nextEntity=this._source.indexOf('<',pos);let nextComment=this._source.indexOf('/*',pos);if(nextEntity===-1){nextEntity=this._length;}
if(nextComment===-1){nextComment=this._length;}
let nextEntry=Math.min(nextEntity,nextComment);this._index=nextEntry;},error:function(message,type='parsererror'){const pos=this._index;let start=this._source.lastIndexOf('<',pos-1);const lastClose=this._source.lastIndexOf('>',pos-1);start=lastClose>start?lastClose+1:start;const context=this._source.slice(start,pos+10);const msg=message+' at pos '+pos+': `'+context+'`';const err=new L10nError(msg);if(this.emit){this.emit(type,err);}
return err;}};function walkEntry(entry,fn){if(typeof entry==='string'){return fn(entry);}
const newEntry=Object.create(null);if(entry.value){newEntry.value=walkValue(entry.value,fn);}
if(entry.index){newEntry.index=entry.index;}
if(entry.attrs){newEntry.attrs=Object.create(null);for(let key in entry.attrs){newEntry.attrs[key]=walkEntry(entry.attrs[key],fn);}}
return newEntry;}
function walkValue(value,fn){if(typeof value==='string'){return fn(value);}
if(value.type){return value;}
const newValue=Array.isArray(value)?[]:Object.create(null);const keys=Object.keys(value);for(let i=0,key;key=keys[i];i++){newValue[key]=walkValue(value[key],fn);}
return newValue;}
function createGetter(id,name){let _pseudo=null;return function getPseudo(){if(_pseudo){return _pseudo;}
const reAlphas=/[a-zA-Z]/g;const reVowels=/[aeiouAEIOU]/g;const reWords=/[^\W0-9_]+/g;const reExcluded=/(%[EO]?\w|\{\s*.+?\s*\}|&[#\w]+;|<\s*.+?\s*>)/;const charMaps={'fr-x-psaccent':'ȦƁƇḒḖƑƓĦĪĴĶĿḾȠǾƤɊŘŞŦŬṼẆẊẎẐ[\\]^_`ȧƀƈḓḗƒɠħīĵķŀḿƞǿƥɋřşŧŭṽẇẋẏẑ','ar-x-psbidi':'∀ԐↃpƎɟפHIſӼ˥WNOԀÒᴚS⊥∩ɅMXʎZ[\\]ᵥ_,ɐqɔpǝɟƃɥıɾʞʅɯuodbɹsʇnʌʍxʎz'};const mods={'fr-x-psaccent':val=>val.replace(reVowels,match=>match+match.toLowerCase()),'ar-x-psbidi':val=>val.replace(reWords,match=>'‮'+match+'‬')};const replaceChars=(map,val)=>val.replace(reAlphas,match=>map.charAt(match.charCodeAt(0)-65));const transform=val=>replaceChars(charMaps[id],mods[id](val));const apply=(fn,val)=>{if(!val){return val;}
const parts=val.split(reExcluded);const modified=parts.map(function(part){if(reExcluded.test(part)){return part;}
return fn(part);});return modified.join('');};return _pseudo={name:transform(name),process:str=>apply(transform,str)};};}
const pseudo=Object.defineProperties(Object.create(null),{'fr-x-psaccent':{enumerable:true,get:createGetter('fr-x-psaccent','Runtime Accented')},'ar-x-psbidi':{enumerable:true,get:createGetter('ar-x-psbidi','Runtime Bidi')}});let Env=(function(){function Env(fetchResource){_classCallCheck(this,Env);this.fetchResource=fetchResource;this.resCache=new Map();this.resRefs=new Map();this.numberFormatters=null;this.parsers={properties:PropertiesParser,l20n:L20nParser};const listeners={};this.emit=emit.bind(this,listeners);this.addEventListener=addEventListener.bind(this,listeners);this.removeEventListener=removeEventListener.bind(this,listeners);}
_createClass(Env,[{key:'createContext',value:function createContext(langs,resIds){const ctx=new Context(this,langs,resIds);resIds.forEach(resId=>{const usedBy=this.resRefs.get(resId)||0;this.resRefs.set(resId,usedBy+1);});return ctx;}},{key:'destroyContext',value:function destroyContext(ctx){ctx.resIds.forEach(resId=>{const usedBy=this.resRefs.get(resId)||0;if(usedBy>1){return this.resRefs.set(resId,usedBy-1);}
this.resRefs.delete(resId);this.resCache.forEach((val,key)=>key.startsWith(resId)?this.resCache.delete(key):null);});}},{key:'_parse',value:function _parse(syntax,lang,data){const parser=this.parsers[syntax];if(!parser){return data;}
const emit=(type,err)=>this.emit(type,amendError(lang,err));return parser.parse.call(parser,emit,data);}},{key:'_create',value:function _create(lang,entries){if(lang.src!=='pseudo'){return entries;}
const pseudoentries=Object.create(null);for(let key in entries){pseudoentries[key]=walkEntry(entries[key],pseudo[lang.code].process);}
return pseudoentries;}},{key:'_getResource',value:function _getResource(lang,res){const cache=this.resCache;const id=res+lang.code+lang.src;if(cache.has(id)){return cache.get(id);}
const syntax=res.substr(res.lastIndexOf('.')+1);const saveEntries=data=>{const entries=this._parse(syntax,lang,data);cache.set(id,this._create(lang,entries));};const recover=err=>{err.lang=lang;this.emit('fetcherror',err);cache.set(id,err);};const langToFetch=lang.src==='pseudo'?{code:'en-US',src:'app',ver:lang.ver}:lang;const resource=this.fetchResource(res,langToFetch).then(saveEntries,recover);cache.set(id,resource);return resource;}}]);return Env;})();function amendError(lang,err){err.lang=lang;return err;}
function prioritizeLocales(def,availableLangs,requested){let supportedLocale;for(let i=0;i<requested.length;i++){const locale=requested[i];if(availableLangs.indexOf(locale)!==-1){supportedLocale=locale;break;}}
if(!supportedLocale||supportedLocale===def){return[def];}
return[supportedLocale,def];}
function negotiateLanguages({appVersion,defaultLang,availableLangs},additionalLangs,prevLangs,requestedLangs){const allAvailableLangs=Object.keys(availableLangs).concat(Object.keys(additionalLangs)).concat(Object.keys(pseudo));const newLangs=prioritizeLocales(defaultLang,allAvailableLangs,requestedLangs);const langs=newLangs.map(code=>({code:code,src:getLangSource(appVersion,availableLangs,additionalLangs,code),ver:appVersion}));return{langs,haveChanged:!arrEqual(prevLangs,newLangs)};}
function arrEqual(arr1,arr2){return arr1.length===arr2.length&&arr1.every((elem,i)=>elem===arr2[i]);}
function getMatchingLangpack(appVersion,langpacks){for(let i=0,langpack;langpack=langpacks[i];i++){if(langpack.target===appVersion){return langpack;}}
return null;}
function getLangSource(appVersion,availableLangs,additionalLangs,code){if(additionalLangs&&additionalLangs[code]){const lp=getMatchingLangpack(appVersion,additionalLangs[code]);if(lp&&(!(code in availableLangs)||parseInt(lp.revision)>availableLangs[code])){return'extra';}}
if(code in pseudo&&!(code in availableLangs)){return'pseudo';}
return'app';}
let Remote=(function(){function Remote(fetchResource,broadcast){_classCallCheck(this,Remote);this.broadcast=broadcast;this.env=new Env(fetchResource);this.ctxs=new Map();}
_createClass(Remote,[{key:'registerView',value:function registerView(view,resources,meta,additionalLangs,requestedLangs){const{langs}=negotiateLanguages(meta,additionalLangs,[],requestedLangs);this.ctxs.set(view,this.env.createContext(langs,resources));return langs;}},{key:'unregisterView',value:function unregisterView(view){this.ctxs.delete(view);return true;}},{key:'formatEntities',value:function formatEntities(view,keys){return this.ctxs.get(view).formatEntities(...keys);}},{key:'formatValues',value:function formatValues(view,keys){return this.ctxs.get(view).formatValues(...keys);}},{key:'changeLanguages',value:function changeLanguages(view,meta,additionalLangs,requestedLangs){const oldCtx=this.ctxs.get(view);const prevLangs=oldCtx.langs;const newLangs=negotiateLanguages(meta,additionalLangs,prevLangs,requestedLangs);this.ctxs.set(view,this.env.createContext(newLangs.langs,oldCtx.resIds));return newLangs;}},{key:'requestLanguages',value:function requestLanguages(requestedLangs){this.broadcast('languageschangerequest',requestedLangs);}},{key:'getName',value:function getName(code){return pseudo[code].name;}},{key:'processString',value:function processString(code,str){return pseudo[code].process(str);}}]);return Remote;})();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 remote=new Remote(fetchResource,broadcast);const client=new Client(remote);document.l10n=new View(client,document);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();})};})();

View file

@ -0,0 +1,11 @@
;'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();}());

View file

@ -0,0 +1,554 @@
/* exported cropResizeRotate */
/* global getImageSize, LazyLoader, JPEGParser */
/* global Downsample */
//
// Given a blob that represents an encoded image, decode the image, crop it,
// rotate it, resize it, encode it again and pass the encoded blob to the
// callback.
//
// If the image includes EXIF orientation information, it will be
// rotated and/or mirrored so that the proper side is up and EXIF
// orientation information will not be needed in the output blob. The
// blob will not include any EXIF data.
//
// The cropRegion argument is optional. If specfied, it should be an
// object with left, top, width and height properties that specify the
// region of interest in the image. These coordinates should be
// specified as if the image has already been rotated and mirrored. If
// this argument is not specified, then no cropping is done and the
// entire image is returned.
//
// The outputSize argument specifies the desired size of the output
// image. If not specified, then the image is returned full-size. If
// this argument is specified, then it should be an object with width
// and height properties or a single number. If outputSize is an
// object, then the returned image will have the specified size or
// smaller. If the aspect ratio of the output size does not match the
// aspect ratio of the original image or of the crop region, then the
// largest area of the input region that fits the output size without
// letterboxing will be used. If the output size is larger than the
// crop region, then the output size is reduced to match the crop
// region.
//
// If outputSize is a number, then the #-moz-samplesize media fragment
// will be used, if necessary, to ensure that the input image is
// decoded at the specified size or smaller. Note that this media
// fragment gives only coarse control over image size, so passing a
// number for this argument can result in the image being decoded at a
// size substantially smaller than the specified value. If outputSize
// is a number and a crop region is specified, the image may be
// downsampled and then cropped, further reducing the size of the
// resulting image.
//
// The outputType argument specifies the type of the output
// image. Legal values are "image/jpeg", "image/jpeg+exif" and
// "image/png". If not specified, and if the input image does not need
// to be cropped resized or rotated, then it will be returned
// unchanged regardless of the type. If no output type is specified
// and a new blob needs to be created then "image/jpeg" will be
// used. If a type is explicitly specified, and does not match the
// type of the input image, then a new blob will be created even if no
// other changes to the image are necessary. "image/jpeg+exif" is what
// you want if you need to have the Exif in the updated copy.
//
// The optional metadata argument provides a way to pass in image size and
// rotation metadata if you already have it. If this argument is omitted
// or null, getImageSize() will be used to compute the metadata. But if you
// have already called getImageSize() on the blob, you can provide the
// metadata you have and avoid having to reparse the blob.
//
// The callback argument should be a function that expects two arguments.
// If the image is successfully processed, the first argument will be null
// and the second will be a blob. If there was an error, the first argument
// will be an error message and the second argument will be undefined.
//
// If no cropRegion and no outputSize are specified, if the type of the
// input blob matches the requested outputType, and if the image does not
// require any rotation, then this function will not do any work and will
// simply pass the input blob to the callback.
//
// This function requires other shared JS files:
//
// shared/js/blobview.js
// shared/js/media/image_size.js
// shared/js/media/jpeg_metadata_parser.js
// shared/js/media/downsample.js
// shared/js/media/jpeg-exif.js (with LazyLoader)
//
function cropResizeRotate(blob, cropRegion, outputSize, outputType,
metadata, callback)
{
'use strict';
const JPEG = 'image/jpeg';
const PNG = 'image/png';
const EXIF = 'image/jpeg+exif';
// The 2nd, 3rd, 4th and 5th arguments are optional, so fix things up if we're
// called with fewer than 6 args. The last argument is always the callback.
switch (arguments.length) {
case 2:
callback = cropRegion;
cropRegion = outputSize = outputType = metadata = null;
break;
case 3:
callback = outputSize;
outputSize = outputType = metadata = null;
break;
case 4:
callback = outputType;
outputType = metadata = null;
break;
case 5:
callback = metadata;
metadata = null;
break;
case 6:
// everything fine. do nothing here
break;
default:
throw new Error('wrong number of arguments: ' + arguments.length);
}
if (cropRegion) { // make a private copy
cropRegion = {
left: cropRegion.left,
top: cropRegion.top,
width: cropRegion.width,
height: cropRegion.height
};
}
if (outputSize && typeof outputSize === 'object') { // make a private copy
outputSize = {
width: outputSize.width,
height: outputSize.height
};
}
// If we were passed a metadata object, pass it to gotSize. Otherwise,
// find the metadata object first and then pass it.
if (metadata) {
gotSize(metadata);
}
else {
getImageSize(blob, gotSize, function(msg) { callback(msg); });
}
function gotSize(metadata) {
// This is the full size of the image in the input coordiate system
var rawImageWidth = metadata.width;
var rawImageHeight = metadata.height;
var fullsize = rawImageWidth * rawImageHeight;
var rotation = metadata.rotation || 0;
var mirrored = metadata.mirrored || false;
// Compute the full size of the image in the output coordinate system
// I.e. if the image is sideways, swap the width and height
var rotatedImageWidth, rotatedImageHeight;
if (rotation === 0 || rotation === 180) {
rotatedImageWidth = rawImageWidth;
rotatedImageHeight = rawImageHeight;
}
else {
rotatedImageWidth = rawImageHeight;
rotatedImageHeight = rawImageWidth;
}
// If there is no crop region, use the full, rotated image.
// If there is a crop region, make sure it fits inside the image.
if (!cropRegion) {
cropRegion = {
left: 0,
top: 0,
width: rotatedImageWidth,
height: rotatedImageHeight
};
}
else {
if (cropRegion.left < 0 || cropRegion.top < 0 ||
(cropRegion.left + cropRegion.width > rotatedImageWidth) ||
(cropRegion.top + cropRegion.height > rotatedImageHeight)) {
callback('crop region does not fit inside image');
return;
}
}
// If there is no output size, use the size of the crop region.
// If there is an output size make sure it is smaller than the crop region
// and then adjust the crop region as needed so that the aspect ratios
// match
if (outputSize === null || outputSize === undefined) {
outputSize = {
width: cropRegion.width,
height: cropRegion.height
};
}
else if (typeof outputSize === 'number') {
if (outputSize <= 0) {
callback('outputSize must be positive');
return;
}
if (fullsize < outputSize) {
// If the full size of the image is less than the image decode size
// limit, then we can decode the image at full size and use the full
// crop region dimensions as the output size.
outputSize = {
width: cropRegion.width,
height: cropRegion.height
};
}
else {
// In this case we need to specify an output size that is small
// enough that we will be forced below to use #-moz-samplesize
// to downsample the image while decoding it.
// Note that we base this samplesize computation on the full size
// of the image, because we have to decode the entire thing even
// if we are later going to crop it.
var ds = Downsample.areaAtLeast(outputSize / fullsize);
// Now that we've figured out how much the full image will be
// downsampled, scale the crop region to match.
outputSize = {
width: ds.scale(cropRegion.width),
height: ds.scale(cropRegion.height)
};
}
}
if (!(outputSize.width > 0 && outputSize.height > 0)) {
callback('outputSize width and height must be positive');
return;
}
// If the outputSize is bigger than the crop region, just adjust
// the output size to match.
if (outputSize.width > cropRegion.width) {
outputSize.width = cropRegion.width;
}
if (outputSize.height > cropRegion.height) {
outputSize.height = cropRegion.height;
}
// How much do we have to scale the crop region in X and Y dimensions
// to match the output size?
var scaleX = outputSize.width / cropRegion.width;
var scaleY = outputSize.height / cropRegion.height;
// We now adjust the crop region to match the output size. For
// example if the outputSize is 200x200 and the cropRegion is
// 600x400, then scaleX is .33 and scaleY is .5. In this case we can
// leave the height of the crop region alone, but we need to reduce
// the width of the crop region and adjust the left of the crop region
if (scaleY > scaleX) { // adjust width of crop region
var oldCropWidth = cropRegion.width;
cropRegion.width = Math.round(outputSize.width / scaleY);
cropRegion.left += (oldCropWidth - cropRegion.width) >> 1;
}
else if (scaleX > scaleY) { // adjust height of crop region
var oldCropHeight = cropRegion.height;
cropRegion.height = Math.round(outputSize.height / scaleX);
cropRegion.top += (oldCropHeight - cropRegion.height) >> 1;
}
// Make sure the outputType is valid, if one was specified
if (outputType && outputType !== JPEG &&
outputType !== PNG && outputType !== EXIF) {
callback('unsupported outputType: ' + outputType);
return;
}
var preserveExif = false;
if (blob.type === JPEG && outputType === EXIF) {
preserveExif = true;
outputType = JPEG;
}
// Now that we've done these computations, we can pause for a moment
// to see if there is actually any work that needs doing here. If not
// we can just pass the input blob unchanged through to the callback
if (rotation === 0 && // No need to rotate
!mirrored && // or to mirror the image.
(!outputType || // Don't care about output type
blob.type === outputType) && // or type is unchanged.
outputSize.width === rawImageWidth && // Doesn't need crop or resize.
outputSize.height == rawImageHeight) {
callback(null, blob);
return;
}
// The crop region we've been working with so far is in the output
// coordinate system: it assumes that any required rotation has been done.
// In order to know exactly which pixels to extract from the image we
// need to convert to the unrotated, unmirrored input coordinate system.
var inputCropRegion;
// First, handle rotation
switch (rotation) {
case 180:
// The image is upside down. The width and height are the same but
// the top and left have to change.
inputCropRegion = {
left: rawImageWidth - cropRegion.left - cropRegion.width,
top: rawImageHeight - cropRegion.top - cropRegion.height,
width: cropRegion.width,
height: cropRegion.height
};
break;
case 90:
// sideways: swap width and height and adjust top and left
inputCropRegion = {
left: cropRegion.top,
top: rawImageHeight - cropRegion.left - cropRegion.width,
width: cropRegion.height,
height: cropRegion.width
};
break;
case 270:
// sideways: swap width and height and adjust top and left
inputCropRegion = {
left: rawImageWidth - cropRegion.top - cropRegion.height,
top: cropRegion.left,
width: cropRegion.height,
height: cropRegion.width
};
break;
default:
// the crop region is the same in this case
inputCropRegion = {
left: cropRegion.left,
top: cropRegion.top,
width: cropRegion.width,
height: cropRegion.height
};
break;
}
// Next, adjust for mirroring
if (mirrored) {
if (rotation === 90 || rotation === 270) {
inputCropRegion.top =
rawImageHeight - inputCropRegion.top - inputCropRegion.height;
}
else {
inputCropRegion.left =
rawImageWidth - inputCropRegion.left - inputCropRegion.width;
}
}
// In order to decode the image, we create a blob:// URL for it
var baseURL = URL.createObjectURL(blob);
// Decoding an image takes a lot of memory and we want to minimize that.
// Gecko allows us to use media fragments with our image URL to specify
// that we do not want it to decode all of the pixels in the image. The
// #-moz-samplesize= fragment allows us to specify that JPEG images
// should be downsampled while being decoded, and this can save a lot of
// memory.
var sampledsize;
var downsample;
// If we decode the image with a #-moz-samplesize media fragment, both
// the x and y dimensions are reduced by the sample size, so the total
// number of pixels is reduced by the square of the sample size.
if (blob.type === JPEG) {
// What media fragment can we use to downsample the crop region
// so that it is as small as possible without being smaller than
// the output size? We know that the output size and crop
// region have the same aspect ratio now, so we only have to
// consider one dimension. If we passed in a single number outputSize
// up above then we Downsample.areaAtLeast() to compute the outputSize.
// We should now get the same media fragment value here.
downsample =
Downsample.sizeNoMoreThan(outputSize.width / cropRegion.width);
// And if apply that media fragment to the entire image, how big is
// the result?
sampledsize = downsample.scale(rawImageWidth) *
downsample.scale(rawImageHeight);
}
else {
downsample = Downsample.NONE;
sampledsize = fullsize;
}
// Now add the appropriate media fragments to the url
var url;
var resizedWithMediaFragment = false;
if (sampledsize < fullsize) {
// Use a #-moz-samplesize media fragment to downsample while decoding
url = baseURL + downsample;
resizedWithMediaFragment = true;
}
else {
// No media fragments in this case
url = baseURL;
}
// Now we've done our calculations and we have an image URL to decode
var offscreenImage = new Image();
offscreenImage.src = url;
offscreenImage.onerror = function() {
callback('error decoding image: ' + url);
};
offscreenImage.onload = gotImage;
// Called when the image has loaded
function gotImage() {
// If we used a #-moz-samplesize media fragment on the image url,
// and we got an image that is smaller than full-size, then we
// need to reduce the crop region proportionally.
if (resizedWithMediaFragment) {
if (offscreenImage.width < rawImageWidth ||
offscreenImage.height < rawImageHeight) {
var sampleSizeX = rawImageWidth / offscreenImage.width;
var sampleSizeY = rawImageHeight / offscreenImage.height;
inputCropRegion.left =
Math.round(inputCropRegion.left / sampleSizeX);
inputCropRegion.top =
Math.round(inputCropRegion.top / sampleSizeY);
inputCropRegion.width =
Math.round(inputCropRegion.width / sampleSizeX);
inputCropRegion.height =
Math.round(inputCropRegion.height / sampleSizeY);
}
}
// We've decoded the image now, so create a canvas we can copy it into
var canvas = document.createElement('canvas');
var destWidth = canvas.width = outputSize.width;
var destHeight = canvas.height = outputSize.height;
// Since we're only using the canvas as a way to encode the image
// we set this willReadFrequently flag as a hint so that we avoid
// copying the image data to and from the GPU since we don't do any
// GPU operations on it
var context = canvas.getContext('2d', { willReadFrequently: true });
// If the image needs to be rotated or mirrored we have to establish
// an appropriate transform on the context
if (rotation || mirrored) {
// translate so we're rotating around the center
context.translate(canvas.width / 2, canvas.height / 2);
if (mirrored) {
context.scale(-1, 1);
}
// rotate
switch (rotation) {
case 90:
context.rotate(Math.PI / 2);
destWidth = canvas.height;
destHeight = canvas.width;
break;
case 180:
context.rotate(Math.PI);
break;
case 270:
context.rotate(-Math.PI / 2);
destWidth = canvas.height;
destHeight = canvas.width;
break;
}
// And translate back
if (rotation === 90 || rotation === 270) {
// For the 90 and 270 case we swap width and height
context.translate(-canvas.height / 2, -canvas.width / 2);
}
else {
context.translate(-canvas.width / 2, -canvas.height / 2);
}
}
try {
// Now we copy the image into the canvas.
// The image has been loaded, but not decoded yet. If the image file
// appears to be valid and has valid width and height metadata, then
// the onload event handler will fire. But if the image is corrupt
// or too big for gecko to decode with the amount of available
// memory, then this drawImage() call can fail with an exception.
context.drawImage(offscreenImage,
// What part of the image we're drawing
inputCropRegion.left, inputCropRegion.top,
inputCropRegion.width, inputCropRegion.height,
// And what part of the canvas we're drawing it to
0, 0, destWidth, destHeight);
}
catch(e) {
callback('Failed to decode image in cropResizeRotate; ' +
'image may be corrupt or too large: ' + e);
return;
}
finally {
// Once the image has been copied, we can release the decoded image
// memory and the blob URL.
offscreenImage.onload = offscreenImage.onerror = null; offscreenImage.removeAttribute('src');
URL.revokeObjectURL(baseURL);
}
var inputBlob = blob; // XXX just use a different parameter name
// Finally, encode the image into a blob
var postCallback = preserveExif ? copyMetadata : gotEncodedBlob;
canvas.toBlob(postCallback, outputType || JPEG);
function copyMetadata(outputBlob) {
try {
LazyLoader.load(['shared/js/media/jpeg-exif.js'], () => {
JPEGParser.readExifMetaData(inputBlob, (error, metaData) => {
if (error || !metaData) {
gotEncodedBlob(outputBlob);
return;
}
metaData.Orientation = 1;
if (metaData.PixelXDimension) {
metaData.PixelXDimension = outputSize.width;
}
if (metaData.PixelYDimension) {
metaData.PixelYDimension = outputSize.height;
}
JPEGParser.writeExifMetaData(
outputBlob,
metaData,
(error, modifiedBlob) => {
if (error) {
console.error('Error' + error);
}
// Process modified file
gotEncodedBlob(modifiedBlob);
});
});
});
}
catch(e) {
console.log(e.stack);
}
}
function gotEncodedBlob(blob) {
// We have the encoded image but before we pass it to the callback
// we need to free the canvas.
canvas.width = canvas.height = 0;
canvas = context = null;
callback(null, blob);
}
}
}
}

View file

@ -0,0 +1,11 @@
;;(function(exports){'use strict';function round(x){return Math.round(x*100)/100;}
function MozSampleSize(n,scale){return Object.freeze({dimensionScale:round(scale),areaScale:round(scale*scale),toString:function(){return'#-moz-samplesize='+n;},scale:function(x){return Math.ceil(x*scale);}});}
var NONE=Object.freeze({dimensionScale:1,areaScale:1,toString:function(){return'';},scale:function(x){return x;}});var fragments=[NONE,MozSampleSize(2,1/2),MozSampleSize(3,3/8),MozSampleSize(4,1/4),MozSampleSize(8,1/8)];function sizeAtLeast(scale){scale=round(scale);for(var i=0;i<fragments.length;i++){var f=fragments[i];if(f.dimensionScale<=scale){return f;}}
return fragments[fragments.length-1];}
function sizeNoMoreThan(scale){scale=round(scale);for(var i=fragments.length-1;i>=0;i--){var f=fragments[i];if(f.dimensionScale>=scale){return f;}}
return NONE;}
function areaAtLeast(scale){scale=round(scale);for(var i=0;i<fragments.length;i++){var f=fragments[i];if(f.areaScale<=scale){return f;}}
return fragments[fragments.length-1];}
function areaNoMoreThan(scale){scale=round(scale);for(var i=fragments.length-1;i>=0;i--){var f=fragments[i];if(f.areaScale>=scale){return f;}}
return NONE;}
exports.Downsample={sizeAtLeast:sizeAtLeast,sizeNoMoreThan:sizeNoMoreThan,areaAtLeast:areaAtLeast,areaNoMoreThan:areaNoMoreThan,NONE:NONE,MAX_SIZE_REDUCTION:1/fragments[fragments.length-1].dimensionScale,MAX_AREA_REDUCTION:1/fragments[fragments.length-1].areaScale};}(window));

View file

@ -0,0 +1,13 @@
;function getImageSize(blob,callback,error){'use strict';BlobView.get(blob,0,Math.min(1024,blob.size),function(data){if(data.byteLength<=8){error('corrupt image file');return;}
var magic=data.getBinaryText(0,8);if(magic.substring(0,4)==='GIF8'){try{callback({type:'gif',width:data.getUint16(6,true),height:data.getUint16(8,true)});}
catch(e){error(e.toString());}}
else if(magic.substring(0,8)==='\x89PNG\r\n\x1A\n'){try{callback({type:'png',width:data.getUint32(16,false),height:data.getUint32(20,false)});}
catch(e){error(e.toString());}}
else if(magic.substring(0,2)==='BM'&&data.getUint32(2,true)===blob.size){try{var width,height;if(data.getUint16(14,true)===12){width=data.getUint16(18,true);height=data.getUint16(20,true);}
else{width=data.getUint32(18,true);height=data.getUint32(22,true);}
callback({type:'bmp',width:width,height:height});}
catch(e){error(e.toString());}}
else if(magic.substring(0,2)==='\xFF\xD8'){parseJPEGMetadata(blob,function(metadata){if(metadata.progressive){delete metadata.progressive;metadata.type='pjpeg';}
else{metadata.type='jpeg';}
callback(metadata);},error);}
else{error('unknown image type');}});}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,25 @@
;'use strict';function parseJPEGMetadata(file,metadataCallback,metadataError){var metadata={};var TIFFHeaderOffset=0;BlobView.get(file,0,Math.min(16*1024,file.size),function(data){if(data.byteLength<2||data.getUint8(0)!==0xFF||data.getUint8(1)!==0xD8){metadataError('Not a JPEG file');return;}
getSegment(data,2,segmentHandler);});function getSegment(data,offset,callback){try{var header=data.getUint8(offset);if(header!==0xFF){metadataError('Malformed JPEG file: bad segment header');return;}
var type=data.getUint8(offset+1);var size=data.getUint16(offset+2)+2;var start=data.sliceOffset+data.viewOffset+offset;var isLast=(start+size>=file.size);var length=isLast?size:size+4;data.getMore(start,length,function(data){callback(type,size,data,isLast);});}
catch(e){metadataError(e.toString()+'\n'+e.stack);}}
function segmentHandler(type,size,data,isLastSegment){try{switch(type){case 0xC0:case 0xC1:case 0xC2:case 0xC3:metadata.height=data.getUint16(5);metadata.width=data.getUint16(7);if(type===0xC2){metadata.progressive=true;}
metadataCallback(metadata);break;case 0xE1:parseAPP1(data);default:if(isLastSegment){metadataError('unexpected end of JPEG file');return;}
getSegment(data,size,segmentHandler);}}
catch(e){metadataError(e.toString()+'\n'+e.stack);}}
function parseAPP1(data){if(data.getUint32(4,false)===0x45786966){var exif=parseEXIFData(data);if(exif.THUMBNAIL&&exif.THUMBNAILLENGTH){var start=data.sliceOffset+data.viewOffset+TIFFHeaderOffset+
exif.THUMBNAIL;metadata.preview={start:start,end:start+exif.THUMBNAILLENGTH};}
switch(exif.ORIENTATION){case 2:metadata.rotation=0;metadata.mirrored=true;break;case 3:metadata.rotation=180;metadata.mirrored=false;break;case 4:metadata.rotation=180;metadata.mirrored=true;break;case 5:metadata.rotation=90;metadata.mirrored=true;break;case 6:metadata.rotation=90;metadata.mirrored=false;break;case 7:metadata.rotation=270;metadata.mirrored=true;break;case 8:metadata.rotation=270;metadata.mirrored=false;break;default:metadata.rotation=0;metadata.mirrored=false;break;}}}
function parseEXIFData(data){var exif={};var byteorder=data.getUint8(10);if(byteorder===0x4D){byteorder=false;}else if(byteorder===0x49){byteorder=true;}else{throw Error('invalid byteorder in EXIF segment');}
TIFFHeaderOffset=10;if(data.getUint16(12,byteorder)!==42){throw Error('bad magic number in EXIF segment');}
var offset=data.getUint32(14,byteorder);parseIFD(data,offset+TIFFHeaderOffset,byteorder,exif,true);var ifd0entries=data.getUint16(offset+TIFFHeaderOffset,byteorder);var ifd1=data.getUint32(offset+12+12*ifd0entries,byteorder);if(ifd1!==0){parseIFD(data,ifd1+TIFFHeaderOffset,byteorder,exif,true);}
return exif;}
function parseIFD(data,offset,byteorder,exif,onlyParseOne){var numentries=data.getUint16(offset,byteorder);for(var i=0;i<numentries;i++){parseEntry(data,offset+2+12*i,byteorder,exif);}
if(onlyParseOne){return;}
var next=data.getUint32(offset+2+12*numentries,byteorder);if(next!==0&&next<file.size){parseIFD(data,next+TIFFHeaderOffset,byteorder,exif);}}
var typesize=[0,1,1,2,4,8,1,1,2,4,8,4,8];var tagnames={'274':'ORIENTATION','513':'THUMBNAIL','514':'THUMBNAILLENGTH'};function parseEntry(data,offset,byteorder,exif){var tag=data.getUint16(offset,byteorder);var tagname=tagnames[tag];if(!tagname||exif[tagname]){return;}
var type=data.getUint16(offset+2,byteorder);var count=data.getUint32(offset+4,byteorder);var total=count*typesize[type];var valueOffset=total<=4?offset+8:data.getUint32(offset+8,byteorder)+TIFFHeaderOffset;exif[tagname]=parseValue(data,valueOffset,type,count,byteorder);}
function parseValue(data,offset,type,count,byteorder){var i;if(type===2){var codes=[];for(i=0;i<count-1;i++){codes[i]=data.getUint8(offset+i);}
return String.fromCharCode.apply(String,codes);}else{if(count==1){return parseOneValue(data,offset,type,byteorder);}else{var values=[];var size=typesize[type];for(i=0;i<count;i++){values[i]=parseOneValue(data,offset+size*i,type,byteorder);}
return values;}}}
function parseOneValue(data,offset,type,byteorder){switch(type){case 1:case 7:return data.getUint8(offset);case 2:return null;case 3:return data.getUint16(offset,byteorder);case 4:return data.getUint32(offset,byteorder);case 5:return data.getUint32(offset,byteorder)/data.getUint32(offset+4,byteorder);case 6:return data.getInt8(offset);case 8:return data.getInt16(offset,byteorder);case 9:return data.getInt32(offset,byteorder);case 10:return data.getInt32(offset,byteorder)/data.getInt32(offset+4,byteorder);case 11:return data.getFloat32(offset,byteorder);case 12:return data.getFloat64(offset,byteorder);}
return null;}}

View file

@ -0,0 +1,72 @@
;'use strict';function MediaFrame(container,includeVideo,maxImageSize){this.clear();if(typeof container==='string'){container=document.getElementById(container);}
this.container=container;this.maximumImageSize=maxImageSize||0;this.image=new Image();this.image.className='image-view';this.image.style.opacity=0;this.image.onload=function(){this.style.opacity=1;};this.image.style.transformOrigin='center center';this.image.style.backgroundImage='none';this.image.style.backgroundSize='contain';this.image.style.backgroundRepeat='no-repeat';this.image.style.backgroundColor='#222';this.container.appendChild(this.image);if(includeVideo!==false){this.video=new VideoPlayer(container);this.video.hide();}
container.classList.add('media-frame-container');MediaFrame.instancesToLocalize.set(container,this);}
MediaFrame.instancesToLocalize=new WeakMap();function localize(){for(var container of document.querySelectorAll('.media-frame-container')){var instance=MediaFrame.instancesToLocalize.get(container);if(instance){instance.localize();}}}
document.addEventListener('DOMRetranslated',localize);MediaFrame.computeMaxImageDecodeSize=function(mem){if(!mem){return 0;}
else if(mem<256){return 2*1024*1024;}
else if(mem<512){var screensize=screen.width*window.devicePixelRatio*screen.height*window.devicePixelRatio;if(mem<325&&screensize>480*800){return 2.5*1024*1024;}
return 3*1024*1024;}
else if(mem<1024){return 5*1024*1024;}
else{return(mem/1024)*10*1024*1024;}};if(navigator.getFeature){MediaFrame.pendingPromise=navigator.getFeature('hardware.memory');MediaFrame.pendingPromise.then(function resolve(mem){delete MediaFrame.pendingPromise;MediaFrame.maxImageDecodeSize=MediaFrame.computeMaxImageDecodeSize(mem);},function reject(err){delete MediaFrame.pendingPromise;MediaFrame.maxImageDecodeSize=0;});}
MediaFrame.prototype.displayImage=function displayImage(blob,width,height,preview,rotation,mirrored)
{var self=this;if(MediaFrame.pendingPromise){MediaFrame.pendingPromise.then(function resolve(){self.displayImage(blob,width,height,preview,rotation,mirrored);});return;}
this.clear();this.imageblob=blob;this.fullSampleSize=computeFullSampleSize(blob,width,height);this.fullsizeWidth=this.fullSampleSize.scale(width);this.fullsizeHeight=this.fullSampleSize.scale(height);this.tinyPreviewURL=null;this.imageurl=URL.createObjectURL(blob);this.fullImageURL=this.imageurl+this.fullSampleSize;this.rotation=rotation||0;this.mirrored=mirrored||false;this.displayingImage=true;this.localize();function isValidPreview(preview){if(!preview){return false;}
if(!preview.width||!preview.height){return false;}
if(!preview.start&&!preview.filename){return false;}
if(Math.abs(width/height-preview.width/preview.height)>0.01){return false;}
return true;}
function isBigEnoughPreview(preview){if(!preview){return false;}
if(self.minimumPreviewWidth&&self.minimumPreviewHeight){return Math.max(preview.width,preview.height)>=Math.max(self.minimumPreviewWidth,self.minimumPreviewHeight)&&Math.min(preview.width,preview.height)>=Math.min(self.minimumPreviewWidth,self.minimumPreviewHeight);}
var screenWidth=window.innerWidth*window.devicePixelRatio;var screenHeight=window.innerHeight*window.devicePixelRatio;return((preview.width>=screenWidth||preview.height>=screenHeight)&&(preview.width>=screenHeight||preview.height>=screenWidth));}
var isValid=isValidPreview(preview);var isBigEnough=isBigEnoughPreview(preview);if(isValid&&isBigEnough){if(preview.start){gotPreview(blob.slice(preview.start,preview.end,'image/jpeg'),preview.width,preview.height);}
else{var storage=navigator.getDeviceStorage('pictures');var getreq=storage.get(preview.filename);getreq.onsuccess=function(){gotPreview(getreq.result,preview.width,preview.height);};getreq.onerror=function(){noPreview();};}}
else if(isValid){this.tinyPreviewURL=URL.createObjectURL(blob.slice(preview.start,preview.end,'image/jpeg'));noPreview(this.tinyPreviewURL);}
else{noPreview();}
function gotPreview(previewblob,previewWidth,previewHeight){self.previewurl=URL.createObjectURL(previewblob);self.previewImageURL=self.previewurl;self.previewWidth=previewWidth;self.previewHeight=previewHeight;self.displayingPreview=true;self._displayImage(self.previewImageURL,self.previewWidth,self.previewHeight);}
function noPreview(bgURL){self.previewurl=null;var previewSampleSize=computePreviewSampleSize(blob,width,height);if(previewSampleSize!==Downsample.NONE){self.previewImageURL=self.imageurl+previewSampleSize;self.previewWidth=previewSampleSize.scale(width);self.previewHeight=previewSampleSize.scale(height);self.displayingPreview=true;self._displayImage(self.previewImageURL,self.previewWidth,self.previewHeight,bgURL);}
else{self.previewImageURL=null;self.displayingPreview=false;self._displayImage(self.fullImageURL,self.fullsizeWidth,self.fullsizeHeight);}}
function computeFullSampleSize(blob,width,height){if(blob.type!=='image/jpeg'){return Downsample.NONE;}
var max=MediaFrame.maxImageDecodeSize||0;if(self.maximumImageSize&&(max===0||self.maximumImageSize<max)){max=self.maximumImageSize;}
if(!max||width*height<=max){return Downsample.NONE;}
return Downsample.areaAtLeast(max/(width*height));}
function computePreviewSampleSize(blob,width,height){if(blob.type!=='image/jpeg'){return Downsample.NONE;}
var screenWidth=window.innerWidth*window.devicePixelRatio;var screenHeight=window.innerHeight*window.devicePixelRatio;var portraitScale=Math.min(screenWidth/width,screenHeight/height);var landscapeScale=Math.min(screenHeight/width,screenWidth/height);var scale=Math.max(portraitScale,landscapeScale);return Downsample.sizeNoMoreThan(scale);}};MediaFrame.prototype._displayImage=function(url,width,height,bg){this.image.style.width=width+'px';this.image.style.height=height+'px';if(bg){this.image.style.backgroundImage='url('+bg+')';requestAnimationFrame(()=>{this.image.src=url;});}
else{this.image.style.backgroundImage='none';this.image.src=url;}
if(this.rotation===0||this.rotation===180){this.itemWidth=width;this.itemHeight=height;}else{this.itemWidth=height;this.itemHeight=width;}
this.computeFit();this.setPosition();var temp=this.image.clientLeft;};MediaFrame.prototype.localize=function localize(){if(!this.displayingImage){return;}
var portrait=this.fullsizeWidth<this.fullsizeHeight;if(this.rotation==90||this.rotation==270){portrait=!portrait;}
var timestamp=this.imageblob.lastModifiedDate;var orientationL10nId=portrait?'orientationPortrait':'orientationLandscape';document.l10n.formatValue(orientationL10nId).then((orientationText)=>{if(timestamp){if(!this.dtf){this.dtf=Intl.DateTimeFormat(navigator.languages,{hour12:navigator.mozHour12,hour:'numeric',minute:'numeric',day:'numeric',month:'numeric',year:'numeric'});}
var ts=this.dtf.format(new Date(timestamp));document.l10n.setAttributes(this.image,'imageDescription',{orientation:orientationText,timestamp:ts});}else{document.l10n.setAttributes(this.image,'imageDescriptionNoTimestamp',{orientation:orientationText});}});};MediaFrame.prototype._switchToFullSizeImage=function _switchToFull(){if(!this.displayingImage||!this.displayingPreview){return;}
this.displayingPreview=false;this._displayImage(this.fullImageURL,this.fullsizeWidth,this.fullsizeHeight,this.previewImageURL);};MediaFrame.prototype._switchToPreviewImage=function _switchToPreview(){if(!this.displayingImage||this.displayingPreview||!this.previewImageURL){return;}
this.displayingPreview=true;this._displayImage(this.previewImageURL,this.previewWidth,this.previewHeight);};MediaFrame.prototype.displayVideo=function displayVideo(videoblob,posterblob,aspectRatio,rotation)
{if(!this.video){return;}
this.clear();this.displayingVideo=true;this.videoblob=videoblob;this.posterblob=posterblob;this.videourl=URL.createObjectURL(videoblob);this.posterurl=URL.createObjectURL(posterblob);this.video.load(this.videourl,this.posterurl,aspectRatio,rotation||0,videoblob.lastModifiedDate);this.video.show();};MediaFrame.prototype.clear=function clear(){this.displayingImage=false;this.displayingPreview=false;this.displayingVideo=false;this.itemWidth=this.itemHeight=null;this.imageblob=null;this.videoblob=null;this.posterblob=null;this.fullSampleSize=null;this.fullImageURL=null;this.previewImageURL=null;this.fullsizeWidth=this.fullsizeHeight=null;this.previewWidth=this.previewHeight=null;this.fit=null;if(this.imageurl){URL.revokeObjectURL(this.imageurl);}
this.imageurl=null;if(this.previewurl){URL.revokeObjectURL(this.previewurl);}
this.previewurl=null;if(this.tinyPreviewURL){URL.revokeObjectURL(this.tinyPreviewURL);}
this.tinyPreviewURL=null;if(this.image){this.image.style.opacity=0;this.image.style.backgroundImage='none';this.image.src='';this.image.removeAttribute('aria-label');}
if(this.video){this.video.reset();this.video.hide();if(this.videourl){URL.revokeObjectURL(this.videourl);}
this.videourl=null;if(this.posterurl){URL.revokeObjectURL(this.posterurl);}
this.posterurl=null;}};MediaFrame.prototype.setPosition=function setPosition(){if(!this.fit||!this.displayingImage){return;}
var dx=this.fit.left,dy=this.fit.top;switch(this.rotation){case 0:case 180:dx+=(this.fit.width-this.itemWidth)/2;dy+=(this.fit.height-this.itemHeight)/2;break;case 90:case 270:dx+=(this.fit.width-this.itemHeight)/2;dy+=(this.fit.height-this.itemWidth)/2;break;}
var sx=this.mirrored?-this.fit.scale:this.fit.scale;var sy=this.fit.scale;var transform='translate('+dx+'px, '+dy+'px) '+'scale('+sx+','+sy+')'+'rotate('+this.rotation+'deg) ';this.image.style.transform=transform;};MediaFrame.prototype.computeFit=function computeFit(){if(!this.displayingImage){return;}
this.viewportWidth=this.container.offsetWidth;this.viewportHeight=this.container.offsetHeight;var scalex=this.viewportWidth/this.itemWidth;var scaley=this.viewportHeight/this.itemHeight;var scale=Math.min(Math.min(scalex,scaley),1);var width=Math.floor(this.itemWidth*scale);var height=Math.floor(this.itemHeight*scale);this.fit={width:width,height:height,left:Math.floor((this.viewportWidth-width)/2),top:Math.floor((this.viewportHeight-height)/2),scale:scale,baseScale:scale};};MediaFrame.prototype.reset=function reset(){if(this.displayingImage&&!this.displayingPreview&&this.previewImageURL){this._switchToPreviewImage();return;}
this.computeFit();this.setPosition();if(this.displayingVideo){this.video.setPlayerSize();}};MediaFrame.prototype.resize=function resize(){var oldWidth=this.viewportWidth;var oldHeight=this.viewportHeight;var newWidth=this.container.offsetWidth;var newHeight=this.container.offsetHeight;var oldfit=this.fit;if(!oldfit){return;}
this.computeFit();var newfit=this.fit;if(Math.abs(oldfit.scale-oldfit.baseScale)<0.01||newfit.baseScale>oldfit.scale){this.reset();return;}
oldfit.left+=(newWidth-oldWidth)/2;oldfit.top+=(newHeight-oldHeight)/2;oldfit.baseScale=newfit.baseScale;this.fit=oldfit;this.setPosition();};MediaFrame.prototype.zoom=function zoom(scale,fixedX,fixedY,time){if(!this.displayingImage){return;}
if(this.displayingPreview){this._switchToFullSizeImage();}
if(this.fit.scale*scale>1){scale=1/(this.fit.scale);}
else if(this.fit.scale*scale<this.fit.baseScale){scale=this.fit.baseScale/this.fit.scale;}
this.fit.scale=this.fit.scale*scale;this.fit.width=Math.floor(this.itemWidth*this.fit.scale);this.fit.height=Math.floor(this.itemHeight*this.fit.scale);var photoX=fixedX-this.fit.left;var photoY=fixedY-this.fit.top;photoX=Math.floor(photoX*scale);photoY=Math.floor(photoY*scale);this.fit.left=fixedX-photoX;this.fit.top=fixedY-photoY;if(this.fit.width<=this.viewportWidth){this.fit.left=(this.viewportWidth-this.fit.width)/2;}
else{if(this.fit.left>0){this.fit.left=0;}
if(this.fit.left+this.fit.width<this.viewportWidth){this.fit.left=this.viewportWidth-this.fit.width;}}
if(this.fit.height<=this.viewportHeight){this.fit.top=(this.viewportHeight-this.fit.height)/2;}
else{if(this.fit.top>0){this.fit.top=0;}
if(this.fit.top+this.fit.height<this.viewportHeight){this.fit.top=this.viewportHeight-this.fit.height;}}
if(time){var transition='transform '+time+'ms ease';this.image.style.transition=transition;var self=this;this.image.addEventListener('transitionend',function done(){self.image.removeEventListener('transitionend',done);self.image.style.transition='';});}
this.setPosition();};MediaFrame.prototype.pan=function(dx,dy){if(!this.displayingImage){return dx;}
if(this.fit.height>this.viewportHeight){this.fit.top+=dy;if(this.fit.top>0){this.fit.top=0;}
if(this.fit.top+this.fit.height<this.viewportHeight){this.fit.top=this.viewportHeight-this.fit.height;}}
var extra=0;if(this.fit.width<=this.viewportWidth){extra=dx;}
else{this.fit.left+=dx;if(this.fit.left>0){extra=this.fit.left;this.fit.left=0;}
if(this.fit.left+this.fit.width<this.viewportWidth){extra=this.fit.left+this.fit.width-this.viewportWidth;this.fit.left=this.viewportWidth-this.fit.width;}}
this.setPosition();return extra;};MediaFrame.prototype.setMinimumPreviewSize=function(w,h){this.minimumPreviewWidth=w;this.minimumPreviewHeight=h;};

View file

@ -0,0 +1,11 @@
;'use strict';var MediaUtils={formatDate:function(timestamp){if(!timestamp||timestamp===undefined||isNaN(timestamp)){return;}
return new Date(timestamp).toLocaleString(navigator.languages,{'month':'numeric','year':'numeric','day':'numeric'});},getLocalizedSizeTokens:function(size){if(!size||size===undefined||isNaN(size)){return Promise.resolve('');}
var units=['B','KB','MB','GB','TB','PB','EB','ZB','YB'];var i=0;while(size>=1024&&i<(units.length-1)){size/=1024;++i;}
var sizeDecimal=i<2?Math.round(size):Math.round(size*10)/10;return document.l10n.formatValue('byteUnit-'+units[i]).then((unit)=>{return{size:sizeDecimal,unit};});},getLocalizedSize:function(size){return this.getLocalizedSizeTokens(size).then((args)=>{return document.l10n.formatValue('fileSize',args);});},formatDuration:function(duration){function padLeft(num,length){var r=String(num);while(r.length<length){r='0'+r;}
return r;}
duration=Math.round(duration);var minutes=Math.floor(duration/60);var seconds=duration%60;if(minutes<60){return padLeft(minutes,2)+':'+padLeft(seconds,2);}
var hours=Math.floor(minutes/60);minutes=Math.floor(minutes%60);return hours+':'+padLeft(minutes,2)+':'+padLeft(seconds,2);},populateMediaInfo:function(data){for(var id in data){if(data.hasOwnProperty(id)){var element=document.getElementById(id);if(element){if(typeof data[id]==='string'){element.setAttribute('data-l10n-id',data[id]);}else if(data[id].hasOwnProperty('raw')){element.removeAttribute('data-l10n-id');element.textContent=data[id].raw;}else{document.l10n.setAttributes(element,data[id].id,data[id].args);}}}}},binarySearch:function(array,element,comparator,from,to){if(comparator===undefined){comparator=function(a,b){return a-b;};}
if(from===undefined){return MediaUtils.binarySearch(array,element,comparator,0,array.length);}
if(from===to){return from;}
var mid=Math.floor((from+to)/2);var result=comparator(element,array[mid]);if(result<0){return MediaUtils.binarySearch(array,element,comparator,from,mid);}
else{return MediaUtils.binarySearch(array,element,comparator,mid+1,to);}}};

View file

@ -0,0 +1,148 @@
;'use strict';var MediaDB=(function(){function MediaDB(mediaType,metadataParser,options){this.mediaType=mediaType;this.metadataParser=metadataParser;if(!options){options={};}
this.indexes=options.indexes||[];this.version=options.version||1;this.mimeTypes=options.mimeTypes;this.autoscan=(options.autoscan!==undefined)?options.autoscan:true;this.state=MediaDB.OPENING;this.scanning=false;this.initialScanComplete=false;this.parsingBigFiles=false;this.updateRecord=options.updateRecord;this.reparsedRecord=options.reparsedRecord;if(options.excludeFilter&&(options.excludeFilter instanceof RegExp)){this.clientExcludeFilter=options.excludeFilter;}
this.batchHoldTime=options.batchHoldTime||100;this.batchSize=options.batchSize||0;this.dbname='MediaDB/'+this.mediaType+'/';var media=this;this.details={eventListeners:{},pendingInsertions:[],pendingDeletions:[],whenDoneProcessing:[],pendingCreateNotifications:[],pendingDeleteNotifications:[],pendingNotificationTimer:null,newestFileModTime:0};if(!this.metadataParser){this.metadataParser=function(file,callback){setTimeout(function(){callback({});},0);};}
var dbVersion=(0xFFFF&this.version)<<16|(0xFFFF&MediaDB.VERSION);var openRequest=indexedDB.open(this.dbname,dbVersion);openRequest.onerror=function(e){console.error('MediaDB():',openRequest.error.name);};openRequest.onblocked=function(e){console.error('indexedDB.open() is blocked in MediaDB()');};openRequest.onupgradeneeded=function(e){var db=openRequest.result;var transaction=e.target.transaction;var oldVersion=e.oldVersion;var oldDbVersion=0xFFFF&oldVersion;var oldClientVersion=0xFFFF&(oldVersion>>16);if(oldClientVersion===0){oldDbVersion=2;oldClientVersion=oldVersion/oldDbVersion;}
if(0===db.objectStoreNames.length){createObjectStores(db);}else{handleUpgrade(db,transaction,oldDbVersion,oldClientVersion);}};openRequest.onsuccess=function(e){media.db=openRequest.result;media.db.onerror=function(event){console.error('MediaDB: ',event.target.error&&event.target.error.name);};changeState(media,MediaDB.ENUMERABLE);var cursorRequest=media.db.transaction('files','readonly').objectStore('files').index('date').openCursor(null,'prev');cursorRequest.onerror=function(){console.error('MediaDB initialization error',cursorRequest.error);};cursorRequest.onsuccess=function(){var cursor=cursorRequest.result;if(cursor){media.details.newestFileModTime=cursor.value.date;}
else{media.details.newestFileModTime=0;}
initDeviceStorage();};};function createObjectStores(db){var filestore=db.createObjectStore('files',{keyPath:'name'});filestore.createIndex('date','date');media.indexes.forEach(function(indexName){if(indexName==='name'||indexName==='date'){return;}
filestore.createIndex(indexName,indexName);});}
function enumerateOldFiles(store,callback){var openCursorReq=store.openCursor();openCursorReq.onsuccess=function(){var cursor=openCursorReq.result;if(cursor){callback(cursor.value);cursor.continue();}};}
function handleUpgrade(db,trans,oldDbVersion,oldClientVersion){media.state=MediaDB.UPGRADING;var evtDetail={'oldMediaDBVersion':oldDbVersion,'oldClientVersion':oldClientVersion,'newMediaDBVersion':MediaDB.VERSION,'newClientVersion':media.version};dispatchEvent(media,'upgrading',evtDetail);var store=trans.objectStore('files');if(media.version!=oldClientVersion){upgradeIndexesChanges(store);}
var clientUpgradeNeeded=(media.version!=oldClientVersion)&&media.updateRecord;if((2!=oldDbVersion||3!=MediaDB.VERSION)&&!clientUpgradeNeeded){return;}
enumerateOldFiles(store,function doUpgrade(dbfile){if(2==oldDbVersion&&3==MediaDB.VERSION){upgradeDBVer2to3(store,dbfile);}
if(clientUpgradeNeeded){handleClientUpgrade(store,dbfile,oldClientVersion);}});}
function upgradeIndexesChanges(store){var dbIndexes=store.indexNames;var clientIndexes=media.indexes;for(var i=0;i<dbIndexes.length;i++){if('name'===dbIndexes[i]||'date'===dbIndexes[i]){continue;}
if(clientIndexes.indexOf(dbIndexes[i])<0){store.deleteIndex(dbIndexes[i]);}}
for(i=0;i<clientIndexes.length;i++){if(!dbIndexes.contains(clientIndexes[i])){store.createIndex(clientIndexes[i],clientIndexes[i]);}}}
function upgradeDBVer2to3(store,dbfile){if(dbfile.name[0]==='/'){return;}
store.delete(dbfile.name);dbfile.name='/sdcard/'+dbfile.name;store.add(dbfile);}
function handleClientUpgrade(store,dbfile,oldClientVersion){try{dbfile.metadata=media.updateRecord(dbfile,oldClientVersion,media.version);if(dbfile.needsReparse&&!media.reparsedRecord){console.warn('client app requested reparse, but no reparsedRecord was set');delete dbfile.needsReparse;}
store.put(dbfile);}catch(ex){console.warn('client app updates record, '+dbfile.name+', failed: '+ex.message);}}
function initDeviceStorage(){var details=media.details;details.storages=navigator.getDeviceStorages(mediaType);details.availability={};getStorageAvailability();function getStorageAvailability(){var next=0;getNextAvailability();function getNextAvailability(){if(next>=details.storages.length){setupHandlers();return;}
var s=details.storages[next++];var name=s.storageName;var req=s.available();req.onsuccess=function(e){details.availability[name]=req.result;getNextAvailability();};req.onerror=function(e){details.availability[name]='unavailable';getNextAvailability();};}}
function setupHandlers(){for(var i=0;i<details.storages.length;i++){details.storages[i].addEventListener('change',changeHandler);}
details.dsEventListener=changeHandler;sendInitialEvent();}
function sendInitialEvent(){var state=getState(details.availability);changeState(media,state);if(media.autoscan){scan(media);}}
function getState(availability){var n=0;var a=0;var u=0;var s=0;for(var name in availability){n++;switch(availability[name]){case'available':a++;break;case'unavailable':u++;break;case'shared':s++;break;}}
if(s>0){return MediaDB.UNMOUNTED;}
if(u===n){return MediaDB.NOCARD;}
return MediaDB.READY;}
function changeHandler(e){switch(e.reason){case'modified':case'deleted':fileChangeHandler(e);return;case'available':case'unavailable':case'shared':volumeChangeHandler(e);return;default:return;}}
function volumeChangeHandler(e){var storageName=e.target.storageName;if(details.availability[storageName]===e.reason){return;}
var oldState=media.state;details.availability[storageName]=e.reason;var newState=getState(details.availability);if(newState!==oldState){changeState(media,newState);if(newState===MediaDB.READY){if(media.autoscan){scan(media);}}
else{endscan(media);}}
else if(newState===MediaDB.READY){if(e.reason==='available'){dispatchEvent(media,'ready');if(media.autoscan){scan(media);}}
else if(e.reason==='unavailable'){dispatchEvent(media,'cardremoved');deleteAllFiles(storageName);}}}
function fileChangeHandler(e){var filename=e.path;if(ignoreName(media,filename)){return;}
if(e.reason==='modified'){insertRecord(media,filename);}else{deleteRecord(media,filename);}}
function deleteAllFiles(storageName){var storagePrefix=storageName?'/'+storageName+'/':'';var store=media.db.transaction('files').objectStore('files');var cursorRequest=store.openCursor();cursorRequest.onsuccess=function(){var cursor=cursorRequest.result;if(cursor){if(cursor.value.name.startsWith(storagePrefix)){deleteRecord(media,cursor.value.name);}
cursor.continue();}};}}}
MediaDB.prototype={close:function close(){this.db.close();for(var i=0;i<this.details.storages.length;i++){var s=this.details.storages[i];s.removeEventListener('change',this.details.dsEventListener);}
changeState(this,MediaDB.CLOSED);},addEventListener:function addEventListener(type,listener){if(!this.details.eventListeners.hasOwnProperty(type)){this.details.eventListeners[type]=[];}
var listeners=this.details.eventListeners[type];if(listeners.indexOf(listener)!==-1){return;}
listeners.push(listener);},removeEventListener:function removeEventListener(type,listener){if(!this.details.eventListeners.hasOwnProperty(type)){return;}
var listeners=this.details.eventListeners[type];var position=listeners.indexOf(listener);if(position===-1){return;}
listeners.splice(position,1);},getFileInfo:function getFile(filename,callback,errback){if(this.state===MediaDB.OPENING){throw Error('MediaDB is not ready. State: '+this.state);}
var media=this;var read=media.db.transaction('files','readonly').objectStore('files').get(filename);read.onerror=function(){var msg='MediaDB.getFileInfo: unknown filename: '+filename;if(errback){errback(msg);}else{console.error(msg);}};read.onsuccess=function(){if(callback){callback(read.result);}};},getFile:function getFile(filename,callback,errback){if(this.state!==MediaDB.READY){throw Error('MediaDB is not ready. State: '+this.state);}
var storage=navigator.getDeviceStorage(this.mediaType);var getRequest=storage.get(filename);getRequest.onsuccess=function(){callback(getRequest.result);};getRequest.onerror=function(){var errmsg=getRequest.error&&getRequest.error.name;if(errback){errback(errmsg);}else{console.error('MediaDB.getFile:',errmsg);}};},deleteFile:function deleteFile(filename){if(this.state!==MediaDB.READY){throw Error('MediaDB is not ready. State: '+this.state);}
var storage=navigator.getDeviceStorage(this.mediaType);storage.delete(filename).onerror=function(e){console.error('MediaDB.deleteFile(): Failed to delete',filename,'from DeviceStorage:',e.target.error);};},addFile:function addFile(filename,file){if(this.state!==MediaDB.READY){throw Error('MediaDB is not ready. State: '+this.state);}
var media=this;var storage=navigator.getDeviceStorage(media.mediaType);var deletereq=storage.delete(filename);deletereq.onsuccess=deletereq.onerror=save;function save(){var request=storage.addNamed(file,filename);request.onerror=function(){console.error('MediaDB: Failed to store',filename,'in DeviceStorage:',request.error);};}},updateMetadata:function(filename,metadata,callback){if(this.state===MediaDB.OPENING){throw Error('MediaDB is not ready. State: '+this.state);}
var media=this;var read=media.db.transaction('files','readonly').objectStore('files').get(filename);read.onerror=function(){console.error('MediaDB.updateMetadata called with unknown filename');};read.onsuccess=function(){var fileinfo=read.result;Object.keys(metadata).forEach(function(key){fileinfo.metadata[key]=metadata[key];});var write=media.db.transaction('files','readwrite').objectStore('files').put(fileinfo);write.onerror=function(){console.error('MediaDB.updateMetadata: database write failed',write.error&&write.error.name);};if(callback){write.onsuccess=function(){callback();};}};},count:function(key,range,callback){if(this.state!==MediaDB.READY&&this.state!==MediaDB.ENUMERABLE){throw Error('MediaDB is not ready or enumerable. State: '+this.state);}
if(arguments.length===1){callback=key;range=undefined;key=undefined;}
else if(arguments.length===2){callback=range;range=key;key=undefined;}
var store=this.db.transaction('files').objectStore('files');if(key&&key!=='name'){store=store.index(key);}
var countRequest=store.count(range||null);countRequest.onerror=function(){console.error('MediaDB.count() failed with',countRequest.error);};countRequest.onsuccess=function(e){callback(e.target.result);};},enumerate:function enumerate(key,range,direction,callback){if(this.state!==MediaDB.READY&&this.state!==MediaDB.ENUMERABLE){throw Error('MediaDB is not ready or enumerable. State: '+this.state);}
var handle={state:'enumerating'};if(arguments.length===1){callback=key;key=undefined;}
else if(arguments.length===2){callback=range;range=undefined;}
else if(arguments.length===3){callback=direction;direction=undefined;}
var store=this.db.transaction('files').objectStore('files');if(key&&key!=='name'){store=store.index(key);}
var cursorRequest=store.openCursor(range||null,direction||'next');cursorRequest.onerror=function(){console.error('MediaDB.enumerate() failed with',cursorRequest.error);handle.state='error';};cursorRequest.onsuccess=function(){if(handle.state==='cancelling'){handle.state='cancelled';return;}
var cursor=cursorRequest.result;if(cursor){try{var fileinfo=cursor.value;if(!fileinfo.fail){callback(fileinfo);}}
catch(e){console.warn('MediaDB.enumerate(): callback threw',e,e.stack);}
cursor.continue();}
else{handle.state='complete';callback(null);}};return handle;},advancedEnumerate:function(key,range,direction,index,callback){if(this.state!==MediaDB.READY){throw Error('MediaDB is not ready. State: '+this.state);}
var handle={state:'enumerating'};var store=this.db.transaction('files').objectStore('files');if(key&&key!=='name'){store=store.index(key);}
var cursorRequest=store.openCursor(range||null,direction||'next');var isTarget=false;cursorRequest.onerror=function(){console.error('MediaDB.enumerate() failed with',cursorRequest.error);handle.state='error';};cursorRequest.onsuccess=function(){if(handle.state==='cancelling'){handle.state='cancelled';return;}
var cursor=cursorRequest.result;if(cursor){try{if(index===0){isTarget=true;}
var fileinfo=cursor.value;if(!fileinfo.fail&&isTarget){callback(cursor.value);cursor.continue();}
else{cursor.advance(index);isTarget=true;}}
catch(e){console.warn('MediaDB.enumerate(): callback threw',e,e.stack);}}
else{handle.state='complete';callback(null);}};return handle;},enumerateAll:function enumerateAll(key,range,direction,callback){var batch=[];if(arguments.length===1){callback=key;key=undefined;}
else if(arguments.length===2){callback=range;range=undefined;}
else if(arguments.length===3){callback=direction;direction=undefined;}
return this.enumerate(key,range,direction,function(fileinfo){if(fileinfo!==null){batch.push(fileinfo);}else{callback(batch);}});},cancelEnumeration:function cancelEnumeration(handle){if(handle.state==='enumerating'){handle.state='cancelling';}},getAll:function getAll(callback){if(this.state!==MediaDB.READY&&this.state!==MediaDB.ENUMERABLE){throw Error('MediaDB is not ready or enumerable. State: '+this.state);}
var store=this.db.transaction('files').objectStore('files');var request=store.mozGetAll();request.onerror=function(){console.error('MediaDB.getAll() failed with',request.error);};request.onsuccess=function(){var all=request.result;var good=all.filter(function(fileinfo){return!fileinfo.fail;});callback(good);};},scan:function(){scan(this);},freeSpace:function freeSpace(callback){if(this.state!==MediaDB.READY){throw Error('MediaDB is not ready. State: '+this.state);}
var storage=navigator.getDeviceStorage(this.mediaType);var freereq=storage.freeSpace();freereq.onsuccess=function(){callback(freereq.result);};}};MediaDB.VERSION=3;MediaDB.OPENING='opening';MediaDB.UPGRADING='upgrading';MediaDB.ENUMERABLE='enumerable';MediaDB.READY='ready';MediaDB.NOCARD='nocard';MediaDB.UNMOUNTED='unmounted';MediaDB.CLOSED='closed';function ignore(media,file){if(ignoreName(media,file.name)){return true;}
if(media.mimeTypes&&media.mimeTypes.indexOf(file.type)===-1){return true;}
return false;}
function ignoreName(media,filename){if(media.clientExcludeFilter&&media.clientExcludeFilter.test(filename)){return true;}else{return(filename[0]==='.'||filename.indexOf('/.')!==-1);}}
function scan(media){media.scanning=true;dispatchEvent(media,'scanstart');quickScan(media.details.newestFileModTime);function quickScan(timestamp){var options;if(timestamp>0){media.details.firstscan=false;options={since:new Date(timestamp+1)};}
else{media.details.firstscan=true;media.details.records=[];options={};}
scanDS(media.details.storages,null,options).then(processFiles).catch(handleScanError);function processFiles(files){if(!media.scanning){return;}
files=files.sort(function(a,b){return b.lastModifiedDate-a.lastModifiedDate;});for(var i=0;i<files.length;i++){insertRecord(media,files[i]);}
whenDoneProcessing(media,function(){sendNotifications(media);if(media.details.firstscan){endscan(media);}
else{fullScan();}});}
function handleScanError(error){console.warn('Error while scanning',error);endscan(media);}}
function fullScan(){if(media.state!==MediaDB.READY){endscan(media);return;}
var dsfiles;scanDS(media.details.storages).then(function(files){dsfiles=files;getDBFiles();}).catch(function(error){console.warn('Error while scanning',error);endscan(media);});function getDBFiles(){var store=media.db.transaction('files').objectStore('files');var getAllRequest=store.mozGetAll();getAllRequest.onsuccess=function(){if(!media.scanning){return;}
var dbfiles=getAllRequest.result;compareLists(dbfiles,dsfiles);};}
function compareLists(dbfiles,dsfiles){dsfiles.sort(function(a,b){if(a.name<b.name){return-1;}else{return 1;}});var dsindex=0,dbindex=0;while(true){var dsfile;if(dsindex<dsfiles.length){dsfile=dsfiles[dsindex];}else{dsfile=null;}
var dbfile;if(dbindex<dbfiles.length){dbfile=dbfiles[dbindex];}else{dbfile=null;}
if(dsfile===null&&dbfile===null){break;}
if(dbfile===null){insertRecord(media,dsfile);dsindex++;continue;}
if(dsfile===null){deleteRecord(media,dbfile.name);dbindex++;continue;}
if(dsfile.name===dbfile.name){var lastModified=dsfile.lastModifiedDate;var timeDifference=lastModified.getTime()-dbfile.date;var sameTime=(timeDifference===0||((Math.abs(timeDifference)<=12*60*60*1000)&&(timeDifference%10*60*1000===0)));var sameSize=dsfile.size===dbfile.size;if(!sameTime||!sameSize){deleteRecord(media,dbfile.name);insertRecord(media,dsfile);}else if(dbfile.needsReparse){deleteRecord(media,dbfile.name);insertRecord(media,dsfile,dbfile.metadata);}
dsindex++;dbindex++;continue;}
if(dsfile.name<dbfile.name){insertRecord(media,dsfile);dsindex++;continue;}
if(dsfile.name>dbfile.name){deleteRecord(media,dbfile.name);dbindex++;continue;}
console.error('Assertion failed');}
insertRecord(media,null);}}
function scanDS(storage,directory,options){if(Array.isArray(storage)){return Promise.all(storage.map((s)=>scanDS(s,directory,options))).then(function(arrays){return Array.prototype.concat.apply([],arrays);});}
return new Promise(function(resolve,reject){var files=[];var cursor=storage.enumerate(directory||'',options||{});cursor.onerror=function(){if(cursor.error.name==='NotFoundError'){resolve(files);}
else{reject(cursor.error);}};cursor.onsuccess=function(){var result=cursor.result;if(result){if(!ignore(media,result)){files.push(result);}
cursor.continue();}
else{resolve(files);}};});}}
function endscan(media){if(media.scanning){media.initialScanComplete=true;media.scanning=false;media.parsingBigFiles=false;dispatchEvent(media,'scanend');}}
function insertRecord(media,fileOrName,oldMetadata){var details=media.details;details.pendingInsertions.push([fileOrName,oldMetadata]);if(details.processingQueue){return;}
processQueue(media);}
function deleteRecord(media,filename){var details=media.details;details.pendingDeletions.push(filename);if(details.processingQueue){return;}
processQueue(media);}
function whenDoneProcessing(media,f){var details=media.details;if(details.processingQueue){details.whenDoneProcessing.push(f);}else{f();}}
function processQueue(media){var details=media.details;details.processingQueue=true;next();function next(){if(details.pendingDeletions.length>0){deleteFiles();}
else if(details.pendingInsertions.length>0){insertFile(...details.pendingInsertions.shift());}
else{details.processingQueue=false;if(details.whenDoneProcessing.length>0){var functions=details.whenDoneProcessing;details.whenDoneProcessing=[];functions.forEach(function(f){f();});}}}
function deleteFiles(){var transaction=media.db.transaction('files','readwrite');var store=transaction.objectStore('files');deleteNextFile();function deleteNextFile(){if(details.pendingDeletions.length===0){next();return;}
var filename=details.pendingDeletions.shift();var request=store.delete(filename);request.onerror=function(){console.warn('MediaDB: Unknown file in deleteRecord:',filename,request.error);deleteNextFile();};request.onsuccess=function(){queueDeleteNotification(media,filename);deleteNextFile();};}}
function insertFile(f,oldMetadata){if(f===null){sendNotifications(media);endscan(media);next();return;}
if(typeof f==='string'){var storage=navigator.getDeviceStorage(media.mediaType);var getreq=storage.get(f);getreq.onerror=function(){console.warn('MediaDB: Unknown file in insertRecord:',f,getreq.error);next();};getreq.onsuccess=function(){if(media.mimeTypes&&ignore(media,getreq.result)){next();}else{parseMetadata(getreq.result,f,oldMetadata);}};}
else{parseMetadata(f,f.name,oldMetadata);}}
function parseMetadata(file,filename,oldMetadata){if(!file.lastModifiedDate){console.warn('MediaDB: parseMetadata: no lastModifiedDate for',filename,'using Date.now() until #793955 is fixed');}
var fileinfo={name:filename,type:file.type,size:file.size,date:file.lastModifiedDate?file.lastModifiedDate.getTime():Date.now()};if(fileinfo.date>details.newestFileModTime){details.newestFileModTime=fileinfo.date;}
media.metadataParser(file,gotMetadata,metadataError,parsingBigFile);function parsingBigFile(){media.parsingBigFiles=true;}
function metadataError(e){console.warn('MediaDB: error parsing metadata for',filename,':',e);fileinfo.fail=true;storeRecord(fileinfo);}
function gotMetadata(metadata){fileinfo.metadata=metadata;if(oldMetadata&&media.reparsedRecord){fileinfo.metadata=media.reparsedRecord(oldMetadata,metadata);}
storeRecord(fileinfo);if(!media.scanning){media.parsingBigFiles=false;}}}
function storeRecord(fileinfo){if(media.details.firstscan){media.details.records.push(fileinfo);if(!fileinfo.fail){queueCreateNotification(media,fileinfo);}
next();}
else{var transaction=media.db.transaction('files','readwrite');var store=transaction.objectStore('files');var request=store.add(fileinfo);request.onsuccess=function(){if(!fileinfo.fail){queueCreateNotification(media,fileinfo);}
next();};request.onerror=function(event){if(request.error.name==='ConstraintError'){event.stopPropagation();event.preventDefault();var putrequest=store.put(fileinfo);putrequest.onsuccess=function(){queueDeleteNotification(media,fileinfo.name);if(!fileinfo.fail){queueCreateNotification(media,fileinfo);}
next();};putrequest.onerror=function(){console.error('MediaDB: unexpected ConstraintError','in insertRecord for file:',fileinfo.name);next();};}
else{console.error('MediaDB: unexpected error in insertRecord:',request.error,'for file:',fileinfo.name);next();}};}}}
function queueCreateNotification(media,fileinfo){var creates=media.details.pendingCreateNotifications;creates.push(fileinfo);if(media.batchSize&&creates.length>=media.batchSize){sendNotifications(media);}else{resetNotificationTimer(media);}}
function queueDeleteNotification(media,filename){var deletes=media.details.pendingDeleteNotifications;deletes.push(filename);if(media.batchSize&&deletes.length>=media.batchSize){sendNotifications(media);}else{resetNotificationTimer(media);}}
function resetNotificationTimer(media){var details=media.details;if(details.pendingNotificationTimer){clearTimeout(details.pendingNotificationTimer);}
details.pendingNotificationTimer=setTimeout(function(){sendNotifications(media);},media.scanning?media.batchHoldTime:100);}
function sendNotifications(media){var details=media.details;if(details.pendingNotificationTimer){clearTimeout(details.pendingNotificationTimer);details.pendingNotificationTimer=null;}
if(details.pendingDeleteNotifications.length>0){var deletions=details.pendingDeleteNotifications;details.pendingDeleteNotifications=[];dispatchEvent(media,'deleted',deletions);}
if(details.pendingCreateNotifications.length>0){var creations=details.pendingCreateNotifications;details.pendingCreateNotifications=[];if(details.firstscan&&details.records.length>0){var transaction=media.db.transaction('files','readwrite');var store=transaction.objectStore('files');for(var i=0;i<details.records.length;i++){store.add(details.records[i]);}
details.records.length=0;transaction.oncomplete=function(){dispatchEvent(media,'created',creations);};}
else{dispatchEvent(media,'created',creations);}}}
function dispatchEvent(media,type,detail){var handler=media['on'+type];var listeners=media.details.eventListeners[type];if(!handler&&(!listeners||listeners.length===0)){return;}
var event={type:type,target:media,currentTarget:media,timestamp:Date.now(),detail:detail};if(typeof handler==='function'){try{handler.call(media,event);}
catch(e){console.warn('MediaDB: ','on'+type,'event handler threw',e,e.stack);}}
if(!listeners){return;}
for(var i=0;i<listeners.length;i++){try{var listener=listeners[i];if(typeof listener==='function'){listener.call(media,event);}
else{listener.handleEvent(event);}}
catch(e){console.warn('MediaDB: ',type,'event listener threw',e,e.stack);}}}
function changeState(media,state){if(media.state!==state){media.state=state;switch(state){case MediaDB.READY:case MediaDB.ENUMERABLE:dispatchEvent(media,state);break;default:dispatchEvent(media,'unavailable',state);break;}}}
return MediaDB;}());

View file

@ -0,0 +1,2 @@
;'use strict';var MimeMapper={_typeToExtensionMap:{'image/jpeg':'jpg','image/png':'png','image/gif':'gif','image/bmp':'bmp','audio/mpeg':'mp3','audio/mp4':'m4a','audio/ogg':'ogg','audio/webm':'webm','audio/3gpp':'3gp','audio/amr':'amr','video/mp4':'mp4','video/mpeg':'mpg','video/ogg':'ogg','video/webm':'webm','video/3gpp':'3gp','video/3gpp2':'3g2','application/pdf':'pdf','application/vcard':'vcf','text/vcard':'vcf','text/x-vcard':'vcf'},_extensionToTypeMap:{'jpg':'image/jpeg','jpeg':'image/jpeg','jpe':'image/jpeg','png':'image/png','gif':'image/gif','bmp':'image/bmp','mp3':'audio/mpeg','m4a':'audio/mp4','m4b':'audio/mp4','m4p':'audio/mp4','m4r':'audio/mp4','aac':'audio/aac','opus':'audio/ogg','amr':'audio/amr','mp4':'video/mp4','mpeg':'video/mpeg','mpg':'video/mpeg','ogv':'video/ogg','ogx':'video/ogg','webm':'video/webm','3gp':'video/3gpp','3g2':'video/3gpp2','ogg':'video/ogg','pdf':'application/pdf','vcf':'text/vcard'},_parseExtension:function(filename){var array=filename.split('.');return array.length>1?array.pop():'';},isSupportedType:function(mimetype){return(mimetype in this._typeToExtensionMap);},isSupportedExtension:function(extension){return(extension in this._extensionToTypeMap);},isFilenameMatchesType:function(filename,mimetype){var extension=this._parseExtension(filename);var guessedType=this.guessTypeFromExtension(extension);return(guessedType==mimetype);},guessExtensionFromType:function(mimetype){return this._typeToExtensionMap[mimetype];},guessTypeFromExtension:function(extension){return this._extensionToTypeMap[extension];},guessTypeFromFileProperties:function(filename,mimetype){var extension=this._parseExtension(filename);var type=this.isSupportedType(mimetype)?mimetype:this.guessTypeFromExtension(extension);return type||'';},ensureFilenameMatchesType:function(filename,mimetype){if(!this.isFilenameMatchesType(filename,mimetype)){var guessedExt=this.guessExtensionFromType(mimetype);if(guessedExt){filename+='.'+guessedExt;}}
return filename;}};

View file

@ -0,0 +1,8 @@
;'use strict';var ScreenLayout={defaultQueries:{tiny:'(max-width: 767px)',small:'(min-width: 768px) and (max-width: 991px)',medium:'(min-width: 992px) and (max-width: 1200px)',large:'(min-width: 1201px)',hardwareHomeButton:window.VulpesCompat?'(min-width: 0px)':'(-moz-physical-home-button)'},init:function sl_init(){this.queries=(function(qs){var result={};for(var key in qs){result[key]=window.matchMedia(qs[key]);}
return result;})(this.defaultQueries);},_isOnRealDevice:undefined,isOnRealDevice:function sl_isOnRealDevice(){if(typeof(this._isOnRealDevice)!=='undefined'){return this._isOnRealDevice;}
if(window.innerWidth===screen.availWidth){this._isOnRealDevice=true;}else{this._isOnRealDevice=false;}
return this._isOnRealDevice;},getCurrentLayout:function sl_getCurrentLayout(type){if(type===undefined){for(var name in this.defaultQueries){if(this.queries[name]&&this.queries[name].matches){return name;}}}
if(typeof this.queries[type]!=='undefined'){return this.queries[type].matches;}
return false;},watch:function sl_watch(name,media){var mediaString=media||this.queries[name].media;if(!mediaString){return;}
this.unwatch(name);this.queries[name]=window.matchMedia(mediaString);this.boundHandleChange=this.handleChange.bind(this);this.queries[name].addListener(this.boundHandleChange);},unwatch:function sl_unwatch(name){if(this.queries[name]){this.queries[name].removeListener(this.boundHandleChange);}},handleChange:function sl_handleChange(evt){for(var key in this.queries){if(this.queries[key].media!==evt.media){continue;}
window.dispatchEvent(new CustomEvent('screenlayoutchange',{detail:{name:key,status:evt.matches}}));}}};ScreenLayout.init();

View file

@ -0,0 +1,19 @@
;'use strict';(function(exports){var ShrinkingUI=function(foregroundElement,backgroundElement){this.elements.foregroundElement=foregroundElement;this.elements.backgroundElement=backgroundElement;};ShrinkingUI.prototype={DEBUG:false,THRESHOLD:50,SUSPEND_INTERVAL:100,state:{shrinking:false,ending:false,tilting:false,overThreshold:false,toward:'TOP',touch:{initY:-1,prevY:-1},slideTransitionCb:null,tiltTransitionCb:null},elements:{},configs:{degreeLandscape:'2.7deg',degreePortrait:'0.65deg',overDegreeLandscape:'2.9deg',overDegreePortrait:'0.9deg'},tip:null,cover:null};ShrinkingUI.prototype.debug=function su_debug(msg,optObject){if(this.DEBUG){var output='[DEBUG] ShrinkingUI: '+msg;if(optObject){output+=JSON.stringify(optObject);}
dump(output);}};ShrinkingUI.prototype.start=function su_start(){window.addEventListener('shrinking-receiving',this);this.startTilt();};ShrinkingUI.prototype.stop=function su_stop(){if(this.isActive()){this.stopTilt();}
window.removeEventListener('shrinking-receiving',this);};ShrinkingUI.prototype.handleEvent=function su_handleEvent(evt){switch(evt.type){case'shrinking-receiving':this._receivingEffects();break;case'touchstart':this._handleSendingStart(evt);break;case'touchmove':this._handleSendingSlide(evt);break;case'touchend':this._handleSendingOut(evt);break;}};ShrinkingUI.prototype.respondToHierarchyEvent=function su_respondToHierarchyEvent(evt){if(this['_handle_'+evt.type]){return this['_handle_'+evt.type](evt);}
return true;};ShrinkingUI.prototype._handle_holdhome=function su__handle_holdhome(evt){return this.isActive();};ShrinkingUI.prototype._handle_home=function su__handle_home(evt){return this.isActive();};ShrinkingUI.prototype.startTilt=function su_startTilt(){if(this.isActive()){return;}
if(!this.elements.backgroundElement||!this.elements.foregroundElement){return;}
this.state.shrinking=true;this.state.tilting=true;var afterTilt=()=>{this.elements.foregroundElement.classList.add('hidden');this.state.tilting=false;};this._setTip();this._setState(true);screen.mozLockOrientation(screen.mozOrientation);this._shrinkingTilt(afterTilt);};ShrinkingUI.prototype._setTip=function su_setTip(){var backgroundElement=this.elements.backgroundElement;if(!this.tip){this.tip=this._slidingTip();backgroundElement.appendChild(this.tip);}
this.tip.classList.remove('hide');};ShrinkingUI.prototype.stopTilt=function su_stopTilt(){if(!this.state.shrinking||this.state.ending){return;}
if(this.state.tilting){this.state.tilting=false;}
this.state.shrinking=false;this.state.ending=true;var afterTiltBack=(()=>{this.elements.foregroundElement.classList.remove('hidden');this._cleanEffects().then(()=>{this.state.ending=false;});});this.tip.remove();this.tip=null;this._shrinkingTiltBack(true,afterTiltBack);};ShrinkingUI.prototype.isActive=function su_isActive(){if(this.state.shrinking||this.state.tilting||this.state.ending){return true;}
return false;};ShrinkingUI.prototype._setState=function su_shrinking(state){var foregroundElement=this.elements.foregroundElement;foregroundElement.setAttribute('data-shrinking-state',state.toString());this.debug('Setting shrink state to: '+state);};ShrinkingUI.prototype._updateSlideTransition=function su_updateSlideTransition(cb){if(this.tip&&this.state.slideTransitionCb){this.elements.foregroundElement.style.transitionDuration='0s';this.tip.removeEventListener('transitionend',this.state.slideTransitionCb);}
this.state.slideTransitionCb=cb;};ShrinkingUI.prototype._updateTiltTransition=function su_updateTiltTransition(cb){var foregroundElement=this.elements.foregroundElement;if(foregroundElement&&this.state.tiltTransitionCb){foregroundElement.removeEventListener('transitionend',this.state.tiltTransitionCb);}
this.state.tiltTransitionCb=cb;};ShrinkingUI.prototype._receivingEffects=function su_receivingEffects(){var foregroundElement=this.elements.foregroundElement;foregroundElement.style.opacity='0';var afterTop=(function(){foregroundElement.style.opacity='';foregroundElement.style.transition='transform 0.5s ease';this._sendingSlideTo('BOTTOM',(function doTiltBack(){this._shrinkingTiltBack(false,this._cleanEffects);}).bind(this));}).bind(this);var afterTilt=(function(){foregroundElement.style.transition='transform 0.05s ease';this._sendingSlideTo('TOP',afterTop);}).bind(this);this._shrinkingTilt(afterTilt);};ShrinkingUI.prototype._sendingSlideTo=function su_sendingSlideTo(y,callback){var foregroundElement=this.elements.foregroundElement;var cbDone=(function on_cbDone(evt){foregroundElement.removeEventListener('transitionend',cbDone);this.elements.foregroundElement.style.transitionDuration='0s';if('undefined'!==typeof callback){callback();}}).bind(this);if('TOP'===y){foregroundElement.style.transitionDuration='0.3s';y=foregroundElement.parentElement.clientHeight;}else if('BOTTOM'===y){if(this.state.touch.prevY<=0){cbDone();}else{foregroundElement.style.transitionDuration='0.3s';}
y=0;}else if(y<0){y=0;}
foregroundElement.addEventListener('transitionend',cbDone);this._updateTiltTransition(cbDone);foregroundElement.style.transform='rotateX('+this._getTiltingDegree()+') '+'translateY(-'+y+'px)';};ShrinkingUI.prototype._slidingCover=function slidingCover(){var cover=document.createElement('div');cover.id='shrinking-cover';cover.style.width='100%';cover.style.height='100%';cover.style.position='relative';cover.style.zIndex='2';cover.addEventListener('touchstart',this);cover.addEventListener('touchmove',this);cover.addEventListener('touchend',this);return cover;};ShrinkingUI.prototype._slidingTip=function slidingTip(){var tip=document.createElement('div');var tipArrow=document.createElement('div');var tipText=document.createElement('div');tip.id='shrinking-tip';tipArrow.id='shrinking-tip-arrow';tipText.id='shrinking-text';tipArrow.textContent='\u00A0';tipText.setAttribute('data-l10n-id','shrinking-tip');tip.appendChild(tipText);tip.appendChild(tipArrow);return tip;};ShrinkingUI.prototype._disableSlidingCover=function su_disableSlidingCover(){this.cover.removeEventListener('touchstart',this);this.cover.removeEventListener('touchmove',this);this.cover.removeEventListener('touchend',this);};ShrinkingUI.prototype._shrinkingTilt=function su_shrinkingTilt(cb){var foregroundElement=this.elements.foregroundElement;var backgroundElement=this.elements.backgroundElement;if(null===this.cover){this.cover=this._slidingCover();var anchor=foregroundElement.firstElementChild;foregroundElement.insertBefore(this.cover,anchor);}
backgroundElement.classList.add('shrinking-wrapper');foregroundElement.style.transition='transform 0.5s ease';var bounceBack=(function on_bounceBack(evt){if(evt.target!==foregroundElement){return;}
foregroundElement.removeEventListener('transitionend',bounceBack);foregroundElement.addEventListener('transitionend',bounceBackEnd);this._updateTiltTransition(bounceBackEnd);foregroundElement.style.transition='transform ease';foregroundElement.style.transform='rotateX('+this._getTiltingDegree()+') ';}).bind(this);var bounceBackEnd=(function on_bounceBackEnd(evt){if(evt.target!==foregroundElement){return;}
foregroundElement.removeEventListener('transitionend',bounceBackEnd);foregroundElement.style.transition='transform 0.5s ease 0s';if(cb){cb();}}).bind(this);foregroundElement.addEventListener('transitionend',bounceBack);this._updateTiltTransition(bounceBack);foregroundElement.style.transformOrigin='50% 100% 0';foregroundElement.style.transform='rotateX('+this._getOverTiltingDegree()+')';};ShrinkingUI.prototype._shrinkingTiltBack=function su_shrinkingTiltBack(instant,callback){var foregroundElement=this.elements.foregroundElement;if(!instant){var tsEnd=(function _tsEnd(evt){foregroundElement.removeEventListener('transitionend',tsEnd);if(callback){callback();}}).bind(this);foregroundElement.style.transition='transform 0.3s ease';foregroundElement.addEventListener('transitionend',tsEnd);this._updateTiltTransition(tsEnd);foregroundElement.style.transform='rotateX(0.0deg)';}else{foregroundElement.style.transition='';foregroundElement.style.transform='rotateX(0.0deg)';if(callback){callback();}}};ShrinkingUI.prototype._handleSendingStart=function su_handleSendingStart(evt){this.state.touch.initY=evt.touches[0].pageY;this.debug('_handleSendingStart(): ',this.isActive());evt.stopImmediatePropagation();var tsEnd=(function _tsEnd(){this.tip.removeEventListener('transitionend',tsEnd);}).bind(this);this.tip.classList.add('hide');this.tip.addEventListener('transitionend',tsEnd);this._updateSlideTransition(tsEnd);return false;};ShrinkingUI.prototype._handleSendingSlide=function su_handleSendingSlide(evt){var pgy=evt.touches[0].pageY;var slideY=this.state.touch.initY-pgy;if('undefined'===typeof this.state.touch.initY){this.state.touch.initY=slideY;}
if('undefined'===typeof this.state.touch.prevY){this.state.touch.prevY=slideY;}
this.state.toward=(this.state.touch.prevY<slideY)?'TOP':'BOTTOM';this._sendingSlideTo(slideY);this.state.touch.prevY=slideY;this.state.overThreshold=(slideY>this.THRESHOLD)?true:false;};ShrinkingUI.prototype._handleSendingOut=function su_handleSendingOut(evt){this.debug('_handleSendingOut(): ',this.isActive());if(this.state.overThreshold&&'TOP'===this.state.toward){this._sendingSlideTo('TOP',(function(){this._disableSlidingCover();window.dispatchEvent(new CustomEvent('shrinking-sent'));}).bind(this));}else{this._sendingSlideTo('BOTTOM',(function resumeSending(){this._setTip();}).bind(this));}};ShrinkingUI.prototype._cleanEffects=function su_cleanEffects(){var foregroundElement=this.elements.foregroundElement;var backgroundElement=this.elements.backgroundElement;return new Promise((resolve,rejected)=>{this.debug('_cleanEffects(): ',this.isActive());this._disableSlidingCover();foregroundElement.style.transition='';foregroundElement.style.transform='';foregroundElement.style.transformOrigin='50% 50% 0';this._setState(false);this._updateTiltTransition(null);this._updateSlideTransition(null);backgroundElement.classList.remove('shrinking-wrapper');this.cover.remove();this.cover=null;resolve();});};ShrinkingUI.prototype._getTiltingDegree=function su_getTiltingDegree(){return(window.OrientationManager?window.OrientationManager.fetchCurrentOrientation().indexOf('landscape')!==-1:window.innerHeight<window.innerWidth)?this.configs.degreeLandscape:this.configs.degreePortrait;};ShrinkingUI.prototype._getOverTiltingDegree=function su_getOverTiltingDegree(){return(window.OrientationManager?window.OrientationManager.fetchCurrentOrientation().indexOf('landscape')!==-1:window.innerHeight<window.innerWidth)?this.configs.overDegreeLandscape:this.configs.overDegreePortrait;};exports.ShrinkingUI=ShrinkingUI;})(window);