1
0
mirror of https://github.com/typemill/typemill.git synced 2025-07-30 19:00:32 +02:00

open modal if logged out

This commit is contained in:
trendschau
2023-09-08 21:31:29 +02:00
parent 0ec5ab79a6
commit 7056e15afa
27 changed files with 1263 additions and 1007 deletions

View File

@@ -33,7 +33,7 @@ class ControllerApiSystemSettings extends Controller
$validator = new Validation();
$validatedOutput = $validator->recursiveValidation($formdefinitions, $settingsinput);
if(!empty($valiator->errors))
if(!empty($validator->errors))
{
$response->getBody()->write(json_encode([
'message' => Translations::translate('Please correct errors in form.'),

View File

@@ -193,7 +193,7 @@ bloxeditor.component('new-block',{
eventBus.$emit('publisherclear');
tmaxios.post('/api/v1/block',{
tmaxios.post('/api/v1/block',{
'url': data.urlinfo.route,
'block_id': this.index,
'markdown': this.newblockmarkdown.trim(),
@@ -216,7 +216,11 @@ bloxeditor.component('new-block',{
{
if(error.response)
{
eventBus.$emit('publishermessage', error.response.data.message);
let message = handleErrorMessage(error);
if(message)
{
eventBus.$emit('publishermessage', message);
}
}
});
},
@@ -236,9 +240,9 @@ bloxeditor.component('content-block', {
<new-block :index="index"></new-block>
</div>
<div class="relative blox-wrapper mb-1">
<div v-if="index != 0" class="sideaction hidden absolute -top-3 left-1/2 -translate-x-1/2 z-10 text-xs">
<div v-if="index != 0" class="sideaction hidden absolute -top-3 left-1/2 -translate-x-1/2 z-10 text-xs">
<button class="delete w-16 p-1 border-r border-stone-700 bg-stone-200 hover:bg-rose-500 hover:text-white transition-1" @mousedown.prevent="disableSort()" @click.prevent="deleteBlock">{{ $filters.translate('delete') }}</button>
<button class="add w-16 p-1 border-l border-stone-700 bg-stone-200 hover:bg-teal-500 hover:text-white transition-1" :disabled="disabled" @mousedown.prevent="disableSort()" @click.prevent="openNewBlock">{{ $filters.translate('add') }}</button>
<button class="add w-16 p-1 border-l border-stone-700 bg-stone-200 hover:bg-teal-500 hover:text-white transition-1" :disabled="disabled" @mousedown.prevent="disableSort()" @click.prevent="openNewBlock">{{ $filters.translate('add') }}</button>
</div>
<div v-if="!edit" class="blox-preview px-6 py-3 hover:bg-stone-100 overflow-hidden transition-1" @click="showEditor" v-html="getHtml(element.html)"></div>
<div v-else class="blox-editor bg-stone-100">
@@ -247,7 +251,7 @@ bloxeditor.component('content-block', {
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</div>
</div>
<component ref="activeComponent" :disabled="disabled" :markdown="updatedmarkdown" :index="index" @saveBlockEvent="saveBlock" @updateMarkdownEvent="updateMarkdownFunction" :is="componentType"></component>
<div class="edit-buttons absolute -bottom-3 right-4 z-10 text-xs">
<button class="cancel w-20 p-1 border-r border-stone-700 bg-stone-200 hover:bg-rose-500 hover:text-white transition-1" :disabled="disabled" @click.prevent="closeEditor">{{ $filters.translate('cancel') }}</button>
@@ -382,7 +386,7 @@ bloxeditor.component('content-block', {
eventBus.$emit('publisherclear');
tmaxios.delete('/api/v1/block',{
tmaxios.delete('/api/v1/block',{
data: {
'url': data.urlinfo.route,
'block_id': this.index,
@@ -407,7 +411,11 @@ bloxeditor.component('content-block', {
self.load = false;
if(error.response)
{
eventBus.$emit('publishermessage', error.response.data.message);
let message = handleErrorMessage(error);
if(message)
{
eventBus.$emit('publishermessage', message);
}
}
});
},
@@ -441,7 +449,7 @@ bloxeditor.component('content-block', {
this.load = true;
eventBus.$emit('publisherclear');
tmaxios.put('/api/v1/block',{
tmaxios.put('/api/v1/block',{
'url': data.urlinfo.route,
'block_id': this.index,
'markdown': this.updatedmarkdown.trim(),
@@ -466,7 +474,11 @@ bloxeditor.component('content-block', {
self.load = false;
if(error.response)
{
eventBus.$emit('publishermessage', error.response.data.message);
let message = handleErrorMessage(error);
if(message)
{
eventBus.$emit('publishermessage', message);
}
}
});
},

View File

@@ -10,7 +10,7 @@ const navigation = Vue.createApp({
<a :href="getUrl(home.urlRelWoF)" class="flex-grow p-1 pl-3 border-l-2 border-stone-50 hover:bg-teal-500 hover:text-stone-50" :class="home.active ? 'text-stone-50 bg-teal-500' : ''">
{{ $filters.translate(home.name) }}
</a>
</div>
</div>
<div class="pl-2 pl-3 pl-4 pl-6 pl-8 pl-9 pl-10 pl-12 pl-15 text-stone-50"></div>
<navilevel :navigation="navigation" :expanded="expanded" />
</div>`,
@@ -151,7 +151,7 @@ navigation.component('navilevel',{
}"
:expanded="expanded"
>
<template #item="{ element }">
<template #item="{ element }">
<li :class="element.elementType" :id="element.keyPath" :data-url="element.urlRelWoF" :data-active="element.active">
<div class="flex w-full my-px border-b border-stone-200 relative" :class="element.elementType == 'folder' ? 'font-bold' : ''">
<div class="border-l-4" :class="getStatusClass(element.status)"></div>
@@ -163,7 +163,7 @@ navigation.component('navilevel',{
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</div>
</div>
<div v-if="element.elementType == 'folder' && element.contains == 'pages'" class=" p-1 bg-transparent absolute right-0" @click="callToggle(element.name)">
<svg v-if="isExpanded(element.name)" class="icon icon-cheveron-up">
<use xlink:href="#icon-cheveron-up"></use>
@@ -365,10 +365,15 @@ navigation.component('navilevel',{
})
.catch(function (error)
{
if(error.response.data.errors.message)
if(error.response)
{
eventBus.$emit('revertNavigation');
// publishController.errors.message = error.response.data.errors;
let message = handleErrorMessage(error);
if(message)
{
eventBus.$emit('publishermessage', message);
}
}
});
},
@@ -408,7 +413,14 @@ navigation.component('navilevel',{
})
.catch(function (error)
{
eventBus.$emit('publishermessage', error.response.data.message);
if(error.response)
{
let message = handleErrorMessage(error);
if(message)
{
eventBus.$emit('publishermessage', message);
}
}
});
},
emitter(value) {

View File

@@ -1,31 +1,31 @@
class Event{
constructor(){
this.events = {};
}
constructor(){
this.events = {};
}
$on(eventName, fn) {
this.events[eventName] = this.events[eventName] || [];
this.events[eventName].push(fn);
}
$on(eventName, fn) {
this.events[eventName] = this.events[eventName] || [];
this.events[eventName].push(fn);
}
$off(eventName, fn) {
if (this.events[eventName]) {
for (var i = 0; i < this.events[eventName].length; i++) {
if (this.events[eventName][i] === fn) {
this.events[eventName].splice(i, 1);
break;
}
};
}
}
$off(eventName, fn) {
if (this.events[eventName]) {
for (var i = 0; i < this.events[eventName].length; i++) {
if (this.events[eventName][i] === fn) {
this.events[eventName].splice(i, 1);
break;
}
};
}
}
$emit(eventName, data) {
if (this.events[eventName]) {
this.events[eventName].forEach(function(fn) {
fn(data);
});
}
}
$emit(eventName, data) {
if (this.events[eventName]) {
this.events[eventName].forEach(function(fn) {
fn(data);
});
}
}
};
const eventBus = new Event();
const eventBus = new Event();

View File

@@ -27,7 +27,7 @@ const app = Vue.createApp({
</div>
</div>
</div>
<form v-else class="inline-block w-full">
<form v-else class="inline-block w-full">
<div>
<p>Buy a typemill-license and enjoy our flatrate-model for plugins and -themes.</p><p>We offer two types of subscription-based licenses:</p>
<div class="flex flex-wrap justify-between">
@@ -48,23 +48,23 @@ const app = Vue.createApp({
<fieldset class="flex flex-wrap justify-between border-2 border-stone-200 p-4 my-8" v-if="fieldDefinition.type == 'fieldset'">
<legend class="text-lg font-medium">{{ fieldDefinition.legend }}</legend>
<component v-for="(subfieldDefinition, subfieldname) in fieldDefinition.fields"
:key="subfieldname"
:is="selectComponent(subfieldDefinition.type)"
:errors="errors"
:name="subfieldname"
:userroles="userroles"
:value="formData[subfieldname]"
v-bind="subfieldDefinition">
:key="subfieldname"
:is="selectComponent(subfieldDefinition.type)"
:errors="errors"
:name="subfieldname"
:userroles="userroles"
:value="formData[subfieldname]"
v-bind="subfieldDefinition">
</component>
</fieldset>
<component v-else
:key="fieldname"
:is="selectComponent(fieldDefinition.type)"
:errors="errors"
:name="fieldname"
:userroles="userroles"
:value="formData[fieldname]"
v-bind="fieldDefinition">
:key="fieldname"
:is="selectComponent(fieldDefinition.type)"
:errors="errors"
:name="fieldname"
:userroles="userroles"
:value="formData[fieldname]"
v-bind="fieldDefinition">
</component>
</div>
<div class="my-5">
@@ -72,8 +72,8 @@ const app = Vue.createApp({
<input type="submit" @click.prevent="save()" value="save" class="w-full p-3 my-1 bg-stone-700 hover:bg-stone-900 text-white cursor-pointer transition duration-100">
</div>
-->
</form>
</Transition>`,
</form>
</Transition>`,
data() {
return {
licenseData: data.licensedata,
@@ -111,13 +111,14 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
/* form validation errors */
if(error.response.data.errors !== undefined)
if(error.response)
{
self.errors = error.response.data.errors;
self.message = handleErrorMessage(error);
self.messageClass = 'bg-rose-500';
if(error.response.data.errors !== undefined)
{
self.errors = error.response.data.errors;
}
}
});
},

File diff suppressed because it is too large Load Diff

View File

@@ -97,9 +97,14 @@ const app = Vue.createApp({
})
.catch(function (error)
{
if(error.response)
{
}
if(error.response)
{
let message = handleErrorMessage(error);
if(message)
{
eventBus.$emit('publishermessage', message);
}
}
});
eventBus.$on('forminput', formdata => {
@@ -146,9 +151,18 @@ const app = Vue.createApp({
{
if(error.response)
{
self.formErrors = error.response.data.errors;
self.message = 'please correct the errors above';
self.messageClass = 'bg-rose-500';
self.formErrors = error.response.data.errors;
let message = handleErrorMessage(error);
/* does it make sense to change logic and show errors in publisher?
if(message)
{
eventBus.$emit('publishermessage', message);
}
*/
}
});
},
@@ -175,7 +189,7 @@ app.component('tab-meta', {
class="h-12 w-3/4 border px-2 py-3 border-stone-300 bg-stone-200"
type="text"
v-model="slug"
pattern="[a-z0-9\- ]"
pattern="[a-z0-9]"
@input="changeSlug()"
/>
<button
@@ -281,9 +295,17 @@ app.component('tab-meta', {
})
.catch(function (error)
{
eventBus.$emit('publishermessage', error.response.data.message);
if(error.response)
{
let message = handleErrorMessage(error);
if(message)
{
eventBus.$emit('publishermessage', message);
}
}
});
}
}
}
}
})

View File

@@ -8,12 +8,12 @@ const app = Vue.createApp({
<p class="py-2">License: {{ plugin.license }}</p>
<div class="flex">
<label :for="pluginname" class="p-2">{{ $filters.translate('active') }}</label>
<input type="checkbox" class="w-6 h-6 my-2 accent-white"
:name="pluginname"
v-model="formData[pluginname]['active']"
@change="activate(pluginname)">
<input type="checkbox" class="w-6 h-6 my-2 accent-white"
:name="pluginname"
v-model="formData[pluginname]['active']"
@change="activate(pluginname)">
</div>
</div>
</div>
<div class="w-full p-8">
<div class="w-full">
<h2 class="text-xl font-bold mb-3">{{plugin.name}}</h2>
@@ -34,23 +34,23 @@ const app = Vue.createApp({
<fieldset class="flex flex-wrap justify-between border-2 border-stone-200 p-4 my-8" v-if="fieldDefinition.type == 'fieldset'">
<legend class="text-lg font-medium">{{ fieldDefinition.legend }}</legend>
<component v-for="(subfieldDefinition, subfieldname) in fieldDefinition.fields"
:key="subfieldname"
:is="selectComponent(subfieldDefinition.type)"
:errors="errors"
:name="subfieldname"
:userroles="userroles"
:value="formData[pluginname][subfieldname]"
v-bind="subfieldDefinition">
:key="subfieldname"
:is="selectComponent(subfieldDefinition.type)"
:errors="errors"
:name="subfieldname"
:userroles="userroles"
:value="formData[pluginname][subfieldname]"
v-bind="subfieldDefinition">
</component>
</fieldset>
<component v-else
:key="fieldname"
:is="selectComponent(fieldDefinition.type)"
:errors="errors"
:name="fieldname"
:userroles="userroles"
:value="formData[pluginname][fieldname]"
v-bind="fieldDefinition">
:key="fieldname"
:is="selectComponent(fieldDefinition.type)"
:errors="errors"
:name="fieldname"
:userroles="userroles"
:value="formData[pluginname][fieldname]"
v-bind="fieldDefinition">
</component>
</div>
<div class="my-5">
@@ -66,15 +66,15 @@ const app = Vue.createApp({
</ul>
<div class="my-5 text-center">
<modal v-if="showModal" @close="showModal = false">
<template #header>
<h3>{{ $filters.translate('License required') }}</h3>
</template>
<template #body>
<p>{{ $filters.translate(modalMessage) }}</p>
</template>
<template #button>
<a :href="getLinkToLicense()" class="focus:outline-none px-4 p-3 mr-3 text-white bg-teal-500 hover:bg-teal-700 transition duration-100">{{ $filters.translate('Check your license') }}</a>
</template>
<template #header>
<h3>{{ $filters.translate('License required') }}</h3>
</template>
<template #body>
<p>{{ $filters.translate(modalMessage) }}</p>
</template>
<template #button>
<a :href="getLinkToLicense()" class="focus:outline-none px-4 p-3 mr-3 text-white bg-teal-500 hover:bg-teal-700 transition duration-100">{{ $filters.translate('Check your license') }}</a>
</template>
</modal>
</div>
</div>
@@ -124,8 +124,11 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
if(error.response)
{
self.message = handleErrorMessage(error);
self.messageClass = 'bg-rose-500';
}
});
},
@@ -167,9 +170,12 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.formData[pluginname]['active'] = false;
self.modalMessage = error.response.data.message;
self.showModal = true;
if(error.response)
{
self.formData[pluginname]['active'] = false;
self.modalMessage = handleErrorMessage(error);
self.showModal = true;
}
});
},
setCurrent: function(name)
@@ -203,11 +209,14 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
if(error.response.data.errors !== undefined)
if(error.response)
{
self.errors = error.response.data.errors;
self.message = handleErrorMessage(error);
self.messageClass = 'bg-rose-500';
if(error.response.data.errors !== undefined)
{
self.errors = error.response.data.errors;
}
}
});
},

View File

@@ -1,5 +1,5 @@
const posts = Vue.createApp({
template: `<section id="posts" v-if="showPosts" class="px-12 py-8 bg-stone-50 shadow-md mb-16">
template: `<section id="posts" v-if="showPosts" class="px-12 py-8 bg-stone-50 shadow-md mb-16">
<div class="w-full relative">
<label class="block mb-1 font-medium">{{ $filters.translate('Short title for post') }}</label>
<div class="flex">
@@ -86,61 +86,66 @@ const posts = Vue.createApp({
var self = this;
tmaxios.post('/api/v1/post',{
tmaxios.post('/api/v1/post',{
'folder_id': this.item.keyPath,
'item_name': this.posttitle,
'type': 'file',
})
.then(function (response)
{
if(response.data.item)
{
self.posts = response.data.item.folderContent;
self.posttitle = '';
}
})
.catch(function (error)
{
if(error.response)
{
eventBus.$emit('publishermessage', error.response.data.errors);
}
});
.then(function (response)
{
if(response.data.item)
{
self.posts = response.data.item.folderContent;
self.posttitle = '';
}
})
.catch(function (error)
{
if(error.response)
{
let message = handleErrorMessage(error);
if(message)
{
eventBus.$emit('publishermessage', message);
}
}
});
}
}
})
posts.component('single-post',{
props: ['post', 'baseurl', 'editormode'],
template: `<div class="my-4">
<a :href="getUrl(post.urlRelWoF)" :class="getBorderStyle(post.status)" class="border-l border-l-4 w-full inline-block p-4 bg-stone-100 hover:bg-stone-200 transition duration-100">
<h4 class="text-l font-bold">{{ post.name }} <span class="float-right text-xs font-normal">{{ getDate(post.order) }}</span></h4>
</a>
</div>`,
methods: {
getBorderStyle(status)
{
if(status == 'published')
{
return "border-teal-500";
}
if(status == 'modified')
{
return "border-yellow-400";
}
if(status == 'unpublished')
{
return "border-rose-500";
}
},
getUrl(posturl)
{
props: ['post', 'baseurl', 'editormode'],
template: `<div class="my-4">
<a :href="getUrl(post.urlRelWoF)" :class="getBorderStyle(post.status)" class="border-l border-l-4 w-full inline-block p-4 bg-stone-100 hover:bg-stone-200 transition duration-100">
<h4 class="text-l font-bold">{{ post.name }} <span class="float-right text-xs font-normal">{{ getDate(post.order) }}</span></h4>
</a>
</div>`,
methods: {
getBorderStyle(status)
{
if(status == 'published')
{
return "border-teal-500";
}
if(status == 'modified')
{
return "border-yellow-400";
}
if(status == 'unpublished')
{
return "border-rose-500";
}
},
getUrl(posturl)
{
return this.baseurl + '/tm/content/' + this.editormode + this.post.urlRelWoF;
},
getDate(str)
{
var cleandate = [str.slice(0,4), str.slice(4,6), str.slice(6,8)];
return cleandate.join("-");
}
}
},
getDate(str)
{
var cleandate = [str.slice(0,4), str.slice(4,6), str.slice(6,8)];
return cleandate.join("-");
}
}
})

View File

@@ -86,48 +86,48 @@ const publisher = Vue.createApp({
</div>
<transition name="fade">
<modal v-if="showModal == 'discard'" @close="showModal = false">
<template #header>
<h3>{{ $filters.translate('Discard changes') }}</h3>
</template>
<template #body>
<p>{{ $filters.translate('Do you want to discard your changes and set the content back to the live version') }}?</p>
</template>
<template #button>
<button @click="discardChanges" class="focus:outline-none px-4 p-3 mr-3 text-white bg-rose-500 hover:bg-rose-700 transition duration-100">{{ $filters.translate('Discard changes') }}</button>
</template>
<template #header>
<h3>{{ $filters.translate('Discard changes') }}</h3>
</template>
<template #body>
<p>{{ $filters.translate('Do you want to discard your changes and set the content back to the live version') }}?</p>
</template>
<template #button>
<button @click="discardChanges" class="focus:outline-none px-4 p-3 mr-3 text-white bg-rose-500 hover:bg-rose-700 transition duration-100">{{ $filters.translate('Discard changes') }}</button>
</template>
</modal>
</transition>
<transition name="fade">
<modal v-if="showModal == 'delete'" @close="showModal = false">
<template #header>
<h3>{{ $filters.translate('Delete page') }}</h3>
</template>
<template #body>
<p>
{{ $filters.translate('Do you really want to delete this page') }}?
{{ $filters.translate('Please confirm') }}.
</p>
</template>
<template #button>
<button @click="deleteArticle" class="focus:outline-none px-4 p-3 mr-3 text-white bg-rose-500 hover:bg-rose-700 transition duration-100">{{ $filters.translate('Delete page') }}</button>
</template>
<template #header>
<h3>{{ $filters.translate('Delete page') }}</h3>
</template>
<template #body>
<p>
{{ $filters.translate('Do you really want to delete this page') }}?
{{ $filters.translate('Please confirm') }}.
</p>
</template>
<template #button>
<button @click="deleteArticle" class="focus:outline-none px-4 p-3 mr-3 text-white bg-rose-500 hover:bg-rose-700 transition duration-100">{{ $filters.translate('Delete page') }}</button>
</template>
</modal>
</transition>
<transition name="fade">
<modal v-if="showModal == 'unpublish'" @close="showModal = false">
<template #header>
<h3>{{ $filters.translate('Unpublish page') }}</h3>
</template>
<template #body>
<p>
{{ $filters.translate('This page has been modified') }}.
{{ $filters.translate('If you unpublish the page, then we will delete the published version and keep the modified version') }}.
{{ $filters.translate('Please confirm') }}.
</p>
</template>
<template #button>
<button @click="unpublishArticle" class="focus:outline-none px-4 p-3 mr-3 text-white bg-rose-500 hover:bg-rose-700 transition duration-100">{{ $filters.translate('Unpublish page') }}</button>
</template>
<template #header>
<h3>{{ $filters.translate('Unpublish page') }}</h3>
</template>
<template #body>
<p>
{{ $filters.translate('This page has been modified') }}.
{{ $filters.translate('If you unpublish the page, then we will delete the published version and keep the modified version') }}.
{{ $filters.translate('Please confirm') }}.
</p>
</template>
<template #button>
<button @click="unpublishArticle" class="focus:outline-none px-4 p-3 mr-3 text-white bg-rose-500 hover:bg-rose-700 transition duration-100">{{ $filters.translate('Unpublish page') }}</button>
</template>
</modal>
</transition>
</div>`,
@@ -175,47 +175,47 @@ const publisher = Vue.createApp({
isPublished()
{
return this.item.status == 'published' ? true : false;
},
},
isModified()
{
return this.item.status == 'modified' ? true : false;
},
},
isUnpublished()
{
return this.item.status == 'unpublished' ? true : false;
},
publishClass()
{
if(this.item.status == 'unpublished')
{
return 'bg-teal-500 hover:bg-teal-600';
}
else
{
return 'bg-yellow-500 hover:bg-yellow-600';
}
/*
if(this.item.status == 'modified')
{
return 'bg-yellow-500 hover:bg-yellow-600';
}*/
},
nopublish()
{
if(this.item.status != 'published')
{
return false;
}
return this.nochanges;
},
rawUrl()
{
return data.urlinfo.baseurl + '/tm/content/raw' + this.item.urlRelWoF;
},
visualUrl()
{
return data.urlinfo.baseurl + '/tm/content/visual' + this.item.urlRelWoF;
},
},
publishClass()
{
if(this.item.status == 'unpublished')
{
return 'bg-teal-500 hover:bg-teal-600';
}
else
{
return 'bg-yellow-500 hover:bg-yellow-600';
}
/*
if(this.item.status == 'modified')
{
return 'bg-yellow-500 hover:bg-yellow-600';
}*/
},
nopublish()
{
if(this.item.status != 'published')
{
return false;
}
return this.nochanges;
},
rawUrl()
{
return data.urlinfo.baseurl + '/tm/content/raw' + this.item.urlRelWoF;
},
visualUrl()
{
return data.urlinfo.baseurl + '/tm/content/visual' + this.item.urlRelWoF;
},
},
methods: {
clearPublisher()
@@ -224,14 +224,14 @@ const publisher = Vue.createApp({
this.messageClass = false;
this.showModal = false;
},
markChanges()
{
this.nochanges = false;
},
unmarkChanges()
{
this.nochanges = true;
},
markChanges()
{
this.nochanges = false;
},
unmarkChanges()
{
this.nochanges = true;
},
getStatusClass(status)
{
if(status == 'published')
@@ -265,8 +265,13 @@ const publisher = Vue.createApp({
{
if(error.response)
{
self.message = error.response.data.message;
self.messageClass = "bg-rose-500";
let message = handleErrorMessage(error);
if(message)
{
self.message = message;
self.messageClass = "bg-rose-500";
}
}
});
},
@@ -286,7 +291,7 @@ const publisher = Vue.createApp({
{
self = this;
tmaxios.delete('/api/v1/article/unpublish',{
tmaxios.delete('/api/v1/article/unpublish',{
data: {
'url': data.urlinfo.route,
'item_id': this.item.keyPath,
@@ -300,10 +305,17 @@ const publisher = Vue.createApp({
})
.catch(function (error)
{
self.showModal = false;
if(error.response)
{
self.message = error.response.data.message;
self.messageClass = "bg-rose-500";
let message = handleErrorMessage(error);
if(message)
{
self.message = message;
self.messageClass = "bg-rose-500";
}
}
});
},
@@ -317,7 +329,7 @@ const publisher = Vue.createApp({
'item_id': this.item.keyPath,
}
})
.then(function (response)
.then(function (response)
{
self.clearPublisher();
eventBus.$emit('item', response.data.item);
@@ -326,10 +338,17 @@ const publisher = Vue.createApp({
})
.catch(function (error)
{
self.showModal = false;
if(error.response)
{
self.message = error.response.data.message;
self.messageClass = "bg-rose-500";
let message = handleErrorMessage(error);
if(message)
{
self.message = message;
self.messageClass = "bg-rose-500";
}
}
});
},
@@ -345,23 +364,29 @@ const publisher = Vue.createApp({
{
var self = this;
tmaxios.delete('/api/v1/article',{
tmaxios.delete('/api/v1/article',{
data: {
'url': data.urlinfo.route,
'item_id': this.item.keyPath,
}
})
.then(function (response)
{
.then(function (response)
{
window.location.replace(response.data.url);
})
})
.catch(function (error)
{
self.showModal = false;
if(error.response)
{
self.showModal = false;
self.message = error.response.data.message;
self.messageClass = "bg-rose-500";
let message = handleErrorMessage(error);
if(message)
{
self.message = message;
self.messageClass = "bg-rose-500";
}
}
});
},

View File

@@ -130,7 +130,14 @@ const raweditor = Vue.createApp({
})
.catch(function (error)
{
if(error.response)
{
let message = handleErrorMessage(error);
if(message)
{
eventBus.$emit('publishermessage', message);
}
}
});
},
publishDraft()
@@ -150,7 +157,14 @@ const raweditor = Vue.createApp({
})
.catch(function (error)
{
if(error.response)
{
let message = handleErrorMessage(error);
if(message)
{
eventBus.$emit('publishermessage', message);
}
}
});
},
},

View File

@@ -51,3 +51,76 @@ const translatefilter = {
}
}
function handleErrorMessage(error)
{
if(error.response)
{
if(error.response.status == 401)
{
eventBus.$emit('loginform', false);
}
else if(error.response.data.message)
{
return error.response.data.message;
}
}
return false;
}
const loginform = Vue.createApp({
template: `<transition name="initial" appear>
<div v-if="show" class="fixed w-full h-100 inset-0 z-50 overflow-hidden flex justify-center items-center bg-stone-700 bg-opacity-90">
<div class="border border-teal-500 shadow-lg bg-white w-11/12 md:max-w-md mx-auto shadow-lg z-50 overflow-y-auto">
<div class="text-left p-6">
<div class="text-2xl font-bold"><h2>You are logged out</h2></div>
<div class="my-5">
<p>You can visit the login page and authenticate again. Or you can close this window but you cannot perform any actions.</p>
</div>
<div class="flex justify-end pt-2">
<a :href="loginurl" class="focus:outline-none px-4 p-3 mr-3 text-black bg-stone-200 hover:bg-stone-300 transition duration-100">login page</a>
<button class="focus:outline-none px-4 p-3 mr-3 text-black bg-stone-200 hover:bg-stone-300 transition duration-100" @click="show = false">close window</button>
</div>
</div>
</div>
</div>
</transition>`,
data() {
return {
show: false,
errors: {},
username: '',
password: '',
loginurl: data.urlinfo.baseurl + '/tm/login'
}
},
mounted() {
eventBus.$on('loginform', content => {
this.show = true;
});
},
methods: {
login: function()
{
var self = this;
tmaxios.post('/api/v1/authenticate',{
'username': this.username,
'password': this.password
})
.then(function (response)
{
self.show = false;
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
if(error.response.data.errors !== undefined)
{
self.errors = error.response.data.errors;
}
});
},
},
})

View File

@@ -1,6 +1,6 @@
const app = Vue.createApp({
template: `<Transition name="initial" appear>
<form class="inline-block w-full">
<form class="inline-block w-full">
<p v-if="version.system !== undefined"><a href="https://typemill.net" class="block p-2 text-center bg-rose-500 text-white">Please update typemill to version {{ version.system }}</a></p>
<ul class="flex mt-4 mb-4">
<li v-for="tab in tabs" class="">
@@ -24,8 +24,8 @@ const app = Vue.createApp({
<div :class="messageClass" class="block w-full h-8 px-3 py-1 my-1 text-white transition duration-100">{{ $filters.translate(message) }}</div>
<input type="submit" @click.prevent="save()" :value="$filters.translate('save')" class="w-full p-3 my-1 bg-stone-700 hover:bg-stone-900 text-white cursor-pointer transition duration-100">
</div>
</form>
</Transition>`,
</form>
</Transition>`,
data() {
return {
currentTab: 'System',
@@ -65,13 +65,15 @@ const app = Vue.createApp({
if(response.data.system)
{
self.version = response.data.system;
console.info(self.version);
}
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
if(error.response)
{
self.message = handleErrorMessage(error);
self.messageClass = 'bg-rose-500';
}
});
},
methods: {
@@ -98,11 +100,14 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
if(error.response.data.errors !== undefined)
if(error.response)
{
self.errors = error.response.data.errors;
self.message = handleErrorMessage(error);
self.messageClass = 'bg-rose-500';
if(error.response.data.errors !== undefined)
{
self.errors = error.response.data.errors;
}
}
});
},

View File

@@ -8,12 +8,12 @@ const app = Vue.createApp({
<p class="py-2">License: {{ theme.license }}</p>
<div class="flex">
<label :for="themename" class="p-2">{{ $filters.translate('active') }}</label>
<input type="checkbox" class="w-6 h-6 my-2 accent-white"
:name="themename"
v-model="formData[themename]['active']"
@change="activate(themename)">
<input type="checkbox" class="w-6 h-6 my-2 accent-white"
:name="themename"
v-model="formData[themename]['active']"
@change="activate(themename)">
</div>
</div>
</div>
<div class="w-full p-8">
<div class="flex pb-4">
<div class="w-1/2">
@@ -71,15 +71,15 @@ const app = Vue.createApp({
</ul>
<div class="my-5 text-center">
<modal v-if="showModal" @close="showModal = false">
<template #header>
<h3>{{ $filters.translate('License required') }}</h3>
</template>
<template #body>
<p>{{ $filters.translate(modalMessage) }}</p>
</template>
<template #button>
<a :href="getLinkToLicense()" class="focus:outline-none px-4 p-3 mr-3 text-white bg-teal-500 hover:bg-teal-700 transition duration-100">{{ $filters.translate('Check your license') }}</a>
</template>
<template #header>
<h3>{{ $filters.translate('License required') }}</h3>
</template>
<template #body>
<p>{{ $filters.translate(modalMessage) }}</p>
</template>
<template #button>
<a :href="getLinkToLicense()" class="focus:outline-none px-4 p-3 mr-3 text-white bg-teal-500 hover:bg-teal-700 transition duration-100">{{ $filters.translate('Check your license') }}</a>
</template>
</modal>
</div>
</div>
@@ -132,8 +132,11 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
if(error.response)
{
self.messageClass = 'bg-rose-500';
self.message = handleErrorMessage(error);
}
});
},
methods: {
@@ -182,8 +185,12 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.modalMessage = error.response.data.message;
self.showModal = true;
if(error.response)
{
self.showModal = true;
self.modalMessage = handleErrorMessage(error);
self.messageClass = 'bg-rose-500';
}
});
},
setCurrent: function(name)
@@ -219,11 +226,14 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
if(error.response.data.errors !== undefined)
if(error.response)
{
self.errors = error.response.data.errors;
self.message = handleErrorMessage(error);
self.messageClass = 'bg-rose-500';
if(error.response.data.errors !== undefined)
{
self.errors = error.response.data.errors;
}
}
});
},

View File

@@ -6,23 +6,23 @@ const app = Vue.createApp({
<fieldset class="flex flex-wrap justify-between border-2 border-stone-200 p-4 my-8" v-if="fieldDefinition.type == 'fieldset'">
<legend class="text-lg font-medium">{{ $filters.translate(fieldDefinition.legend) }}</legend>
<component v-for="(subfieldDefinition, subfieldname) in fieldDefinition.fields"
:key="subfieldname"
:is="selectComponent(subfieldDefinition.type)"
:errors="errors"
:name="subfieldname"
:userroles="userroles"
:value="formData[subfieldname]"
v-bind="subfieldDefinition">
:key="subfieldname"
:is="selectComponent(subfieldDefinition.type)"
:errors="errors"
:name="subfieldname"
:userroles="userroles"
:value="formData[subfieldname]"
v-bind="subfieldDefinition">
</component>
</fieldset>
<component v-else
:key="fieldname"
:is="selectComponent(fieldDefinition.type)"
:errors="errors"
:name="fieldname"
:userroles="userroles"
:value="formData[fieldname]"
v-bind="fieldDefinition">
:key="fieldname"
:is="selectComponent(fieldDefinition.type)"
:errors="errors"
:name="fieldname"
:userroles="userroles"
:value="formData[fieldname]"
v-bind="fieldDefinition">
</component>
</div>
<div class="my-5">
@@ -33,15 +33,15 @@ const app = Vue.createApp({
<div class="my-5 text-center">
<button @click.prevent="showModal = true" class="p-3 px-4 text-rose-500 border border-rose-100 hover:border-rose-500 cursor-pointer transition duration-100">{{ $filters.translate('delete user') }}</button>
<modal v-if="showModal" @close="showModal = false">
<template #header>
<h3>{{ $filters.translate('Delete user') }}</h3>
</template>
<template #body>
<p>{{ $filters.translate('Do you really want to delete this user') }}?</p>
</template>
<template #button>
<button @click="deleteuser()" class="focus:outline-none px-4 p-3 mr-3 text-white bg-rose-500 hover:bg-rose-700 transition duration-100">{{ $filters.translate('delete user') }}</button>
</template>
<template #header>
<h3>{{ $filters.translate('Delete user') }}</h3>
</template>
<template #body>
<p>{{ $filters.translate('Do you really want to delete this user') }}?</p>
</template>
<template #button>
<button @click="deleteuser()" class="focus:outline-none px-4 p-3 mr-3 text-white bg-rose-500 hover:bg-rose-700 transition duration-100">{{ $filters.translate('delete user') }}</button>
</template>
</modal>
</div>
</div>
@@ -89,11 +89,14 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
if(error.response.data.errors !== undefined)
if(error.response)
{
self.errors = error.response.data.errors;
self.messageClass = 'bg-rose-500';
self.message = handleErrorMessage(error);
if(error.response.data.errors !== undefined)
{
self.errors = error.response.data.errors;
}
}
});
},
@@ -117,12 +120,15 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.showModal = false;
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
if(error.response.data.errors !== undefined)
if(error.response)
{
self.errors = error.response.data.errors;
self.showModal = false;
self.messageClass = 'bg-rose-500';
self.message = handleErrorMessage(error);
if(error.response.data.errors !== undefined)
{
self.errors = error.response.data.errors;
}
}
});
},

View File

@@ -10,28 +10,28 @@ const app = Vue.createApp({
<option v-for="option,optionkey in userroles">{{option}}</option>
</select>
</div>
<form v-if="formDefinitions" class="w-full my-8">
<form v-if="formDefinitions" class="w-full my-8">
<div v-for="(fieldDefinition, fieldname) in formDefinitions">
<fieldset class="flex flex-wrap justify-between border-2 border-stone-200 p-4 my-8" v-if="fieldDefinition.type == 'fieldset'">
<legend class="text-lg font-medium">{{ fieldDefinition.legend }}</legend>
<component v-for="(subfieldDefinition, subfieldname) in fieldDefinition.fields"
:key="subfieldname"
:is="selectComponent(subfieldDefinition.type)"
:errors="errors"
:name="subfieldname"
:userroles="userroles"
:value="formData[subfieldname]"
v-bind="subfieldDefinition">
:key="subfieldname"
:is="selectComponent(subfieldDefinition.type)"
:errors="errors"
:name="subfieldname"
:userroles="userroles"
:value="formData[subfieldname]"
v-bind="subfieldDefinition">
</component>
</fieldset>
<component v-else
:key="fieldname"
:is="selectComponent(fieldDefinition.type)"
:errors="errors"
:name="fieldname"
:userroles="userroles"
:value="formData[fieldname]"
v-bind="fieldDefinition">
:key="fieldname"
:is="selectComponent(fieldDefinition.type)"
:errors="errors"
:name="fieldname"
:userroles="userroles"
:value="formData[fieldname]"
v-bind="fieldDefinition">
</component>
</div>
<div class="my-5">
@@ -67,10 +67,10 @@ const app = Vue.createApp({
this.reset();
var self = this;
tmaxios.get('/api/v1/userform',{
params: {
tmaxios.get('/api/v1/userform',{
params: {
'userrole': this.selectedrole
}
}
})
.then(function (response)
{
@@ -79,13 +79,16 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
if(error.response.data.errors !== undefined)
if(error.response)
{
self.errors = error.response.data.errors;
self.messageClass = 'bg-rose-500';
self.message = handleErrorMessage(error);
if(error.response.data.errors !== undefined)
{
self.errors = error.response.data.errors;
}
}
});
});
},
save: function()
{
@@ -104,11 +107,14 @@ const app = Vue.createApp({
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
if(error.response.data.errors !== undefined)
if(error.response)
{
self.errors = error.response.data.errors;
self.messageClass = 'bg-rose-500';
self.message = handleErrorMessage(error);
if(error.response.data.errors !== undefined)
{
self.errors = error.response.data.errors;
}
}
});
},

View File

@@ -4,10 +4,10 @@ const app = Vue.createApp({
<searchbox :error="error"></searchbox>
</Transition>
</div>
<div class="w-full overflow-auto">
<div class="w-full overflow-auto">
<Transition name="initial" appear>
<usertable :userdata="userdata"></usertable>
</Transition>
<usertable :userdata="userdata"></usertable>
</Transition>
</div>
<ul class="w-full flex mt-4" v-if="showpagination">
<pagination
@@ -33,8 +33,8 @@ const app = Vue.createApp({
this.calculatepages();
},
computed: {
showpagination: function () {
return this.pages != 1;
showpagination: function () {
return this.pages != 1;
}
},
methods: {
@@ -53,27 +53,30 @@ const app = Vue.createApp({
this.pages = Math.ceil(this.usernames.length / this.pagesize);
this.pagenumber = 1;
},
getusernamesforpage: function() {
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
return this.usernames.slice((this.pagenumber - 1) * this.pagesize, this.pagenumber * this.pagesize);
getusernamesforpage: function() {
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
return this.usernames.slice((this.pagenumber - 1) * this.pagesize, this.pagenumber * this.pagesize);
},
getuserdata: function(usernames)
{
var self = this;
tmaxios.get('/api/v1/users/getbynames',{
params: {
'usernames': usernames,
}
tmaxios.get('/api/v1/users/getbynames',{
params: {
'usernames': usernames,
}
})
.then(function (response) {
self.userdata = response.data.userdata;
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
});
.then(function (response) {
self.userdata = response.data.userdata;
})
.catch(function (error)
{
if(error.response)
{
self.messageClass = 'bg-rose-500';
self.message = handleErrorMessage(error);
}
});
},
search: function(term,filter)
{
@@ -98,25 +101,31 @@ const app = Vue.createApp({
var self = this;
tmaxios.get('/api/v1/users/getbyemail',{
params: {
'email': term,
}
tmaxios.get('/api/v1/users/getbyemail',{
params: {
'email': term,
}
})
.then(function (response)
{
self.userdata = response.data.userdata;
for(var x = 0; x <= self.userdata.length; x++)
{
self.usernames.push(self.userdata[x].username);
}
self.calculatepages();
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
});
.then(function (response)
{
self.userdata = response.data.userdata;
if(self.userdata.length > 0)
{
for(var x = 0; x <= self.userdata.length; x++)
{
self.usernames.push(self.userdata[x].username);
}
self.calculatepages();
}
})
.catch(function (error)
{
if(error.response)
{
self.messageClass = 'bg-rose-500';
self.message = handleErrorMessage(error);
}
});
}
else if(filter == 'userrole')
{
@@ -126,57 +135,60 @@ const app = Vue.createApp({
var self = this;
tmaxios.get('/api/v1/users/getbyrole',{
params: {
'role': term,
}
tmaxios.get('/api/v1/users/getbyrole',{
params: {
'role': term,
}
})
.then(function (response)
{
self.userdata = response.data.userdata;
for(var x = 0; x <= self.userdata.length; x++)
{
self.usernames.push(self.userdata[x].username);
}
.then(function (response)
{
self.userdata = response.data.userdata;
for(var x = 0; x <= self.userdata.length; x++)
{
self.usernames.push(self.userdata[x].username);
}
self.calculatepages();
})
.catch(function (error)
{
self.messageClass = 'bg-rose-500';
self.message = error.response.data.message;
});
})
.catch(function (error)
{
if(error.response)
{
self.messageClass = 'bg-rose-500';
self.message = handleErrorMessage(error);
}
});
}
},
filterItems: function(arr, query)
{
return arr.filter(function(el){
return el.toLowerCase().indexOf(query.toLowerCase()) !== -1
return el.toLowerCase().indexOf(query.toLowerCase()) !== -1
})
},
}
})
app.component('searchbox', {
props: ['usernames', 'error'],
data: function () {
props: ['usernames', 'error'],
data: function () {
return {
filter: 'username',
searchterm: '',
userroles: data.userroles,
filter: 'username',
searchterm: '',
userroles: data.userroles,
}
},
template: `<div>
<div>
<button @click.prevent="setFilter('username')" :class="checkActive('username')" class="px-2 py-2 border-b-4 hover:bg-stone-200 hover:border-stone-700 transition duration-100">{{ $filters.translate('username') }}</button>
template: `<div>
<div>
<button @click.prevent="setFilter('username')" :class="checkActive('username')" class="px-2 py-2 border-b-4 hover:bg-stone-200 hover:border-stone-700 transition duration-100">{{ $filters.translate('username') }}</button>
<button @click.prevent="setFilter('userrole')" :class="checkActive('userrole')" class="px-2 py-2 border-b-4 hover:bg-stone-200 hover:border-stone-700 transition duration-100">{{ $filters.translate('userrole') }}</button>
<button @click.prevent="setFilter('usermail')" :class="checkActive('usermail')" class="px-2 py-2 border-b-4 hover:bg-stone-200 hover:border-stone-700 transition duration-100">{{ $filters.translate('e-mail') }}</button>
</div>
<div class="w-100 flex">
<div class="w-100 flex">
<select v-if="this.filter == 'userrole'" v-model="searchterm" class="w-3/4 h-12 px-2 py-3 border border-stone-300 bg-stone-200">
<option v-for="role in userroles">{{role}}</option>
</select>
<input v-else type="text" v-model="searchterm" class="w-3/4 h-12 px-2 py-3 border border-stone-300 bg-stone-200">
<div class="w-1/4 flex justify-around">
<input v-else type="text" v-model="searchterm" class="w-3/4 h-12 px-2 py-3 border border-stone-300 bg-stone-200">
<div class="w-1/4 flex justify-around">
<button class="w-half bg-stone-200 hover:bg-stone-100" @click.prevent="clearSearch()">{{ $filters.translate('Clear') }}</button>
<button class="w-half bg-stone-700 hover:bg-stone-900 text-white" @click.prevent="startSearch()">{{ $filters.translate('Search') }}</button>
</div>
@@ -184,96 +196,96 @@ app.component('searchbox', {
<div v-if="error" class="error pt1 f6">{{error}}</div>
<div v-if="this.filter == \'usermail\'" class="text-xs">{{ $filters.translate('You can use the asterisk (*) wildcard to search for name@* or *@domain.com') }}.</div>
</div>`,
methods: {
startSearch: function()
{
this.$root.error = false;
if(this.searchterm.trim() != '')
{
if(this.searchterm.trim().length < 3)
{
this.$root.error = 'Please enter at least 3 characters';
return;
}
this.$root.search(this.searchterm, this.filter);
}
},
clearSearch: function()
{
this.$root.error = false;
this.searchterm = '';
this.$root.clear(this.filter);
},
setFilter: function(filter)
{
this.searchterm = '';
this.filter = filter;
if(filter == 'userrole')
{
this.searchterm = this.userroles[0];
}
},
checkActive: function(filter)
{
if(this.filter == filter)
{
return 'border-stone-700 bg-stone-200';
}
return 'border-stone-100 bg-stone-100';
}
}
methods: {
startSearch: function()
{
this.$root.error = false;
if(this.searchterm.trim() != '')
{
if(this.searchterm.trim().length < 3)
{
this.$root.error = 'Please enter at least 3 characters';
return;
}
this.$root.search(this.searchterm, this.filter);
}
},
clearSearch: function()
{
this.$root.error = false;
this.searchterm = '';
this.$root.clear(this.filter);
},
setFilter: function(filter)
{
this.searchterm = '';
this.filter = filter;
if(filter == 'userrole')
{
this.searchterm = this.userroles[0];
}
},
checkActive: function(filter)
{
if(this.filter == filter)
{
return 'border-stone-700 bg-stone-200';
}
return 'border-stone-100 bg-stone-100';
}
}
})
app.component('usertable', {
props: ['userdata'],
template: `<table class="w-full mt-8" cellspacing="0">
props: ['userdata'],
template: `<table class="w-full mt-8" cellspacing="0">
<tr>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('Username') }}</th>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('Userrole') }}</th>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('E-Mail') }}</th>
<th class="p-3 bg-stone-200 border-2 border-stone-50">{{ $filters.translate('Edit') }}</th>
</tr>
<tr v-for="user,index in userdata" key="username">
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.username }}</td>
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.userrole }}</td>
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.email }}</td>
<td class="bg-stone-100 border-2 border-white text-center hover:bg-teal-500 hover:text-white pointer transition duration-100"><a :href="getEditLink(user.username)" class="block w-full p-3">{{ $filters.translate('edit') }}</a></td>
</tr>
<tr>
<td class="p-3 bg-stone-100 border-2 border-white"><a class="text-teal-500 hover:underline" :href="getNewUserLink()">{{ $filters.translate('New user') }}</a></td>
<td class="p-3 bg-stone-100 border-2 border-white"></td>
<td class="p-3 bg-stone-100 border-2 border-white"></td>
<td class="bg-stone-100 border-2 border-white text-center text-teal-500 hover:bg-teal-500 hover:text-white transition duration-100"><a class="block w-full p-3" :href="getNewUserLink()">{{ $filters.translate('add') }}</a></td>
</tr>
<tr v-for="user,index in userdata" key="username">
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.username }}</td>
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.userrole }}</td>
<td class="p-3 bg-stone-100 border-2 border-white">{{ user.email }}</td>
<td class="bg-stone-100 border-2 border-white text-center hover:bg-teal-500 hover:text-white pointer transition duration-100"><a :href="getEditLink(user.username)" class="block w-full p-3">{{ $filters.translate('edit') }}</a></td>
</tr>
<tr>
<td class="p-3 bg-stone-100 border-2 border-white"><a class="text-teal-500 hover:underline" :href="getNewUserLink()">{{ $filters.translate('New user') }}</a></td>
<td class="p-3 bg-stone-100 border-2 border-white"></td>
<td class="p-3 bg-stone-100 border-2 border-white"></td>
<td class="bg-stone-100 border-2 border-white text-center text-teal-500 hover:bg-teal-500 hover:text-white transition duration-100"><a class="block w-full p-3" :href="getNewUserLink()">{{ $filters.translate('add') }}</a></td>
</tr>
</table>`,
methods: {
methods: {
getEditLink: function(username){
return tmaxios.defaults.baseURL + '/tm/user/' + username;
},
getNewUserLink: function(){
return tmaxios.defaults.baseURL + '/tm/user/new';
},
}
}
})
app.component('pagination', {
props: ['page'],
template: '<li><button class="p-1 border-2 border-stone-50 hover:bg-stone-200" :class="checkActive()" @click="goto(page)">{{ page }}</button></li>',
methods: {
goto: function(page){
props: ['page'],
template: '<li><button class="p-1 border-2 border-stone-50 hover:bg-stone-200" :class="checkActive()" @click="goto(page)">{{ page }}</button></li>',
methods: {
goto: function(page){
this.$root.$data.pagenumber = page;
let usernames = this.$root.getusernamesforpage();
this.$root.getuserdata(usernames);
},
checkActive: function()
{
if(this.page == this.$root.$data.pagenumber)
{
return 'bg-stone-200';
}
return 'bg-stone-100';
}
}
},
checkActive: function()
{
if(this.page == this.$root.$data.pagenumber)
{
return 'bg-stone-200';
}
return 'bg-stone-100';
}
}
})

View File

@@ -42,6 +42,7 @@
{% block content %}{% endblock %}
</article>
</div>
<div id="loginform"></div>
<!-- < csrf() | raw > -->
@@ -67,6 +68,7 @@
<script>
navigation.config.globalProperties.$filters = translatefilter;
navigation.mount('#contentNavigation');
loginform.mount("#loginform");
</script>
{% block javascript %}{% endblock %}

View File

@@ -42,7 +42,7 @@
{% block content %}{% endblock %}
</article>
</div>
<div id="loginform"></div>
<!-- < csrf() | raw > -->
<script>
@@ -64,6 +64,7 @@
<script src="{{ base_url() }}/system/typemill/author/js/vue-medialib.js?v={{ settings.version }}"></script>
<script>
/* kixote.mount('#kixote'); */
loginform.mount("#loginform");
</script>
{% block javascript %}{% endblock %}

View File

@@ -45,7 +45,8 @@
</article>
</div>
<div id="loginform"></div>
<script>
const data = {{ jsdata | json_encode() | raw }};
@@ -73,6 +74,8 @@
app.config.globalProperties.$filters = translatefilter;
app.mount('#system');
loginform.mount("#loginform");
/* kixote.mount('#kixote'); */
</script>

View File

@@ -32,7 +32,7 @@ fieldsetsystem:
maxlength: 4
language:
type: select
label: Language (admin ui)
label: Language (author area)
css: w-half
maxlength: 60
options: