Publishing module assets

parent 9f044885
......@@ -12,7 +12,7 @@
<script>
// Source: https://github.com/dangvanthanh/vue-ckeditor2
let inc = 0
let inc = new Date().getTime();
export default {
name: 'vue-ckeditor',
props: {
......@@ -46,9 +46,11 @@
},
watch: {
value (val) {
let html = this.instance.getData();
if (val !== html) {
this.instance.setData(val);
if (this.instance) {
let html = this.instance.getData();
if (val !== html) {
this.instance.setData(val);
}
}
}
},
......
......@@ -3,9 +3,7 @@
</template>
<script>
import Translate from '../../../../Core/Assets/js/mixins/Translate'
export default {
mixins: [Translate],
props: {
rows: {default: null},
scope: {default: null},
......@@ -19,8 +17,8 @@
methods: {
deleteRow(event) {
this.$confirm(this.deleteMessage, this.deleteTitle, {
confirmButtonText: this.translate('core', 'button.delete'),
cancelButtonText: this.translate('core', 'button.cancel'),
confirmButtonText: this.trans('core.button.delete'),
cancelButtonText: this.trans('core.button.cancel'),
type: 'warning'
}).then(() => {
let vm = this;
......@@ -38,20 +36,20 @@
.catch(error => {
vm.$message({
type: 'error',
message: response.data.message
message: error.data.message
});
});
}).catch(() => {
this.$message({
type: 'info',
message: this.translate('core', 'delete cancelled')
message: this.trans('core.delete cancelled')
});
});
}
},
mounted() {
this.deleteMessage = this.translate('core', 'modal.confirmation-message');
this.deleteTitle = this.translate('core', 'modal.title');
this.deleteMessage = this.trans('core.modal.confirmation-message');
this.deleteTitle = this.trans('core.modal.title');
}
}
</script>
export default {
methods: {
getCurrentEditor() {
const configuredEditor = window.AsgardCMS.editor;
if (configuredEditor === 'simplemde') {
return 'markdown-editor';
}
if (configuredEditor === 'ckeditor') {
return 'ckeditor';
}
return 'ckeditor'
},
}
}
export default {
methods: {
pushRoute(route) {
this.$router.push(route);
}
}
}
<template>
</template>
<script>
export default {
methods: {
ucfirst(string) {
return string[0].toUpperCase() + string.substr(1);
},
ucwords(string) {
return string.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
}
},
}
</script>
export default {
methods: {
trans(string) {
// Makes a string: core.button.cancel | core.button.created at
// to: core["button.cancel"] | core["button.created at"]
let array = string.split('.');
if (array.length < 2) { return this.$t(string) }
let first = array.splice(0,1);
let key = array.join('.');
return this.$t(`${first}['${key}']`);
},
}
}
import MediaManager from './components/MediaManager.vue';
import MediaList from './components/MediaList.vue';
import MediaForm from './components/MediaForm.vue';
const locales = window.AsgardCMS.locales;
export default [
{
path: '/media/media',
component: MediaManager,
children: [
{
path: '',
component: MediaList,
name: 'admin.media.media.index'
},
{
path: ':mediaId/edit',
component: MediaForm,
name: 'admin.media.media.edit',
props: {
locales,
}
},
]
}
];
<style>
.el-select{
display: block;
}
</style>
<template>
<div>
<div class="content-header">
<h1>
{{ trans('media.title.edit media') }}
</h1>
<el-breadcrumb separator="/">
<el-breadcrumb-item>
<a href="/backend">Home</a>
</el-breadcrumb-item>
<el-breadcrumb-item :to="{name: 'admin.media.media.index', query: {folder_id: media.folder_id}}">{{ trans('media.breadcrumb.media') }}
</el-breadcrumb-item>
<el-breadcrumb-item :to="{name: 'admin.media.media.edit'}">{{ trans('media.title.edit media') }}
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<el-form ref="form" :model="media" label-width="120px" label-position="top"
v-loading.body="loading"
@keydown="form.errors.clear($event.target.name);">
<div class="row">
<div class="col-md-8">
<div class="box box-primary">
<div class="box-body">
<el-tabs type="card" v-model="activeTab">
<el-tab-pane :label="localeArray.name" v-for="(localeArray, locale) in locales"
:key="localeArray.name" :name="locale">
<el-form-item :label="trans('media.form.alt_attribute')"
:class="{'el-form-item is-error': form.errors.has(locale + '.alt_attribute') }">
<el-input v-model="media[locale].alt_attribute"></el-input>
<div class="el-form-item__error" v-if="form.errors.has(locale + '.alt_attribute')"
v-text="form.errors.first(locale + '.alt_attribute')"></div>
</el-form-item>
<el-form-item :label="trans('media.form.description')"
:class="{'el-form-item is-error': form.errors.has(locale + '.description') }">
<el-input type="textarea" v-model="media[locale].description"></el-input>
<div class="el-form-item__error" v-if="form.errors.has(locale + '.description')"
v-text="form.errors.first(locale + '.description')"></div>
</el-form-item>
<el-form-item :label="trans('media.form.keywords')"
:class="{'el-form-item is-error': form.errors.has(locale + '.keywords') }">
<el-input v-model="media[locale].keywords"></el-input>
<div class="el-form-item__error" v-if="form.errors.has(locale + '.keywords')"
v-text="form.errors.first(locale + '.keywords')"></div>
</el-form-item>
<hr>
<tags-input namespace="asgardcms/media" v-model="tags" :value="tags" :current-tags="tags"></tags-input>
<el-form-item>
<el-button type="primary" @click="onSubmit()" :loading="loading">
{{ trans('core.save') }}
</el-button>
<el-button @click="onCancel()">{{ trans('core.button.cancel') }}
</el-button>
</el-form-item>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
<div class="col-md-4">
<img :src="media.path" alt="" v-if="media.is_image" style="width: 100%;"/>
<i class="fa fa-file" style="font-size: 50px;" v-else=""></i>
</div>
</div>
</el-form>
<div class="row">
<div class="col-md-12">
<h3>Thumbnails</h3>
<ul class="list-unstyled">
<li v-for="thumbnail in media.thumbnails" :key="thumbnail.name" style="float:left; margin-right: 10px">
<img :src="thumbnail.path" alt=""/>
<p class="text-muted" style="text-align: center">{{ thumbnail.name }} ({{ thumbnail.size }})</p>
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
import Form from 'form-backend-validation'
import axios from 'axios'
export default {
props: {
locales: {default: null},
},
data() {
return {
media: _(this.locales)
.keys()
.map(locale => [locale, {
description: '',
alt_attribute: '',
keywords: '',
}])
.fromPairs()
//.merge({template: 'default', is_home: 0, medias_single: []})
.value(),
form: new Form(),
loading: false,
tags: {},
activeTab: window.AsgardCMS.currentLocale || 'en',
}
},
methods: {
fetchMedia() {
this.loading = true;
axios.get(route('api.media.media.find', {media: this.$route.params.mediaId}))
.then(response => {
this.loading = false;
this.media = response.data.data;
this.tags = response.data.data.tags;
})
.catch(error => {
})
},
onSubmit() {
this.form = new Form(_.merge(this.media, {tags: this.tags}));
this.loading = true;
this.form.put(route('api.media.media.update', {file: this.media.id}))
.then(response => {
this.loading = false;
this.$message({
type: 'success',
message: response.message
});
this.$router.push({name: 'admin.media.media.index', query: {folder_id: this.media.folder_id}})
})
.catch(error => {
console.log(error);
this.loading = false;
this.$notify.error({
title: 'Error',
message: 'There are some errors in the form.'
});
});
},
onCancel() {
if (this.media.folder_id == 0) {
this.$router.push({name: 'admin.media.media.index', query: {}});
return;
}
this.$router.push({name: 'admin.media.media.index', query: {folder_id: this.media.folder_id}})
},
},
mounted() {
if (this.$route.params.mediaId !== undefined) {
this.fetchMedia();
}
}
}
</script>
<template>
<div class="row" style="margin-top: -35px;">
<div class="col-xs-12">
<div class="sc-table">
<div class="el-row">
<div class="title">
<h4 v-if="singleModal">{{ trans('media.choose file') }}</h4>
<h3 v-if="! singleModal">{{ trans('media.title.media') }}</h3>
<div class="media-breadcrumb">
<el-breadcrumb separator="/" v-if="! singleModal">
<el-breadcrumb-item>
<a href="/backend">Home</a>
</el-breadcrumb-item>
<el-breadcrumb-item :to="{name: 'admin.media.media.index'}">{{ trans('media.breadcrumb.media') }}
</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>
</div>
<div class="box box-primary">
<div class="box-body">
<div class="tool-bar el-row" style="padding-bottom: 20px;">
<div class="actions el-col el-col-14">
<new-folder :parent-id="folderId"></new-folder>
<upload-button :parent-id="folderId"></upload-button>
<el-button-group>
<el-button type="primary" :disabled="selectedMedia.length === 0">Move</el-button>
<el-button type="danger" :disabled="selectedMedia.length === 0"
@click.preent="batchDelete" :loading="filesAreDeleting">
Delete
</el-button>
</el-button-group>
</div>
<div class="search el-col el-col-5">
<el-input icon="search" @change="performSearch" v-model="searchQuery">
</el-input>
</div>
</div>
<el-row>
<el-col :span="24">
<el-breadcrumb separator="/" style="margin-bottom: 20px;">
<el-breadcrumb-item v-for="(folder, index) in folderBreadcrumb" @click.native="changeRoot(folder.id, index)" :key="folder.id">
{{ folder.name }}
</el-breadcrumb-item>
</el-breadcrumb>
</el-col>
</el-row>
<el-table
:data="data"
stripe
style="width: 100%"
ref="mediaTable"
v-loading.body="tableIsLoading"
@sort-change="handleSortChange"
@selection-change="handleSelectionChange">
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column label="" width="150">
<template scope="scope">
<img :src="scope.row.small_thumb" alt="" v-if="scope.row.is_image"/>
<i :class="`fa ${scope.row.fa_icon}`" style="font-size: 38px;"
v-if="! scope.row.is_image && ! scope.row.is_folder"></i>
<i class="fa fa-folder" style="font-size: 38px;"
v-if="scope.row.is_folder"></i>
</template>
</el-table-column>
<el-table-column prop="filename" :label="trans('media.table.filename')" sortable="custom">
<template scope="scope">
<strong v-if="scope.row.is_folder" style="cursor: pointer;" @click="enterFolder(scope)">
{{ scope.row.filename }}
</strong>
<span v-else>{{ scope.row.filename }}</span>
</template>
</el-table-column>
<el-table-column prop="created_at" :label="trans('core.table.created at')" sortable="custom"
width="150">
</el-table-column>
<el-table-column prop="actions" label="" width="150">
<template scope="scope">
<a class="btn btn-primary btn-flat" @click.prevent="insertMedia(scope)"
v-if="singleModal && ! scope.row.is_folder">
{{ trans('media.insert') }}
</a>
<div v-if="! singleModal">
<a class="btn btn-default btn-flat" @click.prevent="loadEditForm(scope)"
v-if="! scope.row.is_folder"><i class="fa fa-pencil"></i></a>
<a @click.prevent="showEditFolder(scope.row)" class="btn btn-default btn-flat"
v-if="scope.row.is_folder">
<i class="fa fa-pencil"></i>
</a>
<delete-button :scope="scope" :rows="data"></delete-button>
</div>
</template>
</el-table-column>
</el-table>
<div class="pagination-wrap" style="text-align: center; padding-top: 20px;">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="meta.current_page"
:page-sizes="[10, 20, 50, 100]"
:page-size="parseInt(meta.per_page)"
layout="total, sizes, prev, pager, next, jumper"
:total="meta.total">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
<rename-folder></rename-folder>
</div>
</template>
<script>
import axios from 'axios'
import NewFolder from './NewFolder.vue';
import UploadButton from './UploadButton.vue';
import RenameFolder from './RenameFolder.vue';
export default {
components: {
'new-folder': NewFolder,
'upload-button': UploadButton,
'rename-folder': RenameFolder,
},
props: {
singleModal: {type: Boolean},
eventName: {},
},
data() {
return {
data: [],
tableIsLoading: false,
meta: {
current_page: 1,
per_page: 10,
},
order_meta: {
order_by: '',
order: '',
},
links: {},
searchQuery: '',
folderId: 0,
selectedMedia: {},
folderBreadcrumb: [
{id: 0, name: 'Home'},
],
filesAreDeleting: false,
}
},
methods: {
queryServer(customProperties) {
let properties = {
page: this.meta.current_page,
per_page: this.meta.per_page,
order_by: this.order_meta.order_by,
order: this.order_meta.order,
search: this.searchQuery,
folder_id: this.folderId,
};
axios.get(route('api.media.all-vue', _.merge(properties, customProperties)))
.then(response => {
this.tableIsLoading = false;
this.data = response.data.data;
this.meta = response.data.meta;
this.links = response.data.links;
this.order_meta.order_by = properties.order_by;
this.order_meta.order = properties.order;
});
},
fetchMediaData() {
this.tableIsLoading = true;
if (this.$route.query.folder_id !== undefined) {
this.queryServer({folder_id: this.$route.query.folder_id});
this.fetchFolderBreadcrumb(this.$route.query.folder_id);
return;
}
this.queryServer();
},
fetchFolderBreadcrumb(folderId) {
if (folderId === 0) {
this.folderBreadcrumb = [
{id: 0, name: 'Home'},
];
return;
}
axios.get(route('api.media.folders.breadcrumb', {folder: folderId}))
.then(response => {
this.folderBreadcrumb = response.data;
});
},
handleSizeChange(event) {
console.log('per page :' + event);
this.tableIsLoading = true;
this.queryServer({per_page: event});
},
handleCurrentChange(event) {
console.log('current page :' + event);
this.tableIsLoading = true;
this.queryServer({page: event});
},
handleSortChange(event) {
console.log('sorting', event);
this.tableIsLoading = true;
this.queryServer({order_by: event.prop, order: event.order,});
},
performSearch(query) {
console.log('searching:' + query);
this.tableIsLoading = true;
this.queryServer({search: query});
},
enterFolder(scope) {
this.tableIsLoading = true;
this.queryServer({folder_id: scope.row.id});
this.folderId = scope.row.id;
this.$router.push({ query: { folder_id: scope.row.id }});
this.fetchFolderBreadcrumb(scope.row.id);
},
insertMedia(scope) {
this.$events.emit(this.eventName, scope.row);
},
handleSelectionChange(selectedMedia) {
this.selectedMedia = selectedMedia;
},
loadEditForm(scope) {
console.log('clicked edit to' + scope.row.id);
this.$router.push({name: 'admin.media.media.edit', params: {mediaId: scope.row.id}})
},
showEditFolder(scope) {
this.$events.emit('editFolderWasClicked', scope);
},
changeRoot(folderId, index) {
this.tableIsLoading = true;
this.queryServer({folder_id: folderId});
this.folderId = folderId;
if (folderId === 0) {
this.$router.push({ query: {}});
} else {
this.$router.push({ query: { folder_id: folderId }});
}
this.fetchFolderBreadcrumb(folderId);
},
batchDelete() {
this.$confirm(this.trans('core.modal.confirmation-message'), this.trans('core.modal.title'), {
confirmButtonText: this.trans('core.button.delete'),
cancelButtonText: this.trans('core.button.cancel'),
type: 'warning'
})
.then(() => {
this.filesAreDeleting = true;
axios.post(route('api.media.media.batch-destroy'), {
files: this.selectedMedia
})
.then(response => {
this.$message({
type: 'success',
message: response.data.message
});
this.filesAreDeleting = false;
this.$refs.mediaTable.clearSelection();
this.queryServer();
});
})
.catch(() => {
this.$message({
type: 'info',
message: this.trans('core.delete cancelled')
});
});
},
},
mounted() {
this.selectedMedia.length = 0;
this.fetchMediaData();
this.$events.listen('fileWasUploaded', eventData => {
this.tableIsLoading = true;
this.queryServer({folder_id: eventData.data.folder_id});
});
this.$events.listen('folderWasCreated', eventData => {
this.tableIsLoading = true;
this.queryServer({folder_id: eventData.data.folder_id});
});
this.$events.listen('folderWasUpdated', eventData => {
this.tableIsLoading = true;
this.queryServer({folder_id: eventData.data.folder_id});
});
}
}
</script>
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
data() {
return {}
},
methods: {},
mounted() {}
}
</script>
<style>
.new-folder {
float: left;
margin-right: 10px;
}
</style>
<template>
<div>
<el-button type="success" class="new-folder" @click="dialogFormVisible = true">
<i class="el-icon-fa-plus"></i> New Folder
</el-button>
<el-dialog title="New Folder" :visible.sync="dialogFormVisible" size="tiny">
<el-form :model="folder" v-loading.body="loading" @submit.native.prevent="onSubmit()">
<el-form-item label="Folder name" :class="{'el-form-item is-error': form.errors.has('name') }">
<el-input v-model="folder.name" auto-complete="off" autofocus></el-input>
<div class="el-form-item__error" v-if="form.errors.has('name')"
v-text="form.errors.first('name')"></div>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeDialog">Cancel</el-button>
<el-button type="primary" @click="onSubmit()">Confirm</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Form from 'form-backend-validation'
export default {
props: {
parentId: {type: Number}
},
data() {
return {
dialogFormVisible: false,
folder: {
name: '',
},
form: new Form(),
loading: false,
}
},
methods: {
onSubmit() {
this.form = new Form(_.merge(this.folder, {parent_id: this.parentId}));
this.loading = true;
this.form.post(route('api.media.folders.store'))
.then(response => {
this.loading = false;
this.$message({
type: 'success',
message: response.message
});
this.dialogFormVisible = false;
this.folder.name = '';
this.$events.emit('folderWasCreated', response);
})
.catch(error => {
console.log(error);
this.loading = false;
this.$notify.error({
title: 'Error',
message: 'There are some errors in the form.'
});
});
},
closeDialog() {
this.form.clear();
this.dialogFormVisible = false;
},
},
mounted() {
}
}
</script>
<template>
<div>
<el-dialog title="Rename Folder" :visible.sync="dialogFormVisible" size="tiny">
<el-form :model="folder" v-loading.body="loading" @submit.native.prevent="onSubmit()">
<el-form-item label="Folder name" :class="{'el-form-item is-error': form.errors.has('name') }">
<el-input v-model="folder.name" auto-complete="off" autofocus></el-input>
<div class="el-form-item__error" v-if="form.errors.has('name')"
v-text="form.errors.first('name')"></div>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeDialog">Cancel</el-button>
<el-button type="primary" @click="onSubmit()">Confirm</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import Form from 'form-backend-validation'
export default {
// props: {
// currentFolder: {type: Object}
// },
data() {
return {
dialogFormVisible: false,
folder: {
name: '',
id: '',
parent_id: '',
},
form: new Form(),
loading: false,
}
},
methods: {
onSubmit() {
this.form = new Form(this.folder);
this.loading = true;
this.form.post(route('api.media.folders.update', {folder: this.folder.id}))
.then(response => {
this.loading = false;
this.$message({
type: 'success',
message: response.message
});
this.dialogFormVisible = false;
this.$events.emit('folderWasUpdated', response);
})
.catch(error => {
console.log(error);
this.loading = false;
this.$notify.error({
title: 'Error',
message: 'There are some errors in the form.'
});
});
},
closeDialog() {
this.form.clear();
this.dialogFormVisible = false;
},
},
mounted() {
this.$events.listen('editFolderWasClicked', eventData => {
this.folder.name = eventData.filename;
this.folder.id = eventData.id;
this.folder.parent_id = eventData.folder_id;
this.dialogFormVisible = true;
});
}
}
</script>
<template>
<div>
<label class="el-form-item__label">{{ getFieldLabel() }}</label>
<div class="jsThumbnailImageWrapper jsSingleThumbnailWrapper" v-if="hasSelectedMedia">
<figure>
<img :src="this.selectedMedia.medium_thumb" alt="" v-if="this.selectedMedia.is_image"/>
<i :class="`fa ${this.selectedMedia.fa_icon}`" style="font-size: 60px;" v-if="! this.selectedMedia.is_image"></i>
<span v-if="! this.selectedMedia.is_image" style="display:block;">{{ this.selectedMedia.filename }}</span>
</figure>
<div class="clearfix"></div>
<el-button type="button" @click="unSelectMedia">{{ trans('media.remove media') }}</el-button>
</div>
<div class="" v-else>
<el-button type="button" @click="dialogVisible = true">{{ trans('media.Browse') }}</el-button>
</div>
<el-dialog
:visible.sync="dialogVisible"
size="full"
:before-close="handleClose">
<media-list single-modal :event-name="this.eventName"></media-list>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">{{ trans('core.button.cancel') }}</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import UploadZone from './UploadZone.vue';
import MediaList from './MediaList.vue';
import StringHelpers from '../../../../Core/Assets/js/mixins/StringHelpers'
import axios from 'axios'
export default {
mixins: [StringHelpers],
props: {
zone: {type: String, required: true},
entity: {type: String, required: true},
entityId: {type: Number},
label: {type: String},
},
components: {
'upload-zone': UploadZone,
'media-list': MediaList,
},
watch: {
entityId() {
if (this.entityId) {
this.fetchMedia();
}
},
},
data() {
return {
dialogVisible: false,
selectedMedia: {},
eventName: '',
}
},
computed: {
hasSelectedMedia() {
return ! _.isEmpty(this.selectedMedia);
},
},
methods: {
handleClose(done) {
done();
},
unSelectMedia() {
this.selectedMedia = {};
this.$emit('singleFileSelected', _.merge({id: null}, {zone: this.zone}));
},
fetchMedia() {
axios.get(route('api.media.find-first-by-zone-and-entity', {
zone: this.zone,
entity: this.entity,
entity_id: this.entityId,
}))
.then(response => {
this.$emit('singleFileSelected', _.merge(response.data.data, {zone: this.zone}));
this.selectedMedia = response.data.data;
})
},
getFieldLabel() {
return this.label || this.ucwords(this.zone.replace('_', ' '));
},
makeId() {
let text = "";
let possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < 5; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
},
},
mounted() {
this.eventName = 'fileWasSelected' + this.makeId() + Math.floor(Math.random() * 999999);
this.$events.listen(this.eventName, mediaData => {
this.dialogVisible = false;
this.selectedMedia = mediaData;
this.$emit('singleFileSelected', _.merge(mediaData, {zone: this.zone}));
});
}
}
</script>
<style>
.el-upload__input {
display: none !important;
}
.el-upload--text {
display: block;
}
.el-upload-dragger {
width: 100%;
}
.media-upload {
margin-bottom: 10px;
}
</style>
<template>
<el-upload
class="upload-demo"
:action="uploadUrl"
:on-remove="handleRemove"
:on-success="handleSuccess"
:show-file-list="false"
:http-request="uploadFile"
:multiple="true"
style="display: inline-block; margin-right: 10px;">
<el-button size="small" type="primary" style="padding: 11px 9px;" :loading="fileIsUploading">{{ trans('media.upload file') }}</el-button>
</el-upload>
</template>
<script>
import axios from 'axios'
export default {
props: {
parentId: {type: Number}
},
data() {
return {
fileIsUploading: false,
}
},
computed: {
uploadUrl() {
return route('api.media.store').domain + route('api.media.store').url;
},
requestHeaders() {
let userApiToken = document.head.querySelector('meta[name="user-api-token"]');
return {
'Authorization': 'Bearer ' + userApiToken.content
};
},
},
methods: {
handleSuccess(response, file, fileList) {
this.$events.emit('fileWasUploaded', response);
},
uploadFile(event) {
this.fileIsUploading = true;
let data = new FormData();
data.append('parent_id', this.parentId);
data.append('file', event.file);
axios.post(route('api.media.store'), data)
.then(response => {
this.$events.emit('fileWasUploaded', response);
this.fileIsUploading = false;
})
.catch(error => {
console.log(error.response.data);
this.fileIsUploading = false;
this.$notify.error({
title: 'Error',
message: error.response.data.errors.file[0]
});
});
},
handleRemove() {},
},
mounted() {
}
}
</script>
<style>
.el-upload__input {
display: none !important;
}
.el-upload--text {
display: block;
}
.el-upload-dragger {
width: 100%;
}
.media-upload {
margin-bottom: 10px;
}
</style>
<template>
<div class="row">
<div class="col-xs-12">
<el-upload
class="media-upload"
drag
:action="uploadUrl"
:on-preview="handlePreview"
:on-remove="handleRemove"
:on-success="handleSuccess"
:file-list="fileList"
:headers="requestHeaders"
multiple>
<i class="el-icon-upload"></i>
<div class="el-upload__text">Drop file here or <em>click to upload</em></div>
</el-upload>
</div>
</div>
</template>
<script>
export default {
data() {
return {
fileList: [],
}
},
computed: {
uploadUrl() {
return route('api.media.store').domain + route('api.media.store').url;
},
requestHeaders() {
let userApiToken = document.head.querySelector('meta[name="user-api-token"]');
return {
'Authorization': 'Bearer ' + userApiToken.content
};
},
},
methods: {
handleSuccess(response, file, fileList) {
this.$events.emit('fileWasUploaded', response);
this.fileList = [];
},
handlePreview() {},
handleRemove() {},
},
mounted() {}
}
</script>
export default {
methods: {
selectSingleFile(event, model) {
this[model].medias_single = _.merge(this[model].medias_single, {
[event.zone]: event.id,
});
},
}
}
......@@ -2,24 +2,19 @@ import PageTable from './components/PageTable.vue'
import PageTableServerSide from './components/PageTableServerSide.vue'
import PageForm from './components/PageForm.vue'
const translations = window.translations;
const locales = window.locales;
const locales = window.AsgardCMS.locales;
export default [
{
path: '/page/pages',
name: 'admin.page.page.index',
component: PageTableServerSide,
props: {
translations,
}
},
{
path: '/page/pages/create',
name: 'admin.page.page.create',
component: PageForm,
props: {
translations,
locales,
pageTitle: 'create page',
}
......@@ -29,7 +24,6 @@ export default [
name: 'admin.page.page.edit',
component: PageForm,
props: {
translations,
locales,
pageTitle: 'edit page',
}
......
......@@ -2,15 +2,15 @@
<div class="div">
<div class="content-header">
<h1>
{{ translate('page', pageTitle) }}
{{ trans(`page.${pageTitle}`) }}
</h1>
<el-breadcrumb separator="/">
<el-breadcrumb-item>
<a href="/backend">Home</a>
</el-breadcrumb-item>
<el-breadcrumb-item :to="{name: 'admin.page.page.index'}">{{ translate('page', 'pages') }}
<el-breadcrumb-item :to="{name: 'admin.page.page.index'}">{{ trans('page.pages') }}
</el-breadcrumb-item>
<el-breadcrumb-item :to="{name: 'admin.page.page.create'}">{{ translate('page', pageTitle) }}
<el-breadcrumb-item :to="{name: 'admin.page.page.create'}">{{ trans(`page.${pageTitle}`) }}
</el-breadcrumb-item>
</el-breadcrumb>
</div>
......@@ -22,19 +22,19 @@
<div class="col-md-10">
<div class="box box-primary">
<div class="box-body">
<el-tabs type="card">
<el-tabs type="card" v-model="activeTab">
<el-tab-pane :label="localeArray.name" v-for="(localeArray, locale) in locales"
:key="localeArray.name">
:key="localeArray.name" :name="locale">
<span slot="label" :class="{'error' : form.errors.has(locale)}">{{ localeArray.name
}}</span>
<el-form-item :label="translate('page', 'title')"
<el-form-item :label="trans('page.title')"
:class="{'el-form-item is-error': form.errors.has(locale + '.title') }">
<el-input v-model="page[locale].title"></el-input>
<div class="el-form-item__error" v-if="form.errors.has(locale + '.title')"
v-text="form.errors.first(locale + '.title')"></div>
</el-form-item>
<el-form-item :label="translate('page', 'slug')"
<el-form-item :label="trans('page.slug')"
:class="{'el-form-item is-error': form.errors.has(locale + '.slug') }">
<el-input v-model="page[locale].slug">
<el-button slot="prepend" @click="generateSlug($event, locale)">Generate</el-button>
......@@ -43,10 +43,11 @@
v-text="form.errors.first(locale + '.slug')"></div>
</el-form-item>
<el-form-item :label="translate('page', 'body')"
<el-form-item :label="trans('page.body')"
:class="{'el-form-item is-error': form.errors.has(locale + '.body') }">
<ckeditor v-model="page[locale].body" :value="page[locale].body">
</ckeditor>
<component :is="getCurrentEditor()" v-model="page[locale].body" :value="page[locale].body">
</component>
<div class="el-form-item__error" v-if="form.errors.has(locale + '.body')"
v-text="form.errors.first(locale + '.body')"></div>
</el-form-item>
......@@ -56,17 +57,17 @@
<h4 class="box-title">
<a class="collapsed" data-toggle="collapse" data-parent="#accordion"
:href="`#collapseMeta-${locale}`">
{{ translate('page', 'meta_data') }}
{{ trans('page.meta_data') }}
</a>
</h4>
</div>
<div style="height: 0px;" :id="`collapseMeta-${locale}`"
class="panel-collapse collapse">
<div class="box-body">
<el-form-item :label="translate('page', 'meta_title')">
<el-form-item :label="trans('page.meta_title')">
<el-input v-model="page[locale].meta_title"></el-input>
</el-form-item>
<el-form-item :label="translate('page', 'meta_description')">
<el-form-item :label="trans('page.meta_description')">
<el-input type="textarea"
v-model="page[locale].meta_description"></el-input>
</el-form-item>
......@@ -79,28 +80,28 @@
<h4 class="box-title">
<a class="collapsed" data-toggle="collapse" data-parent="#accordion"
:href="`#collapseFacebook-${locale}`">
{{ translate('page', 'facebook_data') }}
{{ trans('page.facebook_data') }}
</a>
</h4>
</div>
<div style="height: 0px;" :id="`collapseFacebook-${locale}`"
class="panel-collapse collapse">
<div class="box-body">
<el-form-item :label="translate('page', 'og_title')">
<el-form-item :label="trans('page.og_title')">
<el-input v-model="page[locale].og_title"></el-input>
</el-form-item>
<el-form-item :label="translate('page', 'og_description')">
<el-form-item :label="trans('page.og_description')">
<el-input type="textarea"
v-model="page[locale].og_description"></el-input>
</el-form-item>
<el-form-item :label="translate('page', 'og_type')">
<el-form-item :label="trans('page.og_type')">
<el-select v-model="page[locale].og_type"
:placeholder="translate('page', 'og_type')">
<el-option :label="translate('page', 'facebook-types.website')"
:placeholder="trans('page.og_type')">
<el-option :label="trans('page.facebook-types.website')"
value="website"></el-option>
<el-option :label="translate('page', 'facebook-types.product')"
<el-option :label="trans('page.facebook-types.product')"
value="product"></el-option>
<el-option :label="translate('page', 'facebook-types.article')"
<el-option :label="trans('page.facebook-types.article')"
value="article"></el-option>
</el-select>
</el-form-item>
......@@ -110,9 +111,9 @@
<el-form-item>
<el-button type="primary" @click="onSubmit()" :loading="loading">
{{ translate('core', 'save') }}
{{ trans('core.save') }}
</el-button>
<el-button @click="onCancel()">{{ translate('core', 'button.cancel') }}
<el-button @click="onCancel()">{{ trans('core.button.cancel') }}
</el-button>
</el-form-item>
......@@ -126,9 +127,9 @@
<div class="box-body">
<el-form-item label="">
<el-checkbox v-model="page.is_home" :true-label="1" :false-label="0" name="is_home"
:label="translate('page', 'is homepage')"></el-checkbox>
:label="trans('page.is homepage')"></el-checkbox>
</el-form-item>
<el-form-item :label="translate('page', 'template')"
<el-form-item :label="trans('page.template')"
:class="{'el-form-item is-error': form.errors.has('template') }">
<el-select v-model="page.template" filterable>
<el-option v-for="(template, key) in templates" :key="template"
......@@ -137,23 +138,30 @@
<div class="el-form-item__error" v-if="form.errors.has('template')"
v-text="form.errors.first('template')"></div>
</el-form-item>
<tags-input namespace="asgardcms/page" @input="setTags" :current-tags="tags"></tags-input>
<tags-input namespace="asgardcms/page" v-model="tags" :value="tags" :current-tags="tags"></tags-input>
<single-media zone="image" @singleFileSelected="selectSingleFile($event, 'page')"
entity="Modules\Page\Entities\Page" :entity-id="page.id"></single-media>
</div>
</div>
</div>
</div>
</el-form>
<button v-shortkey="['b']" @shortkey="pushRoute({name: 'admin.page.page.index'})" v-show="false"></button>
</div>
</template>
<script>
import axios from 'axios'
import Translate from '../../../../Core/Assets/js/mixins/Translate'
import Slugify from '../../../../Core/Assets/js/mixins/Slugify'
import ShortcutHelper from '../../../../Core/Assets/js/mixins/ShortcutHelper'
import ActiveEditor from '../../../../Core/Assets/js/mixins/ActiveEditor'
import SingleFileSelector from '../../../../Media/Assets/js/mixins/SingleFileSelector'
import Form from 'form-backend-validation'
export default {
mixins: [Translate, Slugify],
mixins: [Slugify, ShortcutHelper, ActiveEditor, SingleFileSelector],
props: {
locales: {default: null},
pageTitle: {default: null, String},
......@@ -173,7 +181,7 @@
og_type: '',
}])
.fromPairs()
.merge({template: 'default', is_home: 0})
.merge({template: 'default', is_home: 0, medias_single: []})
.value(),
templates: {
......@@ -184,6 +192,7 @@
form: new Form(),
loading: false,
tags: {},
activeTab: window.AsgardCMS.currentLocale || 'en',
}
},
methods: {
......@@ -221,9 +230,6 @@
generateSlug(event, locale) {
this.page[locale].slug = this.slugify(this.page[locale].title);
},
setTags(tags) {
this.tags = tags;
},
fetchPage() {
this.loading = true;
axios.post(route('api.page.page.find', {page: this.$route.params.pageId}))
......@@ -231,6 +237,7 @@
this.loading = false;
this.page = response.data.data;
this.tags = response.data.data.tags;
$('.publicUrl').attr('href', this.page.urls.public_url).show();
})
.catch(error => {
})
......@@ -248,6 +255,9 @@
if (this.$route.params.pageId !== undefined) {
this.fetchPage();
}
},
destroyed() {
$('.publicUrl').hide();
}
}
</script>
......@@ -6,7 +6,7 @@
<data-tables :data="data" :actions-def="actionsDef">
<el-table-column prop="id" label="Id" width="100">
</el-table-column>
<el-table-column prop="title" :label="translate('page', 'title')">
<el-table-column prop="title" :label="trans('page.title')">
</el-table-column>
<el-table-column prop="slug" label="Slug">
</el-table-column>
......@@ -30,12 +30,10 @@
<script>
import axios from 'axios'
import Translate from '../../../../Core/Assets/js/mixins/Translate'
let data;
export default {
mixins: [Translate],
data() {
return {
data,
......@@ -44,7 +42,7 @@
links: {},
actionsDef: {
def: [{
name: this.translate('page', 'create page'),
name: this.trans('page.create-page'),
icon: 'edit',
handler: () => {
this.$router.push({name: 'admin.page.page.create'})
......
......@@ -2,13 +2,13 @@
<div class="div">
<div class="content-header">
<h1>
{{ translate('page', 'pages') }}
{{ trans('page.pages') }}
</h1>
<el-breadcrumb separator="/">
<el-breadcrumb-item>
<a href="/backend">Home</a>
</el-breadcrumb-item>
<el-breadcrumb-item :to="{name: 'admin.page.page.index'}">{{ translate('page', 'pages') }}</el-breadcrumb-item>
<el-breadcrumb-item :to="{name: 'admin.page.page.index'}">{{ trans('page.pages') }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
......@@ -18,10 +18,19 @@
<div class="box-body">
<div class="sc-table">
<div class="tool-bar el-row" style="padding-bottom: 20px;">
<div class="actions el-col el-col-5">
<div class="actions el-col el-col-8">
<el-dropdown @command="handleExtraActions" v-if="showExtraButtons">
<el-button type="primary">
{{ trans('core.table.actions') }}<i class="el-icon-caret-bottom el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="mark-online">{{ trans('core.mark as online') }}</el-dropdown-item>
<el-dropdown-item command="mark-offline">{{ trans('core.mark as offline') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<router-link :to="{name: 'admin.page.page.create'}">
<el-button type="primary"><i class="el-icon-edit"></i>
{{ translate('page', 'create page') }}
{{ trans('page.create page') }}
</el-button>
</router-link>
</div>
......@@ -35,22 +44,33 @@
:data="data"
stripe
style="width: 100%"
ref="pageTable"
v-loading.body="tableIsLoading"
@sort-change="handleSortChange">
@sort-change="handleSortChange"
@selection-change="handleSelectionChange">
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column :label="trans('page.status')" width="75">
<template scope="scope">
<i class="el-icon-fa-circle" :class="(scope.row.translations.status === true) ? 'text-success':'text-danger'"></i>
</template>
</el-table-column>
<el-table-column prop="id" label="Id" width="100" sortable="custom">
</el-table-column>
<el-table-column prop="translations.title" :label="translate('page', 'title')">
<el-table-column prop="translations.title" :label="trans('page.title')">
</el-table-column>
<el-table-column prop="translations.slug" label="Slug">
<el-table-column prop="translations.slug" :label="trans('page.slug')">
</el-table-column>
<el-table-column prop="created_at" label="Created at" sortable="custom">
<el-table-column prop="created_at" :label="trans('core.table.created at')" sortable="custom">
</el-table-column>
<el-table-column fixed="right" prop="actions" label="Actions">
<el-table-column fixed="right" prop="actions" :label="trans('core.table.actions')">
<template scope="scope">
<a class="btn btn-default btn-flat" @click.prevent="goToEdit(scope)"><i
class="fa fa-pencil"></i></a>
<delete-button :scope="scope" :rows="data" :translations="translations">
<delete-button :scope="scope" :rows="data">
</delete-button>
</template>
</el-table-column>
......@@ -71,107 +91,116 @@
</div>
</div>
</div>
<button v-shortkey="['c']" @shortkey="pushRoute({name: 'admin.page.page.create'})" v-show="false"></button>
</div>
</template>
<script>
import axios from 'axios'
import Translate from '../../../../Core/Assets/js/mixins/Translate'
import _ from "lodash";
import ShortcutHelper from '../../../../Core/Assets/js/mixins/ShortcutHelper'
let data;
export default {
mixins: [Translate],
mixins: [ShortcutHelper],
data() {
return {
data,
meta: {},
order_meta: {},
meta: {
current_page: 1,
per_page: 10,
},
order_meta: {
order_by: '',
order: '',
},
links: {},
searchQuery: '',
tableIsLoading: false,
showExtraButtons: false,
selectedPages: {},
}
},
watch: {
selectedPages() {
this.selectedPages.length >= 1 ? this.showExtraButtons = true : this.showExtraButtons = false;
}
},
methods: {
fetchData() {
this.tableIsLoading = true;
axios.get(route('api.page.page.indexServerSide'))
queryServer(customProperties) {
let properties = {
page: this.meta.current_page,
per_page: this.meta.per_page,
order_by: this.order_meta.order_by,
order: this.order_meta.order,
search: this.searchQuery,
};
axios.get(route('api.page.page.indexServerSide', _.merge(properties, customProperties)))
.then(response => {
this.tableIsLoading = false;
this.data = response.data.data;
this.meta = response.data.meta;
this.links = response.data.links;
this.order_meta.order_by = properties.order_by;
this.order_meta.order = properties.order;
});
},
fetchData() {
this.tableIsLoading = true;
this.queryServer();
},
goToEdit(scope) {
this.$router.push({name: 'admin.page.page.edit', params: {pageId: scope.row.id}})
},
handleSizeChange(event) {
console.log('per page :' + event);
this.tableIsLoading = true;
axios.get(route('api.page.page.indexServerSide', {
per_page: event,
page: this.meta.current_page,
order_by: this.order_meta.order_by,
order: this.order_meta.order,
}))
.then(response => {
this.tableIsLoading = false;
this.data = response.data.data;
this.meta = response.data.meta;
this.links = response.data.links;
});
this.queryServer({per_page: event});
},
handleCurrentChange(event) {
console.log('current page :' + event);
this.tableIsLoading = true;
axios.get(route('api.page.page.indexServerSide', {
page: event,
per_page: this.meta.per_page,
order_by: this.order_meta.order_by,
order: this.order_meta.order,
search: this.searchQuery,
}))
.then(response => {
this.tableIsLoading = false;
this.data = response.data.data;
this.meta = response.data.meta;
this.links = response.data.links;
});
this.queryServer({page: event});
},
handleSortChange(event) {
console.log('sorting', event);
this.tableIsLoading = true;
axios.get(route('api.page.page.indexServerSide', {
page: this.meta.current_page,
per_page: this.meta.per_page,
order_by: event.prop,
order: event.order,
search: this.searchQuery,
}))
.then(response => {
this.tableIsLoading = false;
this.data = response.data.data;
this.meta = response.data.meta;
this.links = response.data.links;
this.order_meta.order_by = event.prop;
this.order_meta.order = event.order;
});
this.queryServer({order_by: event.prop, order: event.order,});
},
performSearch(query) {
console.log('searching:' + query);
this.tableIsLoading = true;
axios.get(route('api.page.page.indexServerSide', {
search: query,
}))
this.queryServer({search: query});
},
handleExtraActions(action) {
let pageIds = _.map(this.selectedPages, function(elem) {
return elem.id;
});
axios.get(route('api.page.page.mark-status', {action: action, pageIds: JSON.stringify(pageIds)}))
.then(response => {
this.tableIsLoading = false;
this.data = response.data.data;
this.meta = response.data.meta;
this.links = response.data.links;
});
this.$message({
type: 'success',
message: response.data.message
});
this.$refs.pageTable.clearSelection();
this.data.find(function (page) {
if (pageIds.indexOf(page.id) >= 0) {
page.translations.status = action === 'mark-online';
}
});
})
.catch(error => {
this.$message({
type: 'error',
message: this.trans('core.something went wrong'),
});
})
},
handleSelectionChange(selectedPages) {
this.selectedPages = selectedPages;
},
},
mounted() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment