From 0c5d58eca26c102feeab2ff0967b31df13b8f149 Mon Sep 17 00:00:00 2001
From: farbod <zamanifarbod2@gmail.com>
Date: Fri, 28 Jan 2022 09:58:40 +0100
Subject: [PATCH 1/6] courseware-vue-select with drop-up, fixes #274

---
 package-lock.json                             | 17 +++++
 package.json                                  |  1 +
 .../assets/stylesheets/scss/courseware.scss   | 19 ++++-
 .../CoursewareAccordionContainer.vue          |  4 +-
 .../courseware/CoursewareChartBlock.vue       |  5 +-
 .../courseware/CoursewareHeadlineBlock.vue    | 17 +++--
 .../courseware/CoursewareImageMapBlock.vue    |  6 +-
 .../courseware/CoursewareKeyPointBlock.vue    |  8 +-
 .../CoursewareStructuralElement.vue           |  4 +-
 .../courseware/CoursewareTabsContainer.vue    |  4 +-
 .../courseware/CoursewareVueSelect.vue        | 73 +++++++++++++++++++
 resources/vue/courseware-index-app.js         |  2 +
 12 files changed, 135 insertions(+), 25 deletions(-)
 create mode 100755 resources/vue/components/courseware/CoursewareVueSelect.vue

diff --git a/package-lock.json b/package-lock.json
index 8c411fc1d9d..d224e5da624 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,6 +22,7 @@
                 "@fullcalendar/resource-timegrid": "^4.3.0",
                 "@fullcalendar/resource-timeline": "^4.3.0",
                 "@fullcalendar/timegrid": "^4.3.0",
+                "@popperjs/core": "^2.11.2",
                 "autoprefixer": "^10.2.5",
                 "axios": "^0.21.0",
                 "babel-loader": "^8.2.1",
@@ -1307,6 +1308,16 @@
                 "node": ">=10"
             }
         },
+        "node_modules/@popperjs/core": {
+            "version": "2.11.2",
+            "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz",
+            "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==",
+            "dev": true,
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/popperjs"
+            }
+        },
         "node_modules/@trysound/sax": {
             "version": "0.1.1",
             "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz",
@@ -15365,6 +15376,12 @@
                 }
             }
         },
+        "@popperjs/core": {
+            "version": "2.11.2",
+            "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz",
+            "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==",
+            "dev": true
+        },
         "@trysound/sax": {
             "version": "0.1.1",
             "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz",
diff --git a/package.json b/package.json
index 683e2c1039f..e6720293dea 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
         "@fullcalendar/resource-timegrid": "^4.3.0",
         "@fullcalendar/resource-timeline": "^4.3.0",
         "@fullcalendar/timegrid": "^4.3.0",
+        "@popperjs/core": "^2.11.2",
         "autoprefixer": "^10.2.5",
         "axios": "^0.21.0",
         "babel-loader": "^8.2.1",
diff --git a/resources/assets/stylesheets/scss/courseware.scss b/resources/assets/stylesheets/scss/courseware.scss
index 524636c71af..a2be0224bf3 100755
--- a/resources/assets/stylesheets/scss/courseware.scss
+++ b/resources/assets/stylesheets/scss/courseware.scss
@@ -4189,7 +4189,7 @@ cw tiles end
 /*
 vSelect
 */
-.cw-vs-select {
+.cw-vs-select, .cw-vs-select-detachted-ul {
     max-width: 48em;
 
     .vs__dropdown-toggle {
@@ -4205,8 +4205,23 @@ vSelect
         height: 20px;
         margin-right: 4px;
     }
-}
 
+    .vs__dropdown-menu {
+        border-radius: 0;
+    }
+
+    &.cw-vs-select-drop-up {
+        border-bottom: solid thin $content-color-40;
+        border-top: none;
+    }
+
+    &.vs__dropdown-menu {
+        border-radius: 0;
+        border-bottom: none;
+        border-top: solid thin $content-color-40;
+        box-shadow: 0px -3px 6px 0 rgba(0, 0, 0, 0.15);
+    }
+}
 /*
 vSelect end
 */
diff --git a/resources/vue/components/courseware/CoursewareAccordionContainer.vue b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
index 4a318c30f29..1a9a2278182 100755
--- a/resources/vue/components/courseware/CoursewareAccordionContainer.vue
+++ b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
@@ -39,7 +39,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <v-select :options="icons" v-model="section.icon" class="cw-vs-select">
+                        <courseware-vue-select :options="icons" v-model="section.icon" class="cw-vs-select">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -52,7 +52,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label
                         class="cw-container-section-delete"
diff --git a/resources/vue/components/courseware/CoursewareChartBlock.vue b/resources/vue/components/courseware/CoursewareChartBlock.vue
index 4bce8b46c7f..068858651bb 100755
--- a/resources/vue/components/courseware/CoursewareChartBlock.vue
+++ b/resources/vue/components/courseware/CoursewareChartBlock.vue
@@ -49,7 +49,7 @@
                         </label>
                         <label>
                             <translate>Farbe</translate>
-                            <v-select
+                            <courseware-vue-select
                                 :options="colors"
                                 :reduce="colors => colors.value"
                                 label="rgb"
@@ -57,6 +57,7 @@
                                 v-model="item.color"
                                 class="cw-vs-select"
                                 @option:selected="buildChart"
+                                append-to-body
                             >
                                 <template #open-indicator="selectAttributes">
                                     <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
@@ -70,7 +71,7 @@
                                 <template #option="{name, rgb}">
                                     <span class="vs__option-color" :style="{'background-color': 'rgb(' + rgb + ')'}"></span><span>{{name}}</span>
                                 </template>
-                            </v-select>
+                            </courseware-vue-select>
                         </label>
                     </fieldset>
                 </form>
diff --git a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
index 349ac9545c2..e78615c3577 100755
--- a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
+++ b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
@@ -57,7 +57,7 @@
                     </label>
                     <label>
                         <translate>Textfarbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="colors"
                             label="hex"
                             :reduce="color => color.hex"
@@ -77,11 +77,11 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <v-select :clearable="false" :options="icons" v-model="currentIcon" class="cw-vs-select">
+                        <courseware-vue-select :clearable="false" :options="icons" v-model="currentIcon" class="cw-vs-select" append-to-body>
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -94,11 +94,11 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label>
                         <translate>Icon-Farbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="iconColors"
                             label="name"
                             :reduce="iconColor => iconColor.class"
@@ -118,7 +118,7 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label>
                         <translate>Hintergrundtyp</translate>
@@ -129,13 +129,14 @@
                     </label>
                     <label  v-if="currentBackgroundType === 'color'">
                         <translate>Hintergrundfarbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="colors"
                             label="hex"
                             :reduce="color => color.hex"
                             v-model="currentBackgroundColor"
                             :clearable="false"
                             class="cw-vs-select"
+                            append-to-body
                         >
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
@@ -149,7 +150,7 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label v-if="currentBackgroundType === 'image'">
                         <translate>Hintergrundbild</translate>
diff --git a/resources/vue/components/courseware/CoursewareImageMapBlock.vue b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
index 082e2ac9ef3..353af1e17a4 100755
--- a/resources/vue/components/courseware/CoursewareImageMapBlock.vue
+++ b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
@@ -60,7 +60,7 @@
                         >
                             <label>
                                 <translate>Farbe</translate>
-                                <v-select
+                                <courseware-vue-select
                                     :options="colors"
                                     label="name"
                                     :reduce="color => color.class"
@@ -80,7 +80,7 @@
                                     <template #option="{name, rgba}">
                                         <span class="vs__option-color" :style="{'background-color': rgba}"></span><span>{{name}}</span>
                                     </template>
-                                </v-select>
+                                </courseware-vue-select>
                             </label>
                             <label v-if="shape.type === 'arc'" class="cw-block-image-map-dimensions">
                                 X: <input type="number" v-model="shape.data.centerX" @change="drawScreen" /> Y:
@@ -376,7 +376,7 @@ export default {
             shapeWidth = shapeWidth || 0;
 
             let newText = [];
-            
+
             if (shapeWidth <= 0) {
                 return [text];
             }
diff --git a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
index 7c57f2a6e5c..07ca4475d4e 100755
--- a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
+++ b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
@@ -29,7 +29,7 @@
 
                     <label for="cw-keypoint-color">
                         <translate>Farbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="colors"
                             label="icon"
                             :clearable="false"
@@ -49,12 +49,12 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
 
                     <label for="cw-keypoint-icons">
                         <translate>Icon</translate>
-                        <v-select :options="icons" :clearable="false" v-model="currentIcon" class="cw-vs-select">
+                        <courseware-vue-select :options="icons" :clearable="false" v-model="currentIcon" class="cw-vs-select" append-to-body>
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -67,7 +67,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                 </form>
             </template>
diff --git a/resources/vue/components/courseware/CoursewareStructuralElement.vue b/resources/vue/components/courseware/CoursewareStructuralElement.vue
index b67001327e3..92c3ac4485f 100755
--- a/resources/vue/components/courseware/CoursewareStructuralElement.vue
+++ b/resources/vue/components/courseware/CoursewareStructuralElement.vue
@@ -134,7 +134,7 @@
                             <form class="default" @submit.prevent="">
                                 <label>
                                     <translate>Farbe</translate>
-                                    <v-select
+                                    <courseware-vue-select
                                         v-model="currentElement.attributes.payload.color"
                                         :options="colors"
                                         :reduce="(color) => color.class"
@@ -157,7 +157,7 @@
                                             <span class="vs__option-color" :style="{ 'background-color': hex }"></span
                                             ><span>{{ name }}</span>
                                         </template>
-                                    </v-select>
+                                    </courseware-vue-select>
                                 </label>
                                 <label>
                                     <translate>Zweck</translate>
diff --git a/resources/vue/components/courseware/CoursewareTabsContainer.vue b/resources/vue/components/courseware/CoursewareTabsContainer.vue
index f8502bd8542..8718eff4156 100755
--- a/resources/vue/components/courseware/CoursewareTabsContainer.vue
+++ b/resources/vue/components/courseware/CoursewareTabsContainer.vue
@@ -42,7 +42,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <v-select :options="icons" v-model="section.icon" class="cw-vs-select">
+                        <courseware-vue-select :options="icons" v-model="section.icon" class="cw-vs-select">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -55,7 +55,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label
                         class="cw-container-section-delete"
diff --git a/resources/vue/components/courseware/CoursewareVueSelect.vue b/resources/vue/components/courseware/CoursewareVueSelect.vue
new file mode 100755
index 00000000000..96fe15d557a
--- /dev/null
+++ b/resources/vue/components/courseware/CoursewareVueSelect.vue
@@ -0,0 +1,73 @@
+<template>
+    <v-select ref="select"
+        @change="updateValue"
+        v-bind="{...$props, ...$attrs}"
+        v-on="$listeners"
+        :calculate-position="withPopper"
+    >
+        <template v-for="(index, name) in $scopedSlots" v-slot:[name]="data">
+            <slot :name="name" v-bind="data"></slot>
+        </template>
+    </v-select>
+</template>
+
+<script>
+import { createPopper } from '@popperjs/core'
+export default {
+    name: 'courseware-vue-select',
+    inheritAttrs: false,
+    data() {
+        return {
+            placement: 'top'
+        };
+    },
+    methods: {
+        updateValue(val) {
+            this.$emit('input', val)
+        },
+        withPopper(dropdownList, component, { width }) {
+            dropdownList.style.width = width
+            const popper = createPopper(component.$refs.toggle, dropdownList, {
+                placement: this.placement,
+                modifiers: [
+                    {
+                        name: 'offset',
+                        options: {
+                            offset: [0, -1],
+                        },
+                    },
+                    {
+                        name: 'toggleClass',
+                        enabled: true,
+                        phase: 'write',
+                        fn({ state }) {
+                            component.$el.classList.toggle(
+                                'cw-vs-select-drop-up',
+                                state.placement === 'top'
+                            )
+                        },
+                    },
+                ],
+            })
+            return () => popper.destroy()
+        },
+    },
+    mounted() {
+        if (this.$attrs['append-to-body'] !== undefined) {
+            /*
+                Because the ul.vs__dropdown-menu is appending to the body, the default css (.cw-vs-select)
+                won't work anymore, therefore we need to add a css class (.cw-vs-select-detachted-ul) to its class list.
+            */
+            this.$refs.select.$on("open", async () => {
+                await this.$nextTick();
+                await this.$nextTick();
+                this.$refs.select?._vnode.children.forEach(({ elm }) => {
+                    if (elm instanceof HTMLElement && elm.tagName === "UL") {
+                        elm.classList.add('cw-vs-select-detachted-ul');
+                    }
+                });
+            });
+        }
+    }
+};
+</script>
diff --git a/resources/vue/courseware-index-app.js b/resources/vue/courseware-index-app.js
index ffdae6a70c6..616f9c1cd22 100755
--- a/resources/vue/courseware-index-app.js
+++ b/resources/vue/courseware-index-app.js
@@ -10,8 +10,10 @@ import axios from 'axios';
 import { mapResourceModules } from '@elan-ev/reststate-vuex';
 import vSelect from 'vue-select';
 import 'vue-select/dist/vue-select.css'
+import CoursewareVueSelect from './components/courseware/CoursewareVueSelect.vue';
 
 Vue.component('v-select', vSelect);
+Vue.component('courseware-vue-select', CoursewareVueSelect);
 
 const mountApp = (STUDIP, createApp, element) => {
     const getHttpClient = () =>
-- 
GitLab


From 75e456aee314d836edc4e2ddc3025333f0303636 Mon Sep 17 00:00:00 2001
From: farbod <zamanifarbod2@gmail.com>
Date: Fri, 28 Jan 2022 09:58:40 +0100
Subject: [PATCH 2/6] courseware-vue-select with drop-up, fixes #274

---
 package-lock.json                             | 17 +++++
 package.json                                  |  1 +
 .../assets/stylesheets/scss/courseware.scss   | 19 ++++-
 .../CoursewareAccordionContainer.vue          |  4 +-
 .../courseware/CoursewareChartBlock.vue       |  5 +-
 .../courseware/CoursewareHeadlineBlock.vue    | 17 +++--
 .../courseware/CoursewareImageMapBlock.vue    |  6 +-
 .../courseware/CoursewareKeyPointBlock.vue    |  8 +-
 .../CoursewareStructuralElement.vue           |  4 +-
 .../courseware/CoursewareTabsContainer.vue    |  4 +-
 .../courseware/CoursewareVueSelect.vue        | 73 +++++++++++++++++++
 resources/vue/courseware-index-app.js         |  2 +
 12 files changed, 135 insertions(+), 25 deletions(-)
 create mode 100755 resources/vue/components/courseware/CoursewareVueSelect.vue

diff --git a/package-lock.json b/package-lock.json
index 8c411fc1d9d..d224e5da624 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,6 +22,7 @@
                 "@fullcalendar/resource-timegrid": "^4.3.0",
                 "@fullcalendar/resource-timeline": "^4.3.0",
                 "@fullcalendar/timegrid": "^4.3.0",
+                "@popperjs/core": "^2.11.2",
                 "autoprefixer": "^10.2.5",
                 "axios": "^0.21.0",
                 "babel-loader": "^8.2.1",
@@ -1307,6 +1308,16 @@
                 "node": ">=10"
             }
         },
+        "node_modules/@popperjs/core": {
+            "version": "2.11.2",
+            "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz",
+            "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==",
+            "dev": true,
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/popperjs"
+            }
+        },
         "node_modules/@trysound/sax": {
             "version": "0.1.1",
             "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz",
@@ -15365,6 +15376,12 @@
                 }
             }
         },
+        "@popperjs/core": {
+            "version": "2.11.2",
+            "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz",
+            "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==",
+            "dev": true
+        },
         "@trysound/sax": {
             "version": "0.1.1",
             "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz",
diff --git a/package.json b/package.json
index 683e2c1039f..e6720293dea 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
         "@fullcalendar/resource-timegrid": "^4.3.0",
         "@fullcalendar/resource-timeline": "^4.3.0",
         "@fullcalendar/timegrid": "^4.3.0",
+        "@popperjs/core": "^2.11.2",
         "autoprefixer": "^10.2.5",
         "axios": "^0.21.0",
         "babel-loader": "^8.2.1",
diff --git a/resources/assets/stylesheets/scss/courseware.scss b/resources/assets/stylesheets/scss/courseware.scss
index 524636c71af..a2be0224bf3 100755
--- a/resources/assets/stylesheets/scss/courseware.scss
+++ b/resources/assets/stylesheets/scss/courseware.scss
@@ -4189,7 +4189,7 @@ cw tiles end
 /*
 vSelect
 */
-.cw-vs-select {
+.cw-vs-select, .cw-vs-select-detachted-ul {
     max-width: 48em;
 
     .vs__dropdown-toggle {
@@ -4205,8 +4205,23 @@ vSelect
         height: 20px;
         margin-right: 4px;
     }
-}
 
+    .vs__dropdown-menu {
+        border-radius: 0;
+    }
+
+    &.cw-vs-select-drop-up {
+        border-bottom: solid thin $content-color-40;
+        border-top: none;
+    }
+
+    &.vs__dropdown-menu {
+        border-radius: 0;
+        border-bottom: none;
+        border-top: solid thin $content-color-40;
+        box-shadow: 0px -3px 6px 0 rgba(0, 0, 0, 0.15);
+    }
+}
 /*
 vSelect end
 */
diff --git a/resources/vue/components/courseware/CoursewareAccordionContainer.vue b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
index 4a318c30f29..1a9a2278182 100755
--- a/resources/vue/components/courseware/CoursewareAccordionContainer.vue
+++ b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
@@ -39,7 +39,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <v-select :options="icons" v-model="section.icon" class="cw-vs-select">
+                        <courseware-vue-select :options="icons" v-model="section.icon" class="cw-vs-select">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -52,7 +52,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label
                         class="cw-container-section-delete"
diff --git a/resources/vue/components/courseware/CoursewareChartBlock.vue b/resources/vue/components/courseware/CoursewareChartBlock.vue
index 4bce8b46c7f..068858651bb 100755
--- a/resources/vue/components/courseware/CoursewareChartBlock.vue
+++ b/resources/vue/components/courseware/CoursewareChartBlock.vue
@@ -49,7 +49,7 @@
                         </label>
                         <label>
                             <translate>Farbe</translate>
-                            <v-select
+                            <courseware-vue-select
                                 :options="colors"
                                 :reduce="colors => colors.value"
                                 label="rgb"
@@ -57,6 +57,7 @@
                                 v-model="item.color"
                                 class="cw-vs-select"
                                 @option:selected="buildChart"
+                                append-to-body
                             >
                                 <template #open-indicator="selectAttributes">
                                     <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
@@ -70,7 +71,7 @@
                                 <template #option="{name, rgb}">
                                     <span class="vs__option-color" :style="{'background-color': 'rgb(' + rgb + ')'}"></span><span>{{name}}</span>
                                 </template>
-                            </v-select>
+                            </courseware-vue-select>
                         </label>
                     </fieldset>
                 </form>
diff --git a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
index 349ac9545c2..e78615c3577 100755
--- a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
+++ b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
@@ -57,7 +57,7 @@
                     </label>
                     <label>
                         <translate>Textfarbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="colors"
                             label="hex"
                             :reduce="color => color.hex"
@@ -77,11 +77,11 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <v-select :clearable="false" :options="icons" v-model="currentIcon" class="cw-vs-select">
+                        <courseware-vue-select :clearable="false" :options="icons" v-model="currentIcon" class="cw-vs-select" append-to-body>
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -94,11 +94,11 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label>
                         <translate>Icon-Farbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="iconColors"
                             label="name"
                             :reduce="iconColor => iconColor.class"
@@ -118,7 +118,7 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label>
                         <translate>Hintergrundtyp</translate>
@@ -129,13 +129,14 @@
                     </label>
                     <label  v-if="currentBackgroundType === 'color'">
                         <translate>Hintergrundfarbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="colors"
                             label="hex"
                             :reduce="color => color.hex"
                             v-model="currentBackgroundColor"
                             :clearable="false"
                             class="cw-vs-select"
+                            append-to-body
                         >
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
@@ -149,7 +150,7 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label v-if="currentBackgroundType === 'image'">
                         <translate>Hintergrundbild</translate>
diff --git a/resources/vue/components/courseware/CoursewareImageMapBlock.vue b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
index 082e2ac9ef3..353af1e17a4 100755
--- a/resources/vue/components/courseware/CoursewareImageMapBlock.vue
+++ b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
@@ -60,7 +60,7 @@
                         >
                             <label>
                                 <translate>Farbe</translate>
-                                <v-select
+                                <courseware-vue-select
                                     :options="colors"
                                     label="name"
                                     :reduce="color => color.class"
@@ -80,7 +80,7 @@
                                     <template #option="{name, rgba}">
                                         <span class="vs__option-color" :style="{'background-color': rgba}"></span><span>{{name}}</span>
                                     </template>
-                                </v-select>
+                                </courseware-vue-select>
                             </label>
                             <label v-if="shape.type === 'arc'" class="cw-block-image-map-dimensions">
                                 X: <input type="number" v-model="shape.data.centerX" @change="drawScreen" /> Y:
@@ -376,7 +376,7 @@ export default {
             shapeWidth = shapeWidth || 0;
 
             let newText = [];
-            
+
             if (shapeWidth <= 0) {
                 return [text];
             }
diff --git a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
index 7c57f2a6e5c..07ca4475d4e 100755
--- a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
+++ b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
@@ -29,7 +29,7 @@
 
                     <label for="cw-keypoint-color">
                         <translate>Farbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="colors"
                             label="icon"
                             :clearable="false"
@@ -49,12 +49,12 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
 
                     <label for="cw-keypoint-icons">
                         <translate>Icon</translate>
-                        <v-select :options="icons" :clearable="false" v-model="currentIcon" class="cw-vs-select">
+                        <courseware-vue-select :options="icons" :clearable="false" v-model="currentIcon" class="cw-vs-select" append-to-body>
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -67,7 +67,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                 </form>
             </template>
diff --git a/resources/vue/components/courseware/CoursewareStructuralElement.vue b/resources/vue/components/courseware/CoursewareStructuralElement.vue
index b67001327e3..92c3ac4485f 100755
--- a/resources/vue/components/courseware/CoursewareStructuralElement.vue
+++ b/resources/vue/components/courseware/CoursewareStructuralElement.vue
@@ -134,7 +134,7 @@
                             <form class="default" @submit.prevent="">
                                 <label>
                                     <translate>Farbe</translate>
-                                    <v-select
+                                    <courseware-vue-select
                                         v-model="currentElement.attributes.payload.color"
                                         :options="colors"
                                         :reduce="(color) => color.class"
@@ -157,7 +157,7 @@
                                             <span class="vs__option-color" :style="{ 'background-color': hex }"></span
                                             ><span>{{ name }}</span>
                                         </template>
-                                    </v-select>
+                                    </courseware-vue-select>
                                 </label>
                                 <label>
                                     <translate>Zweck</translate>
diff --git a/resources/vue/components/courseware/CoursewareTabsContainer.vue b/resources/vue/components/courseware/CoursewareTabsContainer.vue
index f8502bd8542..8718eff4156 100755
--- a/resources/vue/components/courseware/CoursewareTabsContainer.vue
+++ b/resources/vue/components/courseware/CoursewareTabsContainer.vue
@@ -42,7 +42,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <v-select :options="icons" v-model="section.icon" class="cw-vs-select">
+                        <courseware-vue-select :options="icons" v-model="section.icon" class="cw-vs-select">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -55,7 +55,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label
                         class="cw-container-section-delete"
diff --git a/resources/vue/components/courseware/CoursewareVueSelect.vue b/resources/vue/components/courseware/CoursewareVueSelect.vue
new file mode 100755
index 00000000000..96fe15d557a
--- /dev/null
+++ b/resources/vue/components/courseware/CoursewareVueSelect.vue
@@ -0,0 +1,73 @@
+<template>
+    <v-select ref="select"
+        @change="updateValue"
+        v-bind="{...$props, ...$attrs}"
+        v-on="$listeners"
+        :calculate-position="withPopper"
+    >
+        <template v-for="(index, name) in $scopedSlots" v-slot:[name]="data">
+            <slot :name="name" v-bind="data"></slot>
+        </template>
+    </v-select>
+</template>
+
+<script>
+import { createPopper } from '@popperjs/core'
+export default {
+    name: 'courseware-vue-select',
+    inheritAttrs: false,
+    data() {
+        return {
+            placement: 'top'
+        };
+    },
+    methods: {
+        updateValue(val) {
+            this.$emit('input', val)
+        },
+        withPopper(dropdownList, component, { width }) {
+            dropdownList.style.width = width
+            const popper = createPopper(component.$refs.toggle, dropdownList, {
+                placement: this.placement,
+                modifiers: [
+                    {
+                        name: 'offset',
+                        options: {
+                            offset: [0, -1],
+                        },
+                    },
+                    {
+                        name: 'toggleClass',
+                        enabled: true,
+                        phase: 'write',
+                        fn({ state }) {
+                            component.$el.classList.toggle(
+                                'cw-vs-select-drop-up',
+                                state.placement === 'top'
+                            )
+                        },
+                    },
+                ],
+            })
+            return () => popper.destroy()
+        },
+    },
+    mounted() {
+        if (this.$attrs['append-to-body'] !== undefined) {
+            /*
+                Because the ul.vs__dropdown-menu is appending to the body, the default css (.cw-vs-select)
+                won't work anymore, therefore we need to add a css class (.cw-vs-select-detachted-ul) to its class list.
+            */
+            this.$refs.select.$on("open", async () => {
+                await this.$nextTick();
+                await this.$nextTick();
+                this.$refs.select?._vnode.children.forEach(({ elm }) => {
+                    if (elm instanceof HTMLElement && elm.tagName === "UL") {
+                        elm.classList.add('cw-vs-select-detachted-ul');
+                    }
+                });
+            });
+        }
+    }
+};
+</script>
diff --git a/resources/vue/courseware-index-app.js b/resources/vue/courseware-index-app.js
index ffdae6a70c6..616f9c1cd22 100755
--- a/resources/vue/courseware-index-app.js
+++ b/resources/vue/courseware-index-app.js
@@ -10,8 +10,10 @@ import axios from 'axios';
 import { mapResourceModules } from '@elan-ev/reststate-vuex';
 import vSelect from 'vue-select';
 import 'vue-select/dist/vue-select.css'
+import CoursewareVueSelect from './components/courseware/CoursewareVueSelect.vue';
 
 Vue.component('v-select', vSelect);
+Vue.component('courseware-vue-select', CoursewareVueSelect);
 
 const mountApp = (STUDIP, createApp, element) => {
     const getHttpClient = () =>
-- 
GitLab


From 4b2c9abb37451dfb45243e3e3d82f5d2c8135f1a Mon Sep 17 00:00:00 2001
From: farbod <zamanifarbod2@gmail.com>
Date: Fri, 28 Jan 2022 09:58:40 +0100
Subject: [PATCH 3/6] courseware-vue-select with drop-up, fixes #274

---
 package-lock.json                             | 17 +++++
 package.json                                  |  1 +
 .../assets/stylesheets/scss/courseware.scss   | 19 ++++-
 .../CoursewareAccordionContainer.vue          |  4 +-
 .../courseware/CoursewareChartBlock.vue       |  5 +-
 .../courseware/CoursewareHeadlineBlock.vue    | 17 +++--
 .../courseware/CoursewareImageMapBlock.vue    |  6 +-
 .../courseware/CoursewareKeyPointBlock.vue    |  8 +-
 .../CoursewareStructuralElement.vue           |  4 +-
 .../courseware/CoursewareTabsContainer.vue    |  4 +-
 .../courseware/CoursewareVueSelect.vue        | 73 +++++++++++++++++++
 resources/vue/courseware-index-app.js         |  2 +
 12 files changed, 135 insertions(+), 25 deletions(-)
 create mode 100755 resources/vue/components/courseware/CoursewareVueSelect.vue

diff --git a/package-lock.json b/package-lock.json
index 8c411fc1d9d..d224e5da624 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,6 +22,7 @@
                 "@fullcalendar/resource-timegrid": "^4.3.0",
                 "@fullcalendar/resource-timeline": "^4.3.0",
                 "@fullcalendar/timegrid": "^4.3.0",
+                "@popperjs/core": "^2.11.2",
                 "autoprefixer": "^10.2.5",
                 "axios": "^0.21.0",
                 "babel-loader": "^8.2.1",
@@ -1307,6 +1308,16 @@
                 "node": ">=10"
             }
         },
+        "node_modules/@popperjs/core": {
+            "version": "2.11.2",
+            "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz",
+            "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==",
+            "dev": true,
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/popperjs"
+            }
+        },
         "node_modules/@trysound/sax": {
             "version": "0.1.1",
             "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz",
@@ -15365,6 +15376,12 @@
                 }
             }
         },
+        "@popperjs/core": {
+            "version": "2.11.2",
+            "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz",
+            "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==",
+            "dev": true
+        },
         "@trysound/sax": {
             "version": "0.1.1",
             "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz",
diff --git a/package.json b/package.json
index 683e2c1039f..e6720293dea 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
         "@fullcalendar/resource-timegrid": "^4.3.0",
         "@fullcalendar/resource-timeline": "^4.3.0",
         "@fullcalendar/timegrid": "^4.3.0",
+        "@popperjs/core": "^2.11.2",
         "autoprefixer": "^10.2.5",
         "axios": "^0.21.0",
         "babel-loader": "^8.2.1",
diff --git a/resources/assets/stylesheets/scss/courseware.scss b/resources/assets/stylesheets/scss/courseware.scss
index cd4c5c83bf3..1612b7514af 100755
--- a/resources/assets/stylesheets/scss/courseware.scss
+++ b/resources/assets/stylesheets/scss/courseware.scss
@@ -4186,7 +4186,7 @@ cw tiles end
 /*
 vSelect
 */
-.cw-vs-select {
+.cw-vs-select, .cw-vs-select-detachted-ul {
     max-width: 48em;
 
     .vs__dropdown-toggle {
@@ -4202,8 +4202,23 @@ vSelect
         height: 20px;
         margin-right: 4px;
     }
-}
 
+    .vs__dropdown-menu {
+        border-radius: 0;
+    }
+
+    &.cw-vs-select-drop-up {
+        border-bottom: solid thin $content-color-40;
+        border-top: none;
+    }
+
+    &.vs__dropdown-menu {
+        border-radius: 0;
+        border-bottom: none;
+        border-top: solid thin $content-color-40;
+        box-shadow: 0px -3px 6px 0 rgba(0, 0, 0, 0.15);
+    }
+}
 /*
 vSelect end
 */
diff --git a/resources/vue/components/courseware/CoursewareAccordionContainer.vue b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
index 4a318c30f29..1a9a2278182 100755
--- a/resources/vue/components/courseware/CoursewareAccordionContainer.vue
+++ b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
@@ -39,7 +39,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <v-select :options="icons" v-model="section.icon" class="cw-vs-select">
+                        <courseware-vue-select :options="icons" v-model="section.icon" class="cw-vs-select">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -52,7 +52,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label
                         class="cw-container-section-delete"
diff --git a/resources/vue/components/courseware/CoursewareChartBlock.vue b/resources/vue/components/courseware/CoursewareChartBlock.vue
index 4bce8b46c7f..068858651bb 100755
--- a/resources/vue/components/courseware/CoursewareChartBlock.vue
+++ b/resources/vue/components/courseware/CoursewareChartBlock.vue
@@ -49,7 +49,7 @@
                         </label>
                         <label>
                             <translate>Farbe</translate>
-                            <v-select
+                            <courseware-vue-select
                                 :options="colors"
                                 :reduce="colors => colors.value"
                                 label="rgb"
@@ -57,6 +57,7 @@
                                 v-model="item.color"
                                 class="cw-vs-select"
                                 @option:selected="buildChart"
+                                append-to-body
                             >
                                 <template #open-indicator="selectAttributes">
                                     <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
@@ -70,7 +71,7 @@
                                 <template #option="{name, rgb}">
                                     <span class="vs__option-color" :style="{'background-color': 'rgb(' + rgb + ')'}"></span><span>{{name}}</span>
                                 </template>
-                            </v-select>
+                            </courseware-vue-select>
                         </label>
                     </fieldset>
                 </form>
diff --git a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
index 349ac9545c2..e78615c3577 100755
--- a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
+++ b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
@@ -57,7 +57,7 @@
                     </label>
                     <label>
                         <translate>Textfarbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="colors"
                             label="hex"
                             :reduce="color => color.hex"
@@ -77,11 +77,11 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <v-select :clearable="false" :options="icons" v-model="currentIcon" class="cw-vs-select">
+                        <courseware-vue-select :clearable="false" :options="icons" v-model="currentIcon" class="cw-vs-select" append-to-body>
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -94,11 +94,11 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label>
                         <translate>Icon-Farbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="iconColors"
                             label="name"
                             :reduce="iconColor => iconColor.class"
@@ -118,7 +118,7 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label>
                         <translate>Hintergrundtyp</translate>
@@ -129,13 +129,14 @@
                     </label>
                     <label  v-if="currentBackgroundType === 'color'">
                         <translate>Hintergrundfarbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="colors"
                             label="hex"
                             :reduce="color => color.hex"
                             v-model="currentBackgroundColor"
                             :clearable="false"
                             class="cw-vs-select"
+                            append-to-body
                         >
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
@@ -149,7 +150,7 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label v-if="currentBackgroundType === 'image'">
                         <translate>Hintergrundbild</translate>
diff --git a/resources/vue/components/courseware/CoursewareImageMapBlock.vue b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
index 082e2ac9ef3..353af1e17a4 100755
--- a/resources/vue/components/courseware/CoursewareImageMapBlock.vue
+++ b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
@@ -60,7 +60,7 @@
                         >
                             <label>
                                 <translate>Farbe</translate>
-                                <v-select
+                                <courseware-vue-select
                                     :options="colors"
                                     label="name"
                                     :reduce="color => color.class"
@@ -80,7 +80,7 @@
                                     <template #option="{name, rgba}">
                                         <span class="vs__option-color" :style="{'background-color': rgba}"></span><span>{{name}}</span>
                                     </template>
-                                </v-select>
+                                </courseware-vue-select>
                             </label>
                             <label v-if="shape.type === 'arc'" class="cw-block-image-map-dimensions">
                                 X: <input type="number" v-model="shape.data.centerX" @change="drawScreen" /> Y:
@@ -376,7 +376,7 @@ export default {
             shapeWidth = shapeWidth || 0;
 
             let newText = [];
-            
+
             if (shapeWidth <= 0) {
                 return [text];
             }
diff --git a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
index 7c57f2a6e5c..07ca4475d4e 100755
--- a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
+++ b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
@@ -29,7 +29,7 @@
 
                     <label for="cw-keypoint-color">
                         <translate>Farbe</translate>
-                        <v-select
+                        <courseware-vue-select
                             :options="colors"
                             label="icon"
                             :clearable="false"
@@ -49,12 +49,12 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
 
                     <label for="cw-keypoint-icons">
                         <translate>Icon</translate>
-                        <v-select :options="icons" :clearable="false" v-model="currentIcon" class="cw-vs-select">
+                        <courseware-vue-select :options="icons" :clearable="false" v-model="currentIcon" class="cw-vs-select" append-to-body>
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -67,7 +67,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                 </form>
             </template>
diff --git a/resources/vue/components/courseware/CoursewareStructuralElement.vue b/resources/vue/components/courseware/CoursewareStructuralElement.vue
index b67001327e3..92c3ac4485f 100755
--- a/resources/vue/components/courseware/CoursewareStructuralElement.vue
+++ b/resources/vue/components/courseware/CoursewareStructuralElement.vue
@@ -134,7 +134,7 @@
                             <form class="default" @submit.prevent="">
                                 <label>
                                     <translate>Farbe</translate>
-                                    <v-select
+                                    <courseware-vue-select
                                         v-model="currentElement.attributes.payload.color"
                                         :options="colors"
                                         :reduce="(color) => color.class"
@@ -157,7 +157,7 @@
                                             <span class="vs__option-color" :style="{ 'background-color': hex }"></span
                                             ><span>{{ name }}</span>
                                         </template>
-                                    </v-select>
+                                    </courseware-vue-select>
                                 </label>
                                 <label>
                                     <translate>Zweck</translate>
diff --git a/resources/vue/components/courseware/CoursewareTabsContainer.vue b/resources/vue/components/courseware/CoursewareTabsContainer.vue
index f8502bd8542..8718eff4156 100755
--- a/resources/vue/components/courseware/CoursewareTabsContainer.vue
+++ b/resources/vue/components/courseware/CoursewareTabsContainer.vue
@@ -42,7 +42,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <v-select :options="icons" v-model="section.icon" class="cw-vs-select">
+                        <courseware-vue-select :options="icons" v-model="section.icon" class="cw-vs-select">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -55,7 +55,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </v-select>
+                        </courseware-vue-select>
                     </label>
                     <label
                         class="cw-container-section-delete"
diff --git a/resources/vue/components/courseware/CoursewareVueSelect.vue b/resources/vue/components/courseware/CoursewareVueSelect.vue
new file mode 100755
index 00000000000..96fe15d557a
--- /dev/null
+++ b/resources/vue/components/courseware/CoursewareVueSelect.vue
@@ -0,0 +1,73 @@
+<template>
+    <v-select ref="select"
+        @change="updateValue"
+        v-bind="{...$props, ...$attrs}"
+        v-on="$listeners"
+        :calculate-position="withPopper"
+    >
+        <template v-for="(index, name) in $scopedSlots" v-slot:[name]="data">
+            <slot :name="name" v-bind="data"></slot>
+        </template>
+    </v-select>
+</template>
+
+<script>
+import { createPopper } from '@popperjs/core'
+export default {
+    name: 'courseware-vue-select',
+    inheritAttrs: false,
+    data() {
+        return {
+            placement: 'top'
+        };
+    },
+    methods: {
+        updateValue(val) {
+            this.$emit('input', val)
+        },
+        withPopper(dropdownList, component, { width }) {
+            dropdownList.style.width = width
+            const popper = createPopper(component.$refs.toggle, dropdownList, {
+                placement: this.placement,
+                modifiers: [
+                    {
+                        name: 'offset',
+                        options: {
+                            offset: [0, -1],
+                        },
+                    },
+                    {
+                        name: 'toggleClass',
+                        enabled: true,
+                        phase: 'write',
+                        fn({ state }) {
+                            component.$el.classList.toggle(
+                                'cw-vs-select-drop-up',
+                                state.placement === 'top'
+                            )
+                        },
+                    },
+                ],
+            })
+            return () => popper.destroy()
+        },
+    },
+    mounted() {
+        if (this.$attrs['append-to-body'] !== undefined) {
+            /*
+                Because the ul.vs__dropdown-menu is appending to the body, the default css (.cw-vs-select)
+                won't work anymore, therefore we need to add a css class (.cw-vs-select-detachted-ul) to its class list.
+            */
+            this.$refs.select.$on("open", async () => {
+                await this.$nextTick();
+                await this.$nextTick();
+                this.$refs.select?._vnode.children.forEach(({ elm }) => {
+                    if (elm instanceof HTMLElement && elm.tagName === "UL") {
+                        elm.classList.add('cw-vs-select-detachted-ul');
+                    }
+                });
+            });
+        }
+    }
+};
+</script>
diff --git a/resources/vue/courseware-index-app.js b/resources/vue/courseware-index-app.js
index ffdae6a70c6..616f9c1cd22 100755
--- a/resources/vue/courseware-index-app.js
+++ b/resources/vue/courseware-index-app.js
@@ -10,8 +10,10 @@ import axios from 'axios';
 import { mapResourceModules } from '@elan-ev/reststate-vuex';
 import vSelect from 'vue-select';
 import 'vue-select/dist/vue-select.css'
+import CoursewareVueSelect from './components/courseware/CoursewareVueSelect.vue';
 
 Vue.component('v-select', vSelect);
+Vue.component('courseware-vue-select', CoursewareVueSelect);
 
 const mountApp = (STUDIP, createApp, element) => {
     const getHttpClient = () =>
-- 
GitLab


From cf6cd9b8dd4766499767db5953b634d6e092d4ef Mon Sep 17 00:00:00 2001
From: farbod <zamanifarbod2@gmail.com>
Date: Wed, 2 Feb 2022 16:03:05 +0100
Subject: [PATCH 4/6] introducing studipselect + improvements, refs #274

---
 .../assets/stylesheets/scss/courseware.scss      |  9 ++++-----
 resources/vue/base-components.js                 |  2 ++
 .../CoursewareVueSelect.vue => StudipSelect.vue} | 16 ++++++++++++----
 .../courseware/CoursewareAccordionContainer.vue  |  4 ++--
 .../courseware/CoursewareChartBlock.vue          |  4 ++--
 .../courseware/CoursewareHeadlineBlock.vue       | 16 ++++++++--------
 .../courseware/CoursewareImageMapBlock.vue       |  4 ++--
 .../courseware/CoursewareKeyPointBlock.vue       |  8 ++++----
 .../courseware/CoursewareStructuralElement.vue   |  4 ++--
 .../courseware/CoursewareTabsContainer.vue       |  4 ++--
 resources/vue/courseware-index-app.js            |  6 ------
 11 files changed, 40 insertions(+), 37 deletions(-)
 rename resources/vue/components/{courseware/CoursewareVueSelect.vue => StudipSelect.vue} (82%)

diff --git a/resources/assets/stylesheets/scss/courseware.scss b/resources/assets/stylesheets/scss/courseware.scss
index 1612b7514af..ccfed2363bb 100755
--- a/resources/assets/stylesheets/scss/courseware.scss
+++ b/resources/assets/stylesheets/scss/courseware.scss
@@ -4186,7 +4186,7 @@ cw tiles end
 /*
 vSelect
 */
-.cw-vs-select, .cw-vs-select-detachted-ul {
+.cw-vs-select, .vs-select-detachted-ul {
     max-width: 48em;
 
     .vs__dropdown-toggle {
@@ -4203,17 +4203,16 @@ vSelect
         margin-right: 4px;
     }
 
-    .vs__dropdown-menu {
+    .vs__dropdown-menu, &.vs__dropdown-menu {
         border-radius: 0;
     }
 
-    &.cw-vs-select-drop-up {
+    &.vs-select-drop-up {
         border-bottom: solid thin $content-color-40;
         border-top: none;
     }
 
-    &.vs__dropdown-menu {
-        border-radius: 0;
+    &.vs-select-ul-drop-up {
         border-bottom: none;
         border-top: solid thin $content-color-40;
         box-shadow: 0px -3px 6px 0 rgba(0, 0, 0, 0.15);
diff --git a/resources/vue/base-components.js b/resources/vue/base-components.js
index 54d52fe0183..b57094e559b 100644
--- a/resources/vue/base-components.js
+++ b/resources/vue/base-components.js
@@ -10,6 +10,7 @@ import StudipMessageBox from './components/StudipMessageBox.vue';
 import StudipProxyCheckbox from './components/StudipProxyCheckbox.vue';
 import StudipProxiedCheckbox from './components/StudipProxiedCheckbox.vue';
 import StudipTooltipIcon from './components/StudipTooltipIcon.vue';
+import StudipSelect from './components/StudipSelect.vue';
 
 const BaseComponents = {
     Quicksearch,
@@ -24,6 +25,7 @@ const BaseComponents = {
     StudipProxyCheckbox,
     StudipProxiedCheckbox,
     StudipTooltipIcon,
+    StudipSelect,
 };
 
 export default BaseComponents;
diff --git a/resources/vue/components/courseware/CoursewareVueSelect.vue b/resources/vue/components/StudipSelect.vue
similarity index 82%
rename from resources/vue/components/courseware/CoursewareVueSelect.vue
rename to resources/vue/components/StudipSelect.vue
index 96fe15d557a..3df2c9672a2 100755
--- a/resources/vue/components/courseware/CoursewareVueSelect.vue
+++ b/resources/vue/components/StudipSelect.vue
@@ -12,10 +12,15 @@
 </template>
 
 <script>
+import vSelect from 'vue-select';
 import { createPopper } from '@popperjs/core'
+import 'vue-select/dist/vue-select.css'
 export default {
-    name: 'courseware-vue-select',
+    name: 'studip-select',
     inheritAttrs: false,
+    components: {
+        vSelect,
+    },
     data() {
         return {
             placement: 'top'
@@ -41,8 +46,12 @@ export default {
                         enabled: true,
                         phase: 'write',
                         fn({ state }) {
+                            component.$refs.dropdownMenu.classList.toggle(
+                                'vs-select-ul-drop-up',
+                                state.placement === 'top'
+                            )
                             component.$el.classList.toggle(
-                                'cw-vs-select-drop-up',
+                                'vs-select-drop-up',
                                 state.placement === 'top'
                             )
                         },
@@ -59,11 +68,10 @@ export default {
                 won't work anymore, therefore we need to add a css class (.cw-vs-select-detachted-ul) to its class list.
             */
             this.$refs.select.$on("open", async () => {
-                await this.$nextTick();
                 await this.$nextTick();
                 this.$refs.select?._vnode.children.forEach(({ elm }) => {
                     if (elm instanceof HTMLElement && elm.tagName === "UL") {
-                        elm.classList.add('cw-vs-select-detachted-ul');
+                        elm.classList.add('vs-select-detachted-ul');
                     }
                 });
             });
diff --git a/resources/vue/components/courseware/CoursewareAccordionContainer.vue b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
index 1a9a2278182..175cf08df06 100755
--- a/resources/vue/components/courseware/CoursewareAccordionContainer.vue
+++ b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
@@ -39,7 +39,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <courseware-vue-select :options="icons" v-model="section.icon" class="cw-vs-select">
+                        <studip-select :options="icons" v-model="section.icon" class="cw-vs-select">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -52,7 +52,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </courseware-vue-select>
+                        </studip-select>
                     </label>
                     <label
                         class="cw-container-section-delete"
diff --git a/resources/vue/components/courseware/CoursewareChartBlock.vue b/resources/vue/components/courseware/CoursewareChartBlock.vue
index 068858651bb..22116806508 100755
--- a/resources/vue/components/courseware/CoursewareChartBlock.vue
+++ b/resources/vue/components/courseware/CoursewareChartBlock.vue
@@ -49,7 +49,7 @@
                         </label>
                         <label>
                             <translate>Farbe</translate>
-                            <courseware-vue-select
+                            <studip-select
                                 :options="colors"
                                 :reduce="colors => colors.value"
                                 label="rgb"
@@ -71,7 +71,7 @@
                                 <template #option="{name, rgb}">
                                     <span class="vs__option-color" :style="{'background-color': 'rgb(' + rgb + ')'}"></span><span>{{name}}</span>
                                 </template>
-                            </courseware-vue-select>
+                            </studip-select>
                         </label>
                     </fieldset>
                 </form>
diff --git a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
index e78615c3577..258e54a831f 100755
--- a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
+++ b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
@@ -57,7 +57,7 @@
                     </label>
                     <label>
                         <translate>Textfarbe</translate>
-                        <courseware-vue-select
+                        <studip-select
                             :options="colors"
                             label="hex"
                             :reduce="color => color.hex"
@@ -77,11 +77,11 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </courseware-vue-select>
+                        </studip-select>
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <courseware-vue-select :clearable="false" :options="icons" v-model="currentIcon" class="cw-vs-select" append-to-body>
+                        <studip-select :clearable="false" :options="icons" v-model="currentIcon" class="cw-vs-select" append-to-body>
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -94,11 +94,11 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </courseware-vue-select>
+                        </studip-select>
                     </label>
                     <label>
                         <translate>Icon-Farbe</translate>
-                        <courseware-vue-select
+                        <studip-select
                             :options="iconColors"
                             label="name"
                             :reduce="iconColor => iconColor.class"
@@ -118,7 +118,7 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </courseware-vue-select>
+                        </studip-select>
                     </label>
                     <label>
                         <translate>Hintergrundtyp</translate>
@@ -129,7 +129,7 @@
                     </label>
                     <label  v-if="currentBackgroundType === 'color'">
                         <translate>Hintergrundfarbe</translate>
-                        <courseware-vue-select
+                        <studip-select
                             :options="colors"
                             label="hex"
                             :reduce="color => color.hex"
@@ -150,7 +150,7 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </courseware-vue-select>
+                        </studip-select>
                     </label>
                     <label v-if="currentBackgroundType === 'image'">
                         <translate>Hintergrundbild</translate>
diff --git a/resources/vue/components/courseware/CoursewareImageMapBlock.vue b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
index 353af1e17a4..2f2b72440d1 100755
--- a/resources/vue/components/courseware/CoursewareImageMapBlock.vue
+++ b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
@@ -60,7 +60,7 @@
                         >
                             <label>
                                 <translate>Farbe</translate>
-                                <courseware-vue-select
+                                <studip-select
                                     :options="colors"
                                     label="name"
                                     :reduce="color => color.class"
@@ -80,7 +80,7 @@
                                     <template #option="{name, rgba}">
                                         <span class="vs__option-color" :style="{'background-color': rgba}"></span><span>{{name}}</span>
                                     </template>
-                                </courseware-vue-select>
+                                </studip-select>
                             </label>
                             <label v-if="shape.type === 'arc'" class="cw-block-image-map-dimensions">
                                 X: <input type="number" v-model="shape.data.centerX" @change="drawScreen" /> Y:
diff --git a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
index 07ca4475d4e..04d7bf742ac 100755
--- a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
+++ b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
@@ -29,7 +29,7 @@
 
                     <label for="cw-keypoint-color">
                         <translate>Farbe</translate>
-                        <courseware-vue-select
+                        <studip-select
                             :options="colors"
                             label="icon"
                             :clearable="false"
@@ -49,12 +49,12 @@
                             <template #option="{name, hex}">
                                 <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span>
                             </template>
-                        </courseware-vue-select>
+                        </studip-select>
                     </label>
 
                     <label for="cw-keypoint-icons">
                         <translate>Icon</translate>
-                        <courseware-vue-select :options="icons" :clearable="false" v-model="currentIcon" class="cw-vs-select" append-to-body>
+                        <studip-select :options="icons" :clearable="false" v-model="currentIcon" class="cw-vs-select" append-to-body>
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -67,7 +67,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </courseware-vue-select>
+                        </studip-select>
                     </label>
                 </form>
             </template>
diff --git a/resources/vue/components/courseware/CoursewareStructuralElement.vue b/resources/vue/components/courseware/CoursewareStructuralElement.vue
index 92c3ac4485f..6b5fe022d36 100755
--- a/resources/vue/components/courseware/CoursewareStructuralElement.vue
+++ b/resources/vue/components/courseware/CoursewareStructuralElement.vue
@@ -134,7 +134,7 @@
                             <form class="default" @submit.prevent="">
                                 <label>
                                     <translate>Farbe</translate>
-                                    <courseware-vue-select
+                                    <studip-select
                                         v-model="currentElement.attributes.payload.color"
                                         :options="colors"
                                         :reduce="(color) => color.class"
@@ -157,7 +157,7 @@
                                             <span class="vs__option-color" :style="{ 'background-color': hex }"></span
                                             ><span>{{ name }}</span>
                                         </template>
-                                    </courseware-vue-select>
+                                    </studip-select>
                                 </label>
                                 <label>
                                     <translate>Zweck</translate>
diff --git a/resources/vue/components/courseware/CoursewareTabsContainer.vue b/resources/vue/components/courseware/CoursewareTabsContainer.vue
index 8718eff4156..f919c78cc12 100755
--- a/resources/vue/components/courseware/CoursewareTabsContainer.vue
+++ b/resources/vue/components/courseware/CoursewareTabsContainer.vue
@@ -42,7 +42,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <courseware-vue-select :options="icons" v-model="section.icon" class="cw-vs-select">
+                        <studip-select :options="icons" v-model="section.icon" class="cw-vs-select">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -55,7 +55,7 @@
                             <template #option="option">
                                 <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span>
                             </template>
-                        </courseware-vue-select>
+                        </studip-select>
                     </label>
                     <label
                         class="cw-container-section-delete"
diff --git a/resources/vue/courseware-index-app.js b/resources/vue/courseware-index-app.js
index 616f9c1cd22..0cd567e0ef7 100755
--- a/resources/vue/courseware-index-app.js
+++ b/resources/vue/courseware-index-app.js
@@ -8,12 +8,6 @@ import VueRouter from 'vue-router';
 import Vuex from 'vuex';
 import axios from 'axios';
 import { mapResourceModules } from '@elan-ev/reststate-vuex';
-import vSelect from 'vue-select';
-import 'vue-select/dist/vue-select.css'
-import CoursewareVueSelect from './components/courseware/CoursewareVueSelect.vue';
-
-Vue.component('v-select', vSelect);
-Vue.component('courseware-vue-select', CoursewareVueSelect);
 
 const mountApp = (STUDIP, createApp, element) => {
     const getHttpClient = () =>
-- 
GitLab


From 630b76d7a75687282c592a9eaf3f3a74055d3498 Mon Sep 17 00:00:00 2001
From: farbod <zamanifarbod2@gmail.com>
Date: Wed, 9 Feb 2022 17:20:02 +0100
Subject: [PATCH 5/6] studip-select enhancements, refs #274

---
 .../assets/stylesheets/scss/courseware.scss   | 21 +-------
 .../stylesheets/scss/studip_vue_select.scss   | 21 ++++++++
 resources/assets/stylesheets/studip.scss      |  1 +
 resources/vue/components/StudipSelect.vue     | 51 +++++++++++--------
 .../courseware/CoursewareChartBlock.vue       |  1 -
 .../courseware/CoursewareHeadlineBlock.vue    |  3 +-
 .../courseware/CoursewareKeyPointBlock.vue    |  2 +-
 7 files changed, 54 insertions(+), 46 deletions(-)
 create mode 100755 resources/assets/stylesheets/scss/studip_vue_select.scss

diff --git a/resources/assets/stylesheets/scss/courseware.scss b/resources/assets/stylesheets/scss/courseware.scss
index ccfed2363bb..dad1388f49c 100755
--- a/resources/assets/stylesheets/scss/courseware.scss
+++ b/resources/assets/stylesheets/scss/courseware.scss
@@ -4186,13 +4186,9 @@ cw tiles end
 /*
 vSelect
 */
-.cw-vs-select, .vs-select-detachted-ul {
+.cw-vs-select, .studip-v-select-detachted-ul {
     max-width: 48em;
 
-    .vs__dropdown-toggle {
-        border: solid thin $content-color-40;
-        border-radius: 0;
-    }
     .vs__option-with-icon{
         padding-left: 8px;
     }
@@ -4202,21 +4198,6 @@ vSelect
         height: 20px;
         margin-right: 4px;
     }
-
-    .vs__dropdown-menu, &.vs__dropdown-menu {
-        border-radius: 0;
-    }
-
-    &.vs-select-drop-up {
-        border-bottom: solid thin $content-color-40;
-        border-top: none;
-    }
-
-    &.vs-select-ul-drop-up {
-        border-bottom: none;
-        border-top: solid thin $content-color-40;
-        box-shadow: 0px -3px 6px 0 rgba(0, 0, 0, 0.15);
-    }
 }
 /*
 vSelect end
diff --git a/resources/assets/stylesheets/scss/studip_vue_select.scss b/resources/assets/stylesheets/scss/studip_vue_select.scss
new file mode 100755
index 00000000000..5ad51bc1c0c
--- /dev/null
+++ b/resources/assets/stylesheets/scss/studip_vue_select.scss
@@ -0,0 +1,21 @@
+.studip-v-select, .studip-v-select-detachted-ul {
+    .vs__dropdown-toggle {
+        border: solid thin $content-color-40;
+        border-radius: 0;
+    }
+
+    .vs__dropdown-menu, &.vs__dropdown-menu {
+        border-radius: 0;
+    }
+
+    &.studip-v-select-drop-up {
+        border-bottom: solid thin $content-color-40;
+        border-top: none;
+    }
+
+    &.studip-v-select-ul-drop-up {
+        border-bottom: none;
+        border-top: solid thin $content-color-40;
+        box-shadow: 0px -3px 6px 0 rgba(0, 0, 0, 0.15);
+    }
+}
diff --git a/resources/assets/stylesheets/studip.scss b/resources/assets/stylesheets/studip.scss
index 2f46b79b9a1..8f851b952a6 100644
--- a/resources/assets/stylesheets/studip.scss
+++ b/resources/assets/stylesheets/studip.scss
@@ -28,6 +28,7 @@
 @import "scss/tooltip";
 @import "scss/table_of_contents";
 @import "scss/wiki";
+@import "scss/studip_vue_select";
 
 @import "scss/grid";
 
diff --git a/resources/vue/components/StudipSelect.vue b/resources/vue/components/StudipSelect.vue
index 3df2c9672a2..0d80f947061 100755
--- a/resources/vue/components/StudipSelect.vue
+++ b/resources/vue/components/StudipSelect.vue
@@ -4,6 +4,8 @@
         v-bind="{...$props, ...$attrs}"
         v-on="$listeners"
         :calculate-position="withPopper"
+        class="studip-v-select"
+        append-to-body
     >
         <template v-for="(index, name) in $scopedSlots" v-slot:[name]="data">
             <slot :name="name" v-bind="data"></slot>
@@ -21,10 +23,11 @@ export default {
     components: {
         vSelect,
     },
-    data() {
-        return {
-            placement: 'top'
-        };
+    props: {
+        maxHeight: {
+            type: String,
+            default: '12em'
+        },
     },
     methods: {
         updateValue(val) {
@@ -32,8 +35,13 @@ export default {
         },
         withPopper(dropdownList, component, { width }) {
             dropdownList.style.width = width
+            dropdownList.style.maxHeight = this.maxHeight;
+            dropdownList.classList.add('studip-v-select-detachted-ul');
+            let dropdownListHeight = parseFloat(getComputedStyle(dropdownList).height) +
+                parseFloat(getComputedStyle(dropdownList).paddingTop) +
+                parseFloat(getComputedStyle(dropdownList).paddingBottom);
             const popper = createPopper(component.$refs.toggle, dropdownList, {
-                placement: this.placement,
+                placement: this.calculatePlacement(dropdownListHeight),
                 modifiers: [
                     {
                         name: 'offset',
@@ -47,11 +55,11 @@ export default {
                         phase: 'write',
                         fn({ state }) {
                             component.$refs.dropdownMenu.classList.toggle(
-                                'vs-select-ul-drop-up',
+                                'studip-v-select-ul-drop-up',
                                 state.placement === 'top'
                             )
                             component.$el.classList.toggle(
-                                'vs-select-drop-up',
+                                'studip-v-select-drop-up',
                                 state.placement === 'top'
                             )
                         },
@@ -60,21 +68,20 @@ export default {
             })
             return () => popper.destroy()
         },
-    },
-    mounted() {
-        if (this.$attrs['append-to-body'] !== undefined) {
-            /*
-                Because the ul.vs__dropdown-menu is appending to the body, the default css (.cw-vs-select)
-                won't work anymore, therefore we need to add a css class (.cw-vs-select-detachted-ul) to its class list.
-            */
-            this.$refs.select.$on("open", async () => {
-                await this.$nextTick();
-                this.$refs.select?._vnode.children.forEach(({ elm }) => {
-                    if (elm instanceof HTMLElement && elm.tagName === "UL") {
-                        elm.classList.add('vs-select-detachted-ul');
-                    }
-                });
-            });
+        calculatePlacement(dropdownListHeight) {
+            let scrollTop = window.pageYOffset || document.documentElement.scrollTop;
+            let selectBottom = Math.ceil(
+                this.$refs.select.$el.getBoundingClientRect().bottom + scrollTop
+            );
+            let totalExpandedList = selectBottom + dropdownListHeight;
+            let totalDocHeight = Math.max(
+                document.body.scrollHeight,
+                document.body.offsetHeight,
+                document.documentElement.clientHeight,
+                document.documentElement.scrollHeight,
+                document.documentElement.offsetHeight
+            );
+            return totalExpandedList >= totalDocHeight ? 'top' : 'bottom';
         }
     }
 };
diff --git a/resources/vue/components/courseware/CoursewareChartBlock.vue b/resources/vue/components/courseware/CoursewareChartBlock.vue
index 22116806508..55ab3b4cd10 100755
--- a/resources/vue/components/courseware/CoursewareChartBlock.vue
+++ b/resources/vue/components/courseware/CoursewareChartBlock.vue
@@ -57,7 +57,6 @@
                                 v-model="item.color"
                                 class="cw-vs-select"
                                 @option:selected="buildChart"
-                                append-to-body
                             >
                                 <template #open-indicator="selectAttributes">
                                     <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
diff --git a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
index 258e54a831f..7c7bf23ef85 100755
--- a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
+++ b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
@@ -81,7 +81,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <studip-select :clearable="false" :options="icons" v-model="currentIcon" class="cw-vs-select" append-to-body>
+                        <studip-select :clearable="false" :options="icons" v-model="currentIcon" class="cw-vs-select">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -136,7 +136,6 @@
                             v-model="currentBackgroundColor"
                             :clearable="false"
                             class="cw-vs-select"
-                            append-to-body
                         >
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
diff --git a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
index 04d7bf742ac..12efdc3f6fa 100755
--- a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
+++ b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
@@ -54,7 +54,7 @@
 
                     <label for="cw-keypoint-icons">
                         <translate>Icon</translate>
-                        <studip-select :options="icons" :clearable="false" v-model="currentIcon" class="cw-vs-select" append-to-body>
+                        <studip-select :options="icons" :clearable="false" v-model="currentIcon" class="cw-vs-select">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
-- 
GitLab


From ef77b4d9ca915ee6264c40aa991fa953f2b1a792 Mon Sep 17 00:00:00 2001
From: farbod <zamanifarbod2@gmail.com>
Date: Thu, 10 Feb 2022 11:39:09 +0100
Subject: [PATCH 6/6] enhancement studip-select, refs #274

---
 .../assets/stylesheets/scss/courseware.scss   | 28 +++----------------
 .../{studip_vue_select.scss => select.scss}   | 17 +++++++++++
 resources/assets/stylesheets/studip.scss      |  2 +-
 resources/vue/components/StudipSelect.vue     | 22 ++++++++++++---
 .../CoursewareAccordionContainer.vue          |  4 +--
 .../courseware/CoursewareChartBlock.vue       |  1 -
 .../CoursewareContentOverviewElements.vue     |  1 -
 .../courseware/CoursewareHeadlineBlock.vue    |  5 +---
 .../courseware/CoursewareImageMapBlock.vue    |  1 -
 .../courseware/CoursewareKeyPointBlock.vue    |  3 +-
 .../CoursewareStructuralElement.vue           |  1 -
 .../courseware/CoursewareTabsContainer.vue    |  2 +-
 12 files changed, 45 insertions(+), 42 deletions(-)
 rename resources/assets/stylesheets/scss/{studip_vue_select.scss => select.scss} (63%)

diff --git a/resources/assets/stylesheets/scss/courseware.scss b/resources/assets/stylesheets/scss/courseware.scss
index 4ed682a2700..aaeecc57c3a 100755
--- a/resources/assets/stylesheets/scss/courseware.scss
+++ b/resources/assets/stylesheets/scss/courseware.scss
@@ -169,14 +169,14 @@ c o n t e n t s
     .loading-indicator span.load-3 {
         animation: loading-animation-3 1s linear 20;
     }
-    
+
     @keyframes loading-animation-1 {
       0%   { transform: scale(1); }
       16%  { transform: scale(1.3); }
       33%  { transform: scale(1); }
       100% { transform: scale(1); }
     }
-    
+
     @keyframes loading-animation-2 {
       0%   { transform: scale(1); }
       33%  { transform: scale(1); }
@@ -184,7 +184,7 @@ c o n t e n t s
       65%  { transform: scale(1); }
       100% { transform: scale(1); }
     }
-    
+
     @keyframes loading-animation-3 {
       0%   { transform: scale(1); }
       66%  { transform: scale(1); }
@@ -2288,7 +2288,7 @@ d a s h b o a r d
 .responsive-display {
     .cw-dashboard {
         .cw-dashboard-box {
-    
+
             &.cw-dashboard-box-full {
                 width: 100%
             }
@@ -4608,26 +4608,6 @@ cw tiles
 cw tiles end
 */
 
-/*
-vSelect
-*/
-.cw-vs-select, .studip-v-select-detachted-ul {
-    max-width: 48em;
-
-    .vs__option-with-icon{
-        padding-left: 8px;
-    }
-    .vs__option-color {
-        border: solid thin $content-color-40;
-        padding-left: 20px;
-        height: 20px;
-        margin-right: 4px;
-    }
-}
-/*
-vSelect end
-*/
-
 /* cw manager copy */
 
 .cw-manager-copy-selector {
diff --git a/resources/assets/stylesheets/scss/studip_vue_select.scss b/resources/assets/stylesheets/scss/select.scss
similarity index 63%
rename from resources/assets/stylesheets/scss/studip_vue_select.scss
rename to resources/assets/stylesheets/scss/select.scss
index 5ad51bc1c0c..f7a44410fa1 100755
--- a/resources/assets/stylesheets/scss/studip_vue_select.scss
+++ b/resources/assets/stylesheets/scss/select.scss
@@ -1,4 +1,17 @@
 .studip-v-select, .studip-v-select-detachted-ul {
+    max-width: 48em;
+
+    .vs__option-with-icon{
+        padding-left: 8px;
+    }
+
+    .vs__option-color {
+        border: solid thin $content-color-40;
+        padding-left: 20px;
+        height: 20px;
+        margin-right: 4px;
+    }
+
     .vs__dropdown-toggle {
         border: solid thin $content-color-40;
         border-radius: 0;
@@ -18,4 +31,8 @@
         border-top: solid thin $content-color-40;
         box-shadow: 0px -3px 6px 0 rgba(0, 0, 0, 0.15);
     }
+
+    &.studip-v-select-ul-dialog {
+        z-index: 3002;
+    }
 }
diff --git a/resources/assets/stylesheets/studip.scss b/resources/assets/stylesheets/studip.scss
index 8f851b952a6..1c92ea605a7 100644
--- a/resources/assets/stylesheets/studip.scss
+++ b/resources/assets/stylesheets/studip.scss
@@ -28,7 +28,7 @@
 @import "scss/tooltip";
 @import "scss/table_of_contents";
 @import "scss/wiki";
-@import "scss/studip_vue_select";
+@import "scss/select";
 
 @import "scss/grid";
 
diff --git a/resources/vue/components/StudipSelect.vue b/resources/vue/components/StudipSelect.vue
index 0d80f947061..6347b2964ff 100755
--- a/resources/vue/components/StudipSelect.vue
+++ b/resources/vue/components/StudipSelect.vue
@@ -34,12 +34,15 @@ export default {
             this.$emit('input', val)
         },
         withPopper(dropdownList, component, { width }) {
+            if (component.$el?.offsetParent.classList.contains('studip-dialog-content')) {
+                dropdownList.classList.add('studip-v-select-ul-dialog');
+            }
             dropdownList.style.width = width
             dropdownList.style.maxHeight = this.maxHeight;
             dropdownList.classList.add('studip-v-select-detachted-ul');
-            let dropdownListHeight = parseFloat(getComputedStyle(dropdownList).height) +
-                parseFloat(getComputedStyle(dropdownList).paddingTop) +
-                parseFloat(getComputedStyle(dropdownList).paddingBottom);
+            let dropdownListHeight = parseFloat(this.getStyleValue(dropdownList, 'height')) +
+                parseFloat(this.getStyleValue(dropdownList, 'paddingTop')) +
+                parseFloat(this.getStyleValue(dropdownList, 'paddingBottom'));
             const popper = createPopper(component.$refs.toggle, dropdownList, {
                 placement: this.calculatePlacement(dropdownListHeight),
                 modifiers: [
@@ -81,7 +84,18 @@ export default {
                 document.documentElement.scrollHeight,
                 document.documentElement.offsetHeight
             );
-            return totalExpandedList >= totalDocHeight ? 'top' : 'bottom';
+            let footerHeight = document.getElementById('layout_footer').offsetHeight;
+            let functionalAreaHeight = totalDocHeight - footerHeight;
+            return totalExpandedList >= functionalAreaHeight ? 'top' : 'bottom';
+        },
+        getStyleValue(element, styleProp) {
+            let result = '';
+            if (window.getComputedStyle) {
+                result = getComputedStyle(element)[styleProp];
+            } else if (element.currentStyle) {
+                result = element.currentStyle[styleProp];
+            }
+            return result;
         }
     }
 };
diff --git a/resources/vue/components/courseware/CoursewareAccordionContainer.vue b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
index ea925628b60..fee4720b7f2 100755
--- a/resources/vue/components/courseware/CoursewareAccordionContainer.vue
+++ b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
@@ -45,7 +45,7 @@
                             <component :is="component(block)" :block="block" :canEdit="canEdit" :isTeacher="isTeacher" />
                         </li>
                     </transition-group>
-                
+
                 </draggable>
             </courseware-collapsible-box>
             <div v-if="sortMode && canEdit">
@@ -62,7 +62,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <studip-select :options="icons" v-model="section.icon" class="cw-vs-select">
+                        <studip-select :options="icons" v-model="section.icon">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
diff --git a/resources/vue/components/courseware/CoursewareChartBlock.vue b/resources/vue/components/courseware/CoursewareChartBlock.vue
index 1768d22d575..8dd58ec2433 100755
--- a/resources/vue/components/courseware/CoursewareChartBlock.vue
+++ b/resources/vue/components/courseware/CoursewareChartBlock.vue
@@ -55,7 +55,6 @@
                                 label="rgb"
                                 :clearable="false"
                                 v-model="item.color"
-                                class="cw-vs-select"
                                 @option:selected="buildChart"
                             >
                                 <template #open-indicator="selectAttributes">
diff --git a/resources/vue/components/courseware/CoursewareContentOverviewElements.vue b/resources/vue/components/courseware/CoursewareContentOverviewElements.vue
index 17e661c4bad..75bc3c76975 100755
--- a/resources/vue/components/courseware/CoursewareContentOverviewElements.vue
+++ b/resources/vue/components/courseware/CoursewareContentOverviewElements.vue
@@ -183,7 +183,6 @@
                                 :options="colors"
                                 :reduce="(color) => color.class"
                                 label="class"
-                                class="cw-vs-select"
                             >
                                 <template #open-indicator="selectAttributes">
                                     <span v-bind="selectAttributes"
diff --git a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
index 41b99d8ccad..1adfd945e0c 100755
--- a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
+++ b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
@@ -63,7 +63,6 @@
                             :reduce="color => color.hex"
                             :clearable="false"
                             v-model="currentTextColor"
-                            class="cw-vs-select"
                         >
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
@@ -81,7 +80,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <studip-select :clearable="false" :options="icons" v-model="currentIcon" class="cw-vs-select">
+                        <studip-select :clearable="false" :options="icons" v-model="currentIcon">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
@@ -104,7 +103,6 @@
                             :reduce="iconColor => iconColor.class"
                             :clearable="false"
                             v-model="currentIconColor"
-                            class="cw-vs-select"
                         >
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
@@ -135,7 +133,6 @@
                             :reduce="color => color.hex"
                             v-model="currentBackgroundColor"
                             :clearable="false"
-                            class="cw-vs-select"
                         >
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
diff --git a/resources/vue/components/courseware/CoursewareImageMapBlock.vue b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
index f248d0cc66a..9596e8854a0 100755
--- a/resources/vue/components/courseware/CoursewareImageMapBlock.vue
+++ b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
@@ -66,7 +66,6 @@
                                     :reduce="color => color.class"
                                     :clearable="false"
                                     v-model="shape.data.color"
-                                    class="cw-vs-select"
                                 >
                                     <template #open-indicator="selectAttributes">
                                         <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
diff --git a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
index 854575a95f5..39124e548b9 100755
--- a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
+++ b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
@@ -35,7 +35,6 @@
                             :clearable="false"
                             :reduce="option => option.icon"
                             v-model="currentColor"
-                            class="cw-vs-select"
                         >
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
@@ -54,7 +53,7 @@
 
                     <label for="cw-keypoint-icons">
                         <translate>Icon</translate>
-                        <studip-select :options="icons" :clearable="false" v-model="currentIcon" class="cw-vs-select">
+                        <studip-select :options="icons" :clearable="false" v-model="currentIcon">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
diff --git a/resources/vue/components/courseware/CoursewareStructuralElement.vue b/resources/vue/components/courseware/CoursewareStructuralElement.vue
index bab4958e937..f30c92455b9 100755
--- a/resources/vue/components/courseware/CoursewareStructuralElement.vue
+++ b/resources/vue/components/courseware/CoursewareStructuralElement.vue
@@ -180,7 +180,6 @@
                                         :options="colors"
                                         :reduce="(color) => color.class"
                                         label="class"
-                                        class="cw-vs-select"
                                     >
                                         <template #open-indicator="selectAttributes">
                                             <span v-bind="selectAttributes"
diff --git a/resources/vue/components/courseware/CoursewareTabsContainer.vue b/resources/vue/components/courseware/CoursewareTabsContainer.vue
index 1764d9b25d7..66c66926515 100755
--- a/resources/vue/components/courseware/CoursewareTabsContainer.vue
+++ b/resources/vue/components/courseware/CoursewareTabsContainer.vue
@@ -73,7 +73,7 @@
                     </label>
                     <label>
                         <translate>Icon</translate>
-                        <studip-select :options="icons" v-model="section.icon" class="cw-vs-select">
+                        <studip-select :options="icons" v-model="section.icon">
                             <template #open-indicator="selectAttributes">
                                 <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
                             </template>
-- 
GitLab