diff --git a/UI/WebServerResources/js/Common.js b/UI/WebServerResources/js/Common.js index f828b306e..4154d5d1e 100644 --- a/UI/WebServerResources/js/Common.js +++ b/UI/WebServerResources/js/Common.js @@ -1,3 +1,3 @@ -function l(){var a,b,c=arguments[0],d=c,e=arguments;for(labels[c]?d=labels[c]:clabels[c]&&(d=clabels[c]),a=1,b=0;a1&&(d=d.replace(/%((%)|s|d)/g,function(b){var c=null;if(b[2])c=b[2];else{switch(c=e[a],b){case"%d":c=parseFloat(c),isNaN(c)&&(c=0)}a++}return c})),d}function hexToRgb(a){var b=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a);return b?{r:parseInt(b[1],16),g:parseInt(b[2],16),b:parseInt(b[3],16)}:null}function contrast(a){var b,c,d=1;if(b=hexToRgb(a)){c=[b.r/255,b.g/255,b.b/255];for(var e=0;e.179?"black":"white"}function guid(){function a(){return(65536*(1+Math.random())|0).toString(16).substring(1)}return(a()+a()+"-"+a()+"-4"+a().substr(0,3)+"-"+a()+"-"+a()+a()+a()).toLowerCase()}!function(){"use strict";function a(a,b,c,d){d.definePalette("sogo-green",{50:"eaf5e9",100:"cbe5c8",200:"aad6a5",300:"88c781",400:"66b86a",500:"56b04c",600:"4da143",700:"388e3c",800:"367d2e",900:"225e1b",A100:"ffffff",A200:"69f0ae",A400:"00e676",A700:"00c853",contrastDefaultColor:"dark",contrastLightColors:["300","400","500","600","700","800","900"]}),d.definePalette("sogo-blue",{50:"f0faf9",100:"e1f5f3",200:"ceebe8",300:"bfe0dd",400:"b2d6d3",500:"a1ccc8",600:"8ebfbb",700:"7db3b0",800:"639997",900:"4d8080",A100:"d4f7fa",A200:"c3f5fa",A400:"53e3f0",A700:"00b0c0",contrastDefaultColor:"light",contrastDarkColors:["50","100","200"]}),d.definePalette("sogo-paper",{50:"fcf7f8",100:"f7f1dc",200:"ede5ca",300:"e6d8ba",400:"e2d2a3",500:"d6c48d",600:"baa870",700:"857545",800:"524517",900:"433809",1000:"000000",A100:"ffffff",A200:"eeeeee",A400:"bdbdbd",A700:"616161",contrastDefaultColor:"dark",contrastLightColors:["800","900"]}),d.theme("default").primaryPalette("sogo-blue",{"default":"900","hue-1":"400","hue-2":"800","hue-3":"A700"}).accentPalette("sogo-green",{"default":"500","hue-1":"A100","hue-2":"300","hue-3":"A700"}).backgroundPalette("grey",{"default":"A100","hue-1":"200","hue-2":"300","hue-3":"500"}),DebugEnabled||(a.debugEnabled(!1),b.debugInfoEnabled(!1)),c.interceptors.push("AuthInterceptor"),c.interceptors.push("ErrorInterceptor")}function b(a,b){return{response:function(c){return c&&/^application\/json/.test(c.config.headers.Accept)&&/^/.test(c.data)?(a.location.reload(!0),b.reject()):c}}}function c(a,b){return{responseError:function(c){return/^application\/json/.test(c.config.headers.Accept)&&a.$broadcast("http:Error",c),b.reject(c)}}}angular.module("SOGo.Common",["ngAnimate","ngMessages","ngSanitize","ngMaterial","mdColors"]).value("sgSettings",{isPopup:document.body.classList.contains("popup"),baseURL:function(){return ApplicationBaseURL||null},activeUser:function(a){var b={login:UserLogin||null,identification:UserIdentification||null,email:UserEmail||null,language:UserLanguage||null,folderURL:UserFolderURL||null,isSuperUser:IsSuperUser||null,path:{calendar:UserCalendarPath||null,contacts:UserContactsPath||null,mail:UserMailPath||null,preferences:UserPreferencesPath||null,administration:IsSuperUser?UserAdministrationPath:null,logoff:UserLogoffPath||null}};return a?b[a]:b}}).constant("sgColors",{selection:["#FFFFFF","#330033","#C0C0C0","#999999","#666666","#333333","#000000","#FFCCCC","#FF6666","#FF0000","#CC0000","#990000","#660000","#330000","#FFCC99","#FF9966","#FF9900","#FF6600","#CC6600","#993300","#663300","#FFFF99","#FFFF66","#FFCC66","#FFCC33","#CC9933","#996633","#663333","#FFFFCC","#FFFF33","#FFFF00","#FFCC00","#999900","#666600","#333300","#CCCCCC","#66FF99","#33FF33","#33CC00","#009900","#006600","#003300","#99FFFF","#33FFFF","#66CCCC","#00CCCC","#339999","#336666","#003333","#CCFFFF","#66FFFF","#33CCFF","#3366FF","#3333FF","#000099","#000066","#CCCCFF","#9999FF","#6666CC","#6633FF","#6600CC","#333399","#330099","#FFCCFF","#FF99FF","#CC66CC","#CC33CC","#993399","#663366","#99FF99"]}).constant("sgConstant",{xs:"(max-width: 599px)","gt-xs":"(min-width: 600px)",sm:"(min-width: 600px) and (max-width: 959px)","gt-sm":"(min-width: 960px)",md:"(min-width: 960px) and (max-width: 1279px)","gt-md":"(min-width: 1280px)",lg:"(min-width: 1280px) and (max-width: 1919px)","gt-lg":"(min-width: 1920px)",xl:"(min-width: 1920px)"}).config(a).factory("AuthInterceptor",b).factory("ErrorInterceptor",c),a.$inject=["$logProvider","$compileProvider","$httpProvider","$mdThemingProvider"],b.$inject=["$window","$q"],c.$inject=["$rootScope","$q"]}(),function(){"use strict";function a(a){c=a}function b(a,b,d){function e(a){var b=a.join("");return b}function f(a,b,c,d,e,f){if(e){var g="rgb("+e.value[0]+","+e.value[1]+","+e.value[2]+")",h="rgb("+e.contrast[0]+","+e.contrast[1]+","+e.contrast[2]+")",i={theme:c,palette:d,value:g,contrast:h,hue:f};s.insertRule(a(i),t),t+=1,s.insertRule(b(i),t),t+=1}}function g(a,b,c,d,e){if(d){var f="rgb("+d.value[0]+","+d.value[1]+","+d.value[2]+")";s.insertRule(a({theme:b,palette:c,value:f,hue:e}),t),t+=1}}function h(){var a=b[0].head.querySelector('style[title="Dynamic-Generated-by-mdColors"]');return null===a&&(a=b[0].createElement("style"),a.title="Dynamic-Generated-by-mdColors",a.appendChild(b[0].createTextNode("")),b[0].head.appendChild(a)),a.sheet}for(var i=a(e([".md-{{theme}}-theme",".md-fg"])+" { color:{{value}};}"),j=a(e([".md-{{theme}}-theme",".md-bg"])+" { background-color:{{value}};}"),k=a(e([".md-{{theme}}-theme",".md-bdr"])+" { border-color:{{value}};}"),l=a(e([".md-{{theme}}-theme",".md-{{hue}}",".md-fg"])+" { color:{{value}};}"),m=a(e([".md-{{theme}}-theme",".md-{{hue}}",".md-bg"])+" { background-color:{{value}};}"),n=a(e([".md-{{theme}}-theme",".md-{{palette}}",".md-fg"])+" { color:{{value}};}"),o=a(e([".md-{{theme}}-theme",".md-{{palette}}",".md-bg"])+" { background-color:{{value}}; color:{{contrast}}; }"),p=a(e([".md-{{theme}}-theme",".md-{{palette}}",".md-bdr"])+" { border-color:{{value}};}"),q=a(e([".md-{{theme}}-theme",".md-{{palette}}.md-{{hue}}",".md-fg"])+" { color:{{value}};}"),r=a(e([".md-{{theme}}-theme",".md-{{palette}}.md-{{hue}}",".md-bg"])+" { background-color:{{value}};}"),s=h(),t=0;s.cssRules.length>0;)s.deleteRule(0);angular.forEach(c._THEMES,function(a,b){f(i,j,b,"primary",c._PALETTES[a.colors.primary.name][a.colors.primary.hues["default"]]),f(l,m,b,"primary",c._PALETTES[a.colors.primary.name][a.colors.primary.hues["hue-2"]],"hue-2"),f(l,m,b,"primary",c._PALETTES[a.colors.primary.name][a.colors.primary.hues["hue-3"]],"hue-3"),f(l,m,b,"primary",c._PALETTES[a.colors.primary.name][a.colors.primary.hues["hue-1"]],"hue-1"),g(k,b,"primary",c._PALETTES[a.colors.primary.name][a.colors.primary.hues["default"]]),angular.forEach(a.colors,function(a,d){f(n,o,b,d,c._PALETTES[a.name][a.hues["default"]]),g(p,b,d,c._PALETTES[a.name][a.hues["default"]]),f(q,r,b,d,c._PALETTES[a.name][a.hues["hue-2"]],"hue-2"),f(q,r,b,d,c._PALETTES[a.name][a.hues["hue-3"]],"hue-3"),f(q,r,b,d,c._PALETTES[a.name][a.hues["hue-1"]],"hue-1")})})}var c;angular.module("mdColors",["ngMaterial"]).config(a).run(b),a.$inject=["$mdThemingProvider"],b.$inject=["$interpolate","$document","$log"]}(),function(){"use strict";function a(a){return a.decodeURIComponent}a.$inject=["$window"],angular.module("SOGo.Common").filter("decodeUri",a)}(),function(){"use strict";function a(a){return a.encodeURIComponent}a.$inject=["$window"],angular.module("SOGo.Common").filter("encodeUri",a)}(),function(){"use strict";function a(a){return function(b){var c=angular.element("
"+b+"
");return c.find("a").attr("target","_blank"),a.trustAs("html",c.html())}}a.$inject=["$sce"],angular.module("SOGo.Common").filter("ensureTarget",a)}(),function(){"use strict";function a(){return l}angular.module("SOGo.Common").filter("loc",a)}(),function(){"use strict";function a(){return function(a){for(var b=[],c=0;c",'
',' error_outline'," "+l(c)+"","
",""].join(""),hideDelay:5e3,position:"top right"}):i.debug("untrap error")}b.isPopup=k.isPopup,b.activeUser=k.activeUser(),b.baseURL=k.baseURL(),b.leftIsClose=h(j.xs),b.currentDay=window.currentDay,c(function(){d(function(){e.get("../date").then(function(a){b.currentDay=a})},864e5)},1e3*window.currentDay.secondsBeforeTomorrow),b.toggleLeft=function(){b.leftIsClose=n(),f("left").toggle().then(function(){i.debug("toggle left is done")})},b.toggleRight=function(){f("right").toggle().then(function(){i.debug("toggle right is done")})},b.$watch(function(){return h(j["gt-sm"])},function(a){b.isGtMedium=a,a&&(b.leftIsClose=!1)}),a.$on("http:Error",o),m.getAlarms()}a.$inject=["$rootScope","$scope","$timeout","$interval","$http","$mdSidenav","$mdToast","$mdMedia","$log","sgConstant","sgSettings","Alarm"],angular.module("SOGo.Common").controller("navController",a)}(),function(){"use strict";function a(a){this.folderId=a}a.factory=["$q","$timeout","sgSettings","Resource","User",function(b,c,d,e,f){return angular.extend(a,{$q:b,$timeout:c,$$resource:new e(d.activeUser("folderURL"),d.activeUser()),$User:f}),a}],angular.module("SOGo.Common").factory("Acl",a.factory),a.prototype.$users=function(b){var c,d=this,e=a.$q.defer();if(!this.users){var f;return f=angular.isDefined(b)?a.$$resource.userResource(b).fetch(this.folderId,"acls"):a.$$resource.fetch(this.folderId,"acls"),f.then(function(f){return d.users=[],angular.forEach(f.users,function(e){c=new a.$User(e),c.canSubscribeUser=c.isSubscribed,c.wasSubscribed=c.isSubscribed,c.$rights=angular.bind(c,c.$acl,d.folderId,b),d.users.push(c)}),e.resolve(d.users),d.users})}return e.resolve(this.users),e.promise},a.prototype.$addUser=function(b,c){var d=this,e=a.$q.defer(),f={uid:b.uid};if(!b.uid||_.indexOf(_.pluck(this.users,"uid"),b.uid)>-1)e.resolve();else{var g;g=angular.isDefined(c)?a.$$resource.userResource(c).fetch(this.folderId,"addUserInAcls",f):a.$$resource.fetch(this.folderId,"addUserInAcls",f),g.then(function(){b.wasSubscribed=!1,b.userClass=b.isGroup?"normal-group":"normal-user",b.$rights=angular.bind(b,b.$acl,d.folderId),d.users.push(b),e.resolve(b)},function(a,b){e.reject(l("An error occured please try again."))})}return e.promise},a.prototype.$removeUser=function(b){var c=this,d={uid:b};return a.$$resource.fetch(this.folderId,"removeUserFromAcls",d).then(function(){var a=_.indexOf(_.pluck(c.users,"uid"),b);a>=0&&c.users.splice(a,1)})},a.prototype.$resetUsersRights=function(){angular.forEach(this.users,function(a){a.$resetRights()})},a.prototype.$saveUsersRights=function(b){var c=this,d=a.$q.defer(),e=a.$q.defer(),f={action:"saveUserRights"},g=[];if(angular.forEach(this.users,function(a){a.$rightsAreDirty()&&g.push(a.$omit())}),g.length){var h;h=angular.isDefined(b)?a.$$resource.userResource(b).save(this.folderId,g,f):a.$$resource.save(this.folderId,g,f),h.then(function(){angular.forEach(c.users,function(a){a.$rightsAreDirty()&&(a.$shadowRights=angular.copy(a.rights))}),d.resolve()},d.reject)}else d.resolve();return g=[],angular.forEach(this.users,function(a){!a.wasSubscribed&&a.isSubscribed&&g.push(a.uid)}),g.length?(f={uids:g.join(",")},a.$$resource.fetch(this.folderId,"subscribeUsers",f).then(function(){angular.forEach(c.users,function(a){a.wasSubscribed=a.isSubscribed}),e.resolve()},e.reject)):e.resolve(),a.$q.all([d.promise,e.promise])}}(),function(){"use strict";function a(){this.currentAlarm=null}function b(b,c,d,e){return angular.extend(a,{$timeout:b,$$resource:new d(c.activeUser("folderURL")+"Calendar",c.activeUser()),$toast:e}),a}a.getAlarms=function(){var b=this,c=new Date,d=Math.floor(c.getTime()/1e3);this.$$resource.fetch("","alarmslist?browserTime="+d).then(function(c){var d=c.alarms.sort(function(a,b){var c=parseInt(a[2]),d=parseInt(b[2]);return d-c});if(d.length>0){var e=d.pop(),f=new Date,g=Math.floor(f.getTime()/1e3),h=e[0]+"/"+e[1],i=parseInt(e[2]),j=i;i>0&&(j-=g);var k=(new Date(1e3*i),angular.bind(b,a.showAlarm,h));b.currentAlarm&&b.$timeout.cancel(b.currentAlarm),b.currentAlarm=b.$timeout(k,1e3*j)}})},a.showAlarm=function(a){var b=this;this.$$resource.fetch(a,"?resetAlarm=yes").then(function(c){function d(a,c,d){a.reminder="10",a.cancel=function(){c.hide()},a.ok=function(){b.$$resource.fetch(d,"view?snoozeAlarm="+a.reminder),c.hide()}}b.$toast.show({position:"top right",hideDelay:0,template:["",'
'," ",' ",' '," ",l("5 minutes")," "," ",l("10 minutes")," "," ",l("15 minutes")," "," ",l("30 minutes")," "," ",l("45 minutes")," "," ",l("1 hour")," "," ",l("1 day")," "," "," ",' ',l("Cancel")," ",' ',l("Ok")," ","
","
"].join(""),locals:{url:a},controller:d}),d.$inject=["scope","$mdToast","url"]})},b.$inject=["$timeout","sgSettings","Resource","$mdToast"],angular.module("SOGo.Common").factory("Alarm",b)}(),function(){"use strict";function a(){function a(a){var b,c,d,e,f,g;for(b=null,c=a+"=",d=document.cookie.split(";"),e=0;!b&&e0&&(f=f.substr(g)),0===f.indexOf(c)&&(b=f.substr(c.length))}return b}function b(){var b,c=null,d=a("0xHIGHFLYxSOGo");return d&&d.length>8&&(b=decodeURIComponent(d.substr(8)),c=b.base64decode().split(":")),c}function c(a,b){var c,d,e,f,g,h,i,j;return c=a,b&&(c+="@"+b.value),d=""+window.location.href,e=ApplicationBaseURL+"/"+encodeURIComponent(c),"/"==e[0]&&(g=d.split("/"),h=g[2],i=g[0],e=i+"//"+h+e),g=e.split("/"),g.splice(0,3),f=g.join("/"),j=!d.startsWith(e)&&!d.startsWith(f)||d.endsWith("/logoff")?e:d}function d(a,d,e){var f;return f={login:function(f){var g,h=a.defer(),i=f.username,j=f.password,k=f.domain,m=f.rememberLogin?1:0;return f.loginSuffix&&!i.endsWith(f.loginSuffix)&&(i+=loginSuffix,k=!1),f.language&&"WONoSelectionString"!=f.language&&(g=f.language),d({method:"POST",url:"/SOGo/connect",data:{userName:i,password:j,domain:k,language:g,rememberLogin:m}}).then(function(a){var d=a.data,e=b();e?"undefined"!=typeof d.expire&&"undefined"!=typeof d.grace?d.expire<0&&d.grace>0?h.reject({grace:d.grace}):d.expire>0&&-1==d.grace?h.reject({expire:d.expire}):h.resolve(c(i,k)):h.resolve(c(i,k)):h.reject(l("cookiesNotEnabled"))},function(a){var b,c,d=a.data;d&&d.LDAPPasswordPolicyError?(c=d.LDAPPasswordPolicyError,b=c==e.PolicyNoError?l("Wrong username or password."):c==e.PolicyAccountLocked?l("Your account was locked due to too many failed attempts."):l("Login failed due to unhandled error case: ")+c):b=l("Unhandled error response"),h.reject({error:b})}),h.promise},changePassword:function(c){var f=a.defer(),g=b();return d({method:"POST",url:"/SOGo/so/changePassword",data:{userName:g[0],password:g[1],newPassword:c}}).then(f.resolve,function(a){var b,c=a.data,d=c.LDAPPasswordPolicyError;d?d==e.PolicyNoError?b=l("Password change failed"):d==e.PolicyPasswordModNotAllowed?b=l("Password change failed - Permission denied"):d==e.PolicyInsufficientPasswordQuality?b=l("Password change failed - Insufficient password quality"):d==e.PolicyPasswordTooShort?b=l("Password change failed - Password is too short"):d==e.PolicyPasswordTooYoung?b=l("Password change failed - Password is too young"):d==e.PolicyPasswordInHistory?b=l("Password change failed - Password is in history"):(b=l("Unhandled policy error: %{0}").formatted(d),d=e.PolicyPasswordUnknown):(d=e.PolicyPasswordSystemUnknown,b=_("Unhandled error response")),f.reject(b)}),f.promise}}}this.$get=d,d.$inject=["$q","$http","passwordPolicyConfig"]}angular.module("SOGo.Authentication",[]).constant("passwordPolicyConfig",{PolicyPasswordChangeUnsupported:-3,PolicyPasswordSystemUnknown:-2,PolicyPasswordUnknown:-1,PolicyPasswordExpired:0,PolicyAccountLocked:1,PolicyChangeAfterReset:2,PolicyPasswordModNotAllowed:3,PolicyMustSupplyOldPassword:4,PolicyInsufficientPasswordQuality:5,PolicyPasswordTooShort:6,PolicyPasswordTooYoung:7,PolicyPasswordInHistory:8,PolicyNoError:65535}).provider("Authentication",a)}(),function(){"use strict";function a(){}function b(b,c){return angular.extend(a,{$q:b,$modal:c}),a}a.alert=function(a,b){var c=this.$modal.alert().title(a).htmlContent(b).ok(l("OK"));this.$modal.show(c)},a.confirm=function(a,b,c){var d=this.$modal.confirm().title(a).htmlContent(b).ok(c&&c.ok?c.ok:l("OK")).cancel(c&&c.cancel?c.cancel:l("Cancel"));return this.$modal.show(d)},a.prompt=function(a,b,c){function d(b,c){b.title=a,b.name="",b.cancel=function(){f.reject(),c.hide()},b.ok=function(){f.resolve(b.name),c.hide()}}var e=c||{},f=this.$q.defer();return this.$modal.show({parent:angular.element(document.body),clickOutsideToClose:!0,escapeToClose:!0,template:['',' ','

'," "," ",' '," ","
"," ",' '," "+l("Cancel")," ",' '," "+l("OK")," "," ","
"].join(""),controller:d}),d.$inject=["scope","$mdDialog"],f.promise},b.$inject=["$q","$mdDialog"],angular.module("SOGo.Common").factory("Dialog",b)}(),function(){"use strict";function a(){return function(a,b,c,d){var e,f,g,h=b,i=c;return a?(e=a.indexOf("<"),e>=0&&(f=a.indexOf(">",e),f>e&&(a=a.substring(e+1,f))),b||(h=48),g=a.md5(),i&&"none"!=i||(c=d&&d.no_404?"mm":"404"),"https://www.gravatar.com/avatar/"+g+"?s="+h+"&d="+c):""}}angular.module("SOGo.Common").factory("Gravatar",a)}(),function(){"use strict";function a(a,b,c,d,e){angular.extend(this,{_http:a,_q:b,_path:c,_activeUser:d}),angular.extend(this,e),this._path=this._path.replace(/\/$/,"")}a.$factory=["$http","$q",function(b,c){return function(d,e,f){return new a(b,c,d,e,f)}}],angular.module("SOGo.Common").factory("Resource",a.$factory),a.prototype.userResource=function(b){var c=_.compact(this._activeUser.folderURL.split("/"));return c.splice(c.length-1,1,escape(b)),new a(this._http,this._q,"/"+c.join("/"),this._activeUser)},a.prototype.fetch=function(a,b,c){var d=this._q.defer(),e=[this._path];return a&&e.push(a.split("/")),b&&e.push(b),e=_.compact(_.flatten(e)).join("/"),this._http({method:"GET",url:e,params:c}).then(function(a){return d.resolve(a.data)},function(a){return 404==a.status?d.reject():void 0}),d.promise},a.prototype.newguid=function(a){var b=this._q.defer(),c=this._path+"/"+a+"/newguid";return this._http.get(c).then(function(a){return b.resolve(a.data)},b.reject),b.promise},a.prototype.create=function(a,b){var c=this._q.defer(),d=this._path+"/"+a;return this._http.post(d,{name:b}).then(function(a){return c.resolve(a.data)},c.reject),c.promise},a.prototype.post=function(a,b,c){var d=this._q.defer(),e=[this._path];return a&&e.push(a),b&&e.push(b),e=_.compact(_.flatten(e)).join("/"),this._http.post(e,c).then(function(a){return d.resolve(a.data)},d.reject),d.promise},a.prototype.save=function(a,b,c){var d=(this._q.defer(),c&&c.action?c.action:"save");return this.post(a,d,b)},a.prototype.remove=function(a){var b=this._q.defer(),c=this._path+"/"+a+"/delete";return this._http.get(c).then(function(a){return b.resolve(a.data)},b.reject),b.promise}}(),function(){"use strict";function a(a){a&&this.init(a)}a.factory=["$q","$log","sgSettings","Resource","Gravatar",function(b,c,d,e,f){return angular.extend(a,{$q:b,$log:c,$$resource:new e(d.activeUser("folderURL"),d.activeUser()),$gravatar:f,$query:"",$users:[]}),a}],angular.module("SOGo.Common").factory("User",a.factory),a.$filter=function(b,c,d){var e={search:b};if(!d||!d.dry){if(!b)return a.$users.splice(0,a.$users.length),a.$q.when(a.$users);if(a.$query==b)return a.$q.when(a.$users);a.$query=b}return a.$$resource.fetch(null,"usersSearch",e).then(function(b){var e,f,g,h,i=function(a){return this.uid==a.uid};for(h=d&&d.dry?[]:a.$users,e=c?_.filter(b.users,function(a){return!_.find(c,i,a)}):b.users,f=h.length-1;f>=0;f--)g=h[f],_.find(e,i,g)||h.splice(f,1);return _.each(e,function(b,c){if(_.isUndefined(_.find(h,i,b))){var d=new a(b);h.splice(c,0,d)}}),a.$log.debug(h),h})},a.prototype.init=function(b){angular.extend(this,b),this.$$shortFormat||(this.$$shortFormat=this.$shortFormat()),this.$$image||(this.$$image=this.image||a.$gravatar(this.c_email,32,a.$alternateAvatar,{no_404:!0})),this.empty=" "},a.prototype.$shortFormat=function(a){var b=this.cn||this.c_email,c=this.c_email,d=a&&a.email===!1;return!d&&c&&b!=c&&(b+=" <"+c+">"),b},a.prototype.$acl=function(b,c){var d=this,e=a.$q.defer(),f={uid:this.uid};if(this.$shadowRights)e.resolve(this.rights);else{var g;g=angular.isDefined(c)?a.$$resource.userResource(c).fetch(b,"userRights",f):a.$$resource.fetch(b,"userRights",f),g.then(function(a){return d.rights=a,d.$shadowRights=angular.copy(a),e.resolve(a),a})}return e.promise},a.prototype.$isAnonymous=function(){return"anonymous"==this.uid},a.prototype.$isSpecial=function(){return this.userClass&&"public-user"==this.userClass},a.prototype.$confirmRights=function(a){var b=!1;return this.$confirmation?!1:(_.some(_.values(this.rights))&&("anonymous"==this.uid?"AddressBook"==a.constructor.name?b=l('Potentially anyone on the Internet will be able to access your address book "%{0}", even if they do not have an account on this system. Is this information suitable for the public Internet?',a.name):"Calendar"==a.constructor.name&&(b=l('Potentially anyone on the Internet will be able to access your calendar "%{0}", even if they do not have an account on this system. Is this information suitable for the public Internet?',a.name)):("anyone"==this.uid||""==this.uid)&&("AddressBook"==a.constructor.name?b=l('Any user with an account on this system will be able to access your address book "%{0}". Are you certain you trust them all?',a.name):"Calendar"==a.constructor.name?b=l('Any user with an account on this system will be able to access your calendar "%{0}". Are you certain you trust them all?',a.name):"Mailbox"==a.constructor.name&&(b=l('Any user with an account on this system will be able to access your mailbox "%{0}". Are you certain you trust them all?',a.name)))),this.$confirmation=b,b)},a.prototype.$rightsAreDirty=function(){return this.rights&&!_.isEqual(this.rights,this.$shadowRights)},a.prototype.$resetRights=function(a){var b=this;a?_.map(_.keys(this.rights),function(a){angular.isString(b.rights[a])?b.rights[a]="None":b.rights[a]=0}):this.rights=angular.copy(this.$shadowRights)},a.prototype.$folders=function(b){var c=this,d=a.$q.defer(),e={type:b};return this.$$folders?d.resolve(this.$$folders):a.$$resource.userResource(this.uid).fetch(null,"foldersSearch",e).then(function(a){c.$$folders=a.folders,d.resolve(a.folders)}),d.promise},a.prototype.$omit=function(){var a={};return angular.forEach(this,function(b,c){"constructor"!=c&&"$"!=c[0]&&(a[c]=b)}),a},a.prototype.toString=function(){return"[User "+this.c_email+"]"}}(),function(){"use strict";function a(a,b){return function(c){b(function(){a.$broadcast("sgFocusOn",c)})}}a.$inject=["$rootScope","$timeout"],angular.module("SOGo.Common").factory("sgFocus",a)}(),function(){"use strict";function a(){return{restrict:"AE",scope:{},bindToController:{size:"@",email:"=sgEmail",src:"=sgSrc"},template:["person",''].join(""),link:b,controller:"sgAvatarImageController",controllerAs:"vm"}}function b(a,b,c,d){var e=b.find("img"),f=b.find("md-icon");c.size&&(e.attr("width",c.size),e.attr("height",c.size)),d.img=e,d.genericImg=f}function c(a,b,c,d,e,f){function g(a){var b=f(a,j.size,e.defaults.SOGoAlternateAvatar);c({method:"GET",url:b,cache:!0,headers:{Accept:"image/*"}}).then(function(){j.url||(j.url=b,j.urlEmail=a,i())},function(){h()})}function h(){j.url=null,j.urlEmail=null,j.img.addClass("ng-hide"),j.genericImg.removeClass("ng-hide")}function i(){j.genericImg.addClass("ng-hide"),j.img.removeClass("ng-hide")}var j;j=this,e.ready().then(function(){a.$watch("vm.email",function(a,b){a&&j.urlEmail!=a?(h(),g(a)):a||h()})}),"sg-src"in b[0].attributes&&a.$watch("vm.src",function(a){a&&(j.url=a,j.urlEmail=""+j.email,i())})}c.$inject=["$scope","$element","$http","$q","Preferences","Gravatar"],angular.module("SOGo.Common").directive("sgAvatarImage",a).controller("sgAvatarImageController",c)}(),function(){"use strict";function a(){function a(a,b,c,d){d.$render=function(){a.sgColor=d.$viewValue,a.sgIconColor=contrast(d.$viewValue)}}return{restrict:"E",require:"ngModel",template:["",' ',' color_lens'," ",' ',' ',' ',' check_box'," "," "," ",""].join(""),replace:!0,controller:b,link:a}}function b(a,b,c){var d=b.controller("ngModel");a.sgColors=c.selection,a.setColor=function(b){a.sgColor=b,a.sgIconColor=contrast(b),d.$setViewValue(b)}}b.$inject=["$scope","$element","sgColors"],angular.module("SOGo.Common").directive("sgColorPicker",a)}(),function(){"use strict";function a(a){function b(b,c,d){var e=b.$watch(function(a){return a.$eval(d.sgCompile)},function(d){c.html(d),a(c.contents())(b),e()})}return{restrict:"A",link:b}}a.$inject=["$compile"],angular.module("SOGo.Common").directive("sgCompile",a)}(),function(){"use strict";function a(){var a=13;return function(b,c,d){c.bind("keydown keypress",function(c){c.which===a&&(b.$apply(d.sgEnter),c.preventDefault())})}}angular.module("SOGo.Common").directive("sgEnter",a)}(),function(){"use strict";function a(){var a=27;return function(b,c,d){c.bind("keydown",function(c){c.keyCode===a&&b.$apply(d.sgEscape)})}}angular.module("SOGo.Common").directive("sgEscape",a)}(),function(){"use strict";function a(){return function(a,b,c){a.$on("sgFocusOn",function(a,d){d===c.sgFocusOn&&(b[0].focus(),b[0].select())})}}angular.module("SOGo.Common").directive("sgFocusOn",a)}(),function(){"use strict";function a(){function a(){var a=this;a.contrast=contrast}return{restrict:"E",require:"ngModel",scope:{ngModel:"="},replace:!0,bindToController:!0,controller:a,controllerAs:"cssCtrl",template:['"].join("")}}angular.module("SOGo.Common").directive("sgFolderStylesheet",a)}(),function(){"use strict";function a(){return{restrict:"A",scope:{placeholder:"=sgPlaceholder"},link:function(a,b,c){a.$watch("placeholder",function(){b[0].placeholder=a.placeholder})}}}angular.module("SOGo.Common").directive("sgPlaceholder",a)}(),function(){"use strict";function a(a){function b(b,c){var d=(b.find("md-input-container"),b.find("input")),e=b.find("md-select"),f=b.find("md-button");return d.attr("ng-model","$sgSearchController.searchText"),d.attr("ng-model-options","$sgSearchController.searchTextOptions"),d.attr("ng-change","$sgSearchController.onChange()"),e&&(e.attr("ng-model","$sgSearchController.searchField"),e.attr("ng-change","$sgSearchController.onChange()")),f&&f.attr("sg-search-cancel")?(f.attr("ng-click",f.attr("sg-search-cancel")),f.removeAttr("sg-search-cancel")):f=null,function(b,c,e,g){var h=c.find("button");g.formName=c.attr("name"),g.inputName=d.attr("name"),g.allowDot=a(c.attr("sg-allow-dot"))(b),g.doSearch=a(c.attr("sg-search")),f&&h&&h.on("click",g.cancelSearch)}}return{restrict:"A",controller:"sgSearchController",controllerAs:"$sgSearchController",priority:1001,compile:b}}function b(){function a(a,b){return function(a,b,c,d,e){e(function(a){b.append(a)})}}return{restrict:"A",priority:1e3,transclude:!0,compile:a}}function c(a,b,c){var d,e=this;d=angular.isNumber(a.minimumSearchLength)?a.minimumSearchLength:2,e.searchText=null,e.searchTextOptions={updateOn:"default blur",debounce:{"default":300,blur:0}},e.onChange=function(){var a=b[e.formName],c=a[e.inputName],d=c.$viewValue;(e.allowDot&&"."==d||a.$valid&&d)&&("."==d&&c.$setValidity("minlength",!0),e.doSearch(b,{searchText:d,searchField:e.searchField}))},e.cancelSearch=function(){e.searchText=null}}a.$inject=["$parse"],c.$inject=["$window","$scope","$element"], -angular.module("SOGo.Common").controller("sgSearchController",c).directive("sgSearch",a).directive("sgSearch",b)}(),function(){"use strict";function a(a){return{restrict:"A",scope:{folderType:"@sgSubscribe",onFolderSelect:"&sgSubscribeOnSelect"},replace:!1,bindToController:!0,controller:c,controllerAs:"$sgSubscribeDialogController",link:b}}function b(a,b,c,d){b.find("input");b.on("click",d.showDialog)}function c(a){var b=this;b.showDialog=function(){a.show({templateUrl:"../Contacts/UIxContactsUserFolders",clickOutsideToClose:!0,locals:{folderType:b.folderType,onFolderSelect:b.onFolderSelect},controller:d,controllerAs:"subscribe"})}}function d(a,b,c,d){var e=this;e.selectedUser=null,e.users=d.$users,e.searchTextOptions={updateOn:"default blur",debounce:{"default":300,blur:0}},e.onChange=function(){d.$filter(e.searchText).then(function(){e.selectedUser&&_.isUndefined(_.find(d.$users,function(a){return a.uid==e.selectedUser.uid}))&&(e.selectedUser=null)})},e.selectUser=function(a){e.selectedUser==e.users[a]?e.selectedUser=null:e.users[a].$folders(b).then(function(){e.selectedUser=e.users[a]})},e.selectFolder=function(a){c({folderData:a})},e.close=function(){a.hide()}}a.$inject=["User"],c.$inject=["$mdDialog"],d.$inject=["$mdDialog","folderType","onFolderSelect","User"],angular.module("SOGo.Common").directive("sgSubscribe",a)}(),function(){"use strict";function a(){return{template:['
','
','
','
',' {{hour.displayName}}',"
","
","
",'
','
','
',' {{minute.displayName}}',"
","
","
",'
','
','
',' {{minute.displayName}}',"
","
","
",'
',' ',"
","
"].join(""),scope:{},require:["ngModel","sgTimePane"],controller:b,controllerAs:"ctrl",bindToController:!0,link:function(a,b,c,d){var e=d[0],f=d[1],g=b;f.configureNgModel(e,f,g)}}}function b(a,b,c,d,f,g,h,i,j,k,l){var m;this.$scope=c,this.$element=a,this.timePaneElement=a[0].querySelector(".sg-time-pane"),this.$animate=d,this.$q=f,this.$mdInkRipple=k,this.$mdUtil=l,this.keyCode=g.KEY_CODE,this.dateUtil=i,this.id=e++,this.ngModelCtrl=null,this.selectedTime=null,this.displayTime=null,this.isInitialized=!1,c.hours=[],c.hours[0]=[],c.hours[0][0]=[],c.hours[0][1]=[],c.hours[1]=[],c.hours[1][0]=[],c.hours[1][1]=[];for(var n=0;6>n;n++)c.hours[0][0][n]={id:"tp-"+this.id+"-hour-"+n,displayName:10>n?"0"+n:""+n,selected:!1},c.hours[0][1][n]={id:"tp-"+this.id+"-hour-"+(n+6),displayName:10>n+6?"0"+(n+6):""+(n+6),selected:!1},c.hours[1][0][n]={id:"tp-"+this.id+"-hour-"+(n+12),displayName:""+(n+12),selected:!1},c.hours[1][1][n]={id:"tp-"+this.id+"-hour-"+(n+18),displayName:""+(n+18),selected:!1};for(c.min5=[],c.min5[0]=[],c.min5[1]=[],n=0;6>n;n++)m=5*n,c.min5[0][n]={id:"tp-"+this.id+"-minute5-"+m,displayName:10>m?":0"+m:":"+m,selected:!0},c.min5[1][n]={id:"tp-"+this.id+"-minute5-"+(m+30),displayName:":"+(m+30),selected:!1};for(c.min1=[],n=0;12>n;n++){c.min1[n]=[];for(var o=0;5>o;o++)m=5*n+o,c.min1[n][o]={id:"tp-"+this.id+"-minute-"+m,displayName:10>m?":0"+m:":"+m,selected:!0}}c.show5min=!0,c.getToggleBtnLbl=function(){return c.is5min()?">>":"<<"},c.toggleManual5min=function(){c.manual5min=!c.is5min()},c.is5min=function(){return c.manual5min===!0||c.manual5min===!1?c.manual5min:c.show5min},b.tabindex||a.attr("tabindex","-1");var p=this;this.hourClickHandler=function(a){var b=new Date(p.displayTime);b.setHours(Number(a)),p.setNgModelValue(b,"hours")},c.hourClickHandler=this.hourClickHandler,this.minuteClickHandler=function(a){var b=a.substr(1),c=new Date(p.displayTime);c.setMinutes(Number(b)),p.setNgModelValue(c,"minutes")},c.minuteClickHandler=this.minuteClickHandler,this.attachTimePaneEventListeners()}angular.module("SOGo.Common").directive("sgTimePane",a);var c="md-bg",d="md-focus",e=0;b.$inject=["$element","$attrs","$scope","$animate","$q","$mdConstant","$mdTheming","$$mdDateUtil","$mdDateLocale","$mdInkRipple","$mdUtil"],b.prototype.configureNgModel=function(a,b,c){this.ngModelCtrl=a;var d=this;a.$render=function(){d.changeSelectedTime(d.ngModelCtrl.$viewValue,b,c)}},b.prototype.changeSelectedTime=function(a,b,d){var e=this.selectedTime;this.selectedTime=a,this.changeDisplayTime(a).then(function(){if(e){var d=e.getHours(),f=document.getElementById("tp-"+b.id+"-hour-"+d);f&&(f.classList.remove(c),f.setAttribute("aria-selected","false"));var g=e.getMinutes(),h=document.getElementById("tp-"+b.id+"-minute-"+g);h&&(h.classList.remove(c),h.setAttribute("aria-selected","false"));var i=document.getElementById("tp-"+b.id+"-minute5-"+g);i&&(i.classList.remove(c),i.setAttribute("aria-selected","false"))}if(a){var j,k=a.getHours(),l=document.getElementById("tp-"+b.id+"-hour-"+k);l&&(l.classList.add(c),l.setAttribute("aria-selected","true"));var m=a.getMinutes();m%5===0?(b.$scope.show5min=!0,j=document.getElementById("tp-"+b.id+"-minute5-"+m),j&&(j.classList.add(c),j.setAttribute("aria-selected","true"))):b.$scope.show5min=!1,j=document.getElementById("tp-"+b.id+"-minute-"+m),j&&(j.classList.add(c),j.setAttribute("aria-selected","true"))}})},b.prototype.changeDisplayTime=function(a){var b=new Date(a);return this.isInitialized?this.dateUtil.isValidDate(b)?(this.displayTime=b,this.$q.when()):this.$q.when():(this.buildInitialTimePaneDisplay(),this.$q.when())},b.prototype.buildInitialTimePaneDisplay=function(){this.displayTime=this.selectedTime||this.today,this.isInitialized=!0},b.prototype.attachTimePaneEventListeners=function(){this.$element.on("keydown",angular.bind(this,this.handleKeyEvent))},b.prototype.handleKeyEvent=function(a){var b=this;this.$scope.$apply(function(){return a.which==b.keyCode.ESCAPE||a.which==b.keyCode.TAB?(b.$scope.$emit("md-time-pane-close"),void(a.which==b.keyCode.TAB&&a.preventDefault())):a.which===b.keyCode.ENTER?(b.setNgModelValue(b.displayTime,"enter"),void a.preventDefault()):void 0})},b.prototype.setNgModelValue=function(a,b){this.$scope.$emit("sg-time-pane-change",{date:a,changed:b}),this.ngModelCtrl.$setViewValue(a),this.ngModelCtrl.$render()},b.prototype.focus=function(a,b){var c=a||this.selectedTime||this.today,e=this.timePaneElement.querySelector(".md-focus");if(e&&e.classList.remove(d),c){var f=c.getHours(),g=document.getElementById("tp-"+b.id+"-hour-"+f);g&&(g.classList.add(d),g.focus())}}}(),function(){"use strict";function a(){return{template:['",'
",' ',' ','
',"
","
",'
','
','
',"
",'
',' ',"
","
"].join(""),require:["ngModel","sgTimepicker"],scope:{placeholder:"@mdPlaceholder"},controller:b,controllerAs:"ctrl",bindToController:!0,link:function(a,b,c,d){var e=d[0],f=d[1];f.configureNgModel(e)}}}function b(a,b,c,d,e,f,g,h,i,j,k,l,m){this.$compile=d,this.$timeout=e,this.$window=f,this.dateLocale=k,this.dateUtil=l,this.$mdConstant=g,this.$mdMedia=h,this.$mdUtil=j,this.$$rAF=m,this.ngModelCtrl=null,this.inputElement=b[0].querySelector("input"),this.inputContainer=b[0].querySelector(".sg-timepicker-input-container"),this.ngInputElement=angular.element(this.inputElement),this.timePane=b[0].querySelector(".sg-timepicker-time-pane"),this.timeButton=b[0].querySelector(".sg-timepicker-button"),this.inputMask=b[0].querySelector(".sg-timepicker-input-mask-opaque"),this.$element=b,this.$attrs=c,this.$scope=a,this.date=null,this.isFocused=!1,this.isDisabled=!1,this.setDisabled(b[0].disabled||angular.isString(c.disabled)),this.isTimeOpen=!1,this.timePaneOpenedFrom=null,this.timePane.id="sg-time-pane"+j.nextUid(),i(b),this.bodyClickHandler=angular.bind(this,this.handleBodyClick),this.windowResizeHandler=j.debounce(angular.bind(this,this.closeTimePane),100),c.tabindex||b.attr("tabindex","-1"),this.installPropertyInterceptors(),this.attachChangeListeners(),this.attachInteractionListeners();var n=this;a.$on("$destroy",function(){n.detachTimePane()})}angular.module("SOGo.Common").directive("sgTimepicker",a);var c=3,d="sg-timepicker-invalid",e=500,f={MIN5:{GTSM:192,SM:312},MIN1:{GTSM:384,SM:474}},g={GTSM:530,SM:292};b.$inject=["$scope","$element","$attrs","$compile","$timeout","$window","$mdConstant","$mdMedia","$mdTheming","$mdUtil","$mdDateLocale","$$mdDateUtil","$$rAF"],b.prototype.configureNgModel=function(a){this.ngModelCtrl=a;var b=this;a.$render=function(){var a=b.ngModelCtrl.$viewValue;if(a&&!(a instanceof Date))throw Error("The ng-model for sg-timepicker must be a Date instance. Currently the model is a: "+typeof a);b.time=a,b.inputElement.value=b.dateLocale.formatTime(a),b.resizeInputElement(),b.updateErrorState()}},b.prototype.attachChangeListeners=function(){var a=this;a.$scope.$on("sg-time-pane-change",function(b,c){var e=new Date(c.date);a.ngModelCtrl.$setViewValue(e),a.time=e,a.inputElement.value=a.dateLocale.formatTime(e),"minutes"==c.changed&&a.closeTimePane(),a.resizeInputElement(),a.inputContainer.classList.remove(d)}),a.ngInputElement.on("input",angular.bind(a,a.resizeInputElement)),a.ngInputElement.on("input",a.$mdUtil.debounce(a.handleInputEvent,e,a))},b.prototype.attachInteractionListeners=function(){var a=this,b=this.$scope,c=this.$mdConstant.KEY_CODE;a.ngInputElement.on("keydown",function(d){d.altKey&&d.keyCode==c.DOWN_ARROW&&(a.openTimePane(d),b.$digest())}),b.$on("md-time-close",function(){a.closeTimePane()})},b.prototype.installPropertyInterceptors=function(){var a=this;if(this.$attrs.ngDisabled){var b=this.$mdUtil.validateScope(this.$element)?this.$element.scope():null;b&&b.$watch(this.$attrs.ngDisabled,function(b){a.setDisabled(b)})}Object.defineProperty(this,"placeholder",{get:function(){return a.inputElement.placeholder},set:function(b){a.inputElement.placeholder=b||""}})},b.prototype.setDisabled=function(a){this.isDisabled=a,this.inputElement.disabled=a,this.timeButton.disabled=a},b.prototype.updateErrorState=function(a){var b=a||this.date;this.clearErrorState(),this.dateUtil.isValidDate(b)||this.ngModelCtrl.$setValidity("valid",null===b),this.ngModelCtrl.$valid||this.inputContainer.classList.add(d)},b.prototype.clearErrorState=function(){this.inputContainer.classList.remove(d),["valid"].forEach(function(a){this.ngModelCtrl.$setValidity(a,!0)},this)},b.prototype.resizeInputElement=function(){this.inputElement.size=this.inputElement.value.length+c},b.prototype.handleInputEvent=function(a){var b=this.inputElement.value,c=b.split(/[\.:]/);if(""===b)this.ngModelCtrl.$setViewValue(null),this.time=null,this.inputContainer.classList.remove(d);else if(c.length<2)this.inputContainer.classList.toggle(d,b);else{var e=Number(c[0]),f=Number(c[1]),g=new Date(this.time);e&&e>=0&&23>=e&&f&&f>=0&&59>=f&&angular.isDate(g)?(g.setHours(e),g.setMinutes(f),this.ngModelCtrl.$setViewValue(g),this.time=g,this.inputContainer.classList.remove(d)):this.inputContainer.classList.toggle(d,b)}},b.prototype.attachTimePane=function(){var a=this.timePane;this.$element.addClass("sg-timepicker-open"),this.$element.find("button").addClass("md-primary");var b=this.inputContainer.getBoundingClientRect(),c=document.body.getBoundingClientRect(),d=b.top-c.top,e=b.left-c.left,h=this.$mdMedia("sm")?g.SM:g.GTSM;e+h>c.right&&c.right-h>0&&(e=c.right-h,a.classList.add("sg-timepicker-pos-adjusted")),a.style.left=e+"px";var i="object"==typeof this.time&&this.time.getMinutes()%5===0?"MIN5":"MIN1",j=this.$mdMedia("sm")?f[i].SM:f[i].GTSM;d+j>c.bottom&&c.bottom-j>0&&(d=c.bottom-j,a.classList.add("sg-timepicker-pos-adjusted")),a.style.top=d+"px",document.body.appendChild(a),this.inputMask.style.left=b.width+"px",this.$$rAF(function(){a.classList.add("md-pane-open")})},b.prototype.detachTimePane=function(){this.$element.removeClass("sg-timepicker-open"),this.$element.find("button").removeClass("md-primary"),this.timePane.classList.remove("md-pane-open"),this.timePane.classList.remove("md-timepicker-pos-adjusted"),this.timePane.parentNode&&this.timePane.parentNode.removeChild(this.timePane)},b.prototype.openTimePane=function(a){if(!this.isTimeOpen&&!this.isDisabled){this.isTimeOpen=!0,this.timePaneOpenedFrom=a.target,this.attachTimePane(),this.$mdUtil.disableScrollAround(this.timePane);var b=this;this.$mdUtil.nextTick(function(){document.body.addEventListener("click",b.bodyClickHandler)},!1),window.addEventListener("resize",this.windowResizeHandler)}},b.prototype.closeTimePane=function(){this.isTimeOpen&&(this.isTimeOpen=!1,this.detachTimePane(),this.timePaneOpenedFrom.focus(),this.timePaneOpenedFrom=null,this.$mdUtil.enableScrolling(),document.body.removeEventListener("click",this.bodyClickHandler),window.removeEventListener("resize",this.windowResizeHandler))},b.prototype.getTimePaneCtrl=function(){return angular.element(this.timePane.querySelector("sg-time-pane")).controller("sgTimePane")},b.prototype.focusTime=function(){var a=this;this.$mdUtil.nextTick(function(){var b=a.getTimePaneCtrl();a.getTimePaneCtrl().focus(null,b)},!1)},b.prototype.setFocused=function(a){this.isFocused=a},b.prototype.handleBodyClick=function(a){if(this.isTimeOpen){var b=this.$mdUtil.getClosest(a.target,"sg-time-pane");b||this.closeTimePane(),this.$scope.$digest()}}}(),function(){"use strict";function a(a){function b(b,c,d,e){function f(a){var b=_.findIndex(i,function(b){return j?b[j]==a:b==a});if(0>b)if(j){var c={};c[j]=a,i.push(c)}else i.push(a);else i.splice(b,1)}var g,h,i,j,k,l,m=c.find("md-grid-tile");for(k=b.$watch(function(){return a(d.sgToggleGrid)(b)},function(a){if(angular.isDefined(a)){var b=a;i=a,d.sgToggleGridAttr&&(j=d.sgToggleGridAttr,b=_.pluck(a,d.sgToggleGridAttr)),_.each(m,function(a){var c=angular.element(a);_.contains(b,c.attr("value"))&&c.addClass("sg-active")}),k()}}),l=function(){var a=angular.element(this),b=a.attr("value");a.toggleClass("sg-active"),f(b)},h=0;h>2,e=(3&a)<<4|b>>4,f=(15&b)<<2|c>>6,g=63&c,isNaN(b)?f=g=64:isNaN(c)&&(g=64),h=h+this._base64_keyStr.charAt(d)+this._base64_keyStr.charAt(e)+this._base64_keyStr.charAt(f)+this._base64_keyStr.charAt(g);return h},String.prototype.base64decode=function(){for(var a,b,c,d,e,f,g,h="",i=0,j=""+this;i>4,b=(15&e)<<4|f>>2,c=(3&f)<<6|g,h+=String.fromCharCode(a),64!=f&&(h+=String.fromCharCode(b)),64!=g&&(h+=String.fromCharCode(c));return h},String.prototype.md5=function(){if(this.length){var a=function(a){function b(a,b){return a<>>32-b}function c(a,b){var c,d,e,f,g;return e=2147483648&a,f=2147483648&b,c=1073741824&a,d=1073741824&b,g=(1073741823&a)+(1073741823&b),c&d?2147483648^g^e^f:c|d?1073741824&g?3221225472^g^e^f:1073741824^g^e^f:g^e^f}function d(a,b,c){return a&b|~a&c}function e(a,b,c){return a&c|b&~c}function f(a,b,c){return a^b^c}function g(a,b,c){return b^(a|~c)}function h(a,e,f,g,h,i,j){return a=c(a,c(c(d(e,f,g),h),j)),c(b(a,i),e)}function i(a,d,f,g,h,i,j){return a=c(a,c(c(e(d,f,g),h),j)),c(b(a,i),d)}function j(a,d,e,g,h,i,j){return a=c(a,c(c(f(d,e,g),h),j)),c(b(a,i),d)}function k(a,d,e,f,h,i,j){return a=c(a,c(c(g(d,e,f),h),j)),c(b(a,i),d)}function l(a){for(var b,c=a.length,d=c+8,e=(d-d%64)/64,f=16*(e+1),g=Array(f-1),h=0,i=0;c>i;)b=(i-i%4)/4,h=i%4*8,g[b]=g[b]|a.charCodeAt(i)<>>29,g}function m(a){var b,c,d="",e="";for(c=0;3>=c;c++)b=a>>>8*c&255,e="0"+b.toString(16),d+=e.substr(e.length-2,2);return d}function n(a){a=a.replace(/rn/g,"n");for(var b="",c=0;cd?b+=String.fromCharCode(d):d>127&&2048>d?(b+=String.fromCharCode(d>>6|192),b+=String.fromCharCode(63&d|128)):(b+=String.fromCharCode(d>>12|224),b+=String.fromCharCode(d>>6&63|128),b+=String.fromCharCode(63&d|128))}return b}var o,p,q,r,s,t,u,v,w,x=Array(),y=7,z=12,A=17,B=22,C=5,D=9,E=14,F=20,G=4,H=11,I=16,J=23,K=6,L=10,M=15,N=21;for(a=n(a),x=l(a),t=1732584193,u=4023233417,v=2562383102,w=271733878,o=0;o=0&&(h.month=c),c>=0}],"%B":[/[^\d\s\.\/\-]{2,}/,function(b){var c=_.indexOf(a.months,b);return c>=0&&(h.month=c),c>=0}],"%y":[/\d\d/,function(a){var b=parseInt(g.getFullYear().toString().substring(2))+5;return h.year=parseInt(a),h.yeard){var e=c;c=d,d=e}for(var f=Math.round((d-c)/864e5)+1,g=0;f>g;g++){var h=new Date;h.setTime(c+864e5*g),b.push(h)}return b},Date.prototype.minutesTo=function(a){var b,c;return b=Math.floor(a.valueOf()-this.valueOf())/1e3/60,c=a.getTimezoneOffset()-this.getTimezoneOffset(),b-c},Date.prototype.stringWithSeparator=function(a){var b=""+(this.getMonth()+1),c=""+this.getDate(),d=this.getYear();return 1e3>d&&(d=""+(d+1900)),1==b.length&&(b="0"+b),1==c.length&&(c="0"+c),"-"==a?str=d+"-"+b+"-"+c:str=c+"/"+b+"/"+d,str},Date.prototype.addDays=function(a){var b,c,d;c=this.getTime(),b=new Date(c),c+=864e5*a,this.setTime(c),d=this.getTimezoneOffset()-b.getTimezoneOffset(),0!==d&&(c=this.getTime()+60*d*1e3,this.setTime(c))},Date.prototype.addHours=function(a){var b=this.getTime();b+=36e5*a,this.setTime(b)},Date.prototype.addMinutes=function(a){var b=this.getTime();b+=6e4*a,this.setTime(b)},Date.prototype.beginOfDay=function(){var a=new Date(this.getTime());return a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0),a},Date.prototype.beginOfWeek=function(a){var b=a-this.getDay();b>0&&(b-=7);var c=this.beginOfDay();return c.setHours(12),c.addDays(b),c},Date.prototype.endOfWeek=function(a){var b=this.beginOfWeek(a);return b.addDays(6),b.setHours(23),b.setMinutes(59),b.setSeconds(59),b.setMilliseconds(999),b},Date.prototype.getDayString=function(){var a=this.getYear();1e3>a&&(a+=1900);var b=""+(this.getMonth()+1);1==b.length&&(b="0"+b),a+=b;var c=""+this.getDate();return 1==c.length&&(c="0"+c),a+=c},Date.prototype.getHourString=function(){var a=this.getHours()+"00";return 3==a.length&&(a="0"+a),a},Date.prototype.format=function(a,b){var c,d,e,f,g=[],h=/%[daAmbByYHIMp]/g,i={"%d":this.getUTCDate(),"%e":this.getUTCDate(),"%a":a.shortDays[this.getUTCDay()],"%A":a.days[this.getUTCDay()],"%m":this.getUTCMonth()+1,"%b":a.shortMonths[this.getUTCMonth()],"%B":a.months[this.getUTCMonth()],"%y":this.getUTCFullYear().toString().substring(2),"%Y":this.getUTCFullYear(),"%H":this.getHours(),"%M":this.getMinutes()};for(i["%I"]=i["%H"]>12?i["%H"]%12:i["%H"],i["%p"]=l(i["%H"]<12?"AM":"PM"),i["%d"]=(i["%d"]<10?"0":"")+i["%d"],i["%e"]=(i["%e"]<10?" ":"")+i["%e"],i["%m"]=(i["%m"]<10?"0":"")+i["%m"],i["%H"]=(i["%H"]<10?"0":"")+i["%H"],i["%I"]=(i["%I"]<10?"0":"")+i["%I"],i["%M"]=(i["%M"]<10?"0":"")+i["%M"],c=b.replace(h,"\x00").split("\x00"),d=b.match(h),e=0,f=d.length;f>=e;e++)c.length&&g.push(c.shift()),g.push(i[d[e]]);return g.join("")}; +function l(){var a,b,c=arguments[0],d=c,e=arguments;for(labels[c]?d=labels[c]:clabels[c]&&(d=clabels[c]),a=1,b=0;a1&&(d=d.replace(/%((%)|s|d)/g,function(b){var c=null;if(b[2])c=b[2];else{switch(c=e[a],b){case"%d":c=parseFloat(c),isNaN(c)&&(c=0)}a++}return c})),d}function hexToRgb(a){var b=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a);return b?{r:parseInt(b[1],16),g:parseInt(b[2],16),b:parseInt(b[3],16)}:null}function contrast(a){var b,c,d=1;if(b=hexToRgb(a)){c=[b.r/255,b.g/255,b.b/255];for(var e=0;e.179?"black":"white"}function guid(){function a(){return(65536*(1+Math.random())|0).toString(16).substring(1)}return(a()+a()+"-"+a()+"-4"+a().substr(0,3)+"-"+a()+"-"+a()+a()+a()).toLowerCase()}!function(){"use strict";function a(a,b,c,d){d.definePalette("sogo-green",{50:"eaf5e9",100:"cbe5c8",200:"aad6a5",300:"88c781",400:"66b86a",500:"56b04c",600:"4da143",700:"388e3c",800:"367d2e",900:"225e1b",A100:"ffffff",A200:"69f0ae",A400:"00e676",A700:"00c853",contrastDefaultColor:"dark",contrastLightColors:["300","400","500","600","700","800","900"]}),d.definePalette("sogo-blue",{50:"f0faf9",100:"e1f5f3",200:"ceebe8",300:"bfe0dd",400:"b2d6d3",500:"a1ccc8",600:"8ebfbb",700:"7db3b0",800:"639997",900:"4d8080",A100:"d4f7fa",A200:"c3f5fa",A400:"53e3f0",A700:"00b0c0",contrastDefaultColor:"light",contrastDarkColors:["50","100","200"]}),d.definePalette("sogo-paper",{50:"fcf7f8",100:"f7f1dc",200:"ede5ca",300:"e6d8ba",400:"e2d2a3",500:"d6c48d",600:"baa870",700:"857545",800:"524517",900:"433809",1000:"000000",A100:"ffffff",A200:"eeeeee",A400:"bdbdbd",A700:"616161",contrastDefaultColor:"dark",contrastLightColors:["800","900"]}),d.theme("default").primaryPalette("sogo-blue",{"default":"900","hue-1":"400","hue-2":"800","hue-3":"A700"}).accentPalette("sogo-green",{"default":"500","hue-1":"A100","hue-2":"300","hue-3":"A700"}).backgroundPalette("grey",{"default":"A100","hue-1":"200","hue-2":"300","hue-3":"500"}),DebugEnabled||(a.debugEnabled(!1),b.debugInfoEnabled(!1)),c.interceptors.push("AuthInterceptor"),c.interceptors.push("ErrorInterceptor")}function b(a,b){return{response:function(c){return c&&/^application\/json/.test(c.config.headers.Accept)&&/^/.test(c.data)?(a.location.reload(!0),b.reject()):c}}}function c(a,b){return{responseError:function(c){return/^application\/json/.test(c.config.headers.Accept)&&a.$broadcast("http:Error",c),b.reject(c)}}}angular.module("SOGo.Common",["ngAnimate","ngMessages","ngSanitize","ngMaterial","mdColors"]).value("sgSettings",{isPopup:document.body.classList.contains("popup"),baseURL:function(){return ApplicationBaseURL||null},activeUser:function(a){var b={login:UserLogin||null,identification:UserIdentification||null,email:UserEmail||null,language:UserLanguage||null,folderURL:UserFolderURL||null,isSuperUser:IsSuperUser||null,path:{calendar:UserCalendarPath||null,contacts:UserContactsPath||null,mail:UserMailPath||null,preferences:UserPreferencesPath||null,administration:IsSuperUser?UserAdministrationPath:null,logoff:UserLogoffPath||null}};return a?b[a]:b}}).constant("sgColors",{selection:["#FFFFFF","#330033","#C0C0C0","#999999","#666666","#333333","#000000","#FFCCCC","#FF6666","#FF0000","#CC0000","#990000","#660000","#330000","#FFCC99","#FF9966","#FF9900","#FF6600","#CC6600","#993300","#663300","#FFFF99","#FFFF66","#FFCC66","#FFCC33","#CC9933","#996633","#663333","#FFFFCC","#FFFF33","#FFFF00","#FFCC00","#999900","#666600","#333300","#CCCCCC","#66FF99","#33FF33","#33CC00","#009900","#006600","#003300","#99FFFF","#33FFFF","#66CCCC","#00CCCC","#339999","#336666","#003333","#CCFFFF","#66FFFF","#33CCFF","#3366FF","#3333FF","#000099","#000066","#CCCCFF","#9999FF","#6666CC","#6633FF","#6600CC","#333399","#330099","#FFCCFF","#FF99FF","#CC66CC","#CC33CC","#993399","#663366","#99FF99"]}).constant("sgConstant",{xs:"(max-width: 599px)","gt-xs":"(min-width: 600px)",sm:"(min-width: 600px) and (max-width: 959px)","gt-sm":"(min-width: 960px)",md:"(min-width: 960px) and (max-width: 1279px)","gt-md":"(min-width: 1280px)",lg:"(min-width: 1280px) and (max-width: 1919px)","gt-lg":"(min-width: 1920px)",xl:"(min-width: 1920px)"}).config(a).factory("AuthInterceptor",b).factory("ErrorInterceptor",c),a.$inject=["$logProvider","$compileProvider","$httpProvider","$mdThemingProvider"],b.$inject=["$window","$q"],c.$inject=["$rootScope","$q"]}(),function(){"use strict";function a(a){c=a}function b(a,b,d){function e(a){var b=a.join("");return b}function f(a,b,c,d,e,f){if(e){var g="rgb("+e.value[0]+","+e.value[1]+","+e.value[2]+")",h="rgb("+e.contrast[0]+","+e.contrast[1]+","+e.contrast[2]+")",i={theme:c,palette:d,value:g,contrast:h,hue:f};s.insertRule(a(i),t),t+=1,s.insertRule(b(i),t),t+=1}}function g(a,b,c,d,e){if(d){var f="rgb("+d.value[0]+","+d.value[1]+","+d.value[2]+")";s.insertRule(a({theme:b,palette:c,value:f,hue:e}),t),t+=1}}function h(){var a=b[0].head.querySelector('style[title="Dynamic-Generated-by-mdColors"]');return null===a&&(a=b[0].createElement("style"),a.title="Dynamic-Generated-by-mdColors",a.appendChild(b[0].createTextNode("")),b[0].head.appendChild(a)),a.sheet}for(var i=a(e([".md-{{theme}}-theme",".md-fg"])+" { color:{{value}};}"),j=a(e([".md-{{theme}}-theme",".md-bg"])+" { background-color:{{value}};}"),k=a(e([".md-{{theme}}-theme",".md-bdr"])+" { border-color:{{value}};}"),l=a(e([".md-{{theme}}-theme",".md-{{hue}}",".md-fg"])+" { color:{{value}};}"),m=a(e([".md-{{theme}}-theme",".md-{{hue}}",".md-bg"])+" { background-color:{{value}};}"),n=a(e([".md-{{theme}}-theme",".md-{{palette}}",".md-fg"])+" { color:{{value}};}"),o=a(e([".md-{{theme}}-theme",".md-{{palette}}",".md-bg"])+" { background-color:{{value}}; color:{{contrast}}; }"),p=a(e([".md-{{theme}}-theme",".md-{{palette}}",".md-bdr"])+" { border-color:{{value}};}"),q=a(e([".md-{{theme}}-theme",".md-{{palette}}.md-{{hue}}",".md-fg"])+" { color:{{value}};}"),r=a(e([".md-{{theme}}-theme",".md-{{palette}}.md-{{hue}}",".md-bg"])+" { background-color:{{value}};}"),s=h(),t=0;s.cssRules.length>0;)s.deleteRule(0);angular.forEach(c._THEMES,function(a,b){f(i,j,b,"primary",c._PALETTES[a.colors.primary.name][a.colors.primary.hues["default"]]),f(l,m,b,"primary",c._PALETTES[a.colors.primary.name][a.colors.primary.hues["hue-2"]],"hue-2"),f(l,m,b,"primary",c._PALETTES[a.colors.primary.name][a.colors.primary.hues["hue-3"]],"hue-3"),f(l,m,b,"primary",c._PALETTES[a.colors.primary.name][a.colors.primary.hues["hue-1"]],"hue-1"),g(k,b,"primary",c._PALETTES[a.colors.primary.name][a.colors.primary.hues["default"]]),angular.forEach(a.colors,function(a,d){f(n,o,b,d,c._PALETTES[a.name][a.hues["default"]]),g(p,b,d,c._PALETTES[a.name][a.hues["default"]]),f(q,r,b,d,c._PALETTES[a.name][a.hues["hue-2"]],"hue-2"),f(q,r,b,d,c._PALETTES[a.name][a.hues["hue-3"]],"hue-3"),f(q,r,b,d,c._PALETTES[a.name][a.hues["hue-1"]],"hue-1")})})}var c;angular.module("mdColors",["ngMaterial"]).config(a).run(b),a.$inject=["$mdThemingProvider"],b.$inject=["$interpolate","$document","$log"]}(),function(){"use strict";function a(a){return a.decodeURIComponent}a.$inject=["$window"],angular.module("SOGo.Common").filter("decodeUri",a)}(),function(){"use strict";function a(a){return a.encodeURIComponent}a.$inject=["$window"],angular.module("SOGo.Common").filter("encodeUri",a)}(),function(){"use strict";function a(a){return function(b){var c=angular.element("
"+b+"
");return c.find("a").attr("target","_blank"),a.trustAs("html",c.html())}}a.$inject=["$sce"],angular.module("SOGo.Common").filter("ensureTarget",a)}(),function(){"use strict";function a(){return l}angular.module("SOGo.Common").filter("loc",a)}(),function(){"use strict";function a(){return function(a){for(var b=[],c=0;c",'
',' error_outline'," "+l(c)+"","
",""].join(""),hideDelay:5e3,position:"top right"}):i.debug("untrap error")}b.isPopup=k.isPopup,b.activeUser=k.activeUser(),b.baseURL=k.baseURL(),b.leftIsClose=h(j.xs),b.currentDay=window.currentDay,c(function(){d(function(){e.get("../date").then(function(a){b.currentDay=a})},864e5)},1e3*window.currentDay.secondsBeforeTomorrow),b.toggleLeft=function(){b.leftIsClose=n(),f("left").toggle().then(function(){i.debug("toggle left is done")})},b.toggleRight=function(){f("right").toggle().then(function(){i.debug("toggle right is done")})},b.$watch(function(){return h(j["gt-sm"])},function(a){b.isGtMedium=a,a&&(b.leftIsClose=!1)}),a.$on("http:Error",o),m.getAlarms()}a.$inject=["$rootScope","$scope","$timeout","$interval","$http","$mdSidenav","$mdToast","$mdMedia","$log","sgConstant","sgSettings","Alarm"],angular.module("SOGo.Common").controller("navController",a)}(),function(){"use strict";function a(a){this.folderId=a}a.factory=["$q","$timeout","sgSettings","Resource","User",function(b,c,d,e,f){return angular.extend(a,{$q:b,$timeout:c,$$resource:new e(d.activeUser("folderURL"),d.activeUser()),$User:f}),a}],angular.module("SOGo.Common").factory("Acl",a.factory),a.prototype.$users=function(b){var c,d=this,e=a.$q.defer();if(!this.users){var f;return f=angular.isDefined(b)?a.$$resource.userResource(b).fetch(this.folderId,"acls"):a.$$resource.fetch(this.folderId,"acls"),f.then(function(f){return d.users=[],angular.forEach(f.users,function(e){c=new a.$User(e),c.canSubscribeUser=c.isSubscribed,c.wasSubscribed=c.isSubscribed,c.$rights=angular.bind(c,c.$acl,d.folderId,b),d.users.push(c)}),e.resolve(d.users),d.users})}return e.resolve(this.users),e.promise},a.prototype.$addUser=function(b,c){var d=this,e=a.$q.defer(),f={uid:b.uid};if(!b.uid||_.indexOf(_.pluck(this.users,"uid"),b.uid)>-1)e.resolve();else{var g;g=angular.isDefined(c)?a.$$resource.userResource(c).fetch(this.folderId,"addUserInAcls",f):a.$$resource.fetch(this.folderId,"addUserInAcls",f),g.then(function(){b.wasSubscribed=!1,b.userClass=b.isGroup?"normal-group":"normal-user",b.$rights=angular.bind(b,b.$acl,d.folderId),d.users.push(b),e.resolve(b)},function(a,b){e.reject(l("An error occured please try again."))})}return e.promise},a.prototype.$removeUser=function(b){var c=this,d={uid:b};return a.$$resource.fetch(this.folderId,"removeUserFromAcls",d).then(function(){var a=_.indexOf(_.pluck(c.users,"uid"),b);a>=0&&c.users.splice(a,1)})},a.prototype.$resetUsersRights=function(){angular.forEach(this.users,function(a){a.$resetRights()})},a.prototype.$saveUsersRights=function(b){var c=this,d=a.$q.defer(),e=a.$q.defer(),f={action:"saveUserRights"},g=[];if(angular.forEach(this.users,function(a){a.$rightsAreDirty()&&g.push(a.$omit())}),g.length){var h;h=angular.isDefined(b)?a.$$resource.userResource(b).save(this.folderId,g,f):a.$$resource.save(this.folderId,g,f),h.then(function(){angular.forEach(c.users,function(a){a.$rightsAreDirty()&&(a.$shadowRights=angular.copy(a.rights))}),d.resolve()},d.reject)}else d.resolve();return g=[],angular.forEach(this.users,function(a){!a.wasSubscribed&&a.isSubscribed&&g.push(a.uid)}),g.length?(f={uids:g.join(",")},a.$$resource.fetch(this.folderId,"subscribeUsers",f).then(function(){angular.forEach(c.users,function(a){a.wasSubscribed=a.isSubscribed}),e.resolve()},e.reject)):e.resolve(),a.$q.all([d.promise,e.promise])}}(),function(){"use strict";function a(){this.currentAlarm=null}function b(b,c,d,e){return angular.extend(a,{$timeout:b,$$resource:new d(c.activeUser("folderURL")+"Calendar",c.activeUser()),$toast:e}),a}a.getAlarms=function(){var b=this,c=new Date,d=Math.floor(c.getTime()/1e3);this.$$resource.fetch("","alarmslist?browserTime="+d).then(function(c){var d=c.alarms.sort(function(a,b){var c=parseInt(a[2]),d=parseInt(b[2]);return d-c});if(d.length>0){var e=d.pop(),f=new Date,g=Math.floor(f.getTime()/1e3),h=e[0]+"/"+e[1],i=parseInt(e[2]),j=i;i>0&&(j-=g);var k=(new Date(1e3*i),angular.bind(b,a.showAlarm,h));b.currentAlarm&&b.$timeout.cancel(b.currentAlarm),b.currentAlarm=b.$timeout(k,1e3*j)}})},a.showAlarm=function(a){var b=this;this.$$resource.fetch(a,"?resetAlarm=yes").then(function(c){function d(a,c,d){a.reminder="10",a.cancel=function(){c.hide()},a.ok=function(){b.$$resource.fetch(d,"view?snoozeAlarm="+a.reminder),c.hide()}}b.$toast.show({position:"top right",hideDelay:0,template:["",'
'," ",' ",' '," ",l("5 minutes")," "," ",l("10 minutes")," "," ",l("15 minutes")," "," ",l("30 minutes")," "," ",l("45 minutes")," "," ",l("1 hour")," "," ",l("1 day")," "," "," ",' ',l("Cancel")," ",' ',l("Ok")," ","
","
"].join(""),locals:{url:a},controller:d}),d.$inject=["scope","$mdToast","url"]})},b.$inject=["$timeout","sgSettings","Resource","$mdToast"],angular.module("SOGo.Common").factory("Alarm",b)}(),function(){"use strict";function a(){function a(a){var b,c,d,e,f,g;for(b=null,c=a+"=",d=document.cookie.split(";"),e=0;!b&&e0&&(f=f.substr(g)),0===f.indexOf(c)&&(b=f.substr(c.length))}return b}function b(){var b,c=null,d=a("0xHIGHFLYxSOGo");return d&&d.length>8&&(b=decodeURIComponent(d.substr(8)),c=b.base64decode().split(":")),c}function c(a,b){var c,d,e,f,g,h,i,j;return c=a,b&&(c+="@"+b.value),d=""+window.location.href,e=ApplicationBaseURL+"/"+encodeURIComponent(c),"/"==e[0]&&(g=d.split("/"),h=g[2],i=g[0],e=i+"//"+h+e),g=e.split("/"),g.splice(0,3),f=g.join("/"),j=!d.startsWith(e)&&!d.startsWith(f)||d.endsWith("/logoff")?e:d}function d(a,d,e){var f;return f={login:function(f){var g,h=a.defer(),i=f.username,j=f.password,k=f.domain,m=f.rememberLogin?1:0;return f.loginSuffix&&!i.endsWith(f.loginSuffix)&&(i+=loginSuffix,k=!1),f.language&&"WONoSelectionString"!=f.language&&(g=f.language),d({method:"POST",url:"/SOGo/connect",data:{userName:i,password:j,domain:k,language:g,rememberLogin:m}}).then(function(a){var d=a.data,e=b();e?"undefined"!=typeof d.expire&&"undefined"!=typeof d.grace?d.expire<0&&d.grace>0?h.reject({grace:d.grace}):d.expire>0&&-1==d.grace?h.reject({expire:d.expire}):h.resolve(c(i,k)):h.resolve(c(i,k)):h.reject(l("cookiesNotEnabled"))},function(a){var b,c,d=a.data;d&&d.LDAPPasswordPolicyError?(c=d.LDAPPasswordPolicyError,b=c==e.PolicyNoError?l("Wrong username or password."):c==e.PolicyAccountLocked?l("Your account was locked due to too many failed attempts."):l("Login failed due to unhandled error case: ")+c):b=l("Unhandled error response"),h.reject({error:b})}),h.promise},changePassword:function(c){var f=a.defer(),g=b();return d({method:"POST",url:"/SOGo/so/changePassword",data:{userName:g[0],password:g[1],newPassword:c}}).then(f.resolve,function(a){var b,c=a.data,d=c.LDAPPasswordPolicyError;d?d==e.PolicyNoError?b=l("Password change failed"):d==e.PolicyPasswordModNotAllowed?b=l("Password change failed - Permission denied"):d==e.PolicyInsufficientPasswordQuality?b=l("Password change failed - Insufficient password quality"):d==e.PolicyPasswordTooShort?b=l("Password change failed - Password is too short"):d==e.PolicyPasswordTooYoung?b=l("Password change failed - Password is too young"):d==e.PolicyPasswordInHistory?b=l("Password change failed - Password is in history"):(b=l("Unhandled policy error: %{0}").formatted(d),d=e.PolicyPasswordUnknown):(d=e.PolicyPasswordSystemUnknown,b=_("Unhandled error response")),f.reject(b)}),f.promise}}}this.$get=d,d.$inject=["$q","$http","passwordPolicyConfig"]}angular.module("SOGo.Authentication",[]).constant("passwordPolicyConfig",{PolicyPasswordChangeUnsupported:-3,PolicyPasswordSystemUnknown:-2,PolicyPasswordUnknown:-1,PolicyPasswordExpired:0,PolicyAccountLocked:1,PolicyChangeAfterReset:2,PolicyPasswordModNotAllowed:3,PolicyMustSupplyOldPassword:4,PolicyInsufficientPasswordQuality:5,PolicyPasswordTooShort:6,PolicyPasswordTooYoung:7,PolicyPasswordInHistory:8,PolicyNoError:65535}).provider("Authentication",a)}(),function(){"use strict";function a(){}function b(b,c){return angular.extend(a,{$q:b,$modal:c}),a}a.alert=function(a,b){var c=this.$modal.alert().title(a).htmlContent(b).ok(l("OK"));this.$modal.show(c)},a.confirm=function(a,b,c){var d=this.$modal.confirm().title(a).htmlContent(b).ok(c&&c.ok?c.ok:l("OK")).cancel(c&&c.cancel?c.cancel:l("Cancel"));return this.$modal.show(d)},a.prompt=function(a,b,c){function d(b,c){b.title=a,b.name="",b.cancel=function(){f.reject(),c.hide()},b.ok=function(){f.resolve(b.name),c.hide()}}var e=c||{},f=this.$q.defer();return this.$modal.show({parent:angular.element(document.body),clickOutsideToClose:!0,escapeToClose:!0,template:['',' ','

'," "," ",' '," ","
"," ",' '," "+l("Cancel")," ",' '," "+l("OK")," "," ","
"].join(""),controller:d}),d.$inject=["scope","$mdDialog"],f.promise},b.$inject=["$q","$mdDialog"],angular.module("SOGo.Common").factory("Dialog",b)}(),function(){"use strict";function a(){return function(a,b,c,d){var e,f,g,h=b,i=c;return a?(e=a.indexOf("<"),e>=0&&(f=a.indexOf(">",e),f>e&&(a=a.substring(e+1,f))),b||(h=48),g=a.md5(),i&&"none"!=i||(c=d&&d.no_404?"mm":"404"),"https://www.gravatar.com/avatar/"+g+"?s="+h+"&d="+c):""}}angular.module("SOGo.Common").factory("Gravatar",a)}(),function(){"use strict";function a(a,b,c,d,e){angular.extend(this,{_http:a,_q:b,_path:c,_activeUser:d}),angular.extend(this,e),this._path=this._path.replace(/\/$/,"")}a.$factory=["$http","$q",function(b,c){return function(d,e,f){return new a(b,c,d,e,f)}}],angular.module("SOGo.Common").factory("Resource",a.$factory),a.prototype.userResource=function(b){var c=_.compact(this._activeUser.folderURL.split("/"));return c.splice(c.length-1,1,escape(b)),new a(this._http,this._q,"/"+c.join("/"),this._activeUser)},a.prototype.fetch=function(a,b,c){var d=this._q.defer(),e=[this._path];return a&&e.push(a.split("/")),b&&e.push(b),e=_.compact(_.flatten(e)).join("/"),this._http({method:"GET",url:e,params:c}).then(function(a){return d.resolve(a.data)},function(a){return 404==a.status?d.reject():void 0}),d.promise},a.prototype.newguid=function(a){var b=this._q.defer(),c=this._path+"/"+a+"/newguid";return this._http.get(c).then(function(a){return b.resolve(a.data)},b.reject),b.promise},a.prototype.create=function(a,b){var c=this._q.defer(),d=this._path+"/"+a;return this._http.post(d,{name:b}).then(function(a){return c.resolve(a.data)},c.reject),c.promise},a.prototype.post=function(a,b,c){var d=this._q.defer(),e=[this._path];return a&&e.push(a),b&&e.push(b),e=_.compact(_.flatten(e)).join("/"),this._http.post(e,c).then(function(a){return d.resolve(a.data)},d.reject),d.promise},a.prototype.save=function(a,b,c){var d=(this._q.defer(),c&&c.action?c.action:"save");return this.post(a,d,b)},a.prototype.remove=function(a){var b=this._q.defer(),c=this._path+"/"+a+"/delete";return this._http.get(c).then(function(a){return b.resolve(a.data)},b.reject),b.promise}}(),function(){"use strict";function a(a){a&&this.init(a)}a.factory=["$q","$log","sgSettings","Resource","Gravatar",function(b,c,d,e,f){return angular.extend(a,{$q:b,$log:c,$$resource:new e(d.activeUser("folderURL"),d.activeUser()),$gravatar:f,$query:"",$users:[]}),a}],angular.module("SOGo.Common").factory("User",a.factory),a.$filter=function(b,c,d){var e={search:b};if(!d||!d.dry){if(!b)return a.$users.splice(0,a.$users.length),a.$q.when(a.$users);if(a.$query==b)return a.$q.when(a.$users);a.$query=b}return a.$$resource.fetch(null,"usersSearch",e).then(function(b){var e,f,g,h,i=function(a){return this.uid==a.uid};for(d?d.dry?h=[]:d.results&&(h=d.results):h=a.$users,e=c?_.filter(b.users,function(a){return!_.find(c,i,a)}):b.users,f=h.length-1;f>=0;f--)g=h[f],_.find(e,i,g)||h.splice(f,1);return _.each(e,function(b,c){if(_.isUndefined(_.find(h,i,b))){var d=new a(b);h.splice(c,0,d)}}),a.$log.debug(h),h})},a.prototype.init=function(b){angular.extend(this,b),this.$$shortFormat||(this.$$shortFormat=this.$shortFormat()),this.$$image||(this.$$image=this.image||a.$gravatar(this.c_email,32,a.$alternateAvatar,{no_404:!0})),this.empty=" "},a.prototype.$shortFormat=function(a){var b=this.cn||this.c_email,c=this.c_email,d=a&&a.email===!1;return!d&&c&&b!=c&&(b+=" <"+c+">"),b},a.prototype.$acl=function(b,c){var d=this,e=a.$q.defer(),f={uid:this.uid};if(this.$shadowRights)e.resolve(this.rights);else{var g;g=angular.isDefined(c)?a.$$resource.userResource(c).fetch(b,"userRights",f):a.$$resource.fetch(b,"userRights",f),g.then(function(a){return d.rights=a,d.$shadowRights=angular.copy(a),e.resolve(a),a})}return e.promise},a.prototype.$isAnonymous=function(){return"anonymous"==this.uid},a.prototype.$isSpecial=function(){return this.userClass&&"public-user"==this.userClass},a.prototype.$confirmRights=function(a){var b=!1;return this.$confirmation?!1:(_.some(_.values(this.rights))&&("anonymous"==this.uid?"AddressBook"==a.constructor.name?b=l('Potentially anyone on the Internet will be able to access your address book "%{0}", even if they do not have an account on this system. Is this information suitable for the public Internet?',a.name):"Calendar"==a.constructor.name&&(b=l('Potentially anyone on the Internet will be able to access your calendar "%{0}", even if they do not have an account on this system. Is this information suitable for the public Internet?',a.name)):("anyone"==this.uid||""==this.uid)&&("AddressBook"==a.constructor.name?b=l('Any user with an account on this system will be able to access your address book "%{0}". Are you certain you trust them all?',a.name):"Calendar"==a.constructor.name?b=l('Any user with an account on this system will be able to access your calendar "%{0}". Are you certain you trust them all?',a.name):"Mailbox"==a.constructor.name&&(b=l('Any user with an account on this system will be able to access your mailbox "%{0}". Are you certain you trust them all?',a.name)))),this.$confirmation=b,b)},a.prototype.$rightsAreDirty=function(){return this.rights&&!_.isEqual(this.rights,this.$shadowRights)},a.prototype.$resetRights=function(a){var b=this;a?_.map(_.keys(this.rights),function(a){angular.isString(b.rights[a])?b.rights[a]="None":b.rights[a]=0}):this.rights=angular.copy(this.$shadowRights)},a.prototype.$folders=function(b){var c=this,d=a.$q.defer(),e={type:b};return this.$$folders?d.resolve(this.$$folders):a.$$resource.userResource(this.uid).fetch(null,"foldersSearch",e).then(function(a){c.$$folders=a.folders,d.resolve(a.folders)}),d.promise},a.prototype.$omit=function(){var a={};return angular.forEach(this,function(b,c){"constructor"!=c&&"$"!=c[0]&&(a[c]=b)}),a},a.prototype.toString=function(){return"[User "+this.c_email+"]"}}(),function(){"use strict";function a(a,b){return function(c){b(function(){a.$broadcast("sgFocusOn",c)})}}a.$inject=["$rootScope","$timeout"],angular.module("SOGo.Common").factory("sgFocus",a)}(),function(){"use strict";function a(){return{restrict:"AE",scope:{},bindToController:{size:"@",email:"=sgEmail",src:"=sgSrc"},template:["person",''].join(""),link:b,controller:"sgAvatarImageController",controllerAs:"vm"}}function b(a,b,c,d){var e=b.find("img"),f=b.find("md-icon");c.size&&(e.attr("width",c.size),e.attr("height",c.size)),d.img=e,d.genericImg=f}function c(a,b,c,d,e,f){function g(a){var b=f(a,j.size,e.defaults.SOGoAlternateAvatar);c({method:"GET",url:b,cache:!0,headers:{Accept:"image/*"}}).then(function(){j.url||(j.url=b,j.urlEmail=a,i())},function(){h()})}function h(){j.url=null,j.urlEmail=null,j.img.addClass("ng-hide"),j.genericImg.removeClass("ng-hide")}function i(){j.genericImg.addClass("ng-hide"),j.img.removeClass("ng-hide")}var j;j=this,e.ready().then(function(){a.$watch("vm.email",function(a,b){a&&j.urlEmail!=a?(h(),g(a)):a||h()})}),"sg-src"in b[0].attributes&&a.$watch("vm.src",function(a){a&&(j.url=a,j.urlEmail=""+j.email,i())})}c.$inject=["$scope","$element","$http","$q","Preferences","Gravatar"],angular.module("SOGo.Common").directive("sgAvatarImage",a).controller("sgAvatarImageController",c)}(),function(){"use strict";function a(){function a(a,b,c,d){d.$render=function(){a.sgColor=d.$viewValue,a.sgIconColor=contrast(d.$viewValue)}}return{restrict:"E",require:"ngModel",template:["",' ',' color_lens'," ",' ',' ',' ',' check_box'," "," "," ",""].join(""),replace:!0,controller:b,link:a}}function b(a,b,c){var d=b.controller("ngModel");a.sgColors=c.selection,a.setColor=function(b){a.sgColor=b,a.sgIconColor=contrast(b),d.$setViewValue(b)}}b.$inject=["$scope","$element","sgColors"],angular.module("SOGo.Common").directive("sgColorPicker",a)}(),function(){"use strict";function a(a){function b(b,c,d){var e=b.$watch(function(a){return a.$eval(d.sgCompile)},function(d){c.html(d),a(c.contents())(b),e()})}return{restrict:"A",link:b}}a.$inject=["$compile"],angular.module("SOGo.Common").directive("sgCompile",a)}(),function(){"use strict";function a(){var a=13;return function(b,c,d){c.bind("keydown keypress",function(c){c.which===a&&(b.$apply(d.sgEnter),c.preventDefault())})}}angular.module("SOGo.Common").directive("sgEnter",a)}(),function(){"use strict";function a(){var a=27;return function(b,c,d){c.bind("keydown",function(c){c.keyCode===a&&b.$apply(d.sgEscape)})}}angular.module("SOGo.Common").directive("sgEscape",a)}(),function(){"use strict";function a(){return function(a,b,c){a.$on("sgFocusOn",function(a,d){d===c.sgFocusOn&&(b[0].focus(),b[0].select())})}}angular.module("SOGo.Common").directive("sgFocusOn",a)}(),function(){"use strict";function a(){function a(){var a=this;a.contrast=contrast}return{restrict:"E",require:"ngModel",scope:{ngModel:"="},replace:!0,bindToController:!0,controller:a,controllerAs:"cssCtrl",template:['"].join("")}}angular.module("SOGo.Common").directive("sgFolderStylesheet",a)}(),function(){"use strict";function a(){return{restrict:"A",scope:{placeholder:"=sgPlaceholder"},link:function(a,b,c){a.$watch("placeholder",function(){b[0].placeholder=a.placeholder})}}}angular.module("SOGo.Common").directive("sgPlaceholder",a)}(),function(){"use strict";function a(a){function b(b,c){var d=(b.find("md-input-container"),b.find("input")),e=b.find("md-select"),f=b.find("md-button");return d.attr("ng-model","$sgSearchController.searchText"),d.attr("ng-model-options","$sgSearchController.searchTextOptions"),d.attr("ng-change","$sgSearchController.onChange()"),e&&(e.attr("ng-model","$sgSearchController.searchField"),e.attr("ng-change","$sgSearchController.onChange()")),f&&f.attr("sg-search-cancel")?(f.attr("ng-click",f.attr("sg-search-cancel")),f.removeAttr("sg-search-cancel")):f=null,function(b,c,e,g){var h=c.find("button");g.formName=c.attr("name"),g.inputName=d.attr("name"),g.allowDot=a(c.attr("sg-allow-dot"))(b),g.doSearch=a(c.attr("sg-search")),f&&h&&h.on("click",g.cancelSearch)}}return{restrict:"A",controller:"sgSearchController",controllerAs:"$sgSearchController",priority:1001,compile:b}}function b(){function a(a,b){return function(a,b,c,d,e){e(function(a){b.append(a)})}}return{restrict:"A",priority:1e3,transclude:!0,compile:a}}function c(a,b,c){var d,e=this;d=angular.isNumber(a.minimumSearchLength)?a.minimumSearchLength:2,e.searchText=null,e.searchTextOptions={updateOn:"default blur",debounce:{"default":300,blur:0}},e.onChange=function(){var a=b[e.formName],c=a[e.inputName],d=c.$viewValue;(e.allowDot&&"."==d||a.$valid&&d)&&("."==d&&c.$setValidity("minlength",!0),e.doSearch(b,{searchText:d,searchField:e.searchField}))},e.cancelSearch=function(){e.searchText=null}}a.$inject=["$parse"], +c.$inject=["$window","$scope","$element"],angular.module("SOGo.Common").controller("sgSearchController",c).directive("sgSearch",a).directive("sgSearch",b)}(),function(){"use strict";function a(a){return{restrict:"A",scope:{folderType:"@sgSubscribe",onFolderSelect:"&sgSubscribeOnSelect"},replace:!1,bindToController:!0,controller:c,controllerAs:"$sgSubscribeDialogController",link:b}}function b(a,b,c,d){b.find("input");b.on("click",d.showDialog)}function c(a){var b=this;b.showDialog=function(){a.show({templateUrl:"../Contacts/UIxContactsUserFolders",clickOutsideToClose:!0,locals:{folderType:b.folderType,onFolderSelect:b.onFolderSelect},controller:d,controllerAs:"subscribe"})}}function d(a,b,c,d){var e=this;e.selectedUser=null,e.users=[],e.searchTextOptions={updateOn:"default blur",debounce:{"default":300,blur:0}},e.onChange=function(a){d.$filter(e.searchText,null,{results:e.users}).then(function(b){a.$setValidity("matches",b.length>0),a.$setTouched(),e.selectedUser&&_.isUndefined(_.find(b,function(a){return a.uid==e.selectedUser.uid}))&&(e.selectedUser=null)})},e.selectUser=function(a){e.selectedUser==e.users[a]?e.selectedUser=null:e.users[a].$folders(b).then(function(){e.selectedUser=e.users[a]})},e.selectFolder=function(a){c({folderData:a})},e.close=function(){a.hide()}}a.$inject=["User"],c.$inject=["$mdDialog"],d.$inject=["$mdDialog","folderType","onFolderSelect","User"],angular.module("SOGo.Common").directive("sgSubscribe",a)}(),function(){"use strict";function a(){return{template:['
','
','
','
',' {{hour.displayName}}',"
","
","
",'
','
','
',' {{minute.displayName}}',"
","
","
",'
','
','
',' {{minute.displayName}}',"
","
","
",'
',' ',"
","
"].join(""),scope:{},require:["ngModel","sgTimePane"],controller:b,controllerAs:"ctrl",bindToController:!0,link:function(a,b,c,d){var e=d[0],f=d[1],g=b;f.configureNgModel(e,f,g)}}}function b(a,b,c,d,f,g,h,i,j,k,l){var m;this.$scope=c,this.$element=a,this.timePaneElement=a[0].querySelector(".sg-time-pane"),this.$animate=d,this.$q=f,this.$mdInkRipple=k,this.$mdUtil=l,this.keyCode=g.KEY_CODE,this.dateUtil=i,this.id=e++,this.ngModelCtrl=null,this.selectedTime=null,this.displayTime=null,this.isInitialized=!1,c.hours=[],c.hours[0]=[],c.hours[0][0]=[],c.hours[0][1]=[],c.hours[1]=[],c.hours[1][0]=[],c.hours[1][1]=[];for(var n=0;6>n;n++)c.hours[0][0][n]={id:"tp-"+this.id+"-hour-"+n,displayName:10>n?"0"+n:""+n,selected:!1},c.hours[0][1][n]={id:"tp-"+this.id+"-hour-"+(n+6),displayName:10>n+6?"0"+(n+6):""+(n+6),selected:!1},c.hours[1][0][n]={id:"tp-"+this.id+"-hour-"+(n+12),displayName:""+(n+12),selected:!1},c.hours[1][1][n]={id:"tp-"+this.id+"-hour-"+(n+18),displayName:""+(n+18),selected:!1};for(c.min5=[],c.min5[0]=[],c.min5[1]=[],n=0;6>n;n++)m=5*n,c.min5[0][n]={id:"tp-"+this.id+"-minute5-"+m,displayName:10>m?":0"+m:":"+m,selected:!0},c.min5[1][n]={id:"tp-"+this.id+"-minute5-"+(m+30),displayName:":"+(m+30),selected:!1};for(c.min1=[],n=0;12>n;n++){c.min1[n]=[];for(var o=0;5>o;o++)m=5*n+o,c.min1[n][o]={id:"tp-"+this.id+"-minute-"+m,displayName:10>m?":0"+m:":"+m,selected:!0}}c.show5min=!0,c.getToggleBtnLbl=function(){return c.is5min()?">>":"<<"},c.toggleManual5min=function(){c.manual5min=!c.is5min()},c.is5min=function(){return c.manual5min===!0||c.manual5min===!1?c.manual5min:c.show5min},b.tabindex||a.attr("tabindex","-1");var p=this;this.hourClickHandler=function(a){var b=new Date(p.displayTime);b.setHours(Number(a)),p.setNgModelValue(b,"hours")},c.hourClickHandler=this.hourClickHandler,this.minuteClickHandler=function(a){var b=a.substr(1),c=new Date(p.displayTime);c.setMinutes(Number(b)),p.setNgModelValue(c,"minutes")},c.minuteClickHandler=this.minuteClickHandler,this.attachTimePaneEventListeners()}angular.module("SOGo.Common").directive("sgTimePane",a);var c="md-bg",d="md-focus",e=0;b.$inject=["$element","$attrs","$scope","$animate","$q","$mdConstant","$mdTheming","$$mdDateUtil","$mdDateLocale","$mdInkRipple","$mdUtil"],b.prototype.configureNgModel=function(a,b,c){this.ngModelCtrl=a;var d=this;a.$render=function(){d.changeSelectedTime(d.ngModelCtrl.$viewValue,b,c)}},b.prototype.changeSelectedTime=function(a,b,d){var e=this.selectedTime;this.selectedTime=a,this.changeDisplayTime(a).then(function(){if(e){var d=e.getHours(),f=document.getElementById("tp-"+b.id+"-hour-"+d);f&&(f.classList.remove(c),f.setAttribute("aria-selected","false"));var g=e.getMinutes(),h=document.getElementById("tp-"+b.id+"-minute-"+g);h&&(h.classList.remove(c),h.setAttribute("aria-selected","false"));var i=document.getElementById("tp-"+b.id+"-minute5-"+g);i&&(i.classList.remove(c),i.setAttribute("aria-selected","false"))}if(a){var j,k=a.getHours(),l=document.getElementById("tp-"+b.id+"-hour-"+k);l&&(l.classList.add(c),l.setAttribute("aria-selected","true"));var m=a.getMinutes();m%5===0?(b.$scope.show5min=!0,j=document.getElementById("tp-"+b.id+"-minute5-"+m),j&&(j.classList.add(c),j.setAttribute("aria-selected","true"))):b.$scope.show5min=!1,j=document.getElementById("tp-"+b.id+"-minute-"+m),j&&(j.classList.add(c),j.setAttribute("aria-selected","true"))}})},b.prototype.changeDisplayTime=function(a){var b=new Date(a);return this.isInitialized?this.dateUtil.isValidDate(b)?(this.displayTime=b,this.$q.when()):this.$q.when():(this.buildInitialTimePaneDisplay(),this.$q.when())},b.prototype.buildInitialTimePaneDisplay=function(){this.displayTime=this.selectedTime||this.today,this.isInitialized=!0},b.prototype.attachTimePaneEventListeners=function(){this.$element.on("keydown",angular.bind(this,this.handleKeyEvent))},b.prototype.handleKeyEvent=function(a){var b=this;this.$scope.$apply(function(){return a.which==b.keyCode.ESCAPE||a.which==b.keyCode.TAB?(b.$scope.$emit("md-time-pane-close"),void(a.which==b.keyCode.TAB&&a.preventDefault())):a.which===b.keyCode.ENTER?(b.setNgModelValue(b.displayTime,"enter"),void a.preventDefault()):void 0})},b.prototype.setNgModelValue=function(a,b){this.$scope.$emit("sg-time-pane-change",{date:a,changed:b}),this.ngModelCtrl.$setViewValue(a),this.ngModelCtrl.$render()},b.prototype.focus=function(a,b){var c=a||this.selectedTime||this.today,e=this.timePaneElement.querySelector(".md-focus");if(e&&e.classList.remove(d),c){var f=c.getHours(),g=document.getElementById("tp-"+b.id+"-hour-"+f);g&&(g.classList.add(d),g.focus())}}}(),function(){"use strict";function a(){return{template:['",'
",' ',' ','
',"
","
",'
','
','
',"
",'
',' ',"
","
"].join(""),require:["ngModel","sgTimepicker"],scope:{placeholder:"@mdPlaceholder"},controller:b,controllerAs:"ctrl",bindToController:!0,link:function(a,b,c,d){var e=d[0],f=d[1];f.configureNgModel(e)}}}function b(a,b,c,d,e,f,g,h,i,j,k,l,m){this.$compile=d,this.$timeout=e,this.$window=f,this.dateLocale=k,this.dateUtil=l,this.$mdConstant=g,this.$mdMedia=h,this.$mdUtil=j,this.$$rAF=m,this.ngModelCtrl=null,this.inputElement=b[0].querySelector("input"),this.inputContainer=b[0].querySelector(".sg-timepicker-input-container"),this.ngInputElement=angular.element(this.inputElement),this.timePane=b[0].querySelector(".sg-timepicker-time-pane"),this.timeButton=b[0].querySelector(".sg-timepicker-button"),this.inputMask=b[0].querySelector(".sg-timepicker-input-mask-opaque"),this.$element=b,this.$attrs=c,this.$scope=a,this.date=null,this.isFocused=!1,this.isDisabled=!1,this.setDisabled(b[0].disabled||angular.isString(c.disabled)),this.isTimeOpen=!1,this.timePaneOpenedFrom=null,this.timePane.id="sg-time-pane"+j.nextUid(),i(b),this.bodyClickHandler=angular.bind(this,this.handleBodyClick),this.windowResizeHandler=j.debounce(angular.bind(this,this.closeTimePane),100),c.tabindex||b.attr("tabindex","-1"),this.installPropertyInterceptors(),this.attachChangeListeners(),this.attachInteractionListeners();var n=this;a.$on("$destroy",function(){n.detachTimePane()})}angular.module("SOGo.Common").directive("sgTimepicker",a);var c=3,d="sg-timepicker-invalid",e=500,f={MIN5:{GTSM:192,SM:312},MIN1:{GTSM:384,SM:474}},g={GTSM:530,SM:292};b.$inject=["$scope","$element","$attrs","$compile","$timeout","$window","$mdConstant","$mdMedia","$mdTheming","$mdUtil","$mdDateLocale","$$mdDateUtil","$$rAF"],b.prototype.configureNgModel=function(a){this.ngModelCtrl=a;var b=this;a.$render=function(){var a=b.ngModelCtrl.$viewValue;if(a&&!(a instanceof Date))throw Error("The ng-model for sg-timepicker must be a Date instance. Currently the model is a: "+typeof a);b.time=a,b.inputElement.value=b.dateLocale.formatTime(a),b.resizeInputElement(),b.updateErrorState()}},b.prototype.attachChangeListeners=function(){var a=this;a.$scope.$on("sg-time-pane-change",function(b,c){var e=new Date(c.date);a.ngModelCtrl.$setViewValue(e),a.time=e,a.inputElement.value=a.dateLocale.formatTime(e),"minutes"==c.changed&&a.closeTimePane(),a.resizeInputElement(),a.inputContainer.classList.remove(d)}),a.ngInputElement.on("input",angular.bind(a,a.resizeInputElement)),a.ngInputElement.on("input",a.$mdUtil.debounce(a.handleInputEvent,e,a))},b.prototype.attachInteractionListeners=function(){var a=this,b=this.$scope,c=this.$mdConstant.KEY_CODE;a.ngInputElement.on("keydown",function(d){d.altKey&&d.keyCode==c.DOWN_ARROW&&(a.openTimePane(d),b.$digest())}),b.$on("md-time-close",function(){a.closeTimePane()})},b.prototype.installPropertyInterceptors=function(){var a=this;if(this.$attrs.ngDisabled){var b=this.$mdUtil.validateScope(this.$element)?this.$element.scope():null;b&&b.$watch(this.$attrs.ngDisabled,function(b){a.setDisabled(b)})}Object.defineProperty(this,"placeholder",{get:function(){return a.inputElement.placeholder},set:function(b){a.inputElement.placeholder=b||""}})},b.prototype.setDisabled=function(a){this.isDisabled=a,this.inputElement.disabled=a,this.timeButton.disabled=a},b.prototype.updateErrorState=function(a){var b=a||this.date;this.clearErrorState(),this.dateUtil.isValidDate(b)||this.ngModelCtrl.$setValidity("valid",null===b),this.ngModelCtrl.$valid||this.inputContainer.classList.add(d)},b.prototype.clearErrorState=function(){this.inputContainer.classList.remove(d),["valid"].forEach(function(a){this.ngModelCtrl.$setValidity(a,!0)},this)},b.prototype.resizeInputElement=function(){this.inputElement.size=this.inputElement.value.length+c},b.prototype.handleInputEvent=function(a){var b=this.inputElement.value,c=b.split(/[\.:]/);if(""===b)this.ngModelCtrl.$setViewValue(null),this.time=null,this.inputContainer.classList.remove(d);else if(c.length<2)this.inputContainer.classList.toggle(d,b);else{var e=Number(c[0]),f=Number(c[1]),g=new Date(this.time);e&&e>=0&&23>=e&&f&&f>=0&&59>=f&&angular.isDate(g)?(g.setHours(e),g.setMinutes(f),this.ngModelCtrl.$setViewValue(g),this.time=g,this.inputContainer.classList.remove(d)):this.inputContainer.classList.toggle(d,b)}},b.prototype.attachTimePane=function(){var a=this.timePane;this.$element.addClass("sg-timepicker-open"),this.$element.find("button").addClass("md-primary");var b=this.inputContainer.getBoundingClientRect(),c=document.body.getBoundingClientRect(),d=b.top-c.top,e=b.left-c.left,h=this.$mdMedia("sm")?g.SM:g.GTSM;e+h>c.right&&c.right-h>0&&(e=c.right-h,a.classList.add("sg-timepicker-pos-adjusted")),a.style.left=e+"px";var i="object"==typeof this.time&&this.time.getMinutes()%5===0?"MIN5":"MIN1",j=this.$mdMedia("sm")?f[i].SM:f[i].GTSM;d+j>c.bottom&&c.bottom-j>0&&(d=c.bottom-j,a.classList.add("sg-timepicker-pos-adjusted")),a.style.top=d+"px",document.body.appendChild(a),this.inputMask.style.left=b.width+"px",this.$$rAF(function(){a.classList.add("md-pane-open")})},b.prototype.detachTimePane=function(){this.$element.removeClass("sg-timepicker-open"),this.$element.find("button").removeClass("md-primary"),this.timePane.classList.remove("md-pane-open"),this.timePane.classList.remove("md-timepicker-pos-adjusted"),this.timePane.parentNode&&this.timePane.parentNode.removeChild(this.timePane)},b.prototype.openTimePane=function(a){if(!this.isTimeOpen&&!this.isDisabled){this.isTimeOpen=!0,this.timePaneOpenedFrom=a.target,this.attachTimePane(),this.$mdUtil.disableScrollAround(this.timePane);var b=this;this.$mdUtil.nextTick(function(){document.body.addEventListener("click",b.bodyClickHandler)},!1),window.addEventListener("resize",this.windowResizeHandler)}},b.prototype.closeTimePane=function(){this.isTimeOpen&&(this.isTimeOpen=!1,this.detachTimePane(),this.timePaneOpenedFrom.focus(),this.timePaneOpenedFrom=null,this.$mdUtil.enableScrolling(),document.body.removeEventListener("click",this.bodyClickHandler),window.removeEventListener("resize",this.windowResizeHandler))},b.prototype.getTimePaneCtrl=function(){return angular.element(this.timePane.querySelector("sg-time-pane")).controller("sgTimePane")},b.prototype.focusTime=function(){var a=this;this.$mdUtil.nextTick(function(){var b=a.getTimePaneCtrl();a.getTimePaneCtrl().focus(null,b)},!1)},b.prototype.setFocused=function(a){this.isFocused=a},b.prototype.handleBodyClick=function(a){if(this.isTimeOpen){var b=this.$mdUtil.getClosest(a.target,"sg-time-pane");b||this.closeTimePane(),this.$scope.$digest()}}}(),function(){"use strict";function a(a){function b(b,c,d,e){function f(a){var b=_.findIndex(i,function(b){return j?b[j]==a:b==a});if(0>b)if(j){var c={};c[j]=a,i.push(c)}else i.push(a);else i.splice(b,1)}var g,h,i,j,k,l,m=c.find("md-grid-tile");for(k=b.$watch(function(){return a(d.sgToggleGrid)(b)},function(a){if(angular.isDefined(a)){var b=a;i=a,d.sgToggleGridAttr&&(j=d.sgToggleGridAttr,b=_.pluck(a,d.sgToggleGridAttr)),_.each(m,function(a){var c=angular.element(a);_.contains(b,c.attr("value"))&&c.addClass("sg-active")}),k()}}),l=function(){var a=angular.element(this),b=a.attr("value");a.toggleClass("sg-active"),f(b)},h=0;h>2,e=(3&a)<<4|b>>4,f=(15&b)<<2|c>>6,g=63&c,isNaN(b)?f=g=64:isNaN(c)&&(g=64),h=h+this._base64_keyStr.charAt(d)+this._base64_keyStr.charAt(e)+this._base64_keyStr.charAt(f)+this._base64_keyStr.charAt(g);return h},String.prototype.base64decode=function(){for(var a,b,c,d,e,f,g,h="",i=0,j=""+this;i>4,b=(15&e)<<4|f>>2,c=(3&f)<<6|g,h+=String.fromCharCode(a),64!=f&&(h+=String.fromCharCode(b)),64!=g&&(h+=String.fromCharCode(c));return h},String.prototype.md5=function(){if(this.length){var a=function(a){function b(a,b){return a<>>32-b}function c(a,b){var c,d,e,f,g;return e=2147483648&a,f=2147483648&b,c=1073741824&a,d=1073741824&b,g=(1073741823&a)+(1073741823&b),c&d?2147483648^g^e^f:c|d?1073741824&g?3221225472^g^e^f:1073741824^g^e^f:g^e^f}function d(a,b,c){return a&b|~a&c}function e(a,b,c){return a&c|b&~c}function f(a,b,c){return a^b^c}function g(a,b,c){return b^(a|~c)}function h(a,e,f,g,h,i,j){return a=c(a,c(c(d(e,f,g),h),j)),c(b(a,i),e)}function i(a,d,f,g,h,i,j){return a=c(a,c(c(e(d,f,g),h),j)),c(b(a,i),d)}function j(a,d,e,g,h,i,j){return a=c(a,c(c(f(d,e,g),h),j)),c(b(a,i),d)}function k(a,d,e,f,h,i,j){return a=c(a,c(c(g(d,e,f),h),j)),c(b(a,i),d)}function l(a){for(var b,c=a.length,d=c+8,e=(d-d%64)/64,f=16*(e+1),g=Array(f-1),h=0,i=0;c>i;)b=(i-i%4)/4,h=i%4*8,g[b]=g[b]|a.charCodeAt(i)<>>29,g}function m(a){var b,c,d="",e="";for(c=0;3>=c;c++)b=a>>>8*c&255,e="0"+b.toString(16),d+=e.substr(e.length-2,2);return d}function n(a){a=a.replace(/rn/g,"n");for(var b="",c=0;cd?b+=String.fromCharCode(d):d>127&&2048>d?(b+=String.fromCharCode(d>>6|192),b+=String.fromCharCode(63&d|128)):(b+=String.fromCharCode(d>>12|224),b+=String.fromCharCode(d>>6&63|128),b+=String.fromCharCode(63&d|128))}return b}var o,p,q,r,s,t,u,v,w,x=Array(),y=7,z=12,A=17,B=22,C=5,D=9,E=14,F=20,G=4,H=11,I=16,J=23,K=6,L=10,M=15,N=21;for(a=n(a),x=l(a),t=1732584193,u=4023233417,v=2562383102,w=271733878,o=0;o=0&&(h.month=c),c>=0}],"%B":[/[^\d\s\.\/\-]{2,}/,function(b){var c=_.indexOf(a.months,b);return c>=0&&(h.month=c),c>=0}],"%y":[/\d\d/,function(a){var b=parseInt(g.getFullYear().toString().substring(2))+5;return h.year=parseInt(a),h.yeard){var e=c;c=d,d=e}for(var f=Math.round((d-c)/864e5)+1,g=0;f>g;g++){var h=new Date;h.setTime(c+864e5*g),b.push(h)}return b},Date.prototype.minutesTo=function(a){var b,c;return b=Math.floor(a.valueOf()-this.valueOf())/1e3/60,c=a.getTimezoneOffset()-this.getTimezoneOffset(),b-c},Date.prototype.stringWithSeparator=function(a){var b=""+(this.getMonth()+1),c=""+this.getDate(),d=this.getYear();return 1e3>d&&(d=""+(d+1900)),1==b.length&&(b="0"+b),1==c.length&&(c="0"+c),"-"==a?str=d+"-"+b+"-"+c:str=c+"/"+b+"/"+d,str},Date.prototype.addDays=function(a){var b,c,d;c=this.getTime(),b=new Date(c),c+=864e5*a,this.setTime(c),d=this.getTimezoneOffset()-b.getTimezoneOffset(),0!==d&&(c=this.getTime()+60*d*1e3,this.setTime(c))},Date.prototype.addHours=function(a){var b=this.getTime();b+=36e5*a,this.setTime(b)},Date.prototype.addMinutes=function(a){var b=this.getTime();b+=6e4*a,this.setTime(b)},Date.prototype.beginOfDay=function(){var a=new Date(this.getTime());return a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0),a},Date.prototype.beginOfWeek=function(a){var b=a-this.getDay();b>0&&(b-=7);var c=this.beginOfDay();return c.setHours(12),c.addDays(b),c},Date.prototype.endOfWeek=function(a){var b=this.beginOfWeek(a);return b.addDays(6),b.setHours(23),b.setMinutes(59),b.setSeconds(59),b.setMilliseconds(999),b},Date.prototype.getDayString=function(){var a=this.getYear();1e3>a&&(a+=1900);var b=""+(this.getMonth()+1);1==b.length&&(b="0"+b),a+=b;var c=""+this.getDate();return 1==c.length&&(c="0"+c),a+=c},Date.prototype.getHourString=function(){var a=this.getHours()+"00";return 3==a.length&&(a="0"+a),a},Date.prototype.format=function(a,b){var c,d,e,f,g=[],h=/%[daAmbByYHIMp]/g,i={"%d":this.getUTCDate(),"%e":this.getUTCDate(),"%a":a.shortDays[this.getUTCDay()],"%A":a.days[this.getUTCDay()],"%m":this.getUTCMonth()+1,"%b":a.shortMonths[this.getUTCMonth()],"%B":a.months[this.getUTCMonth()],"%y":this.getUTCFullYear().toString().substring(2),"%Y":this.getUTCFullYear(),"%H":this.getHours(),"%M":this.getMinutes()};for(i["%I"]=i["%H"]>12?i["%H"]%12:i["%H"],i["%p"]=l(i["%H"]<12?"AM":"PM"),i["%d"]=(i["%d"]<10?"0":"")+i["%d"],i["%e"]=(i["%e"]<10?" ":"")+i["%e"],i["%m"]=(i["%m"]<10?"0":"")+i["%m"],i["%H"]=(i["%H"]<10?"0":"")+i["%H"],i["%I"]=(i["%I"]<10?"0":"")+i["%I"],i["%M"]=(i["%M"]<10?"0":"")+i["%M"],c=b.replace(h,"\x00").split("\x00"),d=b.match(h),e=0,f=d.length;f>=e;e++)c.length&&g.push(c.shift()),g.push(i[d[e]]);return g.join("")}; //# sourceMappingURL=Common.js.map \ No newline at end of file diff --git a/UI/WebServerResources/js/Common.js.map b/UI/WebServerResources/js/Common.js.map index 5784f82f0..7af6df9b4 100644 --- a/UI/WebServerResources/js/Common.js.map +++ b/UI/WebServerResources/js/Common.js.map @@ -1 +1 @@ -{"version":3,"sources":["Common/utils.js","Common/Common.app.js","Common/mdColors.app.js","Common/decodeUri.filter.js","Common/encodeUri.filter.js","Common/ensureTarget.filter.js","Common/loc.filter.js","Common/range.filter.js","Common/AclController.js","Common/navController.js","Common/Acl.service.js","Common/Alarm.service.js","Common/Authentication.service.js","Common/Dialog.service.js","Common/Gravatar.service.js","Common/Resource.service.js","Common/User.service.js","Common/sgFocus.service.js","Common/sgAvatarImage.directive.js","Common/sgColorPicker.directive.js","Common/sgCompile.directive.js","Common/sgEnter.directive.js","Common/sgEscape.directive.js","Common/sgFocus.directive.js","Common/sgFolderStylesheet.directive.js","Common/sgPlaceholder.directive.js","Common/sgSearch.directive.js","Common/sgSubscribe.directive.js","Common/sgTimepicker.directive.js","Common/sgToggleGrid.directive.js"],"names":["l","i","j","key","arguments","value","args","labels","clabels","length","replace","m","val","parseFloat","isNaN","hexToRgb","hex","result","exec","r","parseInt","g","b","contrast","color","c","Math","pow","guid","S4","random","toString","substring","substr","toLowerCase","configure","$logProvider","$compileProvider","$httpProvider","$mdThemingProvider","definePalette","50","100","200","300","400","500","600","700","800","900","A100","A200","A400","A700","contrastDefaultColor","contrastLightColors","contrastDarkColors","1000","theme","primaryPalette","default","hue-1","hue-2","hue-3","accentPalette","backgroundPalette","DebugEnabled","debugEnabled","debugInfoEnabled","interceptors","push","AuthInterceptor","$window","$q","response","test","config","headers","Accept","data","location","reload","reject","ErrorInterceptor","$rootScope","responseError","rejection","$broadcast","angular","module","isPopup","document","body","classList","contains","baseURL","ApplicationBaseURL","activeUser","param","settings","login","UserLogin","identification","UserIdentification","email","UserEmail","language","UserLanguage","folderURL","UserFolderURL","isSuperUser","IsSuperUser","path","calendar","UserCalendarPath","contacts","UserContactsPath","mail","UserMailPath","preferences","UserPreferencesPath","administration","UserAdministrationPath","logoff","UserLogoffPath","constant","selection","xs","gt-xs","sm","gt-sm","md","gt-md","lg","gt-lg","xl","factory","$inject","_$mdThemingProvider","runBlock","$interpolate","$document","$log","buildCssSelectors","selectors","join","addRule","fgInterpolate","bgInterpolate","themeName","paletteName","colorArray","hueName","colorValue","colorContrast","context","palette","hue","customSheet","insertRule","index","addBorderRule","bdrInterpolate","getStyleSheet","style","head","querySelector","createElement","title","appendChild","createTextNode","sheet","fgDefault","bgDefault","bdrDefault","fgDefaultHue","bgDefaultHue","fgColor","bgColor","bdrColor","fgHue","bgHue","cssRules","deleteRule","forEach","_THEMES","_PALETTES","colors","primary","name","hues","run","decodeUri","decodeURIComponent","filter","encodeUri","encodeURIComponent","ensureTarget","$sce","element","tree","find","attr","trustAs","html","loc","range","n","res","AclController","$mdDialog","Dialog","usersWithACL","User","folder","userFilter","$query","$filter","$acl","users","closeModal","$resetUsersRights","hide","saveModal","$saveUsersRights","then","status","alert","confirmChange","user","confirmation","$confirmRights","vm","showing","message","removeUser","$removeUser","uid","addUser","$addUser","userToAdd","searchText","selectedUid","selectUser","error","selectedUser","$rights","this","controller","navController","$scope","$timeout","$interval","$http","$mdSidenav","$mdToast","$mdMedia","sgConstant","sgSettings","Alarm","leftIsClose","isOpen","onHttpError","event","isString","statusText","show","template","hideDelay","position","debug","currentDay","window","get","secondsBeforeTomorrow","toggleLeft","toggle","toggleRight","$watch","newVal","isGtMedium","$on","getAlarms","Acl","folderId","Settings","Resource","extend","$$resource","$User","prototype","$users","owner","_this","deferred","defer","acls","isDefined","userResource","fetch","canSubscribeUser","isSubscribed","wasSubscribed","bind","resolve","promise","_","indexOf","pluck","userClass","isGroup","splice","$resetRights","deferredSave","deferredSubscribe","action","$rightsAreDirty","$omit","save","$shadowRights","copy","rights","uids","all","currentAlarm","AlarmService","$toast","now","Date","browserTime","floor","getTime","alarms","sort","a","x","y","next","pop","utc","url","alarmTime","delay","f","showAlarm","cancel","AlarmController","scope","reminder","ok","summary","locals","Authentication","readCookie","foundCookie","prefix","pairs","currentPair","start","cookie","split","charAt","readLoginCookie","loginValues","base64decode","redirectUrl","username","domain","userName","address","baseAddress","altBaseAddress","parts","hostpart","protocol","newAddress","href","startsWith","endsWith","getService","passwordPolicyConfig","service","d","password","rememberLogin","loginSuffix","method","loginCookie","expire","grace","msg","perr","LDAPPasswordPolicyError","PolicyNoError","PolicyAccountLocked","changePassword","newPassword","PolicyPasswordModNotAllowed","PolicyInsufficientPasswordQuality","PolicyPasswordTooShort","PolicyPasswordTooYoung","PolicyPasswordInHistory","formatted","PolicyPasswordUnknown","PolicyPasswordSystemUnknown","$get","PolicyPasswordChangeUnsupported","PolicyPasswordExpired","PolicyChangeAfterReset","PolicyMustSupplyOldPassword","provider","DialogService","$modal","content","htmlContent","confirm","options","prompt","label","PromptDialogController","o","parent","clickOutsideToClose","escapeToClose","inputType","Gravatar","size","alternate_avatar","hash","s","md5","no_404","_http","_q","_path","_activeUser","$factory","compact","escape","params","flatten","newguid","create","post","id","newValue","remove","userData","init","$gravatar","search","excludedUsers","dry","when","results","compareUids","each","isUndefined","$$shortFormat","$shortFormat","$$image","image","c_email","$alternateAvatar","empty","fullname","cn","no_email","$isAnonymous","$isSpecial","$confirmation","some","values","constructor","isEqual","zero","map","keys","$folders","type","$$folders","folders","sgFocus","sgAvatarImage","restrict","bindToController","src","link","controllerAs","attrs","imgElement","mdIconElement","img","genericImg","sgAvatarImageController","$element","Preferences","getGravatar","defaults","SOGoAlternateAvatar","cache","urlEmail","hideGenericAvatar","showGenericAvatar","addClass","removeClass","ready","old","attributes","directive","sgColorPicker","iElement","iAttr","ngModelController","$render","sgColor","$viewValue","sgIconColor","require","sgColorPickerController","sgColors","setColor","$setViewValue","sgCompile","$compile","sgCompileLink","ensureCompileRunsOnce","$eval","contents","sgEnter","ENTER_KEY","which","$apply","preventDefault","sgEscape","ESCAPE_KEY","elem","keyCode","sgFocusOn","e","focus","select","sgFolderStylesheet","sgFolderStylesheetController","ngModel","sgPlaceholder","placeholder","sgSearchPreTransclude","$parse","compile","tElement","tAttr","inputEl","selectEl","buttonEl","removeAttr","compiledButtonEl","formName","inputName","allowDot","doSearch","on","cancelSearch","priority","sgSearch","transclude","clone","append","sgSearchController","minLength","isNumber","minimumSearchLength","searchTextOptions","updateOn","debounce","blur","onChange","form","input","rawSearchText","$valid","$setValidity","searchField","sgSubscribe","folderType","onFolderSelect","sgSubscribeDialogController","showDialog","templateUrl","sgSubscribeController","selectFolder","folderData","close","timePaneDirective","TimePaneCtrl","controllers","ngModelCtrl","sgTimePaneCtrl","timePaneElement","configureNgModel","$attrs","$animate","$mdConstant","$mdTheming","$$mdDateUtil","$mdDateLocale","$mdInkRipple","$mdUtil","KEY_CODE","dateUtil","nextTimePaneUniqueId","selectedTime","displayTime","isInitialized","hours","displayName","selected","min5","min1","ii","show5min","getToggleBtnLbl","is5min","toggleManual5min","manual5min","tabindex","self","hourClickHandler","displayVal","updated","setHours","Number","setNgModelValue","minuteClickHandler","setMinutes","attachTimePaneEventListeners","SELECTED_TIME_CLASS","FOCUSED_TIME_CLASS","changeSelectedTime","date","previousSelectedTime","changeDisplayTime","prevH","getHours","prevHCell","getElementById","setAttribute","prevM","getMinutes","prevMCell","prevM5Cell","mCell","newH","hCell","add","newM","isValidDate","buildInitialTimePaneDisplay","today","handleKeyEvent","ESCAPE","TAB","$emit","ENTER","mode","changed","opt_date","previousFocus","timePickerDirective","TimePickerCtrl","mdTimePickerCtrl","$$rAF","dateLocale","inputElement","inputContainer","ngInputElement","timePane","timeButton","inputMask","isFocused","isDisabled","setDisabled","disabled","isTimeOpen","timePaneOpenedFrom","nextUid","bodyClickHandler","handleBodyClick","windowResizeHandler","closeTimePane","installPropertyInterceptors","attachChangeListeners","attachInteractionListeners","detachTimePane","EXTRA_INPUT_SIZE","INVALID_CLASS","DEFAULT_DEBOUNCE_INTERVAL","TIME_PANE_HEIGHT","MIN5","GTSM","SM","MIN1","TIME_PANE_WIDTH","Error","time","formatTime","resizeInputElement","updateErrorState","handleInputEvent","keyCodes","altKey","DOWN_ARROW","openTimePane","$digest","ngDisabled","validateScope","Object","defineProperty","set","clearErrorState","field","inputString","arr","h","isDate","attachTimePane","elementRect","getBoundingClientRect","bodyRect","paneTop","top","paneLeft","left","paneWidth","right","min","paneHeight","bottom","width","parentNode","removeChild","target","disableScrollAround","nextTick","addEventListener","enableScrolling","removeEventListener","getTimePaneCtrl","focusTime","ctrl","setFocused","isInTime","getClosest","sgToggleGrid","day","findIndex","modelDays","modelAttr","tile","ensureInitRunsOnce","toggleClass","tiles","days","flattenedDays","sgToggleGridAttr","String","suffix","pattern","lastIndexOf","_base64_keyStr","base64encode","chr1","chr2","chr3","enc1","enc2","enc3","enc4","output","utf8encode","charCodeAt","fromCharCode","L","k","K","G","I","F","H","q","p","u","aa","Z","D","t","Array","B","J","P","E","v","Y","X","W","V","C","S","Q","N","M","A","z","w","U","T","R","O","capitalize","toUpperCase","slice","asDate","newDate","newString","isValidEmail","emailRE","asCSSIdentifier","characters","escapeds","re","RegExp","timeInterval","interval","parseDate","localeProvider","format","string","formattingTokens","tokens","token","regexes","parsedInput","matchesCount","year","month","%d","%e","%m","%b","shortMonths","%B","months","%y","nearFuture","getFullYear","%Y","match","NaN","daysUpTo","otherDate","day1","day2","tmp","nbrDays","round","setTime","minutesTo","delta","dstOffset","valueOf","getTimezoneOffset","stringWithSeparator","separator","getMonth","getDate","getYear","str","addDays","initialDate","milliSeconds","addHours","nbrHours","addMinutes","nbrMinutes","beginOfDay","setSeconds","setMilliseconds","beginOfWeek","firstDayOfWeek","offset","getDay","endOfWeek","getDayString","getHourString","separators","max","validParts","getUTCDate","%a","shortDays","getUTCDay","%A","getUTCMonth","getUTCFullYear","%H","%M","shift"],"mappings":"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","file":"Common.js","sourcesContent":["/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\nString.prototype.endsWith = function(suffix) {\n return this.indexOf(suffix, this.length - suffix.length) !== -1;\n};\n\nString.prototype.startsWith = function(pattern, position) {\n position = angular.isNumber(position) ? position : 0;\n return this.lastIndexOf(pattern, position) === position;\n};\n\nString.prototype._base64_keyStr = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\nString.prototype.base64encode = function () {\n var output = \"\";\n var chr1, chr2, chr3, enc1, enc2, enc3, enc4;\n var i = 0;\n \n var input = this.utf8encode();\n\n while (i < input.length) {\n chr1 = input.charCodeAt(i++);\n chr2 = input.charCodeAt(i++);\n chr3 = input.charCodeAt(i++);\n \n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n \n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n \n output = output +\n this._base64_keyStr.charAt(enc1) + this._base64_keyStr.charAt(enc2) +\n this._base64_keyStr.charAt(enc3) + this._base64_keyStr.charAt(enc4);\n }\n \n return output;\n};\n\nString.prototype.base64decode = function() { \n var output = \"\";\n var chr1, chr2, chr3;\n var enc1, enc2, enc3, enc4;\n var i = 0;\n \n var input = \"\" + this; // .replace(/[^A-Za-z0-9\\+\\/\\=]/g, \"\")\n while (i < input.length) {\n enc1 = this._base64_keyStr.indexOf(input.charAt(i++));\n enc2 = this._base64_keyStr.indexOf(input.charAt(i++));\n enc3 = this._base64_keyStr.indexOf(input.charAt(i++));\n enc4 = this._base64_keyStr.indexOf(input.charAt(i++));\n\n chr1 = (enc1 << 2) | (enc2 >> 4);\n chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n chr3 = ((enc3 & 3) << 6) | enc4;\n \n output = output + String.fromCharCode(chr1);\n \n if (enc3 != 64) {\n output = output + String.fromCharCode(chr2);\n }\n if (enc4 != 64) {\n output = output + String.fromCharCode(chr3);\n }\n }\n\n return output;\n};\n\nString.prototype.md5 = function() {\n if (!this.length) { return; }\n // MD5 (Message-Digest Algorithm) by WebToolkit\n var md5 = function(s){function L(k,d){return(k<>>(32-d));}function K(G,k){var I,d,F,H,x;F=(G&2147483648);H=(k&2147483648);I=(G&1073741824);d=(k&1073741824);x=(G&1073741823)+(k&1073741823);if(I&d){return(x^2147483648^F^H);}if(I|d){if(x&1073741824){return(x^3221225472^F^H);}else{return(x^1073741824^F^H);}}else{return(x^F^H);}}function r(d,F,k){return(d&F)|((~d)&k);}function q(d,F,k){return(d&k)|(F&(~k));}function p(d,F,k){return(d^F^k);}function n(d,F,k){return(F^(d|(~k)));}function u(G,F,aa,Z,k,H,I){G=K(G,K(K(r(F,aa,Z),k),I));return K(L(G,H),F);}function f(G,F,aa,Z,k,H,I){G=K(G,K(K(q(F,aa,Z),k),I));return K(L(G,H),F);}function D(G,F,aa,Z,k,H,I){G=K(G,K(K(p(F,aa,Z),k),I));return K(L(G,H),F);}function t(G,F,aa,Z,k,H,I){G=K(G,K(K(n(F,aa,Z),k),I));return K(L(G,H),F);}function e(G){var Z;var F=G.length;var x=F+8;var k=(x-(x%64))/64;var I=(k+1)*16;var aa=Array(I-1);var d=0;var H=0;while(H>>29;return aa;}function B(x){var k=\"\",F=\"\",G,d;for(d=0;d<=3;d++){G=(x>>>(d*8))&255;F=\"0\"+G.toString(16);k=k+F.substr(F.length-2,2);}return k;}function J(k){k=k.replace(/rn/g,\"n\");var d=\"\";for(var F=0;F127)&&(x<2048)){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128);}else{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128);}}}return d;}var C=Array();var P,h,E,v,g,Y,X,W,V;var S=7,Q=12,N=17,M=22;var A=5,z=9,y=14,w=20;var o=4,m=11,l=16,j=23;var U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;for(P=0;P= 0)\n date.month = i;\n return (i >= 0);\n }],\n '%B': [/[^\\d\\s\\.\\/\\-]{2,}/, function(input) {\n var i = _.indexOf(localeProvider.months, input);\n if (i >= 0)\n date.month = i;\n return (i >= 0);\n }],\n '%y': [/\\d\\d/, function(input) {\n var nearFuture = parseInt(now.getFullYear().toString().substring(2)) + 5;\n date.year = parseInt(input);\n if (date.year < nearFuture) date.year += 2000;\n else date.year += 1900;\n return true;\n }],\n '%Y': [/[12]\\d\\d\\d/, function(input) {\n date.year = parseInt(input);\n return true;\n }]\n };\n tokens = format.match(formattingTokens) || [];\n matchesCount = 0;\n\n for (i = 0; i < tokens.length; i++) {\n token = tokens[i];\n parsedInput = (string.match(regexes[token][0]) || [])[0];\n if (parsedInput) {\n string = string.slice(string.indexOf(parsedInput) + parsedInput.length);\n if (regexes[token][1](parsedInput))\n matchesCount++;\n }\n }\n\n if (tokens.length === matchesCount) {\n // console.debug(this + ' + ' + format + ' = ' + JSON.stringify(date));\n return new Date(date.year, date.month, date.day);\n }\n else\n return new Date(NaN);\n};\n\nDate.prototype.daysUpTo = function(otherDate) {\n var days = [];\n\n var day1 = this.getTime();\n var day2 = otherDate.getTime();\n if (day1 > day2) {\n var tmp = day1;\n day1 = day2;\n day2 = tmp;\n }\n\n var nbrDays = Math.round((day2 - day1) / 86400000) + 1;\n for (var i = 0; i < nbrDays; i++) {\n var newDate = new Date();\n newDate.setTime(day1 + (i * 86400000));\n days.push(newDate);\n }\n\n return days;\n};\n\nDate.prototype.minutesTo = function(otherDate) {\n var delta, dstOffset;\n\n delta = Math.floor(otherDate.valueOf() - this.valueOf())/1000/60;\n dstOffset = otherDate.getTimezoneOffset() - this.getTimezoneOffset();\n\n return delta - dstOffset;\n};\n\nDate.prototype.stringWithSeparator = function(separator) {\n var month = '' + (this.getMonth() + 1);\n var day = '' + this.getDate();\n var year = this.getYear();\n if (year < 1000)\n year = '' + (year + 1900);\n if (month.length == 1)\n month = '0' + month;\n if (day.length == 1)\n day = '0' + day;\n\n if (separator == '-')\n str = year + '-' + month + '-' + day;\n else\n str = day + '/' + month + '/' + year;\n\n return str;\n};\n\nDate.prototype.addDays = function(nbrDays) {\n var initialDate, milliSeconds, dstOffset;\n\n milliSeconds = this.getTime();\n initialDate = new Date(milliSeconds);\n milliSeconds += 86400000 * nbrDays;\n this.setTime(milliSeconds);\n\n dstOffset = this.getTimezoneOffset() - initialDate.getTimezoneOffset();\n if (dstOffset !== 0) {\n milliSeconds = this.getTime() + dstOffset*60*1000;\n this.setTime(milliSeconds);\n }\n};\n\nDate.prototype.addHours = function(nbrHours) {\n var milliSeconds = this.getTime();\n milliSeconds += 3600000 * nbrHours;\n this.setTime(milliSeconds);\n};\n\nDate.prototype.addMinutes = function(nbrMinutes) {\n var milliSeconds = this.getTime();\n milliSeconds += 60000 * nbrMinutes;\n this.setTime(milliSeconds);\n};\n\nDate.prototype.beginOfDay = function() {\n var beginOfDay = new Date(this.getTime());\n beginOfDay.setHours(0);\n beginOfDay.setMinutes(0);\n beginOfDay.setSeconds(0);\n beginOfDay.setMilliseconds(0);\n\n return beginOfDay;\n};\n\nDate.prototype.beginOfWeek = function(firstDayOfWeek) {\n var offset = firstDayOfWeek - this.getDay();\n if (offset > 0)\n offset -= 7;\n\n var beginOfWeek = this.beginOfDay();\n beginOfWeek.setHours(12);\n beginOfWeek.addDays(offset);\n\n return beginOfWeek;\n};\n\nDate.prototype.endOfWeek = function(firstDayOfWeek) {\n var endOfWeek = this.beginOfWeek(firstDayOfWeek);\n endOfWeek.addDays(6);\n\n endOfWeek.setHours(23);\n endOfWeek.setMinutes(59);\n endOfWeek.setSeconds(59);\n endOfWeek.setMilliseconds(999);\n\n return endOfWeek;\n};\n\n// YYYYMMDD\nDate.prototype.getDayString = function() {\n var newString = this.getYear();\n if (newString < 1000) newString += 1900;\n var month = '' + (this.getMonth() + 1);\n if (month.length == 1)\n month = '0' + month;\n newString += month;\n var day = '' + this.getDate();\n if (day.length == 1)\n day = '0' + day;\n newString += day;\n\n return newString;\n};\n\n// MMHH\nDate.prototype.getHourString = function() {\n var newString = this.getHours() + '00';\n if (newString.length == 3)\n newString = '0' + newString;\n\n return newString;\n};\n\nDate.prototype.format = function(localeProvider, format) {\n var separators, parts, i, max,\n date = [],\n validParts = /%[daAmbByYHIMp]/g,\n val = {\n '%d': this.getUTCDate(), // day of month (e.g., 01)\n '%e': this.getUTCDate(), // day of month, space padded\n '%a': localeProvider.shortDays[this.getUTCDay()], // locale's abbreviated weekday name (e.g., Sun)\n '%A': localeProvider.days[this.getUTCDay()], // locale's full weekday name (e.g., Sunday)\n '%m': this.getUTCMonth() + 1, // month (01..12)\n '%b': localeProvider.shortMonths[this.getUTCMonth()], // locale's abbreviated month name (e.g., Jan)\n '%B': localeProvider.months[this.getUTCMonth()], // locale's full month name (e.g., January)\n '%y': this.getUTCFullYear().toString().substring(2), // last two digits of year (00..99)\n '%Y': this.getUTCFullYear(), // year\n '%H': this.getHours(), // hour (00..23)\n '%M': this.getMinutes() }; // minute (00..59)\n val['%I'] = val['%H'] > 12 ? val['%H'] % 12 : val['%H']; // hour (01..12)\n val['%p'] = val['%H'] < 12 ? l('AM') : l('PM'); // locale's equivalent of either AM or PM\n\n val['%d'] = (val['%d'] < 10 ? '0' : '') + val['%d'];\n val['%e'] = (val['%e'] < 10 ? ' ' : '') + val['%e'];\n val['%m'] = (val['%m'] < 10 ? '0' : '') + val['%m'];\n val['%H'] = (val['%H'] < 10 ? '0' : '') + val['%H'];\n val['%I'] = (val['%I'] < 10 ? '0' : '') + val['%I'];\n val['%M'] = (val['%M'] < 10 ? '0' : '') + val['%M'];\n\n separators = format.replace(validParts, '\\0').split('\\0');\n parts = format.match(validParts);\n for (i = 0, max = parts.length; i <= max; i++){\n if (separators.length)\n date.push(separators.shift());\n date.push(val[parts[i]]);\n }\n\n return date.join('');\n};\n\n/* Functions */\n\nfunction l() {\n var key = arguments[0], value = key, args = arguments, i, j;\n\n // Retrieve translation\n if (labels[key]) {\n value = labels[key];\n }\n else if (clabels[key]) {\n value = clabels[key];\n }\n\n // Format placeholders %{0}, %{1], %{2}, ...\n for (i = 1, j = 0; i < args.length; i++, j++) {\n value = value.replace('%{' + j + '}', args[i]);\n }\n\n // Format placeholders %d and %s\n i = 1;\n if (args.length > 1) {\n value = value.replace(/%((%)|s|d)/g, function(m) {\n // m is the matched format, e.g. %s, %d\n var val = null;\n if (m[2]) {\n val = m[2];\n }\n else {\n val = args[i];\n // A switch statement so that the formatter can be extended. Default is %s\n switch (m) {\n case '%d':\n val = parseFloat(val);\n if (isNaN(val))\n val = 0;\n break;\n }\n i++;\n }\n return val;\n });\n }\n\n return value;\n}\n\nfunction hexToRgb(hex) {\n var result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n return result ? {\n r: parseInt(result[1], 16),\n g: parseInt(result[2], 16),\n b: parseInt(result[3], 16)\n } : null;\n}\n\n// Respect contrast ratio recommendation from W3C:\n// http://www.w3.org/TR/WCAG20/#contrast-ratiodef\nfunction contrast(hex) {\n var color, c, l = 1;\n\n color = hexToRgb(hex);\n if (color) {\n c = [color.r / 255, color.g / 255, color.b / 255];\n\n for (var i = 0; i < c.length; ++i) {\n if (c[i] <= 0.03928) {\n\tc[i] = c[i] / 12.92;\n }\n else {\n\tc[i] = Math.pow((c[i] + 0.055) / 1.055, 2.4);\n }\n }\n\n l = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];\n }\n\n if (l > 0.179) {\n return 'black';\n }\n else {\n return 'white';\n }\n}\n\nfunction guid() {\n function S4() {\n return (((1+Math.random())*0x10000)|0).toString(16).substring(1); \n }\n \n return (S4() + S4() + \"-\" + S4() + \"-4\" + S4().substr(0,3) + \"-\" + S4() + \"-\" + S4() + S4() + S4()).toLowerCase();\n}\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n angular.module('SOGo.Common', ['ngAnimate', 'ngMessages', 'ngSanitize', 'ngMaterial', 'mdColors'])\n .value('sgSettings', {\n isPopup: document.body.classList.contains('popup'),\n baseURL: function() {\n return ApplicationBaseURL || null;\n },\n activeUser: function(param) {\n var settings = {\n login: UserLogin || null,\n identification: UserIdentification || null,\n email: UserEmail || null,\n language: UserLanguage || null,\n folderURL: UserFolderURL || null,\n isSuperUser: IsSuperUser || null,\n path: {\n calendar: UserCalendarPath || null,\n contacts: UserContactsPath || null,\n mail: UserMailPath || null,\n preferences: UserPreferencesPath || null,\n administration: (IsSuperUser ? UserAdministrationPath : null),\n logoff: UserLogoffPath || null\n }\n };\n if (param)\n return settings[param];\n else\n return settings;\n }\n })\n\n .constant('sgColors', {\n selection: [\n '#FFFFFF',\n '#330033',\n '#C0C0C0',\n '#999999',\n '#666666',\n '#333333',\n '#000000',\n '#FFCCCC',\n '#FF6666',\n '#FF0000',\n '#CC0000',\n '#990000',\n '#660000',\n '#330000',\n '#FFCC99',\n '#FF9966',\n '#FF9900',\n '#FF6600',\n '#CC6600',\n '#993300',\n '#663300',\n '#FFFF99',\n '#FFFF66',\n '#FFCC66',\n '#FFCC33',\n '#CC9933',\n '#996633',\n '#663333',\n '#FFFFCC',\n '#FFFF33',\n '#FFFF00',\n '#FFCC00',\n '#999900',\n '#666600',\n '#333300',\n '#CCCCCC',\n '#66FF99',\n '#33FF33',\n '#33CC00',\n '#009900',\n '#006600',\n '#003300',\n '#99FFFF',\n '#33FFFF',\n '#66CCCC',\n '#00CCCC',\n '#339999',\n '#336666',\n '#003333',\n '#CCFFFF',\n '#66FFFF',\n '#33CCFF',\n '#3366FF',\n '#3333FF',\n '#000099',\n '#000066',\n '#CCCCFF',\n '#9999FF',\n '#6666CC',\n '#6633FF',\n '#6600CC',\n '#333399',\n '#330099',\n '#FFCCFF',\n '#FF99FF',\n '#CC66CC',\n '#CC33CC',\n '#993399',\n '#663366',\n '#99FF99'\n ]\n })\n\n // md break-points values are hard-coded in angular-material/src/core/util/constant.js\n // $mdMedia has a built-in support for those values but can also evaluate others\n .constant('sgConstant', {\n 'xs' : '(max-width: 599px)' ,\n 'gt-xs' : '(min-width: 600px)' ,\n 'sm' : '(min-width: 600px) and (max-width: 959px)' ,\n 'gt-sm' : '(min-width: 960px)' ,\n 'md' : '(min-width: 960px) and (max-width: 1279px)' ,\n 'gt-md' : '(min-width: 1280px)' ,\n 'lg' : '(min-width: 1280px) and (max-width: 1919px)',\n 'gt-lg' : '(min-width: 1920px)' ,\n 'xl' : '(min-width: 1920px)'\n })\n\n .config(configure)\n\n .factory('AuthInterceptor', AuthInterceptor)\n .factory('ErrorInterceptor', ErrorInterceptor);\n\n /**\n * @ngInject\n */\n configure.$inject = ['$logProvider', '$compileProvider', '$httpProvider', '$mdThemingProvider'];\n function configure($logProvider, $compileProvider, $httpProvider, $mdThemingProvider) {\n // Accent palette\n $mdThemingProvider.definePalette('sogo-green', {\n '50': 'eaf5e9',\n '100': 'cbe5c8',\n '200': 'aad6a5',\n '300': '88c781',\n '400': '66b86a',\n '500': '56b04c',\n '600': '4da143',\n '700': '388e3c',\n '800': '367d2e',\n '900': '225e1b',\n // 'A100': 'b9f6ca',\n 'A100': 'ffffff', // assigned to md-hue-1\n 'A200': '69f0ae',\n 'A400': '00e676',\n 'A700': '00c853',\n 'contrastDefaultColor': 'dark',\n // 'contrastDarkColors': ['50', '100', '200', 'A100'],\n 'contrastLightColors': ['300', '400', '500', '600', '700', '800', '900']\n });\n // Primary palette\n $mdThemingProvider.definePalette('sogo-blue', {\n '50': 'f0faf9',\n '100': 'e1f5f3',\n '200': 'ceebe8',\n '300': 'bfe0dd',\n '400': 'b2d6d3',\n '500': 'a1ccc8',\n '600': '8ebfbb',\n '700': '7db3b0',\n '800': '639997',\n '900': '4d8080',\n 'A100': 'd4f7fa',\n 'A200': 'c3f5fa',\n 'A400': '53e3f0',\n 'A700': '00b0c0',\n 'contrastDefaultColor': 'light',\n 'contrastDarkColors': ['50', '100', '200'],\n // 'contrastLightColors': ['300', '400', '500', '600', '700', '800', '900', 'A100', 'A200', 'A400', 'A700']\n });\n // Background palette\n $mdThemingProvider.definePalette('sogo-paper', {\n '50': 'fcf7f8',\n '100': 'f7f1dc',\n '200': 'ede5ca',\n '300': 'e6d8ba',\n '400': 'e2d2a3',\n '500': 'd6c48d',\n '600': 'baa870',\n '700': '857545',\n '800': '524517',\n '900': '433809',\n '1000': '000000',\n 'A100': 'ffffff',\n 'A200': 'eeeeee',\n 'A400': 'bdbdbd',\n 'A700': '616161',\n 'contrastDefaultColor': 'dark',\n 'contrastLightColors': ['800', '900']\n });\n // Default theme definition\n $mdThemingProvider.theme('default')\n .primaryPalette('sogo-blue', {\n 'default': '900',\n 'hue-1': '400',\n 'hue-2': '800',\n 'hue-3': 'A700'\n })\n .accentPalette('sogo-green', {\n 'default': '500',\n // 'hue-1': '200',\n 'hue-1': 'A100',\n 'hue-2': '300',\n 'hue-3': 'A700'\n })\n .backgroundPalette('grey', {\n 'default': 'A100',\n 'hue-1': '200',\n 'hue-2': '300',\n 'hue-3': '500'\n });\n\n if (!DebugEnabled) {\n // Disable debug data\n $logProvider.debugEnabled(false);\n $compileProvider.debugInfoEnabled(false);\n }\n\n $httpProvider.interceptors.push('AuthInterceptor');\n $httpProvider.interceptors.push('ErrorInterceptor');\n }\n\n AuthInterceptor.$inject = ['$window', '$q'];\n function AuthInterceptor($window, $q) {\n return {\n response: function(response) {\n // When expecting JSON but receiving HTML, assume session has expired and reload page\n if (response && /^application\\/json/.test(response.config.headers.Accept) &&\n /^/.test(response.data)) {\n $window.location.reload(true);\n return $q.reject();\n }\n return response;\n }\n };\n }\n\n /**\n * @ngInject\n */\n ErrorInterceptor.$inject = ['$rootScope', '$q'];\n function ErrorInterceptor($rootScope, $q) {\n return {\n responseError: function(rejection) {\n if (/^application\\/json/.test(rejection.config.headers.Accept)) {\n // Broadcast the response error\n $rootScope.$broadcast('http:Error', rejection);\n }\n return $q.reject(rejection);\n }\n };\n }\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n/*\n * https://github.com/angular/material/issues/1269\n * https://gist.github.com/senthilprabhut/dd2147ebabc89bf223e7\n */\n\n(function() {\n 'use strict';\n\n var _$mdThemingProvider;\n\n angular\n .module('mdColors', ['ngMaterial'])\n .config(configure)\n .run(runBlock);\n\n /**\n * @ngInject\n */\n configure.$inject = ['$mdThemingProvider'];\n function configure($mdThemingProvider) {\n _$mdThemingProvider = $mdThemingProvider;\n }\n \n /**\n * @ngInject\n */\n runBlock.$inject = ['$interpolate', '$document', '$log'];\n function runBlock($interpolate, $document, $log) {\n\n function buildCssSelectors(selectors) {\n var result = selectors.join('');\n return result;\n }\n\n var fgDefault = $interpolate(buildCssSelectors(['.md-{{theme}}-theme','.md-fg']) + ' { color:{{value}};}'),\n bgDefault = $interpolate(buildCssSelectors(['.md-{{theme}}-theme','.md-bg']) + ' { background-color:{{value}};}'),\n bdrDefault = $interpolate(buildCssSelectors(['.md-{{theme}}-theme','.md-bdr']) + ' { border-color:{{value}};}'),\n fgDefaultHue = $interpolate(buildCssSelectors(['.md-{{theme}}-theme','.md-{{hue}}','.md-fg']) + ' { color:{{value}};}'),\n bgDefaultHue = $interpolate(buildCssSelectors(['.md-{{theme}}-theme','.md-{{hue}}','.md-bg']) + ' { background-color:{{value}};}'),\n fgColor = $interpolate(buildCssSelectors(['.md-{{theme}}-theme','.md-{{palette}}','.md-fg']) + ' { color:{{value}};}'),\n bgColor = $interpolate(buildCssSelectors(['.md-{{theme}}-theme','.md-{{palette}}','.md-bg']) + ' { background-color:{{value}}; color:{{contrast}}; }'),\n bdrColor = $interpolate(buildCssSelectors(['.md-{{theme}}-theme','.md-{{palette}}','.md-bdr']) + ' { border-color:{{value}};}'),\n fgHue = $interpolate(buildCssSelectors(['.md-{{theme}}-theme','.md-{{palette}}.md-{{hue}}','.md-fg']) + ' { color:{{value}};}'),\n bgHue = $interpolate(buildCssSelectors(['.md-{{theme}}-theme','.md-{{palette}}.md-{{hue}}','.md-bg']) + ' { background-color:{{value}};}'),\n customSheet = getStyleSheet(),\n index = 0;\n\n // Clear out old rules from stylesheet\n while (customSheet.cssRules.length > 0 ) {\n customSheet.deleteRule(0);\n }\n angular.forEach(_$mdThemingProvider._THEMES, function(theme, themeName){\n // Add default selectors - primary is the default palette\n addRule(fgDefault, bgDefault, themeName, 'primary',\n _$mdThemingProvider._PALETTES[theme.colors.primary.name][theme.colors.primary.hues.default]);\n addRule(fgDefaultHue, bgDefaultHue, themeName, 'primary',\n _$mdThemingProvider._PALETTES[theme.colors.primary.name][theme.colors.primary.hues['hue-2'] ], 'hue-2');\n addRule(fgDefaultHue, bgDefaultHue, themeName, 'primary',\n _$mdThemingProvider._PALETTES[theme.colors.primary.name][theme.colors.primary.hues['hue-3'] ], 'hue-3');\n addRule(fgDefaultHue, bgDefaultHue, themeName, 'primary',\n _$mdThemingProvider._PALETTES[theme.colors.primary.name][theme.colors.primary.hues['hue-1'] ], 'hue-1');\n addBorderRule(bdrDefault, themeName, 'primary',\n _$mdThemingProvider._PALETTES[theme.colors.primary.name][theme.colors.primary.hues.default]);\n\n // Add selectors for palettes - accent, background, primary and warn\n angular.forEach(theme.colors, function(color, paletteName){\n addRule(fgColor, bgColor, themeName, paletteName, _$mdThemingProvider._PALETTES[color.name][color.hues.default]);\n addBorderRule(bdrColor, themeName, paletteName, _$mdThemingProvider._PALETTES[color.name][color.hues.default]);\n addRule(fgHue, bgHue, themeName, paletteName, _$mdThemingProvider._PALETTES[color.name][color.hues['hue-2'] ], 'hue-2');\n addRule(fgHue, bgHue, themeName, paletteName, _$mdThemingProvider._PALETTES[color.name][color.hues['hue-3'] ], 'hue-3');\n addRule(fgHue, bgHue, themeName, paletteName, _$mdThemingProvider._PALETTES[color.name][color.hues['hue-1'] ], 'hue-1');\n });\n\n //$log.debug(_.pluck(customSheet.cssRules, 'cssText').join(\"\\n\"));\n });\n\n function addRule(fgInterpolate, bgInterpolate, themeName, paletteName, colorArray, hueName){\n // Set up interpolation functions to build css rules.\n if (!colorArray) return;\n var colorValue = 'rgb(' + colorArray.value[0] + ',' + colorArray.value[1] + ',' + colorArray.value[2] + ')',\n colorContrast = 'rgb(' + colorArray.contrast[0] + ',' + colorArray.contrast[1] + ',' + colorArray.contrast[2] + ')',\n context = {\n theme: themeName,\n palette: paletteName,\n value: colorValue,\n contrast: colorContrast,\n hue: hueName\n };\n\n // Insert foreground color rule\n customSheet.insertRule(fgInterpolate(context), index);\n index += 1;\n\n // Insert background color rule\n customSheet.insertRule(bgInterpolate(context), index);\n index += 1;\n }\n\n function addBorderRule(bdrInterpolate, themeName, paletteName, colorArray, hueName){\n // Set up interpolation functions to build css rule for border color.\n if (!colorArray) return;\n var colorValue = 'rgb(' + colorArray.value[0] + ',' + colorArray.value[1] + ',' + colorArray.value[2] + ')';\n\n customSheet.insertRule(bdrInterpolate({\n theme: themeName,\n palette: paletteName,\n value: colorValue,\n hue: hueName\n }), index);\n index += 1;\n }\n\n function getStyleSheet() {\n // function to add a dynamic style-sheet to the document\n var style = $document[0].head.querySelector('style[title=\"Dynamic-Generated-by-mdColors\"]');\n if (style === null) {\n style = $document[0].createElement('style');\n style.title = 'Dynamic-Generated-by-mdColors';\n // WebKit hack... (not sure if still needed)\n style.appendChild($document[0].createTextNode(''));\n $document[0].head.appendChild(style);\n }\n return style.sheet;\n }\n }\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n/**\n * @type {angular.Module}\n */\n(function () {\n 'use strict';\n\n /**\n * @ngInject\n */\n decodeUri.$inject = ['$window'];\n function decodeUri($window) {\n return $window.decodeURIComponent;\n }\n\n angular.module('SOGo.Common')\n .filter('decodeUri', decodeUri);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n/**\n * @type {angular.Module}\n */\n(function () {\n 'use strict';\n\n /**\n * @ngInject\n */\n encodeUri.$inject = ['$window'];\n function encodeUri($window) {\n return $window.encodeURIComponent;\n }\n\n angular.module('SOGo.Common')\n .filter('encodeUri', encodeUri);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function () {\n 'use strict';\n\n /**\n * ensureTarget - A filter to set a blank target to all links.\n * @memberof SOGo.Common\n * @ngInject\n * @example:\n\n
\n */\n ensureTarget.$inject = ['$sce'];\n function ensureTarget($sce) {\n return function(element) {\n var tree = angular.element('
' + element + '
');\n tree.find('a').attr('target', '_blank');\n return $sce.trustAs('html', tree.html());\n };\n }\n\n angular.module('SOGo.Common')\n .filter('ensureTarget', ensureTarget);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n/**\n * loc - A simple filter to return the localized version of a string.\n * @memberof SOGo.Common\n */\n(function () {\n 'use strict';\n\n /**\n * @ngInject\n */\n function loc() {\n return l;\n }\n\n angular.module('SOGo.Common')\n .filter('loc', loc);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n/**\n * range - A simple filter that will return an array of the size of its argument.\n * @memberof SOGo.Common\n */\n(function () {\n 'use strict';\n\n function range() {\n return function(n) {\n var res = [];\n for (var i = 0; i < parseInt(n); i++) {\n res.push(i);\n }\n return res;\n };\n }\n\n angular.module('SOGo.Common')\n .filter('range', range);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @ngInject\n */\n AclController.$inject = ['$mdDialog', 'Dialog', 'usersWithACL', 'User', 'folder'];\n function AclController($mdDialog, Dialog, usersWithACL, User, folder) {\n var vm = this;\n\n vm.users = usersWithACL; // ACL users\n vm.folder = folder;\n vm.selectedUser = null;\n vm.selectedUid = null;\n vm.userToAdd = '';\n vm.searchText = '';\n vm.userFilter = userFilter;\n vm.closeModal = closeModal;\n vm.saveModal = saveModal;\n vm.confirmChange = confirmChange;\n vm.removeUser = removeUser;\n vm.addUser = addUser;\n vm.selectUser = selectUser;\n vm.confirmation = { showing: false,\n message: ''};\n\n function userFilter($query) {\n return User.$filter($query, folder.$acl.users);\n }\n\n function closeModal() {\n folder.$acl.$resetUsersRights(); // cancel changes\n $mdDialog.hide();\n }\n\n function saveModal() {\n folder.$acl.$saveUsersRights().then(function() {\n $mdDialog.hide();\n }, function(data, status) {\n Dialog.alert(l('Warning'), l('An error occured please try again.'));\n });\n }\n\n function confirmChange(user) {\n var confirmation = user.$confirmRights(vm.folder);\n if (confirmation) {\n vm.confirmation.showing = true;\n vm.confirmation.message = confirmation;\n }\n }\n\n function removeUser(user) {\n folder.$acl.$removeUser(user.uid);\n }\n\n function addUser(data) {\n if (data) {\n folder.$acl.$addUser(data).then(function(user) {\n vm.userToAdd = '';\n vm.searchText = '';\n vm.selectedUid = null;\n if (user)\n selectUser(user);\n }, function(error) {\n Dialog.alert(l('Warning'), error);\n });\n }\n }\n\n function selectUser(user) {\n if (vm.selectedUid == user.uid) {\n vm.selectedUid = null;\n }\n else {\n vm.selectedUid = user.uid;\n vm.selectedUser = user;\n vm.selectedUser.$rights();\n }\n }\n }\n\n angular\n .module('SOGo.Common')\n .controller('AclController', AclController);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n/**\n * @type {angular.Module}\n */\n(function () {\n 'use strict';\n\n /**\n * @ngInject\n */\n navController.$inject = ['$rootScope', '$scope', '$timeout', '$interval', '$http', '$mdSidenav', '$mdToast', '$mdMedia', '$log', 'sgConstant', 'sgSettings', 'Alarm'];\n function navController($rootScope, $scope, $timeout, $interval, $http, $mdSidenav, $mdToast, $mdMedia, $log, sgConstant, sgSettings, Alarm) {\n\n $scope.isPopup = sgSettings.isPopup;\n $scope.activeUser = sgSettings.activeUser();\n $scope.baseURL = sgSettings.baseURL();\n $scope.leftIsClose = $mdMedia(sgConstant.xs);\n\n // Show current day in top bar\n $scope.currentDay = window.currentDay;\n $timeout(function() {\n // Update date when day ends\n $interval(function() {\n $http.get('../date').then(function(data) {\n $scope.currentDay = data;\n });\n }, 24 * 3600 * 1000);\n }, window.currentDay.secondsBeforeTomorrow * 1000);\n\n $scope.toggleLeft = function() {\n $scope.leftIsClose = leftIsClose();\n $mdSidenav('left').toggle()\n .then(function () {\n $log.debug(\"toggle left is done\");\n });\n };\n $scope.toggleRight = function() {\n $mdSidenav('right').toggle()\n .then(function () {\n $log.debug(\"toggle right is done\");\n });\n };\n // $scope.openBottomSheet = function() {\n // $mdBottomSheet.show({\n // parent: angular.element(document.getElementById('left-sidenav')),\n // templateUrl: 'bottomSheetTemplate.html'\n // });\n // };\n // $scope.toggleDetailView = function() {\n // var detail = angular.element(document.getElementById('detailView'));\n // detail.toggleClass('sg-close');\n // };\n $scope.$watch(function() {\n return $mdMedia(sgConstant['gt-sm']);\n }, function(newVal) {\n $scope.isGtMedium = newVal;\n if (newVal) {\n $scope.leftIsClose = false;\n }\n });\n\n function leftIsClose() {\n return !$mdSidenav('left').isOpen();\n }\n\n function onHttpError(event, response) {\n var message;\n if (response.data && response.data.message && angular.isString(response.data.message))\n message = response.data.message;\n else if (response.status)\n message = response.statusText;\n\n if (message)\n $mdToast.show({\n template: [\n '',\n '
',\n ' error_outline',\n ' ' + l(message) + '',\n '
',\n '
'\n ].join(''),\n hideDelay: 5000,\n position: 'top right'\n });\n else\n $log.debug('untrap error');\n }\n\n // Listen to HTTP errors broadcasted from HTTP interceptor\n $rootScope.$on('http:Error', onHttpError);\n\n Alarm.getAlarms();\n }\n\n angular.module('SOGo.Common')\n .controller('navController', navController);\n})();\n","(function() {\n 'use strict';\n\n /**\n * @name Acl\n * @constructor\n * @param {String} folderId - the folder ID associated to the ACLs\n */\n function Acl(folderId) {\n this.folderId = folderId;\n }\n\n /**\n * @memberof Acl\n * @desc The factory we'll use to register with Angular.\n * @return the Acl constructor\n */\n Acl.factory = ['$q', '$timeout', 'sgSettings', 'Resource', 'User', function($q, $timeout, Settings, Resource, User) {\n angular.extend(Acl, {\n $q: $q,\n $timeout: $timeout,\n $$resource: new Resource(Settings.activeUser('folderURL'), Settings.activeUser()),\n $User: User\n });\n\n return Acl;\n }];\n\n /**\n * @module SOGo.Common\n * @desc Factory registration of User in Angular module.\n */\n angular.module('SOGo.Common').factory('Acl', Acl.factory);\n\n /**\n * @function $users\n * @memberof Acl.prototype\n * @param {Object} owner - the owner to use when fetching the ACL as it might not be the Settings.activeUser\n * @desc Fetch the list of users that have specific rights for the current folder.\n * @return a promise of an array of User objects\n */\n Acl.prototype.$users = function(owner) {\n var _this = this,\n deferred = Acl.$q.defer(),\n user;\n if (this.users) {\n deferred.resolve(this.users);\n }\n else {\n var acls;\n if (angular.isDefined(owner))\n acls = Acl.$$resource.userResource(owner).fetch(this.folderId, 'acls');\n else\n acls = Acl.$$resource.fetch(this.folderId, 'acls');\n\n return acls.then(function(response) {\n _this.users = [];\n //console.debug(JSON.stringify(users, undefined, 2));\n angular.forEach(response.users, function(data) {\n user = new Acl.$User(data);\n user.canSubscribeUser = user.isSubscribed;\n user.wasSubscribed = user.isSubscribed;\n user.$rights = angular.bind(user, user.$acl, _this.folderId, owner);\n _this.users.push(user);\n });\n deferred.resolve(_this.users);\n return _this.users;\n });\n }\n return deferred.promise;\n };\n\n /**\n * @function $addUser\n * @memberof Acl.prototype\n * @param {Object} user - a User object with minimal set of attributes (uid, isGroup, cn, c_email)\n * @param {Object} owner - the owner to use when fetching the ACL as it might not be the Settings.activeUser\n * @see {@link User.$filter}\n */\n Acl.prototype.$addUser = function(user, owner) {\n var _this = this,\n deferred = Acl.$q.defer(),\n param = {uid: user.uid};\n if (!user.uid || _.indexOf(_.pluck(this.users, 'uid'), user.uid) > -1) {\n // No UID specified or user already in ACLs\n deferred.resolve();\n }\n else {\n var acls;\n\n if (angular.isDefined(owner))\n acls = Acl.$$resource.userResource(owner).fetch(this.folderId, 'addUserInAcls', param);\n else\n acls = Acl.$$resource.fetch(this.folderId, 'addUserInAcls', param);\n\n acls.then(function() {\n user.wasSubscribed = false;\n user.userClass = user.isGroup ? 'normal-group' : 'normal-user';\n user.$rights = angular.bind(user, user.$acl, _this.folderId);\n _this.users.push(user);\n deferred.resolve(user);\n }, function(data, status) {\n deferred.reject(l('An error occured please try again.'));\n });\n }\n return deferred.promise;\n };\n\n /**\n * @function $removeUser\n * @memberof Acl.prototype\n * @desc Remove a user from the folder's ACL\n * @return a promise of the server call to remove the user from the folder's ACL\n */\n Acl.prototype.$removeUser = function(uid) {\n var _this = this,\n param = {uid: uid};\n return Acl.$$resource.fetch(this.folderId, 'removeUserFromAcls', param).then(function() {\n var i = _.indexOf(_.pluck(_this.users, 'uid'), uid);\n if (i >= 0) {\n _this.users.splice(i, 1);\n }\n });\n };\n\n /**\n * @function $resetUsersRights\n * @memberof Acl.prototype\n * @desc Restore initial rights of all users.\n */\n Acl.prototype.$resetUsersRights = function() {\n angular.forEach(this.users, function(user) {\n user.$resetRights();\n });\n };\n\n /**\n * @function $saveUsersRights\n * @memberof Acl.prototype\n * @desc Save user rights that have changed and subscribe users that have been selected.\n * @param {Object} owner - the owner to use when fetching the ACL as it might not be the Settings.activeUser\n * @return a promise that resolved only if the modifications and subscriptions were successful\n */\n Acl.prototype.$saveUsersRights = function(owner) {\n var _this = this,\n deferredSave = Acl.$q.defer(),\n deferredSubscribe = Acl.$q.defer(),\n param = {action: 'saveUserRights'},\n users = [];\n\n // Save user rights\n angular.forEach(this.users, function(user) {\n if (user.$rightsAreDirty()) {\n users.push(user.$omit());\n // console.debug('save ' + JSON.stringify(user.$omit(), undefined, 2));\n }\n });\n if (users.length) {\n var acls;\n\n if (angular.isDefined(owner))\n acls = Acl.$$resource.userResource(owner).save(this.folderId, users, param);\n else\n acls = Acl.$$resource.save(this.folderId, users, param);\n\n acls.then(function() {\n // Save was successful; copy rights to shadow rights\n angular.forEach(_this.users, function(user) {\n if (user.$rightsAreDirty()) {\n user.$shadowRights = angular.copy(user.rights);\n }\n });\n deferredSave.resolve();\n }, deferredSave.reject);\n }\n else {\n deferredSave.resolve();\n }\n\n // Subscribe users\n users = [];\n angular.forEach(this.users, function(user) {\n if (!user.wasSubscribed && user.isSubscribed) {\n users.push(user.uid);\n // console.debug('subscribe ' + user.uid);\n }\n });\n if (users.length) {\n param = {uids: users.join(',')};\n Acl.$$resource.fetch(this.folderId, 'subscribeUsers', param)\n .then(function() {\n // Subscribe was successful; reset \"wasSubscribed\" attribute\n angular.forEach(_this.users, function(user) {\n user.wasSubscribed = user.isSubscribed;\n });\n deferredSubscribe.resolve();\n }, deferredSubscribe.reject);\n }\n else {\n deferredSubscribe.resolve();\n }\n return Acl.$q.all([deferredSave.promise, deferredSubscribe.promise]);\n };\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name Alarm\n * @constructor\n */\n function Alarm() {\n this.currentAlarm = null;\n }\n\n /**\n * @name getAlarms\n * @desc Fetch the list of alarms from the server and use the last one\n */\n Alarm.getAlarms = function() {\n var _this = this;\n var now = new Date();\n var browserTime = Math.floor(now.getTime()/1000);\n\n this.$$resource.fetch('', 'alarmslist?browserTime=' + browserTime).then(function(data) {\n \n var alarms = data.alarms.sort(function reverseSortByAlarmTime(a, b) {\n var x = parseInt(a[2]);\n var y = parseInt(b[2]);\n return (y - x);\n });\n\n if (alarms.length > 0) {\n var next = alarms.pop();\n var now = new Date();\n var utc = Math.floor(now.getTime()/1000);\n var url = next[0] + '/' + next[1];\n var alarmTime = parseInt(next[2]);\n var delay = alarmTime;\n if (alarmTime > 0) delay -= utc;\n var d = new Date(alarmTime*1000);\n //console.log (\"now = \" + now.toUTCString());\n //console.log (\"next event \" + url + \" in \" + delay + \" seconds (on \" + d.toUTCString() + \")\");\n\n var f = angular.bind(_this, Alarm.showAlarm, url);\n\n if (_this.currentAlarm)\n _this.$timeout.cancel(_this.currentAlarm);\n\n _this.currentAlarm = _this.$timeout(f, delay*1000);\n }\n });\n };\n \n /**\n * @name showAlarm\n * @desc Show the latest alarm using a toast\n * @param url The URL of the calendar component for snoozing\n */\n Alarm.showAlarm = function(url) {\n var _this = this;\n\n this.$$resource.fetch(url, '?resetAlarm=yes').then(function(data) {\n _this.$toast.show({\n position: 'top right',\n hideDelay: 0,\n template: [\n '',\n '
',\n ' ',\n ' ',\n ' ',\n ' ',\n l('5 minutes'),\n ' ',\n ' ',\n l('10 minutes'),\n ' ',\n ' ',\n l('15 minutes'),\n ' ',\n ' ',\n l('30 minutes'),\n ' ',\n ' ',\n l('45 minutes'),\n ' ',\n ' ',\n l('1 hour'),\n ' ',\n ' ',\n l('1 day'),\n ' ',\n ' ',\n ' ',\n ' ',\n l('Cancel'),\n ' ',\n ' ',\n l('Ok'),\n ' ',\n '
',\n '
'\n ].join(''),\n locals: {\n url: url\n },\n controller: AlarmController\n });\n\n /**\n * @ngInject\n */\n AlarmController.$inject = ['scope', '$mdToast', 'url'];\n function AlarmController(scope, $mdToast, url) {\n scope.reminder = '10';\n scope.cancel = function() {\n $mdToast.hide();\n };\n scope.ok = function() {\n _this.$$resource.fetch(url, 'view?snoozeAlarm=' + scope.reminder);\n $mdToast.hide();\n };\n }\n });\n };\n\n /**\n * @memberof Alarm\n * @desc The factory we'll register as Alarm in the Angular module SOGo.Common\n * @ngInject\n */\n AlarmService.$inject = ['$timeout', 'sgSettings', 'Resource', '$mdToast'];\n function AlarmService($timeout, Settings, Resource, $mdToast) {\n angular.extend(Alarm, {\n $timeout: $timeout,\n $$resource: new Resource(Settings.activeUser('folderURL') + 'Calendar', Settings.activeUser()),\n $toast: $mdToast\n });\n\n return Alarm; // return constructor\n }\n\n /* Factory registration in Angular module */\n angular\n .module('SOGo.Common')\n .factory('Alarm', AlarmService);\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n/* JavaScript for Authentication */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n angular.module('SOGo.Authentication', [])\n\n .constant('passwordPolicyConfig', {\n PolicyPasswordChangeUnsupported: -3,\n PolicyPasswordSystemUnknown: -2,\n PolicyPasswordUnknown: -1,\n PolicyPasswordExpired: 0,\n PolicyAccountLocked: 1,\n PolicyChangeAfterReset: 2,\n PolicyPasswordModNotAllowed: 3,\n PolicyMustSupplyOldPassword: 4,\n PolicyInsufficientPasswordQuality: 5,\n PolicyPasswordTooShort: 6,\n PolicyPasswordTooYoung: 7,\n PolicyPasswordInHistory: 8,\n PolicyNoError: 65535\n })\n\n // TODO: convert to a Factory recipe?\n .provider('Authentication', Authentication);\n\n function Authentication() {\n function readCookie(name) {\n var foundCookie, prefix, pairs, i, currentPair, start;\n foundCookie = null;\n prefix = name + '=';\n pairs = document.cookie.split(';');\n for (i = 0; !foundCookie && i < pairs.length; i++) {\n currentPair = pairs[i];\n start = 0;\n while (currentPair.charAt(start) == ' ')\n start++;\n if (start > 0)\n currentPair = currentPair.substr(start);\n if (currentPair.indexOf(prefix) === 0)\n foundCookie = currentPair.substr(prefix.length);\n }\n\n return foundCookie;\n }\n\n function readLoginCookie() {\n var loginValues = null,\n cookie = readCookie('0xHIGHFLYxSOGo'),\n value;\n if (cookie && cookie.length > 8) {\n value = decodeURIComponent(cookie.substr(8));\n loginValues = value.base64decode().split(':');\n }\n\n return loginValues;\n }\n\n function redirectUrl(username, domain) {\n var userName, address, baseAddress, altBaseAddress, parts, hostpart, protocol, newAddress;\n\n userName = username;\n if (domain)\n userName += '@' + domain.value;\n address = '' + window.location.href;\n baseAddress = ApplicationBaseURL + '/' + encodeURIComponent(userName);\n if (baseAddress[0] == '/') {\n parts = address.split('/');\n hostpart = parts[2];\n protocol = parts[0];\n baseAddress = protocol + '//' + hostpart + baseAddress;\n }\n parts = baseAddress.split('/');\n parts.splice(0, 3);\n altBaseAddress = parts.join('/');\n if ((address.startsWith(baseAddress) || address.startsWith(altBaseAddress)) &&\n !address.endsWith('/logoff')) {\n newAddress = address;\n }\n else {\n newAddress = baseAddress;\n }\n\n return newAddress;\n }\n\n this.$get = getService;\n\n /**\n * @ngInject\n */\n getService.$inject = ['$q', '$http', 'passwordPolicyConfig'];\n function getService($q, $http, passwordPolicyConfig) {\n var service;\n\n service = {\n login: function(data) {\n var d = $q.defer(),\n username = data.username,\n password = data.password,\n domain = data.domain,\n language,\n rememberLogin = data.rememberLogin ? 1 : 0;\n\n if (data.loginSuffix && !username.endsWith(data.loginSuffix)) {\n username += loginSuffix;\n domain = false;\n }\n if (data.language && data.language != 'WONoSelectionString') {\n language = data.language;\n }\n\n $http({\n method: 'POST',\n url: '/SOGo/connect',\n data: {\n userName: username,\n password: password,\n domain: domain,\n language: language,\n rememberLogin: rememberLogin\n }\n }).then(function(response) {\n var data = response.data;\n // Make sure browser's cookies are enabled\n var loginCookie = readLoginCookie();\n if (!loginCookie) {\n d.reject(l('cookiesNotEnabled'));\n }\n else {\n // Check password policy\n if (typeof data.expire != 'undefined' && typeof data.grace != 'undefined') {\n if (data.expire < 0 && data.grace > 0) {\n d.reject({grace: data.grace});\n //showPasswordDialog('grace', createPasswordGraceDialog, data['grace']);\n } else if (data.expire > 0 && data.grace == -1) {\n d.reject({expire: data.expire});\n //showPasswordDialog('expiration', createPasswordExpirationDialog, data['expire']);\n }\n else {\n d.resolve(redirectUrl(username, domain));\n }\n }\n else {\n d.resolve(redirectUrl(username, domain));\n }\n }\n }, function(response) {\n var msg, perr, data = response.data;\n if (data && data.LDAPPasswordPolicyError) {\n perr = data.LDAPPasswordPolicyError;\n if (perr == passwordPolicyConfig.PolicyNoError) {\n msg = l('Wrong username or password.');\n }\n else if (perr == passwordPolicyConfig.PolicyAccountLocked) {\n msg = l('Your account was locked due to too many failed attempts.');\n }\n else {\n msg = l('Login failed due to unhandled error case: ') + perr;\n }\n }\n else {\n msg = l('Unhandled error response');\n }\n d.reject({error: msg});\n });\n return d.promise;\n }, // login: function(data) { ...\n\n changePassword: function(newPassword) {\n var d = $q.defer(),\n loginCookie = readLoginCookie();\n\n $http({\n method: 'POST',\n url: '/SOGo/so/changePassword',\n data: {\n userName: loginCookie[0],\n password: loginCookie[1],\n newPassword: newPassword }\n }).then(d.resolve, function(response) {\n var error,\n data = response.data,\n perr = data.LDAPPasswordPolicyError;\n\n if (!perr) {\n perr = passwordPolicyConfig.PolicyPasswordSystemUnknown;\n error = _(\"Unhandled error response\");\n }\n else if (perr == passwordPolicyConfig.PolicyNoError) {\n error = l(\"Password change failed\");\n } else if (perr == passwordPolicyConfig.PolicyPasswordModNotAllowed) {\n error = l(\"Password change failed - Permission denied\");\n } else if (perr == passwordPolicyConfig.PolicyInsufficientPasswordQuality) {\n error = l(\"Password change failed - Insufficient password quality\");\n } else if (perr == passwordPolicyConfig.PolicyPasswordTooShort) {\n error = l(\"Password change failed - Password is too short\");\n } else if (perr == passwordPolicyConfig.PolicyPasswordTooYoung) {\n error = l(\"Password change failed - Password is too young\");\n } else if (perr == passwordPolicyConfig.PolicyPasswordInHistory) {\n error = l(\"Password change failed - Password is in history\");\n } else {\n error = l(\"Unhandled policy error: %{0}\").formatted(perr);\n perr = passwordPolicyConfig.PolicyPasswordUnknown;\n }\n\n d.reject(error);\n });\n return d.promise;\n }\n };\n return service;\n }\n }\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name Dialog\n * @constructor\n */\n function Dialog() {\n }\n\n /**\n * @name alert\n * @desc Show an alert dialog box with a single \"OK\" button\n * @param {string} title\n * @param {string} content\n */\n Dialog.alert = function(title, content) {\n var alert = this.$modal.alert()\n .title(title)\n .htmlContent(content)\n .ok(l('OK'));\n this.$modal.show(alert);\n };\n\n /**\n * @name confirm\n * @desc Show a confirmation dialog box with buttons 'Cancel' and 'OK'\n * @param {string} title\n * @param {string} content\n * @returns a promise that resolves if the user has clicked on the 'OK' button\n */\n Dialog.confirm = function(title, content, options) {\n var confirm = this.$modal.confirm()\n .title(title)\n .htmlContent(content)\n .ok((options && options.ok)? options.ok : l('OK'))\n .cancel((options && options.cancel)? options.cancel : l('Cancel'));\n return this.$modal.show(confirm);\n };\n\n /**\n * @name prompt\n * @desc Show a primpt dialog box with a input text field and the 'Cancel' and 'OK' buttons\n * @param {string} title\n * @param {string} label\n * @param {object} [options] - use a different input type by setting 'inputType'\n * @returns a promise that resolves with the input field value\n */\n Dialog.prompt = function(title, label, options) {\n var o = options || {},\n d = this.$q.defer();\n\n this.$modal.show({\n parent: angular.element(document.body),\n clickOutsideToClose: true,\n escapeToClose: true,\n template: [\n '',\n ' ',\n '

',\n ' ',\n ' ',\n ' ',\n ' ',\n '
',\n ' ',\n ' ',\n ' ' + l('Cancel'),\n ' ',\n ' ',\n ' ' + l('OK'),\n ' ',\n ' ',\n '
'\n ].join(''),\n controller: PromptDialogController\n });\n\n /**\n * @ngInject\n */\n PromptDialogController.$inject = ['scope', '$mdDialog'];\n function PromptDialogController(scope, $mdDialog) {\n scope.title = title;\n scope.name = \"\";\n scope.cancel = function() {\n d.reject();\n $mdDialog.hide();\n };\n scope.ok = function() {\n d.resolve(scope.name);\n $mdDialog.hide();\n };\n }\n\n return d.promise;\n };\n\n /**\n * @memberof Dialog\n * @desc The factory we'll register as Dialog in the Angular module SOGo.Common\n * @ngInject\n */\n DialogService.$inject = ['$q', '$mdDialog'];\n function DialogService($q, $mdDialog) {\n angular.extend(Dialog, { $q: $q , $modal: $mdDialog });\n\n return Dialog; // return constructor\n }\n\n /* Factory registration in Angular module */\n angular\n .module('SOGo.Common')\n .factory('Dialog', DialogService);\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * Gravatar - A service to build the Gravatar URL for an email address\n * @memberof SOGo.Common\n * @param {string} email\n * @param {number} [size] - the size of the image\n * @param {string} alternate avatar to use (none, identicon, monsterid, wavatar, retro)\n * @ngInject\n */\n function Gravatar() {\n return function(email, size, alternate_avatar, options) {\n var x, y, hash, s = size, a = alternate_avatar;\n if (!email) {\n return '';\n }\n x = email.indexOf('<');\n if (x >= 0) {\n y = email.indexOf('>', x);\n if (y > x)\n email = email.substring(x+1,y);\n }\n if (!size) {\n s = 48; // default to 48 pixels\n }\n hash = email.md5();\n\n if (!a || a == \"none\") {\n if (options && options.no_404)\n alternate_avatar = \"mm\"; // mystery man alternative\n else\n alternate_avatar = \"404\";\n }\n\n return 'https://www.gravatar.com/avatar/' + hash + '?s=' + s + '&d=' + alternate_avatar;\n };\n }\n\n angular\n .module('SOGo.Common')\n .factory('Gravatar', Gravatar);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name Resource\n * @constructor\n * @param {Object} $http - the Angular HTTP service\n * @param {Object} $q - the Angular promise/deferred service\n * @param {String} path - the base path of the external resource\n * @param {Object} options - extra attributes to be associated to the object\n */\n function Resource($http, $q, path, activeUser, options) {\n angular.extend(this, {\n _http: $http,\n _q: $q,\n _path: path,\n _activeUser: activeUser\n });\n angular.extend(this, options);\n // Trim trailing slash\n this._path = this._path.replace(/\\/$/, '');\n }\n\n /**\n * @memberof Resource\n * @desc The factory we'll use to register with Angular.\n * @return a new Resource object\n */\n Resource.$factory = ['$http', '$q', function($http, $q) {\n return function(path, activeUser, options) {\n return new Resource($http, $q, path, activeUser, options);\n };\n }];\n\n /**\n * @module SOGo.Common\n * @desc Factory registration of Resource in Angular module.\n */\n angular.module('SOGo.Common').factory('Resource', Resource.$factory);\n\n /**\n * @function userResource\n * @memberof Resource.prototype\n * @desc Create a new Resource object associated to a username different than the active user.\n * @param {String} uid - the user UID\n * @return a new Resource object\n */\n Resource.prototype.userResource = function(uid) {\n var path = _.compact(this._activeUser.folderURL.split('/'));\n path.splice(path.length - 1, 1, escape(uid));\n\n return new Resource(this._http, this._q, '/' + path.join('/'), this._activeUser);\n };\n\n /**\n * @function fetch\n * @memberof Resource.prototype\n * @desc Fetch resource using a specific folder, action and/or parameters.\n * @param {string} folderId - the folder on which the action will be applied (ex: addressbook, calendar)\n * @param {string} action - the action to be used in the URL\n * @param {Object} params - Object parameters injected through the $http service\n * @return a promise\n */\n Resource.prototype.fetch = function(folderId, action, params) {\n var deferred = this._q.defer(),\n path = [this._path];\n if (folderId) path.push(folderId.split('/'));\n if (action) path.push(action);\n path = _.compact(_.flatten(path)).join('/');\n\n this._http({\n method: 'GET',\n url: path,\n params: params\n })\n .then(function(response) {\n return deferred.resolve(response.data);\n }, function(response) {\n if (response.status == 404)\n return deferred.reject();\n });\n\n return deferred.promise;\n };\n\n /**\n * @function newguid\n * @memberof Resource.prototype\n * @desc Fetch a new GUID on the specified folder ID.\n * @return a promise of the new data structure\n */\n Resource.prototype.newguid = function(folderId) {\n var deferred = this._q.defer(),\n path = this._path + '/' + folderId + '/newguid';\n\n this._http\n .get(path)\n .then(function(response) {\n return deferred.resolve(response.data);\n }, deferred.reject);\n\n return deferred.promise;\n };\n\n /**\n * @function create\n * @memberof Resource.prototype\n * @desc Create a new resource using a specific action (post).\n * @param {string} action - the action to be used in the URL\n * @param {string} name - the new resource's name\n * @return a promise\n */\n Resource.prototype.create = function(action, name) {\n var deferred = this._q.defer(),\n path = this._path + '/' + action;\n\n this._http\n .post(path, { name: name })\n .then(function(response) {\n return deferred.resolve(response.data);\n }, deferred.reject);\n\n return deferred.promise;\n };\n\n /**\n * @function post\n * @memberof Resource.prototype\n * @desc Post a resource attributes on the server.\n * @return a promise\n */\n Resource.prototype.post = function(id, action, data) {\n var deferred = this._q.defer(),\n path = [this._path];\n if (id) path.push(id);\n if (action) path.push(action);\n path = _.compact(_.flatten(path)).join('/');\n\n this._http\n .post(path, data)\n .then(function(response) {\n return deferred.resolve(response.data);\n }, deferred.reject);\n\n return deferred.promise;\n };\n\n /**\n * @function save\n * @memberof Resource.prototype\n * @desc Save a resource attributes on the server (post /save).\n * @return a promise\n */\n Resource.prototype.save = function(id, newValue, options) {\n var deferred = this._q.defer(),\n action = (options && options.action)? options.action : 'save';\n\n return this.post(id, action, newValue);\n };\n\n /**\n * @function remove\n * @memberof Resource.prototype\n * @desc Delete a resource (get /delete).\n * @return a promise\n */\n Resource.prototype.remove = function(uid) {\n var deferred = this._q.defer(),\n path = this._path + '/' + uid + '/delete';\n\n this._http\n .get(path)\n .then(function(response) {\n return deferred.resolve(response.data);\n }, deferred.reject);\n\n return deferred.promise;\n };\n\n})();\n","(function() {\n 'use strict';\n\n /**\n * @name User\n * @constructor\n * @param {object} [userData] - some default values for the user\n */\n function User(userData) {\n if (userData) {\n this.init(userData);\n }\n }\n\n /**\n * @memberof User\n * @desc The factory we'll use to register with Angular.\n * @return the User constructor\n */\n User.factory = ['$q', '$log', 'sgSettings', 'Resource', 'Gravatar', function($q, $log, Settings, Resource, Gravatar) {\n angular.extend(User, {\n $q: $q,\n $log: $log,\n $$resource: new Resource(Settings.activeUser('folderURL'), Settings.activeUser()),\n $gravatar: Gravatar,\n $query: '',\n $users: []\n });\n\n return User;\n }];\n\n /**\n * @module SOGo.Common\n * @desc Factory registration of User in Angular module.\n */\n angular.module('SOGo.Common').factory('User', User.factory);\n\n /**\n * @memberof User\n * @desc Search for users that match a string.\n * @param {string} search - a string used to performed the search\n * @param {object[]} excludedUsers - a list of User objects that must be excluded from the results\n * @return a promise of an array of matching User objects\n */\n User.$filter = function(search, excludedUsers, options) {\n var _this = this, param = {search: search};\n\n if (!options || !options.dry) {\n if (!search) {\n // No query specified\n User.$users.splice(0, User.$users.length);\n return User.$q.when(User.$users);\n }\n if (User.$query == search) {\n // Query hasn't changed\n return User.$q.when(User.$users);\n }\n User.$query = search;\n }\n\n return User.$$resource.fetch(null, 'usersSearch', param).then(function(response) {\n var results, index, user, users,\n compareUids = function(data) {\n return this.uid == data.uid;\n };\n\n if (options && options.dry)\n users = [];\n else\n users = User.$users;\n\n if (excludedUsers) {\n // Remove excluded users from response\n results = _.filter(response.users, function(user) {\n return !_.find(excludedUsers, compareUids, user);\n });\n }\n else {\n results = response.users;\n }\n\n // Remove users that no longer match the search query\n for (index = users.length - 1; index >= 0; index--) {\n user = users[index];\n if (!_.find(results, compareUids, user)) {\n users.splice(index, 1);\n }\n }\n // Add new users matching the search query\n _.each(results, function(data, index) {\n if (_.isUndefined(_.find(users, compareUids, data))) {\n var user = new User(data);\n users.splice(index, 0, user);\n }\n });\n User.$log.debug(users);\n return users;\n });\n };\n\n /**\n * @function init\n * @memberof User.prototype\n * @desc Extend instance with required attributes and new data.\n * @param {object} data - attributes of user\n */\n User.prototype.init = function(data) {\n angular.extend(this, data);\n if (!this.$$shortFormat)\n this.$$shortFormat = this.$shortFormat();\n if (!this.$$image)\n this.$$image = this.image || User.$gravatar(this.c_email, 32, User.$alternateAvatar, {no_404: true});\n\n // An empty attribute to trick md-autocomplete when adding users from the ACLs editor\n this.empty = ' ';\n };\n\n /**\n * @function $shortFormat\n * @memberof User.prototype\n * @return the fullname along with the email address\n */\n User.prototype.$shortFormat = function(options) {\n var fullname = this.cn || this.c_email;\n var email = this.c_email;\n var no_email = options && options.email === false;\n if (!no_email && email && fullname != email) {\n fullname += ' <' + email + '>';\n }\n return fullname;\n };\n\n /**\n * @function $acl\n * @memberof User.prototype\n * @desc Fetch the user rights associated to a specific folder and populate the 'rights' attribute.\n * @param {string} the folder ID\n * @param {Object} owner - the owner to use when fetching the ACL as it might not be the Settings.activeUser\n * @return a promise\n */\n User.prototype.$acl = function(folderId, owner) {\n var _this = this,\n deferred = User.$q.defer(),\n param = {uid: this.uid};\n if (this.$shadowRights) {\n deferred.resolve(this.rights);\n }\n else {\n var rights;\n\n if (angular.isDefined(owner))\n rights = User.$$resource.userResource(owner).fetch(folderId, 'userRights', param);\n else\n rights = User.$$resource.fetch(folderId, 'userRights', param);\n\n rights.then(function(data) {\n _this.rights = data;\n // Convert numbers (0|1) to boolean values\n //angular.forEach(_.keys(_this.rights), function(key) {\n // _this.rights[key] = _this.rights[key] ? true : false;\n //});\n // console.debug('rights ' + _this.uid + ' => ' + JSON.stringify(data, undefined, 2));\n // Keep a copy of the server's version\n _this.$shadowRights = angular.copy(data);\n deferred.resolve(data);\n return data;\n });\n }\n return deferred.promise;\n };\n\n /**\n * @function $isAnonymous\n * @memberof User.prototype\n * @return true if it's the special anonymous user\n */\n User.prototype.$isAnonymous = function() {\n return this.uid == 'anonymous';\n };\n\n /**\n * @function $isSpecial\n * @memberof User.prototype\n * @desc Only accurate from the ACL editor.\n * @return true if the user is not a regular system user\n */\n User.prototype.$isSpecial = function() {\n return this.userClass && this.userClass == 'public-user';\n };\n\n /**\n * @function $confirmRights\n * @memberof User.prototype\n * @desc Check if a confirmation is required before giving some rights.\n * @return the confirmation message or false if no confirmation is required\n */\n User.prototype.$confirmRights = function(folder) {\n var confirmation = false;\n\n if (this.$confirmation) {\n // Don't bother the user more than once\n return false;\n }\n\n if (_.some(_.values(this.rights))) {\n if (this.uid == 'anonymous') {\n if (folder.constructor.name == 'AddressBook')\n confirmation = l('Potentially anyone on the Internet will be able to access your address book \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?', folder.name);\n else if (folder.constructor.name == 'Calendar')\n confirmation = l('Potentially anyone on the Internet will be able to access your calendar \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?', folder.name);\n }\n else if (this.uid == 'anyone' || this.uid == '') {\n if (folder.constructor.name == 'AddressBook')\n confirmation = l('Any user with an account on this system will be able to access your address book \"%{0}\". Are you certain you trust them all?', folder.name);\n else if (folder.constructor.name == 'Calendar')\n confirmation = l('Any user with an account on this system will be able to access your calendar \"%{0}\". Are you certain you trust them all?', folder.name);\n else if (folder.constructor.name == 'Mailbox')\n confirmation = l('Any user with an account on this system will be able to access your mailbox \"%{0}\". Are you certain you trust them all?', folder.name);\n }\n }\n\n this.$confirmation = confirmation;\n\n return confirmation;\n };\n\n /**\n * @function $rightsAreDirty\n * @memberof User.prototype\n * @return whether or not the rights have changed from their initial values\n */\n User.prototype.$rightsAreDirty = function() {\n return this.rights && !_.isEqual(this.rights, this.$shadowRights);\n };\n\n /**\n * @function $resetRights\n * @memberof User.prototype\n * @desc Restore initial rights or disable all rights\n * @param {boolean} [zero] - reset all rights to zero when true\n */\n User.prototype.$resetRights = function(zero) {\n var _this = this;\n if (zero) {\n // Disable all rights\n _.map(_.keys(this.rights), function(key) {\n if (angular.isString(_this.rights[key]))\n _this.rights[key] = 'None';\n else\n _this.rights[key] = 0;\n });\n }\n else {\n // Restore initial rights\n this.rights = angular.copy(this.$shadowRights);\n }\n };\n\n /**\n * @function $folders\n * @memberof User.prototype\n * @desc Retrieve the list of folders of a specific type\n * @param {string} type - either 'contact' or 'calendar'\n * @return a promise of the HTTP query result or the cached result\n */\n User.prototype.$folders = function(type) {\n var _this = this,\n deferred = User.$q.defer(),\n param = {type: type};\n if (this.$$folders) {\n deferred.resolve(this.$$folders);\n }\n else {\n User.$$resource.userResource(this.uid).fetch(null, 'foldersSearch', param).then(function(response) {\n _this.$$folders = response.folders;\n deferred.resolve(response.folders);\n });\n }\n return deferred.promise;\n };\n\n /**\n * @function $omit\n * @memberof User.prototype\n * @desc Return a sanitized object used to send to the server.\n * @return an object literal copy of the User instance\n */\n User.prototype.$omit = function() {\n var user = {};\n angular.forEach(this, function(value, key) {\n if (key != 'constructor' && key[0] != '$') {\n user[key] = value;\n }\n });\n return user;\n };\n\n User.prototype.toString = function() {\n return '[User ' + this.c_email + ']';\n };\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n \n /**\n * sgFocus - A service to set the focus on the element associated to a specific string\n * @memberof SOGo.Common\n * @param {string} name - the string identifier of the element\n * @see {@link SOGo.Common.sgFocusOn}\n * @ngInject\n */\n sgFocus.$inject = ['$rootScope', '$timeout'];\n function sgFocus($rootScope, $timeout) {\n return function(name) {\n $timeout(function() {\n $rootScope.$broadcast('sgFocusOn', name);\n });\n };\n }\n\n angular\n .module('SOGo.Common')\n .factory('sgFocus', sgFocus);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true, newcap: false */\n 'use strict';\n\n /**\n * sgAvatarImage - An avatar directive that returns un img element with either a local URL (if sg-src is specified)\n * or a Gravatar URL built from the Gravatar factory (using sg-email).\n * Based on http://blog.lingohub.com/2014/08/better-ux-with-angularjs-directives/.\n * @memberof SOGo.Common\n * @example:\n \n */\n function sgAvatarImage() {\n return {\n restrict: 'AE',\n scope: {},\n bindToController: {\n size: '@',\n email: '=sgEmail',\n src: '=sgSrc'\n },\n template: [\n 'person', // the generic icon\n '' // the gravatar or local image\n ].join(''),\n link: link,\n controller: 'sgAvatarImageController',\n controllerAs: 'vm'\n };\n }\n\n function link(scope, element, attrs, controller) {\n var imgElement = element.find('img'),\n mdIconElement = element.find('md-icon');\n\n if (attrs.size) {\n imgElement.attr('width', attrs.size);\n imgElement.attr('height', attrs.size);\n }\n\n controller.img = imgElement;\n controller.genericImg = mdIconElement;\n }\n\n /**\n * @ngInject\n */\n sgAvatarImageController.$inject = ['$scope', '$element', '$http', '$q', 'Preferences', 'Gravatar'];\n function sgAvatarImageController($scope, $element, $http, $q, Preferences, Gravatar) {\n var vm;\n\n vm = this;\n\n // Wait on user's defaults\n Preferences.ready().then(function() {\n $scope.$watch('vm.email', function(email, old) {\n if (email && vm.urlEmail != email) {\n // Email has changed or doesn't match the current URL (this happens when using md-virtual-repeat)\n showGenericAvatar();\n getGravatar(email);\n }\n else if (!email)\n showGenericAvatar();\n });\n });\n\n // If sg-src is defined, watch the expression for the URL of a local image\n if ('sg-src' in $element[0].attributes) {\n $scope.$watch('vm.src', function(src) {\n if (src) {\n // Set image URL and save the associated email address\n vm.url = src;\n vm.urlEmail = '' + vm.email;\n hideGenericAvatar();\n }\n });\n }\n\n function getGravatar(email) {\n var url = Gravatar(email, vm.size, Preferences.defaults.SOGoAlternateAvatar);\n $http({\n method: 'GET',\n url: url,\n cache: true,\n headers: { Accept: 'image/*' }\n }).then(function successCallback() {\n if (!vm.url) {\n // Set image URL and save the associated email address\n vm.url = url;\n vm.urlEmail = email;\n hideGenericAvatar();\n }\n }, function errorCallback() {\n showGenericAvatar();\n });\n }\n\n function showGenericAvatar() {\n vm.url = null;\n vm.urlEmail = null;\n vm.img.addClass('ng-hide');\n vm.genericImg.removeClass('ng-hide');\n }\n\n function hideGenericAvatar() {\n vm.genericImg.addClass('ng-hide');\n vm.img.removeClass('ng-hide');\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgAvatarImage', sgAvatarImage)\n .controller('sgAvatarImageController', sgAvatarImageController);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgColorPicker - Color picker widget\n * @restrict element\n * @param {function} sgOnSelect - the function to call when clicking on a color.\n * One variable is available: color.\n * @ngInject\n * @example:\n\n \n */\n function sgColorPicker() {\n return {\n restrict: 'E',\n require: 'ngModel',\n template: [\n '',\n ' ',\n ' color_lens',\n ' ',\n ' ',\n ' ',\n ' ',\n ' check_box',\n ' ',\n ' ',\n ' ',\n ''\n ].join(''),\n replace: true,\n controller: sgColorPickerController,\n link: link\n };\n\n function link(scope, iElement, iAttr, ngModelController) {\n // Expose ng-model value to scope\n ngModelController.$render = function() {\n scope.sgColor = ngModelController.$viewValue;\n scope.sgIconColor = contrast(ngModelController.$viewValue);\n };\n }\n }\n \n /**\n * @ngInject\n */\n sgColorPickerController.$inject = ['$scope', '$element', 'sgColors'];\n function sgColorPickerController($scope, $element, sgColors) {\n var ngModelController = $element.controller('ngModel');\n\n $scope.sgColors = sgColors.selection;\n $scope.setColor = function(color) {\n // Update scope value and ng-model\n $scope.sgColor = color;\n $scope.sgIconColor = contrast(color);\n ngModelController.$setViewValue(color);\n };\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgColorPicker', sgColorPicker);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgCompile - Assign an expression to a DOM element and compile it.\n * @memberof SOGo.Common\n * @restrict attribute\n * @param {object} sgCompile - the expression to compile\n * @ngInject\n * @example:\n\n
\n */\n sgCompile.$inject = ['$compile'];\n function sgCompile($compile) {\n return {\n restrict: 'A',\n link: sgCompileLink\n };\n\n function sgCompileLink(scope, element, attrs) {\n var ensureCompileRunsOnce = scope.$watch(\n function(scope) {\n // Watch the sg-compile expression for changes\n return scope.$eval(attrs.sgCompile);\n },\n function(value) {\n // When the sg-compile expression changes, assign it into the current DOM\n element.html(value);\n \n // Compile the new DOM and link it to the current scope.\n // NOTE: we only compile .childNodes so that we don't get into infinite loop compiling ourselves\n $compile(element.contents())(scope);\n \n // Use un-watch feature to ensure compilation happens only once.\n ensureCompileRunsOnce();\n }\n );\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgCompile', sgCompile);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * sgEnter - A directive evaluated when the enter key is pressed\n * @memberof SOGo.Common\n * @ngInject\n * @example:\n\n \n */\n function sgEnter() {\n var ENTER_KEY = 13;\n return function(scope, element, attrs) {\n element.bind(\"keydown keypress\", function(event) {\n if (event.which === ENTER_KEY) {\n scope.$apply(attrs.sgEnter);\n event.preventDefault();\n }\n });\n };\n }\n \n angular\n .module('SOGo.Common')\n .directive('sgEnter', sgEnter);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * sgEscape - A directive evaluated when the escape key is pressed\n * @memberof SOGo.Common\n * @ngInject\n * @example:\n\n \n */\n function sgEscape() {\n var ESCAPE_KEY = 27;\n return function(scope, elem, attrs) {\n elem.bind('keydown', function(event) {\n if (event.keyCode === ESCAPE_KEY) {\n scope.$apply(attrs.sgEscape);\n }\n });\n };\n }\n \n angular\n .module('SOGo.Common')\n .directive('sgEscape', sgEscape);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * sgFocusOn - A directive that sets the focus on its element when the specified string is broadcasted\n * @memberof SOGo.Common\n * @see {@link SOGo.Common.sgFocus}\n * @ngInject\n * @example:\n\n \n */\n function sgFocusOn() {\n return function(scope, elem, attr) {\n scope.$on('sgFocusOn', function(e, name) {\n if (name === attr.sgFocusOn) {\n elem[0].focus();\n elem[0].select();\n }\n });\n };\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgFocusOn', sgFocusOn);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgFolderStylesheet - Add CSS stylesheet for a folder's color (addressbook or calendar)\n * @memberof SOGo.Common\n * @restrict attribute\n * @param {object} ngModel - the object literal describing the folder (an Addressbook or Calendar instance)\n * @example:\n\n \n */\n function sgFolderStylesheet() {\n return {\n restrict: 'E',\n require: 'ngModel',\n scope: {\n ngModel: '='\n },\n replace: true,\n bindToController: true,\n controller: sgFolderStylesheetController,\n controllerAs: 'cssCtrl',\n template: [\n ''\n ].join('')\n };\n\n function sgFolderStylesheetController() {\n var vm = this;\n\n vm.contrast = contrast;\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgFolderStylesheet', sgFolderStylesheet);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * sgPlaceholder - A directive for dynamic placeholder\n * @memberof SOGo.Common\n * @ngInject\n * @example:\n\n \n */\n function sgPlaceholder() {\n return {\n restrict: 'A',\n scope: {\n placeholder: '=sgPlaceholder'\n },\n link: function(scope, elem, attr) {\n scope.$watch('placeholder',function() {\n elem[0].placeholder = scope.placeholder;\n });\n }\n };\n }\n \n angular\n .module('SOGo.Common')\n .directive('sgPlaceholder', sgPlaceholder);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgSearch - Search within a list of items\n * @memberof SOGo.Common\n * @restrict attribute\n * @param {function} sgSearch - the function to call when performing a search.\n * Two variables are available: searchField and searchText.\n * @example:\n\n
\n \n arrow_back\n \n \n \n \n \n Subject\n sender\n \n
\n */\n sgSearchPreTransclude.$inject = ['$parse'];\n function sgSearchPreTransclude($parse) {\n return {\n restrict: 'A',\n controller: 'sgSearchController',\n controllerAs: '$sgSearchController',\n priority: 1001,\n compile: compile\n };\n\n function compile(tElement, tAttr) {\n var mdInputEl = tElement.find('md-input-container'),\n inputEl = tElement.find('input'),\n selectEl = tElement.find('md-select'),\n buttonEl = tElement.find('md-button');\n\n inputEl.attr('ng-model', '$sgSearchController.searchText');\n inputEl.attr('ng-model-options', '$sgSearchController.searchTextOptions');\n inputEl.attr('ng-change', '$sgSearchController.onChange()');\n if (selectEl) {\n selectEl.attr('ng-model', '$sgSearchController.searchField');\n selectEl.attr('ng-change', '$sgSearchController.onChange()');\n }\n if (buttonEl && buttonEl.attr('sg-search-cancel')) {\n buttonEl.attr('ng-click', buttonEl.attr('sg-search-cancel'));\n buttonEl.removeAttr('sg-search-cancel');\n }\n else {\n buttonEl = null;\n }\n\n return function postLink(scope, iElement, iAttr, controller) {\n var compiledButtonEl = iElement.find('button');\n\n // Retrive the form and input names to check the form's validity in the controller\n controller.formName = iElement.attr('name');\n controller.inputName = inputEl.attr('name');\n\n // Associate the sg-allow-dot parameter (boolean) to the controller\n controller.allowDot = $parse(iElement.attr('sg-allow-dot'))(scope);\n\n // Associate callback to controller\n controller.doSearch = $parse(iElement.attr('sg-search'));\n\n // Reset the input field when cancelling the search\n if (buttonEl && compiledButtonEl) {\n compiledButtonEl.on('click', controller.cancelSearch);\n }\n };\n }\n }\n\n function sgSearch() {\n return {\n restrict: 'A',\n priority: 1000,\n transclude: true,\n compile: compile\n };\n\n function compile(tElement, tAttr) {\n return function postLink(scope, iElement, iAttr, controller, transclude) {\n transclude(function(clone) {\n iElement.append(clone);\n });\n };\n }\n }\n\n /**\n * @ngInject\n */\n sgSearchController.$inject = ['$window', '$scope', '$element'];\n function sgSearchController($window, $scope, $element) {\n var vm = this, minLength;\n\n // Domain's defaults\n minLength = angular.isNumber($window.minimumSearchLength)? $window.minimumSearchLength : 2;\n\n // Controller variables\n vm.searchText = null;\n\n // Model options\n vm.searchTextOptions = {\n updateOn: 'default blur',\n debounce: {\n default: 300,\n blur: 0\n }\n };\n\n // Method to call on data changes\n vm.onChange = function() {\n var form = $scope[vm.formName],\n input = form[vm.inputName],\n rawSearchText = input.$viewValue;\n\n if (vm.allowDot && rawSearchText == '.' || form.$valid && rawSearchText) {\n if (rawSearchText == '.')\n // Ignore the minlength constraint when using the dot operator\n input.$setValidity('minlength', true);\n\n // doSearch is the compiled expression of the sg-search attribute\n vm.doSearch($scope, { searchText: rawSearchText, searchField: vm.searchField });\n }\n };\n\n // Reset input field when cancelling the search\n vm.cancelSearch = function() {\n vm.searchText = null;\n };\n }\n\n angular\n .module('SOGo.Common')\n .controller('sgSearchController', sgSearchController)\n .directive('sgSearch', sgSearchPreTransclude)\n .directive('sgSearch', sgSearch);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgSubscribe - Common subscription widget\n * @restrict attribute\n * @param {string} sgSubscribe - the folder type\n * @param {function} sgSubscribeOnSelect - the function to call when subscribing to a folder.\n * One variable is available: folderData.\n * @ngInject\n * @example:\n\n Subscribe ..\n */\n sgSubscribe.$inject = ['User'];\n function sgSubscribe(User) {\n return {\n restrict: 'A',\n scope: {\n folderType: '@sgSubscribe',\n onFolderSelect: '&sgSubscribeOnSelect'\n },\n replace: false,\n bindToController: true,\n controller: sgSubscribeDialogController,\n controllerAs: '$sgSubscribeDialogController',\n link: link\n };\n }\n\n function link(scope, element, attrs, controller) {\n var inputEl = element.find('input');\n element.on('click', controller.showDialog);\n }\n\n /**\n * @ngInject\n */\n sgSubscribeDialogController.$inject = ['$mdDialog'];\n function sgSubscribeDialogController($mdDialog) {\n var vm = this;\n vm.showDialog = function() {\n $mdDialog.show({\n templateUrl: '../Contacts/UIxContactsUserFolders',\n clickOutsideToClose: true,\n locals: {\n folderType: vm.folderType,\n onFolderSelect: vm.onFolderSelect\n },\n controller: sgSubscribeController,\n controllerAs: 'subscribe'\n });\n };\n }\n\n /**\n * @ngInject\n */\n sgSubscribeController.$inject = ['$mdDialog', 'folderType', 'onFolderSelect', 'User'];\n function sgSubscribeController($mdDialog, folderType, onFolderSelect, User) {\n var vm = this;\n\n vm.selectedUser = null;\n vm.users = User.$users;\n\n vm.searchTextOptions = {\n updateOn: 'default blur',\n debounce: {\n default: 300,\n blur: 0\n }\n };\n\n vm.onChange = function() {\n User.$filter(vm.searchText).then(function() {\n if (vm.selectedUser) {\n // If selected user is no longer part of the matching users, unselect it\n if (_.isUndefined(_.find(User.$users, function(user) {\n return user.uid == vm.selectedUser.uid;\n }))) {\n vm.selectedUser = null;\n }\n }\n });\n };\n\n vm.selectUser = function(i) {\n if (vm.selectedUser == vm.users[i]) {\n vm.selectedUser = null;\n }\n else {\n // Fetch folders of specific type for selected user\n vm.users[i].$folders(folderType).then(function() {\n vm.selectedUser = vm.users[i];\n });\n }\n };\n\n // Callback upon subscription to a folder\n vm.selectFolder = function(folder) {\n onFolderSelect({folderData: folder});\n };\n\n vm.close = function() {\n $mdDialog.hide();\n };\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgSubscribe', sgSubscribe);\n})();\n","(function() {\n 'use strict';\n\n angular\n .module('SOGo.Common')\n .directive('sgTimePane', timePaneDirective);\n \n function timePaneDirective() {\n return {\n template: [\n '
',\n '
',\n '
',\n '
',\n ' {{hour.displayName}}',\n '
',\n '
',\n '
',\n '
',\n '
',\n '
',\n ' {{minute.displayName}}',\n '
',\n '
',\n '
',\n '
',\n '
',\n '
',\n ' {{minute.displayName}}',\n '
',\n '
',\n '
',\n '
',\n ' ',\n '
',\n '
'\n ].join(''),\n scope: {},\n require: ['ngModel', 'sgTimePane'],\n controller: TimePaneCtrl,\n controllerAs: 'ctrl',\n bindToController: true,\n link: function(scope, element, attrs, controllers) {\n var ngModelCtrl = controllers[0];\n var sgTimePaneCtrl = controllers[1];\n var timePaneElement = element;\n sgTimePaneCtrl.configureNgModel(ngModelCtrl, sgTimePaneCtrl, timePaneElement);\n }\n };\n }\n\n /** Class applied to the selected hour or minute cell/. */\n var SELECTED_TIME_CLASS = 'md-bg';\n\n /** Class applied to the focused hour or minute cell/. */\n var FOCUSED_TIME_CLASS = 'md-focus';\n\n /** Next identifier for calendar instance. */\n var nextTimePaneUniqueId = 0;\n\n function TimePaneCtrl($element, $attrs, $scope, $animate, $q, $mdConstant,\n $mdTheming, $$mdDateUtil, $mdDateLocale, $mdInkRipple, $mdUtil) {\n var m;\n this.$scope = $scope;\n this.$element = $element;\n this.timePaneElement = $element[0].querySelector('.sg-time-pane');\n this.$animate = $animate;\n this.$q = $q;\n this.$mdInkRipple = $mdInkRipple;\n this.$mdUtil = $mdUtil;\n this.keyCode = $mdConstant.KEY_CODE;\n this.dateUtil = $$mdDateUtil;\n this.id = nextTimePaneUniqueId++;\n this.ngModelCtrl = null;\n this.selectedTime = null;\n this.displayTime = null;\n this.isInitialized = false;\n\n $scope.hours=[];\n $scope.hours[0]=[];\n $scope.hours[0][0]=[];\n $scope.hours[0][1]=[];\n $scope.hours[1]=[];\n $scope.hours[1][0]=[];\n $scope.hours[1][1]=[];\n for(var i=0; i<6; i++){\n $scope.hours[0][0][i] = {id:'tp-'+this.id+'-hour-'+i, displayName:i<10?\"0\"+i:\"\"+i, selected:false};\n $scope.hours[0][1][i] = {id:'tp-'+this.id+'-hour-'+(i+6),displayName:(i+6)<10?\"0\"+(i+6):\"\"+(i+6), selected:false};\n $scope.hours[1][0][i] = {id:'tp-'+this.id+'-hour-'+(i+12), displayName:\"\"+(i+12), selected:false};\n $scope.hours[1][1][i] = {id:'tp-'+this.id+'-hour-'+(i+18), displayName:\"\"+(i+18), selected:false};\n }\n\n $scope.min5=[];\n $scope.min5[0]=[];\n $scope.min5[1]=[];\n for(i=0; i<6; i++){\n m=i*5;\n $scope.min5[0][i] = {id:'tp-'+this.id+'-minute5-'+m, displayName:m<10?\":0\"+m:\":\"+m, selected:true};\n $scope.min5[1][i] = {id:'tp-'+this.id+'-minute5-'+(m+30), displayName:\":\"+(m+30), selected:false};\n }\n\n $scope.min1=[];\n for(i=0; i<12; i++){\n $scope.min1[i]=[];\n for(var ii=0; ii<5; ii++){\n m=i*5 + ii;\n $scope.min1[i][ii] = {id:'tp-'+this.id+'-minute-'+m, displayName:m<10?\":0\"+m:\":\"+m, selected:true};\n }\n }\n\n $scope.show5min = true;\n $scope.getToggleBtnLbl = function() {\n return ($scope.is5min()) ? '>>' : '<<';\n };\n $scope.toggleManual5min = function() {\n $scope.manual5min = !$scope.is5min();\n };\n $scope.is5min = function() {\n if ($scope.manual5min === true || $scope.manual5min === false) {\n return $scope.manual5min;\n }\n else {\n return $scope.show5min;\n }\n };\n\n if (!$attrs.tabindex) {\n $element.attr('tabindex', '-1');\n }\n\n var self = this;\n\n this.hourClickHandler = function(displayVal) {\n var updated = new Date(self.displayTime);\n updated.setHours(Number(displayVal));\n self.setNgModelValue(updated, 'hours');\n };\n $scope.hourClickHandler = this.hourClickHandler;\n\n this.minuteClickHandler = function(displayVal) {\n //remove leading ':'\n var val = displayVal.substr(1);\n var updated = new Date(self.displayTime);\n updated.setMinutes(Number(val));\n self.setNgModelValue(updated, 'minutes');\n };\n $scope.minuteClickHandler = this.minuteClickHandler;\n\n this.attachTimePaneEventListeners();\n }\n TimePaneCtrl.$inject = [\"$element\", \"$attrs\", \"$scope\", \"$animate\", \"$q\", \"$mdConstant\", \"$mdTheming\", \"$$mdDateUtil\", \"$mdDateLocale\", \"$mdInkRipple\", \"$mdUtil\"];\n\n TimePaneCtrl.prototype.configureNgModel = function(ngModelCtrl, sgTimePaneCtrl, timePaneElement) {\n this.ngModelCtrl = ngModelCtrl;\n\n var self = this;\n ngModelCtrl.$render = function() {\n self.changeSelectedTime(self.ngModelCtrl.$viewValue, sgTimePaneCtrl, timePaneElement);\n };\n };\n\n /**\n * Change the selected date in the time (ngModel value has already been changed).\n */\n TimePaneCtrl.prototype.changeSelectedTime = function(date, sgTimePaneCtrl, timePaneElement) {\n var self = this;\n var previousSelectedTime = this.selectedTime;\n this.selectedTime = date;\n this.changeDisplayTime(date).then(function() {\n\n // Remove the selected class from the previously selected date, if any.\n if (previousSelectedTime) {\n var prevH = previousSelectedTime.getHours();\n var prevHCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-hour-'+prevH);\n if (prevHCell) {\n prevHCell.classList.remove(SELECTED_TIME_CLASS);\n prevHCell.setAttribute('aria-selected', 'false');\n }\n var prevM = previousSelectedTime.getMinutes();\n var prevMCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute-'+prevM);\n if (prevMCell) {\n prevMCell.classList.remove(SELECTED_TIME_CLASS);\n prevMCell.setAttribute('aria-selected', 'false');\n }\n var prevM5Cell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute5-'+prevM);\n if (prevM5Cell) {\n prevM5Cell.classList.remove(SELECTED_TIME_CLASS);\n prevM5Cell.setAttribute('aria-selected', 'false');\n }\n }\n\n // Apply the select class to the new selected date if it is set.\n if (date) {\n var newH = date.getHours();\n var mCell, hCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-hour-'+newH);\n if (hCell) {\n hCell.classList.add(SELECTED_TIME_CLASS);\n hCell.setAttribute('aria-selected', 'true');\n }\n var newM = date.getMinutes();\n if (newM % 5 === 0) {\n sgTimePaneCtrl.$scope.show5min = true;\n mCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute5-'+newM);\n if (mCell) {\n mCell.classList.add(SELECTED_TIME_CLASS);\n mCell.setAttribute('aria-selected', 'true');\n }\n }\n else {\n sgTimePaneCtrl.$scope.show5min = false;\n }\n mCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute-'+newM);\n if (mCell) {\n mCell.classList.add(SELECTED_TIME_CLASS);\n mCell.setAttribute('aria-selected', 'true');\n }\n\n }\n });\n };\n\n TimePaneCtrl.prototype.changeDisplayTime = function(date) {\n var d = new Date(date);\n if (!this.isInitialized) {\n this.buildInitialTimePaneDisplay();\n return this.$q.when();\n }\n if (!this.dateUtil.isValidDate(d)) {\n return this.$q.when();\n }\n\n this.displayTime = d;\n\n return this.$q.when();\n };\n TimePaneCtrl.prototype.buildInitialTimePaneDisplay = function() {\n this.displayTime = this.selectedTime || this.today;\n this.isInitialized = true;\n };\n\n TimePaneCtrl.prototype.attachTimePaneEventListeners = function() {\n // Keyboard interaction.\n this.$element.on('keydown', angular.bind(this, this.handleKeyEvent));\n };\n\n /*** User input handling ***/\n\n /**\n * Handles a key event in the calendar with the appropriate action. The action will either\n * be to select the focused date or to navigate to focus a new date.\n * @param {KeyboardEvent} event\n */\n TimePaneCtrl.prototype.handleKeyEvent = function(event) {\n var self = this;\n this.$scope.$apply(function() {\n // Capture escape and emit back up so that a wrapping component\n // (such as a time-picker) can decide to close.\n if (event.which == self.keyCode.ESCAPE || event.which == self.keyCode.TAB) {\n self.$scope.$emit('md-time-pane-close');\n\n if (event.which == self.keyCode.TAB) {\n event.preventDefault();\n }\n\n return;\n }\n\n // Remaining key events fall into two categories: selection and navigation.\n // Start by checking if this is a selection event.\n if (event.which === self.keyCode.ENTER) {\n self.setNgModelValue(self.displayTime, 'enter');\n event.preventDefault();\n return;\n }\n\n // Selection isn't occuring, so the key event is either navigation or nothing.\n /*var date = self.getFocusDateFromKeyEvent(event);\n if (date) {\n event.preventDefault();\n event.stopPropagation();\n\n // Since this is a keyboard interaction, actually give the newly focused date keyboard\n // focus after the been brought into view.\n self.changeDisplayTime(date).then(function () {\n self.focus(date);\n });\n }*/\n });\n };\n\n /**\n * Sets the ng-model value for the time pane and emits a change event.\n * @param {Date} date\n */\n TimePaneCtrl.prototype.setNgModelValue = function(date, mode) {\n this.$scope.$emit('sg-time-pane-change', {date:date, changed:mode});\n this.ngModelCtrl.$setViewValue(date);\n this.ngModelCtrl.$render();\n };\n\n /**\n * Focus the cell corresponding to the given date.\n * @param {Date=} opt_date\n */\n TimePaneCtrl.prototype.focus = function(opt_date, sgTimePaneCtrl) {\n var date = opt_date || this.selectedTime || this.today;\n\n var previousFocus = this.timePaneElement.querySelector('.md-focus');\n if (previousFocus) {\n previousFocus.classList.remove(FOCUSED_TIME_CLASS);\n }\n\n if (date) {\n var newH = date.getHours();\n var hCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-hour-'+newH);\n if (hCell) {\n hCell.classList.add(FOCUSED_TIME_CLASS);\n hCell.focus();\n }\n }\n };\n})();\n\n(function() {\n 'use strict';\n \n angular.module('SOGo.Common')\n .directive('sgTimepicker', timePickerDirective);\n\n /**\n * @ngdoc directive\n * @name mdTimepicker\n * @module material.components.timepicker\n *\n * @param {Date} ng-model The component's model. Expects a JavaScript Date object.\n * @param {expression=} ng-change Expression evaluated when the model value changes.\n * @param {boolean=} disabled Whether the timepicker is disabled.\n *\n * @description\n * `` is a component used to select a single time.\n * For information on how to configure internationalization for the time picker,\n * see `$mdTimeLocaleProvider`.\n *\n * @usage\n * \n * \n * \n *\n */\n function timePickerDirective() {\n return {\n template: [\n // Buttons are not in the tab order because users can open the hours pane via keyboard\n // interaction on the text input, and multiple tab stops for one component (picker)\n // may be confusing.\n '',\n ' access_time',\n '',\n '
',\n ' ',\n ' ',\n '
',\n '
',\n '
',\n // This pane will be detached from here and re-attached to the document body.\n '
',\n '
',\n '
', // using mdColors\n '
',\n '
',\n ' ',\n '
',\n '
'\n ].join(''),\n require: ['ngModel', 'sgTimepicker'],\n scope: {\n placeholder: '@mdPlaceholder'\n },\n controller: TimePickerCtrl,\n controllerAs: 'ctrl',\n bindToController: true,\n link: function(scope, element, attr, controllers) {\n var ngModelCtrl = controllers[0];\n var mdTimePickerCtrl = controllers[1];\n\n mdTimePickerCtrl.configureNgModel(ngModelCtrl);\n }\n };\n }\n\n /** Additional offset for the input's `size` attribute, which is updated based on its content. */\n var EXTRA_INPUT_SIZE = 3;\n\n /** Class applied to the container if the date is invalid. */\n var INVALID_CLASS = 'sg-timepicker-invalid';\n\n /** Default time in ms to debounce input event by. */\n var DEFAULT_DEBOUNCE_INTERVAL = 500;\n\n /**\n * Height of the calendar pane used to check if the pane is going outside the boundary of\n * the viewport. See calendar.scss for how $md-calendar-height is computed; an extra 20px is\n * also added to space the pane away from the exact edge of the screen.\n *\n * This is computed statically now, but can be changed to be measured if the circumstances\n * of calendar sizing are changed.\n */\n var TIME_PANE_HEIGHT = { MIN5: { GTSM: 172 + 20, SM: 292 + 20 },\n MIN1: { GTSM: 364 + 20, SM: 454 + 20 } };\n\n /**\n * Width of the calendar pane used to check if the pane is going outside the boundary of\n * the viewport. See calendar.scss for how $md-calendar-width is computed; an extra 20px is\n * also added to space the pane away from the exact edge of the screen.\n *\n * This is computed statically now, but can be changed to be measured if the circumstances\n * of calendar sizing are changed.\n */\n var TIME_PANE_WIDTH = { GTSM: 510 + 20, SM: 272 + 20 };\n\n /**\n * Controller for sg-timepicker.\n *\n * ngInject @constructor\n */\n TimePickerCtrl.$inject = [\"$scope\", \"$element\", \"$attrs\", \"$compile\", \"$timeout\", \"$window\",\n \"$mdConstant\", \"$mdMedia\", \"$mdTheming\", \"$mdUtil\", \"$mdDateLocale\", \"$$mdDateUtil\", \"$$rAF\"];\n function TimePickerCtrl($scope, $element, $attrs, $compile, $timeout, $window,\n $mdConstant, $mdMedia, $mdTheming, $mdUtil, $mdDateLocale, $$mdDateUtil, $$rAF) {\n /** @final */\n this.$compile = $compile;\n\n /** @final */\n this.$timeout = $timeout;\n\n /** @final */\n this.$window = $window;\n\n /** @final */\n this.dateLocale = $mdDateLocale;\n\n /** @final */\n this.dateUtil = $$mdDateUtil;\n\n /** @final */\n this.$mdConstant = $mdConstant;\n\n /** @final */\n this.$mdMedia = $mdMedia;\n\n /* @final */\n this.$mdUtil = $mdUtil;\n\n /** @final */\n this.$$rAF = $$rAF;\n\n /** @type {!angular.NgModelController} */\n this.ngModelCtrl = null;\n\n /** @type {HTMLInputElement} */\n this.inputElement = $element[0].querySelector('input');\n\n /** @type {HTMLElement} */\n this.inputContainer = $element[0].querySelector('.sg-timepicker-input-container');\n\n /** @final {!angular.JQLite} */\n this.ngInputElement = angular.element(this.inputElement);\n\n /** @type {HTMLElement} Floating time pane. */\n this.timePane = $element[0].querySelector('.sg-timepicker-time-pane');\n\n /** @type {HTMLElement} Time icon button. */\n this.timeButton = $element[0].querySelector('.sg-timepicker-button');\n\n /**\n * Element covering everything but the input in the top of the floating calendar pane.\n * @type {HTMLElement}\n */\n this.inputMask = $element[0].querySelector('.sg-timepicker-input-mask-opaque');\n\n /** @final {!angular.JQLite} */\n this.$element = $element;\n\n /** @final {!angular.Attributes} */\n this.$attrs = $attrs;\n\n /** @final {!angular.Scope} */\n this.$scope = $scope;\n\n /** @type {Date} */\n this.date = null;\n\n /** @type {boolean} */\n this.isFocused = false;\n\n /** @type {boolean} */\n this.isDisabled = false;\n this.setDisabled($element[0].disabled || angular.isString($attrs.disabled));\n\n /** @type {boolean} Whether the date-picker's calendar pane is open. */\n this.isTimeOpen = false;\n\n /**\n * Element from which the calendar pane was opened. Keep track of this so that we can return\n * focus to it when the pane is closed.\n * @type {HTMLElement}\n */\n this.timePaneOpenedFrom = null;\n\n this.timePane.id = 'sg-time-pane' + $mdUtil.nextUid();\n\n $mdTheming($element);\n\n /** Pre-bound click handler is saved so that the event listener can be removed. */\n this.bodyClickHandler = angular.bind(this, this.handleBodyClick);\n\n /** Pre-bound resize handler so that the event listener can be removed. */\n this.windowResizeHandler = $mdUtil.debounce(angular.bind(this, this.closeTimePane), 100);\n\n // Unless the user specifies so, the datepicker should not be a tab stop.\n // This is necessary because ngAria might add a tabindex to anything with an ng-model\n // (based on whether or not the user has turned that particular feature on/off).\n if (!$attrs.tabindex) {\n $element.attr('tabindex', '-1');\n }\n\n this.installPropertyInterceptors();\n this.attachChangeListeners();\n this.attachInteractionListeners();\n\n var self = this;\n $scope.$on('$destroy', function() {\n self.detachTimePane();\n });\n }\n\n /**\n * Sets up the controller's reference to ngModelController.\n * @param {!angular.NgModelController} ngModelCtrl\n */\n TimePickerCtrl.prototype.configureNgModel = function(ngModelCtrl) {\n this.ngModelCtrl = ngModelCtrl;\n\n var self = this;\n ngModelCtrl.$render = function() {\n var value = self.ngModelCtrl.$viewValue;\n\n if (value && !(value instanceof Date)) {\n throw Error('The ng-model for sg-timepicker must be a Date instance. ' +\n 'Currently the model is a: ' + (typeof value));\n }\n\n self.time = value;\n self.inputElement.value = self.dateLocale.formatTime(value);\n self.resizeInputElement();\n self.updateErrorState();\n };\n };\n\n /**\n * Attach event listeners for both the text input and the md-time.\n * Events are used instead of ng-model so that updates don't infinitely update the other\n * on a change. This should also be more performant than using a $watch.\n */\n TimePickerCtrl.prototype.attachChangeListeners = function() {\n var self = this;\n\n self.$scope.$on('sg-time-pane-change', function(event, data) {\n var time = new Date(data.date);\n self.ngModelCtrl.$setViewValue(time);\n self.time = time;\n self.inputElement.value = self.dateLocale.formatTime(time);\n if (data.changed == 'minutes') {\n self.closeTimePane();\n }\n self.resizeInputElement();\n self.inputContainer.classList.remove(INVALID_CLASS);\n });\n\n self.ngInputElement.on('input', angular.bind(self, self.resizeInputElement));\n self.ngInputElement.on('input', self.$mdUtil.debounce(self.handleInputEvent,\n DEFAULT_DEBOUNCE_INTERVAL, self));\n };\n\n /** Attach event listeners for user interaction. */\n TimePickerCtrl.prototype.attachInteractionListeners = function() {\n var self = this;\n var $scope = this.$scope;\n var keyCodes = this.$mdConstant.KEY_CODE;\n\n // Add event listener through angular so that we can triggerHandler in unit tests.\n self.ngInputElement.on('keydown', function(event) {\n if (event.altKey && event.keyCode == keyCodes.DOWN_ARROW) {\n self.openTimePane(event);\n $scope.$digest();\n }\n });\n\n $scope.$on('md-time-close', function() {\n self.closeTimePane();\n });\n };\n\n /**\n * Capture properties set to the time-picker and imperitively handle internal changes.\n * This is done to avoid setting up additional $watches.\n */\n TimePickerCtrl.prototype.installPropertyInterceptors = function() {\n var self = this;\n\n if (this.$attrs.ngDisabled) {\n // The expression is to be evaluated against the directive element's scope and not\n // the directive's isolate scope.\n var scope = this.$mdUtil.validateScope(this.$element) ? this.$element.scope() : null;\n if (scope) {\n scope.$watch(this.$attrs.ngDisabled, function(isDisabled) {\n self.setDisabled(isDisabled);\n });\n }\n }\n\n Object.defineProperty(this, 'placeholder', {\n get: function() { return self.inputElement.placeholder; },\n set: function(value) { self.inputElement.placeholder = value || ''; }\n });\n };\n\n /**\n * Sets whether the date-picker is disabled.\n * @param {boolean} isDisabled\n */\n TimePickerCtrl.prototype.setDisabled = function(isDisabled) {\n this.isDisabled = isDisabled;\n this.inputElement.disabled = isDisabled;\n this.timeButton.disabled = isDisabled;\n };\n\n /**\n * Sets the custom ngModel.$error flags to be consumed by ngMessages. Flags are:\n * - mindate: whether the selected date is before the minimum date.\n * - maxdate: whether the selected flag is after the maximum date.\n * - filtered: whether the selected date is allowed by the custom filtering function.\n * - valid: whether the entered text input is a valid date\n *\n * The 'required' flag is handled automatically by ngModel.\n *\n * @param {Date=} opt_date Date to check. If not given, defaults to the datepicker's model value.\n */\n TimePickerCtrl.prototype.updateErrorState = function(opt_date) {\n var date = opt_date || this.date;\n\n // Clear any existing errors to get rid of anything that's no longer relevant.\n this.clearErrorState();\n\n if (!this.dateUtil.isValidDate(date)) {\n // The date is seen as \"not a valid date\" if there is *something* set\n // (i.e.., not null or undefined), but that something isn't a valid date.\n this.ngModelCtrl.$setValidity('valid', date === null);\n }\n\n // TODO(jelbourn): Change this to classList.toggle when we stop using PhantomJS in unit tests\n // because it doesn't conform to the DOMTokenList spec.\n // See https://github.com/ariya/phantomjs/issues/12782.\n if (!this.ngModelCtrl.$valid) {\n this.inputContainer.classList.add(INVALID_CLASS);\n }\n };\n\n /** Clears any error flags set by `updateErrorState`. */\n TimePickerCtrl.prototype.clearErrorState = function() {\n this.inputContainer.classList.remove(INVALID_CLASS);\n ['valid'].forEach(function(field) {\n this.ngModelCtrl.$setValidity(field, true);\n }, this);\n };\n\n /**\n * Resizes the input element based on the size of its content.\n */\n TimePickerCtrl.prototype.resizeInputElement = function() {\n this.inputElement.size = this.inputElement.value.length + EXTRA_INPUT_SIZE;\n };\n\n /**\n * Sets the model value if the user input is a valid time.\n * Adds an invalid class to the input element if not.\n */\n TimePickerCtrl.prototype.handleInputEvent = function(self) {\n var inputString = this.inputElement.value;\n var arr = inputString.split(/[\\.:]/);\n\n if (inputString === '') {\n this.ngModelCtrl.$setViewValue(null);\n this.time = null;\n this.inputContainer.classList.remove(INVALID_CLASS);\n }\n else if (arr.length < 2) {\n this.inputContainer.classList.toggle(INVALID_CLASS, inputString);\n }\n else {\n var h = Number(arr[0]);\n var m = Number(arr[1]);\n var newVal = new Date(this.time);\n if (h && h >= 0 && h <= 23 && m && m >= 0 && m <= 59 && angular.isDate(newVal)) {\n newVal.setHours(h);\n newVal.setMinutes(m);\n this.ngModelCtrl.$setViewValue(newVal);\n this.time = newVal;\n this.inputContainer.classList.remove(INVALID_CLASS);\n }\n else {\n this.inputContainer.classList.toggle(INVALID_CLASS, inputString);\n }\n }\n };\n\n /** Position and attach the floating calendar to the document. */\n TimePickerCtrl.prototype.attachTimePane = function() {\n var timePane = this.timePane;\n this.$element.addClass('sg-timepicker-open');\n this.$element.find('button').addClass('md-primary');\n\n var elementRect = this.inputContainer.getBoundingClientRect();\n var bodyRect = document.body.getBoundingClientRect();\n\n // Check to see if the calendar pane would go off the screen. If so, adjust position\n // accordingly to keep it within the viewport.\n var paneTop = elementRect.top - bodyRect.top;\n var paneLeft = elementRect.left - bodyRect.left;\n\n // If the right edge of the pane would be off the screen and shifting it left by the\n // difference would not go past the left edge of the screen.\n var paneWidth = this.$mdMedia('sm')? TIME_PANE_WIDTH.SM : TIME_PANE_WIDTH.GTSM;\n if (paneLeft + paneWidth > bodyRect.right &&\n bodyRect.right - paneWidth > 0) {\n paneLeft = bodyRect.right - paneWidth;\n timePane.classList.add('sg-timepicker-pos-adjusted');\n }\n timePane.style.left = paneLeft + 'px';\n\n // If the bottom edge of the pane would be off the screen and shifting it up by the\n // difference would not go past the top edge of the screen.\n var min = (typeof this.time == 'object' && this.time.getMinutes() % 5 === 0)? 'MIN5' : 'MIN1';\n var paneHeight = this.$mdMedia('sm')? TIME_PANE_HEIGHT[min].SM : TIME_PANE_HEIGHT[min].GTSM;\n if (paneTop + paneHeight > bodyRect.bottom &&\n bodyRect.bottom - paneHeight > 0) {\n paneTop = bodyRect.bottom - paneHeight;\n timePane.classList.add('sg-timepicker-pos-adjusted');\n }\n\n timePane.style.top = paneTop + 'px';\n document.body.appendChild(timePane);\n\n // The top of the calendar pane is a transparent box that shows the text input underneath.\n // Since the pane is floating, though, the page underneath the pane *adjacent* to the input is\n // also shown unless we cover it up. The inputMask does this by filling up the remaining space\n // based on the width of the input.\n this.inputMask.style.left = elementRect.width + 'px';\n\n // Add CSS class after one frame to trigger open animation.\n this.$$rAF(function() {\n timePane.classList.add('md-pane-open');\n });\n };\n\n /** Detach the floating time pane from the document. */\n TimePickerCtrl.prototype.detachTimePane = function() {\n this.$element.removeClass('sg-timepicker-open');\n this.$element.find('button').removeClass('md-primary');\n this.timePane.classList.remove('md-pane-open');\n this.timePane.classList.remove('md-timepicker-pos-adjusted');\n\n if (this.timePane.parentNode) {\n // Use native DOM removal because we do not want any of the angular state of this element\n // to be disposed.\n this.timePane.parentNode.removeChild(this.timePane);\n }\n };\n\n /**\n * Open the floating time pane.\n * @param {Event} event\n */\n TimePickerCtrl.prototype.openTimePane = function(event) {\n if (!this.isTimeOpen && !this.isDisabled) {\n this.isTimeOpen = true;\n this.timePaneOpenedFrom = event.target;\n this.attachTimePane();\n //this.focusTime();\n\n // Because the time pane is attached directly to the body, it is possible that the\n // rest of the component (input, etc) is in a different scrolling container, such as\n // an md-content. This means that, if the container is scrolled, the pane would remain\n // stationary. To remedy this, we disable scrolling while the time pane is open, which\n // also matches the native behavior for things like `',\n ' ',\n ' ',\n ' ',\n ' ',\n ' ' + l('Cancel'),\n ' ',\n ' ',\n ' ' + l('OK'),\n ' ',\n ' ',\n ''\n ].join(''),\n controller: PromptDialogController\n });\n\n /**\n * @ngInject\n */\n PromptDialogController.$inject = ['scope', '$mdDialog'];\n function PromptDialogController(scope, $mdDialog) {\n scope.title = title;\n scope.name = \"\";\n scope.cancel = function() {\n d.reject();\n $mdDialog.hide();\n };\n scope.ok = function() {\n d.resolve(scope.name);\n $mdDialog.hide();\n };\n }\n\n return d.promise;\n };\n\n /**\n * @memberof Dialog\n * @desc The factory we'll register as Dialog in the Angular module SOGo.Common\n * @ngInject\n */\n DialogService.$inject = ['$q', '$mdDialog'];\n function DialogService($q, $mdDialog) {\n angular.extend(Dialog, { $q: $q , $modal: $mdDialog });\n\n return Dialog; // return constructor\n }\n\n /* Factory registration in Angular module */\n angular\n .module('SOGo.Common')\n .factory('Dialog', DialogService);\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * Gravatar - A service to build the Gravatar URL for an email address\n * @memberof SOGo.Common\n * @param {string} email\n * @param {number} [size] - the size of the image\n * @param {string} alternate avatar to use (none, identicon, monsterid, wavatar, retro)\n * @ngInject\n */\n function Gravatar() {\n return function(email, size, alternate_avatar, options) {\n var x, y, hash, s = size, a = alternate_avatar;\n if (!email) {\n return '';\n }\n x = email.indexOf('<');\n if (x >= 0) {\n y = email.indexOf('>', x);\n if (y > x)\n email = email.substring(x+1,y);\n }\n if (!size) {\n s = 48; // default to 48 pixels\n }\n hash = email.md5();\n\n if (!a || a == \"none\") {\n if (options && options.no_404)\n alternate_avatar = \"mm\"; // mystery man alternative\n else\n alternate_avatar = \"404\";\n }\n\n return 'https://www.gravatar.com/avatar/' + hash + '?s=' + s + '&d=' + alternate_avatar;\n };\n }\n\n angular\n .module('SOGo.Common')\n .factory('Gravatar', Gravatar);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * @name Resource\n * @constructor\n * @param {Object} $http - the Angular HTTP service\n * @param {Object} $q - the Angular promise/deferred service\n * @param {String} path - the base path of the external resource\n * @param {Object} options - extra attributes to be associated to the object\n */\n function Resource($http, $q, path, activeUser, options) {\n angular.extend(this, {\n _http: $http,\n _q: $q,\n _path: path,\n _activeUser: activeUser\n });\n angular.extend(this, options);\n // Trim trailing slash\n this._path = this._path.replace(/\\/$/, '');\n }\n\n /**\n * @memberof Resource\n * @desc The factory we'll use to register with Angular.\n * @return a new Resource object\n */\n Resource.$factory = ['$http', '$q', function($http, $q) {\n return function(path, activeUser, options) {\n return new Resource($http, $q, path, activeUser, options);\n };\n }];\n\n /**\n * @module SOGo.Common\n * @desc Factory registration of Resource in Angular module.\n */\n angular.module('SOGo.Common').factory('Resource', Resource.$factory);\n\n /**\n * @function userResource\n * @memberof Resource.prototype\n * @desc Create a new Resource object associated to a username different than the active user.\n * @param {String} uid - the user UID\n * @return a new Resource object\n */\n Resource.prototype.userResource = function(uid) {\n var path = _.compact(this._activeUser.folderURL.split('/'));\n path.splice(path.length - 1, 1, escape(uid));\n\n return new Resource(this._http, this._q, '/' + path.join('/'), this._activeUser);\n };\n\n /**\n * @function fetch\n * @memberof Resource.prototype\n * @desc Fetch resource using a specific folder, action and/or parameters.\n * @param {string} folderId - the folder on which the action will be applied (ex: addressbook, calendar)\n * @param {string} action - the action to be used in the URL\n * @param {Object} params - Object parameters injected through the $http service\n * @return a promise\n */\n Resource.prototype.fetch = function(folderId, action, params) {\n var deferred = this._q.defer(),\n path = [this._path];\n if (folderId) path.push(folderId.split('/'));\n if (action) path.push(action);\n path = _.compact(_.flatten(path)).join('/');\n\n this._http({\n method: 'GET',\n url: path,\n params: params\n })\n .then(function(response) {\n return deferred.resolve(response.data);\n }, function(response) {\n if (response.status == 404)\n return deferred.reject();\n });\n\n return deferred.promise;\n };\n\n /**\n * @function newguid\n * @memberof Resource.prototype\n * @desc Fetch a new GUID on the specified folder ID.\n * @return a promise of the new data structure\n */\n Resource.prototype.newguid = function(folderId) {\n var deferred = this._q.defer(),\n path = this._path + '/' + folderId + '/newguid';\n\n this._http\n .get(path)\n .then(function(response) {\n return deferred.resolve(response.data);\n }, deferred.reject);\n\n return deferred.promise;\n };\n\n /**\n * @function create\n * @memberof Resource.prototype\n * @desc Create a new resource using a specific action (post).\n * @param {string} action - the action to be used in the URL\n * @param {string} name - the new resource's name\n * @return a promise\n */\n Resource.prototype.create = function(action, name) {\n var deferred = this._q.defer(),\n path = this._path + '/' + action;\n\n this._http\n .post(path, { name: name })\n .then(function(response) {\n return deferred.resolve(response.data);\n }, deferred.reject);\n\n return deferred.promise;\n };\n\n /**\n * @function post\n * @memberof Resource.prototype\n * @desc Post a resource attributes on the server.\n * @return a promise\n */\n Resource.prototype.post = function(id, action, data) {\n var deferred = this._q.defer(),\n path = [this._path];\n if (id) path.push(id);\n if (action) path.push(action);\n path = _.compact(_.flatten(path)).join('/');\n\n this._http\n .post(path, data)\n .then(function(response) {\n return deferred.resolve(response.data);\n }, deferred.reject);\n\n return deferred.promise;\n };\n\n /**\n * @function save\n * @memberof Resource.prototype\n * @desc Save a resource attributes on the server (post /save).\n * @return a promise\n */\n Resource.prototype.save = function(id, newValue, options) {\n var deferred = this._q.defer(),\n action = (options && options.action)? options.action : 'save';\n\n return this.post(id, action, newValue);\n };\n\n /**\n * @function remove\n * @memberof Resource.prototype\n * @desc Delete a resource (get /delete).\n * @return a promise\n */\n Resource.prototype.remove = function(uid) {\n var deferred = this._q.defer(),\n path = this._path + '/' + uid + '/delete';\n\n this._http\n .get(path)\n .then(function(response) {\n return deferred.resolve(response.data);\n }, deferred.reject);\n\n return deferred.promise;\n };\n\n})();\n","(function() {\n 'use strict';\n\n /**\n * @name User\n * @constructor\n * @param {object} [userData] - some default values for the user\n */\n function User(userData) {\n if (userData) {\n this.init(userData);\n }\n }\n\n /**\n * @memberof User\n * @desc The factory we'll use to register with Angular.\n * @return the User constructor\n */\n User.factory = ['$q', '$log', 'sgSettings', 'Resource', 'Gravatar', function($q, $log, Settings, Resource, Gravatar) {\n angular.extend(User, {\n $q: $q,\n $log: $log,\n $$resource: new Resource(Settings.activeUser('folderURL'), Settings.activeUser()),\n $gravatar: Gravatar,\n $query: '',\n $users: []\n });\n\n return User;\n }];\n\n /**\n * @module SOGo.Common\n * @desc Factory registration of User in Angular module.\n */\n angular.module('SOGo.Common').factory('User', User.factory);\n\n /**\n * @memberof User\n * @desc Search for users that match a string.\n * @param {string} search - a string used to performed the search\n * @param {object[]} excludedUsers - a list of User objects that must be excluded from the results\n * @return a promise of an array of matching User objects\n */\n User.$filter = function(search, excludedUsers, options) {\n var _this = this, param = {search: search};\n\n if (!options || !options.dry) {\n if (!search) {\n // No query specified\n User.$users.splice(0, User.$users.length);\n return User.$q.when(User.$users);\n }\n if (User.$query == search) {\n // Query hasn't changed\n return User.$q.when(User.$users);\n }\n User.$query = search;\n }\n\n return User.$$resource.fetch(null, 'usersSearch', param).then(function(response) {\n var results, index, user, users,\n compareUids = function(data) {\n return this.uid == data.uid;\n };\n\n if (options) {\n if (options.dry)\n users = [];\n else if (options.results)\n users = options.results;\n }\n else\n users = User.$users;\n\n if (excludedUsers) {\n // Remove excluded users from response\n results = _.filter(response.users, function(user) {\n return !_.find(excludedUsers, compareUids, user);\n });\n }\n else {\n results = response.users;\n }\n\n // Remove users that no longer match the search query\n for (index = users.length - 1; index >= 0; index--) {\n user = users[index];\n if (!_.find(results, compareUids, user)) {\n users.splice(index, 1);\n }\n }\n // Add new users matching the search query\n _.each(results, function(data, index) {\n if (_.isUndefined(_.find(users, compareUids, data))) {\n var user = new User(data);\n users.splice(index, 0, user);\n }\n });\n User.$log.debug(users);\n return users;\n });\n };\n\n /**\n * @function init\n * @memberof User.prototype\n * @desc Extend instance with required attributes and new data.\n * @param {object} data - attributes of user\n */\n User.prototype.init = function(data) {\n angular.extend(this, data);\n if (!this.$$shortFormat)\n this.$$shortFormat = this.$shortFormat();\n if (!this.$$image)\n this.$$image = this.image || User.$gravatar(this.c_email, 32, User.$alternateAvatar, {no_404: true});\n\n // An empty attribute to trick md-autocomplete when adding users from the ACLs editor\n this.empty = ' ';\n };\n\n /**\n * @function $shortFormat\n * @memberof User.prototype\n * @return the fullname along with the email address\n */\n User.prototype.$shortFormat = function(options) {\n var fullname = this.cn || this.c_email;\n var email = this.c_email;\n var no_email = options && options.email === false;\n if (!no_email && email && fullname != email) {\n fullname += ' <' + email + '>';\n }\n return fullname;\n };\n\n /**\n * @function $acl\n * @memberof User.prototype\n * @desc Fetch the user rights associated to a specific folder and populate the 'rights' attribute.\n * @param {string} the folder ID\n * @param {Object} owner - the owner to use when fetching the ACL as it might not be the Settings.activeUser\n * @return a promise\n */\n User.prototype.$acl = function(folderId, owner) {\n var _this = this,\n deferred = User.$q.defer(),\n param = {uid: this.uid};\n if (this.$shadowRights) {\n deferred.resolve(this.rights);\n }\n else {\n var rights;\n\n if (angular.isDefined(owner))\n rights = User.$$resource.userResource(owner).fetch(folderId, 'userRights', param);\n else\n rights = User.$$resource.fetch(folderId, 'userRights', param);\n\n rights.then(function(data) {\n _this.rights = data;\n // Convert numbers (0|1) to boolean values\n //angular.forEach(_.keys(_this.rights), function(key) {\n // _this.rights[key] = _this.rights[key] ? true : false;\n //});\n // console.debug('rights ' + _this.uid + ' => ' + JSON.stringify(data, undefined, 2));\n // Keep a copy of the server's version\n _this.$shadowRights = angular.copy(data);\n deferred.resolve(data);\n return data;\n });\n }\n return deferred.promise;\n };\n\n /**\n * @function $isAnonymous\n * @memberof User.prototype\n * @return true if it's the special anonymous user\n */\n User.prototype.$isAnonymous = function() {\n return this.uid == 'anonymous';\n };\n\n /**\n * @function $isSpecial\n * @memberof User.prototype\n * @desc Only accurate from the ACL editor.\n * @return true if the user is not a regular system user\n */\n User.prototype.$isSpecial = function() {\n return this.userClass && this.userClass == 'public-user';\n };\n\n /**\n * @function $confirmRights\n * @memberof User.prototype\n * @desc Check if a confirmation is required before giving some rights.\n * @return the confirmation message or false if no confirmation is required\n */\n User.prototype.$confirmRights = function(folder) {\n var confirmation = false;\n\n if (this.$confirmation) {\n // Don't bother the user more than once\n return false;\n }\n\n if (_.some(_.values(this.rights))) {\n if (this.uid == 'anonymous') {\n if (folder.constructor.name == 'AddressBook')\n confirmation = l('Potentially anyone on the Internet will be able to access your address book \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?', folder.name);\n else if (folder.constructor.name == 'Calendar')\n confirmation = l('Potentially anyone on the Internet will be able to access your calendar \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?', folder.name);\n }\n else if (this.uid == 'anyone' || this.uid == '') {\n if (folder.constructor.name == 'AddressBook')\n confirmation = l('Any user with an account on this system will be able to access your address book \"%{0}\". Are you certain you trust them all?', folder.name);\n else if (folder.constructor.name == 'Calendar')\n confirmation = l('Any user with an account on this system will be able to access your calendar \"%{0}\". Are you certain you trust them all?', folder.name);\n else if (folder.constructor.name == 'Mailbox')\n confirmation = l('Any user with an account on this system will be able to access your mailbox \"%{0}\". Are you certain you trust them all?', folder.name);\n }\n }\n\n this.$confirmation = confirmation;\n\n return confirmation;\n };\n\n /**\n * @function $rightsAreDirty\n * @memberof User.prototype\n * @return whether or not the rights have changed from their initial values\n */\n User.prototype.$rightsAreDirty = function() {\n return this.rights && !_.isEqual(this.rights, this.$shadowRights);\n };\n\n /**\n * @function $resetRights\n * @memberof User.prototype\n * @desc Restore initial rights or disable all rights\n * @param {boolean} [zero] - reset all rights to zero when true\n */\n User.prototype.$resetRights = function(zero) {\n var _this = this;\n if (zero) {\n // Disable all rights\n _.map(_.keys(this.rights), function(key) {\n if (angular.isString(_this.rights[key]))\n _this.rights[key] = 'None';\n else\n _this.rights[key] = 0;\n });\n }\n else {\n // Restore initial rights\n this.rights = angular.copy(this.$shadowRights);\n }\n };\n\n /**\n * @function $folders\n * @memberof User.prototype\n * @desc Retrieve the list of folders of a specific type\n * @param {string} type - either 'contact' or 'calendar'\n * @return a promise of the HTTP query result or the cached result\n */\n User.prototype.$folders = function(type) {\n var _this = this,\n deferred = User.$q.defer(),\n param = {type: type};\n if (this.$$folders) {\n deferred.resolve(this.$$folders);\n }\n else {\n User.$$resource.userResource(this.uid).fetch(null, 'foldersSearch', param).then(function(response) {\n _this.$$folders = response.folders;\n deferred.resolve(response.folders);\n });\n }\n return deferred.promise;\n };\n\n /**\n * @function $omit\n * @memberof User.prototype\n * @desc Return a sanitized object used to send to the server.\n * @return an object literal copy of the User instance\n */\n User.prototype.$omit = function() {\n var user = {};\n angular.forEach(this, function(value, key) {\n if (key != 'constructor' && key[0] != '$') {\n user[key] = value;\n }\n });\n return user;\n };\n\n User.prototype.toString = function() {\n return '[User ' + this.c_email + ']';\n };\n\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n \n /**\n * sgFocus - A service to set the focus on the element associated to a specific string\n * @memberof SOGo.Common\n * @param {string} name - the string identifier of the element\n * @see {@link SOGo.Common.sgFocusOn}\n * @ngInject\n */\n sgFocus.$inject = ['$rootScope', '$timeout'];\n function sgFocus($rootScope, $timeout) {\n return function(name) {\n $timeout(function() {\n $rootScope.$broadcast('sgFocusOn', name);\n });\n };\n }\n\n angular\n .module('SOGo.Common')\n .factory('sgFocus', sgFocus);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true, newcap: false */\n 'use strict';\n\n /**\n * sgAvatarImage - An avatar directive that returns un img element with either a local URL (if sg-src is specified)\n * or a Gravatar URL built from the Gravatar factory (using sg-email).\n * Based on http://blog.lingohub.com/2014/08/better-ux-with-angularjs-directives/.\n * @memberof SOGo.Common\n * @example:\n \n */\n function sgAvatarImage() {\n return {\n restrict: 'AE',\n scope: {},\n bindToController: {\n size: '@',\n email: '=sgEmail',\n src: '=sgSrc'\n },\n template: [\n 'person', // the generic icon\n '' // the gravatar or local image\n ].join(''),\n link: link,\n controller: 'sgAvatarImageController',\n controllerAs: 'vm'\n };\n }\n\n function link(scope, element, attrs, controller) {\n var imgElement = element.find('img'),\n mdIconElement = element.find('md-icon');\n\n if (attrs.size) {\n imgElement.attr('width', attrs.size);\n imgElement.attr('height', attrs.size);\n }\n\n controller.img = imgElement;\n controller.genericImg = mdIconElement;\n }\n\n /**\n * @ngInject\n */\n sgAvatarImageController.$inject = ['$scope', '$element', '$http', '$q', 'Preferences', 'Gravatar'];\n function sgAvatarImageController($scope, $element, $http, $q, Preferences, Gravatar) {\n var vm;\n\n vm = this;\n\n // Wait on user's defaults\n Preferences.ready().then(function() {\n $scope.$watch('vm.email', function(email, old) {\n if (email && vm.urlEmail != email) {\n // Email has changed or doesn't match the current URL (this happens when using md-virtual-repeat)\n showGenericAvatar();\n getGravatar(email);\n }\n else if (!email)\n showGenericAvatar();\n });\n });\n\n // If sg-src is defined, watch the expression for the URL of a local image\n if ('sg-src' in $element[0].attributes) {\n $scope.$watch('vm.src', function(src) {\n if (src) {\n // Set image URL and save the associated email address\n vm.url = src;\n vm.urlEmail = '' + vm.email;\n hideGenericAvatar();\n }\n });\n }\n\n function getGravatar(email) {\n var url = Gravatar(email, vm.size, Preferences.defaults.SOGoAlternateAvatar);\n $http({\n method: 'GET',\n url: url,\n cache: true,\n headers: { Accept: 'image/*' }\n }).then(function successCallback() {\n if (!vm.url) {\n // Set image URL and save the associated email address\n vm.url = url;\n vm.urlEmail = email;\n hideGenericAvatar();\n }\n }, function errorCallback() {\n showGenericAvatar();\n });\n }\n\n function showGenericAvatar() {\n vm.url = null;\n vm.urlEmail = null;\n vm.img.addClass('ng-hide');\n vm.genericImg.removeClass('ng-hide');\n }\n\n function hideGenericAvatar() {\n vm.genericImg.addClass('ng-hide');\n vm.img.removeClass('ng-hide');\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgAvatarImage', sgAvatarImage)\n .controller('sgAvatarImageController', sgAvatarImageController);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgColorPicker - Color picker widget\n * @restrict element\n * @param {function} sgOnSelect - the function to call when clicking on a color.\n * One variable is available: color.\n * @ngInject\n * @example:\n\n \n */\n function sgColorPicker() {\n return {\n restrict: 'E',\n require: 'ngModel',\n template: [\n '',\n ' ',\n ' color_lens',\n ' ',\n ' ',\n ' ',\n ' ',\n ' check_box',\n ' ',\n ' ',\n ' ',\n ''\n ].join(''),\n replace: true,\n controller: sgColorPickerController,\n link: link\n };\n\n function link(scope, iElement, iAttr, ngModelController) {\n // Expose ng-model value to scope\n ngModelController.$render = function() {\n scope.sgColor = ngModelController.$viewValue;\n scope.sgIconColor = contrast(ngModelController.$viewValue);\n };\n }\n }\n \n /**\n * @ngInject\n */\n sgColorPickerController.$inject = ['$scope', '$element', 'sgColors'];\n function sgColorPickerController($scope, $element, sgColors) {\n var ngModelController = $element.controller('ngModel');\n\n $scope.sgColors = sgColors.selection;\n $scope.setColor = function(color) {\n // Update scope value and ng-model\n $scope.sgColor = color;\n $scope.sgIconColor = contrast(color);\n ngModelController.$setViewValue(color);\n };\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgColorPicker', sgColorPicker);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgCompile - Assign an expression to a DOM element and compile it.\n * @memberof SOGo.Common\n * @restrict attribute\n * @param {object} sgCompile - the expression to compile\n * @ngInject\n * @example:\n\n
\n */\n sgCompile.$inject = ['$compile'];\n function sgCompile($compile) {\n return {\n restrict: 'A',\n link: sgCompileLink\n };\n\n function sgCompileLink(scope, element, attrs) {\n var ensureCompileRunsOnce = scope.$watch(\n function(scope) {\n // Watch the sg-compile expression for changes\n return scope.$eval(attrs.sgCompile);\n },\n function(value) {\n // When the sg-compile expression changes, assign it into the current DOM\n element.html(value);\n \n // Compile the new DOM and link it to the current scope.\n // NOTE: we only compile .childNodes so that we don't get into infinite loop compiling ourselves\n $compile(element.contents())(scope);\n \n // Use un-watch feature to ensure compilation happens only once.\n ensureCompileRunsOnce();\n }\n );\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgCompile', sgCompile);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * sgEnter - A directive evaluated when the enter key is pressed\n * @memberof SOGo.Common\n * @ngInject\n * @example:\n\n \n */\n function sgEnter() {\n var ENTER_KEY = 13;\n return function(scope, element, attrs) {\n element.bind(\"keydown keypress\", function(event) {\n if (event.which === ENTER_KEY) {\n scope.$apply(attrs.sgEnter);\n event.preventDefault();\n }\n });\n };\n }\n \n angular\n .module('SOGo.Common')\n .directive('sgEnter', sgEnter);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * sgEscape - A directive evaluated when the escape key is pressed\n * @memberof SOGo.Common\n * @ngInject\n * @example:\n\n \n */\n function sgEscape() {\n var ESCAPE_KEY = 27;\n return function(scope, elem, attrs) {\n elem.bind('keydown', function(event) {\n if (event.keyCode === ESCAPE_KEY) {\n scope.$apply(attrs.sgEscape);\n }\n });\n };\n }\n \n angular\n .module('SOGo.Common')\n .directive('sgEscape', sgEscape);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * sgFocusOn - A directive that sets the focus on its element when the specified string is broadcasted\n * @memberof SOGo.Common\n * @see {@link SOGo.Common.sgFocus}\n * @ngInject\n * @example:\n\n \n */\n function sgFocusOn() {\n return function(scope, elem, attr) {\n scope.$on('sgFocusOn', function(e, name) {\n if (name === attr.sgFocusOn) {\n elem[0].focus();\n elem[0].select();\n }\n });\n };\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgFocusOn', sgFocusOn);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgFolderStylesheet - Add CSS stylesheet for a folder's color (addressbook or calendar)\n * @memberof SOGo.Common\n * @restrict attribute\n * @param {object} ngModel - the object literal describing the folder (an Addressbook or Calendar instance)\n * @example:\n\n \n */\n function sgFolderStylesheet() {\n return {\n restrict: 'E',\n require: 'ngModel',\n scope: {\n ngModel: '='\n },\n replace: true,\n bindToController: true,\n controller: sgFolderStylesheetController,\n controllerAs: 'cssCtrl',\n template: [\n ''\n ].join('')\n };\n\n function sgFolderStylesheetController() {\n var vm = this;\n\n vm.contrast = contrast;\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgFolderStylesheet', sgFolderStylesheet);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /**\n * sgPlaceholder - A directive for dynamic placeholder\n * @memberof SOGo.Common\n * @ngInject\n * @example:\n\n \n */\n function sgPlaceholder() {\n return {\n restrict: 'A',\n scope: {\n placeholder: '=sgPlaceholder'\n },\n link: function(scope, elem, attr) {\n scope.$watch('placeholder',function() {\n elem[0].placeholder = scope.placeholder;\n });\n }\n };\n }\n \n angular\n .module('SOGo.Common')\n .directive('sgPlaceholder', sgPlaceholder);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgSearch - Search within a list of items\n * @memberof SOGo.Common\n * @restrict attribute\n * @param {function} sgSearch - the function to call when performing a search.\n * Two variables are available: searchField and searchText.\n * @example:\n\n
\n \n arrow_back\n \n \n \n \n \n Subject\n sender\n \n
\n */\n sgSearchPreTransclude.$inject = ['$parse'];\n function sgSearchPreTransclude($parse) {\n return {\n restrict: 'A',\n controller: 'sgSearchController',\n controllerAs: '$sgSearchController',\n priority: 1001,\n compile: compile\n };\n\n function compile(tElement, tAttr) {\n var mdInputEl = tElement.find('md-input-container'),\n inputEl = tElement.find('input'),\n selectEl = tElement.find('md-select'),\n buttonEl = tElement.find('md-button');\n\n inputEl.attr('ng-model', '$sgSearchController.searchText');\n inputEl.attr('ng-model-options', '$sgSearchController.searchTextOptions');\n inputEl.attr('ng-change', '$sgSearchController.onChange()');\n if (selectEl) {\n selectEl.attr('ng-model', '$sgSearchController.searchField');\n selectEl.attr('ng-change', '$sgSearchController.onChange()');\n }\n if (buttonEl && buttonEl.attr('sg-search-cancel')) {\n buttonEl.attr('ng-click', buttonEl.attr('sg-search-cancel'));\n buttonEl.removeAttr('sg-search-cancel');\n }\n else {\n buttonEl = null;\n }\n\n return function postLink(scope, iElement, iAttr, controller) {\n var compiledButtonEl = iElement.find('button');\n\n // Retrive the form and input names to check the form's validity in the controller\n controller.formName = iElement.attr('name');\n controller.inputName = inputEl.attr('name');\n\n // Associate the sg-allow-dot parameter (boolean) to the controller\n controller.allowDot = $parse(iElement.attr('sg-allow-dot'))(scope);\n\n // Associate callback to controller\n controller.doSearch = $parse(iElement.attr('sg-search'));\n\n // Reset the input field when cancelling the search\n if (buttonEl && compiledButtonEl) {\n compiledButtonEl.on('click', controller.cancelSearch);\n }\n };\n }\n }\n\n function sgSearch() {\n return {\n restrict: 'A',\n priority: 1000,\n transclude: true,\n compile: compile\n };\n\n function compile(tElement, tAttr) {\n return function postLink(scope, iElement, iAttr, controller, transclude) {\n transclude(function(clone) {\n iElement.append(clone);\n });\n };\n }\n }\n\n /**\n * @ngInject\n */\n sgSearchController.$inject = ['$window', '$scope', '$element'];\n function sgSearchController($window, $scope, $element) {\n var vm = this, minLength;\n\n // Domain's defaults\n minLength = angular.isNumber($window.minimumSearchLength)? $window.minimumSearchLength : 2;\n\n // Controller variables\n vm.searchText = null;\n\n // Model options\n vm.searchTextOptions = {\n updateOn: 'default blur',\n debounce: {\n default: 300,\n blur: 0\n }\n };\n\n // Method to call on data changes\n vm.onChange = function() {\n var form = $scope[vm.formName],\n input = form[vm.inputName],\n rawSearchText = input.$viewValue;\n\n if (vm.allowDot && rawSearchText == '.' || form.$valid && rawSearchText) {\n if (rawSearchText == '.')\n // Ignore the minlength constraint when using the dot operator\n input.$setValidity('minlength', true);\n\n // doSearch is the compiled expression of the sg-search attribute\n vm.doSearch($scope, { searchText: rawSearchText, searchField: vm.searchField });\n }\n };\n\n // Reset input field when cancelling the search\n vm.cancelSearch = function() {\n vm.searchText = null;\n };\n }\n\n angular\n .module('SOGo.Common')\n .controller('sgSearchController', sgSearchController)\n .directive('sgSearch', sgSearchPreTransclude)\n .directive('sgSearch', sgSearch);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /*\n * sgSubscribe - Common subscription widget\n * @restrict attribute\n * @param {string} sgSubscribe - the folder type\n * @param {function} sgSubscribeOnSelect - the function to call when subscribing to a folder.\n * One variable is available: folderData.\n * @ngInject\n * @example:\n\n Subscribe ..\n */\n sgSubscribe.$inject = ['User'];\n function sgSubscribe(User) {\n return {\n restrict: 'A',\n scope: {\n folderType: '@sgSubscribe',\n onFolderSelect: '&sgSubscribeOnSelect'\n },\n replace: false,\n bindToController: true,\n controller: sgSubscribeDialogController,\n controllerAs: '$sgSubscribeDialogController',\n link: link\n };\n }\n\n function link(scope, element, attrs, controller) {\n var inputEl = element.find('input');\n element.on('click', controller.showDialog);\n }\n\n /**\n * @ngInject\n */\n sgSubscribeDialogController.$inject = ['$mdDialog'];\n function sgSubscribeDialogController($mdDialog) {\n var vm = this;\n vm.showDialog = function() {\n $mdDialog.show({\n templateUrl: '../Contacts/UIxContactsUserFolders',\n clickOutsideToClose: true,\n locals: {\n folderType: vm.folderType,\n onFolderSelect: vm.onFolderSelect\n },\n controller: sgSubscribeController,\n controllerAs: 'subscribe'\n });\n };\n }\n\n /**\n * @ngInject\n */\n sgSubscribeController.$inject = ['$mdDialog', 'folderType', 'onFolderSelect', 'User'];\n function sgSubscribeController($mdDialog, folderType, onFolderSelect, User) {\n var vm = this;\n\n vm.selectedUser = null;\n vm.users = [];\n\n vm.searchTextOptions = {\n updateOn: 'default blur',\n debounce: {\n default: 300,\n blur: 0\n }\n };\n\n vm.onChange = function(input) {\n User.$filter(vm.searchText, null, { results: vm.users }).then(function(users) {\n input.$setValidity('matches', users.length > 0);\n input.$setTouched();\n if (vm.selectedUser) {\n // If selected user is no longer part of the matching users, unselect it\n if (_.isUndefined(_.find(users, function(user) {\n return user.uid == vm.selectedUser.uid;\n }))) {\n vm.selectedUser = null;\n }\n }\n });\n };\n\n vm.selectUser = function(i) {\n if (vm.selectedUser == vm.users[i]) {\n vm.selectedUser = null;\n }\n else {\n // Fetch folders of specific type for selected user\n vm.users[i].$folders(folderType).then(function() {\n vm.selectedUser = vm.users[i];\n });\n }\n };\n\n // Callback upon subscription to a folder\n vm.selectFolder = function(folder) {\n onFolderSelect({folderData: folder});\n };\n\n vm.close = function() {\n $mdDialog.hide();\n };\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgSubscribe', sgSubscribe);\n})();\n","(function() {\n 'use strict';\n\n angular\n .module('SOGo.Common')\n .directive('sgTimePane', timePaneDirective);\n \n function timePaneDirective() {\n return {\n template: [\n '
',\n '
',\n '
',\n '
',\n ' {{hour.displayName}}',\n '
',\n '
',\n '
',\n '
',\n '
',\n '
',\n ' {{minute.displayName}}',\n '
',\n '
',\n '
',\n '
',\n '
',\n '
',\n ' {{minute.displayName}}',\n '
',\n '
',\n '
',\n '
',\n ' ',\n '
',\n '
'\n ].join(''),\n scope: {},\n require: ['ngModel', 'sgTimePane'],\n controller: TimePaneCtrl,\n controllerAs: 'ctrl',\n bindToController: true,\n link: function(scope, element, attrs, controllers) {\n var ngModelCtrl = controllers[0];\n var sgTimePaneCtrl = controllers[1];\n var timePaneElement = element;\n sgTimePaneCtrl.configureNgModel(ngModelCtrl, sgTimePaneCtrl, timePaneElement);\n }\n };\n }\n\n /** Class applied to the selected hour or minute cell/. */\n var SELECTED_TIME_CLASS = 'md-bg';\n\n /** Class applied to the focused hour or minute cell/. */\n var FOCUSED_TIME_CLASS = 'md-focus';\n\n /** Next identifier for calendar instance. */\n var nextTimePaneUniqueId = 0;\n\n function TimePaneCtrl($element, $attrs, $scope, $animate, $q, $mdConstant,\n $mdTheming, $$mdDateUtil, $mdDateLocale, $mdInkRipple, $mdUtil) {\n var m;\n this.$scope = $scope;\n this.$element = $element;\n this.timePaneElement = $element[0].querySelector('.sg-time-pane');\n this.$animate = $animate;\n this.$q = $q;\n this.$mdInkRipple = $mdInkRipple;\n this.$mdUtil = $mdUtil;\n this.keyCode = $mdConstant.KEY_CODE;\n this.dateUtil = $$mdDateUtil;\n this.id = nextTimePaneUniqueId++;\n this.ngModelCtrl = null;\n this.selectedTime = null;\n this.displayTime = null;\n this.isInitialized = false;\n\n $scope.hours=[];\n $scope.hours[0]=[];\n $scope.hours[0][0]=[];\n $scope.hours[0][1]=[];\n $scope.hours[1]=[];\n $scope.hours[1][0]=[];\n $scope.hours[1][1]=[];\n for(var i=0; i<6; i++){\n $scope.hours[0][0][i] = {id:'tp-'+this.id+'-hour-'+i, displayName:i<10?\"0\"+i:\"\"+i, selected:false};\n $scope.hours[0][1][i] = {id:'tp-'+this.id+'-hour-'+(i+6),displayName:(i+6)<10?\"0\"+(i+6):\"\"+(i+6), selected:false};\n $scope.hours[1][0][i] = {id:'tp-'+this.id+'-hour-'+(i+12), displayName:\"\"+(i+12), selected:false};\n $scope.hours[1][1][i] = {id:'tp-'+this.id+'-hour-'+(i+18), displayName:\"\"+(i+18), selected:false};\n }\n\n $scope.min5=[];\n $scope.min5[0]=[];\n $scope.min5[1]=[];\n for(i=0; i<6; i++){\n m=i*5;\n $scope.min5[0][i] = {id:'tp-'+this.id+'-minute5-'+m, displayName:m<10?\":0\"+m:\":\"+m, selected:true};\n $scope.min5[1][i] = {id:'tp-'+this.id+'-minute5-'+(m+30), displayName:\":\"+(m+30), selected:false};\n }\n\n $scope.min1=[];\n for(i=0; i<12; i++){\n $scope.min1[i]=[];\n for(var ii=0; ii<5; ii++){\n m=i*5 + ii;\n $scope.min1[i][ii] = {id:'tp-'+this.id+'-minute-'+m, displayName:m<10?\":0\"+m:\":\"+m, selected:true};\n }\n }\n\n $scope.show5min = true;\n $scope.getToggleBtnLbl = function() {\n return ($scope.is5min()) ? '>>' : '<<';\n };\n $scope.toggleManual5min = function() {\n $scope.manual5min = !$scope.is5min();\n };\n $scope.is5min = function() {\n if ($scope.manual5min === true || $scope.manual5min === false) {\n return $scope.manual5min;\n }\n else {\n return $scope.show5min;\n }\n };\n\n if (!$attrs.tabindex) {\n $element.attr('tabindex', '-1');\n }\n\n var self = this;\n\n this.hourClickHandler = function(displayVal) {\n var updated = new Date(self.displayTime);\n updated.setHours(Number(displayVal));\n self.setNgModelValue(updated, 'hours');\n };\n $scope.hourClickHandler = this.hourClickHandler;\n\n this.minuteClickHandler = function(displayVal) {\n //remove leading ':'\n var val = displayVal.substr(1);\n var updated = new Date(self.displayTime);\n updated.setMinutes(Number(val));\n self.setNgModelValue(updated, 'minutes');\n };\n $scope.minuteClickHandler = this.minuteClickHandler;\n\n this.attachTimePaneEventListeners();\n }\n TimePaneCtrl.$inject = [\"$element\", \"$attrs\", \"$scope\", \"$animate\", \"$q\", \"$mdConstant\", \"$mdTheming\", \"$$mdDateUtil\", \"$mdDateLocale\", \"$mdInkRipple\", \"$mdUtil\"];\n\n TimePaneCtrl.prototype.configureNgModel = function(ngModelCtrl, sgTimePaneCtrl, timePaneElement) {\n this.ngModelCtrl = ngModelCtrl;\n\n var self = this;\n ngModelCtrl.$render = function() {\n self.changeSelectedTime(self.ngModelCtrl.$viewValue, sgTimePaneCtrl, timePaneElement);\n };\n };\n\n /**\n * Change the selected date in the time (ngModel value has already been changed).\n */\n TimePaneCtrl.prototype.changeSelectedTime = function(date, sgTimePaneCtrl, timePaneElement) {\n var self = this;\n var previousSelectedTime = this.selectedTime;\n this.selectedTime = date;\n this.changeDisplayTime(date).then(function() {\n\n // Remove the selected class from the previously selected date, if any.\n if (previousSelectedTime) {\n var prevH = previousSelectedTime.getHours();\n var prevHCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-hour-'+prevH);\n if (prevHCell) {\n prevHCell.classList.remove(SELECTED_TIME_CLASS);\n prevHCell.setAttribute('aria-selected', 'false');\n }\n var prevM = previousSelectedTime.getMinutes();\n var prevMCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute-'+prevM);\n if (prevMCell) {\n prevMCell.classList.remove(SELECTED_TIME_CLASS);\n prevMCell.setAttribute('aria-selected', 'false');\n }\n var prevM5Cell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute5-'+prevM);\n if (prevM5Cell) {\n prevM5Cell.classList.remove(SELECTED_TIME_CLASS);\n prevM5Cell.setAttribute('aria-selected', 'false');\n }\n }\n\n // Apply the select class to the new selected date if it is set.\n if (date) {\n var newH = date.getHours();\n var mCell, hCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-hour-'+newH);\n if (hCell) {\n hCell.classList.add(SELECTED_TIME_CLASS);\n hCell.setAttribute('aria-selected', 'true');\n }\n var newM = date.getMinutes();\n if (newM % 5 === 0) {\n sgTimePaneCtrl.$scope.show5min = true;\n mCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute5-'+newM);\n if (mCell) {\n mCell.classList.add(SELECTED_TIME_CLASS);\n mCell.setAttribute('aria-selected', 'true');\n }\n }\n else {\n sgTimePaneCtrl.$scope.show5min = false;\n }\n mCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-minute-'+newM);\n if (mCell) {\n mCell.classList.add(SELECTED_TIME_CLASS);\n mCell.setAttribute('aria-selected', 'true');\n }\n\n }\n });\n };\n\n TimePaneCtrl.prototype.changeDisplayTime = function(date) {\n var d = new Date(date);\n if (!this.isInitialized) {\n this.buildInitialTimePaneDisplay();\n return this.$q.when();\n }\n if (!this.dateUtil.isValidDate(d)) {\n return this.$q.when();\n }\n\n this.displayTime = d;\n\n return this.$q.when();\n };\n TimePaneCtrl.prototype.buildInitialTimePaneDisplay = function() {\n this.displayTime = this.selectedTime || this.today;\n this.isInitialized = true;\n };\n\n TimePaneCtrl.prototype.attachTimePaneEventListeners = function() {\n // Keyboard interaction.\n this.$element.on('keydown', angular.bind(this, this.handleKeyEvent));\n };\n\n /*** User input handling ***/\n\n /**\n * Handles a key event in the calendar with the appropriate action. The action will either\n * be to select the focused date or to navigate to focus a new date.\n * @param {KeyboardEvent} event\n */\n TimePaneCtrl.prototype.handleKeyEvent = function(event) {\n var self = this;\n this.$scope.$apply(function() {\n // Capture escape and emit back up so that a wrapping component\n // (such as a time-picker) can decide to close.\n if (event.which == self.keyCode.ESCAPE || event.which == self.keyCode.TAB) {\n self.$scope.$emit('md-time-pane-close');\n\n if (event.which == self.keyCode.TAB) {\n event.preventDefault();\n }\n\n return;\n }\n\n // Remaining key events fall into two categories: selection and navigation.\n // Start by checking if this is a selection event.\n if (event.which === self.keyCode.ENTER) {\n self.setNgModelValue(self.displayTime, 'enter');\n event.preventDefault();\n return;\n }\n\n // Selection isn't occuring, so the key event is either navigation or nothing.\n /*var date = self.getFocusDateFromKeyEvent(event);\n if (date) {\n event.preventDefault();\n event.stopPropagation();\n\n // Since this is a keyboard interaction, actually give the newly focused date keyboard\n // focus after the been brought into view.\n self.changeDisplayTime(date).then(function () {\n self.focus(date);\n });\n }*/\n });\n };\n\n /**\n * Sets the ng-model value for the time pane and emits a change event.\n * @param {Date} date\n */\n TimePaneCtrl.prototype.setNgModelValue = function(date, mode) {\n this.$scope.$emit('sg-time-pane-change', {date:date, changed:mode});\n this.ngModelCtrl.$setViewValue(date);\n this.ngModelCtrl.$render();\n };\n\n /**\n * Focus the cell corresponding to the given date.\n * @param {Date=} opt_date\n */\n TimePaneCtrl.prototype.focus = function(opt_date, sgTimePaneCtrl) {\n var date = opt_date || this.selectedTime || this.today;\n\n var previousFocus = this.timePaneElement.querySelector('.md-focus');\n if (previousFocus) {\n previousFocus.classList.remove(FOCUSED_TIME_CLASS);\n }\n\n if (date) {\n var newH = date.getHours();\n var hCell = document.getElementById('tp-'+sgTimePaneCtrl.id+'-hour-'+newH);\n if (hCell) {\n hCell.classList.add(FOCUSED_TIME_CLASS);\n hCell.focus();\n }\n }\n };\n})();\n\n(function() {\n 'use strict';\n \n angular.module('SOGo.Common')\n .directive('sgTimepicker', timePickerDirective);\n\n /**\n * @ngdoc directive\n * @name mdTimepicker\n * @module material.components.timepicker\n *\n * @param {Date} ng-model The component's model. Expects a JavaScript Date object.\n * @param {expression=} ng-change Expression evaluated when the model value changes.\n * @param {boolean=} disabled Whether the timepicker is disabled.\n *\n * @description\n * `` is a component used to select a single time.\n * For information on how to configure internationalization for the time picker,\n * see `$mdTimeLocaleProvider`.\n *\n * @usage\n * \n * \n * \n *\n */\n function timePickerDirective() {\n return {\n template: [\n // Buttons are not in the tab order because users can open the hours pane via keyboard\n // interaction on the text input, and multiple tab stops for one component (picker)\n // may be confusing.\n '',\n ' access_time',\n '',\n '
',\n ' ',\n ' ',\n '
',\n '
',\n '
',\n // This pane will be detached from here and re-attached to the document body.\n '
',\n '
',\n '
', // using mdColors\n '
',\n '
',\n ' ',\n '
',\n '
'\n ].join(''),\n require: ['ngModel', 'sgTimepicker'],\n scope: {\n placeholder: '@mdPlaceholder'\n },\n controller: TimePickerCtrl,\n controllerAs: 'ctrl',\n bindToController: true,\n link: function(scope, element, attr, controllers) {\n var ngModelCtrl = controllers[0];\n var mdTimePickerCtrl = controllers[1];\n\n mdTimePickerCtrl.configureNgModel(ngModelCtrl);\n }\n };\n }\n\n /** Additional offset for the input's `size` attribute, which is updated based on its content. */\n var EXTRA_INPUT_SIZE = 3;\n\n /** Class applied to the container if the date is invalid. */\n var INVALID_CLASS = 'sg-timepicker-invalid';\n\n /** Default time in ms to debounce input event by. */\n var DEFAULT_DEBOUNCE_INTERVAL = 500;\n\n /**\n * Height of the calendar pane used to check if the pane is going outside the boundary of\n * the viewport. See calendar.scss for how $md-calendar-height is computed; an extra 20px is\n * also added to space the pane away from the exact edge of the screen.\n *\n * This is computed statically now, but can be changed to be measured if the circumstances\n * of calendar sizing are changed.\n */\n var TIME_PANE_HEIGHT = { MIN5: { GTSM: 172 + 20, SM: 292 + 20 },\n MIN1: { GTSM: 364 + 20, SM: 454 + 20 } };\n\n /**\n * Width of the calendar pane used to check if the pane is going outside the boundary of\n * the viewport. See calendar.scss for how $md-calendar-width is computed; an extra 20px is\n * also added to space the pane away from the exact edge of the screen.\n *\n * This is computed statically now, but can be changed to be measured if the circumstances\n * of calendar sizing are changed.\n */\n var TIME_PANE_WIDTH = { GTSM: 510 + 20, SM: 272 + 20 };\n\n /**\n * Controller for sg-timepicker.\n *\n * ngInject @constructor\n */\n TimePickerCtrl.$inject = [\"$scope\", \"$element\", \"$attrs\", \"$compile\", \"$timeout\", \"$window\",\n \"$mdConstant\", \"$mdMedia\", \"$mdTheming\", \"$mdUtil\", \"$mdDateLocale\", \"$$mdDateUtil\", \"$$rAF\"];\n function TimePickerCtrl($scope, $element, $attrs, $compile, $timeout, $window,\n $mdConstant, $mdMedia, $mdTheming, $mdUtil, $mdDateLocale, $$mdDateUtil, $$rAF) {\n /** @final */\n this.$compile = $compile;\n\n /** @final */\n this.$timeout = $timeout;\n\n /** @final */\n this.$window = $window;\n\n /** @final */\n this.dateLocale = $mdDateLocale;\n\n /** @final */\n this.dateUtil = $$mdDateUtil;\n\n /** @final */\n this.$mdConstant = $mdConstant;\n\n /** @final */\n this.$mdMedia = $mdMedia;\n\n /* @final */\n this.$mdUtil = $mdUtil;\n\n /** @final */\n this.$$rAF = $$rAF;\n\n /** @type {!angular.NgModelController} */\n this.ngModelCtrl = null;\n\n /** @type {HTMLInputElement} */\n this.inputElement = $element[0].querySelector('input');\n\n /** @type {HTMLElement} */\n this.inputContainer = $element[0].querySelector('.sg-timepicker-input-container');\n\n /** @final {!angular.JQLite} */\n this.ngInputElement = angular.element(this.inputElement);\n\n /** @type {HTMLElement} Floating time pane. */\n this.timePane = $element[0].querySelector('.sg-timepicker-time-pane');\n\n /** @type {HTMLElement} Time icon button. */\n this.timeButton = $element[0].querySelector('.sg-timepicker-button');\n\n /**\n * Element covering everything but the input in the top of the floating calendar pane.\n * @type {HTMLElement}\n */\n this.inputMask = $element[0].querySelector('.sg-timepicker-input-mask-opaque');\n\n /** @final {!angular.JQLite} */\n this.$element = $element;\n\n /** @final {!angular.Attributes} */\n this.$attrs = $attrs;\n\n /** @final {!angular.Scope} */\n this.$scope = $scope;\n\n /** @type {Date} */\n this.date = null;\n\n /** @type {boolean} */\n this.isFocused = false;\n\n /** @type {boolean} */\n this.isDisabled = false;\n this.setDisabled($element[0].disabled || angular.isString($attrs.disabled));\n\n /** @type {boolean} Whether the date-picker's calendar pane is open. */\n this.isTimeOpen = false;\n\n /**\n * Element from which the calendar pane was opened. Keep track of this so that we can return\n * focus to it when the pane is closed.\n * @type {HTMLElement}\n */\n this.timePaneOpenedFrom = null;\n\n this.timePane.id = 'sg-time-pane' + $mdUtil.nextUid();\n\n $mdTheming($element);\n\n /** Pre-bound click handler is saved so that the event listener can be removed. */\n this.bodyClickHandler = angular.bind(this, this.handleBodyClick);\n\n /** Pre-bound resize handler so that the event listener can be removed. */\n this.windowResizeHandler = $mdUtil.debounce(angular.bind(this, this.closeTimePane), 100);\n\n // Unless the user specifies so, the datepicker should not be a tab stop.\n // This is necessary because ngAria might add a tabindex to anything with an ng-model\n // (based on whether or not the user has turned that particular feature on/off).\n if (!$attrs.tabindex) {\n $element.attr('tabindex', '-1');\n }\n\n this.installPropertyInterceptors();\n this.attachChangeListeners();\n this.attachInteractionListeners();\n\n var self = this;\n $scope.$on('$destroy', function() {\n self.detachTimePane();\n });\n }\n\n /**\n * Sets up the controller's reference to ngModelController.\n * @param {!angular.NgModelController} ngModelCtrl\n */\n TimePickerCtrl.prototype.configureNgModel = function(ngModelCtrl) {\n this.ngModelCtrl = ngModelCtrl;\n\n var self = this;\n ngModelCtrl.$render = function() {\n var value = self.ngModelCtrl.$viewValue;\n\n if (value && !(value instanceof Date)) {\n throw Error('The ng-model for sg-timepicker must be a Date instance. ' +\n 'Currently the model is a: ' + (typeof value));\n }\n\n self.time = value;\n self.inputElement.value = self.dateLocale.formatTime(value);\n self.resizeInputElement();\n self.updateErrorState();\n };\n };\n\n /**\n * Attach event listeners for both the text input and the md-time.\n * Events are used instead of ng-model so that updates don't infinitely update the other\n * on a change. This should also be more performant than using a $watch.\n */\n TimePickerCtrl.prototype.attachChangeListeners = function() {\n var self = this;\n\n self.$scope.$on('sg-time-pane-change', function(event, data) {\n var time = new Date(data.date);\n self.ngModelCtrl.$setViewValue(time);\n self.time = time;\n self.inputElement.value = self.dateLocale.formatTime(time);\n if (data.changed == 'minutes') {\n self.closeTimePane();\n }\n self.resizeInputElement();\n self.inputContainer.classList.remove(INVALID_CLASS);\n });\n\n self.ngInputElement.on('input', angular.bind(self, self.resizeInputElement));\n self.ngInputElement.on('input', self.$mdUtil.debounce(self.handleInputEvent,\n DEFAULT_DEBOUNCE_INTERVAL, self));\n };\n\n /** Attach event listeners for user interaction. */\n TimePickerCtrl.prototype.attachInteractionListeners = function() {\n var self = this;\n var $scope = this.$scope;\n var keyCodes = this.$mdConstant.KEY_CODE;\n\n // Add event listener through angular so that we can triggerHandler in unit tests.\n self.ngInputElement.on('keydown', function(event) {\n if (event.altKey && event.keyCode == keyCodes.DOWN_ARROW) {\n self.openTimePane(event);\n $scope.$digest();\n }\n });\n\n $scope.$on('md-time-close', function() {\n self.closeTimePane();\n });\n };\n\n /**\n * Capture properties set to the time-picker and imperitively handle internal changes.\n * This is done to avoid setting up additional $watches.\n */\n TimePickerCtrl.prototype.installPropertyInterceptors = function() {\n var self = this;\n\n if (this.$attrs.ngDisabled) {\n // The expression is to be evaluated against the directive element's scope and not\n // the directive's isolate scope.\n var scope = this.$mdUtil.validateScope(this.$element) ? this.$element.scope() : null;\n if (scope) {\n scope.$watch(this.$attrs.ngDisabled, function(isDisabled) {\n self.setDisabled(isDisabled);\n });\n }\n }\n\n Object.defineProperty(this, 'placeholder', {\n get: function() { return self.inputElement.placeholder; },\n set: function(value) { self.inputElement.placeholder = value || ''; }\n });\n };\n\n /**\n * Sets whether the date-picker is disabled.\n * @param {boolean} isDisabled\n */\n TimePickerCtrl.prototype.setDisabled = function(isDisabled) {\n this.isDisabled = isDisabled;\n this.inputElement.disabled = isDisabled;\n this.timeButton.disabled = isDisabled;\n };\n\n /**\n * Sets the custom ngModel.$error flags to be consumed by ngMessages. Flags are:\n * - mindate: whether the selected date is before the minimum date.\n * - maxdate: whether the selected flag is after the maximum date.\n * - filtered: whether the selected date is allowed by the custom filtering function.\n * - valid: whether the entered text input is a valid date\n *\n * The 'required' flag is handled automatically by ngModel.\n *\n * @param {Date=} opt_date Date to check. If not given, defaults to the datepicker's model value.\n */\n TimePickerCtrl.prototype.updateErrorState = function(opt_date) {\n var date = opt_date || this.date;\n\n // Clear any existing errors to get rid of anything that's no longer relevant.\n this.clearErrorState();\n\n if (!this.dateUtil.isValidDate(date)) {\n // The date is seen as \"not a valid date\" if there is *something* set\n // (i.e.., not null or undefined), but that something isn't a valid date.\n this.ngModelCtrl.$setValidity('valid', date === null);\n }\n\n // TODO(jelbourn): Change this to classList.toggle when we stop using PhantomJS in unit tests\n // because it doesn't conform to the DOMTokenList spec.\n // See https://github.com/ariya/phantomjs/issues/12782.\n if (!this.ngModelCtrl.$valid) {\n this.inputContainer.classList.add(INVALID_CLASS);\n }\n };\n\n /** Clears any error flags set by `updateErrorState`. */\n TimePickerCtrl.prototype.clearErrorState = function() {\n this.inputContainer.classList.remove(INVALID_CLASS);\n ['valid'].forEach(function(field) {\n this.ngModelCtrl.$setValidity(field, true);\n }, this);\n };\n\n /**\n * Resizes the input element based on the size of its content.\n */\n TimePickerCtrl.prototype.resizeInputElement = function() {\n this.inputElement.size = this.inputElement.value.length + EXTRA_INPUT_SIZE;\n };\n\n /**\n * Sets the model value if the user input is a valid time.\n * Adds an invalid class to the input element if not.\n */\n TimePickerCtrl.prototype.handleInputEvent = function(self) {\n var inputString = this.inputElement.value;\n var arr = inputString.split(/[\\.:]/);\n\n if (inputString === '') {\n this.ngModelCtrl.$setViewValue(null);\n this.time = null;\n this.inputContainer.classList.remove(INVALID_CLASS);\n }\n else if (arr.length < 2) {\n this.inputContainer.classList.toggle(INVALID_CLASS, inputString);\n }\n else {\n var h = Number(arr[0]);\n var m = Number(arr[1]);\n var newVal = new Date(this.time);\n if (h && h >= 0 && h <= 23 && m && m >= 0 && m <= 59 && angular.isDate(newVal)) {\n newVal.setHours(h);\n newVal.setMinutes(m);\n this.ngModelCtrl.$setViewValue(newVal);\n this.time = newVal;\n this.inputContainer.classList.remove(INVALID_CLASS);\n }\n else {\n this.inputContainer.classList.toggle(INVALID_CLASS, inputString);\n }\n }\n };\n\n /** Position and attach the floating calendar to the document. */\n TimePickerCtrl.prototype.attachTimePane = function() {\n var timePane = this.timePane;\n this.$element.addClass('sg-timepicker-open');\n this.$element.find('button').addClass('md-primary');\n\n var elementRect = this.inputContainer.getBoundingClientRect();\n var bodyRect = document.body.getBoundingClientRect();\n\n // Check to see if the calendar pane would go off the screen. If so, adjust position\n // accordingly to keep it within the viewport.\n var paneTop = elementRect.top - bodyRect.top;\n var paneLeft = elementRect.left - bodyRect.left;\n\n // If the right edge of the pane would be off the screen and shifting it left by the\n // difference would not go past the left edge of the screen.\n var paneWidth = this.$mdMedia('sm')? TIME_PANE_WIDTH.SM : TIME_PANE_WIDTH.GTSM;\n if (paneLeft + paneWidth > bodyRect.right &&\n bodyRect.right - paneWidth > 0) {\n paneLeft = bodyRect.right - paneWidth;\n timePane.classList.add('sg-timepicker-pos-adjusted');\n }\n timePane.style.left = paneLeft + 'px';\n\n // If the bottom edge of the pane would be off the screen and shifting it up by the\n // difference would not go past the top edge of the screen.\n var min = (typeof this.time == 'object' && this.time.getMinutes() % 5 === 0)? 'MIN5' : 'MIN1';\n var paneHeight = this.$mdMedia('sm')? TIME_PANE_HEIGHT[min].SM : TIME_PANE_HEIGHT[min].GTSM;\n if (paneTop + paneHeight > bodyRect.bottom &&\n bodyRect.bottom - paneHeight > 0) {\n paneTop = bodyRect.bottom - paneHeight;\n timePane.classList.add('sg-timepicker-pos-adjusted');\n }\n\n timePane.style.top = paneTop + 'px';\n document.body.appendChild(timePane);\n\n // The top of the calendar pane is a transparent box that shows the text input underneath.\n // Since the pane is floating, though, the page underneath the pane *adjacent* to the input is\n // also shown unless we cover it up. The inputMask does this by filling up the remaining space\n // based on the width of the input.\n this.inputMask.style.left = elementRect.width + 'px';\n\n // Add CSS class after one frame to trigger open animation.\n this.$$rAF(function() {\n timePane.classList.add('md-pane-open');\n });\n };\n\n /** Detach the floating time pane from the document. */\n TimePickerCtrl.prototype.detachTimePane = function() {\n this.$element.removeClass('sg-timepicker-open');\n this.$element.find('button').removeClass('md-primary');\n this.timePane.classList.remove('md-pane-open');\n this.timePane.classList.remove('md-timepicker-pos-adjusted');\n\n if (this.timePane.parentNode) {\n // Use native DOM removal because we do not want any of the angular state of this element\n // to be disposed.\n this.timePane.parentNode.removeChild(this.timePane);\n }\n };\n\n /**\n * Open the floating time pane.\n * @param {Event} event\n */\n TimePickerCtrl.prototype.openTimePane = function(event) {\n if (!this.isTimeOpen && !this.isDisabled) {\n this.isTimeOpen = true;\n this.timePaneOpenedFrom = event.target;\n this.attachTimePane();\n //this.focusTime();\n\n // Because the time pane is attached directly to the body, it is possible that the\n // rest of the component (input, etc) is in a different scrolling container, such as\n // an md-content. This means that, if the container is scrolled, the pane would remain\n // stationary. To remedy this, we disable scrolling while the time pane is open, which\n // also matches the native behavior for things like `