diff --git a/app/views/oer/addfile/choose_file.php b/app/views/oer/addfile/choose_file.php index 6c896cf8d05c5a4adf8add4dfde83f414376b27a..c651766fa67f57bf794cb83065d4207b7af3f55d 100644 --- a/app/views/oer/addfile/choose_file.php +++ b/app/views/oer/addfile/choose_file.php @@ -9,15 +9,14 @@ if ($best_nine_tags && count($best_nine_tags) > 0) { } } ?> -<form class="oer_search" - action="<?= $controller->link_for("oer/market/search") ?>" - method="GET" - data-searchresults="<?= htmlReady(json_encode($material_data)) ?>" - data-filteredtag="<?= htmlReady(Request::get("tag")) ?>" - data-filteredcategory="<?= htmlReady(Request::get("category")) ?>" - data-tags="<?= htmlReady(json_encode($tags)) ?>" - data-material_select_url_template="<?= htmlReady($controller->url_for("oer/addfile/choose_file", ['material_id' => "__material_id__", 'to_plugin' => Request::get("to_plugin"), 'to_folder_id' => Request::get("to_folder_id")])) ?>"> - <input type="hidden" name="to_plugin" value="<?= htmlReady(Request::get("to_plugin")) ?>"> - <input type="hidden" name="to_folder_id" value="<?= htmlReady(Request::get("to_folder_id")) ?>"> - <?= $this->render_partial("oer/market/_searchform") ?> -</form> +<?= Studip\VueApp::create('OERSearch') + ->withProps([ + 'url' => $controller->url_for('oer/market/search'), + 'search-results' => $material_data ?? false, + 'filtered-tag' => Request::get('tag'), + 'filtered-category' => Request::get('category'), + 'tags' => $tags, + 'material-select-url-template' => $controller->url_for('oer/addfile/choose_file', ['material_id' => '__material_id__']), + 'to-plugin' => Request::get('to_plugin'), + 'to-folder-id' => Request::get('to_folder_id'), + ]) ?> diff --git a/app/views/oer/market/_searchform.php b/app/views/oer/market/_searchform.php deleted file mode 100644 index 474042b6d09e10e07457bfad1d47c32bd1a20b5f..0000000000000000000000000000000000000000 --- a/app/views/oer/market/_searchform.php +++ /dev/null @@ -1,179 +0,0 @@ -<div class="searchform"> - <div class="oneliner"> - <div class="frame"> - <span v-if="category != null" - class="category activefilter" title="<?= _('Aktiver Filter der Kategorie') ?>"> - <span>{{ category }}</span> - <a href="#" - @click.prevent="clearCategory" - class="erasefilter" - title="<?= _('Filter der Kategorie entfernen') ?>"> - <studip-icon shape="decline" role="clickable" :size="16" class="text-bottom"></studip-icon> - </a> - </span> - - <span v-if="difficulty[0] != 1 || difficulty[1] != 12" - class="niveau activefilter" - title="<?= _('Aktiver Filter für das Niveau') ?>"> - <?= _('Niveau') ?>: - <span>{{ difficulty[0] }}</span> - - - <span>{{ difficulty[1] }}</span> - <a href="#" - @click.prevent="clearDifficulty" - class="erasefilter" - title="<?= _('Filter des Niveaus entfernen') ?>"> - <studip-icon shape="decline" role="clickable" :size="16" class="text-bottom"></studip-icon> - </a> - </span> - - <input type="text" - name="search" - @focus="showFilterPanel" - @keyup="sync_search_text" - @keydown.enter.prevent="search"> - - <button v-if="difficulty[0] != 1 || difficulty[1] != 12 || (category != null) || (searchtext.length > 0)" - class="erase" - type="button" - title="<?= _('Suchformular zurücksetzen') ?>" - @click="clearAllFilters"> - <studip-icon shape="decline" role="clickable"></studip-icon> - </button> - - <button @click="triggerFilterPanel" - type="button" - title="<?= _('Suchfilter einstellen') ?>" - :class="activeFilterPanel ? 'active' : ''"> - <studip-icon shape="filter" :role="activeFilterPanel ? 'info_alt' : 'clickable'"></studip-icon> - </button> - - <div v-if="activeFilterPanel" class="filterpanel_shadow"></div> - - <div v-if="activeFilterPanel" class="filterpanel"> - <div> - <h3><?= _('Kategorien') ?></h3> - <ul class="clean"> - <li> - <a href="<?= $controller->link_for("oer/market", ['category' => "audio"]) ?>" @click.prevent="category = 'audio'"> - <studip-icon v-if="category != 'audio'" shape="radiobutton-unchecked" role="clickable" :size="16" class="text-bottom"></studip-icon> - <studip-icon v-if="category == 'audio'" shape="radiobutton-checked" role="clickable" :size="16" class="text-bottom"></studip-icon> - <?= _('Audio') ?> - </a> - </li> - <li> - <a href="<?= $controller->link_for("oer/market", ['category' => "video"]) ?>" @click.prevent="category = 'video'"> - <studip-icon v-if="category != 'video'" shape="radiobutton-unchecked" role="clickable" :size="16" class="text-bottom"></studip-icon> - <studip-icon v-if="category == 'video'" shape="radiobutton-checked" role="clickable" :size="16" class="text-bottom"></studip-icon> - <?= _('Video') ?> - </a> - </li> - <li> - <a href="<?= $controller->link_for("oer/market", ['category' => "presentation"]) ?>" @click.prevent="category = 'presentation'"> - <studip-icon v-if="category != 'presentation'" shape="radiobutton-unchecked" role="clickable" :size="16" class="text-bottom"></studip-icon> - <studip-icon v-if="category == 'presentation'" shape="radiobutton-checked" role="clickable" :size="16" class="text-bottom"></studip-icon> - <?= _('Folien') ?> - </a> - </li> - <li> - <a href="<?= $controller->link_for("oer/market", ['category' => "elearning"]) ?>" @click.prevent="category = 'elearning'"> - <studip-icon v-if="category != 'elearning'" shape="radiobutton-unchecked" role="clickable" :size="16" class="text-bottom"></studip-icon> - <studip-icon v-if="category == 'elearning'" shape="radiobutton-checked" role="clickable" :size="16" class="text-bottom"></studip-icon> - <?= _('Lernmodule') ?> - </a> - </li> - <li> - <a href="<?= $controller->link_for("oer/market", ['get' => "all"]) ?>"> - <studip-icon shape="link-intern" role="clickable" :size="16" class="text-bottom"></studip-icon> - <?= _('Alles') ?> - </a> - </li> - </ul> - </div> - <div class="level_filter"> - <h3><?= _('Niveau') ?></h3> - <div class="level_labels"> - <div><?= _('Leicht') ?></div> - <div><?= _('Schwer') ?></div> - </div> - <div class="level_numbers"> - <? for ($i = 1; $i <= 12; $i++) : ?> - <div><?= ($i < 10 ? " " : "").$i ?></div> - <? endfor ?> - </div> - <div id="difficulty_slider"></div> - - <input type="hidden" id="difficulty" name="difficulty" value=""> - </div> - </div> - - - <button title="<?= _('Suche starten') ?>" @click.prevent="search" @focus="hideFilterPanel"> - <studip-icon shape="search" role="clickable"></studip-icon> - </button> - </div> - - </div> - - -</div> - -<div class="browser"> - - <div v-if="browseMode === false" class="intro"> - <img src="<?= Assets::image_path("oer-keyvisual-negative.svg") ?>" class="illustration responsive-hidden"> - <div> - <h3><?= _('Wertvolle Lernmaterialien entdecken!') ?></h3> - <div class="responsive-hidden"> - <?= _('Neue und spannende Lernmaterialien zu finden, ist ganz einfach. Mit dem Entdeckermodus können Sie nach Schlagwörtern stöbern und durch Themengebiete surfen.') ?> - </div> - - <div> - <?= \Studip\LinkButton::create(_('Zum Entdeckermodus'), "#", ['@click.prevent' => "browseMode=true"]) ?> - </div> - </div> - </div> - - <div v-if="browseMode === true" class="tagcloud"> - <div> - <h3><?= _('Wertvolle Materialien entdecken!') ?></h3> - <?= _('Klicken Sie auf die Schlagwörter und entdecken Sie Lernmaterialien zum Thema.') ?> - </div> - <a href="" @click.prevent="backInCloud" class="back-button"> - <studip-icon shape="arr_1left" role="clickable" :size="50"></studip-icon> - </a> - <ul class="tags clean"> - <li v-for="tag in tags"> - <a href="#" - class="button" - :style="getTagStyle(tag.tag_hash)" - :title="tag.name" - @click.prevent="browseTag(tag.tag_hash, tag.name)">{{"#" + tag.name}}</a> - </li> - </ul> - </div> - -</div> - -<div v-if="results && results.length === 0" class="oer_no_results"> - <?= MessageBox::info(_('Keine Ergebnisse gefunden.'))?> -</div> - -<ul class="results oer_material_overview" v-if="results && results.length > 0"> - <li v-for="result in results" :key="result.material_id"> - <article class="contentbox" :title="result.name"> - <a :href="getMaterialURL(result.material_id)" target="_blank"> - <header> - <h1> - <studip-icon :shape="getIconShape(result)" - role="clickable" - :size="20" - class="text-bottom"></studip-icon> - {{ shortenName(result.name) }} - </h1> - </header> - <div class="image" :style="'background-image: url(' + result.logo_url + ');' + (!result.front_image_content_type ? ' background-size: 60% auto;': '')"></div> - </a> - </article> - </li> -</ul> diff --git a/app/views/oer/market/index.php b/app/views/oer/market/index.php index 66e1f2c47851d32067effa1fe263eb84b1c6287a..d2a1ed67dca84f2963eefed0b0c2ae40fe8f4a59 100644 --- a/app/views/oer/market/index.php +++ b/app/views/oer/market/index.php @@ -6,17 +6,15 @@ * @var OERMaterial[] $new_ones */ ?> -<form class="oer_search" - action="<?= $controller->search() ?>" - method="GET" aria-live="polite" - data-searchresults="<?= htmlReady(json_encode($material_data)) ?>" - data-filteredtag="<?= htmlReady(Request::get('tag')) ?>" - data-filteredcategory="<?= htmlReady(Request::get('category')) ?>" - data-tags="<?= htmlReady(json_encode($tags)) ?>" - data-material_select_url_template="<?= htmlReady($controller->detailsURL('__material_id__')) ?>"> - <?= $this->render_partial('oer/market/_searchform') ?> -</form> - +<?= Studip\VueApp::create('OERSearch') + ->withProps([ + 'url' => $controller->link_for('oer/market/search'), + 'search-results' => $material_data, + 'filtered-tag' => Request::get('tag'), + 'filtered-category' => Request::get('category'), + 'tags' => $tags, + 'material-select-url-template' => $controller->detailsURL('__material_id__'), + ]) ?> <? if (!empty($new_ones)) : ?> <div id="new_ones"> @@ -26,10 +24,3 @@ </ul> </div> <? endif ?> - - - - - - -<? diff --git a/resources/assets/javascripts/bootstrap/oer.js b/resources/assets/javascripts/bootstrap/oer.js index 2b471496a64a13ba051119b69d50593b4c974831..3adecbc8482a3c798ff6a1788ad583a2bd42eba2 100644 --- a/resources/assets/javascripts/bootstrap/oer.js +++ b/resources/assets/javascripts/bootstrap/oer.js @@ -1,9 +1,6 @@ import Quicksearch from '../../../vue/components/Quicksearch.vue'; STUDIP.domReady(() => { - if (jQuery(".oer_search").length) { - STUDIP.OER.initSearch(); - } jQuery(".serversettings .index_server a").on("click", function () { var host_id = jQuery(this).closest("tr").data("host_id"); var active = jQuery(this).is(".checked") ? 0 : 1; diff --git a/resources/assets/javascripts/lib/oer.js b/resources/assets/javascripts/lib/oer.js index 17f0186ad114c1d9b8ab050ff0a7ea0f249a636c..f9e175e5b84ad1f30127857799608c1f2a5e777f 100644 --- a/resources/assets/javascripts/lib/oer.js +++ b/resources/assets/javascripts/lib/oer.js @@ -32,212 +32,7 @@ const OER = { } else if (player.webkitRequestFullscreen) { player.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); } - }, - initSearch: function () { - STUDIP.Vue.load().then(({createApp}) => { - STUDIP.OER.Search = createApp({ - el: ".oer_search", - data() { - return { - browseMode: false, - tags: $(".oer_search").data("tags"), - tagHistory: [], - searchtext: "", - activeFilterPanel: false, - difficulty: [1, 12], - category: null, - results: false, - material_select_url_template: $(".oer_search").data("material_select_url_template") - }; - }, - methods: { - sync_search_text: function () { - this.searchtext = $(".oer_search input[name=search]").val(); - }, - triggerFilterPanel: function () { - this.activeFilterPanel = !this.activeFilterPanel; - }, - showFilterPanel: function () { - this.activeFilterPanel = true; - }, - hideFilterPanel: function () { - this.activeFilterPanel = false; - }, - clearAllFilters: function (keep_results) { - this.clearCategory(); - this.clearDifficulty(); - if (this.searchtext != '') { - this.searchtext = ''; - } - $(".oer_search input[name=search]").val(''); - if (keep_results !== true) { - this.results = false; - } - }, - clearDifficulty: function () { - if ((this.difficulty[0] != 1) && (this.difficulty[1] != 12)) { - this.difficulty = [1, 12]; - } - jQuery("#difficulty_slider").slider("values", this.difficulty); - }, - clearCategory: function () { - if (this.category != null) { - this.category = null; - } - }, - getIconShape: function (result) { - if (result.category === "video") { - return "video"; - } - if (result.category === "audio") { - return "file-audio"; - } - if (result.category === "presentation") { - return "file-pdf"; - } - if (result.category === "elearning") { - return "learnmodule"; - } - if (result.content_type === "application/zip") { - return "archive3"; - } - return "file"; - }, - search: function () { - let v = this; - this.browseMode = false; - $.ajax({ - url: STUDIP.URLHelper.getURL("dispatch.php/oer/market/search"), - data: { - type: this.category, - difficulty: this.difficulty.join(","), - search: this.searchtext - }, - dataType: "json", - success: function (output) { - $("#new_ones").hide(); - v.results = output.materials; - v.activeFilterPanel = false; - $(".material_navigation").toggle(v.results.length == 0); - $(".mainlist").toggle(v.results.length == 0); - $(".new_ones").toggle(v.results.length == 0); - } - }); - return false; - }, - browseTag: function (tag_hash, name) { - let v = this; - this.clearAllFilters(true); - let tags = []; - for (let i in this.tagHistory) { - tags.push(this.tagHistory[i].tag_hash); - } - if (tag_hash && (tags.indexOf(tag_hash) === -1)) { - tags.push(tag_hash); - } - let p = new Promise(function (resolve, reject) { - $.ajax({ - url: STUDIP.URLHelper.getURL("dispatch.php/oer/market/get_tags"), - data: { - tags: tags - }, - dataType: "json", - success: function (output) { - v.results = output.results.materials; - v.tags = output.tags; - if (tag_hash) { - v.tagHistory.push({ - tag_hash: tag_hash, - name: name - }); - } - if (v.tagHistory.length > 0) { - $("#new_ones").hide(); - } - resolve(); - }, - error: function (jqXHR, textStatus, errorThrown) { - reject(new Error(errorThrown)); - } - }); - }); - return p; - }, - backInCloud: function () { - if (this.tagHistory.length === 0) { - this.browseMode = false; - return; - } - this.tagHistory.pop(); - let tag_hash = null; - let tag_name = null; - if (this.tagHistory.length > 0) { - tag_hash = this.tagHistory[this.tagHistory.length - 1].tag_hash; - tag_name = this.tagHistory[this.tagHistory.length - 1].name; - } - let v = this; - this.tagHistory.pop(); - this.browseTag(tag_hash, tag_name).then(function () { - if (v.tagHistory.length === 0) { - $("#new_ones").show(); - } - }); - - }, - getTagStyle: function (tag_hash) { - return "position: relative; top: " + Math.floor(Math.random() * 15 - 15) + "px"; - }, - capitalizeFirstLetter: function (string) { - return string.charAt(0).toUpperCase() + string.slice(1); - }, - getMaterialURL: function (material_id) { - return this.material_select_url_template.replace("__material_id__", material_id); - }, - shortenName: function (name) { - if (name.length > 55) { - return name.substring(0, 50) + ' ...'; - } else { - return name; - } - } - }, - mounted: function () { - this.results = $(this.$el).data('searchresults'); - if (this.results !== false) { - $("#new_ones").hide(); - } - if ($(this.$el).data('filteredcategory')) { - this.category = $(this.$el).data('filteredcategory'); - } - }, - updated: function () { - this.$nextTick(function () { - if (!jQuery("#difficulty_slider.ui-slider").length) { //to prevent an endless loop - let v = this; - jQuery("#difficulty_slider").slider({ - range: true, - min: 1, - max: 12, - values: [v.difficulty[0], v.difficulty[1]], - change: function (event, ui) { - v.difficulty = ui.values; - } - }); - } - }); - } - }); - }); - - - jQuery(document).on("click", function (evnt) { - if (!jQuery(evnt.target).is(".searchform *") && STUDIP.OER.Search) { - STUDIP.OER.Search.hideFilterPanel(); - } - }); - } }; - export default OER; diff --git a/resources/assets/stylesheets/scss/oer.scss b/resources/assets/stylesheets/scss/oer.scss index 4fcb1801f1a240b7c81571d3028fea77f9d55ff4..45c9361e1607200a8ef04f4a244c9b1e5c08b363 100644 --- a/resources/assets/stylesheets/scss/oer.scss +++ b/resources/assets/stylesheets/scss/oer.scss @@ -275,7 +275,7 @@ ul.reviews, ol.reviews { margin-left: 5px; } - button { + button[type="button"] { border-right: none; border-bottom: none; border-top: none; @@ -296,7 +296,7 @@ ul.reviews, ol.reviews { } } - button { + button[type="button"] { border: thin solid var(--content-color-40); background-color: var(--content-color-20); display: flex; @@ -304,10 +304,6 @@ ul.reviews, ol.reviews { justify-content: center; width: 35px; } - - > button { - margin-left: 10px; - } } .filterpanel { diff --git a/resources/vue/components/OERSearch.vue b/resources/vue/components/OERSearch.vue new file mode 100644 index 0000000000000000000000000000000000000000..e3975f33179d471b5ea51c51fb7852205445f7b0 --- /dev/null +++ b/resources/vue/components/OERSearch.vue @@ -0,0 +1,385 @@ +<template> + <form class="oer_search" :action="url"> + <div class="searchform"> + <div class="oneliner"> + <div class="frame"> + <span v-if="category != null" + class="category activefilter" :title="$gettext('Aktiver Filter der Kategorie')"> + <span>{{ category }}</span> + <a href="#" + @click.prevent="clearCategory()" + class="erasefilter" + :title="$gettext('Filter der Kategorie entfernen')"> + <studip-icon shape="decline" class="text-bottom"></studip-icon> + </a> + </span> + + <span v-if="difficulty[0] != 1 || difficulty[1] != 12" + class="niveau activefilter" + title="$gettext('Aktiver Filter für das Niveau')" + > + {{ $gettext('Niveau') }}: + <span>{{ difficulty[0] }}</span> + - + <span>{{ difficulty[1] }}</span> + <a href="#" + @click.prevent="clearDifficulty()" + class="erasefilter" + :title="$gettext('Filter des Niveaus entfernen')"> + <studip-icon shape="decline" class="text-bottom"></studip-icon> + </a> + </span> + + <input type="text" + name="search" + v-model.trim="searchtext" + @focus="toggleFilterPanel(true)" + @keydown.enter.prevent="search()"> + + <button v-if="difficulty[0] != 1 || difficulty[1] != 12 || (category != null) || (searchtext.length > 0)" + class="erase" + type="button" + :title="$gettext('Suchformular zurücksetzen')" + @click="clearAllFilters"> + <studip-icon shape="decline"></studip-icon> + </button> + + <button @click="toggleFilterPanel()" + type="button" + :title="$gettext('Suchfilter einstellen')" + :class="activeFilterPanel ? 'active' : ''"> + <studip-icon shape="filter" :role="activeFilterPanel ? 'info_alt' : 'clickable'"></studip-icon> + </button> + + <div v-if="activeFilterPanel" class="filterpanel_shadow"></div> + + <div v-if="activeFilterPanel" class="filterpanel"> + <div> + <h3>{{ $gettext('Kategorien') }}</h3> + <ul class="clean"> + <li> + <button class="as-link" @click.prevent="category = 'audio'"> + <studip-icon :shape="category === 'audio' ? 'radiobutton-checked' : 'radiobutton-unchecked'" class="text-bottom"></studip-icon> + {{ $gettext('Audio') }} + </button> + </li> + <li> + <button class="as-link" @click.prevent="category = 'video'"> + <studip-icon :shape="category === 'video' ? 'radiobutton-checked' : 'radiobutton-unchecked'" class="text-bottom"></studip-icon> + {{ $gettext('Video') }} + </button> + </li> + <li> + <button class="as-link" @click.prevent="category = 'presentation'"> + <studip-icon :shape="category === 'presentation' ? 'radiobutton-checked' : 'radiobutton-unchecked'" class="text-bottom"></studip-icon> + {{ $gettext('Folien') }} + </button> + </li> + <li> + <button class="as-link" @click.prevent="category = 'elearning'"> + <studip-icon :shape="category === 'elearning' ? 'radiobutton-checked' : 'radiobutton-unchecked'" class="text-bottom"></studip-icon> + {{ $gettext('Lernmodule') }} + </button> + </li> + <li> + <button class="as-link" @click.prevent="category = null"> + <studip-icon shape="link-intern" class="text-bottom"></studip-icon> + {{ $gettext('Alles') }} + </button> + </li> + </ul> + </div> + <div class="level_filter"> + <h3>{{ $gettext('Niveau') }}</h3> + <div class="level_labels"> + <div>{{ $gettext('Leicht') }}</div> + <div>{{ $gettext('Schwer') }}</div> + </div> + <div class="level_numbers"> + <div v-for="i in 12" :key="i" style="text-align: right"> + {{ i }} + </div> + </div> + <div id="difficulty_slider"></div> + + <input type="hidden" id="difficulty" name="difficulty" value=""> + </div> + </div> + + + <button :title="$gettext('Suche starten')" + @click.prevent="search()" + @focus="toggleFilterPanel(false)" + type="button" + > + <studip-icon shape="search"></studip-icon> + </button> + </div> + + </div> + + + </div> + + <div class="browser"> + + <div v-if="browseMode === false" class="intro"> + <StudipAssetImg file="oer-keyvisual-negative.svg" class="illustration responsive-hidden"></StudipAssetImg> + <div> + <h3>{{ $gettext('Wertvolle Lernmaterialien entdecken!') }}</h3> + <div class="responsive-hidden"> + {{ $gettext('Neue und spannende Lernmaterialien zu finden, ist ganz einfach. Mit dem Entdeckermodus können Sie nach Schlagwörtern stöbern und durch Themengebiete surfen.') }} + </div> + + <div> + <button class="button" @click.prevent="browseMode = true"> + {{ $gettext('Zum Entdeckermodus') }} + </button> + </div> + </div> + </div> + + <div v-if="browseMode === true" class="tagcloud"> + <div> + <h3>{{ $gettext('Wertvolle Materialien entdecken!') }}</h3> + {{ $gettext('Klicken Sie auf die Schlagwörter und entdecken Sie Lernmaterialien zum Thema.') }} + </div> + <a href="" @click.prevent="backInCloud" class="back-button"> + <studip-icon shape="arr_1left" :size="50"></studip-icon> + </a> + <ul class="tags clean"> + <li v-for="tag in tagCloud"> + <a href="#" + class="button" + :style="getTagStyle(tag.tag_hash)" + :title="tag.name" + @click.prevent="browseTag(tag.tag_hash, tag.name)" + > + #{{ tag.name }} + </a> + </li> + </ul> + </div> + + </div> + + <div v-if="browseMode && results && results.length === 0" class="oer_no_results"> + <StudipMessageBox type="info" :hide-close="true"> + {{ $gettext('Keine Ergebnisse gefunden.') }} + </StudipMessageBox> + </div> + + <ul class="results oer_material_overview" v-if="results && results.length > 0"> + <li v-for="result in results" :key="result.material_id"> + <article class="contentbox" :title="result.name"> + <a :href="getMaterialURL(result.material_id)" target="_blank"> + <header> + <h1> + <studip-icon :shape="getIconShape(result)" + class="text-bottom"></studip-icon> + {{ shortenName(result.name) }} + </h1> + </header> + <div class="image" :style="`background-image: url(${result.logo_url});${!result.front_image_content_type ? ' background-size: 60% auto;' : ''}`"></div> + </a> + </article> + </li> + </ul> + + </form> +</template> +<script> +import StudipMessageBox from './StudipMessageBox.vue'; +import StudipAssetImg from './StudipAssetImg.vue'; + +export default { + name: 'OERSearch', + components: {StudipAssetImg, StudipMessageBox}, + props: { + searchResults: [Array, Boolean], + filteredTag: String, + filteredCategory: String, + tags: Array, + materialSelectUrlTemplate: String, + toPlugin: String, + toFolderId: String, + url: { + type: String, + required: true, + } + }, + data() { + return { + browseMode: false, + tagHistory: [], + searchtext: '', + activeFilterPanel: false, + difficulty: [1, 12], + category: null, + results: this.searchResults || false, + }; + }, + computed: { + tagCloud() { + const history = this.tagHistory.map(tag => tag.tag_hash); + return this.tags.filter(tag => !history.includes(tag.tag_hash)); + } + }, + methods: { + toggleFilterPanel(state = null) { + this.activeFilterPanel = state ?? !this.activeFilterPanel; + }, + clearAllFilters(keep_results) { + this.clearCategory(); + this.clearDifficulty(); + this.searchtext = ''; + if (!keep_results) { + this.results = false; + } + }, + clearDifficulty() { + if (this.difficulty[0] != 1 && this.difficulty[1] != 12) { + this.difficulty = [1, 12]; + } + jQuery("#difficulty_slider").slider("values", this.difficulty); + }, + clearCategory() { + if (this.category != null) { + this.category = null; + } + }, + getIconShape(result) { + if (result.category === 'video') { + return 'video'; + } + if (result.category === 'audio') { + return 'file-audio'; + } + if (result.category === 'presentation') { + return 'file-pdf'; + } + if (result.category === 'elearning') { + return 'learnmodule'; + } + if (result.content_type === 'application/zip') { + return 'archive3'; + } + return 'file'; + }, + search() { + this.browseMode = false; + $.getJSON(STUDIP.URLHelper.getURL('dispatch.php/oer/market/search', { + type: this.category, + difficulty: this.difficulty.join(','), + search: this.searchtext + })).done(output => { + this.results = output.materials.length; + this.activeFilterPanel = false; + + this.toggleElements( + this.results.length === 0, + '.material_navigation', + '.mainlist', + '#new_ones' + ); + }); + }, + browseTag(tag_hash, name) { + this.clearAllFilters(true); + let tags = this.tagHistory.map(i => i.tag_hash); + if (tag_hash && !tags.includes(tag_hash)) { + tags.push(tag_hash); + } + return $.getJSON(STUDIP.URLHelper.getURL('dispatch.php/oer/market/get_tags', { tags })).done(output => { + this.results = output.results.materials; + + this.$emit('update:tags', output.tags); + + if (tag_hash) { + this.tagHistory.push({ tag_hash, name }); + } + if (this.tagHistory.length > 0) { + this.toggleElements(false, '#new_ones'); + } + }); + }, + backInCloud() { + if (this.tagHistory.length === 0) { + this.browseMode = false; + return; + } + this.tagHistory.pop(); + let tag_hash = null; + let tag_name = null; + if (this.tagHistory.length > 0) { + tag_hash = this.tagHistory.at(-1).tag_hash; + tag_name = this.tagHistory.at(-1).name; + } + + this.tagHistory.pop(); + this.browseTag(tag_hash, tag_name).done(() => { + if (this.tagHistory.length === 0) { + this.toggleElements(true, '#new_ones'); + } + }); + + }, + getTagStyle(tag_hash) { + return { + position: 'relative', + top: Math.floor(Math.random() * 15 - 15) + 'px' + }; + }, + capitalizeFirstLetter(string) { + return string.charAt(0).toUpperCase() + string.slice(1); + }, + getMaterialURL(material_id) { + return STUDIP.URLHelper.getURL( + this.materialSelectUrlTemplate.replace('__material_id__', material_id), + { + to_plugin: this.toPlugin, + to_folder_id: this.toFolderId + } + ); + }, + shortenName(name, maxLength = 55) { + if (name.length > maxLength) { + return name.substring(0, maxLength - 3) + ' ...'; + } + + return name; + }, + hideFilterPanelListener(event) { + if (!event.target.closest('.oer_search .searchform')) { + this.toggleFilterPanel(false); + } + }, + toggleElements(state, ...selectors) { + document.querySelectorAll(selectors.join(',')).forEach(node => { + node.style.display = state ? '' : 'none'; + }); + } + }, + mounted() { + this.toggleElements(this.results === false, '#new_ones'); + + document.body.addEventListener('click', this.hideFilterPanelListener); + }, + beforeDestroy() { + document.body.removeEventListener('click', this.hideFilterPanelListener) + }, + updated() { + this.$nextTick(() => { + jQuery("#difficulty_slider:not(.ui-slider)").slider({ + range: true, + min: 1, + max: 12, + values: [this.difficulty[0], this.difficulty[1]], + change: (event, ui) => { + this.difficulty = ui.values; + } + }); + }); + } +}; +</script>