sogo/UI/WebServerResources/js/Common.js.map
2017-03-24 09:43:51 -04:00

1 line
282 KiB
Plaintext

{"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/last.filter.js","Common/ln2br.filter.js","Common/loc.filter.js","Common/range.filter.js","Common/stripTags.filter.js","Common/url.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/sgFocus.service.js","Common/sgHotkeys.service.js","Common/User.service.js","Common/sgAvatarImage.directive.js","Common/sgCheckmark.directive.js","Common/sgColorPicker.directive.js","Common/sgCompile.directive.js","Common/sgDatepickerReadonlyInput.directive.js","Common/sgDraggable.directive.js","Common/sgDroppable.directive.js","Common/sgEnter.directive.js","Common/sgEscape.directive.js","Common/sgFocus.directive.js","Common/sgFolderStylesheet.directive.js","Common/sgPlaceholder.directive.js","Common/sgResetOnDisabled.directive.js","Common/sgRippleClick.directive.js","Common/sgSearch.directive.js","Common/sgSelectOnly.directive.js","Common/sgSubscribe.directive.js","Common/sgTimepicker.directive.js","Common/sgToggleGrid.directive.js","Common/sgVariableScrollShrink.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","$mdAriaProvider","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","DebugEnabled","debugEnabled","debugInfoEnabled","disableWarnings","generateThemesOnDemand","interceptors","push","AuthInterceptor","$window","$q","response","test","config","headers","Accept","data","location","reload","reject","ErrorInterceptor","$rootScope","$injector","responseError","rejection","deferred","iframe","status","defer","angular","element","UserFolderURL","on","$http","get","then","resolve","remove","document","body","appendChild","promise","$broadcast","module","isPopup","classList","contains","baseURL","ApplicationBaseURL","resourcesURL","ResourcesURL","activeUser","param","settings","login","UserLogin","identification","UserIdentification","email","UserEmail","language","UserLanguage","folderURL","isSuperUser","IsSuperUser","path","calendar","UserCalendarPath","contacts","UserContactsPath","mail","UserMailPath","preferences","UserPreferencesPath","administration","UserAdministrationPath","help","HelpURL","logoff","UserLogoffPath","minimumSearchLength","isNumber","constant","selection","xs","gt-xs","sm","gt-sm","md","gt-md","lg","gt-lg","xl","print","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","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","tree","find","attr","trustAs","html","last","a","_","ln2br","text","String","undefined","loc","range","n","res","stripTags","url","indexOf","AclController","$timeout","$mdDialog","Dialog","usersWithACL","User","folder","userFilter","$query","$filter","$acl","users","closeModal","$resetUsersRights","hide","saveModal","$saveUsersRights","alert","confirmChange","user","confirmation","$confirmRights","vm","showing","message","removeUser","$removeUser","uid","addUser","$addUser","userToAdd","searchText","selectedUid","selectUser","selectAllRights","$selectAllRights","$event","target","parentNode","selectedUser","inactive","$rights","showRights","this","controller","navController","$scope","$interval","$mdSidenav","$mdToast","$mdMedia","sgConstant","sgSettings","Resource","Alarm","leftIsClose","isOpen","onHttpError","event","isString","statusText","show","template","hideDelay","position","debug","resource","centerIsClose","currentDay","window","secondsBeforeTomorrow","toggleLeft","isGtMedium","triggerHandler","toggle","toggleRight","toggleCenter","options","save","post","state","$watch","newVal","$on","getAlarms","Acl","folderId","Settings","extend","$$resource","$User","prototype","$users","owner","_this","acls","isDefined","userResource","fetch","canSubscribeUser","isSubscribed","wasSubscribed","bind","map","userClass","isGroup","$shadowRights","splice","rights","right","$resetRights","deferredSave","deferredSubscribe","action","$rightsAreDirty","$omit","copy","uids","all","currentAlarm","AlarmService","$toast","now","Date","browserTime","floor","getTime","alarms","sort","x","y","next","pop","utc","alarmTime","delay","f","showAlarm","cancel","AlarmController","scope","summary","reminder","close","snooze","locals","Authentication","redirectUrl","username","domain","userName","address","baseAddress","altBaseAddress","parts","hostpart","protocol","newAddress","href","split","startsWith","endsWith","getService","$cookies","passwordPolicyConfig","readLoginCookie","loginValues","cookie","base64decode","service","d","password","rememberLogin","loginSuffix","method","loginCookie","expire","grace","cn","msg","perr","LDAPPasswordPolicyError","PolicyNoError","PolicyAccountLocked","error","changePassword","newPassword","xsrfCookie","X-XSRF-TOKEN","PolicyPasswordModNotAllowed","PolicyInsufficientPasswordQuality","PolicyPasswordTooShort","PolicyPasswordTooYoung","PolicyPasswordInHistory","formatted","PolicyPasswordUnknown","PolicyPasswordSystemUnknown","put","$get","PolicyPasswordChangeUnsupported","PolicyPasswordExpired","PolicyChangeAfterReset","PolicyMustSupplyOldPassword","provider","DialogService","$modal","content","htmlContent","ok","confirm","prompt","label","PromptDialogController","o","id","asCSSIdentifier","parent","clickOutsideToClose","escapeToClose","inputType","Gravatar","size","alternate_avatar","hash","s","md5","no_404","_http","_q","_path","_activeUser","$factory","compact","escape","Array","apply","slice","call","params","flatten","newguid","create","newValue","download","getFileNameFromHeader","header","trim","type","accept","responseType","cache","transformResponse","fileName","blob","Error","Blob","filename","saveAs","sgFocus","$sgHotkeys","wrapWithApply","fn","$apply","HotKey","description","callback","preventInClass","onKeyUp","lkey","clone","Hotkeys","_hotkeys","_hotkeysUp","_preventIn","_preventInClass","_onKeydown","_onKeyup","_onKeypress","initialize","registerHotkey","createHotkey","_toggleCheatSheet","addEventListener","_invokeHotkeyHandlers","keyString","hotkeys","hotkey","srcElement","nodeName","toUpperCase","includes","intersection","e","console","keyStringFromEvent","charCode","keyCode","which","CHAR_CODES","KEY_CODES","fromCharCode","ctrlKey","altKey","shiftKey","metaKey","uniq","_deregisterHotkey","ret","table","callbackArray","callbackData","deregisterHotkey","_validateHotkey","isArray","TypeError","_registerKey","_registerKeys","registerHotkeyUp","match","eventHotkey","Boolean","CheatSheetController","closeDialog","_cheatSheet","finally","8","9","13","16","17","18","19","20","27","32","33","34","35","36","37","38","39","40","45","46","96","97","98","99","101","102","103","104","105","106","107","109","110","111","112","113","114","115","116","117","118","119","120","121","122","123","42","63","sgHotkeys","userData","init","search","excludedUsers","dry","when","results","compareUids","isUndefined","$$shortFormat","$shortFormat","$$image","image","$avatarIcon","$isGroup","$isSpecial","empty","$fullname","fullname","c_email","no_email","$isAnonymous","$confirmation","some","values","constructor","isEqual","zero","keys","$folders","$$folders","folders","sgAvatarImage","$parse","link","attrs","deregisterWatcher","imgElement","mdIcons","mdIconElement","mdBadgeElement","css","ngDisabled","isDisabled","disabled","display","img","genericImg","restrict","bindToController","src","transclude","controllerAs","sgAvatarImageController","$element","Preferences","getGravatar","defaults","SOGoAlternateAvatar","urlEmail","hideGenericAvatar","showGenericAvatar","addClass","removeClass","configureZoomableAvatar","toggleZoomFcn","toggleClass","off","ready","old","SOGoGravatarEnabled","attributes","directive","sgCheckmarkDirective","$mdAria","$mdTheming","$mdUtil","compile","tElement","tAttrs","hasAttribute","stopImmediatePropagation","ngModelCtrl","parseConstantExpr","expression","fallback","parseFn","listener","ev","viewValue","$viewValue","trueValue","falseValue","$setViewValue","$render","render","CHECKED_CSS","sgTrueValue","sgFalseValue","fakeNgModel","expectWithText","require","sgColorPicker","iElement","iAttr","ngModelController","sgColor","sgIconColor","sgColorPickerController","sgColors","setColor","currentTarget","parentElement","children","tile","add","sgCompile","$compile","sgCompileLink","ensureCompileRunsOnce","$eval","contents","sgDatepickerReadonlyInput","postLink","datepickerCtrl","getInput","eq","input","prop","sgDraggable","sgDraggableObject","dragStart","count","helper","bindedOnDragDetect","onDragDetect","bindedOnDrag","onDrag","sgDragStart","sgDragCount","$destroy","dragHasStarted","getDistanceFromStart","delta","startPosition","clientX","clientY","sqrt","stopPropagation","one","onDragEnd","counter","$emit","top","pageY","left","pageX","sgDroppable","onEnter","overElement","onLeave","dropAction","droppable","deregisterFolderDragStart","deregisterFolderDragEnd","sgDrop","dragFolder","mode","dragMode","sgEnter","ENTER_KEY","preventDefault","sgEscape","ESCAPE_KEY","elem","sgFocusOn","focus","select","sgFolderStylesheet","sgFolderStylesheetController","transparent","ratio","ngModel","sgPlaceholder","placeholder","sgResetOnDisabled","$invalid","date","sgRippleClick","coordinates","getBoundingClientRect","container","overflow","scrollTop","ripple","offsetTop","offsetLeft","height","width","containerId","sgSearchPreTransclude","tAttr","inputEl","selectEl","buttonEl","removeAttr","compiledButtonEl","formName","inputName","allowDot","doSearch","cancelSearch","priority","sgSearch","append","sgSearchController","searchTextOptions","updateOn","debounce","blur","onChange","form","rawSearchText","$valid","$setValidity","searchField","sgSelectOnly","autoComplete","selectedItem","$applyAsync","sgSubscribe","folderType","onFolderSelect","sgSubscribeDialogController","showDialog","templateUrl","sgSubscribeController","$setTouched","selectFolder","folderData","timePaneDirective","TimePaneCtrl","controllers","sgTimePaneCtrl","mdInputContainer","configureNgModel","$$mdDateUtil","$mdConstant","$$rAF","$attrs","$mdDateLocale","dateUtil","KEY_CODE","timePaneElement","SELECTED_TIME_CLASS","FOCUSED_TIME_CLASS","nextUniqueId","displayTime","selectedTime","isInitialized","hours","displayName","selected","min5","min1","ii","show5min","getToggleBtnLbl","is5min","toggleManual5min","manual5min","tabindex","self","hourClickHandler","displayVal","updated","setHours","Number","setNgModelValue","minuteClickHandler","setMinutes","boundKeyHandler","handleKeyEvent","nextTick","changeSelectedTime","previousSelectedTime","prevH","getHours","prevHCell","getElementById","setAttribute","prevM","getMinutes","prevMCell","prevM5Cell","mCell","newH","hCell","newM","changed","ESCAPE","TAB","ENTER","opt_date","today","previousFocus","timePickerDirective","ariaLabelValue","ariaLabel","mdPlaceholder","TimePickerCtrl","mdTimePickerCtrl","parentForm","parseAttributeBoolean","mdNoAsterisk","parentSubmittedWatcher","$submitted","isSubmitted","updateErrorState","dateLocale","documentElement","inputElement","ngInputElement","inputContainer","timePane","timeButton","inputMask","isFocused","setDisabled","isTimeOpen","timePaneOpenedFrom","timePaneId","nextUid","bodyClickHandler","handleBodyClick","windowEventName","IS_MOBILE_REGEX","navigator","userAgent","vendor","opera","windowEventHandler","closeTimePane","windowBlurHandler","handleWindowBlur","leftMargin","topMargin","$set","installPropertyInterceptors","attachChangeListeners","attachInteractionListeners","detachTimePane","EXTRA_INPUT_SIZE","INVALID_CLASS","OPEN_CLASS","DEFAULT_DEBOUNCE_INTERVAL","TIME_PANE_HEIGHT","MIN5","GTXS","XS","MIN1","TIME_PANE_WIDTH","$formatters","time","formatTime","resizeInputElement","$viewChangeListeners","unshift","debounceInterval","handleInputEvent","keyCodes","DOWN_ARROW","openTimePane","$digest","$parent","Object","defineProperty","set","clearErrorState","isValidDate","field","inputString","parsedTime","parseTime","isValidInput","attachTimePane","transform","elementRect","bodyRect","paneTop","paneLeft","viewportTop","viewportLeft","scrollLeft","viewportBottom","innerHeight","viewportRight","innerWidth","paneWidth","scale","min","paneHeight","enableScrolling","removeChild","disableScrollAround","evalAttr","removeEventListener","getTimePaneCtrl","focusTime","ctrl","setFocused","isInTime","getClosest","inputFocusedOnWindowBlur","activeElement","sgToggleGrid","$mdColors","flattenedDays","modelDays","sgToggleGridAttr","modelAttr","tiles","$validate","setInvalid","invalid","tagName","getThemeColor","day","findIndex","$setDirty","$isEmpty","sgVariableScrollShrink","suffix","pattern","lastIndexOf","_base64_keyStr","base64encode","chr1","chr2","chr3","enc1","enc2","enc3","enc4","output","utf8encode","charCodeAt","charAt","L","k","K","G","I","F","H","q","p","u","aa","Z","D","t","B","J","P","h","E","v","Y","X","W","V","C","S","Q","N","M","A","z","w","U","T","R","O","capitalize","asDate","newDate","newString","isValidEmail","emailRE","characters","escapeds","re","RegExp","timeInterval","interval","parseDate","localeProvider","format","string","formattingTokens","tokens","token","regexes","parsedInput","matchesCount","year","getYear","month","getMonth","getDate","hour","minute","%d","%e","%m","%b","shortMonths","toLower","%B","months","%y","nearFuture","getFullYear","%Y","%H","%I","%M","%p","linput","am","pm","NaN","daysUpTo","otherDate","days","day1","day2","tmp","nbrDays","round","setTime","minutesTo","dstOffset","valueOf","getTimezoneOffset","stringWithSeparator","separator","str","addDays","initialDate","milliSeconds","addHours","nbrHours","addMinutes","nbrMinutes","beginOfDay","setSeconds","setMilliseconds","dayOfWeek","offset","baseDayOfWeek","firstDayOfWeek","getDay","firstWeekOfYearForDate","firstWeekRule","januaryFirst","firstWeek","firstWeekOfYear","setMonth","setDate","beginOfWeek","getWeek","previousWeek","weekNumber","endOfWeek","getDayString","getHourString","separators","max","validParts","%a","shortDays","%A","%U","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<<d)|(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<F){Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=(aa[Z]|(G.charCodeAt(H)<<d));H++;}Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=aa[Z]|(128<<d);aa[I-2]=F<<3;aa[I-1]=F>>>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;F<k.length;F++){var x=k.charCodeAt(F);if(x<128){d+=String.fromCharCode(x);}else{if((x>127)&&(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<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g);}var i=B(Y)+B(X)+B(W)+B(V);return i.toLowerCase();};\n return md5(this.toLowerCase());\n};\n\nString.prototype.capitalize = function() {\n return this.charAt(0).toUpperCase() + this.slice(1);\n};\n\nString.prototype.asDate = function () {\n var newDate;\n var date = this.split(\"/\");\n if (date.length == 3)\n newDate = new Date(date[2], date[1] - 1, date[0]); // dd/mm/yyyy\n else {\n date = this.split(\"-\");\n if (date.length == 3)\n newDate = new Date(date[0], date[1] - 1, date[2]); // yyyy-mm-dd\n else {\n if (this.length == 8) {\n newDate = new Date(this.substring(0, 4),\n this.substring(4, 6) - 1,\n this.substring(6, 8)); // yyyymmdd\n }\n }\n }\n\n return newDate;\n};\n\nString.prototype.formatted = function() {\n var newString = this;\n\n for (var i = 0; i < arguments.length; i++) {\n newString = newString.replace(\"%{\" + i + \"}\", arguments[i], \"g\");\n }\n\n return newString;\n};\n\nString.prototype.isValidEmail = function() {\n var emailRE = /^([\\w\\!\\#$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\`{\\|\\}\\~]+\\.)*[\\w\\!\\#$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\`{\\|\\}\\~]+@((((([a-z0-9]{1}[a-z0-9\\-]{0,62}[a-z0-9]{1})|[a-z])\\.)+[a-z]{2,})|(\\d{1,3}\\.){3}\\d{1,3}(\\:\\d{1,5})?)$/i;\n return emailRE.test(this);\n};\n\nString.prototype.asCSSIdentifier = function() {\n var characters = [ '_' , '\\\\.', '#' , '@' , '\\\\*', ':' , ',' , ' ', \"'\", '&', '\\\\+' ];\n var escapeds = [ '_U_', '_D_', '_H_', '_A_', '_S_', '_C_', '_CO_', '_SP_', '_SQ_', '_AM_', '_P_' ];\n\n var newString = this;\n for (var i = 0; i < characters.length; i++) {\n var re = new RegExp(characters[i], 'g');\n newString = newString.replace(re, escapeds[i]);\n }\n\n if (/^\\d+/.test(newString)) {\n newString = '_' + newString;\n }\n\n return newString;\n};\n\nString.prototype.timeInterval = function () {\n var interval;\n if (this == \"once_per_hour\")\n interval = 3600;\n else if (this == \"every_minute\")\n interval = 60;\n else {\n interval = parseInt(this.substr(6)) * 60;\n }\n\n return interval;\n};\n\nString.prototype.parseDate = function(localeProvider, format) {\n var string, formattingTokens, tokens, token, now, date, regexes, i, parsedInput, matchesCount;\n\n string = '' + this;\n formattingTokens = /%[dembByYHIMp]/g;\n now = new Date();\n date = {\n year: now.getYear() + 1900,\n month: now.getMonth(),\n day: now.getDate(),\n hour: 0,\n minute: 0\n };\n regexes = {\n '%d': [/\\d\\d/, function(input) {\n date.day = parseInt(input);\n return (date.day < 32);\n }],\n '%e': [/ ?\\d?\\d/, function(input) {\n date.day = parseInt(input);\n return (date.day < 32);\n }],\n '%m': [/\\d\\d/, function(input) {\n date.month = parseInt(input) - 1;\n return (date.month < 12);\n }],\n '%b': [/[^\\d\\s\\.\\/\\-]{2,}/, function(input) {\n var i = _.indexOf(_.map(localeProvider.shortMonths, _.toLower), _.toLower(input));\n if (i >= 0)\n date.month = i;\n return (i >= 0);\n }],\n '%B': [/[^\\d\\s\\.\\/\\-]{2,}/, function(input) {\n var i = _.indexOf(_.map(localeProvider.months, _.toLower), _.toLower(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 '%H': [/\\d{1,2}/, function(input) {\n date.hour = parseInt(input);\n return (date.hour < 24);\n }],\n '%I': [/\\d{1,2}/, function(input) {\n date.hour = parseInt(input);\n return (date.hour <= 12);\n }],\n '%M': [/[0-5]\\d/, function(input) {\n date.minute = parseInt(input);\n return (date.minute < 60 );\n }],\n '%p': [/[^\\d\\s\\/\\-]+/, function(input) {\n var linput = _.toLower(input), am = _.toLower(l('AM')), pm = _.toLower(l('PM'));\n if (linput == pm)\n date.hour += 12;\n return (linput == am || linput == pm);\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, date.hour, date.minute);\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 return this;\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\n/**\n * See [SOGoUser dayOfWeekForDate:]\n */\nDate.prototype.dayOfWeek = function(localeProvider) {\n var offset, baseDayOfWeek, dayOfWeek;\n\n offset = localeProvider.firstDayOfWeek;\n baseDayOfWeek = this.getDay();\n if (offset > baseDayOfWeek)\n baseDayOfWeek += 7;\n\n dayOfWeek = baseDayOfWeek - offset;\n\n return dayOfWeek;\n};\n\n/**\n * See [SOGoUser firstWeekOfYearForDate:]\n */\nDate.prototype.firstWeekOfYearForDate = function(localeProvider) {\n var firstWeekRule, dayOfWeek, januaryFirst, firstWeek;\n\n firstWeekRule = localeProvider.firstWeekOfYear;\n\n januaryFirst = new Date(this.getTime());\n januaryFirst.setMonth(0);\n januaryFirst.setDate(1);\n dayOfWeek = januaryFirst.dayOfWeek(localeProvider);\n\n if (firstWeekRule == 'First4DayWeek') {\n if (dayOfWeek < 4)\n firstWeek = januaryFirst.beginOfWeek(localeProvider.firstDayOfWeek);\n else\n firstWeek = januaryFirst.addDays(7).beginOfWeek(localeProvider.firstDayOfWeek);\n }\n else if (firstWeekRule == 'FirstFullWeek') {\n if (dayOfWeek === 0)\n firstWeek = januaryFirst.beginOfWeek(localeProvider.firstDayOfWeek);\n else\n firstWeek = januaryFirst.addDays(7).beginOfWeek(localeProvider.firstDayOfWeek);\n }\n else {\n firstWeek = januaryFirst.beginOfWeek(localeProvider.firstDayOfWeek);\n }\n\n return firstWeek;\n};\n\n/**\n * See [SOGoUser weekNumberForDate:]\n */\nDate.prototype.getWeek = function(localeProvider) {\n var firstWeek, previousWeek, weekNumber, clone;\n\n clone = new Date(this.getTime());\n clone.addDays(6);\n firstWeek = clone.firstWeekOfYearForDate(localeProvider);\n if (firstWeek.getTime() < clone.getTime()) {\n weekNumber = 1 + Math.floor((clone.getTime() - firstWeek.getTime()) / (86400000 * 7));\n }\n else\n {\n // Date is within the last week of the previous year;\n // Compute the previous week number to find the week number of the requested date.\n // The number will either be 52 or 53.\n previousWeek = new Date(clone.getTime());\n previousWeek.addDays(-7);\n firstWeek = previousWeek.firstWeekOfYearForDate(localeProvider);\n weekNumber = 2 + Math.floor((previousWeek.getTime() - firstWeek.getTime()) / (86400000 * 7));\n }\n\n return weekNumber;\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 = /%[deaAmbByYUHIMp]/g,\n val = {\n '%d': this.getDate(), // day of month (e.g., 01)\n '%e': this.getDate(), // day of month, space padded\n '%a': localeProvider.shortDays[this.getDay()], // locale's abbreviated weekday name (e.g., Sun)\n '%A': localeProvider.days[this.getDay()], // locale's full weekday name (e.g., Sunday)\n '%m': this.getMonth() + 1, // month (01..12)\n '%b': localeProvider.shortMonths[this.getMonth()], // locale's abbreviated month name (e.g., Jan)\n '%B': localeProvider.months[this.getMonth()], // locale's full month name (e.g., January)\n '%y': this.getFullYear().toString().substring(2), // last two digits of year (00..99)\n '%Y': this.getFullYear(), // year\n '%U': this.getWeek(localeProvider), // week of the 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 resourcesURL: function() {\n return ResourcesURL || 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 help: HelpURL || null,\n logoff: UserLogoffPath || null\n }\n };\n if (param)\n return settings[param];\n else\n return settings;\n },\n minimumSearchLength: function() {\n return angular.isNumber(minimumSearchLength)? minimumSearchLength : 2;\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 // The following breakpoints match our CSS breakpoints in scss/core/variables.scss\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: 1023px)' ,\n 'gt-md' : '(min-width: 1024px)' ,\n 'lg' : '(min-width: 1024px) and (max-width: 1279px)',\n 'gt-lg' : '(min-width: 1280px)' ,\n 'xl' : '(min-width: 1920px)' ,\n 'print' : 'print'\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', '$mdAriaProvider'];\n function configure($logProvider, $compileProvider, $httpProvider, $mdThemingProvider, $mdAriaProvider) {\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': 'fafafa', // assigned to md-hue-1, equivalent to grey-50 (default background palette)\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', // grey-50\n 'hue-2': '300',\n 'hue-3': 'A700'\n });\n\n if (!DebugEnabled) {\n // Disable debugging information\n $logProvider.debugEnabled(false);\n $compileProvider.debugInfoEnabled(false);\n // Disable warnings\n $mdAriaProvider.disableWarnings();\n // Disable theme generation but keep definition in config (required by mdColors)\n $mdThemingProvider.generateThemesOnDemand(true);\n // Disable theming completely\n //$mdThemingProvider.disableTheming();\n }\n\n $httpProvider.interceptors.push('AuthInterceptor');\n $httpProvider.interceptors.push('ErrorInterceptor');\n }\n\n /**\n * @ngInject\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 /^[\\n\\r ]*<!DOCTYPE html>/.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', '$injector'];\n function ErrorInterceptor($rootScope, $q, $injector) {\n return {\n responseError: function(rejection) {\n var deferred, iframe;\n if (/^application\\/json/.test(rejection.config.headers.Accept)) {\n // Handle CAS ticket renewal (TODO: add check on usesCASAuthentication)\n if (rejection.status == -1) {\n deferred = $q.defer();\n iframe = angular.element('<iframe class=\"ng-hide\" src=\"' + UserFolderURL + 'recover\"></iframe>');\n iframe.on('load', function() {\n // Once the browser has followed the redirection, send the initial request\n var $http = $injector.get('$http');\n $http(rejection.config).then(deferred.resolve, deferred.reject);\n iframe.remove();\n });\n document.body.appendChild(iframe[0]);\n return deferred.promise;\n }\n else {\n // Broadcast the response error\n $rootScope.$broadcast('http:Error', rejection);\n }\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}} !important; }'),\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(_.map(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 <div ng-bind-html=\"part.content | ensureTarget\"><!-- msg --></div>\n */\n ensureTarget.$inject = ['$sce'];\n function ensureTarget($sce) {\n return function(element) {\n var tree = angular.element('<div>' + element + '</div>');\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 * 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 last() {\n return function(a) {\n return _.last(a);\n };\n }\n\n angular.module('SOGo.Common')\n .filter('last', last);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n/**\n * ln2br - A filter to convert line feeds and carriage returns to html line breaks\n * @memberof SOGo.Common\n */\n(function () {\n 'use strict';\n\n /**\n * @ngInject\n */\n function ln2br() {\n return function(text) {\n return text ? String(text).replace(/\\r?\\n/gm, '<br>') : undefined;\n };\n }\n\n angular.module('SOGo.Common')\n .filter('ln2br', ln2br);\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/**\n * stripTags - A dumb filter to remove HTML tags from a string.\n * @memberof SOGo.Common\n */\n(function () {\n 'use strict';\n\n /**\n * @ngInject\n */\n function stripTags() {\n return function(text) {\n return text ? String(text).replace(/<[^>]+>/gm, '') : '';\n };\n }\n\n angular.module('SOGo.Common')\n .filter('stripTags', stripTags);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n/**\n * url - A simple filter to ensure a string to be a URL.\n * @memberof SOGo.Common\n */\n(function () {\n 'use strict';\n\n /**\n * @ngInject\n */\n function url() {\n return function(url) {\n return url.indexOf('://') < 0 ? 'http://' + url : url;\n };\n }\n\n angular.module('SOGo.Common')\n .filter('url', url);\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 = ['$timeout', '$mdDialog', 'Dialog', 'usersWithACL', 'User', 'folder'];\n function AclController($timeout, $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.selectAllRights = selectAllRights;\n vm.selectUser = selectUser;\n vm.showRights = showRights;\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 $timeout(function() {\n folder.$acl.$removeUser(user.uid);\n }, 500); // wait for CSS transition to complete (see card.scss)\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 });\n }\n }\n\n function selectAllRights(user) {\n folder.$acl.$selectAllRights(user);\n }\n\n function selectUser(user, $event) {\n if ($event && $event.target.parentNode.classList.contains('md-secondary'))\n return false;\n if (vm.selectedUid == user.uid) {\n vm.selectedUid = null;\n }\n else {\n vm.selectedUid = user.uid;\n vm.selectedUser = user;\n if (!user.inactive)\n vm.selectedUser.$rights();\n }\n }\n\n function showRights(user) {\n return vm.selectedUid == user.uid && !user.inactive;\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', '$window', '$mdSidenav', '$mdToast', '$mdMedia', '$log', 'sgConstant', 'sgSettings', 'Resource', 'Alarm'];\n function navController($rootScope, $scope, $timeout, $interval, $http, $window, $mdSidenav, $mdToast, $mdMedia, $log, sgConstant, sgSettings, Resource, Alarm) {\n var resource = new Resource(sgSettings.baseURL(), sgSettings.activeUser());\n\n $scope.isPopup = sgSettings.isPopup;\n $scope.activeUser = sgSettings.activeUser();\n $scope.baseURL = sgSettings.baseURL();\n $scope.leftIsClose = !$mdMedia(sgConstant['gt-md']);\n $scope.centerIsClose = !!$window.centerIsClose;\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 if ($scope.isGtMedium) {\n // Left sidenav is toggled while sidenav is locked open; bypass $mdSidenav\n $scope.leftIsClose = !$scope.leftIsClose;\n }\n else {\n $scope.leftIsClose = leftIsClose();\n // Fire a window resize when opening the sidenav on a small device.\n // This is a fix until the following issue is officially resolved:\n // https://github.com/angular/material/issues/7309\n if ($scope.leftIsClose)\n angular.element($window).triggerHandler('resize');\n $mdSidenav('left').toggle()\n .then(function () {\n $log.debug(\"toggle left is done\");\n });\n }\n };\n $scope.toggleRight = function() {\n $mdSidenav('right').toggle()\n .then(function () {\n $log.debug(\"toggle right is done\");\n });\n };\n $scope.toggleCenter = function(options) {\n $scope.centerIsClose = !$scope.centerIsClose;\n if (options && options.save)\n resource.post(null, 'saveListState', { state: $scope.centerIsClose? 'collapse' : 'rise' });\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-md']);\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 '<md-toast>',\n ' <div class=\"md-toast-content\">',\n ' <md-icon class=\"md-warn md-hue-1\">error_outline</md-icon>',\n ' <span flex>' + l(message) + '</span>',\n ' </div>',\n '</md-toast>'\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 if (sgSettings.activeUser('path').calendar) {\n // Fetch Calendar alarms\n Alarm.getAlarms();\n }\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(_.map(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, owner);\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, owner) {\n var _this = this,\n param = {uid: uid},\n acls;\n\n if (angular.isDefined(owner))\n acls = Acl.$$resource.userResource(owner).fetch(this.folderId, 'removeUserFromAcls', param);\n else\n acls = Acl.$$resource.fetch(this.folderId, 'removeUserFromAcls', param);\n\n return acls.then(function() {\n var i = _.indexOf(_.map(_this.users, 'uid'), uid);\n if (i >= 0) {\n _this.users[i].$shadowRights = null;\n _this.users.splice(i, 1);\n }\n });\n };\n\n /**\n * @function $selectAllRights\n * @memberof Acl.prototype\n * @desc Select all rights of an user\n */\n Acl.prototype.$selectAllRights = function(user) {\n _.forEach(user.rights, function(value, right) {\n if (angular.isNumber(user.rights[right]))\n user.rights[right] = 1;\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 '<md-toast>',\n ' <div class=\"md-toast-content\">',\n ' <div layout=\"column\" layout=\"start end\">',\n ' <p class=\"sg-padded--top\">{{ summary }}</p>',\n ' <div layout=\"row\" layout-align=\"start center\">',\n ' <md-input-container>',\n ' <label style=\"color: white\">{{ \"Snooze for \" | loc }}</label>',\n ' <md-select ng-model=\"reminder\">',\n ' <md-option value=\"5\">',\n l('5 minutes'),\n ' </md-option>',\n ' <md-option value=\"10\">',\n l('10 minutes'),\n ' </md-option>',\n ' <md-option value=\"15\">',\n l('15 minutes'),\n ' </md-option>',\n ' <md-option value=\"30\">',\n l('30 minutes'),\n ' </md-option>',\n ' <md-option value=\"45\">',\n l('45 minutes'),\n ' </md-option>',\n ' <md-option value=\"60\">',\n l('1 hour'),\n ' </md-option>',\n ' <md-option value=\"1440\">',\n l('1 day'),\n ' </md-option>',\n ' </md-select>',\n ' </md-input-container>',\n ' <md-button ng-click=\"snooze()\">',\n l('Snooze'),\n ' </md-button>',\n ' <md-button ng-click=\"close()\">',\n l('Close'),\n ' </md-button>',\n ' </div>',\n ' </div>',\n ' </div>',\n '</md-toast>'\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.summary = data.summary;\n scope.reminder = '10';\n scope.close = function() {\n $mdToast.hide();\n };\n scope.snooze = 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', ['ngCookies'])\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 .provider('Authentication', Authentication);\n\n function Authentication() {\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', '$cookies', 'passwordPolicyConfig'];\n function getService($q, $http, $cookies, passwordPolicyConfig) {\n var service;\n\n function readLoginCookie() {\n var loginValues = null,\n cookie = $cookies.get('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 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({ cn: data.cn, url: 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 xsrfCookie = $cookies.get('XSRF-TOKEN');\n\n $cookies.remove('XSRF-TOKEN', {path: '/SOGo/'});\n\n $http({\n method: 'POST',\n url: '/SOGo/so/changePassword',\n headers: {\n 'X-XSRF-TOKEN' : xsrfCookie\n },\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 // Restore the cookie\n $cookies.put('XSRF-TOKEN', xsrfCookie, {path: '/SOGo/'});\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 id = title.asCSSIdentifier(),\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 '<md-dialog flex=\"50\" flex-xs=\"90\">',\n ' <form name=\"' + id + 'Form\" ng-submit=\"ok()\">',\n ' <md-dialog-content class=\"md-dialog-content\" layout=\"column\">',\n ' <h2 class=\"md-title\" ng-bind=\"title\"></h2>',\n ' <md-input-container>',\n ' <label>' + label + '</label>',\n ' <input type=\"' + (o.inputType || 'text') + '\"',\n ' aria-label=\"' + title + '\"',\n ' ng-model=\"name\" md-autofocus=\"true\" required />',\n ' </md-input-container>',\n ' </md-dialog-content>',\n ' <md-dialog-actions>',\n ' <md-button ng-click=\"cancel()\">',\n ' ' + l('Cancel'),\n ' </md-button>',\n ' <md-button type=\"submit\" class=\"md-primary\" ng-disabled=\"' + id + 'Form.$invalid\">',\n ' ' + l('OK'),\n ' </md-button>',\n ' </md-dialog-actions>',\n ' </form>',\n '</md-dialog>'\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\n if (uid)\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 path\n * @memberof Resource.prototype\n * @desc Create a URL of the resource context with any number of additional segments\n * @return an absolute URL\n */\n Resource.prototype.path = function() {\n var path = [this._path];\n\n if (arguments.length > 0)\n Array.prototype.push.apply(path, Array.prototype.slice.call(arguments));\n\n return path.join('/');\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 }, deferred.reject);\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 action = (options && options.action)? options.action : 'save';\n\n return this.post(id, action, newValue);\n };\n\n /**\n * @function download\n * @memberof Resource.prototype\n * @desc Download a file from the server. Requires FileSaver.js.\n * @see {@link http://blog.davidjs.com/2015/07/download-files-via-post-request-in-angularjs/|Download files via POST request in AngularJs}\n * @see {@link https://github.com/eligrey/FileSaver.js|FileSaver.js}\n * @return a promise\n */\n Resource.prototype.download = function(id, action, data, options) {\n var deferred = this._q.defer(),\n type = (options && options.type)? options.type : 'application/zip',\n path = [this._path];\n if (id) path.push(id);\n if (action) path.push(action);\n path = _.compact(_.flatten(path)).join('/');\n\n function getFileNameFromHeader(header) {\n var result;\n\n if (!header) return null;\n result = header.split(\";\")[1].trim().split(\"=\")[1];\n\n return result.replace(/\"/g, '');\n }\n\n return this._http({\n method: 'POST',\n url: path,\n data: data,\n headers: {\n accept: type\n },\n responseType: 'arraybuffer',\n cache: false,\n transformResponse: function (data, headers, status) {\n var fileName, result, blob = null;\n\n if (status < 200 || status > 299) {\n throw new Error('Bad gateway');\n }\n if (data) {\n blob = new Blob([data], { type: type });\n }\n if (options && options.filename) {\n fileName = options.filename;\n }\n else {\n getFileNameFromHeader(headers('content-disposition'));\n }\n if (!saveAs) {\n throw new Error('To use Resource.download, FileSaver.js must be loaded.');\n }\n else {\n saveAs(blob, fileName);\n }\n }\n });\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","/* -*- 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: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */\n\n(function() {\n /* jshint validthis: true */\n 'use strict';\n\n /**\n * $sgHotkeys - A service to associate keyboard shortcuts to actions.\n * @memberof SOGo.Common\n *\n * @description\n * This service is a modified version of angular-hotkeys-light by Eugene Brodsky:\n * https://github.com/fupslot/angular-hotkeys-light\n */\n function $sgHotkeys() {\n\n // Key-code values for various meta-keys.\n // Source : http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes\n // http://unixpapa.com/js/key.html\n // Date: Oct 02, 2015.\n var KEY_CODES = {\n 8: 'backspace',\n 9: 'tab',\n 13: 'enter',\n 16: 'shift',\n 17: 'ctrl',\n 18: 'alt',\n 19: 'pause',\n 20: 'caps',\n 27: 'escape',\n 32: 'space',\n 33: 'pageup',\n 34: 'pagedown',\n 35: 'end',\n 36: 'home',\n 37: 'left',\n 38: 'up',\n 39: 'right',\n 40: 'down',\n 45: 'insert',\n 46: 'delete',\n // Numpad\n 96: '0',\n 97: '1',\n 98: '2',\n 99: '3',\n 100: '4',\n 101: '5',\n 102: '6',\n 103: '7',\n 104: '8',\n 105: '9',\n 106: '*',\n 107: '+',\n 109: '-',\n 110: '.',\n 111: '/',\n // Function keys\n 112: 'f1',\n 113: 'f2',\n 114: 'f3',\n 115: 'f4',\n 116: 'f5',\n 117: 'f6',\n 118: 'f7',\n 119: 'f8',\n 120: 'f9',\n 121: 'f10',\n 122: 'f11',\n 123: 'f12'\n };\n // Char-code values for characters that require a key combinations\n var CHAR_CODES = {\n 42: '*',\n 63: '?'\n };\n\n this.$get = getService;\n\n getService.$inject = ['$rootScope', '$window'];\n function getService($rootScope, $window) {\n\n var wrapWithApply = function (fn) {\n return function(event, args) {\n $rootScope.$apply(function() {\n fn.call(this, event, args);\n }.bind(this));\n };\n };\n\n var HotKey = function(params) {\n this.id = params.id || guid();\n this.key = params.key;\n this.description = params.description || null;\n this.context = params.context || null;\n this.callback = params.callback;\n this.preventInClass = params.preventInClass;\n this.args = params.args;\n this.onKeyUp = false;\n\n if (this.key.length > 1)\n // Automatically translate common hotkeys\n this.lkey = l('key_' + this.key);\n };\n\n HotKey.prototype.clone = function() {\n return new HotKey(this);\n };\n\n var Hotkeys = function() {\n /**\n * Sometimes a UI wants keybindings which are global, so called hotkeys.\n * Keys are keystrings (identify key combinations) and values are objects\n * with keys callback, context.\n */\n this._hotkeys = {};\n\n /**\n * Sometimes a UI wants keybindings for keyup behaviour.\n */\n this._hotkeysUp = {};\n\n /**\n * Keybindings are ignored by default when coming from a form input field.\n */\n this._preventIn = ['INPUT', 'SELECT', 'TEXTAREA', 'MD-OPTION'];\n\n /**\n * Keybindings are ignored by default when coming from special elements\n */\n this._preventInClass = ['md-chip-content'];\n\n this._onKeydown = this._onKeydown.bind(this);\n this._onKeyup = this._onKeyup.bind(this);\n this._onKeypress = this._onKeypress.bind(this);\n\n this.initialize();\n };\n\n /**\n * Binds Keydown, Keyup with the window object\n */\n Hotkeys.prototype.initialize = function() {\n this.registerHotkey(\n this.createHotkey({\n key: '?',\n description: l('Show or hide this help'),\n callback: this._toggleCheatSheet.bind(this)\n })\n );\n\n $window.addEventListener('keydown', this._onKeydown, true);\n $window.addEventListener('keyup', this._onKeyup, true);\n $window.addEventListener('keypress', this._onKeypress, true);\n };\n\n /**\n * Invokes callback functions assosiated with the given hotkey\n * @param {Event} event\n * @param {String} keyString hotkey\n * @param {Array.<HotKey>} hotkeys List of registered callbacks for\n * the given hotkey\n * @private\n */\n Hotkeys.prototype._invokeHotkeyHandlers = function(event, keyString, hotkeys) {\n for (var i = 0, l = hotkeys.length; i < l; i++) {\n var hotkey = hotkeys[i],\n target = event.target || event.srcElement,\n nodeName = target.nodeName.toUpperCase();\n if (!_.includes(this._preventIn, nodeName) &&\n _.intersection(target.classList, this._preventInClass).length === 0 &&\n _.intersection(target.classList, hotkey.preventInClass).length === 0) {\n try {\n hotkey.callback.call(hotkey.context, event, hotkey.args);\n } catch(e) {\n console.error('HotKeys: ', hotkey.key, e.message);\n }\n }\n }\n };\n\n /**\n * Keydown Event Handler\n * @private\n */\n Hotkeys.prototype._onKeydown = function(event) {\n var keyString = this.keyStringFromEvent(event);\n if (this._hotkeys[keyString]) {\n this._invokeHotkeyHandlers(event, keyString, this._hotkeys[keyString]);\n }\n };\n\n /**\n * Keyup Event Handler\n * @private\n */\n Hotkeys.prototype._onKeyup = function(event) {\n var keyString = this.keyStringFromEvent(event);\n if (this._hotkeysUp[keyString]) {\n this._invokeHotkeyHandlers(this._hotkeysUp[keyString], keyString);\n }\n };\n\n /**\n * Keypress Event Handler\n * @private\n */\n Hotkeys.prototype._onKeypress = function(event) {\n var charCode, keyString;\n\n charCode = event.keyCode || event.which;\n keyString = CHAR_CODES[charCode];\n if (keyString && this._hotkeys[keyString]) {\n this._invokeHotkeyHandlers(event, keyString, this._hotkeys[keyString]);\n }\n };\n\n /**\n * Cross-browser method which can extract a key string from an event.\n * Key strings are of the form\n *\n * ctrl+alt+shift+meta+character\n *\n * where each of the 4 modifiers may or may not appear, but always appear\n * in that order if they do appear.\n *\n * TODO : this is not yet implemented fully. The trouble is, the keyCode,\n * charCode, and which properties of the DOM standard KeyboardEvent are\n * discouraged in favour of the use of key and char, but key and char are\n * not yet implemented in Gecko nor in Blink/Webkit. We need to leverage\n * keyCode/charCode so that current browser versions are supported, but also\n * look to key and char because they're apparently more useful and are the\n * future.\n */\n Hotkeys.prototype.keyStringFromEvent = function(event) {\n var result = [];\n var key = event.which;\n\n if (KEY_CODES[key]) {\n key = KEY_CODES[key];\n } else {\n key = String.fromCharCode(key).toLowerCase();\n }\n\n if (event.ctrlKey) { result.push('ctrl'); }\n if (event.altKey) { result.push('alt'); }\n if (event.shiftKey) { result.push('shift'); }\n if (event.metaKey) { result.push('meta'); }\n result.push(key);\n return _.uniq(result).join('+');\n };\n\n /**\n * Unregister a hotkey (shortcut) helper for (keyUp/keyDown).\n *\n * @param {String} params.key - valid key string.\n */\n Hotkeys.prototype._deregisterHotkey = function(hotkey) {\n var ret;\n var table = this._hotkeys;\n\n if (hotkey.onKeyUp) {\n table = this._hotkeysUp;\n }\n\n if (table[hotkey.key]) {\n var callbackArray = table[hotkey.key];\n for (var i = 0; i < callbackArray.length; ++i) {\n var callbackData = callbackArray[i];\n if ((hotkey.callback === callbackData.callback &&\n callbackData.context === hotkey.context) ||\n (hotkey.id === callbackData.id)) {\n ret = callbackArray.splice(i, 1);\n }\n }\n if (callbackArray.length === 0)\n delete this._hotkeys[hotkey.key];\n }\n return ret;\n };\n\n /**\n * Unregister hotkeys\n * @param {Hotkey} hotkey A hotkey object\n * @return {Array}\n */\n Hotkeys.prototype.deregisterHotkey = function(hotkey) {\n var result = [];\n\n this._validateHotkey(hotkey);\n\n if (angular.isArray(hotkey.key)) {\n for (var i = hotkey.key.length - 1; i >= 0; i--) {\n var clone = hotkey.clone();\n clone.key = hotkey.key[i];\n var ret = this._deregisterHotkey(clone);\n if (ret !== void 0) {\n result.push(ret[0]);\n }\n }\n } else {\n result.push(this._deregisterHotkey(hotkey));\n }\n return result;\n };\n\n /**\n * Validate HotKey type\n */\n Hotkeys.prototype._validateHotkey = function(hotkey) {\n if (!(hotkey instanceof HotKey)) {\n throw new TypeError('Hotkeys: Expected a hotkey object be instance of HotKey');\n }\n };\n\n /**\n * Register a hotkey (shortcut) helper for (keyUp/keyDown).\n * @param {Object} params Parameters object\n * @param {String} params.key - valid key string.\n * @param {Function} params.callback - routine to run when key is pressed.\n * @param {Object} params.context - @this value in the callback.\n * @param [Boolean] params.onKeyUp - if this is intended for a keyup.\n * @param [String] params.id - the identifier for this registration.\n */\n Hotkeys.prototype._registerKey = function(hotkey) {\n var table = this._hotkeys;\n\n if (hotkey.onKeyUp) {\n table = this._hotkeysUp;\n }\n\n table[hotkey.key] = table[hotkey.key] || [];\n table[hotkey.key].push(hotkey);\n return hotkey;\n };\n\n Hotkeys.prototype._registerKeys = function(hotkey) {\n var result = [];\n\n if (angular.isArray(hotkey.key)) {\n for (var i = hotkey.key.length - 1; i >= 0; i--) {\n var clone = hotkey.clone();\n clone.id = guid();\n clone.key = hotkey.key[i];\n result.push(this._registerKey(clone));\n }\n } else {\n result.push(this._registerKey(hotkey));\n }\n return result;\n };\n\n /**\n * Register a hotkey (shortcut). see _registerHotKey\n */\n Hotkeys.prototype.registerHotkey = function(hotkey) {\n this._validateHotkey(hotkey);\n return this._registerKeys(hotkey);\n };\n\n /**\n * Register a hotkey (shortcut) keyup behavior.\n * see _registerHotKey\n */\n Hotkeys.prototype.registerHotkeyUp = function(hotkey) {\n this._validateHotkey(hotkey);\n hotkey.onKeyUp = true;\n this._registerKeys(hotkey);\n };\n\n /**\n * Creates new hotkey object.\n * @param {Object} args\n * @return {HotKey}\n */\n Hotkeys.prototype.createHotkey = function(args) {\n if (args.key === null || args.key === void 0) {\n throw new TypeError('HotKeys: Argument \"key\" is required');\n }\n\n if (args.callback === null || args.callback === void 0) {\n throw new TypeError('HotKeys: Argument \"callback\" is required');\n }\n\n args.callback = wrapWithApply(args.callback);\n return new HotKey(args);\n };\n\n /**\n * Checks if given shortcut match the event\n * @param {Event} event An event\n * @param {String|Array} key A shortcut\n * @return {Boolean}\n */\n Hotkeys.prototype.match = function(event, key) {\n if (!angular.isArray(key)) {\n key = [key];\n }\n\n var eventHotkey = this.keyStringFromEvent(event);\n return Boolean(~key.indexOf(eventHotkey));\n };\n\n /**\n * Build and display (or hide) the hotkeys cheat sheet\n *\n * If a hotkey is registered multiple times, only the description of the first registered\n * hotkey is displayed.\n */\n Hotkeys.prototype._toggleCheatSheet = function() {\n var _this = this;\n\n if (this._cheatSheet) {\n Hotkeys.$modal.hide();\n this._cheatSheet = null;\n }\n else {\n this._cheatSheet = Hotkeys.$modal\n .show({\n clickOutsideToClose: true,\n escapeToClose: true,\n template: [\n '<md-dialog>',\n ' <md-dialog-content>',\n ' <md-list>',\n ' <md-list-item ng-repeat=\"(hotkey, keys) in hotkeys\">',\n ' <div class=\"sg-hotkey-container\">',\n ' <sg-hotkey>{{keys[0].lkey || hotkey}}</sg-hotkey>',\n ' </div>',\n ' {{keys[0].description}}',\n ' </md-list-item>',\n ' </md-list>',\n ' </md-dialog-content>',\n '</md-dialog>'\n ].join(''),\n controller: CheatSheetController,\n locals: {\n hotkeys: _this._hotkeys\n }\n })\n .finally(function() {\n _this._cheatSheet = null;\n });\n }\n\n CheatSheetController.$inject = ['$scope', 'hotkeys'];\n function CheatSheetController($scope, hotkeys) {\n $scope.hotkeys = hotkeys;\n $scope.closeDialog = function() {\n Hotkeys.$modal.hide();\n };\n }\n };\n\n return Hotkeys;\n }\n }\n\n sgHotkeys.$inject = ['$mdDialog', '$sgHotkeys'];\n function sgHotkeys($mdDialog, $sgHotkeys) {\n angular.extend($sgHotkeys, { $modal: $mdDialog });\n\n return new $sgHotkeys();\n }\n\n angular\n .module('SOGo.Common')\n .service('sgHotkeys', sgHotkeys)\n .provider('$sgHotkeys', $sgHotkeys);\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', function($q, $log, Settings, Resource) {\n angular.extend(User, {\n $q: $q,\n $log: $log,\n $$resource: new Resource(Settings.activeUser('folderURL'), Settings.activeUser()),\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, resource = User.$$resource, 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 else if (options && options.uid) {\n resource = User.$$resource.userResource(options.uid);\n }\n\n return 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, _.bind(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, _.bind(compareUids, user))) {\n users.splice(index, 1);\n }\n }\n // Add new users matching the search query\n _.forEach(results, function(data, index) {\n if (_.isUndefined(_.find(users, _.bind(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;\n this.$avatarIcon = (this.$isGroup() || this.$isSpecial()) ? 'group' : 'person';\n // NOTE: We can't assign a Gravatar at this stage since we would need the Preferences module\n // which already depend on the User module.\n\n // An empty attribute to trick md-autocomplete when adding users from the ACLs editor\n this.empty = ' ';\n };\n\n /**\n * @function $fullname\n * @memberof User.prototype\n * @return a string representing the fullname\n */\n User.prototype.$fullname = function() {\n return this.cn || this.uid;\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.$fullname();\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 $isGroup\n * @memberof User.prototype\n * @return true if the user actually represents a group of users\n */\n User.prototype.$isGroup = function() {\n return this.isGroup || this.userClass && this.userClass == 'normal-group';\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 == '<default>') {\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 if (this.$shadowRights) {\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 /* 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). The element's content must return the name of the generic icon to be used (usually 'person' or 'group').\n * Based on http://blog.lingohub.com/2014/08/better-ux-with-angularjs-directives/.\n * @memberof SOGo.Common\n * @example:\n <sg-avatar-image sg-email=\"test@email.com\" size=\"50\">person</sg-avatar-image>\n */\n sgAvatarImage.$inject = ['$parse'];\n function sgAvatarImage($parse) {\n return {\n restrict: 'AE',\n scope: {},\n bindToController: {\n size: '@',\n email: '=sgEmail',\n src: '=sgSrc'\n },\n transclude: true,\n template: [\n '<div class=\"sg-icon-badge-container\">',\n ' <md-icon ng-transclude></md-icon>', // the generic icon\n ' <md-icon class=\"md-warn sg-icon--badge sg-icon--badge-bottom\"',\n ' style=\"display: none\">not_interested</md-icon>', // the inactive badge (if disabled)\n ' <img class=\"ng-hide\" ng-src=\"{{vm.url}}\">', // the gravatar or local image\n '</div>'\n ].join(''),\n link: link,\n controller: 'sgAvatarImageController',\n controllerAs: 'vm'\n };\n\n function link(scope, element, attrs, controller) {\n var imgElement = element.find('img'),\n mdIcons = element.find('md-icon'),\n mdIconElement = angular.element(mdIcons[0]),\n mdBadgeElement = angular.element(mdIcons[1]),\n deregisterWatcher;\n\n if (attrs.size) {\n imgElement.attr('width', attrs.size);\n imgElement.attr('height', attrs.size);\n mdIconElement.css('font-size', attrs.size + 'px');\n mdBadgeElement.css('font-size', parseInt(attrs.size*0.4) + 'px');\n }\n\n if (angular.isDefined(attrs.ngDisabled)) {\n deregisterWatcher = scope.$watch(attrs.ngDisabled, function(isDisabled) {\n if (attrs.disabled) {\n mdBadgeElement.css({ display: 'block' });\n }\n deregisterWatcher(); // watch once\n });\n }\n\n controller.img = imgElement;\n controller.genericImg = mdIconElement;\n }\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, toggleZoomFcn;\n\n vm = this;\n\n $scope.$on('$destroy', function() {\n if (toggleZoomFcn)\n $element.off('click', toggleZoomFcn);\n });\n\n // Wait on user's defaults\n Preferences.ready().then(function() {\n $scope.$watch(function() { return 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 if (Preferences.defaults.SOGoGravatarEnabled)\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(function() { return 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 configureZoomableAvatar();\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 function configureZoomableAvatar() {\n $element.addClass('sg-avatar-image--zoomable');\n toggleZoomFcn = function() {\n $element.toggleClass('sg-avatar-image--zoom');\n };\n $element.on('click', toggleZoomFcn);\n }\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 'use strict';\n\n angular\n .module('SOGo.Common')\n .directive('sgCheckmark', sgCheckmarkDirective);\n\n /*\n * sgCheckmark - A checkmark to be used in a mdMenuItem\n * @memberof SOGo.Common\n * @restrict element\n *\n * @example:\n\n <md-menu>\n <md-button class=\"md-icon-button\" aria-label=\"Sort\"\n ng-click=\"$mdOpenMenu()\">\n <md-icon>sort</md-icon>\n </md-button>\n <md-menu-content>\n <md-menu-item>\n <sg-checkmark\n aria-label=\"Descending Order\"\n ng-model=\"ctrl.asc\"\n ng-click=\"ctrl.filter()\"\n sg-true-value=\"0\"\n sg-false-value=\"1\">Descending Order</sg-checkmark>\n </md-menu-item> \n </md-menu-content>\n </md-menu>\n */\n sgCheckmarkDirective.$inject = ['$parse', '$mdAria', '$mdTheming', '$mdUtil'];\n function sgCheckmarkDirective($parse, $mdAria, $mdTheming, $mdUtil) {\n var CHECKED_CSS = 'sg-checked';\n\n return {\n restrict: 'E',\n replace: true,\n transclude: true,\n require: '?ngModel',\n //priority: 210, // Run before ngAria\n template: [\n '<button class=\"md-button sg-checkmark\" type=\"button\">',\n ' <md-icon>check</md-icon>',\n ' <span ng-transclude></span',\n '</button>'\n ].join(''),\n compile: compile\n };\n\n function compile(tElement, tAttrs) {\n\n // Attach a click handler in compile in order to immediately stop propagation\n // (especially for ng-click) when the checkmark is disabled.\n tElement.on('click', function(event) {\n if (this.hasAttribute('disabled')) {\n event.stopImmediatePropagation();\n }\n });\n\n return function postLink(scope, element, attr, ngModelCtrl) {\n // See https://github.com/angular/angular.js/commit/c90cefe16142d973a123e945fc9058e8a874c357\n var trueValue = parseConstantExpr($parse, scope, 'sgTrueValue', attr.sgTrueValue, true),\n falseValue = parseConstantExpr($parse, scope, 'sgFalseValue', attr.sgFalseValue, false);\n \n ngModelCtrl = ngModelCtrl || $mdUtil.fakeNgModel();\n $mdTheming(element);\n\n $mdAria.expectWithText(element, 'aria-label');\n\n element.on('click', listener);\n\n ngModelCtrl.$render = render;\n\n function parseConstantExpr($parse, context, name, expression, fallback) {\n var parseFn;\n if (angular.isDefined(expression)) {\n parseFn = $parse(expression);\n if (!parseFn.constant) {\n throw Error('Expected constant expression for `' + name + '`, but saw `' + expression + '`.');\n }\n return parseFn(context);\n }\n return fallback;\n }\n\n function listener(ev) {\n if (element[0].hasAttribute('disabled')) {\n return;\n }\n\n scope.$apply(function() {\n // Toggle the checkmark value\n var viewValue = ngModelCtrl.$viewValue == trueValue? falseValue : trueValue;\n\n ngModelCtrl.$setViewValue( viewValue, ev && ev.type);\n ngModelCtrl.$render();\n });\n }\n\n function render() {\n if (ngModelCtrl.$viewValue == trueValue)\n element.addClass(CHECKED_CSS);\n else\n element.removeClass(CHECKED_CSS);\n }\n };\n }\n }\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 <sg-color-picker sg-on-select=\"properties.calendar.color = color\"></sg-color-picker>\n */\n function sgColorPicker() {\n return {\n restrict: 'E',\n require: 'ngModel',\n template: [\n '<md-menu>',\n ' <md-button class=\"md-icon-button\"',\n ' label:aria-label=\"Options\"',\n ' ng-style=\"{ \\'background-color\\': sgColor }\"',\n ' ng-click=\"$mdOpenMenu()\"',\n ' md-menu-origin=\"md-menu-origin\">',\n ' <md-icon ng-style=\"{ color: sgIconColor }\">color_lens</md-icon>',\n ' </md-button>',\n ' <md-menu-content width=\"3\">',\n ' <md-content class=\"md-padding\">',\n ' <md-grid-list class=\"sg-color-picker\" md-cols=\"7\" md-row-height=\"1:1\" md-gutter=\"0.5em\">',\n ' <md-grid-tile ng-repeat=\"color in ::sgColors track by $index\"',\n ' ng-style=\"::{ \\'background-color\\': color }\"',\n ' ng-class=\"::{ selected: color == sgColor }\"',\n ' ng-click=\"setColor($event, color)\"><md-icon ng-style=\"::{ color: color }\">check_box</md-icon></md-grid-tile>',\n ' </md-grid-list>',\n ' </md-content>',\n ' </md-menu-content>',\n '</md-menu>'\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(event, color) {\n if (event) {\n _.forEach(event.currentTarget.parentElement.children, function(tile) {\n tile.classList.remove('selected');\n });\n event.currentTarget.classList.add('selected');\n }\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 <div sg-compile=\"part.content\"><!-- msg --></div>\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 * sgDatepickerReadonlyInput - A directive that disabled the input field of a datepicker.\n * @memberof SOGo.Common\n *\n * @example:\n\n <md-datepicker md-hide-icons=\"triangle\"\n md-open-on-focus=\"md-open-on-focus\"\n ng-model=\"selectedDate\"\n sg-datepicker-readonly-input>\n */\n function sgDatepickerReadonlyInput() {\n return {\n link: postLink,\n require: 'mdDatepicker',\n restrict: 'A'\n };\n\n function postLink(scope, element, attrs, datepickerCtrl) {\n function getInput() {\n return element.find('input').eq(0);\n }\n\n // We need to wait for the autocomplete directive to be compiled\n var listener = scope.$watch(getInput, function (input) {\n if (input.length) {\n listener(); // self release\n input.prop('disabled', true);\n input.parent().addClass('sg-datepicker-readonly-input-container');\n }\n });\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgDatepickerReadonlyInput', sgDatepickerReadonlyInput);\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 * sgDraggable - Make an element (usually a folder of elements) draggable.\n * @memberof SOGo.Common\n * @restrict attribute\n * @param {Object=} sgDraggable - the object to be exposed to the droppable target.\n * @param {expression} sgDragStart - dragging will only start if this expression returns true.\n * @param {expression} sgDragCount - the number of items being dragged; this number appears inside\n * the sg-draggable-helper element that follows the mouse cursor.\n *\n * @example:\n\n <sg-draggable-helper>\n <md-icon>email</md-icon>\n <sg-draggable-helper-counter></sg-draggable-helper-counter>\n </sg-draggable-helper>\n\n <md-list sg-draggable=\"mailbox.service.selectedFolder\"\n sg-drag-start=\"mailbox.selectedFolder.$selectedCount()\"\n sg-drag-count=\"mailbox.selectedFolder.$selectedCount()\">\n */\n sgDraggable.$inject = ['$parse', '$rootScope', '$document', '$timeout', '$log'];\n function sgDraggable($parse, $rootScope, $document, $timeout, $log) {\n return {\n restrict: 'A',\n link: link\n };\n\n function link(scope, element, attrs) {\n var o;\n \n $timeout(function() {\n var folder, dragStart, count;\n\n folder = $parse(attrs.sgDraggable)(scope);\n dragStart = attrs.sgDragStart? $parse(attrs.sgDragStart) : null;\n count = attrs.sgDragCount? $parse(attrs.sgDragCount) : null;\n o = new sgDraggableObject(element, folder, dragStart, count);\n });\n\n scope.$on('$destroy', function() {\n o.$destroy();\n });\n \n function sgDraggableObject($element, folder, dragStart, count) {\n this.$element = $element;\n this.folder = folder;\n this.dragStart = dragStart;\n this.count = count;\n this.helper = $document.find('sg-draggable-helper');\n\n if (!this.helper) {\n throw Error('sg-draggable requires a sg-draggable-helper element.');\n }\n\n this.bindedOnDragDetect = angular.bind(this, this.onDragDetect);\n this.bindedOnDrag = angular.bind(this, this.onDrag);\n\n // Register the mousedown event that can trigger the dragging action\n this.$element.on('mousedown', this.bindedOnDragDetect);\n }\n\n /**\n * sgDraggableObject is an object that wraps the logic to emit the folder:dragstart and\n * folder:dragend custom events.\n */\n sgDraggableObject.prototype = {\n\n dragHasStarted: false,\n\n $destroy: function() {\n this.$element.off('mousedown', this.bindedOnDragDetect);\n },\n\n getDistanceFromStart: function(event) {\n var delta = {\n x: this.startPosition.clientX - event.clientX,\n y: this.startPosition.clientY - event.clientY\n };\n\n return Math.sqrt(delta.x * delta.x + delta.y * delta.y);\n },\n\n\n // Start dragging on mousedown\n onDragDetect: function(ev) {\n var dragMode, pointerHandler;\n\n ev.stopPropagation();\n\n if (!this.dragStart || this.dragStart(scope)) {\n // Listen to mousemove and start dragging when mouse has moved from at least 3 pixels\n $document.on('mousemove', this.bindedOnDrag);\n // Stop dragging on the next \"mouseup\"\n $document.one('mouseup', angular.bind(this, this.onDragEnd));\n }\n },\n\n // \n onDrag: function(ev) {\n var counter;\n\n if (!this.startPosition) {\n this.startPosition = { clientX: ev.clientX, clientY: ev.clientY };\n }\n else if (!this.dragHasStarted && this.getDistanceFromStart(ev) > 10) {\n counter = this.helper.find('sg-draggable-helper-counter');\n this.dragHasStarted = true;\n\n this.helper.removeClass('ng-hide');\n if (this.count && this.count(scope) > 1)\n counter.text(this.count(scope)).removeClass('ng-hide');\n else\n counter.addClass('ng-hide');\n \n $log.debug('emit folder:dragstart');\n $rootScope.$emit('folder:dragstart', this.folder);\n }\n if (this.dragHasStarted) {\n if (ev.shiftKey)\n this.helper.addClass('sg-draggable-helper--copy');\n else\n this.helper.removeClass('sg-draggable-helper--copy');\n this.helper.css({ top: (ev.pageY + 5) + 'px', left: (ev.pageX + 5) + 'px' });\n }\n },\n\n\n onDragEnd: function(ev) {\n this.startPosition = null;\n $document.off('mousemove', this.bindedOnDrag);\n\n if (this.dragHasStarted) {\n $log.debug('emit folder:dragend');\n $rootScope.$emit('folder:dragend', this.folder, ev.shiftKey?'copy':'move');\n this.dragHasStarted = false;\n this.helper.addClass('ng-hide');\n }\n }\n\n };\n\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgDraggable', sgDraggable);\n})();\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 * sgDroppable - Make an element a possible destination while dragging\n * @memberof SOGo.Common\n * @restrict attribute\n * @param {expression} sgDroppable - dropping is accepted only if this expression returs true.\n * One variables is exposed: dragFolder.\n * @param {expression} sgDrop - called when dropping ends on the element.\n * Two variables are exposed: dragFolder and dragMode.\n *\n * @example:\n\n <md-list-item sg-droppable=\"folder.id != dragFolder.id\"\n sg-drop=\"app.dragSelectedMessages(dragFolder, folder, dragMode)\">\n */\n sgDroppable.$inject = ['$parse', '$rootScope', '$document', '$timeout', '$log'];\n function sgDroppable($parse, $rootScope, $document, $timeout, $log) {\n return {\n restrict: 'A',\n link: link\n };\n\n function link(scope, element, attrs) {\n var overElement = false, dropAction, droppable,\n deregisterFolderDragStart, deregisterFolderDragEnd;\n\n if (!attrs.sgDrop) {\n throw Error('sg-droppable requires a sg-drop action.');\n }\n\n overElement = false;\n droppable = $parse(attrs.sgDroppable);\n dropAction = $parse(attrs.sgDrop);\n\n // Register listeners of custom events on root scope\n deregisterFolderDragStart = $rootScope.$on('folder:dragstart', function(event, folder) {\n if (droppable(scope, { dragFolder: folder })) {\n element.on('mouseenter', onEnter);\n element.on('mouseleave', onLeave);\n }\n });\n deregisterFolderDragEnd = $rootScope.$on('folder:dragend', function(event, folder, mode) {\n element.off('mouseenter');\n element.off('mouseleave');\n if (overElement) {\n angular.bind(element[0], onLeave)(event);\n dropAction(scope, { dragFolder: folder, dragMode: mode });\n }\n });\n\n scope.$on('destroy', function() {\n deregisterFolderDragStart();\n deregisterFolderDragEnd();\n });\n\n function onEnter(event) {\n overElement = true;\n element.addClass('sg-droppable-over');\n }\n\n function onLeave(event) {\n overElement = false;\n this.classList.remove('sg-droppable-over');\n element.off('mousemove');\n }\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgDroppable', sgDroppable);\n})();\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 <input type=\"text\"\n sg-enter=\"save($index)\" />\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 <input type=\"text\"\n sg-escape=\"revertEditing($index)\" />\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 <input type=\"text\"\n sg-focus-on=\"username\" />\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 <sg-folder-stylesheet\n ng-repeat=\"calendar in calendars.list\"\n ng-model=\"calendar\" />\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 '<style type=\"text/css\">',\n /* Background color */\n ' .bg-folder{{ cssCtrl.ngModel.id }} {',\n ' background-color: {{ cssCtrl.ngModel.color }} !important;',\n ' color: {{ cssCtrl.contrast(cssCtrl.ngModel.color) }} !important;',\n ' }',\n ' .sg-event.bg-folder{{ cssCtrl.ngModel.id }} md-icon {',\n ' color: {{ cssCtrl.contrast(cssCtrl.ngModel.color) }} !important;',\n ' }',\n // Set the contrast color of toolbar icons except the one of the background\n ' md-toolbar.bg-folder{{ cssCtrl.ngModel.id }} md-icon:not(.sg-icon-toolbar-bg) {',\n ' color: {{ cssCtrl.contrast(cssCtrl.ngModel.color) }} !important;',\n ' }',\n // Set the contrast color of input labels\n ' .bg-folder{{ cssCtrl.ngModel.id }} label,',\n ' .bg-folder{{ cssCtrl.ngModel.id }} .md-input {',\n ' color: {{ cssCtrl.contrast(cssCtrl.ngModel.color) }} !important;',\n ' opacity: 0.8;',\n ' }',\n /* Foreground color */\n ' .fg-folder{{ cssCtrl.ngModel.id }},',\n ' .sg-event.fg-folder{{ cssCtrl.ngModel.id }} md-icon {',\n ' color: {{ cssCtrl.ngModel.color }} !important;',\n ' }',\n /* Border color */\n ' .bdr-folder{{ cssCtrl.ngModel.id }} {',\n ' border-color: {{ cssCtrl.ngModel.color }} !important;',\n ' }',\n ' .contrast-bdr-folder{{ cssCtrl.ngModel.id }} {',\n ' border-color: {{ cssCtrl.contrast(cssCtrl.ngModel.color) }} !important;',\n ' }',\n /* Checkbox color */\n ' .checkbox-folder{{ cssCtrl.ngModel.id }} .md-icon {',\n ' background-color: {{ cssCtrl.ngModel.color }} !important;',\n ' }',\n ' .checkbox-folder{{ cssCtrl.ngModel.id }}.md-checked .md-icon:after {',\n ' border-color: {{ cssCtrl.contrast(cssCtrl.ngModel.color) }} !important;',\n ' }',\n /* Switch color */\n ' .md-switch-folder{{ cssCtrl.ngModel.id }}.md-checked .md-thumb {',\n ' background-color: {{ cssCtrl.ngModel.color }} !important;',\n ' }',\n ' .md-switch-folder{{ cssCtrl.ngModel.id }}.md-checked .md-bar {',\n ' background-color: {{ cssCtrl.transparent(cssCtrl.ngModel.color, \"0.5\") }} !important;',\n ' }',\n ' .md-switch-folder{{ cssCtrl.ngModel.id }} .md-bar {',\n ' background-color: {{ cssCtrl.transparent(cssCtrl.ngModel.color, \"0.3\") }} !important;',\n ' }',\n '</style>'\n ].join('')\n };\n\n function sgFolderStylesheetController() {\n var vm = this;\n\n vm.contrast = contrast; // defined in Common/utils.js\n vm.transparent = function(hex, ratio) {\n var color = hexToRgb(hex);\n\n return ['rgba(' + color.r, color.g, color.b, ratio + ')'].join(',');\n };\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 <input type=\"text\"\n sg-placeholder=\"this_is_a_variable\" />\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 'use strict';\n\n /**\n * sgResetOnDisabled - A directive to reset any error of a datepicker when marked\n * as disabled.\n * @memberof SOGo.Common\n * @ngInject\n * @example:\n\n <md-datepicker\n ng-model=\"myDate\"\n ng-disabled=\"!myDateEnabled\"\n sg-reset-on-disabled>\n */\n function sgResetOnDisabled() {\n return {\n link: postLink,\n require: 'mdDatepicker',\n restrict: 'A'\n };\n\n function postLink(scope, element, attrs, datepickerCtrl) {\n function getInput() {\n return element.find('input').eq(0);\n }\n\n // We need to wait for the datepicker directive to be compiled\n var listener = scope.$watch(getInput, function (input) {\n var ngModel;\n\n if (input.length) {\n listener(); // self release\n datepickerCtrl.$scope.$watch('ctrl.isDisabled', function(isDisabled) {\n if (isDisabled)\n if (datepickerCtrl.ngModelCtrl.$invalid)\n // Trigger the event that will reset the errors and the model value\n datepickerCtrl.$scope.$emit('md-calendar-change', datepickerCtrl.date);\n });\n }\n });\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgResetOnDisabled', sgResetOnDisabled);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n angular\n .module('SOGo.Common')\n .directive('sgRippleClick', sgRippleClick);\n\n /*\n * sgRippleClick - A ripple effect to cover the parent element.\n * @memberof SOGo.Common\n * @restrict attribute\n *\n * @example:\n\n <md-dialog id=\"mailEditor\">\n <md-button ng-click=\"editor.send()\"\n sg-ripple-click=\"mailEditor\">Send</md-button>\n </md-dialog>\n\n */\n sgRippleClick.$inject = ['$log', '$timeout'];\n function sgRippleClick($log, $timeout) {\n\n return {\n restrict: 'A',\n compile: compile\n };\n\n function compile(tElement, tAttrs) {\n\n return function postLink(scope, element, attr) {\n var ripple, content, container, containerId;\n\n // Lookup container element\n containerId = element.attr('sg-ripple-click');\n container = element[0].parentNode;\n while (container && container.id != containerId) {\n container = container.parentNode;\n }\n if (!container) {\n $log.error('No parent element found with id ' + containerId);\n return undefined;\n }\n\n // Lookup sg-ripple-content element\n content = container.querySelector('sg-ripple-content');\n if (!content) {\n $log.error('sg-ripple-content not found inside #' + containerId);\n return undefined;\n }\n\n // Lookup sg-ripple element\n ripple = container.querySelector('sg-ripple');\n if (ripple) {\n ripple = angular.element(ripple);\n }\n else {\n // If ripple layer doesn't exit, create it with the primary background color\n ripple = angular.element('<sg-ripple class=\"md-default-theme md-bg\"></sg-ripple>');\n container.appendChild(ripple[0]);\n\n // Hide ripple content on initialization\n if (!content.classList.contains('ng-hide'))\n content.classList.add('ng-hide');\n }\n\n // Register listener\n element.on('click', listener);\n\n scope.$on('$destroy', function() {\n element.off('click', listener);\n });\n\n function listener(event) {\n var coordinates;\n\n if (element[0].hasAttribute('disabled')) {\n return;\n }\n\n if (event.pageX && event.pageY) {\n // Event is a mouse click\n coordinates = { left: event.pageX, top: event.pageY };\n }\n else {\n // Event is a form submit; target is the submit button\n coordinates = event.target.getBoundingClientRect();\n }\n\n if (content.classList.contains('ng-hide')) {\n // Show ripple\n angular.element(container).css({ 'overflow': 'hidden', 'position': 'relative' });\n angular.element(content).css({ top: container.scrollTop + 'px' });\n $timeout(function() {\n // Wait until next digest for CSS animation to work\n ripple.css({\n\t 'top': (coordinates.top - container.offsetTop + container.scrollTop) + 'px',\n\t 'left': (coordinates.left - container.offsetLeft) + 'px',\n\t 'height': '400vmin',\n\t 'width': '400vmin'\n\t });\n // Show ripple content\n content.classList.remove('ng-hide');\n });\n }\n else {\n // Hide ripple layer\n ripple.css({\n 'top': (coordinates.top - container.offsetTop + container.scrollTop) + 'px',\n\t 'left': (coordinates.left - container.offsetLeft) + 'px',\n 'height': '0px',\n 'width': '0px'\n });\n // Hide ripple content\n content.classList.add('ng-hide');\n // Restore overflow of container once the animation is completed\n $timeout(function() {\n angular.element(container).css({ 'overflow': '', 'position': '' });\n }, 800);\n }\n }\n };\n }\n }\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 <div sg-search=\"mailbox.$filter({ sort: 'date', asc: false }, [{ searchBy: searchField, searchInput: searchText }])\">\n <md-button class=\"sg-icon-button\"\n sg-search-cancel=\"ctrl.cancelSearch()\">\n <md-icon>arrow_back</md-icon>\n </md-button>\n <md-input-container>\n <input name=\"search\" type=\"search\"/>\n </md-input-container>\n <md-select class=\"sg-toolbar-sort md-contrast-light\">\n <md-option value=\"subject\">Subject</md-option>\n <md-option value=\"sender\">sender</md-option>\n </md-select>\n </div>\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;\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 'use strict';\n\n /**\n * sgSelectOnly - A directive that restricts an autocomplete field to its selectable values.\n * @memberof SOGo.Common\n * @ngInject\n * @example:\n\n <md-autocomplete\n md-items=\"timezone in timeZones\"\n ng-required=\"true\"\n sg-select-only>\n */\n function sgSelectOnly() {\n return {\n link: postLink,\n require: 'mdAutocomplete',\n restrict: 'A'\n };\n\n function postLink(scope, element, attrs, autoComplete) {\n function getInput() {\n return element.find('input').eq(0);\n }\n\n // We need to wait for the autocomplete directive to be compiled\n var listener = scope.$watch(getInput, function (input) {\n var ngModel;\n\n if (input.length) {\n listener(); // self release\n ngModel = input.controller('ngModel');\n input.on('blur', function () {\n if (!autoComplete.scope.selectedItem) {\n scope.$applyAsync(ngModel.$setValidity('required', false));\n }\n });\n }\n });\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgSelectOnly', sgSelectOnly);\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 <md-button sg-subscribe=\"contact\" sg-subscribe-on-select=\"subscribeToFolder\">Subscribe ..</md-button>\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 /**\n * This section is inspired from angular-material/src/components/datepicker/js/calendar.js\n */\n\n angular\n .module('SOGo.Common')\n .directive('sgTimePane', timePaneDirective);\n\n function timePaneDirective() {\n return {\n template: [\n '<div class=\"sg-time-pane\">',\n ' <div class=\"hours-pane\">',\n ' <div ng-repeat=\"hoursBigLine in hours\" layout=\"row\" layout-xs=\"column\">',\n ' <div ng-repeat=\"hoursLine in hoursBigLine\" layout=\"row\" class=\"hours\">',\n ' <md-button class=\"hourBtn sg-time-selection-indicator\" id=\"{{hour.id}}\"',\n ' md-no-ink',\n ' ng-repeat=\"hour in hoursLine\"',\n ' ng-click=\"hourClickHandler(hour.displayName)\">{{hour.displayName}}</md-button>',\n ' </div>',\n ' </div>',\n ' </div>',\n ' <div class=\"min5\" ng-show=\"is5min()\">',\n ' <div layout=\"row\" layout-xs=\"column\">',\n ' <div ng-repeat=\"minutesLine in min5\" layout=\"row\">',\n ' <md-button class=\"minuteBtn sg-time-selection-indicator\" id=\"{{minute.id}}\"',\n ' md-no-ink',\n ' ng-repeat=\"minute in minutesLine\"',\n ' ng-click=\"minuteClickHandler(minute.displayName)\">{{minute.displayName}}</md-button>',\n ' </div>',\n ' </div>',\n ' </div>',\n ' <div class=\"sg-time-scroll-mask\" ng-hide=\"is5min()\">',\n ' <div class=\"min1\" layout=\"row\" layout-xs=\"column\" layout-wrap>',\n ' <div ng-repeat=\"minutesLine in min1\" layout=\"row\" layout-align=\"space-around center\">',\n ' <md-button class=\"minuteBtn sg-time-selection-indicator\" id=\"{{minute.id}}\"',\n ' md-no-ink',\n ' ng-repeat=\"minute in minutesLine\"',\n ' ng-click=\"minuteClickHandler(minute.displayName)\">{{minute.displayName}}</md-button>',\n ' </div>',\n ' </div>',\n ' </div>',\n ' <div flex layout=\"row\" layout-align=\"center center\" md-colors=\"::{background: \\'default-background-200\\'}\">',\n ' <md-button class=\"toggleBtn md-fab md-mini\" ng-bind=\"getToggleBtnLbl()\" ng-click=\"toggleManual5min()\"></md-button>',\n ' </div>',\n '</div>'\n ].join(''),\n scope: {},\n require: ['ngModel', 'sgTimePane', '?^mdInputContainer'],\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\n var mdInputContainer = controllers[2];\n if (mdInputContainer) {\n throw Error('sg-timepicker should not be placed inside md-input-container.');\n }\n\n sgTimePaneCtrl.configureNgModel(ngModelCtrl, sgTimePaneCtrl);\n }\n };\n }\n\n /** Next identifier for calendar instance. */\n var nextUniqueId = 0;\n\n /**\n * Controller for the sgTimePane component.\n * @ngInject @constructor\n */\n TimePaneCtrl.$inject = ['$element', '$scope', '$$mdDateUtil', '$mdUtil',\n '$mdConstant', '$mdTheming', '$$rAF', '$attrs', '$mdDateLocale'];\n function TimePaneCtrl($element, $scope, $$mdDateUtil, $mdUtil,\n $mdConstant, $mdTheming, $$rAF, $attrs, $mdDateLocale) {\n\n var m;\n\n $mdTheming($element);\n\n /** @final {!angular.JQLite} */\n this.$element = $element;\n\n /** @final {!angular.Scope} */\n this.$scope = $scope;\n\n /** @final */\n this.dateUtil = $$mdDateUtil;\n\n /** @final */\n this.$mdUtil = $mdUtil;\n\n /** @final */\n this.keyCode = $mdConstant.KEY_CODE;\n\n /** @final */\n this.$$rAF = $$rAF;\n\n this.timePaneElement = $element[0].querySelector('.sg-time-pane');\n\n // this.$q = $q;\n\n /** @type {!angular.NgModelController} */\n this.ngModelCtrl = null;\n\n /** @type {String} Class applied to the selected hour or minute cell. */\n this.SELECTED_TIME_CLASS = 'sg-time-selected';\n\n /** @type {String} Class applied to the focused hour or minute cell. */\n this.FOCUSED_TIME_CLASS = 'md-focus';\n\n /** @final {number} Unique ID for this time pane instance. */\n this.id = nextUniqueId++;\n\n /**\n * The date that is currently focused or showing in the calendar. This will initially be set\n * to the ng-model value if set, otherwise to today. It will be updated as the user navigates\n * to other months. The cell corresponding to the displayDate does not necesarily always have\n * focus in the document (such as for cases when the user is scrolling the calendar).\n * @type {Date}\n */\n this.displayTime = null;\n\n /**\n * The selected date. Keep track of this separately from the ng-model value so that we\n * can know, when the ng-model value changes, what the previous value was before it's updated\n * in the component's UI.\n *\n * @type {Date}\n */\n this.selectedTime = null;\n\n /**\n * Used to toggle initialize the root element in the next digest.\n * @type {Boolean}\n */\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 // Unless the user specifies so, the calendar 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 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 var boundKeyHandler = angular.bind(this, this.handleKeyEvent);\n\n // Bind the keydown handler to the body, in order to handle cases where the focused\n // element gets removed from the DOM and stops propagating click events.\n angular.element(document.body).on('keydown', boundKeyHandler);\n\n $scope.$on('$destroy', function() {\n angular.element(document.body).off('keydown', boundKeyHandler);\n });\n }\n\n /**\n * Sets up the controller's reference to ngModelController.\n * @param {!angular.NgModelController} ngModelCtrl\n */\n TimePaneCtrl.prototype.configureNgModel = function(ngModelCtrl, sgTimePaneCtrl) {\n var self = this;\n\n // self.displayTime = new Date(self.$viewValue);\n\n self.ngModelCtrl = ngModelCtrl;\n\n self.$mdUtil.nextTick(function() {\n self.isInitialized = true;\n });\n\n ngModelCtrl.$render = function() {\n var date = this.$viewValue;\n self.$mdUtil.nextTick(function() {\n self.changeSelectedTime(date, sgTimePaneCtrl);\n });\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) {\n var self = this;\n var previousSelectedTime = this.selectedTime;\n\n this.selectedTime = date;\n this.displayTime = new Date(date);\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(this.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(this.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(this.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(this.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(this.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(this.SELECTED_TIME_CLASS);\n mCell.setAttribute('aria-selected', 'true');\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 return date;\n };\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 * Focus the cell corresponding to the given date.\n * @param {Date=} opt_date The date to be focused.\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(this.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(this.FOCUSED_TIME_CLASS);\n hCell.focus();\n }\n }\n };\n})();\n\n(function() {\n 'use strict';\n\n /**\n * This section is inspired from angular-material/src/components/datepicker/js/datepickerDirective.js\n */\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 {String=} md-placeholder The time input placeholder value.\n * @param {boolean=} ng-disabled Whether the timepicker is disabled.\n * @param {boolean=} ng-required Whether a value is required for the timepicker.\n *\n * @description\n * `<sg-timepicker>` 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 * <hljs lang=\"html\">\n * <sg-timepicker ng-model=\"birthday\"></sg-timepicker>\n * </hljs>\n *\n */\n\n timePickerDirective.$inject = ['$mdUtil', '$mdAria'];\n function timePickerDirective($mdUtil, $mdAria) {\n return {\n template: function(tElement, tAttrs) {\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 var ariaLabelValue = tAttrs.ariaLabel || tAttrs.mdPlaceholder;\n\n return [\n '<md-button class=\"sg-timepicker-button md-icon-button\" type=\"button\" ',\n ' tabindex=\"-1\" aria-hidden=\"true\" ',\n ' ng-click=\"ctrl.openTimePane($event)\">',\n ' <md-icon class=\"sg-timepicker-icon\">access_time</md-icon>',\n '</md-button>',\n '<div class=\"md-default-theme sg-timepicker-input-container\" ',\n ' ng-class=\"{\\'sg-timepicker-focused\\': ctrl.isFocused}\">',\n ' <input class=\"sg-timepicker-input\" ',\n (ariaLabelValue ? 'aria-label=\"' + ariaLabelValue + '\" ' : ''),\n ' aria-haspopup=\"true\"',\n ' aria-expanded=\"{{ctrl.isTimeOpen}}\" ',\n ' aria-owns=\"{{::ctrl.timePaneId}}\"',\n ' ng-focus=\"ctrl.setFocused(true)\" ng-blur=\"ctrl.setFocused(false)\">',\n ' <md-button type=\"button\" md-no-ink ',\n ' class=\"sg-timepicker-triangle-button md-icon-button\" ',\n ' ng-click=\"ctrl.openTimePane($event)\" ',\n ' aria-label=\"{{::ctrl.dateLocale.msgOpenCalendar}}\">',\n ' <div class=\"sg-timepicker-expand-triangle\"></div>',\n ' </md-button>',\n '</div>',\n // This pane will be detached from here and re-attached to the document body.\n '<div class=\"sg-timepicker-time-pane md-whiteframe-z1\" id=\"{{::ctrl.timePaneId}}\">',\n ' <div class=\"sg-timepicker-input-mask\">',\n ' <div class=\"sg-timepicker-input-mask-opaque\"></div>',\n // ' md-colors=\"::{\\'box-shadow\\': \\'default-background-hue-1\\'}\"></div>', // using mdColors\n ' </div>',\n ' <div class=\"sg-timepicker-time\" md-colors=\"::{background: \\'default-background-A100\\'}\">',\n ' <sg-time-pane role=\"dialog\" aria-label=\"{{::ctrl.dateLocale.msgCalendar}}\" ',\n ' ng-model=\"ctrl.time\" ng-if=\"ctrl.isTimeOpen\"></sg-time-pane>',\n ' </div>',\n '</div>'\n ].join('');\n },\n require: ['ngModel', 'sgTimepicker', '?^form'],\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 var parentForm = controllers[2];\n var mdNoAsterisk = $mdUtil.parseAttributeBoolean(attr.mdNoAsterisk);\n\n mdTimePickerCtrl.configureNgModel(ngModelCtrl);\n\n // TODO: shall we check ^mdInputContainer?\n if (parentForm) {\n // If invalid, highlights the input when the parent form is submitted.\n var parentSubmittedWatcher = scope.$watch(function() {\n return parentForm.$submitted;\n }, function(isSubmitted) {\n if (isSubmitted) {\n mdTimePickerCtrl.updateErrorState();\n parentSubmittedWatcher();\n }\n });\n }\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 /** Class applied to the timepicker when it's open. */\n var OPEN_CLASS = 'sg-timepicker-open';\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: { GTXS: 172 + 20, XS: 291 + 20 },\n MIN1: { GTXS: 364 + 20, XS: 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 = { GTXS: 510 + 20, XS: 274 + 20 };\n\n /** Used for checking whether the current user agent is on iOS or Android. */\n var IS_MOBILE_REGEX = /ipad|iphone|ipod|android/i;\n\n /**\n * Controller for sg-timepicker.\n *\n * ngInject @constructor\n */\n TimePickerCtrl.$inject = ['$scope', '$element', '$attrs', '$window', '$mdConstant',\n '$mdTheming', '$mdUtil', '$mdDateLocale', '$$mdDateUtil', '$$rAF',\n '$mdMedia'];\n function TimePickerCtrl($scope, $element, $attrs, $window, $mdConstant,\n $mdTheming, $mdUtil, $mdDateLocale, $$mdDateUtil, $$rAF,\n $mdMedia) {\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.$mdUtil = $mdUtil;\n\n /** @final */\n this.$$rAF = $$rAF;\n\n /** @final */\n this.$mdMedia = $mdMedia;\n\n /**\n * The root document element. This is used for attaching a top-level click handler to\n * close the calendar panel when a click outside said panel occurs. We use `documentElement`\n * instead of body because, when scrolling is disabled, some browsers consider the body element\n * to be completely off the screen and propagate events directly to the html element.\n * @type {!angular.JQLite}\n */\n this.documentElement = angular.element(document.documentElement);\n\n /** @type {!angular.NgModelController} */\n this.ngModelCtrl = null;\n\n /** @type {HTMLInputElement} */\n this.inputElement = $element[0].querySelector('input');\n\n /** @final {!angular.JQLite} */\n this.ngInputElement = angular.element(this.inputElement);\n\n /** @type {HTMLElement} */\n this.inputContainer = $element[0].querySelector('.sg-timepicker-input-container');\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 = angular.element($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 /** @type {boolean} Whether the calendar should open when the input is focused. */\n // this.openOnFocus = $attrs.hasOwnProperty('mdOpenOnFocus');\n\n /** @final */\n // this.mdInputContainer = null;\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 /** @type {String} Unique id for the time pane. */\n this.timePaneId = 'sg-time-pane' + $mdUtil.nextUid();\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 /**\n * Name of the event that will trigger a close. Necessary to sniff the browser, because\n * the resize event doesn't make sense on mobile and can have a negative impact since it\n * triggers whenever the browser zooms in on a focused input.\n */\n this.windowEventName = IS_MOBILE_REGEX.test(\n navigator.userAgent || navigator.vendor || window.opera\n ) ? 'orientationchange' : 'resize';\n\n /** Pre-bound close handler so that the event listener can be removed. */\n this.windowEventHandler = $mdUtil.debounce(angular.bind(this, this.closeTimePane), 100);\n\n /** Pre-bound handler for the window blur event. Allows for it to be removed later. */\n this.windowBlurHandler = angular.bind(this, this.handleWindowBlur);\n\n /** @type {Number} Extra margin for the left side of the floating calendar pane. */\n this.leftMargin = 20;\n\n /** @type {Number} Extra margin for the top of the floating calendar. Gets determined on the first open. */\n this.topMargin = null;\n\n // Unless the user specifies so, the timepicker 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 this.ngInputElement.attr('tabindex', $attrs.tabindex);\n $attrs.$set('tabindex', null);\n } else {\n $attrs.$set('tabindex', '-1');\n }\n\n $mdTheming($element);\n $mdTheming(angular.element(this.timePane));\n\n this.installPropertyInterceptors();\n this.attachChangeListeners();\n this.attachInteractionListeners();\n\n var self = this;\n\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 Instance of the ngModel controller.\n */\n TimePickerCtrl.prototype.configureNgModel = function(ngModelCtrl) {\n this.ngModelCtrl = ngModelCtrl;\n\n var self = this;\n\n // Responds to external changes to the model value.\n self.ngModelCtrl.$formatters.push(function(value) {\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 return value;\n });\n\n // Responds to external error state changes (e.g. ng-required based on another input).\n ngModelCtrl.$viewChangeListeners.unshift(angular.bind(this, this.updateErrorState));\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\n var debounceInterval = angular.isDefined(this.debounceInterval) ?\n this.debounceInterval : DEFAULT_DEBOUNCE_INTERVAL;\n self.ngInputElement.on('input', self.$mdUtil.debounce(self.handleInputEvent,\n debounceInterval, 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.$scope.$parent;\n\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\n if (this.timeButton) {\n this.timeButton.disabled = isDisabled;\n }\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 parsedTime = inputString ? this.dateLocale.parseTime(inputString) : null;\n\n // An input string is valid if it is either empty (representing no date)\n // or if it parses to a valid time that the user is allowed to select.\n var isValidInput = inputString === '' || this.dateUtil.isValidDate(parsedTime);\n\n // The datepicker's model is only updated when there is a valid input.\n if (isValidInput) {\n var updated = new Date(this.time);\n updated.setHours(parsedTime.getHours());\n updated.setMinutes(parsedTime.getMinutes());\n this.ngModelCtrl.$setViewValue(updated);\n this.time = updated;\n }\n\n this.updateErrorState(parsedTime);\n };\n\n /** Position and attach the floating calendar to the document. */\n TimePickerCtrl.prototype.attachTimePane = function() {\n var timePane = this.timePane;\n var body = document.body;\n\n timePane.style.transform = '';\n this.$element.addClass(OPEN_CLASS);\n // this.mdInputContainer && this.mdInputContainer.element.addClass(OPEN_CLASS);\n angular.element(body).addClass('md-datepicker-is-showing');\n\n var elementRect = this.inputContainer.getBoundingClientRect();\n var bodyRect = body.getBoundingClientRect();\n\n if (!this.topMargin || this.topMargin < 0) {\n this.topMargin = (this.inputMask.parent().prop('clientHeight') - this.ngInputElement.prop('clientHeight')) / 2;\n }\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 - this.topMargin;\n var paneLeft = elementRect.left - bodyRect.left - this.leftMargin;\n\n // If ng-material has disabled body scrolling (for example, if a dialog is open),\n // then it's possible that the already-scrolled body has a negative top/left. In this case,\n // we want to treat the \"real\" top as (0 - bodyRect.top). In a normal scrolling situation,\n // though, the top of the viewport should just be the body's scroll position.\n var viewportTop = (bodyRect.top < 0 && body.scrollTop === 0) ?\n -bodyRect.top :\n document.body.scrollTop;\n\n var viewportLeft = (bodyRect.left < 0 && body.scrollLeft === 0) ?\n -bodyRect.left :\n document.body.scrollLeft;\n\n var viewportBottom = viewportTop + this.$window.innerHeight;\n var viewportRight = viewportLeft + this.$window.innerWidth;\n\n // Creates an overlay with a hole the same size as element. We remove a pixel or two\n // on each end to make it overlap slightly. The overlay's background is added in\n // the theme in the form of a box-shadow with a huge spread.\n this.inputMask.css({\n position: 'absolute',\n left: this.leftMargin + 'px',\n top: this.topMargin + 'px',\n width: (elementRect.width - 1) + 'px',\n height: (elementRect.height - 2) + 'px'\n });\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. If the time pane is too\n // big to fit on the screen at all, move it to the left of the screen and scale the entire\n // element down to fit.\n var paneWidth = this.$mdMedia('xs')? TIME_PANE_WIDTH.XS : TIME_PANE_WIDTH.GTXS;\n if (paneLeft + paneWidth > viewportRight) {\n if (viewportRight - paneWidth > 0) {\n paneLeft = viewportRight - paneWidth;\n } else {\n paneLeft = viewportLeft;\n var scale = this.$window.innerWidth / paneWidth;\n timePane.style.transform = 'scale(' + scale + ')';\n }\n\n timePane.classList.add('sg-timepicker-pos-adjusted');\n }\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('xs')? TIME_PANE_HEIGHT[min].XS : TIME_PANE_HEIGHT[min].GTXS;\n if (paneTop + paneHeight > viewportBottom &&\n viewportBottom - paneHeight > viewportTop) {\n paneTop = viewportBottom - paneHeight;\n timePane.classList.add('sg-timepicker-pos-adjusted');\n }\n\n timePane.style.left = paneLeft + 'px';\n timePane.style.top = paneTop + 'px';\n document.body.appendChild(timePane);\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(OPEN_CLASS);\n //this.mdInputContainer && this.mdInputContainer.element.removeClass(OPEN_CLASS);\n angular.element(document.body).removeClass('md-datepicker-is-showing');\n this.timePane.classList.remove('md-pane-open');\n this.timePane.classList.remove('md-timepicker-pos-adjusted');\n\n if (this.isTimeOpen) {\n this.$mdUtil.enableScrolling();\n }\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\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 `<select>` on Mac and Windows.\n this.$mdUtil.disableScrollAround(this.timePane);\n\n this.attachTimePane();\n //this.focusTime();\n this.evalAttr('ngFocus');\n\n // Attach click listener inside of a timeout because, if this open call was triggered by a\n // click, we don't want it to be immediately propogated up to the body and handled.\n var self = this;\n this.$mdUtil.nextTick(function() {\n // Use 'touchstart` in addition to click in order to work on iOS Safari, where click\n // events aren't propogated under most circumstances.\n // See http://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n self.documentElement.on('click touchstart', self.bodyClickHandler);\n }, false);\n\n window.addEventListener(this.windowEventName, this.windowEventHandler);\n }\n };\n\n /** Close the floating time pane. */\n TimePickerCtrl.prototype.closeTimePane = function() {\n if (this.isTimeOpen) {\n var self = this;\n\n self.detachTimePane();\n self.ngModelCtrl.$setTouched();\n self.evalAttr('ngBlur');\n\n self.documentElement.off('click touchstart', self.bodyClickHandler);\n window.removeEventListener(self.windowEventName, self.windowEventHandler);\n\n self.timePaneOpenedFrom.focus();\n self.timePaneOpenedFrom = null;\n\n self.isTimeOpen = false;\n }\n };\n\n /** Gets the controller instance for the time in the floating pane. */\n TimePickerCtrl.prototype.getTimePaneCtrl = function() {\n return angular.element(this.timePane.querySelector('sg-time-pane')).controller('sgTimePane');\n };\n\n /** Focus the time in the floating pane. */\n TimePickerCtrl.prototype.focusTime = function() {\n // Use a timeout in order to allow the time to be rendered, as it is gated behind an ng-if.\n var self = this;\n this.$mdUtil.nextTick(function() {\n var ctrl = self.getTimePaneCtrl();\n self.getTimePaneCtrl().focus(null, ctrl);\n }, false);\n };\n\n /**\n * Sets whether the input is currently focused.\n * @param {boolean} isFocused\n */\n TimePickerCtrl.prototype.setFocused = function(isFocused) {\n if (!isFocused) {\n this.ngModelCtrl.$setTouched();\n }\n\n this.evalAttr(isFocused ? 'ngFocus' : 'ngBlur');\n\n this.isFocused = isFocused;\n };\n\n /**\n * Handles a click on the document body when the floating time pane is open.\n * Closes the floating time pane if the click is not inside of it.\n * @param {MouseEvent} event\n */\n TimePickerCtrl.prototype.handleBodyClick = function(event) {\n if (this.isTimeOpen) {\n var isInTime = this.$mdUtil.getClosest(event.target, 'sg-time-pane');\n\n if (!isInTime) {\n this.closeTimePane();\n }\n\n this.$scope.$digest();\n }\n };\n\n /**\n * Handles the event when the user navigates away from the current tab. Keeps track of\n * whether the input was focused when the event happened, in order to prevent the time pane\n * from re-opening.\n */\n TimePickerCtrl.prototype.handleWindowBlur = function() {\n this.inputFocusedOnWindowBlur = document.activeElement === this.inputElement;\n };\n\n /**\n * Evaluates an attribute expression against the parent scope.\n * @param {String} attr Name of the attribute to be evaluated.\n */\n TimePickerCtrl.prototype.evalAttr = function(attr) {\n if (this.$attrs[attr]) {\n this.$scope.$parent.$eval(this.$attrs[attr]);\n }\n };\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgToggleGrid - Convert the tiles of a grid to toggle buttons\n * @memberof SOGo.Common\n * @restrict attribute\n * @param {string} [sgToggleGridAttr] - the attribute that specifies if an object is enabled (toggled)\n * @ngInject\n * @example:\n\n <md-grid-list md-cols=\"7\" md-row-height=\"1:1\"\n ng-model=\"editor.event.repeat.days\"\n sg-toggle-grid sg-toggle-grid-attr=\"day\">..</md-grid-list>\n */\n sgToggleGrid.$inject = ['$parse', '$mdUtil', '$mdColors'];\n function sgToggleGrid($parse, $mdUtil, $mdColors) {\n return {\n restrict: 'A',\n require: ['mdGridList', '?ngModel'],\n compile: compile\n };\n\n function compile(tElement, tAttrs) {\n return function postLink(scope, element, attr, controllers) {\n var tiles = tElement.find('md-grid-tile'),\n tile,\n ngModelCtrl,\n i,\n modelDays = [],\n modelAttr,\n toggleClass;\n\n ngModelCtrl = controllers[1] || $mdUtil.fakeNgModel();\n ngModelCtrl.$render = render;\n ngModelCtrl.$isEmpty = function(value) {\n return !value || value.length === 0;\n };\n\n toggleClass = function() {\n // Toggle class on click event and call toggle function\n var tile = angular.element(this),\n day = tile.attr('value');\n tile.toggleClass('sg-active');\n toggle(day);\n };\n\n for (i = 0; i < tiles.length; i++) {\n tile = angular.element(tiles[i]);\n tile.addClass('sg-icon-button');\n tile.find('figure').addClass('md-icon');\n tile.on('click', toggleClass);\n }\n\n function render() {\n var flattenedDays = ngModelCtrl.$viewValue;\n modelDays = ngModelCtrl.$viewValue;\n if (tAttrs.sgToggleGridAttr) {\n modelAttr = tAttrs.sgToggleGridAttr;\n flattenedDays = _.map(ngModelCtrl.$viewValue, tAttrs.sgToggleGridAttr);\n }\n _.forEach(tiles, function(o) {\n var tile = angular.element(o);\n if (_.includes(flattenedDays, tile.attr('value'))) {\n tile.addClass('sg-active');\n }\n });\n ngModelCtrl.$validate();\n setInvalid(ngModelCtrl.$invalid);\n }\n\n function setInvalid(invalid) {\n var label = element.parent().children()[0];\n if (invalid) {\n element.addClass('sg-toggle-grid-invalid');\n if (label.tagName == 'LABEL') {\n label.style.color = $mdColors.getThemeColor('warn');\n }\n }\n else {\n element.removeClass('sg-toggle-grid-invalid');\n if (label.tagName == 'LABEL') {\n label.style.color = '';\n }\n }\n }\n\n function toggle(day) {\n var i = _.findIndex(modelDays, function(o) {\n if (modelAttr)\n return o[modelAttr] == day;\n else\n return o == day;\n });\n if (i < 0) {\n if (modelAttr) {\n var o = {};\n o[modelAttr] = day;\n modelDays.push(o);\n }\n else\n modelDays.push(day);\n }\n else\n modelDays.splice(i, 1);\n\n scope.$apply(function() {\n ngModelCtrl.$setViewValue(modelDays);\n ngModelCtrl.$setDirty();\n ngModelCtrl.$validate();\n setInvalid(ngModelCtrl.$invalid);\n });\n }\n };\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgToggleGrid', sgToggleGrid);\n})();\n","/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n\n(function() {\n 'use strict';\n\n /*\n * sgToggleGrid - Convert the tiles of a grid to toggle buttons\n * @memberof SOGo.Common\n * @restrict attribute\n * @param {object} sgToggleGrid - the model of the source objects\n * @param {string} [sgToggleGridAttr] - the attribute that specifies if an object is enabled (toggled)\n * @ngInject\n * @example:\n\n <md-grid-list md-cols=\"7\" md-row-height=\"1:1\"\n sg-toggle-grid=\"editor.event.repeat.days\"\n sg-toggle-grid-attr=\"day\">..</md-grid-list>\n */\n function sgVariableScrollShrink() {\n return {\n restrict: 'C',\n link: link\n };\n\n function link(scope, element, attrs, ctrl) {\n console.debug('scroll shrink height = ' + element.prop('offsetHeight'));\n }\n }\n\n angular\n .module('SOGo.Common')\n .directive('sgVariableScrollShrink', sgVariableScrollShrink);\n})();\n"]}