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 @@
;;window.COMPONENTS_BASE_URL='/shared/elements/';

View file

@ -0,0 +1,277 @@
;;(function(window,undefined){'use strict';function L10nError(message,id,loc){this.name='L10nError';this.message=message;this.id=id;this.loc=loc;}
L10nError.prototype=Object.create(Error.prototype);L10nError.prototype.constructor=L10nError;var io={_load:function(type,url,callback,sync){var xhr=new XMLHttpRequest();var needParse;if(xhr.overrideMimeType){xhr.overrideMimeType(type);}
xhr.open('GET',url,!sync);if(type==='application/json'){if(sync){needParse=true;}else{xhr.responseType='json';}}
xhr.addEventListener('load',function io_onload(e){if(e.target.status===200||e.target.status===0){var res=e.target.response||e.target.responseText;callback(null,needParse?JSON.parse(res):res);}else{callback(new L10nError('Not found: '+url));}});xhr.addEventListener('error',callback);xhr.addEventListener('timeout',callback);try{xhr.send(null);}catch(e){if(e.name==='NS_ERROR_FILE_NOT_FOUND'){callback(new L10nError('Not found: '+url));}else{throw e;}}},load:function(url,callback,sync){return io._load('text/plain',url,callback,sync);},loadJSON:function(url,callback,sync){return io._load('application/json',url,callback,sync);}};function EventEmitter(){}
EventEmitter.prototype.emit=function ee_emit(){if(!this._listeners){return;}
var args=Array.prototype.slice.call(arguments);var type=args.shift();if(!this._listeners[type]){return;}
var typeListeners=this._listeners[type].slice();for(var i=0;i<typeListeners.length;i++){typeListeners[i].apply(this,args);}};EventEmitter.prototype.addEventListener=function ee_add(type,listener){if(!this._listeners){this._listeners={};}
if(!(type in this._listeners)){this._listeners[type]=[];}
this._listeners[type].push(listener);};EventEmitter.prototype.removeEventListener=function ee_rm(type,listener){if(!this._listeners){return;}
var typeListeners=this._listeners[type];var pos=typeListeners.indexOf(listener);if(pos===-1){return;}
typeListeners.splice(pos,1);};function getPluralRule(lang){var 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;}
var 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';}};var index=locales2rules[lang.replace(/-.*$/,'')];if(!(index in pluralRules)){return function(){return'other';};}
return pluralRules[index];}
var MAX_PLACEABLES=100;var PropertiesParser={patterns:null,entryIds: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(ctx,source){if(!this.patterns){this.init();}
var ast=[];this.entryIds=Object.create(null);var entries=source.match(this.patterns.entries);if(!entries){return ast;}
for(var i=0;i<entries.length;i++){var line=entries[i];if(this.patterns.comment.test(line)){continue;}
while(this.patterns.multiline.test(line)&&i<entries.length){line=line.slice(0,-1)+entries[++i].trim();}
var entityMatch=line.match(this.patterns.entity);if(entityMatch){try{this.parseEntity(entityMatch[1],entityMatch[2],ast);}catch(e){if(ctx){ctx._emitter.emit('parseerror',e);}else{throw e;}}}}
return ast;},parseEntity:function(id,value,ast){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 new L10nError('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 new L10nError('Attribute can\'t start with "$"',id);}}else{attr=null;}
this.setEntityValue(name,attr,key,this.unescapeString(value),ast);},setEntityValue:function(id,attr,key,rawValue,ast){var pos,v;var value=rawValue.indexOf('{{')>-1?this.parseString(rawValue):rawValue;if(attr){pos=this.entryIds[id];if(pos===undefined){v={$i:id};if(key){v[attr]={};v[attr][key]=value;}else{v[attr]=value;}
ast.push(v);this.entryIds[id]=ast.length-1;return;}
if(key){if(typeof(ast[pos][attr])==='string'){ast[pos][attr]={$x:this.parseIndex(ast[pos][attr]),$v:{}};}
ast[pos][attr].$v[key]=value;return;}
ast[pos][attr]=value;return;}
if(key){pos=this.entryIds[id];if(pos===undefined){v={};v[key]=value;ast.push({$i:id,$v:v});this.entryIds[id]=ast.length-1;return;}
if(typeof(ast[pos].$v)==='string'){ast[pos].$x=this.parseIndex(ast[pos].$v);ast[pos].$v={};}
ast[pos].$v[key]=value;return;}
ast.push({$i:id,$v:value});this.entryIds[id]=ast.length-1;},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 new L10nError('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({t:'idOrVar',v: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 unescape('%u'+'0000'.slice(token.length)+token);});},parseIndex:function(str){var match=str.match(this.patterns.index);if(!match){throw new L10nError('Malformed index');}
if(match[2]){return[{t:'idOrVar',v:match[1]},match[2]];}else{return[{t:'idOrVar',v:match[1]}];}}};var KNOWN_MACROS=['plural'];var MAX_PLACEABLE_LENGTH=2500;var rePlaceables=/\{\{\s*(.+?)\s*\}\}/g;var nonLatin1=/[^\x01-\xFF]/;var FSI='\u2068';var PDI='\u2069';function createEntry(node,env){var keys=Object.keys(node);if(typeof node.$v==='string'&&keys.length===2){return node.$v;}
var attrs;for(var i=0,key;key=keys[i];i++){if(key[0]==='$'){continue;}
if(!attrs){attrs=Object.create(null);}
attrs[key]=createAttribute(node[key],env,node.$i+'.'+key);}
return{id:node.$i,value:node.$v!==undefined?node.$v:null,index:node.$x||null,attrs:attrs||null,env:env,dirty:false};}
function createAttribute(node,env,id){if(typeof node==='string'){return node;}
return{id:id,value:node.$v||(node!==undefined?node:null),index:node.$x||null,env:env,dirty:false};}
function format(args,entity){if(typeof entity==='string'){return[{},entity];}
if(entity.dirty){throw new L10nError('Cyclic reference detected: '+entity.id);}
entity.dirty=true;var rv;try{rv=resolveValue({},args,entity.env,entity.value,entity.index);}finally{entity.dirty=false;}
return rv;}
function resolveIdentifier(args,env,id){if(KNOWN_MACROS.indexOf(id)>-1){return[{},env['__'+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 in env&&id!=='__proto__'){return format(args,env[id]);}
throw new L10nError('Unknown reference: '+id);}
function subPlaceable(locals,args,env,id){var res;try{res=resolveIdentifier(args,env,id);}catch(err){return[{error:err},'{{ '+id+' }}'];}
var value=res[1];if(typeof value==='number'){return res;}
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+')');}
if(locals.contextIsNonLatin1||value.match(nonLatin1)){res[1]=FSI+value+PDI;}
return res;}
return[{},'{{ '+id+' }}'];}
function interpolate(locals,args,env,arr){return arr.reduce(function(prev,cur){if(typeof cur==='string'){return[prev[0],prev[1]+cur];}else if(cur.t==='idOrVar'){var placeable=subPlaceable(locals,args,env,cur.v);return[prev[0],prev[1]+placeable[1]];}},[locals,'']);}
function resolveSelector(args,env,expr,index){var selectorName=index[0].v;var selector=resolveIdentifier(args,env,selectorName)[1];if(typeof selector!=='function'){return selector;}
var argValue=index[1]?resolveIdentifier(args,env,index[1])[1]:undefined;if(selector===env.__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,args,env,expr,index){if(!expr){return[locals,expr];}
if(typeof expr==='string'||typeof expr==='boolean'||typeof expr==='number'){return[locals,expr];}
if(Array.isArray(expr)){locals.contextIsNonLatin1=expr.some(function($_){return typeof($_)==='string'&&$_.match(nonLatin1);});return interpolate(locals,args,env,expr);}
if(index){var selector=resolveSelector(args,env,expr,index);if(expr.hasOwnProperty(selector)){return resolveValue(locals,args,env,expr[selector]);}}
if('other'in expr){return resolveValue(locals,args,env,expr.other);}
throw new L10nError('Unresolvable value');}
var Resolver={createEntry:createEntry,format:format,rePlaceables:rePlaceables};function walkContent(node,fn){if(typeof node==='string'){return fn(node);}
if(node.t==='idOrVar'){return node;}
var rv=Array.isArray(node)?[]:{};var keys=Object.keys(node);for(var i=0,key;(key=keys[i]);i++){if(key==='$i'||key==='$x'){rv[key]=node[key];}else{rv[key]=walkContent(node[key],fn);}}
return rv;}
var reAlphas=/[a-zA-Z]/g;var reVowels=/[aeiouAEIOU]/g;var ACCENTED_MAP='\u0226\u0181\u0187\u1E12\u1E16\u0191\u0193\u0126\u012A'+'\u0134\u0136\u013F\u1E3E\u0220\u01FE\u01A4\u024A\u0158'+'\u015E\u0166\u016C\u1E7C\u1E86\u1E8A\u1E8E\u1E90'+'[\\]^_`'+'\u0227\u0180\u0188\u1E13\u1E17\u0192\u0260\u0127\u012B'+'\u0135\u0137\u0140\u1E3F\u019E\u01FF\u01A5\u024B\u0159'+'\u015F\u0167\u016D\u1E7D\u1E87\u1E8B\u1E8F\u1E91';var FLIPPED_MAP='\u2200\u0510\u2183p\u018E\u025F\u05E4HI\u017F'+'\u04FC\u02E5WNO\u0500\xD2\u1D1AS\u22A5\u2229\u0245'+'\uFF2DX\u028EZ'+'[\\]\u1D65_,'+'\u0250q\u0254p\u01DD\u025F\u0183\u0265\u0131\u027E'+'\u029E\u0285\u026Fuodb\u0279s\u0287n\u028C\u028Dx\u028Ez';function makeLonger(val){return val.replace(reVowels,function(match){return match+match.toLowerCase();});}
function replaceChars(map,val){return val.replace(reAlphas,function(match){return map.charAt(match.charCodeAt(0)-65);});}
var reWords=/[^\W0-9_]+/g;function makeRTL(val){return val.replace(reWords,function(match){return'\u202e'+match+'\u202c';});}
var reExcluded=/(%[EO]?\w|\{\s*.+?\s*\}|&[#\w]+;|<\s*.+?\s*>)/;function mapContent(fn,val){if(!val){return val;}
var parts=val.split(reExcluded);var modified=parts.map(function(part){if(reExcluded.test(part)){return part;}
return fn(part);});return modified.join('');}
function Pseudo(id,name,charMap,modFn){this.id=id;this.translate=mapContent.bind(null,function(val){return replaceChars(charMap,modFn(val));});this.name=this.translate(name);}
var PSEUDO={'fr-x-psaccent':new Pseudo('fr-x-psaccent','Runtime Accented',ACCENTED_MAP,makeLonger),'ar-x-psbidi':new Pseudo('ar-x-psbidi','Runtime Bidi',FLIPPED_MAP,makeRTL)};function Locale(id,ctx){this.id=id;this.ctx=ctx;this.isReady=false;this.entries=Object.create(null);this.entries.__plural=getPluralRule(this.isPseudo()?this.ctx.defaultLocale:id);}
Locale.prototype.isPseudo=function(){return this.ctx.qps.indexOf(this.id)!==-1;};var bindingsIO={extra:function(id,ver,path,type,callback,errback){if(type==='properties'){type='text';}
navigator.mozApps.getLocalizationResource(id,ver,path,type).then(callback.bind(null,null),errback);},app:function(id,ver,path,type,callback,errback,sync){switch(type){case'properties':io.load(path,callback,sync);break;case'json':io.loadJSON(path,callback,sync);break;}},};Locale.prototype.build=function L_build(callback){var sync=!callback;var ctx=this.ctx;var self=this;var l10nLoads=ctx.resLinks.length;function onL10nLoaded(err){if(err){ctx._emitter.emit('fetcherror',err);}
if(--l10nLoads<=0){self.isReady=true;if(callback){callback();}}}
if(l10nLoads===0){onL10nLoaded();return;}
function onJSONLoaded(err,json){if(!err&&json){self.addAST(json);}
onL10nLoaded(err);}
function onPropLoaded(err,source){if(!err&&source){var ast=PropertiesParser.parse(ctx,source);self.addAST(ast);}
onL10nLoaded(err);}
var idToFetch=this.isPseudo()?ctx.defaultLocale:this.id;var appVersion=null;var source='app';if(typeof(navigator)!=='undefined'){source=navigator.mozL10n._config.localeSources[this.id]||'app';appVersion=navigator.mozL10n._config.appVersion;}
for(var i=0;i<ctx.resLinks.length;i++){var resLink=decodeURI(ctx.resLinks[i]);var path=resLink.replace('{locale}',idToFetch);var type=path.substr(path.lastIndexOf('.')+1);var cb;switch(type){case'json':cb=onJSONLoaded;break;case'properties':cb=onPropLoaded;break;}
bindingsIO[source](this.id,appVersion,path,type,cb,onL10nLoaded,sync);}};function createPseudoEntry(node,entries){return Resolver.createEntry(walkContent(node,PSEUDO[this.id].translate),entries);}
Locale.prototype.addAST=function(ast){var createEntry=this.isPseudo()?createPseudoEntry.bind(this):Resolver.createEntry;for(var i=0;i<ast.length;i++){this.entries[ast[i].$i]=createEntry(ast[i],this.entries);}};function Context(id){this.id=id;this.isReady=false;this.isLoading=false;this.defaultLocale='en-US';this.availableLocales=[];this.supportedLocales=[];this.qps=[];this.resLinks=[];this.locales={};this._emitter=new EventEmitter();this._ready=new Promise(this.once.bind(this));}
function reportMissing(id,err){this._emitter.emit('notfounderror',err);return id;}
function getWithFallback(id){var cur=0;var loc;var locale;while(loc=this.supportedLocales[cur]){locale=this.getLocale(loc);if(!locale.isReady){locale.build(null);}
var entry=locale.entries[id];if(entry===undefined){cur++;reportMissing.call(this,id,new L10nError('"'+id+'"'+' not found in '+loc+' in '+this.id,id,loc));continue;}
return entry;}
throw new L10nError('"'+id+'"'+' missing from all supported locales in '+this.id,id);}
function formatTuple(args,entity){try{return Resolver.format(args,entity);}catch(err){this._emitter.emit('resolveerror',err);var locals={error:err};return[locals,entity.id];}}
function formatValue(args,entity){if(typeof entity==='string'){return entity;}
return formatTuple.call(this,args,entity)[1];}
function formatEntity(args,entity){var entityTuple=formatTuple.call(this,args,entity);var value=entityTuple[1];var formatted={value:value,attrs:null,};if(entity.attrs){formatted.attrs=Object.create(null);}
for(var key in entity.attrs){var attrTuple=formatTuple.call(this,args,entity.attrs[key]);formatted.attrs[key]=attrTuple[1];}
return formatted;}
function formatAsync(fn,id,args){return this._ready.then(getWithFallback.bind(this,id)).then(fn.bind(this,args),reportMissing.bind(this,id));}
Context.prototype.formatValue=function(id,args){return formatAsync.call(this,formatValue,id,args);};Context.prototype.formatEntity=function(id,args){return formatAsync.call(this,formatEntity,id,args);};function legacyGet(fn,id,args){if(!this.isReady){throw new L10nError('Context not ready');}
var entry;try{entry=getWithFallback.call(this,id);}catch(err){if(err.loc){throw err;}
reportMissing.call(this,id,err);return'';}
return fn.call(this,args,entry);}
Context.prototype.get=function(id,args){return legacyGet.call(this,formatValue,id,args);};Context.prototype.getEntity=function(id,args){return legacyGet.call(this,formatEntity,id,args);};Context.prototype.getLocale=function getLocale(code){var locales=this.locales;if(locales[code]){return locales[code];}
return locales[code]=new Locale(code,this);};function negotiate(available,requested,defaultLocale){var supportedLocale;for(var i=0;i<requested.length;i++){var locale=requested[i];if(available.indexOf(locale)!==-1){supportedLocale=locale;break;}}
if(!supportedLocale||supportedLocale===defaultLocale){return[defaultLocale];}
return[supportedLocale,defaultLocale];}
function freeze(supported){var locale=this.getLocale(supported[0]);if(locale.isReady){setReady.call(this,supported);}else{locale.build(setReady.bind(this,supported));}}
function setReady(supported){this.supportedLocales=supported;this.isReady=true;this._emitter.emit('ready');}
Context.prototype.registerLocales=function(defLocale,available){if(defLocale){this.defaultLocale=defLocale;}
this.availableLocales=[this.defaultLocale];this.qps=Object.keys(PSEUDO);if(available){for(var i=0,loc;loc=available[i];i++){if(this.availableLocales.indexOf(loc)===-1){this.availableLocales.push(loc);var pos=this.qps.indexOf(loc);if(pos!==-1){this.qps.splice(pos,1);}}}}};Context.prototype.requestLocales=function requestLocales(){if(this.isLoading&&!this.isReady){throw new L10nError('Context not ready');}
this.isLoading=true;var requested=Array.prototype.slice.call(arguments);if(requested.length===0){throw new L10nError('No locales requested');}
var supported=negotiate(this.availableLocales.concat(this.qps),requested,this.defaultLocale);if(this.supportedLocales[0]!==supported[0]){freeze.call(this,supported);}};Context.prototype.addEventListener=function(type,listener){this._emitter.addEventListener(type,listener);};Context.prototype.removeEventListener=function(type,listener){this._emitter.removeEventListener(type,listener);};Context.prototype.ready=function(callback){if(this.isReady){setTimeout(callback);}
this.addEventListener('ready',callback);};Context.prototype.once=function(callback){if(this.isReady){setTimeout(callback);return;}
var callAndRemove=(function(){this.removeEventListener('ready',callAndRemove);callback();}).bind(this);this.addEventListener('ready',callAndRemove);};var 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']}};var rtlList=['ar','he','fa','ps','ar-x-psbidi','ur'];var nodeObserver=null;var pendingElements=null;var moConfig={attributes:true,characterData:false,childList:true,subtree:true,attributeFilter:['data-l10n-id','data-l10n-args']};navigator.mozL10n={ctx:null,get:function get(id,ctxdata){return navigator.mozL10n.ctx.get(id,ctxdata);},formatValue:function(id,ctxdata){return navigator.mozL10n.ctx.formatValue(id,ctxdata);},formatEntity:function(id,ctxdata){return navigator.mozL10n.ctx.formatEntity(id,ctxdata);},translateFragment:function(fragment){return translateFragment.call(navigator.mozL10n,fragment);},setAttributes:setL10nAttributes,getAttributes:getL10nAttributes,ready:function ready(callback){return navigator.mozL10n.ctx.ready(callback);},once:function once(callback){return navigator.mozL10n.ctx.once(callback);},get readyState(){return navigator.mozL10n.ctx.isReady?'complete':'loading';},language:{set code(lang){navigator.mozL10n.ctx.requestLocales(lang);},get code(){return navigator.mozL10n.ctx.supportedLocales[0];},get direction(){return getDirection(navigator.mozL10n.ctx.supportedLocales[0]);}},qps:PSEUDO,_config:{appVersion:null,localeSources:Object.create(null),isPretranslated:false,},_getInternalAPI:function(){return{Error:L10nError,Context:Context,Locale:Locale,Resolver:Resolver,getPluralRule:getPluralRule,rePlaceables:rePlaceables,translateDocument:translateDocument,onMetaInjected:onMetaInjected,PropertiesParser:PropertiesParser,walkContent:walkContent,buildLocaleList:buildLocaleList};}};function getDirection(lang){return(rtlList.indexOf(lang)>=0)?'rtl':'ltr';}
var readyStates={loading:0,interactive:1,complete:2};function whenInteractive(callback){if(readyStates[document.readyState]>=readyStates.interactive){callback();return;}
document.addEventListener('readystatechange',function l10n_onrsc(){if(readyStates[document.readyState]>=readyStates.interactive){document.removeEventListener('readystatechange',l10n_onrsc);callback();}});}
function initObserver(){nodeObserver=new MutationObserver(onMutations.bind(navigator.mozL10n));nodeObserver.observe(document,moConfig);}
function init(pretranslate){if(!pretranslate){initObserver();}
initResources.call(navigator.mozL10n);}
function initResources(){var meta={};var nodes=document.head.querySelectorAll('link[rel="localization"],'+'meta[name="availableLanguages"],'+'meta[name="defaultLanguage"],'+'meta[name="appVersion"],'+'script[type="application/l10n"]');for(var i=0,node;node=nodes[i];i++){var type=node.getAttribute('rel')||node.nodeName.toLowerCase();switch(type){case'localization':this.ctx.resLinks.push(node.getAttribute('href'));break;case'meta':onMetaInjected.call(this,node,meta);break;case'script':onScriptInjected.call(this,node);break;}}
var additionalLanguagesPromise;if(navigator.mozApps&&navigator.mozApps.getAdditionalLanguages){additionalLanguagesPromise=navigator.mozApps.getAdditionalLanguages().catch(function(e){console.error('Error while loading getAdditionalLanguages',e);});document.addEventListener('additionallanguageschange',function(evt){registerLocales.call(this,meta,evt.detail);this.ctx.requestLocales.apply(this.ctx,navigator.languages||[navigator.language]);}.bind(this));}else{additionalLanguagesPromise=Promise.resolve();}
additionalLanguagesPromise.then(function(extraLangs){registerLocales.call(this,meta,extraLangs);initLocale.call(this);}.bind(this));}
function registerLocales(meta,extraLangs){var locales=buildLocaleList.call(this,meta,extraLangs);navigator.mozL10n._config.localeSources=locales[1];this.ctx.registerLocales(locales[0],Object.keys(locales[1]));}
function getMatchingLangpack(appVersion,langpacks){for(var i=0,langpack;(langpack=langpacks[i]);i++){if(langpack.target===appVersion){return langpack;}}
return null;}
function buildLocaleList(meta,extraLangs){var loc,lp;var localeSources=Object.create(null);var defaultLocale=meta.defaultLanguage||this.ctx.defaultLocale;if(meta.availableLanguages){for(loc in meta.availableLanguages){localeSources[loc]='app';}}
if(extraLangs){for(loc in extraLangs){lp=getMatchingLangpack(this._config.appVersion,extraLangs[loc]);if(!lp){continue;}
if(!(loc in localeSources)||!meta.availableLanguages[loc]||parseInt(lp.revision)>meta.availableLanguages[loc]){localeSources[loc]='extra';}}}
if(!(defaultLocale in localeSources)){localeSources[defaultLocale]='app';}
return[defaultLocale,localeSources];}
function splitAvailableLanguagesString(str){var langs={};str.split(',').forEach(function(lang){lang=lang.trim().split(':');langs[lang[0]]=parseInt(lang[1]);});return langs;}
function onMetaInjected(node,meta){switch(node.getAttribute('name')){case'availableLanguages':meta.availableLanguages=splitAvailableLanguagesString(node.getAttribute('content'));break;case'defaultLanguage':meta.defaultLanguage=node.getAttribute('content');break;case'appVersion':navigator.mozL10n._config.appVersion=node.getAttribute('content');break;}}
function onScriptInjected(node){var lang=node.getAttribute('lang');var locale=this.ctx.getLocale(lang);locale.addAST(JSON.parse(node.textContent));}
function initLocale(){this.ctx.requestLocales.apply(this.ctx,navigator.languages||[navigator.language]);window.addEventListener('languagechange',function l10n_langchange(){this.ctx.requestLocales.apply(this.ctx,navigator.languages||[navigator.language]);}.bind(this));}
function localizeMutations(mutations){var mutation;var targets=new Set();for(var i=0;i<mutations.length;i++){mutation=mutations[i];if(mutation.type==='childList'){var addedNode;for(var j=0;j<mutation.addedNodes.length;j++){addedNode=mutation.addedNodes[j];if(addedNode.nodeType!==Node.ELEMENT_NODE){continue;}
targets.add(addedNode);}}
if(mutation.type==='attributes'){targets.add(mutation.target);}}
targets.forEach(function(target){if(target.childElementCount){translateFragment.call(this,target);}else if(target.hasAttribute('data-l10n-id')){translateElement.call(this,target);}},this);}
function onMutations(mutations,self){self.disconnect();localizeMutations.call(this,mutations);self.observe(document,moConfig);}
function onReady(){if(!navigator.mozL10n._config.isPretranslated){translateDocument.call(this);}
navigator.mozL10n._config.isPretranslated=false;if(pendingElements){for(var i=0,element;element=pendingElements[i];i++){translateElement.call(this,element);}
pendingElements=null;}
if(!nodeObserver){initObserver();}
fireLocalizedEvent.call(this);}
function fireLocalizedEvent(){var event=new CustomEvent('localized',{'bubbles':false,'cancelable':false,'detail':{'language':this.ctx.supportedLocales[0]}});window.dispatchEvent(event);}
var reOverlay=/<|&#?\w+;/;var reHtml=/[&<>]/g;var htmlEntities={'&':'&amp;','<':'&lt;','>':'&gt;',};function translateDocument(){document.documentElement.lang=this.language.code;document.documentElement.dir=this.language.direction;translateFragment.call(this,document.documentElement);}
function translateFragment(element){if(typeof element.hasAttribute==='function'&&element.hasAttribute('data-l10n-id')){translateElement.call(this,element);}
var nodes=getTranslatableChildren(element);for(var i=0;i<nodes.length;i++){translateElement.call(this,nodes[i]);}}
function setL10nAttributes(element,id,args){element.setAttribute('data-l10n-id',id);if(args){element.setAttribute('data-l10n-args',JSON.stringify(args));}}
function getL10nAttributes(element){return{id:element.getAttribute('data-l10n-id'),args:JSON.parse(element.getAttribute('data-l10n-args'))};}
function getTranslatableChildren(element){return element?element.querySelectorAll('*[data-l10n-id]'):[];}
function camelCaseToDashed(string){if(string==='ariaValueText'){return'aria-valuetext';}
return string.replace(/[A-Z]/g,function(match){return'-'+match.toLowerCase();}).replace(/^-/,'');}
function escapeL10nArgs(match){return htmlEntities[match];}
function translateElement(element){if(!this.ctx.isReady){if(!pendingElements){pendingElements=[];}
pendingElements.push(element);return;}
var l10nId=element.getAttribute('data-l10n-id');if(!l10nId){return false;}
var l10nArgs=element.getAttribute('data-l10n-args');var entity=this.ctx.getEntity(l10nId,l10nArgs?JSON.parse(l10nArgs.replace(reHtml,escapeL10nArgs)):undefined);var value=entity.value;if(typeof value==='string'){if(!reOverlay.test(value)){element.textContent=value;}else{var translation=element.ownerDocument.createElement('template');translation.innerHTML=value;overlayElement(element,translation.content);}}
for(var key in entity.attrs){var attrName=camelCaseToDashed(key);if(isAttrAllowed({name:attrName},element)){element.setAttribute(attrName,entity.attrs[key]);}}}
function overlayElement(sourceElement,translationElement){var result=translationElement.ownerDocument.createDocumentFragment();var k,attr;var childElement;while((childElement=translationElement.childNodes[0])){translationElement.removeChild(childElement);if(childElement.nodeType===Node.TEXT_NODE){result.appendChild(childElement);continue;}
var index=getIndexOfType(childElement);var sourceChild=getNthElementOfType(sourceElement,childElement,index);if(sourceChild){overlayElement(sourceChild,childElement);result.appendChild(sourceChild);continue;}
if(isElementAllowed(childElement)){var sanitizedChild=childElement.ownerDocument.createElement(childElement.nodeName);overlayElement(sanitizedChild,childElement);result.appendChild(sanitizedChild);continue;}
result.appendChild(document.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){var attrName=attr.name.toLowerCase();var 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'){var type=element.type.toLowerCase();if(type==='submit'||type==='button'||type==='reset'){return true;}}
return false;}
function getNthElementOfType(context,element,index){var nthOfType=0;for(var i=0,child;child=context.children[i];i++){if(child.nodeType===Node.ELEMENT_NODE&&child.tagName===element.tagName){if(nthOfType===index){return child;}
nthOfType++;}}
return null;}
function getIndexOfType(element){var index=0;var child;while((child=element.previousElementSibling)){if(child.tagName===element.tagName){index++;}}
return index;}
var DEBUG=false;navigator.mozL10n.ctx=new Context(window.document?document.URL:null);navigator.mozL10n.ctx.ready(onReady.bind(navigator.mozL10n));navigator.mozL10n.ctx.addEventListener('notfounderror',function reportMissingEntity(e){if(DEBUG||e.loc==='en-US'){console.warn(e.toString());}});if(DEBUG){navigator.mozL10n.ctx.addEventListener('fetcherror',console.error.bind(console));navigator.mozL10n.ctx.addEventListener('parseerror',console.error.bind(console));navigator.mozL10n.ctx.addEventListener('resolveerror',console.error.bind(console));}
if(window.document){navigator.mozL10n._config.isPretranslated=document.documentElement.lang===navigator.language;var forcePretranslate=!navigator.mozL10n._config.isPretranslated;whenInteractive(init.bind(navigator.mozL10n,forcePretranslate));}
document.l10n={setAttributes:navigator.mozL10n.setAttributes,getAttributes:navigator.mozL10n.getAttributes,formatValue:function(id,args){return navigator.mozL10n.formatValue(id,args);},translateFragment:function(frag){return Promise.resolve(navigator.mozL10n.translateFragment(frag));},ready:new Promise(function(resolve){navigator.mozL10n.once(resolve);}),formatValues:function(){var keys=arguments;var resp=keys.map(function(key){if(Array.isArray(key)){return navigator.mozL10n.formatValue(key[0],key[1]);}
return navigator.mozL10n.formatValue(key);});return Promise.all(resp);},requestLanguages:function(langs){navigator.mozL10n.ctx.requestLocales.apply(navigator.mozL10n.ctx,langs);},pseudo:{'fr-x-psaccent':{getName:function(){return Promise.resolve(navigator.mozL10n.qps['fr-x-psaccent'].name);},processString:function(s){return Promise.resolve(navigator.mozL10n.qps['fr-x-psaccent'].translate(s));}},'ar-x-psbidi':{getName:function(){return Promise.resolve(navigator.mozL10n.qps['ar-x-psbidi'].name);},processString:function(s){return Promise.resolve(navigator.mozL10n.qps['ar-x-psbidi'].translate(s));}}},};navigator.mozL10n.ready(function(){document.documentElement.setAttribute('langs',navigator.mozL10n.ctx.supportedLocales.join(' '));});navigator.mozL10n.once(function(){window.addEventListener('localized',function(){document.dispatchEvent(new CustomEvent('DOMRetranslated',{bubbles:false,cancelable:false}));});});})(this);;;;'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();}());;'use strict';window.addEventListener('DOMContentLoaded',function(){LazyLoader.load(['/shared/js/l10n.js']).then(function(){});});window.onload=function(){var dependencies=['/shared/js/contact_photo_helper.js','/shared/js/sanitizer.js','/shared/js/contacts/import/utilities/misc.js','/contacts/views/matching/js/matching_ui.js'];window.screen.mozLockOrientation('portrait-primary');LazyLoader.load(dependencies).then(function(){MatchingUI.init();});};;'use strict';(function(exports){var CONTACTS_APP_ORIGIN=location.origin;var contact=null,matchings={};var type='matching';var parentWindow=null;function start(cid){if(!cid){type='listing';window.addEventListener('message',duplicateContactsHandler);parentWindow.postMessage({type:'duplicate_contacts_loaded'},CONTACTS_APP_ORIGIN);return;}
Curtain.show('wait','duplicateContacts');var callbacks={onmatch:showUI,onmismatch:function(){Curtain.show('alert','noDuplicateContacts');Curtain.onok=abort;}};Curtain.oncancel=function oncancel(){callbacks.onmatch=callbacks.onmismatch=null;abort();};var matcherDependencies=['/shared/js/text_normalizer.js','/shared/js/simple_phone_matcher.js','/shared/js/contacts/contacts_matcher.js'];LazyLoader.load(matcherDependencies,function loaded(){setTimeout(function(){parentWindow.ContactsService.get(cid,function success(mContact){contact=mContact;Matcher.match(contact,'active',callbacks);},abort);},1000);});}
function duplicateContactsHandler(e){if(e.origin!==CONTACTS_APP_ORIGIN){return;}
var data=e.data;if(data&&data.type==='show_duplicate_contacts'){window.removeEventListener('message',duplicateContactsHandler);contact={name:[data.data.name]};var duplicateContacts=data.data.duplicateContacts;var total=Object.keys(duplicateContacts).length;var matchingReady=function(){if(--total===0){window.addEventListener('message',contactsMergedHandler);showUI(duplicateContacts);}};Object.keys(duplicateContacts).forEach(function(cid){parentWindow.ContactsService.get(cid,function success(contact){duplicateContacts[cid]={matchingContact:contact,matchings:duplicateContacts[cid].matchings};matchingReady();},matchingReady);});}else if(data&&data.type==='sync'){parentWindow=e.source;navigator.mozL10n.once(function localized(evt){start(window.location.search.substring('contactId'.length+2));});}}
function contactsMergedHandler(e){if(e.origin!==CONTACTS_APP_ORIGIN){return;}
if(e.data&&e.data.type==='duplicate_contacts_merged'){window.removeEventListener('message',contactsMergedHandler);Curtain.hide(function(){parentWindow.postMessage({type:'window_close',data:''},CONTACTS_APP_ORIGIN);});}}
function showUI(results){matchings=results;window.dispatchEvent(new CustomEvent('initUI',{'detail':{'type':type,'contact':contact,'results':results}}));window.addEventListener('UIReady',function fn(){window.removeEventListener('UIReady',fn);if(type==='matching'){Curtain.hide(sendReadyEvent,CONTACTS_APP_ORIGIN);}else{sendReadyEvent();}});}
function sendReadyEvent(){parentWindow.postMessage({type:'ready',data:''},CONTACTS_APP_ORIGIN);}
function abort(){var notifyParent=function cmc_notifyParent(){parentWindow.postMessage({type:'abort',data:''},CONTACTS_APP_ORIGIN);};Curtain.hide(notifyParent);}
function merge(checkedContacts){Curtain.show('wait','mergingDuplicateContacts');Curtain.hideMenu();if(type==='listing'){parentWindow.postMessage({type:'merge_duplicate_contacts',data:checkedContacts},CONTACTS_APP_ORIGIN);return;}
var MERGE_DEPS=['/contacts/js/utilities/merge_helper.js'];LazyLoader.load(MERGE_DEPS,function loaded(){var cb=function cb(){Curtain.hide(function(){parentWindow.postMessage({type:'window_close',data:''},CONTACTS_APP_ORIGIN);});};var list=[];Object.keys(checkedContacts).forEach(function(id){list.push(matchings[id]);});MergeHelper.merge(contact,list).then(cb,cb);});}
window.addEventListener('message',duplicateContactsHandler);window.addEventListener('merge',evt=>{merge(evt.detail.checkedContacts);});})(window);;'use strict';var Curtain=(function(){var cancelButton,retryButton,okButton,progressElement,progressTitle;var cpuWakeLock;var messages=[];var elements=['error','timeout','wait','message','progress','alert'];var _cancelCB=function foo(){};var _retryCB=function foo(){};var _okCB=function foo(){};var form;var panel=document.createElement('panel');panel.id='curtain';var link=document.createElement('link');link.setAttribute('rel','import');link.setAttribute('href','/shared/pages/import/elements/curtain.html');function addListeners(){okButton.onclick=function on_ok(e){delete okButton.onclick;_okCB();_okCB=null;};retryButton.onclick=function on_retry(e){delete retryButton.onclick;_retryCB();_retryCB=null;};cancelButton.onclick=function on_cancel(e){delete cancelButton.onclick;_cancelCB();_cancelCB=null;};}
function cacheElements(){cancelButton=document.querySelector('#cancel');retryButton=document.querySelector('#retry');okButton=document.querySelector('#ok');progressElement=document.querySelector('#progressElement');elements.forEach(function createElementRef(name){messages[name]=document.getElementById(name+'Msg');});progressTitle=document.getElementById('progressTitle');}
function init(){return new Promise(function(resolve,reject){document.head.appendChild(link);panel.setAttribute('is','curtain');panel.className='fade-out';document.body.appendChild(panel);LazyLoader.load([document.getElementById('curtain')],function(){cacheElements();addListeners();resolve();});});}
function clean(){document.body.removeChild(panel);form=null;cancelButton=null;retryButton=null;okButton=null;progressElement=null;progressTitle=null;}
function doShow(type){if(!form){form=panel.querySelector('form');}
form.dataset.state=type;panel.classList.remove('no-menu');panel.classList.add('visible');panel.classList.remove('fade-out');if(type!=='alert'){panel.classList.add('fade-in');}}
function capitalize(str){return str.charAt(0).toUpperCase()+str.slice(1);}
function Progress(pfrom){var from=pfrom;var counter=0;var total=0;progressElement.setAttribute('value',0);function showMessage(){navigator.mozL10n.setAttributes(messages.progress,'progressFB',{current:counter,total:total});}
this.update=function(){progressElement.setAttribute('value',(++counter*100)/total);showMessage();};this.setFrom=function(pfrom){from=capitalize(pfrom);progressTitle.setAttribute('data-l10n-id','progressFB3'+from+'Title');};this.setTotal=function(ptotal){total=ptotal;showMessage();};this.getValue=function(){return counter;};}
return{show:function(type,from){init().then(function(){var out;from=capitalize(from);switch(type){case'wait':messages[type].setAttribute('data-l10n-id',type+from);break;case'timeout':navigator.mozL10n.formatValue('timeout'+from).then(from=>{navigator.mozL10n.setAttributes(messages[type],'timeout1',{from:from});});break;case'error':navigator.mozL10n.formatValue(type+from).then(from=>{navigator.mozL10n.setAttributes(messages[type],'error1',{from:from});});break;case'alert':case'message':messages[type].setAttribute('data-l10n-id',type+from);break;case'progress':progressTitle.setAttribute('data-l10n-id',type+'FB3'+from+'Title');out=new Progress(from);cpuWakeLock=navigator.requestWakeLock('cpu');break;}
doShow(type);return out;});},hide:function c_hide(hiddenCB){if(cpuWakeLock){cpuWakeLock.unlock();cpuWakeLock=null;}
panel.classList.add('fade-out');panel.addEventListener('animationend',function cu_fadeOut(ev){panel.removeEventListener('animationend',cu_fadeOut);delete form.dataset.state;clean();if(typeof hiddenCB==='function'){hiddenCB();}});},set oncancel(cancelCb){if(typeof cancelCb==='function'){_cancelCB=cancelCb;}else{_cancelCB=function foo(){};}},set onretry(retryCb){if(typeof retryCb==='function'){_retryCB=retryCb;}else{_retryCB=function foo(){};}},set onok(okCb){if(typeof okCb==='function'){_okCB=okCb;}else{_okCB=function foo(){};}},get visible(){return panel.classList.contains('visible');},hideMenu:function c_hideMenu(){panel.classList.add('no-menu');}};})();

View file

@ -0,0 +1 @@
;'use strict';window.addEventListener('DOMContentLoaded',function(){LazyLoader.load(['/shared/js/l10n.js']).then(function(){});});window.onload=function(){var dependencies=['/shared/js/contact_photo_helper.js','/shared/js/sanitizer.js','/shared/js/contacts/import/utilities/misc.js','/contacts/views/matching/js/matching_ui.js'];window.screen.mozLockOrientation('portrait-primary');LazyLoader.load(dependencies).then(function(){MatchingUI.init();});};

View file

@ -0,0 +1,12 @@
;'use strict';(function(exports){var CONTACTS_APP_ORIGIN=location.origin;var contact=null,matchings={};var type='matching';var parentWindow=null;function start(cid){if(!cid){type='listing';window.addEventListener('message',duplicateContactsHandler);parentWindow.postMessage({type:'duplicate_contacts_loaded'},CONTACTS_APP_ORIGIN);return;}
Curtain.show('wait','duplicateContacts');var callbacks={onmatch:showUI,onmismatch:function(){Curtain.show('alert','noDuplicateContacts');Curtain.onok=abort;}};Curtain.oncancel=function oncancel(){callbacks.onmatch=callbacks.onmismatch=null;abort();};var matcherDependencies=['/shared/js/text_normalizer.js','/shared/js/simple_phone_matcher.js','/shared/js/contacts/contacts_matcher.js'];LazyLoader.load(matcherDependencies,function loaded(){setTimeout(function(){parentWindow.ContactsService.get(cid,function success(mContact){contact=mContact;Matcher.match(contact,'active',callbacks);},abort);},1000);});}
function duplicateContactsHandler(e){if(e.origin!==CONTACTS_APP_ORIGIN){return;}
var data=e.data;if(data&&data.type==='show_duplicate_contacts'){window.removeEventListener('message',duplicateContactsHandler);contact={name:[data.data.name]};var duplicateContacts=data.data.duplicateContacts;var total=Object.keys(duplicateContacts).length;var matchingReady=function(){if(--total===0){window.addEventListener('message',contactsMergedHandler);showUI(duplicateContacts);}};Object.keys(duplicateContacts).forEach(function(cid){parentWindow.ContactsService.get(cid,function success(contact){duplicateContacts[cid]={matchingContact:contact,matchings:duplicateContacts[cid].matchings};matchingReady();},matchingReady);});}else if(data&&data.type==='sync'){parentWindow=e.source;navigator.mozL10n.once(function localized(evt){start(window.location.search.substring('contactId'.length+2));});}}
function contactsMergedHandler(e){if(e.origin!==CONTACTS_APP_ORIGIN){return;}
if(e.data&&e.data.type==='duplicate_contacts_merged'){window.removeEventListener('message',contactsMergedHandler);Curtain.hide(function(){parentWindow.postMessage({type:'window_close',data:''},CONTACTS_APP_ORIGIN);});}}
function showUI(results){matchings=results;window.dispatchEvent(new CustomEvent('initUI',{'detail':{'type':type,'contact':contact,'results':results}}));window.addEventListener('UIReady',function fn(){window.removeEventListener('UIReady',fn);if(type==='matching'){Curtain.hide(sendReadyEvent,CONTACTS_APP_ORIGIN);}else{sendReadyEvent();}});}
function sendReadyEvent(){parentWindow.postMessage({type:'ready',data:''},CONTACTS_APP_ORIGIN);}
function abort(){var notifyParent=function cmc_notifyParent(){parentWindow.postMessage({type:'abort',data:''},CONTACTS_APP_ORIGIN);};Curtain.hide(notifyParent);}
function merge(checkedContacts){Curtain.show('wait','mergingDuplicateContacts');Curtain.hideMenu();if(type==='listing'){parentWindow.postMessage({type:'merge_duplicate_contacts',data:checkedContacts},CONTACTS_APP_ORIGIN);return;}
var MERGE_DEPS=['/contacts/js/utilities/merge_helper.js'];LazyLoader.load(MERGE_DEPS,function loaded(){var cb=function cb(){Curtain.hide(function(){parentWindow.postMessage({type:'window_close',data:''},CONTACTS_APP_ORIGIN);});};var list=[];Object.keys(checkedContacts).forEach(function(id){list.push(matchings[id]);});MergeHelper.merge(contact,list).then(cb,cb);});}
window.addEventListener('message',duplicateContactsHandler);window.addEventListener('merge',evt=>{merge(evt.detail.checkedContacts);});})(window);

View file

@ -0,0 +1,304 @@
'use strict';
/* global ContactPhotoHelper */
/* global ImageLoader */
/* global LazyLoader */
/* global Sanitizer */
/* jshint nonew: false */
/**
* This object handles every interaction between the user and the UI of the
* matching contacts view
*/
(function(exports) {
var CONTACTS_APP_ORIGIN = location.origin;
var listDependencies = [
'/shared/js/contacts/utilities/image_loader.js'
];
var MatchingUI = {
_: null,
// Counter for checked list items
checked: 0,
// Hash contains identifiers of checked contacts
checkedContacts: {},
// Field order when showing matching details main reason
fieldOrder: ['tel', 'email', 'name'],
init: function() {
this._ = navigator.mozL10n.get;
this.mergeButton = document.getElementById('merge-action');
if (!this.mergeButton) {
return;
}
this.duplicateMessage = document.querySelector('#duplicate-msg > p');
this.contactsList =
document.querySelector('#contacts-list-container > ol');
this.contactsList.addEventListener('click', this.onClick.bind(this)
, true);
this.mergeButton.addEventListener('click', this.onMerge.bind(this));
window.addEventListener('initUI', evt => {
this.load(evt.detail.type, evt.detail.contact, evt.detail.results);
});
},
/*
* Loads the UI that implements the merge of duplicate contacts
*
* @param{Object} Master contact
*
* @param{Object} Hash of matching contacts from Matcher module
*
*/
load: function(type, contact, results) {
this.matchingResults = results;
document.body.dataset.mode = type;
var contactName = this.getDisplayName(contact);
var params = { name: Sanitizer.escapeHTML `${contactName}` };
if (type === 'matching') {
// "Suggested duplicate contacts for xxx"
navigator.mozL10n.setAttributes(this.duplicateMessage,
'suggestedDuplicatesMessage',
params);
} else {
navigator.mozL10n.setAttributes(document.querySelector('title'),
'duplicatesFoundTitle');
// "xxx duplicates information in the following contacts"
navigator.mozL10n.setAttributes(this.duplicateMessage,
'foundDuplicatesMessage',
params);
}
// Rendering the duplicate contacts list
this.renderList(results);
},
templateDuplicateContact: function(contact) {
return Sanitizer.createSafeHTML `<li data-uuid="${contact.id}"
class="block-item">
<label class="pack-checkbox">
<input type="checkbox" checked>
<span></span>
</label>
<aside class="pack-end">
<img data-src="${contact.thumb}">
</aside>
<p>
<bdi class="ellipsis-dir-fix">${contact.displayName}</bdi>
</p>
<p class="match-main-reason">
<bdi class="ellipsis-dir-fix">${contact.mainReason}</bdi>
</p>
</li>`;
},
renderList: function(contacts) {
LazyLoader.load(listDependencies, () => {
// For each contact in the list
var contactsKeys = Object.keys(contacts);
contactsKeys.forEach(id => {
// New contact appended
this.checkedContacts[id] = id;
var contact = this.cookContact(contacts[id]);
// Use a template node so we can append it and also access the node
var item = document.createElement('template');
item.innerHTML =
Sanitizer.unwrapSafeHTML(this.templateDuplicateContact(contact));
this.contactsList.appendChild(item.content);
if (contact.email1 === '') {
var emailField = item.content.querySelector('p:last-child');
emailField && emailField.parentNode.removeChild(emailField);
}
});
this.checked = contactsKeys.length;
this.checkMergeButton();
new ImageLoader('#main', 'li');
setTimeout(() => {
window.dispatchEvent(new CustomEvent('UIReady'));
// Remove the hidden ui
document.body.classList.remove('ui-not-ready');
});
});
},
/*
* It creates a new copy becase it is forbidden to add new attributes to
* original contacts provided by the API
*
* @param(Object) Contact object provided by Gecko
*/
cookContact: function(matching) {
var contact = matching.matchingContact;
var reasons = matching.matchings || {};
var out = {};
this.populate(contact, out, Object.getOwnPropertyNames(contact));
this.populate(contact, out,
Object.getOwnPropertyNames(Object.getPrototypeOf(contact)));
out.displayName = this.getDisplayName(contact);
out.mainReason = this.selectMainReason(reasons);
var photo = ContactPhotoHelper.getThumbnail(out);
if (photo) {
out.thumb = window.URL.createObjectURL(photo);
}
return out;
},
getCompleteName: function(contact) {
var givenName = Array.isArray(contact.givenName) ?
contact.givenName[0] : '';
var familyName = Array.isArray(contact.familyName) ?
contact.familyName[0] : '';
var completeName = givenName && familyName ?
givenName + ' ' + familyName :
givenName || familyName;
return completeName;
},
// Fills the contact data to display if no givenName and familyName
getDisplayName: function(contact) {
if (this.hasName(contact)) {
return this.getCompleteName(contact);
}
var name = [];
if (Array.isArray(contact.name) && contact.name[0] &&
contact.name[0].trim()) {
name.push(contact.name[0]);
} else if (contact.org && contact.org[0] && contact.org[0].trim()) {
name.push(contact.org[0]);
} else if (contact.tel && contact.tel[0]) {
name.push(contact.tel[0].value);
} else if (contact.email && contact.email[0]) {
name.push(contact.email[0].value);
} else {
name.push(this._('noName'));
}
return name[0];
},
hasName: function(contact) {
return (Array.isArray(contact.givenName) && contact.givenName[0] &&
contact.givenName[0].trim()) ||
(Array.isArray(contact.familyName) && contact.familyName[0] &&
contact.familyName[0].trim());
},
selectMainReason: function(matchings) {
var out = '';
for (var j = 0; j < this.fieldOrder.length; j++) {
var aField = this.fieldOrder[j];
var theMatchings = matchings[aField];
if (Array.isArray(theMatchings) && theMatchings[0]) {
out = theMatchings[0].matchedValue;
if (out) {
break;
}
}
}
return out;
},
populate: function(source, target, propertyNames) {
propertyNames.forEach(function(property) {
var propertyValue = source[property];
if (propertyValue) {
target[property] = propertyValue;
}
});
},
onClose: function(e) {
e.stopPropagation();
e.preventDefault();
parent.postMessage({
type: 'window_close',
data: ''
}, CONTACTS_APP_ORIGIN);
},
onClick: function(e) {
e.stopPropagation();
e.preventDefault();
if (e.target.tagName === 'INPUT') {
return false;
}
var li = e.target.closest('li');
var uuid = li.dataset.uuid;
var el = li.querySelector('input');
if (el.checked) {
--this.checked;
delete this.checkedContacts[uuid];
} else {
++this.checked;
this.checkedContacts[uuid] = uuid;
}
// Change manually the status as we prevented this
el.checked = !el.checked;
this.checkMergeButton();
},
isMatch: function(matchings, aField, fieldValue) {
var noMatch = true;
if (matchings[aField]) {
// Using every to short circuit the checking when a match is found.
noMatch = matchings[aField].every(function(obj) {
var val = fieldValue.value || fieldValue;
if (obj.matchedValue === val) {
return false;
}
return true;
});
}
return !noMatch;
},
checkMergeButton: function() {
navigator.mozL10n.setAttributes(this.mergeButton,
'mergeActionButtonLabel',
{ n: this.checked });
this.mergeButton.disabled = (this.checked === 0);
},
onMerge: function(e) {
e.stopPropagation();
e.preventDefault();
window.dispatchEvent(new CustomEvent('merge', {
'detail': {
'checkedContacts': this.checkedContacts
}
}));
}
};
exports.MatchingUI = MatchingUI;
})(window);

View file

@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en-US" dir="ltr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<meta name="theme-color" content="#00b7b7">
<title data-l10n-id="mergeDuplicateTitle">Merge duplicates</title>
<meta name="defaultLanguage" content="en-US">
<meta name="availableLanguages" content="ar:201601260729, bg:201601260729, bn-BD:201601260729, ca:201601260729, cs:201601260729, da:201601260729, de:201601260729, el:201601260729, en-US:201601260729, es:201601260729, eu:201601260729, fr:201601260729, gl:201601260729, hr:201601260729, hu:201601260729, it:201601260729, ja:201601260729, km:201601260729, ko:201601260729, lt:201601260729, mk:201601260729, ms:201601260729, ne-NP:201601260729, nl:201601260729, pa:201601260729, pl:201601260729, pt-BR:201601260729, ro:201601260729, ru:201601260729, sk:201601260729, sq:201601260729, sr-Cyrl:201601260729, sr-Latn:201601260729, sv-SE:201601260729, tr:201601260729, zh-CN:201601260729, zh-TW:201601260729">
<link rel="localization" href="/locales-obj/contacts.views.matching.matching_contacts.{locale}.json">
<!-- <script type="text/javascript" src="/shared/js/l10n.js"></script> -->
<!-- <script type="text/javascript" src="/shared/js/lazy_loader.js"></script> -->
<!-- <script type="text/javascript" src="/contacts/views/matching/js/boot.js"></script> -->
<!-- <script type="text/javascript" src="/contacts/views/matching/js/matching_controller.js"></script> -->
<!-- <script type="text/javascript" src="/shared/pages/import/js/curtain_panel.js"></script> --><script src="./gaia_build_matching_contacts.js" type="text/javascript"></script>
<!-- Lazy loaded, when rendering duplicate list
<script type="text/javascript" src="/shared/js/contacts/utilities/image_loader.js"></script>
<script type="text/javascript" src="/shared/js/contacts/utilities/templates.js"></script>
<script defer src="/shared/js/sanitizer.js"></script>
-->
<!-- Lazy loaded, files needed for match&merge
<script type="text/javascript" src="/shared/js/text_normalizer.js"></script>
<script type="text/javascript" src="/shared/js/simple_phone_matcher.js"></script>
<script type="text/javascript" src="/shared/js/contacts/contacts_matcher.js"></script>
<script type="text/javascript" src="/shared/js/contacts/contacts_merger.js"></script>
-->
<!-- Building Blocks -->
<link href="/shared/style/switches.css" rel="stylesheet">
<link href="/shared/style/lists.css" rel="stylesheet">
<link href="/shared/style/confirm.css" rel="stylesheet">
<link href="/shared/style/animations.css" rel="stylesheet">
<link href="/shared/style/headers.css" rel="stylesheet">
<link href="/shared/style/progress_activity.css" rel="stylesheet">
<link href="/shared/pages/import/style/root.css" rel="stylesheet">
<link href="/shared/pages/import/style/curtain.css" rel="stylesheet">
<!-- Web Components -->
<!-- <script defer="" src="/shared/elements/config.js"></script> --><script src="./gaia_build_defer_matching_contacts.js" defer="" type="text/javascript"></script>
<!-- <link rel="stylesheet" type="text/css" href="/shared/elements/gaia-icons/gaia-icons.css" /> -->
<link rel="stylesheet" type="text/css" href="app://theme.gaiamobile.org/shared/elements/gaia-theme/gaia-theme.css">
<link rel="stylesheet" href="style/matching_contacts.css">
<!--<link rel="import" href="/shared/pages/import/elements/curtain.html">-->
<meta content="2.5" name="appVersion"></head>
<body role="application" class="skin-comms ui-not-ready">
<section role="region">
<section id="main">
<section id="duplicate-msg">
<p></p>
</section>
<!-- Contacts List Section -->
<section id="contacts-list-container" data-type="list" class="active">
<ol>
</ol>
</section> <!-- contacts-list-container -->
<form id="footer" role="dialog" data-type="confirm">
<menu>
<button id="merge-action" data-l10n-id="merge" class="danger full">Merge</button>
</menu>
</form>
</section> <!-- main -->
</section> <!-- role="section" -->
</body>
</html>

View file

@ -0,0 +1,128 @@
@import url("/contacts/style/root.css");
.hide, *[data-template] {
display: none;
}
#main {
position: fixed;
height: 100%;
width: calc(100% + 0.8rem);
overflow-x: hidden;
overflow-y: auto;
background: #F4F4F4;
}
#contacts-list-container.active li:not(:active):after {
display: none;
}
#contacts-list-container label {
left: 0;
}
#contacts-list-container > ol > li[data-uuid] {
display: block;
-moz-padding-start: 4rem;
border-top: none;
}
/*#contacts-list-container > ol > li[data-uuid] aside,
#contacts-list-container > ol > li[data-uuid] label,
#contacts-list-container > ol > li[data-uuid] p {
pointer-events: none;
}*/
#contacts-list-container > ol > li[data-uuid] aside > img {
box-shadow: none;
border: none;
}
#contacts-list-container > ol > li[data-uuid]:last-child {
border-bottom: none;
}
/* BB overrides */
.match-main-reason {
color: #008eab;
}
form[role="dialog"][data-type="edit"] #duplicate-msg > p {
color: #000;
overflow: visible;
white-space: normal;
}
form[role="dialog"][data-type="edit"] #main {
pointer-events: auto;
}
#duplicate-msg {
width: 100%;
z-index: 1;
padding: 0.4rem 0;
}
#duplicate-msg > p {
font-size: 1.8rem;
line-height: 2.2rem;
margin: 1rem 3rem;
}
#footer {
background: none;
pointer-events: none;
position: fixed;
}
#footer menu {
border-top: #d8d8d8 0.1rem solid;
background: #e8e8e8;
}
#footer button:not([disabled]) {
pointer-events: auto;
}
[data-type="list"] aside img {
border-style: hidden;
}
[data-type="list"] li[data-visited="true"] aside img {
border-style: solid;
}
/* Ellipsis direction hack before bug 883884 is fixed */
.ellipsis-dir-fix {
display: block;
width: -moz-fit-content;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
/* RTL View */
html[dir="rtl"] #contacts-list-container label {
left: unset;
right: 0;
}
#contacts-list-container > ol > li[data-uuid] label {
pointer-events: auto;
}
.ui-not-ready {
background-color: #27c8c2;
}
.ui-not-ready section[role="region"] {
display: none;
}
/* Bug 1202359: Prevent send two events */
span::after {
pointer-events: none;
}