Skip to content
Snippets Groups Projects
Verified Commit c57b2f10 authored by Till Glöggler's avatar Till Glöggler
Browse files

Merge remote-tracking branch 'studip/5.0' into 5.0

parents aee11bd8 7346be1e
Branches
No related tags found
No related merge requests found
...@@ -208,7 +208,7 @@ ...@@ -208,7 +208,7 @@
</article> </article>
<article class="studip assign-dates"> <article class="studip assign-dates">
<header><h1><?= _('Termine zuordnen') ?></h1></header> <header><h1><?= _('Termine zuordnen') ?></h1></header>
<div>
<table id="resolve-dates-table" class="default"> <table id="resolve-dates-table" class="default">
<thead> <thead>
<tr> <tr>
...@@ -328,7 +328,7 @@ ...@@ -328,7 +328,7 @@
<? endif ?> <? endif ?>
</tbody> </tbody>
</table> </table>
</div>
</article> </article>
<? endif ?> <? endif ?>
<? endif ?> <? endif ?>
......
...@@ -515,8 +515,7 @@ class StudipCoreFormat extends TextFormat ...@@ -515,8 +515,7 @@ class StudipCoreFormat extends TextFormat
$intern = $domain === $_SERVER['HTTP_HOST']; $intern = $domain === $_SERVER['HTTP_HOST'];
return sprintf('<a class="%s" href="mailto:%s">%s</a>', return sprintf('<a href="mailto:%1$s">%2$s</a>',
$intern ? "link-intern" : "link-extern",
$email, $email,
$link_text $link_text
); );
...@@ -655,7 +654,16 @@ class StudipCoreFormat extends TextFormat ...@@ -655,7 +654,16 @@ class StudipCoreFormat extends TextFormat
$linkmarkup->removeMarkup('links'); $linkmarkup->removeMarkup('links');
$linkmarkup->removeMarkup('wiki-links'); $linkmarkup->removeMarkup('wiki-links');
return sprintf('<a class="%s" href="%s"%s>%s</a>%s', if (strpos($url, 'mailto:') === 0) {
return sprintf(
'<a href="%1$s">%2$s</a>%3$s',
$url,
$linkmarkup->format($title),
$postfix
);
} else {
return sprintf(
'<a class="%s" href="%s"%s>%s</a>%s',
$intern ? 'link-intern' : 'link-extern', $intern ? 'link-intern' : 'link-extern',
$url, $url,
$intern ? '' : ' target="_blank" rel="noreferrer noopener"', $intern ? '' : ' target="_blank" rel="noreferrer noopener"',
...@@ -663,6 +671,7 @@ class StudipCoreFormat extends TextFormat ...@@ -663,6 +671,7 @@ class StudipCoreFormat extends TextFormat
$postfix $postfix
); );
} }
}
protected static function htmlAnchor($markup, $matches, $contents) protected static function htmlAnchor($markup, $matches, $contents)
{ {
......
...@@ -13,8 +13,10 @@ class HTMLPurifier_Injector_ClassifyLinks extends HTMLPurifier_Injector ...@@ -13,8 +13,10 @@ class HTMLPurifier_Injector_ClassifyLinks extends HTMLPurifier_Injector
{ {
if ($token->name === 'a' && isset($token->attr['href'])) { if ($token->name === 'a' && isset($token->attr['href'])) {
$is_link_intern = isLinkIntern($token->attr['href']); $is_link_intern = isLinkIntern($token->attr['href']);
$token->attr['class'] = $is_link_intern ? 'link-intern' : 'link-extern'; if ($is_link_intern) {
if (!$is_link_intern) { $token->attr['class'] = 'link-intern';
} elseif (strpos($token->attr['href'], 'mailto:') !== 0) {
$token->attr['class'] = 'link-extern';
$token->attr['target'] = '_blank'; $token->attr['target'] = '_blank';
} }
} }
......
...@@ -396,7 +396,7 @@ ...@@ -396,7 +396,7 @@
<script> <script>
import ContainerComponents from './container-components.js'; import ContainerComponents from './container-components.js';
import CoursewarePluginComponents from './plugin-components.js' import CoursewarePluginComponents from './plugin-components.js';
import CoursewareStructuralElementPermissions from './CoursewareStructuralElementPermissions.vue'; import CoursewareStructuralElementPermissions from './CoursewareStructuralElementPermissions.vue';
import CoursewareAccordionContainer from './CoursewareAccordionContainer.vue'; import CoursewareAccordionContainer from './CoursewareAccordionContainer.vue';
import CoursewareCompanionBox from './CoursewareCompanionBox.vue'; import CoursewareCompanionBox from './CoursewareCompanionBox.vue';
...@@ -430,7 +430,7 @@ export default { ...@@ -430,7 +430,7 @@ export default {
IsoDate, IsoDate,
StudipDialog, StudipDialog,
}, },
props: {}, props: ['orderedStructuralElements'],
mixins: [CoursewareExport], mixins: [CoursewareExport],
...@@ -481,6 +481,9 @@ export default { ...@@ -481,6 +481,9 @@ export default {
courseware: 'courseware', courseware: 'courseware',
consumeMode: 'consumeMode', consumeMode: 'consumeMode',
containerById: 'courseware-containers/byId', containerById: 'courseware-containers/byId',
relatedContainers: 'courseware-containers/related',
relatedStructuralElements: 'courseware-structural-elements/related',
relatedUsers: 'users/related',
structuralElementById: 'courseware-structural-elements/byId', structuralElementById: 'courseware-structural-elements/byId',
userIsTeacher: 'userIsTeacher', userIsTeacher: 'userIsTeacher',
pluginManager: 'pluginManager', pluginManager: 'pluginManager',
...@@ -494,7 +497,7 @@ export default { ...@@ -494,7 +497,7 @@ export default {
oerTitle: 'oerTitle', oerTitle: 'oerTitle',
licenses: 'licenses', licenses: 'licenses',
exportState: 'exportState', exportState: 'exportState',
exportProgress: 'exportProgress' exportProgress: 'exportProgress',
}), }),
textOer() { textOer() {
...@@ -502,7 +505,7 @@ export default { ...@@ -502,7 +505,7 @@ export default {
title: this.$gettext('Seite auf') + ' ' + this.oerTitle + ' ' + this.$gettext('veröffentlichen'), title: this.$gettext('Seite auf') + ' ' + this.oerTitle + ' ' + this.$gettext('veröffentlichen'),
confirm: this.$gettext('Veröffentlichen'), confirm: this.$gettext('Veröffentlichen'),
close: this.$gettext('Schließen'), close: this.$gettext('Schließen'),
} };
}, },
inCourse() { inCourse() {
...@@ -555,87 +558,38 @@ export default { ...@@ -555,87 +558,38 @@ export default {
}, },
ancestors() { ancestors() {
if (!this.currentElement) {
return [];
}
if (this.currentElement.relationships.ancestors.data) {
return this.currentElement.relationships.ancestors.data.map(({ id }) =>
this.structuralElementById({ id })
);
}
return [];
},
parent() {
if (!this.structuralElement) { if (!this.structuralElement) {
return []; return [];
} }
if (this.structuralElement.relationships.parent.data) {
let id = this.structuralElement.relationships.parent.data.id; return this.relatedStructuralElements({ parent: this.structuralElement, relationship: 'ancestors' });
return this.structuralElementById({ id });
}
return [];
},
hasSiblings() {
if (this.parent.length !== 0) {
return this.parent.relationships.children.data.length > 1;
} else {
return false;
}
}, },
prevElement() { prevElement() {
if (this.hasSiblings) { const currentIndex = this.orderedStructuralElements.indexOf(this.structuralElement.id);
let view = this; if (currentIndex <= 0) {
let siblings = this.parent.relationships.children.data;
let id = '';
siblings.forEach((el, index) => {
if (el.id === view.currentId && index !== 0) {
id = siblings[index - 1].id;
}
});
if (id === '') {
return this.parent;
} else {
return this.structuralElementById({ id });
}
} else if (this.parent.length !== 0) {
return this.parent;
} else {
return null; return null;
} }
const previousId = this.orderedStructuralElements[currentIndex - 1];
const previous = this.structuralElementById({ id: previousId });
return previous;
}, },
nextElement() { nextElement() {
let view = this; const currentIndex = this.orderedStructuralElements.indexOf(this.structuralElement.id);
if (this.structuralElement.relationships.children.data.length > 0) { const lastIndex = this.orderedStructuralElements.length - 1;
let id = this.structuralElement.relationships.children.data[0].id; if (currentIndex === -1 || currentIndex === lastIndex) {
return this.structuralElementById({ id }); return null;
} else if (this.hasSiblings) {
let siblings = this.parent.relationships.children.data;
let id = '';
siblings.forEach((el, index) => {
if (el.id === view.currentId && siblings.length > index + 1) {
id = siblings[index + 1].id;
}
});
if (id === '') {
return this.getNextParentSibling(this.currentId);
} else {
return this.structuralElementById({ id });
}
} else {
return this.getNextParentSibling(this.currentId);
} }
const nextId = this.orderedStructuralElements[currentIndex + 1];
const next = this.structuralElementById({ id: nextId });
return next;
}, },
empty() { empty() {
if (this.containers === null) { if (this.containers === null) {
return true; return true;
} else { } else {
let noBlockFound = true; return !this.containers.some((container) => container.relationships.blocks.data.length > 0);
this.containers.forEach((container) => {
if (container.relationships.blocks.data.length > 0) {
noBlockFound = false;
}
});
return noBlockFound;
} }
}, },
containers() { containers() {
...@@ -643,12 +597,12 @@ export default { ...@@ -643,12 +597,12 @@ export default {
return []; return [];
} }
const containers = this.$store.getters['courseware-containers/related']({ return (
this.relatedContainers({
parent: this.structuralElement, parent: this.structuralElement,
relationship: 'containers', relationship: 'containers',
}); }) ?? []
);
return containers;
}, },
noContainers() { noContainers() {
if (this.containers === null) { if (this.containers === null) {
...@@ -679,7 +633,7 @@ export default { ...@@ -679,7 +633,7 @@ export default {
}, },
owner() { owner() {
const owner = this.$store.getters['users/related']({ const owner = this.relatedUsers({
parent: this.structuralElement, parent: this.structuralElement,
relationship: 'owner', relationship: 'owner',
}); });
...@@ -688,7 +642,7 @@ export default { ...@@ -688,7 +642,7 @@ export default {
}, },
editor() { editor() {
const editor = this.$store.getters['users/related']({ const editor = this.relatedUsers({
parent: this.structuralElement, parent: this.structuralElement,
relationship: 'editor', relationship: 'editor',
}); });
...@@ -764,7 +718,7 @@ export default { ...@@ -764,7 +718,7 @@ export default {
}, },
}, },
async mounted() { mounted() {
if (!this.currentId) { if (!this.currentId) {
this.setCurrentId(this.$route.params.id); this.setCurrentId(this.$route.params.id);
} }
...@@ -797,7 +751,7 @@ export default { ...@@ -797,7 +751,7 @@ export default {
this.initCurrent(); this.initCurrent();
}, },
initCurrent() { initCurrent() {
this.currentElement = JSON.parse(JSON.stringify(this.structuralElement)); this.currentElement = _.cloneDeep(this.structuralElement);
this.uploadFileError = ''; this.uploadFileError = '';
}, },
async menuAction(action) { async menuAction(action) {
...@@ -941,29 +895,6 @@ export default { ...@@ -941,29 +895,6 @@ export default {
containerComponent(container) { containerComponent(container) {
return 'courseware-' + container.attributes['container-type'] + '-container'; return 'courseware-' + container.attributes['container-type'] + '-container';
}, },
getNextParentSibling(element_id) {
let current = this.structuralElementById({ id: element_id });
if (current.relationships.parent.data === null) {
return null;
}
let parent = this.structuralElementById({ id: current.relationships.parent.data.id });
if (parent.relationships.parent.data === null) {
return null;
}
let grandParent = this.structuralElementById({ id: parent.relationships.parent.data.id });
let parentSiblings = grandParent.relationships.children.data;
let id = '';
parentSiblings.forEach((el, index) => {
if (parseInt(el.id, 10) === parseInt(parent.id, 10) && parentSiblings.length > index + 1) {
id = parentSiblings[index + 1].id;
}
});
if (id === '') {
this.getNextParentSibling(parent.id);
} else {
return this.structuralElementById({ id });
}
},
setBookmark() { setBookmark() {
this.addBookmark(this.structuralElement); this.addBookmark(this.structuralElement);
this.companionInfo({ info: this.$gettext('Das Lesezeichen wurde gesetzt') }); this.companionInfo({ info: this.$gettext('Das Lesezeichen wurde gesetzt') });
......
...@@ -111,7 +111,10 @@ export default { ...@@ -111,7 +111,10 @@ export default {
let children = this.structuralElement.relationships.children.data; let children = this.structuralElement.relationships.children.data;
let childElements = []; let childElements = [];
children.forEach((element) => { children.forEach((element) => {
childElements.push(view.structuralElementById({ id: element.id })); let childElement = view.structuralElementById({ id: element.id });
if (childElement.attributes['can-read']) {
childElements.push(childElement);
}
}); });
return childElements; return childElements;
......
<template> <template>
<div v-if="courseware"> <div v-if="courseware">
<courseware-structural-element></courseware-structural-element> <courseware-structural-element
:ordered-structural-elements="orderedStructuralElements"
></courseware-structural-element>
<MountingPortal mountTo="#courseware-action-widget" name="sidebar-actions"> <MountingPortal mountTo="#courseware-action-widget" name="sidebar-actions">
<courseware-action-widget></courseware-action-widget> <courseware-action-widget></courseware-action-widget>
</MountingPortal> </MountingPortal>
...@@ -25,8 +27,14 @@ export default { ...@@ -25,8 +27,14 @@ export default {
CoursewareViewWidget, CoursewareViewWidget,
CoursewareActionWidget, CoursewareActionWidget,
}, },
data: () => ({ orderedStructuralElements: [] }),
computed: { computed: {
...mapGetters(['courseware', 'userId', 'blockAdder']), ...mapGetters({
courseware: 'courseware',
relatedStructuralElement: 'courseware-structural-elements/related',
structuralElements: 'courseware-structural-elements/all',
userId: 'userId',
}),
}, },
methods: { methods: {
...mapActions(['loadCoursewareStructure', 'loadTeacherStatus', 'coursewareBlockAdder']), ...mapActions(['loadCoursewareStructure', 'loadTeacherStatus', 'coursewareBlockAdder']),
...@@ -34,12 +42,56 @@ export default { ...@@ -34,12 +42,56 @@ export default {
async mounted() { async mounted() {
await this.loadCoursewareStructure(); await this.loadCoursewareStructure();
await this.loadTeacherStatus(this.userId); await this.loadTeacherStatus(this.userId);
// console.debug('IndexApp mounted for courseware:', this.courseware, this.$store);
}, },
watch: { watch: {
$route() { $route() {
this.coursewareBlockAdder({}); //reset block adder on navigate this.coursewareBlockAdder({}); //reset block adder on navigate
},
structuralElements(newElements, oldElements) {
const nodes = buildNodes(this.structuralElements, this.relatedStructuralElement.bind(this));
this.orderedStructuralElements = [...visitTree(nodes, findRoot(nodes))];
},
},
};
function buildNodes(structuralElements, relatedStructuralElement) {
return structuralElements.reduce((memo, element) => {
if (element.attributes['can-read']) {
memo.push({
id: element.id,
parent:
relatedStructuralElement({
parent: element,
relationship: 'parent',
})?.id ?? null,
children:
relatedStructuralElement({
parent: element,
relationship: 'children',
})?.map((child) => child.id) ?? [],
});
}
return memo;
}, []);
}
function findRoot(nodes) {
return nodes.find((node) => node.parent === null);
}
function findNode(nodes, id) {
return nodes.find((node) => node.id === id);
}
function* visitTree(nodes, current) {
if (current) {
yield current.id;
for (let index = 0; index < current.children.length; index++) {
yield* visitTree(nodes, findNode(nodes, current.children[index]));
}
} }
} }
};
</script> </script>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment