{"version":3,"file":"stylesheets/197.css?h=e411947430ae607a6dcf","mappings":"AACA,2FACI,mBAGA,kDACI,YACA,eACA,6BACA,YACA,sDACI,sBC6OZ,wBACA,qBACA,CCzPA,2CACI,qDACA,qGACA,aACA,eACA,2EACI,aACA,YACA,gBACA,0BACA,4BACA,wBACA,yCAGJ,6EACI,aACA,oBACA,gBACA,aACA,qBACA,4BACA,oFACI,eACA,eACA,iBAEJ,+EACI,SACA,mBAMJ,2EACI,mBACA,gBAMJ,0EACI,mBCoKZ,+DAGA,YACA,eAHA,eACA,aAGA,CACA,oBACA,cACA,CACA,iDACA,kBACA","sources":["webpack://@studip/core/./resources/vue/components/courseware/structural-element/CoursewareTreeItemAdder.vue","webpack://@studip/core/./resources/vue/components/StudipIdentImage.vue","webpack://@studip/core/./resources/vue/components/courseware/structural-element/CoursewareToolsContents.vue","webpack://@studip/core/./resources/vue/components/courseware/tasks/CoursewareDashboardStudents.vue"],"sourcesContent":["\n.cw-tree-root-list > .cw-tree-item.cw-tree-item-adder > .cw-tree-item-wrapper {\n    border-bottom: none;\n}\n.cw-tree-item-adder {\n    .add-element {\n        border: none;\n        cursor: pointer;\n        background-color: transparent;\n        height: 28px;\n        img {\n            vertical-align: middle;\n        }\n    }\n}\n","<template>\n    <canvas v-show=\"showCanvas\" ref=\"canvas\"></canvas>\n</template>\n\n<script>\nexport default {\n    name: 'studip-ident-image',\n    props: {\n        value: {\n            type: String,\n        },\n        showCanvas: {\n            type: Boolean,\n            default: false,\n        },\n        baseColor: {\n            type: String, // hex color\n        },\n        pattern: {\n            type: String,\n            required: true,\n        },\n        width: {\n            type: Number,\n            default: 1080,\n        },\n        height: {\n            type: Number,\n            default: 720,\n        },\n        shapesMin: {\n            type: Number,\n            default: 5,\n        },\n        shapesMax: {\n            type: Number,\n            default: 8,\n        },\n    },\n    data() {\n        return {\n            random: null,\n            ellipse: null,\n        };\n    },\n    methods: {\n        randint(min, max) {\n            return Math.floor(this.random() * (max - min) + min);\n        },\n        renderIdentimage() {\n            let canvas = this.$refs.canvas;\n            canvas.width = this.width;\n            canvas.height = this.height;\n\n            const minSize = Math.min(this.width, this.height) * 0.2;\n            const ctx = canvas.getContext('2d');\n            const backgroundHSL = this.hexToHSL(this.baseColor);\n            const numShape = this.randint(this.shapesMin, this.shapesMax);\n            const shapeSizes = [];\n\n            ctx.fillStyle = this.hexToRgbA(this.baseColor, 0.8);\n            ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n            const curveStart = this.randint(10, 70)/100 * this.height;\n            const curveEnd = this.randint(10, 70)/100 * this.height;\n            ctx.strokeStyle = `rgba(255, 255, 255, ${this.randint(50, 70) / 100})`;\n            const curvedistance = this.randint(20, 40);\n            const xFactor = this.randint(10, 45) / 100;\n            const yFactor = this.randint(10, 45) / 100;\n            for (let c = 0; c < numShape * 2; c++) {\n                ctx.beginPath();\n                ctx.moveTo(0, curveStart + curvedistance * c);\n                ctx.bezierCurveTo(this.width * xFactor, this.height * yFactor, this.width * (xFactor + 0.5), this.height * (yFactor + 0.5), this.width, curveEnd + curvedistance * c);\n                ctx.stroke();\n            }\n\n            for (let i = 0; i < numShape; i++) {\n                shapeSizes.push(this.randint(minSize*0.2, minSize*2) + minSize);\n            }\n\n            shapeSizes.sort((a, b) => {\n                return a < b ? 1 : a > b ? -1 : 0;\n            });\n\n            shapeSizes.forEach((shapeSizes, index) => {\n                const radius = shapeSizes / 2;\n                const [x, y] = this.createPointInEllipse(ctx);\n                const x_center = x * (this.width + radius / 2) - radius / 4;\n                const y_center = y * (this.height + radius / 2) - radius / 4;\n\n                ctx.fillStyle = `rgba(255, 255, 255, ${this.randint(10, 80) / 100})`;\n\n                ctx.beginPath();\n\n                if (index % 2 === 0) {\n                    ctx.arc(x_center, y_center, radius, 0, 2 * Math.PI);\n                } else {\n                    const size = radius;\n                    ctx.moveTo(x_center + size * Math.cos(0), y_center + size * Math.sin(0));\n\n                    for (let side = 0; side < 7; side++) {\n                        ctx.lineTo(\n                            x_center + size * Math.cos((side * 2 * Math.PI) / 6),\n                            y_center + size * Math.sin((side * 2 * Math.PI) / 6)\n                        );\n                    }\n                }\n\n                ctx.fill();\n            });\n\n            this.$emit('input', canvas.toDataURL());\n        },\n        createPointInEllipse(ctx) {\n            const x = this.random();\n            const y = this.random();\n\n            if (ctx.isPointInPath(this.ellipse, x, y)) {\n                return [x, y];\n            }\n\n            return this.createPointInEllipse(...arguments);\n        },\n\n        cyrb128(value) {\n            let h1 = 1779033703,\n                h2 = 3144134277,\n                h3 = 1013904242,\n                h4 = 2773480762;\n\n            for (let i = 0, k; i < value.length; i++) {\n                k = value.charCodeAt(i);\n                h1 = h2 ^ Math.imul(h1 ^ k, 597399067);\n                h2 = h3 ^ Math.imul(h2 ^ k, 2869860233);\n                h3 = h4 ^ Math.imul(h3 ^ k, 951274213);\n                h4 = h1 ^ Math.imul(h4 ^ k, 2716044179);\n            }\n\n            h1 = Math.imul(h3 ^ (h1 >>> 18), 597399067);\n            h2 = Math.imul(h4 ^ (h2 >>> 22), 2869860233);\n            h3 = Math.imul(h1 ^ (h3 >>> 17), 951274213);\n            h4 = Math.imul(h2 ^ (h4 >>> 19), 2716044179);\n\n            return [(h1 ^ h2 ^ h3 ^ h4) >>> 0, (h2 ^ h1) >>> 0, (h3 ^ h1) >>> 0, (h4 ^ h1) >>> 0];\n        },\n        sfc32(a, b, c, d) {\n            return function () {\n                a >>>= 0;\n                b >>>= 0;\n                c >>>= 0;\n                d >>>= 0;\n                var t = (a + b) | 0;\n                a = b ^ (b >>> 9);\n                b = (c + (c << 3)) | 0;\n                c = (c << 21) | (c >>> 11);\n                d = (d + 1) | 0;\n                t = (t + d) | 0;\n                c = (c + t) | 0;\n\n                return (t >>> 0) / 4294967296;\n            };\n        },\n\n        hexToRGB(color) {\n            color = color.slice(1); // remove #\n            let val = parseInt(color, 16);\n            let r = val >> 16;\n            let g = (val >> 8) & 0x00ff;\n            let b = val & 0x0000ff;\n\n            if (g > 255) {\n                g = 255;\n            } else if (g < 0) {\n                g = 0;\n            }\n            if (b > 255) {\n                b = 255;\n            } else if (b < 0) {\n                b = 0;\n            }\n\n            return { r: r, g: g, b: b };\n        },\n        RGBToHSL(r, g, b) {\n            r /= 255;\n            g /= 255;\n            b /= 255;\n\n            let cmin = Math.min(r, g, b),\n                cmax = Math.max(r, g, b),\n                delta = cmax - cmin,\n                h = 0,\n                s = 0,\n                l = 0;\n            if (delta == 0) h = 0;\n            // Red is max\n            else if (cmax == r) h = ((g - b) / delta) % 6;\n            // Green is max\n            else if (cmax == g) h = (b - r) / delta + 2;\n            // Blue is max\n            else h = (r - g) / delta + 4;\n\n            h = Math.round(h * 60);\n\n            if (h < 0) h += 360;\n            l = (cmax + cmin) / 2;\n\n            s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));\n\n            s = +(s * 100).toFixed(1);\n            l = +(l * 100).toFixed(1);\n\n            return { h: h, s: s, l: l };\n            // return 'hsl(' + h + ',' + s + '%,' + l + '%)';\n        },\n        hexToHSL(color) {\n            const RGB = this.hexToRGB(color);\n            return this.RGBToHSL(RGB.r, RGB.g, RGB.b);\n        },\n        hexToRgbA(hex, a){\n            const RGB = this.hexToRGB(hex);\n\n            return 'rgba(' + RGB.r + ',' + RGB.g + ',' + RGB.b + ',' + a +')';\n        },\n        init() {\n            const seed = this.cyrb128(this.pattern);\n            this.random = this.sfc32(...seed);\n            this.ellipse = new Path2D();\n            this.ellipse.ellipse(0.5, 0.5, 0.5, 0.5, 0, 0, Math.PI * 2);\n            this.renderIdentimage();\n        }\n    },\n    mounted() {\n        this.init();\n    },\n    watch: {\n        baseColor() {\n            this.init();\n        },\n    },\n};\n</script>\n<style scoped>\n  canvas {\n    background-color: #fff;\n  }\n</style>\n","\n.cw-tools-contents-header {\n    display: flex;\n    flex-direction: row;\n    height: 100px;\n    margin-top: 8px;\n    .cw-tools-contents-header-image {\n        height: 100px;\n        width: 150px;\n        min-width: 150px;\n        background-size: 100% auto;\n        background-repeat: no-repeat;\n        background-position: center;\n        background-color: var(--content-color-20);\n    }\n\n    .cw-tools-contents-header-details {\n        margin: 0 8px;\n        display: -webkit-box;\n        overflow: hidden;\n        height: 100px;\n        -webkit-line-clamp: 5;\n        -webkit-box-orient: vertical;\n        header {\n            margin: 0 0 6px 0;\n            font-size: 16px;\n            line-height: 16px;\n        }\n        p {\n            margin: 0;\n            color: var(--black);\n        }\n    }\n}\n.root-is-current {\n    .cw-tools-contents-header-details {\n        header {\n            color: var(--black);\n            font-weight: 600;\n        }\n    }\n}\n.root-is-hidden {\n    .cw-tools-contents-header-details {\n        header {\n            color: var(--black);\n        }\n    }\n}\n","<template>\n    <div class=\"cw-dashboard-students-wrapper\">\n        <CoursewareRibbon :isContentBar=\"true\" :showToolbarButton=\"false\">\n            <template #buttons>\n                <router-link :to=\"{ name: 'task-groups-index' }\">\n                    <StudipIcon shape=\"category-task\" :size=\"24\" />\n                </router-link>\n            </template>\n            <template #breadcrumbList>\n                <li>\n                    {{ $gettext('Aufgaben') }}\n                </li>\n            </template>\n        </CoursewareRibbon>\n        <table class=\"default\" v-if=\"taskGroups.length\">\n            <thead>\n                <tr class=\"sortable\">\n                    <th>\n                        {{ $gettext('Status') }}\n                    </th>\n                    <th :class=\"getSortClass('task-group-title')\" @click=\"sort('task-group-title')\">\n                        {{ $gettext('Titel') }}\n                    </th>\n                    <th :class=\"getSortClass('end-date')\" @click=\"sort('end-date')\">\n                        {{ $gettext('Bearbeitungszeit') }}\n                    </th>\n                    <th class=\"actions\">{{ $gettext('Aktionen') }}</th>\n                </tr>\n            </thead>\n            <tbody>\n                <tr v-for=\"(taskGroup, index) in sortedTaskGroups\" :key=\"index\">\n                    <td>\n                        <StudipIcon\n                            :shape=\"status(taskGroup).shape\"\n                            :role=\"status(taskGroup).role\"\n                            :title=\"status(taskGroup).description\"\n                            aria-hidden=\"true\"\n                        />\n                        <span class=\"sr-only\">{{ status(taskGroup).description }}</span>\n                    </td>\n                    <td>\n                        <router-link :to=\"{ name: 'task-groups-show', params: { id: taskGroup.id } }\">{{\n                            taskGroup.attributes.title\n                        }}</router-link>\n                    </td>\n                    <td>\n                        <StudipDate :date=\"new Date(taskGroup.attributes['start-date'])\" /> - <StudipDate\n                            :date=\"new Date(taskGroup.attributes['end-date'])\"\n                        />\n                    </td>\n                    <td class=\"actions\">\n                        <StudipActionMenu\n                            :items=\"getTaskGroupMenuItems(taskGroup)\"\n                            @addsolvers=\"onShowAddSolvers(taskGroup)\"\n                            @deadline=\"onShowModifyDeadline(taskGroup)\"\n                            @delete=\"onShowDeleteDialog(taskGroup)\"\n                        />\n                    </td>\n                </tr>\n            </tbody>\n        </table>\n\n        <CompanionBox v-else-if=\"!tasksLoading\" :msgCompanion=\"$gettext('Es wurden noch keine Aufgaben verteilt.')\">\n            <template #companionActions>\n                <button @click=\"setShowTasksDistributeDialog(true)\" type=\"button\" class=\"button\">\n                    {{ $gettext('Aufgabe verteilen') }}\n                </button>\n            </template>\n        </CompanionBox>\n\n        <TaskGroupsAddSolversDialog v-if=\"showTaskGroupsAddSolversDialog\" :taskGroup=\"selectedTaskGroup\" @newtask=\"reloadTasks\" />\n        <TaskGroupsDeleteDialog v-if=\"showTaskGroupsDeleteDialog\" :taskGroup=\"selectedTaskGroup\" />\n        <TaskGroupsModifyDeadlineDialog v-if=\"showTaskGroupsModifyDeadlineDialog\" :taskGroup=\"selectedTaskGroup\" />\n        <CoursewareTasksDialogDistribute v-if=\"showTasksDistributeDialog\" @newtask=\"reloadTasks\" />\n    </div>\n</template>\n\n<script>\nimport _ from 'lodash';\nimport { mapActions, mapGetters } from 'vuex';\nimport CompanionBox from '../layouts/CoursewareCompanionBox.vue';\nimport CoursewareRibbon from '../structural-element/CoursewareRibbon.vue';\nimport CoursewareTasksDialogDistribute from './CoursewareTasksDialogDistribute.vue';\nimport StudipActionMenu from '../../StudipActionMenu.vue';\nimport StudipDate from '../../StudipDate.vue';\nimport StudipIcon from '../../StudipIcon.vue';\nimport TaskGroupsAddSolversDialog from './TaskGroupsAddSolversDialog.vue';\nimport TaskGroupsDeleteDialog from './TaskGroupsDeleteDialog.vue';\nimport TaskGroupsModifyDeadlineDialog from './TaskGroupsModifyDeadlineDialog.vue';\nimport { getStatus } from './task-groups-helper.js';\n\nexport default {\n    name: 'courseware-dashboard-students',\n    components: {\n        CompanionBox,\n        CoursewareRibbon,\n        CoursewareTasksDialogDistribute,\n        StudipActionMenu,\n        StudipDate,\n        StudipIcon,\n        TaskGroupsAddSolversDialog,\n        TaskGroupsDeleteDialog,\n        TaskGroupsModifyDeadlineDialog,\n    },\n    data: () => ({\n        selectedTaskGroup: null,\n        sortBy: 'end-date',\n        sortAsc: false,\n    }),\n    computed: {\n        ...mapGetters({\n            context: 'context',\n            showTaskGroupsAddSolversDialog: 'tasks/showTaskGroupsAddSolversDialog',\n            showTaskGroupsDeleteDialog: 'tasks/showTaskGroupsDeleteDialog',\n            showTaskGroupsModifyDeadlineDialog: 'tasks/showTaskGroupsModifyDeadlineDialog',\n            showTasksDistributeDialog: 'tasks/showTasksDistributeDialog',\n            taskGroupsByCid: 'tasks/taskGroupsByCid',\n            tasksLoading: 'courseware-tasks/isLoading',\n        }),\n        sortedTaskGroups() {\n            const sorters = {\n                'task-group-title': (taskGroup) => taskGroup.attributes.title,\n                'end-date': (taskGroup) => new Date(taskGroup.attributes['end-date']),\n            };\n\n            return _.chain(this.taskGroups)\n                .sortBy([sorters[this.sortBy]])\n                .thru((sorted) => (this.sortAsc ? sorted : _.reverse(sorted)))\n                .value();\n        },\n        taskGroups() {\n            return this.taskGroupsByCid(this.context.id);\n        },\n    },\n    methods: {\n        ...mapActions({\n            loadAllTasks: 'courseware-tasks/loadAll',\n            setShowTaskGroupsAddSolversDialog: 'tasks/setShowTaskGroupsAddSolversDialog',\n            setShowTaskGroupsDeleteDialog: 'tasks/setShowTaskGroupsDeleteDialog',\n            setShowTaskGroupsModifyDeadlineDialog: 'tasks/setShowTaskGroupsModifyDeadlineDialog',\n            setShowTasksDistributeDialog: 'tasks/setShowTasksDistributeDialog',\n        }),\n        getSortClass(col) {\n            if (col === this.sortBy) {\n                return this.sortAsc ? 'sortasc' : 'sortdesc';\n            }\n            return '';\n        },\n        getTaskGroupMenuItems(taskGroup) {\n            let menuItems = [];\n\n            const isBeforeEndDate = new Date() < new Date(taskGroup.attributes['end-date']);\n            if (isBeforeEndDate) {\n                menuItems.push({\n                    id: 'add-solvers',\n                    label: this.$gettext('Teilnehmende hinzufügen'),\n                    icon: 'add',\n                    emit: 'addsolvers'\n                });\n                menuItems.push({\n                    id: 'modify-deadline',\n                    label: this.$gettext('Bearbeitungszeit verlängern'),\n                    icon: 'date',\n                    emit: 'deadline'\n                });\n            }\n\n            menuItems.push({\n                id: 'delete',\n                label: this.$gettext('Aufgabe löschen'),\n                icon: 'trash',\n                emit: 'delete',\n            });\n\n            return menuItems;\n        },\n        onShowAddSolvers(taskGroup) {\n            this.selectedTaskGroup = taskGroup;\n            this.setShowTaskGroupsAddSolversDialog(true);\n        },\n        onShowDeleteDialog(taskGroup) {\n            this.selectedTaskGroup = taskGroup;\n            this.setShowTaskGroupsDeleteDialog(true);\n        },\n        onShowModifyDeadline(taskGroup) {\n            this.selectedTaskGroup = taskGroup;\n            this.setShowTaskGroupsModifyDeadlineDialog(true);\n        },\n        reloadTasks() {\n            this.loadAllTasks({\n                options: {\n                    'filter[cid]': this.context.id,\n                    include: 'solver, structural-element, task-feedback, task-group, task-group.lecturer',\n                },\n            });\n        },\n        sort(sortBy) {\n            if (this.sortBy === sortBy) {\n                this.sortAsc = !this.sortAsc;\n            } else {\n                this.sortBy = sortBy;\n            }\n        },\n        status: getStatus,\n    },\n};\n</script>\n\n<style scoped>\n.cw-dashboard-students-wrapper >>> .cw-ribbon-nav {\n    min-width: 24px;\n    padding: 0 1em;\n    height: 24px;\n    margin-top: 2px;\n}\nth {\n    cursor: pointer;\n}\nth:is(:first-child,:last-child) {\n    cursor: not-allowed;\n}\n</style>\n"],"names":[],"sourceRoot":""}