Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • uffd/uffd
  • rixx/uffd
  • thies/uffd
  • leona/uffd
  • enbewe/uffd
  • strifel/uffd
  • thies/uffd-2
7 results
Show changes
Showing
with 888 additions and 67 deletions
/*
Copyright (C) Federico Zivolo 2019
Distributed under the MIT License (license terms are at http://opensource.org/licenses/MIT).
*/(function(e,t){'object'==typeof exports&&'undefined'!=typeof module?module.exports=t():'function'==typeof define&&define.amd?define(t):e.Popper=t()})(this,function(){'use strict';function e(e){return e&&'[object Function]'==={}.toString.call(e)}function t(e,t){if(1!==e.nodeType)return[];var o=e.ownerDocument.defaultView,n=o.getComputedStyle(e,null);return t?n[t]:n}function o(e){return'HTML'===e.nodeName?e:e.parentNode||e.host}function n(e){if(!e)return document.body;switch(e.nodeName){case'HTML':case'BODY':return e.ownerDocument.body;case'#document':return e.body;}var i=t(e),r=i.overflow,p=i.overflowX,s=i.overflowY;return /(auto|scroll|overlay)/.test(r+s+p)?e:n(o(e))}function i(e){return e&&e.referenceNode?e.referenceNode:e}function r(e){return 11===e?re:10===e?pe:re||pe}function p(e){if(!e)return document.documentElement;for(var o=r(10)?document.body:null,n=e.offsetParent||null;n===o&&e.nextElementSibling;)n=(e=e.nextElementSibling).offsetParent;var i=n&&n.nodeName;return i&&'BODY'!==i&&'HTML'!==i?-1!==['TH','TD','TABLE'].indexOf(n.nodeName)&&'static'===t(n,'position')?p(n):n:e?e.ownerDocument.documentElement:document.documentElement}function s(e){var t=e.nodeName;return'BODY'!==t&&('HTML'===t||p(e.firstElementChild)===e)}function d(e){return null===e.parentNode?e:d(e.parentNode)}function a(e,t){if(!e||!e.nodeType||!t||!t.nodeType)return document.documentElement;var o=e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING,n=o?e:t,i=o?t:e,r=document.createRange();r.setStart(n,0),r.setEnd(i,0);var l=r.commonAncestorContainer;if(e!==l&&t!==l||n.contains(i))return s(l)?l:p(l);var f=d(e);return f.host?a(f.host,t):a(e,d(t).host)}function l(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:'top',o='top'===t?'scrollTop':'scrollLeft',n=e.nodeName;if('BODY'===n||'HTML'===n){var i=e.ownerDocument.documentElement,r=e.ownerDocument.scrollingElement||i;return r[o]}return e[o]}function f(e,t){var o=2<arguments.length&&void 0!==arguments[2]&&arguments[2],n=l(t,'top'),i=l(t,'left'),r=o?-1:1;return e.top+=n*r,e.bottom+=n*r,e.left+=i*r,e.right+=i*r,e}function m(e,t){var o='x'===t?'Left':'Top',n='Left'==o?'Right':'Bottom';return parseFloat(e['border'+o+'Width'],10)+parseFloat(e['border'+n+'Width'],10)}function h(e,t,o,n){return ee(t['offset'+e],t['scroll'+e],o['client'+e],o['offset'+e],o['scroll'+e],r(10)?parseInt(o['offset'+e])+parseInt(n['margin'+('Height'===e?'Top':'Left')])+parseInt(n['margin'+('Height'===e?'Bottom':'Right')]):0)}function c(e){var t=e.body,o=e.documentElement,n=r(10)&&getComputedStyle(o);return{height:h('Height',t,o,n),width:h('Width',t,o,n)}}function g(e){return le({},e,{right:e.left+e.width,bottom:e.top+e.height})}function u(e){var o={};try{if(r(10)){o=e.getBoundingClientRect();var n=l(e,'top'),i=l(e,'left');o.top+=n,o.left+=i,o.bottom+=n,o.right+=i}else o=e.getBoundingClientRect()}catch(t){}var p={left:o.left,top:o.top,width:o.right-o.left,height:o.bottom-o.top},s='HTML'===e.nodeName?c(e.ownerDocument):{},d=s.width||e.clientWidth||p.width,a=s.height||e.clientHeight||p.height,f=e.offsetWidth-d,h=e.offsetHeight-a;if(f||h){var u=t(e);f-=m(u,'x'),h-=m(u,'y'),p.width-=f,p.height-=h}return g(p)}function b(e,o){var i=2<arguments.length&&void 0!==arguments[2]&&arguments[2],p=r(10),s='HTML'===o.nodeName,d=u(e),a=u(o),l=n(e),m=t(o),h=parseFloat(m.borderTopWidth,10),c=parseFloat(m.borderLeftWidth,10);i&&s&&(a.top=ee(a.top,0),a.left=ee(a.left,0));var b=g({top:d.top-a.top-h,left:d.left-a.left-c,width:d.width,height:d.height});if(b.marginTop=0,b.marginLeft=0,!p&&s){var w=parseFloat(m.marginTop,10),y=parseFloat(m.marginLeft,10);b.top-=h-w,b.bottom-=h-w,b.left-=c-y,b.right-=c-y,b.marginTop=w,b.marginLeft=y}return(p&&!i?o.contains(l):o===l&&'BODY'!==l.nodeName)&&(b=f(b,o)),b}function w(e){var t=1<arguments.length&&void 0!==arguments[1]&&arguments[1],o=e.ownerDocument.documentElement,n=b(e,o),i=ee(o.clientWidth,window.innerWidth||0),r=ee(o.clientHeight,window.innerHeight||0),p=t?0:l(o),s=t?0:l(o,'left'),d={top:p-n.top+n.marginTop,left:s-n.left+n.marginLeft,width:i,height:r};return g(d)}function y(e){var n=e.nodeName;if('BODY'===n||'HTML'===n)return!1;if('fixed'===t(e,'position'))return!0;var i=o(e);return!!i&&y(i)}function E(e){if(!e||!e.parentElement||r())return document.documentElement;for(var o=e.parentElement;o&&'none'===t(o,'transform');)o=o.parentElement;return o||document.documentElement}function v(e,t,r,p){var s=4<arguments.length&&void 0!==arguments[4]&&arguments[4],d={top:0,left:0},l=s?E(e):a(e,i(t));if('viewport'===p)d=w(l,s);else{var f;'scrollParent'===p?(f=n(o(t)),'BODY'===f.nodeName&&(f=e.ownerDocument.documentElement)):'window'===p?f=e.ownerDocument.documentElement:f=p;var m=b(f,l,s);if('HTML'===f.nodeName&&!y(l)){var h=c(e.ownerDocument),g=h.height,u=h.width;d.top+=m.top-m.marginTop,d.bottom=g+m.top,d.left+=m.left-m.marginLeft,d.right=u+m.left}else d=m}r=r||0;var v='number'==typeof r;return d.left+=v?r:r.left||0,d.top+=v?r:r.top||0,d.right-=v?r:r.right||0,d.bottom-=v?r:r.bottom||0,d}function x(e){var t=e.width,o=e.height;return t*o}function O(e,t,o,n,i){var r=5<arguments.length&&void 0!==arguments[5]?arguments[5]:0;if(-1===e.indexOf('auto'))return e;var p=v(o,n,r,i),s={top:{width:p.width,height:t.top-p.top},right:{width:p.right-t.right,height:p.height},bottom:{width:p.width,height:p.bottom-t.bottom},left:{width:t.left-p.left,height:p.height}},d=Object.keys(s).map(function(e){return le({key:e},s[e],{area:x(s[e])})}).sort(function(e,t){return t.area-e.area}),a=d.filter(function(e){var t=e.width,n=e.height;return t>=o.clientWidth&&n>=o.clientHeight}),l=0<a.length?a[0].key:d[0].key,f=e.split('-')[1];return l+(f?'-'+f:'')}function L(e,t,o){var n=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null,r=n?E(t):a(t,i(o));return b(o,r,n)}function S(e){var t=e.ownerDocument.defaultView,o=t.getComputedStyle(e),n=parseFloat(o.marginTop||0)+parseFloat(o.marginBottom||0),i=parseFloat(o.marginLeft||0)+parseFloat(o.marginRight||0),r={width:e.offsetWidth+i,height:e.offsetHeight+n};return r}function T(e){var t={left:'right',right:'left',bottom:'top',top:'bottom'};return e.replace(/left|right|bottom|top/g,function(e){return t[e]})}function C(e,t,o){o=o.split('-')[0];var n=S(e),i={width:n.width,height:n.height},r=-1!==['right','left'].indexOf(o),p=r?'top':'left',s=r?'left':'top',d=r?'height':'width',a=r?'width':'height';return i[p]=t[p]+t[d]/2-n[d]/2,i[s]=o===s?t[s]-n[a]:t[T(s)],i}function D(e,t){return Array.prototype.find?e.find(t):e.filter(t)[0]}function N(e,t,o){if(Array.prototype.findIndex)return e.findIndex(function(e){return e[t]===o});var n=D(e,function(e){return e[t]===o});return e.indexOf(n)}function P(t,o,n){var i=void 0===n?t:t.slice(0,N(t,'name',n));return i.forEach(function(t){t['function']&&console.warn('`modifier.function` is deprecated, use `modifier.fn`!');var n=t['function']||t.fn;t.enabled&&e(n)&&(o.offsets.popper=g(o.offsets.popper),o.offsets.reference=g(o.offsets.reference),o=n(o,t))}),o}function k(){if(!this.state.isDestroyed){var e={instance:this,styles:{},arrowStyles:{},attributes:{},flipped:!1,offsets:{}};e.offsets.reference=L(this.state,this.popper,this.reference,this.options.positionFixed),e.placement=O(this.options.placement,e.offsets.reference,this.popper,this.reference,this.options.modifiers.flip.boundariesElement,this.options.modifiers.flip.padding),e.originalPlacement=e.placement,e.positionFixed=this.options.positionFixed,e.offsets.popper=C(this.popper,e.offsets.reference,e.placement),e.offsets.popper.position=this.options.positionFixed?'fixed':'absolute',e=P(this.modifiers,e),this.state.isCreated?this.options.onUpdate(e):(this.state.isCreated=!0,this.options.onCreate(e))}}function W(e,t){return e.some(function(e){var o=e.name,n=e.enabled;return n&&o===t})}function B(e){for(var t=[!1,'ms','Webkit','Moz','O'],o=e.charAt(0).toUpperCase()+e.slice(1),n=0;n<t.length;n++){var i=t[n],r=i?''+i+o:e;if('undefined'!=typeof document.body.style[r])return r}return null}function H(){return this.state.isDestroyed=!0,W(this.modifiers,'applyStyle')&&(this.popper.removeAttribute('x-placement'),this.popper.style.position='',this.popper.style.top='',this.popper.style.left='',this.popper.style.right='',this.popper.style.bottom='',this.popper.style.willChange='',this.popper.style[B('transform')]=''),this.disableEventListeners(),this.options.removeOnDestroy&&this.popper.parentNode.removeChild(this.popper),this}function A(e){var t=e.ownerDocument;return t?t.defaultView:window}function M(e,t,o,i){var r='BODY'===e.nodeName,p=r?e.ownerDocument.defaultView:e;p.addEventListener(t,o,{passive:!0}),r||M(n(p.parentNode),t,o,i),i.push(p)}function F(e,t,o,i){o.updateBound=i,A(e).addEventListener('resize',o.updateBound,{passive:!0});var r=n(e);return M(r,'scroll',o.updateBound,o.scrollParents),o.scrollElement=r,o.eventsEnabled=!0,o}function I(){this.state.eventsEnabled||(this.state=F(this.reference,this.options,this.state,this.scheduleUpdate))}function R(e,t){return A(e).removeEventListener('resize',t.updateBound),t.scrollParents.forEach(function(e){e.removeEventListener('scroll',t.updateBound)}),t.updateBound=null,t.scrollParents=[],t.scrollElement=null,t.eventsEnabled=!1,t}function U(){this.state.eventsEnabled&&(cancelAnimationFrame(this.scheduleUpdate),this.state=R(this.reference,this.state))}function Y(e){return''!==e&&!isNaN(parseFloat(e))&&isFinite(e)}function V(e,t){Object.keys(t).forEach(function(o){var n='';-1!==['width','height','top','right','bottom','left'].indexOf(o)&&Y(t[o])&&(n='px'),e.style[o]=t[o]+n})}function j(e,t){Object.keys(t).forEach(function(o){var n=t[o];!1===n?e.removeAttribute(o):e.setAttribute(o,t[o])})}function q(e,t){var o=e.offsets,n=o.popper,i=o.reference,r=$,p=function(e){return e},s=r(i.width),d=r(n.width),a=-1!==['left','right'].indexOf(e.placement),l=-1!==e.placement.indexOf('-'),f=t?a||l||s%2==d%2?r:Z:p,m=t?r:p;return{left:f(1==s%2&&1==d%2&&!l&&t?n.left-1:n.left),top:m(n.top),bottom:m(n.bottom),right:f(n.right)}}function K(e,t,o){var n=D(e,function(e){var o=e.name;return o===t}),i=!!n&&e.some(function(e){return e.name===o&&e.enabled&&e.order<n.order});if(!i){var r='`'+t+'`';console.warn('`'+o+'`'+' modifier is required by '+r+' modifier in order to work, be sure to include it before '+r+'!')}return i}function z(e){return'end'===e?'start':'start'===e?'end':e}function G(e){var t=1<arguments.length&&void 0!==arguments[1]&&arguments[1],o=he.indexOf(e),n=he.slice(o+1).concat(he.slice(0,o));return t?n.reverse():n}function _(e,t,o,n){var i=e.match(/((?:\-|\+)?\d*\.?\d*)(.*)/),r=+i[1],p=i[2];if(!r)return e;if(0===p.indexOf('%')){var s;switch(p){case'%p':s=o;break;case'%':case'%r':default:s=n;}var d=g(s);return d[t]/100*r}if('vh'===p||'vw'===p){var a;return a='vh'===p?ee(document.documentElement.clientHeight,window.innerHeight||0):ee(document.documentElement.clientWidth,window.innerWidth||0),a/100*r}return r}function X(e,t,o,n){var i=[0,0],r=-1!==['right','left'].indexOf(n),p=e.split(/(\+|\-)/).map(function(e){return e.trim()}),s=p.indexOf(D(p,function(e){return-1!==e.search(/,|\s/)}));p[s]&&-1===p[s].indexOf(',')&&console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');var d=/\s*,\s*|\s+/,a=-1===s?[p]:[p.slice(0,s).concat([p[s].split(d)[0]]),[p[s].split(d)[1]].concat(p.slice(s+1))];return a=a.map(function(e,n){var i=(1===n?!r:r)?'height':'width',p=!1;return e.reduce(function(e,t){return''===e[e.length-1]&&-1!==['+','-'].indexOf(t)?(e[e.length-1]=t,p=!0,e):p?(e[e.length-1]+=t,p=!1,e):e.concat(t)},[]).map(function(e){return _(e,i,t,o)})}),a.forEach(function(e,t){e.forEach(function(o,n){Y(o)&&(i[t]+=o*('-'===e[n-1]?-1:1))})}),i}function J(e,t){var o,n=t.offset,i=e.placement,r=e.offsets,p=r.popper,s=r.reference,d=i.split('-')[0];return o=Y(+n)?[+n,0]:X(n,p,s,d),'left'===d?(p.top+=o[0],p.left-=o[1]):'right'===d?(p.top+=o[0],p.left+=o[1]):'top'===d?(p.left+=o[0],p.top-=o[1]):'bottom'===d&&(p.left+=o[0],p.top+=o[1]),e.popper=p,e}var Q=Math.min,Z=Math.floor,$=Math.round,ee=Math.max,te='undefined'!=typeof window&&'undefined'!=typeof document&&'undefined'!=typeof navigator,oe=function(){for(var e=['Edge','Trident','Firefox'],t=0;t<e.length;t+=1)if(te&&0<=navigator.userAgent.indexOf(e[t]))return 1;return 0}(),ne=te&&window.Promise,ie=ne?function(e){var t=!1;return function(){t||(t=!0,window.Promise.resolve().then(function(){t=!1,e()}))}}:function(e){var t=!1;return function(){t||(t=!0,setTimeout(function(){t=!1,e()},oe))}},re=te&&!!(window.MSInputMethodContext&&document.documentMode),pe=te&&/MSIE 10/.test(navigator.userAgent),se=function(e,t){if(!(e instanceof t))throw new TypeError('Cannot call a class as a function')},de=function(){function e(e,t){for(var o,n=0;n<t.length;n++)o=t[n],o.enumerable=o.enumerable||!1,o.configurable=!0,'value'in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}return function(t,o,n){return o&&e(t.prototype,o),n&&e(t,n),t}}(),ae=function(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e},le=Object.assign||function(e){for(var t,o=1;o<arguments.length;o++)for(var n in t=arguments[o],t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n]);return e},fe=te&&/Firefox/i.test(navigator.userAgent),me=['auto-start','auto','auto-end','top-start','top','top-end','right-start','right','right-end','bottom-end','bottom','bottom-start','left-end','left','left-start'],he=me.slice(3),ce={FLIP:'flip',CLOCKWISE:'clockwise',COUNTERCLOCKWISE:'counterclockwise'},ge=function(){function t(o,n){var i=this,r=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};se(this,t),this.scheduleUpdate=function(){return requestAnimationFrame(i.update)},this.update=ie(this.update.bind(this)),this.options=le({},t.Defaults,r),this.state={isDestroyed:!1,isCreated:!1,scrollParents:[]},this.reference=o&&o.jquery?o[0]:o,this.popper=n&&n.jquery?n[0]:n,this.options.modifiers={},Object.keys(le({},t.Defaults.modifiers,r.modifiers)).forEach(function(e){i.options.modifiers[e]=le({},t.Defaults.modifiers[e]||{},r.modifiers?r.modifiers[e]:{})}),this.modifiers=Object.keys(this.options.modifiers).map(function(e){return le({name:e},i.options.modifiers[e])}).sort(function(e,t){return e.order-t.order}),this.modifiers.forEach(function(t){t.enabled&&e(t.onLoad)&&t.onLoad(i.reference,i.popper,i.options,t,i.state)}),this.update();var p=this.options.eventsEnabled;p&&this.enableEventListeners(),this.state.eventsEnabled=p}return de(t,[{key:'update',value:function(){return k.call(this)}},{key:'destroy',value:function(){return H.call(this)}},{key:'enableEventListeners',value:function(){return I.call(this)}},{key:'disableEventListeners',value:function(){return U.call(this)}}]),t}();return ge.Utils=('undefined'==typeof window?global:window).PopperUtils,ge.placements=me,ge.Defaults={placement:'bottom',positionFixed:!1,eventsEnabled:!0,removeOnDestroy:!1,onCreate:function(){},onUpdate:function(){},modifiers:{shift:{order:100,enabled:!0,fn:function(e){var t=e.placement,o=t.split('-')[0],n=t.split('-')[1];if(n){var i=e.offsets,r=i.reference,p=i.popper,s=-1!==['bottom','top'].indexOf(o),d=s?'left':'top',a=s?'width':'height',l={start:ae({},d,r[d]),end:ae({},d,r[d]+r[a]-p[a])};e.offsets.popper=le({},p,l[n])}return e}},offset:{order:200,enabled:!0,fn:J,offset:0},preventOverflow:{order:300,enabled:!0,fn:function(e,t){var o=t.boundariesElement||p(e.instance.popper);e.instance.reference===o&&(o=p(o));var n=B('transform'),i=e.instance.popper.style,r=i.top,s=i.left,d=i[n];i.top='',i.left='',i[n]='';var a=v(e.instance.popper,e.instance.reference,t.padding,o,e.positionFixed);i.top=r,i.left=s,i[n]=d,t.boundaries=a;var l=t.priority,f=e.offsets.popper,m={primary:function(e){var o=f[e];return f[e]<a[e]&&!t.escapeWithReference&&(o=ee(f[e],a[e])),ae({},e,o)},secondary:function(e){var o='right'===e?'left':'top',n=f[o];return f[e]>a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=Z,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]<r(n[d])&&(e.offsets.popper[d]=r(n[d])-o[a]),o[d]>r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!K(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!i)return e;}else if(!e.instance.popper.contains(i))return console.warn('WARNING: `arrow.element` must be child of its popper element!'),e;var r=e.placement.split('-')[0],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-u<s[m]&&(e.offsets.popper[m]-=s[m]-(d[c]-u)),d[m]+u>s[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,w=t(e.instance.popper),y=parseFloat(w['margin'+f],10),E=parseFloat(w['border'+f+'Width'],10),v=b-e.offsets.popper[m]-y-E;return v=ee(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,$(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case ce.FLIP:p=[n,i];break;case ce.CLOCKWISE:p=G(n);break;case ce.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=Z,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)<f(l.right)||'top'===n&&f(a.bottom)>f(l.top)||'bottom'===n&&f(a.top)<f(l.bottom),h=f(a.left)<f(o.left),c=f(a.right)>f(o.right),g=f(a.top)<f(o.top),u=f(a.bottom)>f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,w=-1!==['top','bottom'].indexOf(n),y=!!t.flipVariations&&(w&&'start'===r&&h||w&&'end'===r&&c||!w&&'start'===r&&g||!w&&'end'===r&&u),E=!!t.flipVariationsByContent&&(w&&'start'===r&&c||w&&'end'===r&&h||!w&&'start'===r&&u||!w&&'end'===r&&g),v=y||E;(m||b||v)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),v&&(r=z(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,C(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport',flipVariations:!1,flipVariationsByContent:!1},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!K(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=D(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottom<o.top||t.left>o.right||t.top>o.bottom||t.right<o.left){if(!0===e.hide)return e;e.hide=!0,e.attributes['x-out-of-boundaries']=''}else{if(!1===e.hide)return e;e.hide=!1,e.attributes['x-out-of-boundaries']=!1}return e}},computeStyle:{order:850,enabled:!0,fn:function(e,t){var o=t.x,n=t.y,i=e.offsets.popper,r=D(e.instance.modifiers,function(e){return'applyStyle'===e.name}).gpuAcceleration;void 0!==r&&console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');var s,d,a=void 0===r?t.gpuAcceleration:r,l=p(e.instance.popper),f=u(l),m={position:i.position},h=q(e,2>window.devicePixelRatio||!fe),c='bottom'===o?'top':'bottom',g='right'===n?'left':'right',b=B('transform');if(d='bottom'==c?'HTML'===l.nodeName?-l.clientHeight+h.bottom:-f.height+h.bottom:h.top,s='right'==g?'HTML'===l.nodeName?-l.clientWidth+h.right:-f.width+h.right:h.left,a&&b)m[b]='translate3d('+s+'px, '+d+'px, 0)',m[c]=0,m[g]=0,m.willChange='transform';else{var w='bottom'==c?-1:1,y='right'==g?-1:1;m[c]=d*w,m[g]=s*y,m.willChange=c+', '+g}var E={"x-placement":e.placement};return e.attributes=le({},E,e.attributes),e.styles=le({},m,e.styles),e.arrowStyles=le({},e.offsets.arrow,e.arrowStyles),e},gpuAcceleration:!0,x:'bottom',y:'right'},applyStyle:{order:900,enabled:!0,fn:function(e){return V(e.instance.popper,e.styles),j(e.instance.popper,e.attributes),e.arrowElement&&Object.keys(e.arrowStyles).length&&V(e.arrowElement,e.arrowStyles),e},onLoad:function(e,t,o,n,i){var r=L(i,t,e,o.positionFixed),p=O(o.placement,r,t,e,o.modifiers.flip.boundariesElement,o.modifiers.flip.padding);return t.setAttribute('x-placement',p),V(t,{position:o.positionFixed?'fixed':'absolute'}),o},gpuAcceleration:void 0}}},ge});
//# sourceMappingURL=popper.min.js.map
/**
* @popperjs/core v2.0.4 - MIT License
*/
"use strict";!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).Popper={})}(this,(function(e){function t(e){return{width:(e=e.getBoundingClientRect()).width,height:e.height,top:e.top,right:e.right,bottom:e.bottom,left:e.left,x:e.left,y:e.top}}function n(e){return"[object Window]"!=={}.toString.call(e)?(e=e.ownerDocument)?e.defaultView:window:e}function r(e){return{scrollLeft:(e=n(e)).pageXOffset,scrollTop:e.pageYOffset}}function o(e){return e instanceof n(e).Element}function i(e){return e instanceof n(e).HTMLElement}function a(e){return e?(e.nodeName||"").toLowerCase():null}function s(e,o,s){void 0===s&&(s=!1),e=t(e);var f={scrollLeft:0,scrollTop:0},p={x:0,y:0};return s||("body"!==a(o)&&(f=o!==n(o)&&i(o)?{scrollLeft:o.scrollLeft,scrollTop:o.scrollTop}:r(o)),i(o)&&((p=t(o)).x+=o.clientLeft,p.y+=o.clientTop)),{x:e.left+f.scrollLeft-p.x,y:e.top+f.scrollTop-p.y,width:e.width,height:e.height}}function f(e){return{x:e.offsetLeft,y:e.offsetTop,width:e.offsetWidth,height:e.offsetHeight}}function p(e){return"html"===a(e)?e:e.parentNode||e.host||document.ownerDocument||document.documentElement}function c(e){return n(e).getComputedStyle(e)}function u(e,t){void 0===t&&(t=[]);var r=function e(t){if(0<=["html","body","#document"].indexOf(a(t)))return t.ownerDocument.body;if(i(t)){var n=c(t);if(/auto|scroll|overlay|hidden/.test(n.overflow+n.overflowY+n.overflowX))return t}return e(p(t))}(e);return r=(e="body"===a(r))?n(r):r,t=t.concat(r),e?t:t.concat(u(p(r)))}function d(e){var t;return!i(e)||!(t=e.offsetParent)||void 0!==window.InstallTrigger&&"fixed"===c(t).position?null:t}function l(e){var t=n(e);for(e=d(e);e&&0<=["table","td","th"].indexOf(a(e));)e=d(e);return e&&"body"===a(e)&&"static"===c(e).position?t:e||t}function m(e){var t=new Map,n=new Set,r=[];return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||function e(o){n.add(o.name),[].concat(o.requires||[],o.requiresIfExists||[]).forEach((function(r){n.has(r)||(r=t.get(r))&&e(r)})),r.push(o)}(e)})),r}function h(e){var t;return function(){return t||(t=new Promise((function(n){Promise.resolve().then((function(){t=void 0,n(e())}))}))),t}}function v(e){return e.split("-")[0]}function g(){for(var e=arguments.length,t=Array(e),n=0;n<e;n++)t[n]=arguments[n];return!t.some((function(e){return!(e&&"function"==typeof e.getBoundingClientRect)}))}function b(e){void 0===e&&(e={});var t=e.defaultModifiers,n=void 0===t?[]:t,r=void 0===(e=e.defaultOptions)?H:e;return function(e,t,i){function a(){c.forEach((function(e){return e()})),c=[]}void 0===i&&(i=r);var p={placement:"bottom",orderedModifiers:[],options:Object.assign({},H,{},r),modifiersData:{},elements:{reference:e,popper:t},attributes:{},styles:{}},c=[],d=!1,v={state:p,setOptions:function(i){return a(),p.options=Object.assign({},r,{},p.options,{},i),p.scrollParents={reference:o(e)?u(e):[],popper:u(t)},i=function(e){var t=m(e);return A.reduce((function(e,n){return e.concat(t.filter((function(e){return e.phase===n})))}),[])}([].concat(p.options.modifiers.filter((function(e){return!n.find((function(t){return t.name===e.name}))})),n.map((function(e){return Object.assign({},e,{},p.options.modifiers.find((function(t){return t.name===e.name})))})))),p.orderedModifiers=i.filter((function(e){return e.enabled})),p.orderedModifiers.forEach((function(e){var t=e.name,n=e.options;n=void 0===n?{}:n,"function"==typeof(e=e.effect)&&(t=e({state:p,name:t,instance:v,options:n}),c.push(t||function(){}))})),v.update()},forceUpdate:function(){if(!d){var e=p.elements,t=e.reference;if(g(t,e=e.popper))for(p.rects={reference:s(t,l(e),"fixed"===p.options.strategy),popper:f(e)},p.reset=!1,p.placement=p.options.placement,p.orderedModifiers.forEach((function(e){return p.modifiersData[e.name]=Object.assign({},e.data)})),t=0;t<p.orderedModifiers.length;t++)if(!0===p.reset)p.reset=!1,t=-1;else{var n=p.orderedModifiers[t];e=n.fn;var r=n.options;r=void 0===r?{}:r,n=n.name,"function"==typeof e&&(p=e({state:p,options:r,name:n,instance:v})||p)}}},update:h((function(){return new Promise((function(e){v.forceUpdate(),e(p)}))})),destroy:function(){a(),d=!0}};return g(e,t)?(v.setOptions(i).then((function(e){!d&&i.onFirstUpdate&&i.onFirstUpdate(e)})),v):v}}function y(e){return 0<=["top","bottom"].indexOf(e)?"x":"y"}function x(e){var t=e.reference,n=e.element,r=(e=e.placement)?v(e):null;e=e?e.split("-")[1]:null;var o=t.x+t.width/2-n.width/2,i=t.y+t.height/2-n.height/2;switch(r){case"top":o={x:o,y:t.y-n.height};break;case"bottom":o={x:o,y:t.y+t.height};break;case"right":o={x:t.x+t.width,y:i};break;case"left":o={x:t.x-n.width,y:i};break;default:o={x:t.x,y:t.y}}if(null!=(r=r?y(r):null))switch(i="y"===r?"height":"width",e){case"start":o[r]=Math.floor(o[r])-Math.floor(t[i]/2-n[i]/2);break;case"end":o[r]=Math.floor(o[r])+Math.ceil(t[i]/2-n[i]/2)}return o}function w(e){var t,r=e.popper,o=e.popperRect,i=e.placement,a=e.offsets,s=e.position,f=e.gpuAcceleration,p=e.adaptive,c=window.devicePixelRatio||1;e=Math.round(a.x*c)/c||0,c=Math.round(a.y*c)/c||0;var u=a.hasOwnProperty("x");a=a.hasOwnProperty("y");var d,m="left",h="top";if(p){var v=l(r);v===n(r)&&(v=r.ownerDocument.documentElement),"top"===i&&(h="bottom",c-=v.clientHeight-o.height,c*=f?1:-1),"left"===i&&(m="right",e-=v.clientWidth-o.width,e*=f?1:-1)}return r=Object.assign({position:s},p&&F),f?Object.assign({},r,((d={})[h]=a?"0":"",d[m]=u?"0":"",d.transform=2>(window.devicePixelRatio||1)?"translate("+e+"px, "+c+"px)":"translate3d("+e+"px, "+c+"px, 0)",d)):Object.assign({},r,((t={})[h]=a?c+"px":"",t[m]=u?e+"px":"",t.transform="",t))}function O(e){return e.replace(/left|right|bottom|top/g,(function(e){return I[e]}))}function M(e){return e.replace(/start|end/g,(function(e){return N[e]}))}function D(e,t){var n=!(!t.getRootNode||!t.getRootNode().host);if(e.contains(t))return!0;if(n)do{if(t&&e.isSameNode(t))return!0;t=t.parentNode||t.host}while(t);return!1}function j(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function E(e,o){if("viewport"===o)e=j({width:(e=n(e)).innerWidth,height:e.innerHeight,x:0,y:0});else if(i(o))e=t(o);else{var a=e.ownerDocument.documentElement;e=n(a),o=r(a),(a=s(a.ownerDocument.documentElement,e)).height=Math.max(a.height,e.innerHeight),a.width=Math.max(a.width,e.innerWidth),a.x=-o.scrollLeft,a.y=-o.scrollTop,e=j(a)}return e}function k(e,t,r){return t="clippingParents"===t?function(e){var t=u(e),n=0<=["absolute","fixed"].indexOf(c(e).position)&&i(e)?l(e):e;return o(n)?t.filter((function(e){return o(e)&&D(e,n)})):[]}(e):[].concat(t),(r=(r=[].concat(t,[r])).reduce((function(t,r){var o=E(e,r),s=n(r=i(r)?r:e.ownerDocument.documentElement),f=i(r)?c(r):{};parseFloat(f.borderTopWidth);var p=parseFloat(f.borderRightWidth)||0,u=parseFloat(f.borderBottomWidth)||0,d=parseFloat(f.borderLeftWidth)||0;f="html"===a(r);var l=r.clientWidth+p,m=r.clientHeight+u;return u=r.clientTop,p=r.clientLeft>d?p:f?s.innerWidth-l:r.offsetWidth-l,s=f?s.innerHeight-m:r.offsetHeight-m,r=r.clientLeft,t.top=Math.max(o.top+u,t.top),t.right=Math.min(o.right-p,t.right),t.bottom=Math.min(o.bottom-s,t.bottom),t.left=Math.max(o.left+r,t.left),t}),E(e,r[0]))).width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}function P(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},{},e)}function L(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function W(e,n){void 0===n&&(n={});var r=n;n=void 0===(n=r.placement)?e.placement:n;var i=r.boundary,a=void 0===i?"clippingParents":i,s=void 0===(i=r.rootBoundary)?"viewport":i;i=void 0===(i=r.elementContext)?"popper":i;var f=r.altBoundary,p=void 0!==f&&f;r=P("number"!=typeof(r=void 0===(r=r.padding)?0:r)?r:L(r,T));var c=e.elements.reference;f=e.rects.popper,a=k(o(p=e.elements[p?"popper"===i?"reference":"popper":i])?p:e.elements.popper.ownerDocument.documentElement,a,s),p=x({reference:s=t(c),element:f,strategy:"absolute",placement:n}),f=j(Object.assign({},f,{},p)),s="popper"===i?f:s;var u={top:a.top-s.top+r.top,bottom:s.bottom-a.bottom+r.bottom,left:a.left-s.left+r.left,right:s.right-a.right+r.right};if(e=e.modifiersData.offset,"popper"===i&&e){var d=e[n];Object.keys(u).forEach((function(e){var t=0<=["right","bottom"].indexOf(e)?1:-1,n=0<=["top","bottom"].indexOf(e)?"y":"x";u[e]+=d[n]*t}))}return u}function B(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function R(e){return["top","right","bottom","left"].some((function(t){return 0<=e[t]}))}var T=["top","bottom","right","left"],q=T.reduce((function(e,t){return e.concat([t+"-start",t+"-end"])}),[]),S=[].concat(T,["auto"]).reduce((function(e,t){return e.concat([t,t+"-start",t+"-end"])}),[]),A="beforeRead read afterRead beforeMain main afterMain beforeWrite write afterWrite".split(" "),H={placement:"bottom",modifiers:[],strategy:"absolute"},C={passive:!0},F={top:"auto",right:"auto",bottom:"auto",left:"auto"},I={left:"right",right:"left",bottom:"top",top:"bottom"},N={start:"end",end:"start"},_=[{name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(e){var t=e.state,r=e.instance,o=(e=e.options).scroll,i=void 0===o||o,a=void 0===(e=e.resize)||e,s=n(t.elements.popper),f=[].concat(t.scrollParents.reference,t.scrollParents.popper);return i&&f.forEach((function(e){e.addEventListener("scroll",r.update,C)})),a&&s.addEventListener("resize",r.update,C),function(){i&&f.forEach((function(e){e.removeEventListener("scroll",r.update,C)})),a&&s.removeEventListener("resize",r.update,C)}},data:{}},{name:"popperOffsets",enabled:!0,phase:"read",fn:function(e){var t=e.state;t.modifiersData[e.name]=x({reference:t.rects.reference,element:t.rects.popper,strategy:"absolute",placement:t.placement})},data:{}},{name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(e){var t=e.state,n=e.options;e=void 0===(e=n.gpuAcceleration)||e,n=void 0===(n=n.adaptive)||n,e={placement:v(t.placement),popper:t.elements.popper,popperRect:t.rects.popper,gpuAcceleration:e},t.styles.popper=Object.assign({},t.styles.popper,{},w(Object.assign({},e,{offsets:t.modifiersData.popperOffsets,position:t.options.strategy,adaptive:n}))),null!=t.modifiersData.arrow&&(t.styles.arrow=Object.assign({},t.styles.arrow,{},w(Object.assign({},e,{offsets:t.modifiersData.arrow,position:"absolute",adaptive:!1})))),t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-placement":t.placement})},data:{}},{name:"applyStyles",enabled:!0,phase:"write",fn:function(e){var t=e.state;Object.keys(t.elements).forEach((function(e){var n=t.styles[e]||{},r=t.attributes[e]||{},o=t.elements[e];i(o)&&a(o)&&(Object.assign(o.style,n),Object.keys(r).forEach((function(e){var t=r[e];!1===t?o.removeAttribute(e):o.setAttribute(e,!0===t?"":t)})))}))},effect:function(e){var t=e.state,n={position:"absolute",left:"0",top:"0",margin:"0"};return Object.assign(t.elements.popper.style,n),function(){Object.keys(t.elements).forEach((function(e){var r=t.elements[e],o=Object.keys(t.styles.hasOwnProperty(e)?Object.assign({},t.styles[e]):n);e=t.attributes[e]||{},o=o.reduce((function(e,t){var n;return Object.assign({},e,((n={})[String(t)]="",n))}),{}),i(r)&&a(r)&&(Object.assign(r.style,o),Object.keys(e).forEach((function(e){return r.removeAttribute(e)})))}))}},requires:["computeStyles"]},{name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(e){var t=e.state,n=e.name,r=void 0===(e=e.options.offset)?[0,0]:e,o=(e=S.reduce((function(e,n){var o=t.rects,i=v(n),a=0<=["left","top"].indexOf(i)?-1:1,s="function"==typeof r?r(Object.assign({},o,{placement:n})):r;return o=(o=s[0])||0,s=((s=s[1])||0)*a,i=0<=["left","right"].indexOf(i)?{x:s,y:o}:{x:o,y:s},e[n]=i,e}),{}))[t.placement],i=o.y;t.modifiersData.popperOffsets.x+=o.x,t.modifiersData.popperOffsets.y+=i,t.modifiersData[n]=e}},{name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options;if(e=e.name,!t.modifiersData[e]._skip){var r=n.fallbackPlacements,o=n.padding,i=n.boundary,a=n.rootBoundary,s=void 0===(n=n.flipVariations)||n,f=v(n=t.options.placement);r=r||(f!==n&&s?function(e){if("auto"===v(e))return[];var t=O(e);return[M(e),t,M(t)]}(n):[O(n)]);var p=function(e,t){var n=new Set;return e.filter((function(e){if(e=t(e),!n.has(e))return n.add(e),!0}))}([n].concat(r).reduce((function(e,n){return"auto"===v(n)?e.concat(function(e,t){void 0===t&&(t={});var n=t.boundary,r=t.rootBoundary,o=t.padding,i=t.flipVariations,a=t.placement.split("-")[1],s=(a?i?q:q.filter((function(e){return e.split("-")[1]===a})):T).reduce((function(t,i){return t[i]=W(e,{placement:i,boundary:n,rootBoundary:r,padding:o})[v(i)],t}),{});return Object.keys(s).sort((function(e,t){return s[e]-s[t]}))}(t,{placement:n,boundary:i,rootBoundary:a,padding:o,flipVariations:s})):e.concat(n)}),[]),(function(e){return e}));r=t.rects.reference,n=t.rects.popper;var c=new Map;f=!0;for(var u=p[0],d=0;d<p.length;d++){var l=p[d],m=v(l),h="start"===l.split("-")[1],g=0<=["top","bottom"].indexOf(m),b=g?"width":"height",y=W(t,{placement:l,boundary:i,rootBoundary:a,padding:o});if(h=g?h?"right":"left":h?"bottom":"top",r[b]>n[b]&&(h=O(h)),b=O(h),(m=[0>=y[m],0>=y[h],0>=y[b]]).every((function(e){return e}))){u=l,f=!1;break}c.set(l,m)}if(f)for(r=function(e){var t=p.find((function(t){if(t=c.get(t))return t.slice(0,e).every((function(e){return e}))}));if(t)return u=t,"break"},n=s?3:1;0<n&&"break"!==r(n);n--);t.placement!==u&&(t.modifiersData[e]._skip=!0,t.placement=u,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}},{name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options;e=e.name;var r=n.mainAxis,o=void 0===r||r;r=void 0!==(r=n.altAxis)&&r;var i=n.tether;i=void 0===i||i;var a=n.tetherOffset,s=void 0===a?0:a;n=W(t,{boundary:n.boundary,rootBoundary:n.rootBoundary,padding:n.padding}),a=v(t.placement);var p=t.placement.split("-")[1],c=!p,u=y(a);a="x"===u?"y":"x";var d=t.modifiersData.popperOffsets,l=t.rects.reference,m=t.rects.popper,h="function"==typeof s?s(Object.assign({},t.rects,{placement:t.placement})):s;if(s={x:0,y:0},o){var g="y"===u?"top":"left",b="y"===u?"bottom":"right",x="y"===u?"height":"width";o=d[u];var w=d[u]+n[g],O=d[u]-n[b],M=i?-m[x]/2:0,D="start"===p?l[x]:m[x];p="start"===p?-m[x]:-l[x],m=t.elements.arrow,m=i&&m?f(m):{width:0,height:0};var j=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0};g=j[g],b=j[b],m=Math.max(0,Math.min(Math.abs(l[x]-m[x]),m[x])),j=t.modifiersData.offset?t.modifiersData.offset[t.placement][u]:0,D=t.modifiersData.popperOffsets[u]+(c?l[x]/2-M-m-g-h:D-m-g-h)-j,c=t.modifiersData.popperOffsets[u]+(c?-l[x]/2+M+m+b+h:p+m+b+h)-j,i=Math.max(i?Math.min(w,D):w,Math.min(o,i?Math.max(O,c):O)),t.modifiersData.popperOffsets[u]=i,s[u]=i-o}r&&(r=d[a],i=Math.max(r+n["x"===u?"top":"left"],Math.min(r,r-n["x"===u?"bottom":"right"])),t.modifiersData.popperOffsets[a]=i,s[a]=i-r),t.modifiersData[e]=s},requiresIfExists:["offset"]},{name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state;e=e.name;var r=n.elements.arrow,o=n.modifiersData.popperOffsets,i=v(n.placement),a=y(i);if(i=0<=["left","right"].indexOf(i)?"height":"width",r){var s=n.modifiersData[e+"#persistent"].padding;r=f(r),o=Math.max(s["y"===a?"top":"left"],Math.min(n.rects.popper[i]/2-r[i]/2+((n.rects.reference[i]+n.rects.reference[a]-o[a]-n.rects.popper[i])/2-(o[a]-n.rects.reference[a])/2),n.rects.popper[i]-r[i]-s["y"===a?"bottom":"right"])),n.modifiersData[e]=((t={})[a]=o,t)}},effect:function(e){var t=e.state,n=e.options;e=e.name;var r=n.element;r=void 0===r?"[data-popper-arrow]":r,n=void 0===(n=n.padding)?0:n,("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&D(t.elements.popper,r)&&(t.elements.arrow=r,t.modifiersData[e+"#persistent"]={padding:P("number"!=typeof n?n:L(n,T))})},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]},{name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state;e=e.name;var n=t.rects.reference,r=t.rects.popper,o=t.modifiersData.preventOverflow,i=W(t,{elementContext:"reference"}),a=W(t,{altBoundary:!0});n=B(i,n),r=B(a,r,o),o=R(n),a=R(r),t.modifiersData[e]={referenceClippingOffsets:n,popperEscapeOffsets:r,isReferenceHidden:o,hasPopperEscaped:a},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":o,"data-popper-escaped":a})}}],U=b({defaultModifiers:_});e.createPopper=U,e.defaultModifiers=_,e.popperGenerator=b,Object.defineProperty(e,"__esModule",{value:!0})}));
//# sourceMappingURL=popper.min.js.map
.footer {
position: fixed;
bottom: 0;
width: 100%;
height: 2em;
line-height: 2em;
background-color: #f5f5f5;
}
.narrow-card {
background: #f7f7f7;
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
padding: 30px;
}
.qrcode {
background: #ffffff;
}
@media (prefers-color-scheme: dark) {
.footer {
background-color: #23282d;
}
.narrow-card {
background: #292e33;
}
a {
color: #3395ff;
background-color: transparent
}
a:hover {
color: #0d82ff
}
.btn-link {
color: #3395ff;
}
.btn-link:hover {
color: #0d82ff;
}
.btn-link.disabled,
.btn-link:disabled {
color: #3395ff;
}
/* Dark theme breaks spinners (appears as full ring without animation) */
.spinner-border {
display: inline-block;
width: 2rem;
height: 2rem;
vertical-align: text-bottom;
border: 0.25em solid currentColor;
border-right-color: transparent;
border-radius: 50%;
-webkit-animation: spinner-border .75s linear infinite;
animation: spinner-border .75s linear infinite;
}
.spinner-border-sm {
width: 1rem;
height: 1rem;
border-width: 0.2em;
}
}
.footer {
position: fixed;
bottom: 0;
width: 100%;
height: 2em;
line-height: 2em;
background-color: #f5f5f5;
}
class CleanupTask:
def __init__(self):
self.handlers = []
def handler(self, func):
self.handlers.append(func)
return func
def delete_by_attribute(self, attribute):
def decorator(cls):
@self.handler
def handler():
cls.query.filter(getattr(cls, attribute)).delete()
return cls
return decorator
def run(self):
for handler in self.handlers:
handler()
cleanup_task = CleanupTask()
import random
import subprocess
import base64
from datetime import timedelta, datetime
import io
......@@ -16,23 +15,23 @@ def register_template_helper(app):
@app.template_filter()
def qrcode_svg(content, **attrs): #pylint: disable=unused-variable
img = qrcode.make(content, image_factory=qrcode.image.svg.SvgPathImage, border=0)
img = qrcode.make(content, image_factory=qrcode.image.svg.SvgPathImage, border=4)
svg = img.get_image()
for key, value, in attrs.items():
svg.set(key, value)
buf = io.BytesIO()
img.save(buf)
return Markup(buf.getvalue().decode().replace('<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n', ''))
return Markup(
buf.getvalue().decode()
.replace('<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n', '')
.replace(' id="qr-path" ', ' ')
.replace('<svg ', '<svg class="qrcode" ')
)
@app.template_filter()
def datauri(data, mimetype='text/plain'): #pylint: disable=unused-variable
return Markup('data:%s;base64,%s'%(mimetype, base64.b64encode(data.encode()).decode()))
@app.url_defaults
def static_version_inject(endpoint, values): #pylint: disable=unused-variable
if endpoint == 'static':
values['v'] = app.jinja_env.globals['gitversion']['longhash'] #pylint: disable=no-member
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True
......@@ -42,7 +41,3 @@ def register_template_helper(app):
app.add_template_global(min, name='min')
app.add_template_global(max, name='max')
app.add_template_global(equalto, name='equalto')
# get git commit
git_output = subprocess.check_output(['git', "log", "-g", "-1", "--pretty=%H#%h#%d#%s"]).decode('UTF-8').split('#', 3)
app.jinja_env.globals['gitversion'] = {'hash': git_output[1], 'longhash': git_output[0], 'branch': git_output[2], 'msg': git_output[3]} #pylint: disable=no-member
{% extends 'base.html' %}
{% block body %}
<div class="row mt-2 justify-content-center">
<div class="col-lg-6 col-md-10 narrow-card">
<div class="text-center">
<img alt="branding logo" src="{{ config.get("BRANDING_LOGO_URL") }}" class="col-lg-8 col-md-12" >
</div>
<div class="col-12">
<h2 class="text-center">{{ _('Access Denied') }}</h2>
</div>
<div class="form-group col-12">
<p>
{% if description %}
{{ description|safe }}
{% else %}
{{ _("You don't have the permission to access this page.") }}
{% endif %}
</p>
</div>
</div>
</div>
{% endblock %}
......@@ -4,13 +4,14 @@
{% block head %}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>{% block title %}uffd{% endblock %}</title>
<title>{% block title %}{{ config['SITE_TITLE'] }}{% endblock %}</title>
<link href="{{ url_for('static', filename="bootstrap/bootstrap.min.css") }}" rel="stylesheet">
<link href="{{ url_for('static', filename="bootstrap/bootstrap-prefers-dark-color-only.min.css") }}" rel="stylesheet">
<link href="{{ url_for('static', filename="fa/css/all.css") }}" rel="stylesheet">
<link href="{{ url_for('static', filename="style.css") }}" rel="stylesheet">
<link href="{{ url_for('static', filename="style-1.css") }}" rel="stylesheet">
<script src="{{ url_for('static', filename="jquery/jquery-3.4.1.min.js") }}"></script>
<script src="{{ url_for('static', filename="popper/popper.min.js") }}"></script>
<script src="{{ url_for('static', filename="popper/popper-1.16.0.min.js") }}"></script>
<script src="{{ url_for('static', filename="bootstrap/bootstrap.min.js") }}"></script>
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/png">
......@@ -35,18 +36,19 @@
{%- endmacro %}
<nav class="navbar navbar-expand-md navbar-dark bg-dark static-top" >
<a class="navbar-brand" href="{{ url_for('index') }}">uffd</a>
<a class="navbar-brand" href="{{ url_for('index') }}">{{ config['SITE_TITLE'] }}</a>
{% if getnavbar() or request.user or request.endpoint != 'session.login' or config['LANGUAGES']|length > 1 %}
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#baseNavbar" aria-controls="baseNavbar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="baseNavbar">
{% if getnavbar() %}
<ul class="navbar-nav mr-auto">
{% for n in navbar if (not n.group) and (not n.visible or n.visible()) %}
{% for n in getnavbar() if not n.group %}
{{ navbaricon(n) }}
{% endfor %}
{% for grouper, list in navbar|rejectattr("group", "none")|groupby("group") %}
{% for grouper, list in getnavbar()|rejectattr("group", "none")|groupby("group") %}
<li class="nav-item dropdown {% if request.endpoint in list|map(attribute='endpoint') %} active{% endif %}">
<a
class="nav-link dropdown-toggle dropdow-clickable"
......@@ -66,47 +68,79 @@
</li>
{% endfor %}
</ul>
{% if is_valid_session() %}
{% endif %}
{% if request.user or request.endpoint != 'session.login' or config['LANGUAGES']|length > 1 %}
<ul class="navbar-nav ml-auto">
{% if config['LANGUAGES']|length > 1 %}
<li class="nav-item">
<form class="language-switch py-2 pr-1" method="POST" style="margin-left: -5px;" action="{{ url_for('setlang') }}">
<input type="hidden" name="ref" value="{{ request.full_path }}">
<select name="lang" class="bg-dark" style="border: 0px; color: rgba(255, 255, 255, 0.5);" onchange="$('.language-switch').submit()">
{% for identifier, name in config['LANGUAGES'].items() %}
<option value="{{ identifier }}" {{ 'selected' if identifier == get_locale() }}>{{ name }}</option>
{% endfor %}
</select>
<noscript>
<button type="submit" class="bg-dark py-0 pl-0" style="border: 0px; color: rgba(255, 255, 255, 0.5);">{{_('Change')}}</button>
</noscript>
</form>
</li>
{% endif %}
{% if request.user %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for("session.deviceauth") }}">
<span aria-hidden="true" class="fas fa-mobile-alt" title="{{_('Authorize Device Login')}}"></span>
<span class="d-inline d-md-none">{{_('Device Login')}}</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for("session.logout") }}">
<span aria-hidden="true" class="fa fa-sign-out-alt"></span>
Logout
{{_("Logout")}}
</a>
</li>
{% elif request.endpoint != 'session.login' %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for("session.login", ref=request.full_path) }}">
<span aria-hidden="true" class="fa fa-sign-in-alt"></span>
{{ _("Login") }}
</a>
</li>
{% endif %}
</ul>
{% endif %}
</div>
{% endif %}
</nav>
{% endblock navbar %}
<div class="container mt-2">
{% block main %}
<main role="main" class="container mt-3">
<div class="row">
{% for message in get_flashed_messages() %}
<div class="alert alert-primary col-12" role="alert">{{ message }}</div>
{% for category, message in get_flashed_messages(with_categories=true) %}
<div class="col-12">
<div class="alert alert-{{ 'danger' if category == 'error' else 'warning' if category == 'warning' else 'primary' }}" role="alert">{{ message }}</div>
</div>
{% endfor %}
</div>
</div>
<main role="main" class="container">
{% block body %}
{% endblock body %}
<!-- spacer for floating footer -->
<div class="mb-5"></div>
</main>
{% endblock main %}
<!-- spacer for floating footer -->
<div class="mb-5"></div>
<footer class="footer">
{% block footer %}
<div class="container">
<div class="container-fluid">
<ul class="list-inline">
{% for link in config["FOOTER_LINKS"]%}
<li class="list-inline-item"><a href="{{ link.url }}">{{ link.title }}</a></li>
{% endfor %}
<li class="list-inline-item float-right">
<a href="https://git.cccv.de/infra/uffd/uffd/">Sourcecode</a>
<a target="_blank" href="https://git.cccv.de/infra/uffd/uffd/-/commit/{{ gitversion.longhash }}"><span title="{{ gitversion.branch }} {{ gitversion.hash }}: {{ gitversion.msg }}" data-toggle="tooltip">Version: {{ gitversion.hash }}</span></a>
<a href="https://git.cccv.de/uffd/uffd/">{{_("About uffd")}}</a>
</li>
</ul>
</div>
......
{% extends 'base.html' %}
{% block main %}
<main role="main" class="container mt-3">
<div class="row justify-content-center">
<div class="col-lg-6 col-md-10 px-0">
<div class="row">
{% for category, message in get_flashed_messages(with_categories=true) %}
<div class="col-12">
<div class="alert alert-{{ 'danger' if category == 'error' else 'warning' if category == 'warning' else 'primary' }}" role="alert">{{ message }}</div>
</div>
{% endfor %}
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-lg-6 col-md-10 narrow-card">
<div class="text-center">
<img alt="branding logo" src="{{ config.get("BRANDING_LOGO_URL") }}" class="col-lg-8 col-md-12" >
</div>
{% block body %}
{% endblock body %}
</div>
</div>
</main>
{% endblock main %}
{% extends 'base.html' %}
{% block body %}
<div class="row">
<div class="col">
<p class="text-right">
<a class="btn btn-primary" href="{{ url_for("group.show") }}">
<i class="fa fa-plus" aria-hidden="true"></i> {{_("New")}}
</a>
</p>
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">{{_("GID")}}</th>
<th scope="col">{{_("Name")}}</th>
<th scope="col">{{_("Description")}}</th>
</tr>
</thead>
<tbody>
{% for group in groups|sort(attribute="unix_gid") %}
<tr id="group-{{ group.id }}">
<th scope="row">
{{ group.unix_gid }}
</th>
<td>
<a href="{{ url_for("group.show", id=group.id) }}">
{{ group.name }}
</a>
</td>
<td>
{{ group.description or '' }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
{% extends 'base.html' %}
{% block body %}
<form action="{{ url_for("group.update", id=group.id) }}" method="POST" autocomplete="off">
<div class="align-self-center">
<div class="clearfix pb-2 col">
<div class="float-sm-right">
<button type="submit" class="btn btn-primary"><i class="fa fa-save" aria-hidden="true"></i> {{_("Save")}}</button>
<a href="{{ url_for("group.index") }}" class="btn btn-secondary">{{_("Cancel")}}</a>
{% if group.id %}
<a href="{{ url_for("group.delete", id=group.id) }}" onClick='return confirm({{_("Are you sure?")|tojson}});' class="btn btn-danger"><i class="fa fa-trash" aria-hidden="true"></i> {{_("Delete")}}</a>
{% else %}
<a href="#" class="btn btn-danger disabled"><i class="fa fa-trash" aria-hidden="true"></i> {{_("Delete")}}</a>
{% endif %}
</div>
</div>
<div class="form-group col">
<label for="group-gid">{{_("Group ID")}}</label>
{% if not group.id %}
<input type="number" class="form-control" id="group-gid" name="unix_gid" value="" placeholder="Automatically chosen if empty">
{% else %}
<input type="number" class="form-control" id="group-gid" name="unix_gid" value="{{ group.unix_gid }}" readonly>
{% endif %}
</div>
<div class="form-group col">
<label for="group-loginname">{{_("Name")}}</label>
<input type="text" class="form-control" id="group-loginname" name="name" minlength=1 maxlength=32 pattern="[a-z0-9_-]*" value="{{ group.name or '' }}" {{ 'readonly' if group.id }}>
<small class="form-text text-muted">
{{_('At least one and at most 32 lower-case characters, digits, dashes ("-") or underscores ("_"). <b>Cannot be changed later!</b>')|safe}}
</small>
</div>
<div class="form-group col">
<label for="group-description">{{_("Description")}}</label>
<textarea class="form-control" id="group-description" name="description" rows="5">{{ group.description or '' }}</textarea>
<small class="form-text text-muted">
</small>
</div>
{% if group.id %}
<div class="col">
<span>{{_("Members")}}:</span>
<ul class="row">
{% for member in group.members|sort(attribute='loginname') %}
<li class="col-12 col-xs-6 col-sm-4 col-md-3 col-lg-2"><a href="{{ url_for("user.show", id=member.id) }}">{{ member.loginname }}</a></li>
{% endfor %}
</ul>
</div>
{% endif %}
</div>
</form>
{% endblock %}
{% extends 'base.html' %}
{% block body %}
<div class="btn-toolbar mb-2">
<a class="btn btn-primary ml-auto" href="{{ url_for("invite.new") }}"><i class="fa fa-plus" aria-hidden="true"></i> {{_('New')}}</a>
</div>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">{{_('Link')}}</th>
<th scope="col">{{_('Created by')}}</th>
<th scope="col">{{_('Permissions')}}</th>
<th scope="col">{{_('Usages')}}</th>
<th scope="col">{{_('Status')}}</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{% for invite in invites|sort(attribute='created', reverse=True)|sort(attribute='active', reverse=True) %}
<tr>
<td>
{% if invite.creator == request.user and invite.active %}
<a href="{{ url_for('invite.use', invite_id=invite.id, token=invite.token) }}"><code>{{ invite.short_token }}</code></a>
<button type="button" class="btn btn-link btn-sm p-0 copy-clipboard" data-copy="{{ url_for('invite.use', invite_id=invite.id, token=invite.token, _external=True) }}" title="{{_('Copy link to clipboard')}}"><i class="fas fa-clipboard"></i></button>
<button type="button" class="btn btn-link btn-sm p-0" data-toggle="modal" data-target="#modal-{{ invite.id }}-qrcode" title="{{_('Show link as QR code')}}"><i class="fas fa-qrcode"></i></button>
{% else %}
<code>{{ invite.short_token }}</code>
{% endif %}
</td>
<td>
{% if not invite.creator %}
{{ '<deleted user>' }}
{% else %}
{{ invite.creator.loginname }}
{% endif %}
</td>
<td>
{{ _('Signup') if invite.allow_signup }}{{ ', ' if invite.allow_signup and invite.roles }}
{% for role in invite.roles %}{{ ', ' if loop.index != 1 }}<i class="fas fa-key"></i>&thinsp;{{ role.name }}{% endfor %}
</td>
<td>
<span style="white-space: nowrap;">{{ invite.signups|selectattr('completed')|list|length }} <i class="fas fa-users" title="{{ _('user signups') }}"></i></span>,
<span style="white-space: nowrap;">{{ invite.grants|length }} <i class="fas fa-key" title="role grants"></i></span>
</td>
<td>
{% if invite.disabled %}
{{_('Disabled')}}
{% elif invite.voided %}
{{_('Voided')}}
{% elif invite.expired %}
{{_('Expired')}}
{% elif not invite.permitted %}
{{_('Invalid, unpermitted creator')}}
{% elif not invite.active %}
{{_('Invalid')}}
{% elif invite.single_use %}
{{ _('Valid once, expires %(expiry_date)s', expiry_date=invite.valid_until|dateformat) }}
{% else %}
{{ _('Valid, expires %(expiry_date)s', expiry_date=invite.valid_until|dateformat) }}
{% endif %}
</td>
<td class="text-right">
<button type="button" class="btn btn-link btn-sm p-0" data-toggle="modal" data-target="#modal-{{ invite.id }}"><i class="fas fa-ellipsis-h"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% for invite in invites %}
<div class="modal" tabindex="-1" id="modal-{{ invite.id }}">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{_('Invite Link Details')}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<ul class="list-unstyled">
<li><b>{{_('Type:')}}</b> {% if invite.single_use %}{{_('Single-use')}}{% else %}{{_('Multi-use')}}{% endif %}</li>
<li><b>{{_('Created:')}}</b> {{ invite.created|datetimeformat }}</li>
<li><b>{{_('Expires:')}}</b> {{ invite.valid_until|datetimeformat }}</li>
<li><b>{{_('Permissions:')}}</b>
<ul>
{% if invite.allow_signup %}
<li>{{_('Link allows account registration')}}</li>
{% else %}
<li>{{_('No account registration allowed')}}</li>
{% endif %}
{% for role in invite.roles %}
<li>{{_('Link grants users the role "%(name)s"', name=role.name)}}</li>
{% endfor %}
</ul>
</li>
<li><b>Usages:</b>
{% if not invite.signups and not invite.grants %}
{{_('Never used')}}
{% else %}
<ul>
{% for signup in invite.signups if signup.completed %}
<li>{{_('Registration of user <a href="%(user_url)s">%(user_name)s</a>', user_url=url_for('user.show', id=signup.user.id)|e, user_name=signup.user.loginname|e)|safe}}</li>
{% endfor %}
{% for grant in invite.grants if grant.user %}
<li>{{_('Roles granted to <a href="%(user_url)s">%(user_name)s</a>', user_url=url_for('user.show', id=grant.user.id)|e, user_name=grant.user.loginname|e)|safe}}</li>
{% endfor %}
</ul>
{% endif %}
</li>
</ul>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
{% if invite.active %}
<form action="{{ url_for('invite.disable', invite_id=invite.id) }}" method="POST">
<button type="submit" class="btn btn-primary">{{_('Disable Link')}}</button>
</form>
{% elif invite.creator == request.user and not invite.expired and invite.permitted %}
<form action="{{ url_for('invite.reset', invite_id=invite.id) }}" method="POST">
<button type="submit" class="btn btn-primary">{{_('Reenable Link')}}</button>
</form>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
{% for invite in invites if invite.creator == request.user %}
<div class="modal" tabindex="-1" id="modal-{{ invite.id }}-qrcode">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{_('Invite')}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
{{ url_for('invite.use', invite_id=invite.id, token=invite.token, _external=True)|qrcode_svg(width='100%', height='100%') }}
</div>
</div>
</div>
</div>
{% endfor %}
<script>
$(".copy-clipboard").on("click", function() {
navigator.clipboard.writeText($(this).data("copy"));
});
</script>
{% endblock %}
{% extends 'base.html' %}
{% block body %}
<form action="{{ url_for("invite.new_submit") }}" method="POST" autocomplete="off" class="form">
<div class="form-group">
<label for="single-use">{{_('Link Type')}}</label>
<select class="form-control" id="single-use" name="single-use">
<option value="1" {{ 'selected' if request.values.get('single-use', '1') == '1' }}>{{_('Valid for a single successful use')}}</option>
<option value="0" {{ 'selected' if request.values.get('single-use', '1') == '0' }}>{{_('Multi-use')}}</option>
</select>
</div>
<div class="form-group">
<label for="valid-until">{{_('Valid Until')}}</label>
<input class="form-control" type="datetime-local" id="valid-until" name="valid-until" value="{{ request.values.get('valid-until') or (datetime.now() + timedelta(hours=36)).replace(hour=23, minute=59).isoformat(timespec='minutes') }}" min="{{ datetime.now().isoformat(timespec='minutes') }}" max="{{ (datetime.now() + timedelta(days=config['INVITE_MAX_VALID_DAYS'])).isoformat(timespec='minutes') }}">
<small class="text-muted">{{_('Must be within the next %(max_valid_days)d days', max_valid_days=config['INVITE_MAX_VALID_DAYS'])}}</small>
</div>
{% if allow_signup %}
<div class="form-group">
<label for="allow-signup">{{_('Account Registration')}}</label>
<select class="form-control" id="allow-signup" name="allow-signup">
<option value="1" {{ 'selected' if request.values.get('allow-signup', '1') == '1' }}>{{_('Link allows account registration')}}</option>
<option value="0" {{ 'selected' if request.values.get('allow-signup', '1') == '0' }}>{{_('No account registration allowed')}}</option>
</select>
</div>
{% else %}
<input type="hidden" name="allow-signup" value="0">
{% endif %}
{% if roles %}
<div class="form-group">
<label for="valid-until">{{_('Granted Roles')}}</label>
<table class="table table-sm">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">{{_('Name')}}</th>
<th scope="col">{{_('Description')}}</th>
</tr>
</thead>
<tbody>
{% for role in roles|sort(attribute="name") if not role.is_default %}
<tr>
<td>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="role-{{ role.id }}" name="role-{{ role.id }}" value="1" {{ 'checked' if 'role-%d'%role.id in request.values }}>
</div>
</td>
<td>{{ role.name }}</td>
<td>{{ role.description }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
<button type="submit" class="btn btn-primary"><i class="fa fa-save" aria-hidden="true"></i> {{_('Create Link')}}</button>
<a href="{{ url_for("invite.index") }}" class="btn btn-secondary">{{_('Cancel')}}</a>
</form>
{% endblock %}
{% extends 'base_narrow.html' %}
{% block body %}
<div class="col-12 mb-3">
<h2 class="text-center">{{_('Invite Link')}}</h2>
</div>
{% if not request.user %}
<p>{{_('Welcome to the %(org_name)s Single-Sign-On!', org_name=config.ORGANISATION_NAME)}}</p>
{% endif %}
{% if invite.roles and invite.allow_signup %}
<p>{{_('With this link you can register a new user account with the following roles or add the roles to an existing account:')}}</p>
{% elif invite.roles %}
<p>{{_('With this link you can add the following roles to an existing account:')}}</p>
{% elif invite.allow_signup %}
<p>{{_('With this link you can register a new user account.')}}</p>
{% endif %}
{% if invite.roles %}
<ul>
{% for role in invite.roles %}
<li>{{ role.name }}{% if role.description %}: {{ role.description }}{% endif %}</li>
{% endfor %}
</ul>
{% endif %}
{% if request.user %}
{% if invite.roles %}
<form method="POST" action="{{ url_for("invite.grant", invite_id=invite.id, token=invite.token) }}" class="mb-2">
<button type="submit" class="btn btn-primary btn-block">{{_('Add the roles to your account now')}}</button>
</form>
<a href="{{ url_for("session.logout", ref=url_for("session.login", ref=request.full_path)) }}" class="btn btn-secondary btn-block">{{_('Logout and switch to a different account')}}</a>
{% endif %}
{% if invite.allow_signup %}
<a href="{{ url_for("session.logout", ref=url_for("invite.signup_start", invite_id=invite.id, token=invite.token)) }}" class="btn btn-secondary btn-block">{{_('Logout to register a new account')}}</a>
{% endif %}
{% else %}
{% if invite.allow_signup %}
<a href="{{ url_for("invite.signup_start", invite_id=invite.id, token=invite.token) }}" class="btn btn-primary btn-block">{{_('Register a new account')}}</a>
{% endif %}
{% if invite.roles %}
<a href="{{ url_for("session.login", ref=request.full_path) }}" class="btn btn-primary btn-block">{{_('Login and add the roles to your account')}}</a>
{% endif %}
{% endif %}
{% endblock %}
......@@ -3,50 +3,41 @@
{% block body %}
<div class="row">
<div class="col">
<p class="text-right">
<a class="btn btn-primary" href="{{ url_for("mail.show") }}">
<i class="fa fa-plus" aria-hidden="true"></i> {{_('New')}}
</a>
</p>
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">name</th>
<th scope="col">receiving address</th>
<th scope="col">destinations</th>
<th scope="col">
<p class="text-right">
<a class="btn btn-primary" href="{{ url_for("mail.show") }}">
<i class="fa fa-plus" aria-hidden="true"></i> New
</a>
</p>
</th>
<th scope="col">{{_('Name')}}</th>
<th scope="col">{{_('Receiving addresses')}}</th>
<th scope="col">{{_('Destinations')}}</th>
</tr>
</thead>
<tbody>
{% for mail in mails|sort(attribute="uid") %}
<tr id="mail-{{ mail.uid }}">
<tr id="mail-{{ mail.id }}">
<th scope="row">
<a href="{{ url_for("mail.show", uid=mail.uid) }}">
<a href="{{ url_for("mail.show", mail_id=mail.id) }}">
{{ mail.uid }}
</a>
</th>
<td>
<ul>
<ul class="m-0">
{% for i in mail.receivers %}
<li>{{ i }}</li>
{% endfor %}
</ul>
</td>
<td>
<ul>
<ul class="m-0">
{% for i in mail.destinations %}
<li>{{ i }}</li>
{% endfor %}
</ul>
</td>
<td>
<p class="text-right">
<a href="{{ url_for("mail.show", uid=mail.uid) }}" class="btn btn-primary">
<i class="fa fa-edit" aria-hidden="true"></i> Edit
</a>
</p>
</td>
</tr>
{% endfor %}
</tbody>
......
{% extends 'base.html' %}
{% block body %}
<form action="{{ url_for("mail.update", uid=mail.uid) }}" method="POST">
<form action="{{ url_for("mail.update", mail_id=mail.id) }}" method="POST" autocomplete="off">
<div class="align-self-center">
<div class="form-group col">
<label for="mail-name">Name</label>
<input type="text" class="form-control" id="mail-name" name="mail-uid" {% if mail.uid %} value="{{ mail.uid }}" readonly {% else %} value=""{% endif %}>
<label for="mail-name">{{_('Name')}}</label>
<input type="text" class="form-control" id="mail-name" name="mail-uid" {% if mail.id %} value="{{ mail.uid }}" readonly {% else %} value=""{% endif %}>
<small class="form-text text-muted">
</small>
</div>
<div class="form-group col">
<label for="mail-receivers">Receiving addresses</label>
<label for="mail-receivers">{{_('Receiving addresses')}}</label>
<textarea rows="10" class="form-control" id="mail-receivers" name="mail-receivers">{{ mail.receivers|join('\n') }}</textarea>
<small class="form-text text-muted">
One address per line
{{_('One address pattern (local+ext@domain, local@domain, local, @domain) per line. Only lower-case ASCII letters, digits and symbols.')}}
</small>
</div>
<div class="form-group col">
<label for="mail-destinations">Destinations</label>
<label for="mail-destinations">{{_('Destinations')}}</label>
<textarea rows="10" class="form-control" id="mail-destinations" name="mail-destinations">{{ mail.destinations|join('\n') }}</textarea>
<small class="form-text text-muted">
One address per line
{{_('One address per line')}}
</small>
</div>
<div class="form-group col">
<button type="submit" class="btn btn-primary"><i class="fa fa-save" aria-hidden="true"></i> Save</button>
<a href="{{ url_for("mail.index") }}" class="btn btn-secondary">Cancel</a>
{% if mail.uid %}
<a href="{{ url_for("mail.delete", uid=mail.uid) }}" class="btn btn-danger"><i class="fa fa-trash" aria-hidden="true"></i> Delete</a>
<button type="submit" class="btn btn-primary"><i class="fa fa-save" aria-hidden="true"></i> {{_('Save')}}</button>
<a href="{{ url_for("mail.index") }}" class="btn btn-secondary">{{_('Cancel')}}</a>
{% if mail.id %}
<a href="{{ url_for("mail.delete", mail_id=mail.id) }}" class="btn btn-danger"><i class="fa fa-trash" aria-hidden="true"></i> {{_('Delete')}}</a>
{% else %}
<a href="#" class="btn btn-danger disabled"><i class="fa fa-trash" aria-hidden="true"></i> Delete</a>
<a href="#" class="btn btn-danger disabled"><i class="fa fa-trash" aria-hidden="true"></i> {{_('Delete')}}</a>
{% endif %}
</div>
</div>
......
......@@ -3,14 +3,6 @@
{% block body %}
<h1>OAuth2.0 Authorization Error</h1>
<p><b>Error: {{ error }}</b> {{ '(' + error_description + ')' if error_description else '' }}</p>
{% if args %}
<p>Parameters:</p>
<ul>
{% for key, value in args.items() %}
<li>{{ key }}={{ value }}</li>
{% endfor %}
</ul>
{% endif %}
<hr>
......
{% extends 'base.html' %}
{% extends 'base_narrow.html' %}
{% block body %}
<div class="row mt-2 justify-content-center">
<div class="col-lg-6 col-md-10" style="background: #f7f7f7; box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); padding: 30px;">
<div class="text-center">
<img alt="CCC logo" src="{{ url_for("static", filename="chaosknoten.png") }}" class="col-lg-8 col-md-12" >
</div>
<div class="col-12">
<h2 class="text-center">Logout</h2>
</div>
<div class="col-12">
<h2 class="text-center">{{_('Logout')}}</h2>
</div>
<div class="col-12">
<noscript>
<div class="alert alert-warning" role="alert">Javascript is required for automatic logout</div>
</noscript>
<p>While you successfully logged out of the Single-Sign-On service, you may still be logged in on these services:</p>
<ul>
{% for client in clients if client.logout_urls %}
<li class="client" data-urls='{{ client.logout_urls|tojson }}'>
{{ client.client_id }}
<span class="status-active spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
<i class="status-success fas fa-check d-none"></i>
<i class="status-failed fas fa-exclamation d-none"></i>
</li>
{% endfor %}
</ul>
<div class="col-12">
<noscript>
<div class="alert alert-warning" role="alert">{{_('Javascript is required for automatic logout')}}</div>
</noscript>
<p>{{_('While you successfully logged out of the Single-Sign-On service, you may still be logged in on these services:')}}</p>
<ul>
{% for client in clients if client.logout_uris %}
<li class="client" data-urls='{{ client.logout_uris_json }}'>
{{ client.service.name }}
<span class="status-active spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
<i class="status-success fas fa-check d-none"></i>
<i class="status-failed fas fa-exclamation d-none"></i>
</li>
{% endfor %}
</ul>
<p>
Please wait until you have been automatically logged out of all services or make sure of this yourself.
</p>
<p>
{{_('Please wait until you have been automatically logged out of all services or make sure of this yourself.')}}
</p>
<button id="retry-button" class="btn btn-block btn-primary d-none" disabled>
<span id="cont-text">Logging you out on all services ...</span>
</button>
<button id="retry-button" class="btn btn-block btn-primary d-none" disabled>
<span id="cont-text">{{_('Logging you out on all services ...')}}</span>
</button>
<a href="{{ request.values.get('ref') or '/' }}" class="btn btn-block btn-secondary">
<span>Skip this and continue</span>
</a>
<a href="{{ request.values.get('ref') or '/' }}" class="btn btn-block btn-secondary">
<span>{{_('Skip this and continue')}}</span>
</a>
</div>
</div>
</div>
<script>
......@@ -60,7 +53,6 @@ function logout_services() {
});
});
p = p.then(function () {
console.log('done', elem);
elem.find('.status-active').addClass('d-none');
elem.find('.status-success').removeClass('d-none');
elem.removeClass('client');
......@@ -68,22 +60,20 @@ function logout_services() {
.catch(function (err) {
elem.find('.status-active').addClass('d-none');
elem.find('.status-failed').removeClass('d-none');
console.log(err);
throw err;
});
all_promises.push(p);
});
Promise.allSettled(all_promises).then(function (results) {
console.log(results);
for (result of results) {
if (result.status == 'rejected')
throw result.reason;
}
$('#cont-text').text('Done, redirecting ...');
$('#cont-text').text({{_('Done, redirecting ...')|tojson}});
window.location = {{ (request.values.get('ref') or '/')|tojson }};
}).catch(function (err) {
$("#retry-button").prop('disabled', false);
$('#cont-text').text('Log out failed on some services. Retry?');
$('#cont-text').text({{_('Log out failed on some services. Retry?')|tojson}});
});
}
......
......@@ -3,40 +3,29 @@
{% block body %}
<div class="row">
<div class="col">
<table class="table table-striped">
<p class="text-right">
<a class="btn btn-primary" href="{{ url_for("role.new") }}">
<i class="fa fa-plus" aria-hidden="true"></i> {{_("New")}}
</a>
</p>
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">id</th>
<th scope="col">name</th>
<th scope="col">description</th>
<th scope="col">
<p class="text-right">
<a class="btn btn-primary" href="{{ url_for("role.show") }}">
<i class="fa fa-plus" aria-hidden="true"></i> New
</a>
</p>
</th>
<th scope="col">{{_("Name")}}</th>
<th scope="col">{{_("Description")}}</th>
</tr>
</thead>
<tbody>
{% for role in roles|sort(attribute="name") %}
<tr id="role-{{ role.id }}">
<td>
{{ role.id }}
</td>
<th scope="row">
{{ role.name }}
<a href="{{ url_for("role.show", roleid=role.id) }}">
{{ role.name or _('<empty name>') }}
</a>
</th>
<td>
{{ role.description }}
</td>
<td>
<p class="text-right">
<a href="{{ url_for("role.show", roleid=role.id) }}" class="btn btn-primary">
<i class="fa fa-edit" aria-hidden="true"></i> Edit
</a>
</p>
</td>
</tr>
{% endfor %}
</tbody>
......
{% extends 'base.html' %}
{% block body %}
{% if role.locked %}
<div class="alert alert-warning" role="alert">
{{_("Name, moderator group, included roles and groups of this role are managed externally.")}} <a href="{{ url_for("role.unlock", roleid=role.id) }}" class="alert-link">Unlock this role</a> to edit them at the risk of having your changes overwritten.
</div>
{% endif %}
<form action="{{ url_for("role.update", roleid=role.id) }}" method="POST" autocomplete="off">
<div class="align-self-center">
<div class="clearfix pb-2"><div class="float-sm-right">
<button type="submit" class="btn btn-primary"><i class="fa fa-save" aria-hidden="true"></i> {{_("Save")}}</button>
<a href="{{ url_for("role.index") }}" class="btn btn-secondary">{{_("Cancel")}}</a>
{% if role.id %}
{% if not role.is_default %}
<a href="{{ url_for("role.set_default", roleid=role.id) }}" onClick='return confirm({{_("All non-service users will be removed as members from this role and get its permissions implicitly. Are you sure?")|tojson}});' class="btn btn-secondary">{{_("Set as default")}}</a>
{% else %}
<a href="{{ url_for("role.unset_default", roleid=role.id) }}" onClick='return confirm({{_("Are you sure?")|tojson}});' class="btn btn-secondary">{{_("Unset as default")}}</a>
{% endif %}
<a href="{{ url_for("role.delete", roleid=role.id) }}" onClick='return confirm({{_("Are you sure?")|tojson}});' class="btn btn-danger {{ 'disabled' if role.locked }}"><i class="fa fa-trash" aria-hidden="true"></i> {{_("Delete")}}</a>
{% else %}
<a href="#" class="btn btn-secondary disabled">{{_("Set as default")}}</a>
<a href="#" class="btn btn-danger disabled"><i class="fa fa-trash" aria-hidden="true"></i> {{_("Delete")}}</a>
{% endif %}
</div></div>
<ul class="nav nav-tabs pt-2 border-0" id="tablist" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="settings-tab" data-toggle="tab" href="#settings" role="tab" aria-controls="settings" aria-selected="true">{{_("Settings")}}</a>
</li>
<li class="nav-item">
<a class="nav-link" id="roles-tab" data-toggle="tab" href="#roles" role="tab" aria-controls="roles" aria-selected="false">{{_("Included roles")}} <span class="badge badge-pill badge-secondary">{{ role.included_roles|length }}</span></a>
</li>
<li class="nav-item">
<a class="nav-link" id="groups-tab" data-toggle="tab" href="#groups" role="tab" aria-controls="groups" aria-selected="false">{{_("Included groups")}} <span class="badge badge-pill badge-secondary">{{ role.groups|length }}</span></a>
</li>
</ul>
<div class="tab-content border mb-2 pt-2" id="tabcontent">
<div class="tab-pane fade show active" id="settings" role="tabpanel" aria-labelledby="settings-tab">
<div class="form-group col">
<label for="role-name">{{_("Role Name")}}</label>
<input type="text" class="form-control" id="role-name" name="name" value="{{ role.name or '' }}" {{ 'disabled' if role.locked }}>
<small class="form-text text-muted">
</small>
</div>
<div class="form-group col">
<label for="role-description">{{_("Description")}}</label>
<textarea class="form-control" id="role-description" name="description" rows="5">{{ role.description or '' }}</textarea>
<small class="form-text text-muted">
</small>
</div>
<div class="form-group col">
<label for="moderator-group">{{_("Moderator Group")}}</label>
<select class="form-control" id="moderator-group" name="moderator-group" {{ 'disabled' if role.locked }}>
<option value="" class="text-muted">{{_("No Moderator Group")}}</option>
{% for group in groups %}
<option value="{{ group.id }}" {{ 'selected' if group == role.moderator_group }}>{{ group.name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group col">
<span>{{_("Moderators")}}:</span>
<ul class="row">
{% for moderator in role.moderator_group.members %}
<li class="col-12 col-xs-6 col-sm-4 col-md-3 col-lg-2"><a href="{{ url_for("user.show", id=moderator.id) }}">{{ moderator.loginname }}</a></li>
{% endfor %}
</ul>
</div>
<div class="form-group col">
<span>{{_("Members")}}:</span>
<ul class="row">
{% for member in role.members|sort(attribute='loginname') %}
<li class="col-12 col-xs-6 col-sm-4 col-md-3 col-lg-2"><a href="{{ url_for("user.show", id=member.id) }}">{{ member.loginname }}</a></li>
{% endfor %}
</ul>
</div>
</div>
<div class="tab-pane fade" id="roles" role="tabpanel" aria-labelledby="roles-tab">
<div class="form-group col">
<span>{{_("Roles to include groups from recursively")}}</span>
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">{{_("name")}}</th>
<th scope="col">{{_("description")}}</th>
<th scope="col">{{_("currently includes groups")}}</th>
</tr>
</thead>
<tbody>
{% for r in roles|sort(attribute="name")|sort(attribute='name') %}
<tr id="include-role-{{ r.id }}">
<td>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="include-role-{{ r.id }}-checkbox" name="include-role-{{ r.id }}" value="1" aria-label="enabled"
{% if r == role or role.locked %} disabled{% endif %}
{% if r in role.included_roles %} checked{% endif %}>
</div>
</td>
<td>
<a href="{{ url_for("role.show", roleid=r.id) }}">
{{ r.name }}
</a>
</td>
<td>
{{ r.description }}
</td>
<td>
{% for group in r.groups_effective|sort(attribute='name') %}
<a href="{{ url_for("group.show", id=group.id) }}">{{ group.name }}</a>{{ ', ' if not loop.last }}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="tab-pane fade" id="groups" role="tabpanel" aria-labelledby="groups-tab">
<div class="form-group col">
<span>{{_("Included groups")}}</span>
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">{{_("name")}}</th>
<th scope="col">{{_("description")}}</th>
<th scope="col">{{_("2FA required")}}</th>
</tr>
</thead>
<tbody>
{% for group in groups|sort(attribute="name") %}
<tr id="group-{{ group.id }}">
<td>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="group-{{ group.id }}-checkbox" name="group-{{ group.id }}" value="1" aria-label="enabled" {% if group in role.groups %}checked{% endif %} {{ 'disabled' if role.locked }}>
</div>
</td>
<td>
<a href="{{ url_for("group.show", id=group.id) }}">
{{ group.name }}
</a>
</td>
<td>
{{ group.description }}
</td>
<td>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="group-mfa-{{ group.id }}-checkbox" name="group-mfa-{{ group.id }}" value="1" aria-label="enabled" {% if group in role.groups and role.groups[group].requires_mfa %}checked{% endif %} {{ 'disabled' if role.locked }}>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</form>
{% endblock %}