Commit 60c33f64 authored by Curtis Adam's avatar Curtis Adam

Refactor the cardset templates

parent d20398b6
export let CardsetNavigation = class CardsetNavigation {
/**
* Creates a web push subscription for the current device.
* The Browser ask the user for permissions and creates the subscription.
* Afterwards the subscription will be saved for the current user via the
* Meteor-method addWebPushSubscription.
*/
static subscribeForPushNotification () {
try {
navigator.serviceWorker.getRegistration()
.then(function (registration) {
return registration.pushManager.getSubscription()
.then(function (subscription) {
if (!subscription) {
return registration.pushManager.subscribe({userVisibleOnly: true});
}
});
})
.then(function (subscription) {
if (subscription) {
var rawKey = subscription.getKey ? subscription.getKey('p256dh') : '';
const key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : '';
var rawAuthSecret = subscription.getKey ? subscription.getKey('auth') : '';
const authSecret = rawAuthSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawAuthSecret))) : '';
const endpoint = subscription.endpoint;
const sub = {
endpoint: endpoint,
key: key,
authSecret: authSecret
};
Meteor.call("addWebPushSubscription", sub, function (error) {
if (error) {
throw new Meteor.Error(error.statusCode, 'Error subscription failed');
}
});
}
});
} catch (error) {
console.log(error);
}
}
/**
* Add the current user to the leitner algorithm.
*/
static addToLeitner (cardset_id) {
this.subscribeForPushNotification();
Meteor.call('addToLeitner', cardset_id);
}
};
......@@ -7,4 +7,14 @@ export let CardsetVisuals = class CardsetVisuals {
$('.markdeepCardsetContent').css('height', 'auto');
}
}
static changeCollapseIcon (iconId) {
if ($(iconId).hasClass("glyphicon-collapse-down")) {
$(iconId).removeClass("glyphicon-collapse-down");
$(iconId).addClass("glyphicon-collapse-up");
} else {
$(iconId).removeClass("glyphicon-collapse-up");
$(iconId).addClass("glyphicon-collapse-down");
}
}
};
This diff is collapsed.
This diff is collapsed.
<template name="cardsetLearnActivityStatistic">
{{#if isInRole 'firstLogin'}}
{{> first_login_content_only}}
{{else}}
{{#if isInRole 'blocked'}}
{{> access_denied_content_only}}
{{else}}
{{#unless isEditor}}
{{> access_denied_content_only}}
{{else}}
<div class="container">
<div id="cardsetInfoDetail">
<div class="panel panel-default cardsetInfo">
<div class="panel-body">
<h4>{{this.name}}</h4>
<hr>
<div class="row">
<span class="col-sm-6 collapseCardsetInfoContainer">
{{> cardsetInfoBox}}
</span>
<span class="col-sm-6 collapseCardsetInfoContainer">
{{> learningPhaseInfoBox}}
</span>
</div>
</div>
<div class="panel-footer">
<button id="exportCSV" class="btn btn-success btn-raised btn-default">{{_
"box_export"}}</button>
</div>
</div>
</div>
<div style="overflow-x:auto;">
<table class="table table-striped table-hover table-user-list">
<tbody>
<tr class="active">
<th>{{_ "panel-body.birthname"}}</th>
<th>{{_ "panel-body.givenname"}}</th>
<th>{{_ "panel-body.email"}}
</th>
<th>{{_ "leitnerProgress.box" number=1}} [{{this.learningInterval.[0]}}]
</th>
<th>{{_ "leitnerProgress.box" number=2}} [{{this.learningInterval.[1]}}]
</th>
<th>{{_ "leitnerProgress.box" number=3}} [{{this.learningInterval.[2]}}]
</th>
<th>{{_ "leitnerProgress.box" number=4}} [{{this.learningInterval.[3]}}]
</th>
<th>{{_ "leitnerProgress.box" number=5}} [{{this.learningInterval.[4]}}]
</th>
<th>{{_ "leitnerProgress.learned"}}</th>
<th>{{_ "details"}}</th>
</tr>
{{#each getCardsetStats}}
<tr>
<td>{{this.birthname}}</td>
<td>{{this.givenname}}</td>
<td><a href="mailto:{{this.email}}">{{this.email}}</a></td>
<td>{{this.box1}}</td>
<td>{{this.box2}}</td>
<td>{{this.box3}}</td>
<td>{{this.box4}}</td>
<td>{{this.box5}}</td>
<td>
{{#if earnedTrophy}}
<span class="green-learning-text">
{{this.box6}}{{{getPercentage this.box6}}}
</span>
<i class="fa fa-trophy pull-right"></i>
{{else}}
<span class="red-learning-text">
{{this.box6}}{{{getPercentage this.box6}}}
</span>
{{/if}}
</td>
<td>
<button data-id="{{this.user_id}}" class="btn btn-block detailed-stats"><i
class="glyphicon glyphicon glyphicon-stats"
data-id="{{this.user_id}}"></i></button>
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
<button class="btn btn-block btn-raised btn-danger" id="backButton">
<span class="pull-left"><i class="fa fa-arrow-left"></i> {{_ "backbutton"}}</span>
</button>
</div>
{{/unless}}
{{/if}}
{{/if}}
</template>
//------------------------ IMPORTS
import {Meteor} from "meteor/meteor";
import {Session} from "meteor/session";
import {Template} from "meteor/templating";
import {Cardsets} from "../../../../api/cardsets";
import "./bonus.html";
/*
* ############################################################################
* cardsetLearnActivityStatistic
* ############################################################################
*/
Template.cardsetLearnActivityStatistic.onRendered(function () {
Session.set('activeCardset', Cardsets.findOne({_id: Router.current().params._id}));
});
Template.cardsetLearnActivityStatistic.helpers({
getCardsetStats: function () {
return Session.get("learnerStats");
},
getPercentage: function (count) {
let percentage = Math.round(count / Session.get('activeCardset').quantity * 100);
if (percentage > 0) {
return '<span class="cardPercentage">[' + percentage + ' %]</span>';
}
},
earnedTrophy: function () {
let totalCards = this.box1 + this.box2 + this.box3 + this.box4 + this.box5 + this.box6;
let box6Percentage = (this.box6 / totalCards) * 100;
return box6Percentage >= 95;
}
});
Template.cardsetLearnActivityStatistic.events({
"click #exportCSV": function () {
var cardset = Cardsets.findOne({_id: this._id});
var hiddenElement = document.createElement('a');
var header = [];
header[0] = TAPi18n.__('leitnerProgress.box', {number: 1});
header[1] = TAPi18n.__('leitnerProgress.box', {number: 2});
header[2] = TAPi18n.__('leitnerProgress.box', {number: 3});
header[3] = TAPi18n.__('leitnerProgress.box', {number: 4});
header[4] = TAPi18n.__('leitnerProgress.box', {number: 5});
header[5] = TAPi18n.__('leitnerProgress.learned');
header[6] = TAPi18n.__('box_export_birth_name');
header[7] = TAPi18n.__('box_export_given_name');
header[8] = TAPi18n.__('box_export_mail');
header[9] = TAPi18n.__('leitnerProgress.percentage');
Meteor.call("getCSVExport", cardset._id, header, function (error, result) {
if (error) {
throw new Meteor.Error(error.statusCode, 'Error could not receive content for .csv');
}
if (result) {
var statistics = TAPi18n.__('box_export_statistics');
hiddenElement.href = 'data:text/csv;charset=utf-8,%EF%BB%BF' + encodeURIComponent(result);
hiddenElement.target = '_blank';
var str = (cardset.name + "_" + statistics + "_" + new Date() + ".csv");
hiddenElement.download = str.replace(/ /g, "_").replace(/:/g, "_");
document.body.appendChild(hiddenElement);
hiddenElement.click();
}
});
},
"click #backButton": function () {
Router.go('cardsetdetailsid', {_id: this._id});
},
"click .detailed-stats": function (event) {
Router.go('progress', {
_id: Router.current().params._id,
user_id: $(event.target).data('id')
});
},
"click #showIntervalHelp": function (event) {
event.stopPropagation();
Session.set('helpFilter', "leitner");
Router.go('help');
}
});
Template.cardsetLearnActivityStatistic.created = function () {
Session.set("learnerStats", "");
Meteor.call("getLearningData", Router.current().params._id, function (error, result) {
if (error) {
throw new Meteor.Error(error.statusCode, 'Error could not receive content for stats');
}
if (result) {
Session.set("learnerStats", result);
}
});
};
<template name="cardsetList">
<div id="cardset-list">
{{#if gotCards}}
{{#each cardsetList}}
{{#if isShuffledCardset this._id}}
<div class="cardListName btn-raised {{getColors}}">
{{this.name}}
{{#unless isActiveRoute regex='demo|demolist|making|makinglist'}}
<span class="cardListOwner hidden-xs">
{{getAuthorName this.owner}}
</span>
{{/unless}}
<br>
<span class="badge" title="{{_ "cardset.info.quantity"}}">
{{this.quantity}}
</span>
{{{getCardTypeLabel this.cardType}}}
{{{getDifficultyLabel this.cardType this.difficulty}}}
</div>
{{/if}}
{{#each cardSubject}}
<div class="cardListSubject">
<table class="table table-hover">
<thead>
<tr>
<th>
<span>{{this.subject}}</span>
<span class="badge cardset-list-badge">{{cardList true}}</span>
</th>
</tr>
</thead>
<tbody>
{{#each cardList false}}
<tr class="cardListRow">
<td class="{{getCardsetBackground this.difficulty this.cardType 1}}"
data-id="{{this._id}}" data-card-type="{{this.cardType}}">
<div class="cardListNumber" data-id="{{this._id}}">
{{getPriority @index}}
</div>
<div class="col-xs-11 listCard" data-id="{{this._id}}"
data-card-type="{{this.cardType}}">
{{cleanContent getText}}
</div>
<i class="glyphicon glyphicon-menu-right pull-right" data-id="{{this._id}}"
data-card-type="{{this.cardType}}"></i>
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
{{/each}}
{{/each}}
{{else}}
<table class="table table-bordered table-hover">
<tbody>
<tr class="empty-listitem">
<td colspan="3" align="center">
<span>
{{#if isActiveRoute 'cardsetlistid'}}{{_ "nocards"}}{{else}}{{_
"learningUnit.noUnitsFound"}}{{/if}}</span>
</td>
</tr>
</tbody>
</table>
{{/if}}
</div>
</template>
//------------------------ IMPORTS
import {Session} from "meteor/session";
import {Template} from "meteor/templating";
import {Cards} from "../../../../api/cards";
import {CardVisuals} from "../../../../api/cardVisuals";
import {CardType} from "../../../../api/cardTypes";
import {Cardsets} from "../../../../api/cardsets";
import {Route} from "../../../../api/route";
import {CardNavigation} from "../../../../api/cardNavigation";
import "./cards.html";
/*
* ############################################################################
* cardsetList
* ############################################################################
*/
Template.cardsetList.helpers({
isShuffledCardset: function () {
if (Router.current().route.getName() === "demolist") {
return Cardsets.findOne({kind: 'demo', name: "DemoCardset", shuffled: true}).shuffled;
} else if (Router.current().route.getName() === "makinglist") {
return Cardsets.findOne({kind: 'demo', name: "MakingOfCardset", shuffled: true}).shuffled;
} else {
return Cardsets.findOne({_id: Router.current().params._id}).shuffled;
}
},
cardsetList: function () {
let isDemo = (Router.current().route.getName() === "demolist" || Router.current().route.getName() === "makinglist");
if (Router.current().route.getName() === "cardsetlistid" || Router.current().route.getName() === "presentationlist" || isDemo) {
let cardsetId = Router.current().params._id;
if (isDemo) {
if (Route.isDemo()) {
cardsetId = Cardsets.findOne({kind: 'demo', name: "DemoCardset", shuffled: true})._id;
} else {
cardsetId = Cardsets.findOne({kind: 'demo', name: "MakingOfCardset", shuffled: true})._id;
}
}
if (this.shuffled) {
let cardsetFilter = [];
let sortCardsets = Cardsets.find({_id: {$in: this.cardGroups}}, {
sort: {name: 1}, fields: {_id: 1, name: 1, kind: 1, owner: 1, quantity: 1, difficulty: 1, cardType: 1}
}).fetch();
sortCardsets.forEach(function (cardset) {
if (cardset._id !== cardsetId) {
cardsetFilter.push(cardset);
}
});
return cardsetFilter;
} else {
return Cardsets.find({_id: this._id}).fetch();
}
} else {
return Cardsets.find({_id: Session.get('tempLearningIndex')}).fetch();
}
},
getPriority: function (index) {
return index + 1;
},
cleanContent: function (text) {
return CardVisuals.removeMarkdeepTags(text);
},
gotCards: function () {
if (Router.current().route.getName() === "cardsetlistid" || Router.current().route.getName() === "presentationlist" || Router.current().route.getName() === "demolist" || Router.current().route.getName() === "makinglist") {
if (this.shuffled) {
return Cards.find({cardset_id: {$in: this.cardGroups}}).count();
} else {
return Cards.find({cardset_id: this._id}).count();
}
} else {
return Cards.find({cardset_id: Session.get('tempLearningIndex'), cardType: 0}).count();
}
},
cardSubject: function () {
if (Router.current().route.getName() === "cardsetlistid" || Router.current().route.getName() === "presentationlist" || Router.current().route.getName() === "demolist" || Router.current().route.getName() === "makinglist") {
return _.uniq(Cards.find({
cardset_id: this._id
}, {
cardset_id: 1,
subject: 1,
sort: {subject: 1}
}).fetch(), function (card) {
return card.subject;
});
} else {
return _.uniq(Cards.find({
cardset_id: this._id
}, {
cardset_id: 1,
subject: 1,
sort: {subject: 1}
}).fetch(), function (card) {
return card.subject;
});
}
},
cardList: function (countCards) {
let sortQuery;
sortQuery = CardType.getSortQuery(Cardsets.findOne({_id: this.cardset_id}).cardType);
if (countCards) {
return Cards.find({
cardset_id: this.cardset_id,
subject: this.subject
}, {
fields: {
_id: 1,
front: 1,
back: 1,
hint: 1,
lecture: 1,
top: 1,
bottom: 1,
cardset_id: 1
},
sort: sortQuery
}).count();
}
let cards = Cards.find({
cardset_id: this.cardset_id,
subject: this.subject
}, {
fields: {
_id: 1,
front: 1,
back: 1,
hint: 1,
lecture: 1,
top: 1,
bottom: 1,
cardset_id: 1
},
sort: sortQuery
}).fetch();
return CardVisuals.setTypeAndDifficulty(cards);
},
getColors: function () {
switch (this.kind) {
case "personal":
return "btn-warning";
case "free":
return "btn-info";
case "edu":
return "btn-success";
case "pro":
return "btn-danger";
case "demo":
return "btn-demo";
}
},
gotReferences: function () {
return Cardsets.findOne({_id: Router.current().params._id}).cardGroups !== [""];
},
getText: function () {
let cubeSides = CardType.getCardTypeCubeSides(this.cardType);
switch (cubeSides[0].contentId) {
case 1:
return this.front;
case 2:
return this.back;
case 3:
return this.hint;
case 4:
return this.lecture;
case 5:
return this.top;
case 6:
return this.bottom;
}
}
});
Template.cardsetList.events({
'click .cardListRow': function (evt) {
let cubeSides = CardType.getCardTypeCubeSides($(evt.target).data('card-type'));
Session.set('cardType', $(evt.target).data('card-type'));
Session.set('activeCardContentId', cubeSides[0].contentId);
if (Router.current().route.getName() === "cardsetlistid" || Router.current().route.getName() === "presentationlist" || Router.current().route.getName() === "demolist" || Router.current().route.getName() === "makinglist") {
CardNavigation.setActiveCardData($(evt.target).data('id'));
if (Router.current().route.getName() === "presentationlist") {
Router.go('presentation', {
_id: Router.current().params._id
});
} else if (Router.current().route.getName() === "demolist") {
Router.go('demo');
} else if (Router.current().route.getName() === "makinglist") {
Router.go('making');
} else {
Router.go('cardsetcard', {
_id: Router.current().params._id,
card_id: $(evt.target).data('id')
});
}
} else {
let learningUnit = $(evt.target).data('id');
Session.set('learningIndex', Session.get('tempLearningIndex'));
Session.set('learningUnit', learningUnit);
Session.set('subject', Cards.findOne({_id: learningUnit}).subject);
$('#showSelectLearningUnitModal').modal('hide');
}
}
});
<template name="cardsetManageEditors">
{{#if isInRole 'firstLogin'}}
{{> first_login_content_only}}
{{else}}
{{#if isInRole 'blocked'}}
{{> access_denied_content_only}}
{{else}}
{{#unless isCardsetOwner _id}}
{{> access_denied_content_only}}
{{else}}
<div class="container">
<h3 class="modal-title">{{_ "modal-dialog.manageEditors" name = this.name}}</h3>
<div style="overflow-x:auto;">
<table class="table table-striped table-hover table-user-list">
<tbody>
<tr class="active">
<th>{{_ "panel-body.givenname"}}</th>
<th>{{_ "panel-body.birthname"}}</th>
<th>{{_ "panel-body.roles"}}</th>
<th></th>
</tr>
{{#each getEditors}}
<tr>
<td>{{this.givenname}}</td>
<td>{{this.birthname}}</td>
<td> {{getRoles this.roles}}</td>
<td>
{{#if isCardsetEditor this.id}}
<a class="btn btn-block btn-raised btn-danger removeEditor"
data-id="{{this.id}}">
<i class="fa fa-minus"></i> {{_ "admin.cardset.removeFromWordcloud"}}
</a>
{{else}}
<a class="btn btn-block btn-raised btn-success addEditor"
data-id="{{this.id}}">
<i class="fa fa-plus"></i> {{_ "admin.cardset.addToWordcloud"}}
</a>
{{/if}}
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
<button class="btn btn-block btn-raised btn-danger" id="backButton">
<span class="pull-left"><i class="fa fa-arrow-left"></i> {{_ "backbutton"}}</span>
</button>
</div>
{{/unless}}
{{/if}}
{{/if}}
</template>
//------------------------ IMPORTS
import {Meteor} from "meteor/meteor";
import {Session} from "meteor/session";
import {Template} from "meteor/templating";
import "./editors.html";
/*
* ############################################################################
* cardsetManageEditors
* ############################################################################
*/
Template.cardsetManageEditors.helpers({
getEditors: function () {
return Session.get("editorsList");
}
});
Template.cardsetManageEditors.events({
"click #backButton": function () {
Router.go('cardsetdetailsid', {_id: Router.current().params._id});
},
"click .addEditor": function (event) {
Meteor.call("addEditor", Router.current().params._id, $(event.target).data('id'));
},
"click .removeEditor": function (event) {
Meteor.call("removeEditor", Router.current().params._id, $(event.target).data('id'));
}
});
Template.cardsetManageEditors.created = function () {
Session.set("editorsList", "");
Meteor.call("getEditors", Router.current().params._id, function (error, result) {
if (error) {
throw new Meteor.Error(error.statusCode, 'Error could not receive content for editors');
}
if (result) {
Session.set("editorsList", result);
}
});
};
<template name="learningPhaseInfoBox">
<a id="collapseLearningPhaseInfoButton" class="col-xs-12 card card-block collapseButton"
href="#collapseLearningPhaseInfo" data-toggle="collapse">
<strong>{{_ "set-list.learnphaseInfo"}}</strong>
<i id="collapseLearningPhaseInfoIcon" class="glyphicon glyphicon-collapse-down pull-right"></i>
</a>
<div class="collapse" id="collapseLearningPhaseInfo">
<div class="card card-block">
<table class="table table-condensed table-striped table-hover infoBoxTable">
<tbody>
<tr>
<td>{{_ "set-list.learnphase"}}:</td>
<td>{{getLearningStatus}}</td>
</tr>
<tr>
<td>{{_ "set-list.bonusPoints"}}:</td>
<td>
<a href="https://www.thm.de/site/hochschule/zentrale-bereiche/pruefungsamt/faq.html#bonuspunkte-an-der-thm"
target="_blank">{{_ "set-list.bonusPointsPercentage"}}</a></td>
</tr>
<tr>
<td>{{_ "bonus.form.maxWorkload.label"}}:</td>
<td>{{getWorkload}}</td>
</tr>
<tr>
<td>{{_ "pomodoro.cardsetInfo.count.label"}}:</td>
<td>{{{getPomodoroCount}}}</td>
</tr>
<tr>
<td>{{_ "pomodoro.cardsetInfo.work.label"}}:</td>
<td>{{{getPomodoroWorkTime}}}</td>
</tr>
<tr>
<td>{{_ "pomodoro.cardsetInfo.break.label"}}:</td>
<td>{{{getPomodoroBreakTime}}}</td>
</tr>
<tr>
<td>{{_ "bonus.form.daysBeforeReset.label"}}:</td>
<td>{{getDeadline}}</td>
</tr>
<tr>
<td>{{_ "bonus.form.startDate.label"}}:</td>
<td>{{getDateStart}}</td>
</tr>
<tr>
<td>{{_ "bonus.form.endDate.label"}}:</td>
<td>{{getDateEnd}}</td>
</tr>
<tr>
<td>{{_ "bonus.form.registrationPeriod.label"}}:</td>