511 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			511 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div ref="dialogBackground" class="dialog-background" v-if="visible" @click="bgClicked">
 | |
|     <div class="dialog-window" :class="{
 | |
|       fullscreen: isFullscreen,
 | |
|       'max-size': maxSize,
 | |
|       playing: $store.getters['player/isPlaying'],
 | |
|     }">
 | |
|       <div class="dialog-header" :class="{ hideOnMobile: showHeaderOnMobile == false, 'flat-dialog-header': flatDialogHeader == true }" v-if="showHeader" @dblclick="headerDoubleClick">
 | |
|         <div class="dialog-header-left">
 | |
|           <slot name="header-left" />
 | |
|         </div>
 | |
|         <div class="dialog-header-center">
 | |
|           <h3 v-if="dialogTitle && !flatDialogHeader">{{ dialogTitle }}</h3>
 | |
|           <slot name="header-center" />
 | |
|         </div>
 | |
|         <div class="dialog-header-right">
 | |
|           <slot name="header-right" />
 | |
|           <button class="hideOnMobile" @click="isFullscreen = !isFullscreen" v-if="showFullscreenButton" :title="isFullscreen ? 'Restore' : 'Fullscreen'">
 | |
|             <awesome-icon v-if="isFullscreen" icon="compress" />
 | |
|             <awesome-icon v-else icon="expand" />
 | |
|           </button>
 | |
|           <button @click="cancel" class="red" v-if="showCloseButton" title="Close">
 | |
|             <awesome-icon icon="times" />
 | |
|           </button>
 | |
|         </div>
 | |
|       </div>
 | |
|       <div class="dialog-body" :class="{ hideXScroll: disableXscroll == true, hideYScroll: disableYscroll == true, 'flat-dialog-header': flatDialogHeader == true }">
 | |
|         <slot />
 | |
|         <div class="dialog-body-content" v-if="dialogContent" v-html="dialogContent" />
 | |
|       </div>
 | |
|       <div class="dialog-footer" v-if="showFooter">
 | |
|         <div class="dialog-footer-left">
 | |
|           <span v-if="messageText" class="dialog-message" :class="messageClass">
 | |
|             <awesome-icon v-if="messageIcon" :icon="messageIcon" />
 | |
|             {{ messageText }}
 | |
|           </span>
 | |
|           <slot name="footer-left" />
 | |
|         </div>
 | |
|         <div class="dialog-footer-center">
 | |
|           <slot name="footer-center" />
 | |
|         </div>
 | |
|         <div>
 | |
|           <slot name="footer-right" />
 | |
|           <div class="dialog-footer-controls" v-if="showFooterButtons &&
 | |
|             (openButtons == null || openButtons.length > 0)
 | |
|             ">
 | |
|             <button v-for="(  button, i  ) in   dialogButtons  " :key="i" @click="click('clicked', button.text || button)" :class="button.class || ''" :disabled="button.disabled" :title="button.title || ''" v-show="button.visible != false">
 | |
|               <awesome-icon v-if="button.icon" :icon="button.icon" class="ma-right8" />
 | |
|               {{ button.text || button }}
 | |
|             </button>
 | |
|             <button ref="dialogButton" @click="click('accept')" v-if="showFooterButtons && !dialogButtons" :disabled="!enableFooterButtons" :class="buttonClass">
 | |
|               <awesome-icon v-if="buttonIcon" :icon="buttonIcon" class="ma-right8" />
 | |
|               {{ buttonText }}
 | |
|             </button>
 | |
|           </div>
 | |
|         </div>
 | |
|       </div>
 | |
|     </div>
 | |
|   </div>
 | |
| </template>
 | |
| <script>
 | |
| export default {
 | |
|   name: "DialogControl",
 | |
|   props: {
 | |
|     title: { type: String, default: "" },
 | |
|     content: { type: String, default: "" },
 | |
|     closeOnEscape: {
 | |
|       type: Boolean,
 | |
|       default: true,
 | |
|     },
 | |
|     closeOnFocusLost: {
 | |
|       type: Boolean,
 | |
|       default: true,
 | |
|     },
 | |
|     closeOnButtonClick: {
 | |
|       type: Boolean,
 | |
|       default: true,
 | |
|     },
 | |
|     disableXscroll: {
 | |
|       type: Boolean,
 | |
|       default: false,
 | |
|     },
 | |
|     disableYscroll: {
 | |
|       type: Boolean,
 | |
|       default: false,
 | |
|     },
 | |
|     flatDialogHeader: {
 | |
|       type: Boolean,
 | |
|       default: false
 | |
|     },
 | |
|     showFooter: {
 | |
|       type: Boolean,
 | |
|       default: true,
 | |
|     },
 | |
|     showHeader: {
 | |
|       type: Boolean,
 | |
|       default: true,
 | |
|     },
 | |
|     showHeaderOnMobile: {
 | |
|       type: Boolean,
 | |
|       default: true,
 | |
|     },
 | |
|     showCloseButton: {
 | |
|       type: Boolean,
 | |
|       default: true,
 | |
|     },
 | |
|     showFooterButtons: {
 | |
|       type: Boolean,
 | |
|       default: true,
 | |
|     },
 | |
|     showFullscreenButton: {
 | |
|       type: Boolean,
 | |
|       default: false,
 | |
|     },
 | |
|     enableFooterButtons: {
 | |
|       type: Boolean,
 | |
|       default: true,
 | |
|     },
 | |
|     buttonText: {
 | |
|       type: String,
 | |
|       default: "Done",
 | |
|     },
 | |
|     buttonClass: {
 | |
|       type: String,
 | |
|       default: "",
 | |
|     },
 | |
|     buttonIcon: {
 | |
|       type: String,
 | |
|       default: "",
 | |
|     },
 | |
|     buttons: {
 | |
|       type: Array,
 | |
|     },
 | |
|     maxSize: {
 | |
|       type: Boolean,
 | |
|       default: false,
 | |
|     },
 | |
|   },
 | |
|   data() {
 | |
|     return {
 | |
|       visible: false,
 | |
|       openTitle: "",
 | |
|       openContent: "",
 | |
|       openButtons: null,
 | |
|       isFullscreen: false,
 | |
|       callback: null,
 | |
|       messageText: "",
 | |
|       messageClass: "",
 | |
|       messageIcon: "",
 | |
|     };
 | |
|   },
 | |
|   methods: {
 | |
|     open(title = null, content = null, buttons = null, callback = null) {
 | |
|       this.visible = true;
 | |
|       if (title) {
 | |
|         this.openTitle = title;
 | |
|       }
 | |
|       if (content) {
 | |
|         this.openContent = content;
 | |
|       }
 | |
|       if (buttons) {
 | |
|         this.openButtons = buttons;
 | |
|       }
 | |
|       if (callback) {
 | |
|         this.callback = callback;
 | |
|       }
 | |
|       window.addEventListener("keydown", this.keydownListener);
 | |
|       this.focusButton();
 | |
|       this.$emit("opened");
 | |
|     },
 | |
|     close() {
 | |
|       this.$emit("closing");
 | |
|       this.visible = false;
 | |
|       window.removeEventListener("keydown", this.keydownListener);
 | |
|       this.$emit("closed");
 | |
|       if (this.callback) {
 | |
|         this.callback();
 | |
|       }
 | |
|     },
 | |
|     cancel() {
 | |
|       this.$emit("canceled");
 | |
|       this.close();
 | |
|     },
 | |
|     focusButton() {
 | |
|       this.$nextTick(() => {
 | |
|         if (this.$refs.dialogButton) {
 | |
|           this.$refs.dialogButton.focus();
 | |
|         }
 | |
|       });
 | |
|     },
 | |
|     click(name, parameter = null) {
 | |
|       this.$emit(name, parameter);
 | |
|       if (this.callback) {
 | |
|         this.callback(parameter || name);
 | |
|         this.callback = undefined;
 | |
|       }
 | |
|       if (this.closeOnButtonClick) {
 | |
|         this.close();
 | |
|       }
 | |
|     },
 | |
|     bgClicked(e) {
 | |
|       if (
 | |
|         e.srcElement == this.$refs.dialogBackground &&
 | |
|         this.closeOnFocusLost
 | |
|       ) {
 | |
|         this.cancel();
 | |
|       }
 | |
|     },
 | |
|     headerDoubleClick() {
 | |
|       if (this.showFullscreenButton) {
 | |
|         this.isFullscreen = !this.isFullscreen;
 | |
|       }
 | |
|     },
 | |
|     keydownListener(e) {
 | |
|       if (e.key == "Escape" && this.closeOnEscape) {
 | |
|         e.preventDefault();
 | |
|         this.cancel();
 | |
|       }
 | |
|     },
 | |
|   },
 | |
|   computed: {
 | |
|     dialogTitle() {
 | |
|       return this.openTitle || this.title;
 | |
|     },
 | |
|     dialogButtons() {
 | |
|       return this.openButtons || this.buttons;
 | |
|     },
 | |
|     dialogContent() {
 | |
|       return this.openContent || this.content;
 | |
|     },
 | |
|   },
 | |
| };
 | |
| </script>
 | |
| 
 | |
| <style>
 | |
| .dialog-background {
 | |
|   position: fixed;
 | |
|   display: flex;
 | |
|   align-items: center;
 | |
|   justify-content: center;
 | |
|   background-color: #00000080;
 | |
|   top: 0;
 | |
|   left: 0;
 | |
|   right: 0;
 | |
|   bottom: 0;
 | |
|   z-index: 1000;
 | |
|   animation: fadeIn ease 0.20s;
 | |
| }
 | |
| 
 | |
| .dialog-window {
 | |
|   box-shadow: 0px 8px 32px var(--shadow);
 | |
|   background-color: var(--white);
 | |
|   max-width: 90%;
 | |
|   max-height: 80%;
 | |
|   display: flex;
 | |
|   flex-direction: column;
 | |
|   border-top-left-radius: 8px;
 | |
|   border-top-right-radius: 8px;
 | |
|   position: absolute;
 | |
| }
 | |
| 
 | |
| .dialog-window.max-size {
 | |
|   width: 90%;
 | |
|   height: 90%;
 | |
| }
 | |
| 
 | |
| .dialog-window.fullscreen {
 | |
|   max-width: initial;
 | |
|   max-height: initial;
 | |
|   width: 100%;
 | |
|   height: 100%;
 | |
|   border-top-left-radius: 0px;
 | |
|   border-top-right-radius: 0px;
 | |
| }
 | |
| 
 | |
| .dialog-header {
 | |
|   display: flex;
 | |
|   flex-shrink: 0;
 | |
|   background-color: var(--background);
 | |
|   box-shadow: 0px 1px 4px var(--shadow);
 | |
|   border-top-left-radius: 8px;
 | |
|   border-top-right-radius: 8px;
 | |
|   z-index: 1;
 | |
| }
 | |
| 
 | |
| .dialog-header.flat-dialog-header {
 | |
|   background: transparent;
 | |
|   position: absolute;
 | |
|   left: 0;
 | |
|   right: 0;
 | |
|   top: 0;
 | |
|   box-shadow: none;
 | |
|   z-index: 101;
 | |
| }
 | |
| 
 | |
| .dialog-header h3 {
 | |
|   flex-grow: 1;
 | |
|   margin: 0;
 | |
|   font-size: 0.9rem;
 | |
|   font-weight: bold;
 | |
|   white-space: nowrap;
 | |
|   overflow: hidden;
 | |
|   text-overflow: ellipsis;
 | |
|   align-self: center;
 | |
|   cursor: default;
 | |
| }
 | |
| 
 | |
| .dialog-header input,
 | |
| .dialog-header select {
 | |
|   padding: 0 4px;
 | |
|   border: 0;
 | |
|   border-radius: 0;
 | |
|   background-color: var(--white);
 | |
|   align-self: stretch;
 | |
| }
 | |
| 
 | |
| .dialog-header button,
 | |
| .dialog-header a {
 | |
|   background-color: transparent;
 | |
|   border: 0;
 | |
|   border-radius: 16px;
 | |
|   padding: 4px;
 | |
|   margin: 2px;
 | |
|   cursor: pointer;
 | |
| }
 | |
| 
 | |
| .dialog-header button:hover {
 | |
|   background-color: var(--light-gray);
 | |
| }
 | |
| 
 | |
| .dialog-header button.red:hover {
 | |
|   background-color: var(--red50);
 | |
|   color: var(--white);
 | |
| }
 | |
| 
 | |
| .dialog-header button.red svg {
 | |
|   color: var(--red);
 | |
| }
 | |
| 
 | |
| .dialog-header button.red:hover svg {
 | |
|   color: var(--white);
 | |
| }
 | |
| 
 | |
| .dialog-header button.blue {
 | |
|   background-color: var(--blue);
 | |
| }
 | |
| 
 | |
| .dialog-header button.green:hover {
 | |
|   background-color: var(--green);
 | |
|   color: var(--green);
 | |
| }
 | |
| 
 | |
| .dialog-header button.green svg {
 | |
|   color: var(--green);
 | |
| }
 | |
| 
 | |
| .dialog-header button.yellow {
 | |
|   background-color: var(--yellow);
 | |
| }
 | |
| 
 | |
| /* SUCCESS */
 | |
| .dialog-header button.success svg {
 | |
|   color: var(--success);
 | |
| }
 | |
| 
 | |
| .dialog-header button.success:hover {
 | |
|   background-color: var(--success);
 | |
| }
 | |
| 
 | |
| .dialog-header button.success:hover svg {
 | |
|   color: var(--white);
 | |
| }
 | |
| 
 | |
| .dialog-header button.primary,
 | |
| .dialog-header a.primary {
 | |
|   background-color: var(--primary);
 | |
|   color: var(--white);
 | |
| }
 | |
| 
 | |
| .dialog-header button>span,
 | |
| .dialog-header a>span {
 | |
|   margin-left: 12px;
 | |
| }
 | |
| 
 | |
| .dialog-header svg {
 | |
|   width: 16px !important;
 | |
|   height: 16px;
 | |
| }
 | |
| 
 | |
| .dialog-header>div,
 | |
| .dialog-footer>div {
 | |
|   display: flex;
 | |
|   align-items: center;
 | |
| }
 | |
| 
 | |
| .dialog-header>.dialog-header-center,
 | |
| .dialog-footer>.dialog-footer-center {
 | |
|   flex-grow: 1;
 | |
|   justify-content: center;
 | |
|   margin: 0 12px;
 | |
| }
 | |
| 
 | |
| .dialog-header>.dialog-header-right input,
 | |
| .dialog-header>.dialog-header-right select {
 | |
|   border-left: 1px solid var(--light-border);
 | |
| }
 | |
| 
 | |
| .dialog-header.flat-dialog-header>.dialog-header-right>button {
 | |
|   color: var(--white);
 | |
| }
 | |
| 
 | |
| .dialog-header.flat-dialog-header>.dialog-header-right>button:hover {
 | |
|   color: var(--gray);
 | |
| }
 | |
| 
 | |
| .dialog-body {
 | |
|   display: flex;
 | |
|   flex-direction: column;
 | |
|   overflow-y: auto;
 | |
|   flex-grow: 1;
 | |
| }
 | |
| 
 | |
| 
 | |
| .dialog-body.flat-dialog-header {
 | |
|   border-top-left-radius: 8px;
 | |
|   border-top-right-radius: 8px;
 | |
| }
 | |
| 
 | |
| .dialog-window.fullscreen .dialog-body.flat-dialog-header {
 | |
|   border-top-left-radius: 0px;
 | |
|   border-top-right-radius: 0px;
 | |
| }
 | |
| 
 | |
| .dialog-body.hideXScroll {
 | |
|   overflow-x: hidden;
 | |
| }
 | |
| 
 | |
| .dialog-body.hideYScroll {
 | |
|   overflow-y: hidden;
 | |
| }
 | |
| 
 | |
| .dialog-body-content {
 | |
|   margin: 4px;
 | |
|   display: flex;
 | |
|   flex-direction: column;
 | |
| }
 | |
| 
 | |
| .dialog-footer {
 | |
|   border-top: 1px solid var(--light-border);
 | |
|   display: flex;
 | |
|   flex-shrink: 0;
 | |
|   align-items: center;
 | |
|   background-color: var(--background);
 | |
| }
 | |
| 
 | |
| .dialog-footer button:disabled {
 | |
|   opacity: 0.5;
 | |
| }
 | |
| 
 | |
| .dialog-footer .dialog-message {
 | |
|   flex-grow: 1;
 | |
|   display: flex;
 | |
|   align-items: center;
 | |
|   margin-left: 4px;
 | |
| }
 | |
| 
 | |
| .dialog-footer .dialog-message svg {
 | |
|   margin-right: 4px;
 | |
| }
 | |
| 
 | |
| .dialog-footer .dialog-footer-controls {
 | |
|   padding: 4px;
 | |
|   display: flex;
 | |
| }
 | |
| 
 | |
| .dialog-footer .dialog-footer-controls button:not(:last-child) {
 | |
|   margin-right: 4px;
 | |
| }
 | |
| 
 | |
| @media (max-width: 480px),
 | |
| (max-height: 480px) {
 | |
|   .dialog-window {
 | |
|     max-width: initial;
 | |
|     max-height: initial;
 | |
|     width: 100%;
 | |
|     height: 100%;
 | |
|     border-top-left-radius: 0;
 | |
|     border-top-right-radius: 0;
 | |
|   }
 | |
| 
 | |
|   .dialog-window.max-size {
 | |
|     width: 100%;
 | |
|     height: 100%;
 | |
|   }
 | |
| 
 | |
|   .dialog-header {
 | |
|     border-top-left-radius: 0;
 | |
|     border-top-right-radius: 0;
 | |
|   }
 | |
| 
 | |
|   .dialog-body.flat-dialog-header {
 | |
|     border-top-left-radius: 0;
 | |
|     border-top-right-radius: 0;
 | |
|   }
 | |
| 
 | |
|   .dialog-window.playing {
 | |
|     margin-bottom: 60px;
 | |
|     height: calc(100% - 60px);
 | |
|   }
 | |
| }
 | |
| </style> |