<div class="enablevue">
<searchprogramcomponent id="searchprogramcomponent" texts="" fetch-url="http://localhost:2000/production/KitModules/EPiFind/Services/SearchService.asmx/QueryFreeText" fetch-url-areas="http://localhost:2000/production/KitModules/EPiFind/Services/SearchService.asmx/GetAllAreas"
json='{"query":{"querytext":"","mainfacets":["65227|Kurser|1|False","65227|Program|1|False"],"mainfacet":"All","facets":[],"metafacets":[],"metafacetsor":[],"take":100,"skip":0,"returnSuggestions":true,"addSuggestionsToQuery":false,"sortorder":"","TitleStartsWith":"","SearchPageId":"65227","Language":"sv","DoNotTrack":false,"NoHits":"","UseAutoboost":false,"AddSpellcheckToQuery":false,"WithAndAsDefaultOperator":false}}'
education-type="Type of education" title-text="Title in English" nohits-text="" loading-text="Loading" more-filter-text="More filters" education-text="" studyform-text="Study form" studypace-text="Study pace" progression-text="Progression order" level-text="Level"
termstart-text="Term start" studylocation-text="Location" area-pick-text="Pick a area" area-all-pick-text="All areas" input-placeholder-text="Search course or program" program-button-text="Program" courses-button-text="Courses" search-hit-show-text="Showing"
search-hits-text="hits" application-open-text="Open for application" application-closed-text="Closed" application-late-text="Late application" application-canceled-text="Canceled" hit-course-text="Course" hit-program-text="Program" education-occasion-text="occasion"
education-occasions-text="occasions" status-text="Show only" status-badge-text="Current educations">
</searchprogramcomponent>
</div>
<div class="enablevue">
<searchprogramcomponent id="searchprogramcomponent" texts="{{Strings}}" fetch-url="{{url}}" fetch-url-areas="{{urlAreas}}"
json='{{{Settings}}}'
education-type="{{componentTexts.educationType.value}}"
title-text="{{componentTexts.titleText.value}}"
nohits-text="{{componentTexts.noHits.value}}"
loading-text="{{componentTexts.loadingText.value}}"
more-filter-text="{{componentTexts.moreFilterText.value}}"
education-text="{{componentTexts.educationText.value}}"
studyform-text="{{componentTexts.studyformText.value}}"
studypace-text="{{componentTexts.studypaceText.value}}"
progression-text="{{componentTexts.progressionText.value}}"
level-text="{{componentTexts.levelText.value}}"
termstart-text="{{componentTexts.termstartText.value}}"
studylocation-text="{{componentTexts.studylocationText.value}}"
area-pick-text="{{componentTexts.areaPickText.value}}"
area-all-pick-text="{{componentTexts.areaAllPickText.value}}"
input-placeholder-text="{{componentTexts.inputPlaceholderText.value}}"
program-button-text="{{componentTexts.programButtonText.value}}"
courses-button-text="{{componentTexts.coursesButtonText.value}}"
search-hit-show-text="{{componentTexts.searchHitShowText.value}}"
search-hits-text="{{componentTexts.searchHitsText.value}}"
application-open-text="{{componentTexts.applicationOpenText.value}}"
application-closed-text="{{componentTexts.applicationClosedText.value}}"
application-late-text="{{componentTexts.applicationLateText.value}}"
application-canceled-text="{{componentTexts.applicationCanceledText.value}}"
hit-course-text="{{componentTexts.hitCourseText.value}}"
hit-program-text="{{componentTexts.hitProgramText.value}}"
education-occasion-text="{{componentTexts.educationOccasionText.value}}"
education-occasions-text="{{componentTexts.educationOccasionsText.value}}"
status-text="{{componentTexts.statusText.value}}"
status-badge-text="{{componentTexts.statusBadgeText.value}}"
>
</searchprogramcomponent>
</div>
{
"componentTexts": {
"titleText": {
"value": "Title in English"
},
"educationType": {
"value": "Type of education"
},
"nohitsText": {
"value": "No hits found!"
},
"loadingText": {
"value": "Loading"
},
"moreFilterText": {
"value": "More filters"
},
"studyformText": {
"value": "Study form"
},
"studypaceText": {
"value": "Study pace"
},
"progressionText": {
"value": "Progression order"
},
"levelText": {
"value": "Level"
},
"termstartText": {
"value": "Term start"
},
"studylocationText": {
"value": "Location"
},
"statusText": {
"value": "Show only"
},
"statusBadgeText": {
"value": "Current educations"
},
"areaPickText": {
"value": "Pick a area"
},
"areaAllPickText": {
"value": "All areas"
},
"inputPlaceholderText": {
"value": "Search course or program"
},
"programButtonText": {
"value": "Program"
},
"coursesButtonText": {
"value": "Courses"
},
"searchHitShowText": {
"value": "Showing"
},
"searchHitsText": {
"value": "hits"
},
"applicationOpenText": {
"value": "Open for application"
},
"applicationClosedText": {
"value": "Closed"
},
"applicationLateText": {
"value": "Late application"
},
"applicationCanceledText": {
"value": "Canceled"
},
"educationOccasionText": {
"value": "occasion"
},
"educationOccasionsText": {
"value": "occasions"
},
"hitCourseText": {
"value": "Course"
},
"hitProgramText": {
"value": "Program"
}
},
"urlAreas": "http://localhost:2000/production/KitModules/EPiFind/Services/SearchService.asmx/GetAllAreas",
"url": "http://localhost:2000/production/KitModules/EPiFind/Services/SearchService.asmx/QueryFreeText",
"Settings": "{\"query\":{\"querytext\":\"\",\"mainfacets\":[\"65227|Kurser|1|False\",\"65227|Program|1|False\"],\"mainfacet\":\"All\",\"facets\":[],\"metafacets\":[],\"metafacetsor\":[],\"take\":100,\"skip\":0,\"returnSuggestions\":true,\"addSuggestionsToQuery\":false,\"sortorder\":\"\",\"TitleStartsWith\":\"\",\"SearchPageId\":\"65227\",\"Language\":\"sv\",\"DoNotTrack\":false,\"NoHits\":\"\",\"UseAutoboost\":false,\"AddSpellcheckToQuery\":false,\"WithAndAsDefaultOperator\":false}}"
}
import { BulmaAccordion, BulmaAccordionItem } from "vue-bulma-accordion";
Vue.component("searchprogramcomponent", {
props: [
"titleText",
"educationType",
"nohitsText",
"loadingText",
"moreFilterText",
"studyformText",
"studypaceText",
"progressionText",
"levelText",
"termstartText",
"studylocationText",
"areaPickText",
"areaAllPickText",
"inputPlaceholderText",
"programButtonText",
"coursesButtonText",
"searchHitShowText",
"searchHitsText",
"applicationOpenText",
"applicationClosedText",
"applicationLateText",
"applicationCanceledText",
"hitCourseText",
"hitProgramText",
"statusText",
"statusBadgeText",
"educationOccasionText",
"educationOccasionsText"
],
data() {
return {
isDisabled: false,
areas: "",
hits: "",
filters: "",
filtersAreOpen: false,
userHasSearched: false,
hasDefaultArea: "",
hasDefaultQueryText: "",
url: "",
currentDate: Date.now(),
initialRequest: {
query: {}
},
searchHitCount: 0,
activeFilters: [],
showProgramsOnly: false,
showCoursesOnly: false,
strings: {
educationType: JSON.parse(JSON.stringify(this.educationType)),
titleText: JSON.parse(JSON.stringify(this.titleText)),
nohitsText: JSON.parse(JSON.stringify(this.nohitsText)),
loadingText: JSON.parse(JSON.stringify(this.loadingText)),
moreFilterText: JSON.parse(JSON.stringify(this.moreFilterText)),
studyFormText: JSON.parse(JSON.stringify(this.studyformText)),
studyPaceText: JSON.parse(JSON.stringify(this.studypaceText)),
progressionText: JSON.parse(JSON.stringify(this.progressionText)),
statusText: this.statusText,
statusBadgeText: this.statusBadgeText,
levelText: JSON.parse(JSON.stringify(this.levelText)),
termStartText: JSON.parse(JSON.stringify(this.termstartText)),
studyLocationText: JSON.parse(JSON.stringify(this.studylocationText)),
areaPickText: JSON.parse(JSON.stringify(this.areaPickText)),
areaAllPickText: JSON.parse(JSON.stringify(this.areaAllPickText)),
inputPlaceholderText: JSON.parse(
JSON.stringify(this.inputPlaceholderText)
),
programButtonText: JSON.parse(JSON.stringify(this.programButtonText)),
coursesButtonText: JSON.parse(JSON.stringify(this.coursesButtonText)),
searchHitShowText: JSON.parse(JSON.stringify(this.searchHitShowText)),
searchHitsText: JSON.parse(JSON.stringify(this.searchHitsText)),
applicationOpenText: JSON.parse(
JSON.stringify(this.applicationOpenText)
),
applicationClosedText: JSON.parse(
JSON.stringify(this.applicationClosedText)
),
applicationLateText: JSON.parse(
JSON.stringify(this.applicationLateText)
),
applicationCanceledText: JSON.parse(
JSON.stringify(this.applicationCanceledText)
),
hitCourseText: JSON.parse(JSON.stringify(this.hitCourseText)),
hitProgramText: JSON.parse(JSON.stringify(this.hitProgramText)),
educationOccasionText: JSON.parse(
JSON.stringify(this.educationOccasionText)
),
educationOccasionsText: JSON.parse(
JSON.stringify(this.educationOccasionsText)
)
}
};
},
mounted() {
this.atInit();
},
components: {
BulmaAccordionItem,
BulmaAccordion
},
methods: {
updateQuery(value) {
this.initialRequest.query.querytext = value;
},
atInit() {
if (document.getElementById("searchprogramcomponent")) {
let page = document.getElementById("searchprogramcomponent");
let url = page.getAttribute("fetch-url");
let request = JSON.parse(page.getAttribute("json"));
if (page && url && request) {
this.initialRequest = request;
console.log({ iit: this.initialRequest })
if(request.query.metafacets.length > 0) {
console.log("contains metafacets!", request.query.metafacets)
request.query.metafacets.map(meta => {
this.activeFilters.push(meta)
})
}
if (request.defaults) {
console.log(request.defaults)
let { DefaultArea, DefaultLocation, DefaultMainFacet, DefaultProgression, DefaultSearchTerm, DefaultStudyForm, DefaultStudyPace, DefaultTerm } = request.defaults;
let arrayToBeAddedToMainfacets = [];
if (DefaultArea || DefaultLocation || DefaultMainFacet || DefaultProgression || DefaultStudyForm || DefaultStudyPace || DefaultTerm) {
this.userHasSearched = true;
}
if (DefaultArea) {
arrayToBeAddedToMainfacets.push(DefaultArea)
this.hasDefaultArea = DefaultArea;
}
if (DefaultLocation) {
arrayToBeAddedToMainfacets.push(DefaultLocation)
this.activeFilters.push(DefaultLocation)
}
if (DefaultProgression) {
arrayToBeAddedToMainfacets.push(DefaultProgression)
this.activeFilters.push(DefaultProgression)
}
if (DefaultStudyForm) {
arrayToBeAddedToMainfacets.push(DefaultStudyForm)
this.activeFilters.push(DefaultStudyForm)
}
if (DefaultStudyPace) {
arrayToBeAddedToMainfacets.push(DefaultStudyPace)
this.activeFilters.push(DefaultStudyPace)
}
if (DefaultTerm) {
arrayToBeAddedToMainfacets.push(this.fixTerm(DefaultTerm))
this.activeFilters.push(this.fixTerm(DefaultTerm))
}
if (DefaultMainFacet) {
this.initialRequest.query.mainfacet = DefaultMainFacet;
let emptyArr = [];
emptyArr.push(DefaultMainFacet);
this.initialRequest.query.mainfacets = emptyArr;
if (DefaultMainFacet == "65227|Program|1|False") {
this.showProgramsOnly = true;
}
if (DefaultMainFacet == "65227|Kurser|1|False") {
this.showCoursesOnly = true;
}
}
if (DefaultSearchTerm) {
this.initialRequest.query.querytext = DefaultSearchTerm;
this.hasDefaultQueryText = DefaultSearchTerm;
}
if (arrayToBeAddedToMainfacets.length > 0) {
if (this.activeFilters.length > 0) {
this.filtersAreOpen = true;
}
this.initialRequest.query.metafacets = arrayToBeAddedToMainfacets;
}
}
this.url = url;
this.initialFetch(url, request);
}
}
},
fixTerm(value) {
let newVal = value.replace("Vårterminen", "Våren");
return newVal.replace("Höstterminen", "Hösten");
},
userSubmit(value) {
//Disable Search/Filter View
console.log("Query again", value)
this.fetchAgain(this.url, this.initialRequest);
},
userPickedFilter(value) {
//Disable Search/Filter View
if (
this.activeFilters.includes(value)
) {
let index = this.activeFilters.indexOf(value);
this.activeFilters.splice(index, 1);
let reqIndex = this.initialRequest.query.metafacets.indexOf(value);
this.initialRequest.query.metafacets.splice(reqIndex, 1);
this.fetchAgain(this.url, this.initialRequest);
} else {
this.activeFilters.push(value);
this.initialRequest.query.metafacets.push(value);
this.fetchAgain(this.url, this.initialRequest);
}
},
userpickedCourses(value) {
this.showCoursesOnly = !this.showCoursesOnly;
if (this.showCoursesOnly) {
this.showProgramsOnly = false;
let arr = ["65227|Kurser|1|False"];
this.initialRequest.query.mainfacet = "65227|Kurser|1|False";
this.initialRequest.query.mainfacets = arr;
this.fetchAgain(this.url, this.initialRequest);
}
if (!this.showProgramsOnly && !this.showCoursesOnly) {
let arr = ["65227|Program|1|False", "65227|Kurser|1|False"];
this.initialRequest.query.mainfacet = "All";
this.initialRequest.query.mainfacets = arr;
this.fetchAgain(this.url, this.initialRequest);
}
},
userPickedPrograms(value) {
this.showProgramsOnly = !this.showProgramsOnly;
if (this.showProgramsOnly) {
this.showCoursesOnly = false;
let arr = ["65227|Program|1|False"];
this.initialRequest.query.mainfacet = "65227|Program|1|False";
this.initialRequest.query.mainfacets = arr;
this.fetchAgain(this.url, this.initialRequest);
}
if (!this.showProgramsOnly && !this.showCoursesOnly) {
let arr = ["65227|Program|1|False", "65227|Kurser|1|False"];
this.initialRequest.query.mainfacet = "All";
this.initialRequest.query.mainfacets = arr;
this.fetchAgain(this.url, this.initialRequest);
}
},
userPickedArea(value) {
if (value === "All") {
this.cleanArrayFromAreas(this.initialRequest.query.metafacets);
this.fetchAgain(this.url, this.initialRequest);
} else {
this.cleanArrayFromAreas(this.initialRequest.query.metafacets);
this.activeFilters.push(value);
this.initialRequest.query.metafacets.push(value);
this.fetchAgain(this.url, this.initialRequest);
}
},
cleanArrayFromAreas(arr) {
for (var i = arr.length - 1; i >= 0; i--) {
if (arr[i].includes("Area|")) {
arr.splice(i, 1);
}
}
},
async fetchAgain(url, request) {
try {
this.disableView(true);
let res = await fetch(url, {
method: "post",
headers: {
Accept: "application/json, text/plain, */*",
"Content-Type": "application/json;charset=UTF-8"
},
body: JSON.stringify(request)
});
let data = await res.json();
this.hits = data.d.SearchHits;
if (this.hits.length > 0) {
this.convertApplicationDeadLineDates(this.hits);
this.checkIfCourseIsAvailable(this.hits);
}
this.searchHitCount = data.d.SearchHits.length;
this.disableView(false);
this.userHasSearched = true;
} catch (error) {
this.disableView(false);
}
},
convertApplicationDeadLineDates(items) {
items.forEach(element => {
if (element._source !== null) {
if (element._source.ProgramOccasions.length > 0) {
element._source.ProgramOccasions.map(occasion => {
if (typeof occasion.ApplicationDeadLine === "string") {
let closedDate = moment(occasion.ApplicationClosed).toDate();
let deadLineDate = moment(
occasion.ApplicationDeadLine
).toDate();
occasion.ApplicationClosed = closedDate;
occasion.ApplicationDeadLine = deadLineDate;
} else {
}
});
}
}
});
},
checkIfCourseIsAvailable(items) {
items.map(x => {
if (x._source && x._source.ProgramOccasions.length > 0) {
x._source.ProgramOccasions.map(occasion => {
if (
this.currentDate < occasion.ApplicationDeadLine &&
this.currentDate < occasion.ApplicationClosed &&
!occasion.Canceled
) {
x.HasOpenCourses = true;
}
if (
this.currentDate > occasion.ApplicationDeadLine &&
this.currentDate < occasion.ApplicationClosed &&
!occasion.Canceled
) {
x.HasOpenCourses = true;
}
if (
this.currentDate > occasion.ApplicationClosed &&
!occasion.Canceled
) {
x.HasClosedCourses = true;
}
if (occasion.Canceled) {
x.HasClosedCourses = true;
}
});
}
});
},
async initialFetch(url, request) {
try {
let res = await fetch(url, {
method: "post",
headers: {
Accept: "application/json, text/plain, */*",
"Content-Type": "application/json;charset=UTF-8"
},
body: JSON.stringify(request)
});
let data = await res.json();
if (data.d) {
console.log({ request: request })
console.log({ datad: data.d })
this.areas = data.d.MetaDataFacets.Area;
this.hits = data.d.SearchHits;
this.searchHitCount = data.d.SearchHits.length;
if (this.hits.length > 0) {
this.convertApplicationDeadLineDates(this.hits);
this.checkIfCourseIsAvailable(this.hits);
}
const obj = data.d.MetaDataFacets;
const { Area, Subject, ...filters } = obj;
this.filters = filters;
}
} catch (error) { }
},
disableView(bool) {
this.isDisabled = bool;
},
expandFilters() {
this.filtersAreOpen = !this.filtersAreOpen;
},
clearAreasFromMeta() {
let metafacetsNoAreas = this.initialRequest.query.metafacets.filter(x => !x.includes("Area|"))
console.log({ metafacetsNoAreas: metafacetsNoAreas })
this.initialRequest.query.metafacets = metafacetsNoAreas;
delete this.initialRequest.defaults;
this.fetchAgain(this.url, this.initialRequest);
}
},
watch: {
initialRequest: {
handler(val, oldVal) { },
deep: true
}
},
template: `
<div class="search--container">
<div class="search--title">
<div class="row title-container">
<div class="col-12 text-center">
<h2 class="heading-level-2">
{{strings.titleText}}
</h2>
</div>
</div>
</div>
<loadingcomponent v-if="!this.filters" :text="strings.loadingText" ></loadingcomponent>
<div class="search--search" :class="[this.isDisabled ? 'disabled-view' : '']">
<div class="row">
<div class="col-12 col-md-6">
<areas @clearAreasFromMetafacets="clearAreasFromMeta" :initWithDefaultArea="hasDefaultArea ? hasDefaultArea : ''" :pickText="strings.areaPickText" :allText="strings.areaAllPickText" class="areas" v-if="this.areas" @pickedArea="this.userPickedArea" :areas="this.areas" />
</div>
<div class="col-12 col-md-6">
<searchinput :initWithDefaultSearchTerm="hasDefaultQueryText" :text="strings.inputPlaceholderText" v-if="this.areas" class="search" @userQuery="updateQuery" @userSubmit="userSubmit" />
</div>
</div>
</div>
<div class="search--filters d-flex flex-column" :class="[this.isDisabled ? 'disabled-view' : '']">
<div class="d-flex flex-row flex-wrap">
<programorcourse :educationType="strings.educationType" :programButtonText="strings.programButtonText"
:coursesButtonText="strings.coursesButtonText"
:coursesOnly="this.showCoursesOnly" :programsOnly="this.showProgramsOnly" v-if="this.filters" @pickedPrograms="this.userPickedPrograms" @pickedCourses="this.userpickedCourses" />
<filters class="mr-auto" v-if="this.filters.Studyform && this.activeFilters" :text="strings.studyFormText"
@pickedFilter="this.userPickedFilter" :filters="this.filters.Studyform" :activeFilters="this.activeFilters" />
<button type="button" v-if="this.filters" @click="expandFilters" class="d-flex flex-row button--filters align-items-center">
<transition name="fade" mode="out-in">
<span v-if="filtersAreOpen" class="material-icons mr-1">keyboard_arrow_up</span>
<span v-else class="material-icons mr-1">keyboard_arrow_down</span>
</transition>
<p class="button--text mb-0">{{strings.moreFilterText}}</p>
</button>
</div>
<transition mode="out-in" name="fade">
<div class="search--filters--expanded d-flex flex-wrap" v-if="this.filtersAreOpen">
<filters v-if="this.filters.StudyPace && this.activeFilters" :affix="'%'" :text="strings.studyPaceText"
@pickedFilter="this.userPickedFilter" :filters="this.filters.StudyPace" :activeFilters="this.activeFilters" />
<filters v-if="this.filters.Progression && this.activeFilters" :text="strings.progressionText"
@pickedFilter="this.userPickedFilter" :filters="this.filters.Progression"
:activeFilters="this.activeFilters" />
<filters v-if="this.filters.Level && this.activeFilters" :text="strings.levelText" @pickedFilter="this.userPickedFilter"
:filters="this.filters.Level" :activeFilters="this.activeFilters" />
<filters v-if="this.filters.TermStart && this.activeFilters" :text="strings.termStartText"
@pickedFilter="this.userPickedFilter" :filters="this.filters.TermStart" :activeFilters="this.activeFilters" />
<filters v-if="this.filters.StudyLocation && this.activeFilters" :text="strings.studyLocationText"
@pickedFilter="this.userPickedFilter" :filters="this.filters.StudyLocation"
:activeFilters="this.activeFilters" />
<filters :statusBadgeText="strings.statusBadgeText" v-if="this.filters.Status && this.activeFilters" :text="strings.statusText"
@pickedFilter="this.userPickedFilter" :filters="this.filters.Status"
:activeFilters="this.activeFilters" />
</div>
</transition>
</div>
<div class="search--hits">
<transition mode="out-in" name="fade">
<hits :searchHitsCount="this.searchHitCount" :showPrograms="this.showProgramsOnly" :showCourses="this.showCoursesOnly" v-if="this.hits && this.userHasSearched" :hits="this.hits"
:searchHitShowText="strings.searchHitShowText"
:searchHitsText="strings.searchHitsText"
:applicationOpenText="strings.applicationOpenText"
:applicationClosedText="strings.applicationClosedText"
:applicationLateText="strings.applicationLateText"
:applicationCanceledText="strings.applicationCanceledText"
:educationOccasionText="strings.educationOccasionText"
:educationOccasionsText="strings.educationOccasionsText"
:hitCourseText="strings.hitCourseText"
:hitProgramText="strings.hitProgramText"
/>
</transition>
<transition mode="out-in" name="fade">
<div class="nohits--container" v-if="this.filters && this.searchHitCount == 0 && !this.isDisabled">
<p :class="{'animated shake': this.searchHitCount === 0}">{{strings.nohitsText}}</p>
</div>
</transition>
</div>
</div>
`
});
Vue.component("programorcourse", {
props: [
"coursesOnly",
"programsOnly",
"programButtonText",
"coursesButtonText",
"educationType"
],
data() {
return {
programsButton: false,
coursesButton: false
};
},
methods: {
filterBy(value) {
if (value === "65227|Program|1|False") {
this.$emit("pickedPrograms", value);
}
if (value === "65227|Kurser|1|False") {
this.$emit("pickedCourses", value);
}
}
},
template: `
<div class="filter--container">
<label>{{this.educationType}}</label>
<div class="d-flex flex-row flex-wrap filter--wrapper">
<ul class="d-flex flex-wrap list-unstyled">
<li>
<button type="button" :class="{'selected': programsOnly}" :disabled="coursesOnly" @click="filterBy('65227|Program|1|False')" class="button-small">{{this.programButtonText}}</button>
</li>
<li>
<button type="button" :class="{'selected': coursesOnly}" :disabled="programsOnly" @click="filterBy('65227|Kurser|1|False')" class="button-small">{{this.coursesButtonText}}</button>
</li>
</ul>
</div>
</div>
`
});
Vue.component("areas", {
props: ["areas", "pickText", "allText", "initWithDefaultArea"],
data() {
return {
selected: "",
defaultArea: ""
};
},
methods: {
onChange(event) {
this.$emit("pickedArea", this.defaultArea ? this.defaultArea : this.selected);
if (event.target.value == "All") {
this.$emit("clearAreasFromMetafacets")
}
}
},
mounted() {
this.$nextTick(function () {
this.defaultArea = this.initWithDefaultArea
})
},
template: `
<select :id="this.pickText" :title="this.pickText" class="select-css form-control" v-model="defaultArea ? defaultArea : selected" @change="onChange($event)">
<option disabled value="">{{this.pickText}}</option>
<option value="All">{{this.allText}}</option>
<option v-for="(item, index) in this.areas" :value="item.Term" :key="index">{{item.Text}}</option>
</select>
`
});
Vue.component("searchinput", {
props: ["text", "initWithDefaultSearchTerm"],
data() {
return {
query: "",
isFocus: false,
defaultQuery: ""
};
},
methods: {
submitQuery(e) {
e.preventDefault();
this.$emit("userSubmit", this.query);
}
},
watch: {
query: function (newVal, oldVal) {
this.$emit("userQuery", this.query);
}
},
mounted() {
this.$nextTick(function () {
this.query = this.initWithDefaultSearchTerm
})
},
template: `
<form :title="this.text" @submit.prevent(submitQuery) :class="{'is--focused': isFocus}" class="search--input--container form-control" ref="search">
<input type="text" :alt="this.text" :title="this.text"
:name="this.text" v-model="query" @focus="isFocus = true" @blur="isFocus = false"
:placeholder="this.text" />
<transition name="fade" mode="in-out">
<button @click="this.submitQuery" type="submit" v-if="!isFocus "
class="d-flex align-items-center justify-content-center search--btn">
<span class="material-icons ">search</span>
</button>
<button type="submit" @click="this.submitQuery" v-else
class="d-flex search--btn align-items-center active justify-content-center">
<span class="material-icons blue">search</span>
</button>
</transition>
</form>
`
});
Vue.component("filters", {
props: ["filters", "activeFilters", "text", "affix", "statusBadgeText"],
data() {
return {
active: "",
statusBadge: this.statusBadgeText
};
},
methods: {
submitFilter(value) {
this.$emit("pickedFilter", value);
}
},
mounted() {
if (this.activeFilters) {
this.active = this.activeFilters;
}
},
template: `
<div class="filter--container">
<label v-if="this.text">{{this.text}}</label>
<div class="d-flex flex-row flex-wrap filter--wrapper">
<ul class="d-flex flex-wrap list-unstyled">
<li v-for="(filter, index) in this.filters" :key="index">
<button type="button" :class="{'selected': active.includes(filter.Term)}" class="button-small" @click="submitFilter(filter.Term)">
<template v-if="filter && !filter.Term.includes('Status|')">
<template v-if="filter.Text && filter.Text == 'Normal'">
Campus
</template>
<template v-else>
{{filter.Text}}
</template>
</template>
<template v-if="filter && filter.Term.includes('Status|')">{{statusBadge}}</template>
<template v-if="affix">
<span v-if="active.includes(filter.Term)" class="text-white">{{affix}}</span>
<span v-else>{{affix}}</span>
</template>
</button>
</li>
</ul>
</div>
</div>
`
});
Vue.component("loadingcomponent", {
props: ["text"],
template: `
<div class="d-flex flex-row w-100 pb-5 pt-5">
<button disabled class="d-flex align-items-center button-small ml-auto mr-auto ">
<i class="material-icons">cached</i> <span class="ml-2 filter--button--text" v-if="text">{{text}}</span>
</button>
</div>
`
});
Vue.component("hits", {
props: [
"hits",
"showPrograms",
"showCourses",
"searchHitsCount",
"searchHitShowText",
"searchHitsText",
"applicationOpenText",
"applicationClosedText",
"applicationLateText",
"applicationCanceledText",
"hitCourseText",
"hitProgramText",
"educationOccasionText",
"educationOccasionsText"
],
data() {
return {
currentDate: "",
items: "",
searchHitShow: this.searchHitShowText,
searchHits: this.searchHitsText,
applicationOpen: this.applicationOpenText,
applicationClosed: this.applicationClosedText,
applicationLate: this.applicationLateText,
applicationCanceled: this.applicationCanceledText,
hitCourse: this.hitCourseText,
hitProgram: this.hitProgramText,
educationOccasion: this.educationOccasionText,
educationOccasions: this.educationOccasionsText
};
},
methods: {
convertApplicationDeadLineDates(items) {
items.forEach(element => {
if (element._source !== null) {
if (element._source.ProgramOccasions.length > 0) {
element._source.ProgramOccasions.map(occasion => {
if (typeof occasion.ApplicationDeadLine === "string") {
let closedDate = moment(occasion.ApplicationClosed).toDate();
let deadLineDate = moment(
occasion.ApplicationDeadLine
).toDate();
occasion.ApplicationClosed = closedDate;
occasion.ApplicationDeadLine = deadLineDate;
} else {
}
});
}
}
});
}
},
mounted() {
this.currentDate = moment()._d;
this.items = this.hits;
if (!this.showPrograms && !this.showCourses) {
this.convertApplicationDeadLineDates(this.hits);
}
},
watch: {
items: function () {
if (!this.showPrograms && !this.showCourses) {
this.convertApplicationDeadLineDates(this.hits);
}
}
},
template: `
<div class="hitsarea">
<div v-if="this.searchHitsCount" class="hits--count d-flex flex-row flex-wrap align-items-center">
<p>{{this.searchHitShowText}} <strong>{{this.searchHitsCount}}</strong>
{{this.searchHitsText}}</p>
</div>
<ul class="list-unstyled mb-0" v-for="(item, index) in hits">
<template v-if="item.Section.includes('Program')" class="hits--inner" :icon="'custom'">
<bulma-accordion :key="item.UniqueId">
<bulma-accordion-item>
<div class="d-flex flex-column" slot="title">
<a :href="item.Url">
<h2 v-html="item.Title" class="heading-level-3">
</h2>
</a>
<div class="d-flex flex-row flex-wrap">
<div class="hits-block d-flex flex-row align-items-center">
<p>{{hitProgram}}</p>
</div>
<div class="hits-block d-flex flex-row align-items-center" v-if="item.MetaData && item.MetaData.Points && item.MetaData.Points.StringValue">
<p>{{ item.MetaData.Points.StringValue }} hp</p>
</div>
<div class="hits-block d-flex flex-row align-items-center" v-if="item.MetaData && item.MetaData.Level && item.MetaData.Level.StringValue">
<p>{{ item.MetaData.Level.StringValue }}</p>
</div>
<div class="hits-block d-flex flex-row flex-wrap align-items-center" v-if="item._source && item._source.ProgramOccasions.length > 0">
<p class="d-flex flex-row flex-wrap align-items-center" v-if="item._source.ProgramOccasions.length == 1">
<span class="circle--green" v-if="item.HasOpenCourses"></span>
<span class="circle--grey" v-else-if="item.HasClosedCourses"></span>
{{item._source.ProgramOccasions.length}} {{educationOccasion}}
</p>
<p class="d-flex flex-row flex-wrap align-items-center" v-else>
<span class="circle--green" v-if="item.HasOpenCourses"></span>
<span class="circle--grey" v-else-if="item.HasClosedCourses"></span>
{{item._source.ProgramOccasions.length}} {{educationOccasions}}</p>
</div>
</div>
</div>
<i slot="icon-closed" class="material-icons">keyboard_arrow_down</i>
<i slot="icon-open" class="material-icons">keyboard_arrow_up</i>
<div class="high d-flex flex-column" slot="content">
<div v-if="item._source && item._source.ProgramOccasions && item._source.ProgramOccasions.length > 0" class="hits-occasions d-flex flex-column flex-wrap" v-for="occasion in item._source.ProgramOccasions">
<div class="d-flex flex-row flex-wrap aling-items-center w-100">
<strong v-if="occasion.Orientations && occasion.Orientations.length > 0">{{occasion.Orientations[0].Name}}</strong>
</div>
<div class="d-flex flex-row flex-wrap w-100">
<p>{{occasion.TermStart}}</p>
<p>{{occasion.StudyLocation}}</p>
<p>{{occasion.StudyPace}}</p>
<a :href="item.Url" class="status-link d-flex flex-row align-items-center" v-if="currentDate < occasion.ApplicationDeadLine && currentDate < occasion.ApplicationClosed && !occasion.Canceled">
<span class="circle--green"></span> {{applicationOpen}}
</a>
<a :href="item.Url" class="status-link d-flex flex-row align-items-center" v-if="currentDate > occasion.ApplicationDeadLine && currentDate < occasion.ApplicationClosed && !occasion.Canceled">
<span class="circle--orange"></span> {{applicationLate}}
</a>
<a :href="'https://www.antagning.se/se/search?period=' + occasion.TermStartAbbreviation.slice(0,2) + '+' + occasion.TermStartAbbreviation.slice(2, 6) + '&freeText=' + occasion.RegistrationCode" class="status-link d-flex flex-row align-items-center" v-if="currentDate > occasion.ApplicationClosed && !occasion.Canceled">
<span class="circle--grey"></span> {{applicationClosed}}
</a>
<a :href="'https://www.antagning.se/se/search?period=' + occasion.TermStartAbbreviation.slice(0,2) + '+' + occasion.TermStartAbbreviation.slice(2, 6) + '&freeText=' + occasion.RegistrationCode" class="status-link d-flex flex-row align-items-center" v-if="occasion.Canceled">
<span class="circle--grey"></span> {{applicationCanceled}}
</a>
</div>
</div>
</div>
</bulma-accordion-item>
</bulma-accordion>
</template>
<template v-if="item.Section.includes('Kurs')">
<li :key="item.UniqueId">
<div class="d-flex flex-column hits-inner">
<a :href="item.Url">
<h2 class="heading-level-3" v-html="item.Title"></h2>
</a>
<div class="d-flex flex-row flex-wrap">
<div class="d-flex flex-row flex-wrap">
<div class="hits-block d-flex flex-row align-items-center">
<p>{{hitCourse}}</p>
</div>
<div class="hits-block d-flex flex-row align-items-center" v-if="item.MetaData && item.MetaData.Points && item.MetaData.Points.StringValue">
<p>{{ item.MetaData.Points.StringValue }} hp</p>
</div>
<div class="hits-block d-flex flex-row align-items-center" v-if="item.MetaData && item.MetaData.Level && item.MetaData.Level.StringValue">
<p>{{ item.MetaData.Level.StringValue }}</p>
</div>
</div>
</div>
</div>
</li>
</template>
</ul>
</div>
`
});
.container-fluid .container {
padding-left: 0;
padding-right: 0;
}
.circle--green {
width: 10px;
height: 10px;
background: #27ae60;
border-radius: 50%;
margin-right: 5px;
}
.circle--orange {
width: 10px;
height: 10px;
background: orange;
border-radius: 50%;
margin-right: 5px;
}
.circle--grey {
width: 10px;
height: 10px;
background: $dark-grey;
opacity: 0.4;
border-radius: 50%;
margin-right: 5px;
}
.search--container {
position: relative;
width: 100%;
min-height: 150px;
.accordion {
a {
&.status-link {
color: $dark-grey;
}
}
.card {
border-left: 0px solid;
border-right: 0px solid;
border-top: 1px solid $grey-border;
background-color: #fff;
border-bottom: 0px solid $grey-border;
color: #4a4a4a;
max-width: 100%;
position: relative;
.accordion-body {
height: 0;
overflow: hidden;
.card-content {
background-color: transparent;
transition: all 0.3s ease;
.hits-occasions {
background-color: $bg-grey;
border-top: 1px solid $grey-border;
padding: $xs-space;
margin-top: 5px;
margin-bottom: 5px;
&:first-child {
padding-top: $xs-space;
}
&:last-child {
padding-bottom: $xs-space;
}
p {
margin-right: $xs-space;
margin-bottom: 0px;
padding: 0;
font-size: 16px;
line-height: 24px;
&:last-child {
margin-right: 0px;
}
}
}
}
.card-footer {
background-color: transparent;
border-top: 1px solid $grey-border;
align-items: stretch;
display: flex;
&.is-hidden {
display: none !important;
}
}
}
.card-header {
background-color: transparent;
align-items: stretch;
display: flex;
transition: all 0.3s ease;
padding-left: 0px;
padding-right: 0px;
border-bottom: 1px solid #fff;
padding-top: 20px;
padding-bottom: 20px;
@include media-breakpoint-down(md) {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.card-header-title {
align-items: center;
color: $dark-grey;
display: flex;
flex-grow: 1;
font-family: "Lato Bold";
padding: 0px;
margin-bottom: 0px;
@include media-breakpoint-down(md) {
max-width: 80%;
}
p {
margin-bottom: 0px;
}
}
}
.card-header-icon {
align-items: center;
cursor: pointer;
display: flex;
justify-content: center;
padding: 0.75rem;
margin-bottom: 0px;
@include media-breakpoint-down(md) {
width: 20%;
}
.icon {
align-items: center;
display: inline-flex;
justify-content: center;
height: 0.9rem;
width: 0.9rem;
transform: rotate(180deg);
}
}
}
}
.hits-block {
margin-right: $xs-space;
p {
margin-bottom: 0px;
font-family: Lato;
font-style: normal;
font-size: 16px;
line-height: 24px;
}
}
.circle--green {
width: 10px;
height: 10px;
background: #27ae60;
border-radius: 50%;
margin-right: 5px;
}
.circle--orange {
width: 10px;
height: 10px;
background: orange;
border-radius: 50%;
margin-right: 5px;
}
.circle--grey {
width: 10px;
height: 10px;
background: $dark-grey;
opacity: 0.4;
border-radius: 50%;
margin-right: 5px;
}
.button--filters {
border: none;
cursor: pointer;
margin-top: 12px;
padding: 0;
@include media-breakpoint-down(md) {
margin-bottom: $xs-space;
margin-top: 0px;
}
p {
font-family: "Lato Bold";
font-size: 16px;
}
background-color: transparent;
}
.search--header {
padding: 30px 0;
text-align: right;
a {
color: $dark-grey;
margin-right: $md-space;
span {
vertical-align: middle;
margin-right: 5px;
font-size: 20px;
}
}
}
.nohits--container {
padding: 0px 15px 20px 15px;
.animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.animated.infinite {
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
.animated.hinge {
-webkit-animation-duration: 2s;
animation-duration: 2s;
}
.animated.bounceIn,
.animated.bounceOut {
-webkit-animation-duration: 0.75s;
animation-duration: 0.75s;
}
.animated.flipOutX,
.animated.flipOutY {
-webkit-animation-duration: 0.75s;
animation-duration: 0.75s;
}
@-webkit-keyframes shake {
from,
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
-webkit-transform: translate3d(-10px, 0, 0);
transform: translate3d(-10px, 0, 0);
}
20%,
40%,
60%,
80% {
-webkit-transform: translate3d(10px, 0, 0);
transform: translate3d(10px, 0, 0);
}
}
@keyframes shake {
from,
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
-webkit-transform: translate3d(-10px, 0, 0);
transform: translate3d(-10px, 0, 0);
}
20%,
40%,
60%,
80% {
-webkit-transform: translate3d(10px, 0, 0);
transform: translate3d(10px, 0, 0);
}
}
.shake {
-webkit-animation-name: shake;
animation-name: shake;
}
p {
margin-bottom: 0px;
font-family: "Lato Bold";
}
}
.hits--count {
padding: 30px 0;
text-align: right;
p {
margin-bottom: 0px;
}
a {
color: $dark-grey;
margin-right: $md-space;
span {
vertical-align: middle;
margin-right: 5px;
font-size: 20px;
}
}
}
.button-small {
margin-right: 10px;
font-family: "Lato";
font-size: 16px;
line-height: 19px;
margin-bottom: 5px;
margin-top: 5px;
border-radius: 500px;
&.selected {
font-family: "Lato Bold";
}
}
.search--title {
margin-top: $xs-space;
.title-container{
margin-bottom: $xs-space;
}
}
.search--search {
margin-top: $xs-space;
.search {
@include media-breakpoint-down(sm) {
margin-bottom: 20px;
}
}
select {
margin-bottom: 20px;
}
.search--input {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z'/%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
background-repeat: no-repeat, repeat;
background-position: right 0.7em top 50%, 0 0;
background-size: 1.5em auto, 100%;
transition: all 0.3s ease;
&:hover {
border-color: $grey-hover;
background-color: $grey-hover;
}
&:focus {
border-color: $grey-hover;
background-color: $grey-hover;
}
&::placeholder {
/* Chrome, Firefox, Opera, Safari 10.1+ */
color: rgba(64, 64, 64, 0.7);
}
}
}
.search--hits{
text-align: left;
}
.hits--inner{
text-align: left;
}
.search--filters {
text-align: left;
.more--filters--button {
margin-top: auto;
margin-bottom: 25px;
}
.filter--container {
max-width: 60%;
margin-right: 20px;
.filter--wrapper {
ul {
flex-basis: 100%;
}
}
@include media-breakpoint-up(xs) {
max-width: 100%;
}
label {
font-family: "Lato Bold";
font-style: normal;
font-size: 16px;
line-height: 19px;
}
}
}
}
//IE 11 FIX
_:-ms-fullscreen, :root .search--container .search--filters .filter--container { width: 100%; }
.disabled-view {
position: relative;
pointer-events: none;
&:after {
content: "";
background: rgba(255, 255, 255, 0.6);
position: absolute;
left: 0;
bottom: 0;
top: 0;
transition: all 0.3s ease;
pointer-events: none;
width: 100%;
}
}
.top--primary--search--program--area {
.totalhits {
font-family: "Lato Bold";
}
.filter--button--text {
font-size: 16px;
}
.disabled--overlay {
background: transparent;
transition: all 0.3s ease;
&::before {
content: "";
background: transparent;
position: absolute;
left: 0;
bottom: 0;
top: 0;
transition: all 0.3s ease;
pointer-events: none;
width: 100%;
}
&:after {
content: "";
background: rgba(255, 255, 255, 0.6);
position: absolute;
left: 0;
bottom: 0;
top: 0;
transition: all 0.3s ease;
pointer-events: none;
width: 100%;
}
}
.search--input {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z'/%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3C/svg%3E");
background-repeat: no-repeat, repeat;
background-position: right 0.7em top 50%, 0 0;
background-size: 1.5em auto, 100%;
transition: all 0.3s ease;
&:hover {
border-color: $grey-hover;
background-color: $grey-hover;
}
&:focus {
border-color: $grey-hover;
background-color: $grey-hover;
}
&::placeholder {
/* Chrome, Firefox, Opera, Safari 10.1+ */
color: rgba(64, 64, 64, 0.7);
}
}
.button-small {
margin-right: 10px;
font-family: "Lato";
font-size: 16px;
margin-bottom: 5px;
margin-top: 5px;
&.selected {
font-family: "Lato Bold";
}
}
.button--col--filter {
margin-bottom: 5px;
@include media-breakpoint-down(sm) {
margin-top: 15px;
button {
padding: 0;
margin-bottom: 0px;
}
}
@include media-breakpoint-up(sm) {
margin-left: auto;
}
}
.button--col {
margin-right: 50px;
margin-top: 10px;
}
.button--filters {
border: none;
cursor: pointer;
p {
font-family: "Lato Bold";
font-size: 16px;
}
background-color: transparent;
}
.button-group-title {
margin-bottom: 5px;
font-family: "Lato Bold";
}
.search--container {
margin-top: -50px;
box-shadow: $box-shadow;
background-color: white;
position: relative;
width: 100%;
.search--filter {
padding-bottom: 60px;
margin-top: 5px;
@include media-breakpoint-down(sm) {
padding-bottom: 10px;
}
}
.search--header {
padding: 30px 0;
text-align: right;
a {
color: $dark-grey;
span {
vertical-align: middle;
margin-right: 5px;
font-size: 20px;
}
}
}
.search--program--container {
padding: 0 15px 0 15px;
}
.list--program--container {
min-height: 300px;
}
}
}
.hitsarea {
li {
background-color: white;
border-top: 1px solid $grey-border;
padding-top: $xs-space;
padding-bottom: $xs-space;
.circle--green {
width: 10px;
height: 10px;
background: #27ae60;
border-radius: 50%;
margin-right: 5px;
}
.circle--orange {
width: 10px;
height: 10px;
background: orange;
border-radius: 50%;
margin-right: 5px;
}
.circle--grey {
width: 10px;
height: 10px;
background: $dark-grey;
opacity: 0.4;
border-radius: 50%;
margin-right: 5px;
}
a {
&.program--title {
font-family: "Lato Bold";
font-size: 24px;
line-height: 36px;
color: $dark-grey;
}
}
p {
&.program--text {
font-family: "Lato";
font-size: 16px;
line-height: 24px;
margin-right: $xs-space;
}
&.program--text--closed {
font-family: "Lato";
opacity: 0.4;
font-size: 16px;
line-height: 24px;
margin-right: $xs-space;
}
}
}
}
There are no notes for this item.