Merge branch 'develop' of github.com:tainacan/tainacan into develop

This commit is contained in:
Jacson Passold 2018-04-26 14:35:02 -03:00
commit 080dd68272
44 changed files with 5180 additions and 5066 deletions

6697
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,20 +9,20 @@
"dependencies": {
"axios": "^0.18.0",
"buefy": "^0.6.5",
"bulma": "^0.6.2",
"bulma": "^0.7.1",
"html-to-json": "^0.6.0",
"mdi": "^2.2.43",
"qs": "^6.5.1",
"moment": "^2.22.0",
"moment": "^2.22.1",
"node-sass": "^4.8.3",
"sass-loader": "^6.0.7",
"qs": "^6.5.1",
"sass-loader": "^7.0.1",
"vue": "^2.5.16",
"vue-router": "^3.0.1",
"vuedraggable": "^2.16.0",
"vuex": "^3.0.1"
},
"devDependencies": {
"autoprefixer": "^8.2.0",
"autoprefixer": "^8.3.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"babel-preset-env": "^1.6.1",
@ -31,20 +31,20 @@
"cross-env": "^5.1.4",
"css-loader": "^0.28.11",
"cypress": "^2.1.0",
"element-theme-chalk": "^2.3.2",
"element-theme-chalk": "^2.3.6",
"eslint": "^4.19.1",
"eslint-loader": "^2.0.0",
"eslint-plugin-vue": "^4.4.0",
"eslint-plugin-vue": "^4.5.0",
"file-loader": "^1.1.11",
"postcss-loader": "^2.1.3",
"postcss-loader": "^2.1.4",
"sass-resources-loader": "^1.3.3",
"style-loader": "^0.20.3",
"uglifyjs-webpack-plugin": "^1.2.4",
"vue-custom-element": "^2.1.0",
"style-loader": "^0.21.0",
"uglifyjs-webpack-plugin": "^1.2.5",
"vue-custom-element": "^3.0.4",
"vue-loader": "^14.2.2",
"vue-template-compiler": "^2.5.16",
"webpack": "^4.4.1",
"webpack-cli": "^2.0.13",
"webpack-dev-server": "^3.1.1"
"webpack": "^4.6.0",
"webpack-cli": "^2.0.15",
"webpack-dev-server": "^3.1.3"
}
}

View File

@ -57,55 +57,52 @@ class Admin {
wp_enqueue_style( 'tainacan-admin-page', $TAINACAN_BASE_URL . '/assets/css/tainacan-admin.css' );
$undesired_wp_styles = [
//'admin-menu',
//'admin-bar',
//'code-editor',
//'color-picker',
//'customize-controls',
//'customize-nav-menus',
//'customize-widgets',
//'dashboard',
//'dashicons',
//'deprecated-media',
//'edit',
//'wp-pointer',
//'farbtastic',
//'forms',
//'common',
//'install',
//'wp-auth-check',
//'site-icon',
//'buttons',
//'l10n',
//'list-tables',
//'login',
//'media',
//'nav-menus',
//'revisions',
//'themes',
//'widgets',
//'wp-admin'
'admin-menu',
'admin-bar',
'code-editor',
'color-picker',
'customize-controls',
'customize-nav-menus',
'customize-widgets',
'dashboard',
'dashicons',
'deprecated-media',
'edit',
'wp-pointer',
'farbtastic',
'forms',
'common',
'install',
'wp-auth-check',
'site-icon',
'buttons',
'l10n',
'list-tables',
'login',
'media',
'nav-menus',
'revisions',
'themes',
'widgets',
'wp-admin'
];
wp_dequeue_style( $undesired_wp_styles );
wp_deregister_style( $undesired_wp_styles );
}
function add_admin_js() {
global $TAINACAN_BASE_URL;
wp_enqueue_media();
wp_enqueue_script('jcrop');
wp_enqueue_script( 'tainacan-user-admin', $TAINACAN_BASE_URL . '/assets/user_admin-components.js', [], null, true );
$settings = $this->get_admin_js_localization_params();
wp_localize_script( 'tainacan-user-admin', 'tainacan_plugin', $settings );
wp_enqueue_media();
wp_enqueue_script('undescore', includes_url('js') . '/underscore.min.js' );
wp_enqueue_script('jcrop');
}
@ -201,7 +198,6 @@ class Admin {
// TODO move it to a separate file and start the Vue project
echo "<div id='tainacan-admin-app'></div>";
}
function register_user_meta() {

View File

@ -10,261 +10,273 @@
v-if="collection != null && collection != undefined"
class="tainacan-form"
label-width="120px">
<!-- Name -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_name')"
:type="editFormErrors['name'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['name'] != undefined ? editFormErrors['name'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'name')"
:message="$i18n.getHelperMessage('collections', 'name')"/>
<b-input
id="tainacan-text-name"
v-model="form.name"
@focus="clearErrors('name')"/>
</b-field>
<!-- Thumbnail -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_image')">
<div class="thumbnail-field">
<b-upload
v-if="collection.featured_image == undefined || collection.featured_image == false"
v-model="thumbnail"
drag-drop
@input="uploadThumbnail($event)">
<div class="content has-text-centered">
<p>
<b-icon
icon="upload"/>
</p>
<p>{{ $i18n.get('instruction_image_upload_box') }}</p>
</div>
</b-upload>
<div v-else>
<figure class="image is-128x128">
<img
:alt="$i18n.get('label_thumbnail')"
:src="collection.featured_image">
</figure>
<div class="thumbnail-buttons-row">
<b-upload
v-model="thumbnail"
@input="uploadThumbnail($event)">
<a
id="button-edit"
:aria-label="$i18n.get('label_button_edit_thumb')"><b-icon icon="pencil"/></a>
</b-upload>
<div class="columns is-variable is-8">
<div class="column is-narrow">
<!-- Thumbnail -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_thumbnail')">
<div class="thumbnail-field">
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteThumbnail()"><b-icon icon="delete"/></a>
</div>
</div>
</div>
</b-field>
<button
id="frame-uploader"
class="buttton"
@click="openFrameUploader($event)">Enviar</button>
<!-- Your image container, which can be manipulated with js -->
<div class="custom-img-container">
<img
v-if="you_have_img"
:src="your_img_src"
alt=""
style="max-width:100%;">
</div>
<!-- Your add & remove image links -->
<p class="hide-if-no-js">
<a
class="upload-custom-img"
:class="{ 'hidden': you_have_img, 'hidden' : !you_have_img}"
:href="upload_link">
Set custom image
</a>
<a
class="delete-custom-img"
:class="{'hidden' : !you_have_img, 'visible' : you_have_img }"
href="#">
Remove this image
</a>
</p>
<!-- A hidden input to set and post the chosen image id -->
<input
class="custom-img-id"
name="custom-img-id"
type="hidden"
:value="your_img_id">
<!-- Cover Image-------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_cover_image')">
<div class="thumbnail-field">
<b-upload
v-if="collection.cover_image == undefined || collection.cover_image == false"
v-model="cover"
drag-drop
@input="uploadCover($event)">
<div class="content has-text-centered">
<p>
<b-icon
icon="upload"/>
</p>
<p>{{ $i18n.get('instruction_image_upload_box') }}</p>
</div>
</b-upload>
<div v-else>
<figure class="image is-128x128">
<img
:alt="$i18n.get('label_cover_image')"
:src="collection.cover_image">
</figure>
<div class="thumbnail-buttons-row">
<b-upload
v-model="cover"
@input="uploadCover($event)">
class="button is-rounred is-secondary"
id="button-edit-thumbnail"
:aria-label="$i18n.get('label_button_edit_thumb')"
@click="editImage($event, true)">
<b-icon icon="pencil" />
</a>
<figure class="image is-128x128">
<span
v-if="collection.featured_image == undefined || collection.featured_image == false"
class="image-placeholder">{{ $i18n.get('label_empty_thumbnail') }}</span>
<img
:alt="$i18n.get('label_thumbnail')"
:src="(collection.featured_image == undefined || collection.featured_image == false) ? thumbPlaceholderPath : collection.featured_image">
</figure>
<div class="thumbnail-buttons-row">
<a
id="button-edit"
:aria-label="$i18n.get('label_button_edit_thumb')"><b-icon icon="pencil"/></a>
</b-upload>
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteThumbnail()"><b-icon icon="delete"/></a>
id="button-delete"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteThumbnail()">
<b-icon icon="delete" />
</a>
</div>
</div>
</div>
</b-field>
<!-- Header Page -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_header_image')">
<div class="thumbnail-field">
<a
class="button is-rounred is-secondary"
id="button-edit-header-image"
:aria-label="$i18n.get('label_button_edit_header_image')"
@click="editImage($event, false)">
<b-icon icon="pencil" />
</a>
<figure class="image is-128x128">
<span
v-if="collection.header_image == undefined || collection.header_image == false"
class="image-placeholder">{{ $i18n.get('label_empty_header_image') }}</span>
<img
:alt="$i18n.get('label_thumbnail')"
:src="(collection.header_image == undefined || collection.header_image == false) ? headerPlaceholderPath : collection.header_image">
</figure>
<div class="thumbnail-buttons-row">
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteHeaderImage()">
<b-icon icon="delete" />
</a>
</div>
</div>
</b-field>
</div>
</b-field>
<!-- Description -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_description')"
:type="editFormErrors['description'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['description'] != undefined ? editFormErrors['description'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'description')"
:message="$i18n.getHelperMessage('collections', 'description')"/>
<b-input
id="tainacan-text-description"
type="textarea"
v-model="form.description"
@focus="clearErrors('description')"/>
</b-field>
<div class="column">
<!-- Name -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_name')"
:type="editFormErrors['name'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['name'] != undefined ? editFormErrors['name'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'name')"
:message="$i18n.getHelperMessage('collections', 'name')"/>
<b-input
id="tainacan-text-name"
v-model="form.name"
@focus="clearErrors('name')"/>
</b-field>
<!-- Description -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_description')"
:type="editFormErrors['description'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['description'] != undefined ? editFormErrors['description'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'description')"
:message="$i18n.getHelperMessage('collections', 'description')"/>
<b-input
id="tainacan-text-description"
type="textarea"
v-model="form.description"
@focus="clearErrors('description')"/>
</b-field>
<!-- Status -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_status')"
:type="editFormErrors['status'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['status'] != undefined ? editFormErrors['status'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'status')"
:message="$i18n.getHelperMessage('collections', 'status')"/>
<b-select
id="tainacan-select-status"
v-model="form.status"
@focus="clearErrors('status')"
:placeholder="$i18n.get('instruction_select_a_status')">
<option
v-for="statusOption in statusOptions"
:key="statusOption.value"
:value="statusOption.value"
:disabled="statusOption.disabled">{{ statusOption.label }}
</option>
</b-select>
</b-field>
<!-- Status -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_status')"
:type="editFormErrors['status'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['status'] != undefined ? editFormErrors['status'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'status')"
:message="$i18n.getHelperMessage('collections', 'status')"/>
<b-select
id="tainacan-select-status"
v-model="form.status"
@focus="clearErrors('status')"
:placeholder="$i18n.get('instruction_select_a_status')">
<option
v-for="statusOption in statusOptions"
:key="statusOption.value"
:value="statusOption.value"
:disabled="statusOption.disabled">{{ statusOption.label }}
</option>
</b-select>
</b-field>
<!-- Enable Cover Page -------------------------------- -->
<div class="field">
<b-checkbox
id="tainacan-checkbox-cover-page"
size="is-small"
true-value="yes"
false-value="no"
v-model="form.enable_cover_page">
{{ $i18n.get('label_enable_cover_page') }}
</b-checkbox>
<help-button
:title="$i18n.getHelperTitle('collections', 'enable_cover_page')"
:message="$i18n.getHelperMessage('collections', 'enable_cover_page')"/>
</div>
<!-- Enable Cover Page -------------------------------- -->
<div class="field">
<b-checkbox
id="tainacan-checkbox-cover-page"
size="is-small"
true-value="yes"
false-value="no"
v-model="form.enable_cover_page">
{{ $i18n.get('label_enable_cover_page') }}
</b-checkbox>
<help-button
:title="$i18n.getHelperTitle('collections', 'enable_cover_page')"
:message="$i18n.getHelperMessage('collections', 'enable_cover_page')"/>
</div>
<!-- Cover Page -------------------------------- -->
<b-field
v-show="form.enable_cover_page == 'yes'"
:addons="false"
:label="$i18n.get('label_cover_page')"
:type="editFormErrors['cover_page_id'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['cover_page_id'] != undefined ? editFormErrors['cover_page_id'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'cover_page_id')"
:message="$i18n.getHelperMessage('collections', 'cover_page_id')"/>
<b-autocomplete
id="tainacan-text-cover-page"
:data="coverPages"
v-model="coverPageTitle"
@select="onSelectCoverPage($event)"
:loading="isFetchingPages"
@input="fecthCoverPages()"
@focus="clearErrors('cover_page_id')">
<template slot-scope="props">
{{ props.option.title.rendered }}
</template>
<template slot="empty">No esults found</template>
</b-autocomplete>
<br>
<b-field
id="tainacan-cover-page"
v-if="coverPage != undefined && coverPage.title != undefined">
<div class="control">
<b-taglist attached>
<b-tag
size="is-medium"
type="is-primary"
v-html="coverPage.title.rendered" />
<b-tag
size="is-medium"
type="is-tertiary"
@close="removeCoverPage()"
closable>
<!-- Cover Page -------------------------------- -->
<b-field
v-show="form.enable_cover_page == 'yes'"
:addons="false"
:label="$i18n.get('label_cover_page')"
:type="editFormErrors['cover_page_id'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['cover_page_id'] != undefined ? editFormErrors['cover_page_id'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'cover_page_id')"
:message="$i18n.getHelperMessage('collections', 'cover_page_id')"/>
<b-autocomplete
id="tainacan-text-cover-page"
:placeholder="$i18n.get('instruction_cover_page')"
:data="coverPages"
v-model="coverPageTitle"
@select="onSelectCoverPage($event)"
:loading="isFetchingPages"
@input="fecthCoverPages($event)"
@focus="clearErrors('cover_page_id')"
v-if="coverPage == undefined || coverPage.title == undefined">
<template slot-scope="props">
{{ props.option.title.rendered }}
</template>
<template slot="empty">{{ $i18n.get('info_no_page_found') }}</template>
</b-autocomplete>
<div
v-if="coverPage != undefined && coverPage.title != undefined"
class="control selected-cover-page">
<span v-html="coverPage.title.rendered" />
<span class="selected-cover-page-control">
<a
target="blank"
:href="coverPageEditPath">Edit</a>
:href="coverPageEditPath">{{ $i18n.get('edit') }}</a>
&nbsp;&nbsp;
<a
target="_blank"
:href="coverPage.link">View</a></b-tag>
</b-taglist>
</div>
</b-field>
</b-field>
:href="coverPage.link">{{ $i18n.get('see') }}</a>
&nbsp;&nbsp;
<button
class="button is-secondary is-small"
@click.prevent="removeCoverPage()">{{ $i18n.get('remove') }}</button>
</span>
</div>
</b-field>
<!-- Slug -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_slug')"
:type="editFormErrors['slug'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['slug'] != undefined ? editFormErrors['slug'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'slug')"
:message="$i18n.getHelperMessage('collections', 'slug')"/>
<b-input
id="tainacan-text-slug"
v-model="form.slug"
@focus="clearErrors('slug')"/>
</b-field>
<!-- Moderators List -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_moderators')"
:type="editFormErrors['moderators'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['moderators'] != undefined ? editFormErrors['moderators'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'moderators_ids')"
:message="$i18n.getHelperMessage('collections', 'moderators_ids')"/>
<b-autocomplete
id="tainacan-text-moderators-input"
:placeholder="$i18n.get('instruction_moderators')"
:data="users"
@select="onAddModerator($event)"
:loading="isFetchingModerators"
@input="fecthModerators($event)"
@focus="clearErrors('moderators')">
<template slot-scope="props">
{{ props.option.name }}
</template>
<template slot="empty">{{ $i18n.get('info_no_user_found') }}</template>
</b-autocomplete>
<ul
class="moderators-list"
v-if="moderators != undefined && moderators.length > 0">
<li
:key="index"
v-for="(moderator, index) of moderators">
<b-tag
attached
closable
@close="removeModerator(index)">
{{ moderator.name }}
</b-tag>
</li>
</ul>
<div
class="moderators-empty-list"
v-else>
{{ $i18n.get('info_no_moderator_on_collection') }}
</div>
</b-field>
<!-- Slug -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_slug')"
:type="editFormErrors['slug'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['slug'] != undefined ? editFormErrors['slug'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'slug')"
:message="$i18n.getHelperMessage('collections', 'slug')"/>
<b-input
id="tainacan-text-slug"
v-model="form.slug"
@focus="clearErrors('slug')"/>
</b-field>
<!-- Parent Collection -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_parent_collection')"
:type="editFormErrors['parent'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['parent'] != undefined ? editFormErrors['parent'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'parent')"
:message="$i18n.getHelperMessage('collections', 'parent')"/>
<b-select
id="tainacan-select-parent"
v-model="form.parent"
@focus="clearErrors('parent')"
:loading="isFetchingCollections"
:placeholder="$i18n.get('instruction_select_a_parent_collection')">
<option value="0">{{ $i18n.get('label_no_parent_collection') }}</option>
<option
v-if="collection.id != anotherCollection.id"
v-for="anotherCollection of collections"
:key="anotherCollection.id"
:value="anotherCollection.id">{{ anotherCollection.name }}
</option>
</b-select>
</b-field>
</div>
</div>
<!-- Form submit -------------------------------- -->
<div class="field is-grouped form-submit">
@ -308,8 +320,9 @@ export default {
slug: '',
enable_cover_page: '',
featured_image: '',
cover_image: '',
files:[]
header_image: '',
files:[],
moderators_ids: []
},
thumbnail: {},
cover: {},
@ -337,12 +350,13 @@ export default {
isNewCollection: false,
// Fream Uploader variables
frameUploader: undefined,
your_img_src: '',
your_img_id: '',
you_have_img: false,
upload_link: '',
custom_img_id: ''
thumbPlaceholderPath: tainacan_plugin.base_url + '/admin/images/placeholder_square.png',
headerPlaceholderPath: tainacan_plugin.base_url + '/admin/images/placeholder_rectangle.png',
isFetchingModerators: false,
users: [],
moderators: [],
collections: [],
isFetchingCollections: true
}
},
methods: {
@ -352,22 +366,32 @@ export default {
'fetchCollection',
'sendAttachment',
'updateThumbnail',
'updateCover',
'updateHeaderImage',
'fetchPages',
'fetchPage'
'fetchPage',
'fetchUsers',
'fetchCollectionsForParent'
]),
...mapActions('fields', [
'fetchFields'
]),
onSubmit() {
// Puts loading on Draft Collection creation
this.isLoading = true;
this.form.moderators_ids = [];
for (let moderator of this.moderators)
this.form.moderators_ids.push(moderator.id);
let data = {
collection_id: this.collectionId,
name: this.form.name,
description: this.form.description,
enable_cover_page: this.form.enable_cover_page,
cover_page_id: this.form.cover_page_id,
cover_page_id: this.form.cover_page_id,
slug: this.form.slug,
status: this.form.status
status: this.form.status,
moderators_ids: this.form.moderators_ids,
parent: this.form.parent
};
this.updateCollection(data).then(updatedCollection => {
@ -427,12 +451,25 @@ export default {
this.form.description = this.collection.description;
this.form.enable_cover_page = this.collection.enable_cover_page;
this.form.cover_page_id = this.collection.cover_page_id;
this.form.cover_page_id = this.collection.cover_page_id;
this.form.slug = this.collection.slug;
this.form.parent = this.collection.parent;
this.moderators = [];
// Pre-fill status with publish to incentivate it
this.form.status = 'publish';
// Generates options for parent collection
this.isFetchingCollections = true;
this.fetchCollectionsForParent()
.then((collections) => {
this.collections = collections;
this.isFetchingCollections = false;
})
.catch((error) => {
this.$console.error(error);
this.isFetchingCollections = false;
});
this.isLoading = false;
})
@ -444,65 +481,9 @@ export default {
cancelBack(){
this.$router.push(this.$routerHelper.getCollectionsPath());
},
uploadThumbnail($event) {
this.sendAttachment({ collection_id: this.collectionId, file: $event[0] })
.then((res) => {
this.updateThumbnail({collectionId: this.collectionId, thumbnailId: res.id})
.then((res) => {
this.collection.featured_image = res.featured_image;
})
.catch((error) => {
this.$console.error(error);
});
})
.catch((error) => {
this.$console.error(error);
});
},
deleteThumbnail() {
this.updateThumbnail({collectionId: this.collectionId, thumbnailId: 0})
.then(() => {
this.collection.featured_image = false;
})
.catch((error) => {
this.$console.error(error);
});
},
uploadCover($event) {
this.sendAttachment({ collection_id: this.collectionId, file: $event[0] })
.then((res) => {
this.updateCover({collectionId: this.collectionId, coverId: res.id})
.then((res) => {
this.collection.cover_image = res.cover_image;
})
.catch((error) => {
this.$console.error(error);
});
})
.catch((error) => {
this.$console.error(error);
});
},
deleteCover() {
this.updateCover({collectionId: this.collectionId, coverId: 0})
.then(() => {
this.collection.cover_image = false;
})
.catch((error) => {
this.$console.error(error);
});
},
fecthCoverPages() {
fecthCoverPages(search) {
this.isFetchingPages = true;
this.fetchPages()
this.fetchPages(search)
.then((pages) => {
this.coverPages = pages;
this.isFetchingPages = false;
@ -518,12 +499,37 @@ export default {
this.coverPageTitle = this.coverPage.title.rendered;
this.coverPageEditPath = tainacan_plugin.admin_url + '/post.php?post=' + selectedPage.id + '&action=edit';
},
fecthModerators(search) {
this.isFetchingModerators = true;
let exceptions = [];
for (let user of this.moderators)
exceptions.push(parseInt(user.id));
exceptions.push(this.collection.author_id);
this.fetchUsers({ search: search, exceptions: exceptions})
.then((users) => {
this.users = users;
this.isFetchingModerators = false;
})
.catch((error) => {
this.$console.error(error);
this.isFetchingPages = false;
});
},
onAddModerator(user) {
this.moderators.push({'id': user.id, 'name': user.name});
},
removeModerator(moderatorIndex) {
this.moderators.splice(moderatorIndex, 1);
},
removeCoverPage() {
this.coverPage = {};
this.coverPageTitle = '';
this.form.cover_page_id = '';
},
openFrameUploader(event) {
editImage(event, isThumbnail) {
'use strict';
event.preventDefault();
// If the media frame already exists, reopen it.
@ -534,32 +540,126 @@ export default {
// Create a new media frame
this.frameUploader = wp.media.frames.frame_uploader = wp.media({
title: 'Select or Upload Media Of Your Chosen Persuasion',
frame: 'select',
title: 'Select or Upload and Image.',
button: {
text: 'Use this media'
text: 'Select and Crop',
close: false
},
multiple: false,
library: {
type: 'image',
uploadedTo: this.collectionId
},
uploader: true,
states: [
new wp.media.controller.Library({
title: 'Corta aí',
library: wp.media.query({ type: 'image' }),
multiple: false,
date: false,
priority: 20,
suggestedWidth: 1000,
suggestedHeight: 200
}),
new wp.media.controller.Cropper({
imgSelectOptions: {
enable: true,
handles: true,
imageHeight: 200,
imageWidth: 1000,
instance: true,
keys: true,
maxWidth: 1000,
persistent: true,
x1: 0,
x2: 250,
y1: 0,
y2: 50
}
})
]
});
wp.media.view.settings.post = {
id: this.collectionId,
featuredImageId: this.collection.featured_img_id
id: this.collectionId
}
//console.log(wp.wp_get_image_editor())
this.frameUploader.on('select', () => {
this.frameUploader.state('cropper').set( 'canSkipCrop', true );
this.frameUploader.setState('cropper');
});
this.frameUploader.on('skippedcrop', () => {
let media = this.frameUploader.state().get( 'selection' ).first().toJSON();
if (isThumbnail) {
this.updateThumbnail({collectionId: this.collectionId, thumbnailId: media.id})
.then((res) => {
this.collection.featured_image = res.featured_image;
})
.catch((error) => {
this.$console.error(error);
});
} else {
this.updateHeaderImage({collectionId: this.collectionId, headerImageId: media.id})
.then((res) => {
this.collection.header_image = res.header_image;
})
.catch((error) => {
this.$console.error(error);
});
}
console.log(media);
});
this.frameUploader.on('cropped', (croppedImage) => {
// it is not cropping where we choose, but almost there
if (isThumbnail) {
this.updateThumbnail({collectionId: this.collectionId, thumbnailId: croppedImage.attachment_id})
.then((res) => {
this.collection.featured_image = res.featured_image;
})
.catch((error) => {
this.$console.error(error);
});
} else {
this.updateHeaderImage({collectionId: this.collectionId, headerImageId: croppedImage.attachment_id})
.then((res) => {
this.collection.header_image = res.header_image;
})
.catch((error) => {
this.$console.error(error);
});
}
});
this.frameUploader.open();
}
},
deleteThumbnail() {
this.updateThumbnail({collectionId: this.collectionId, thumbnailId: 0})
.then(() => {
this.collection.featured_image = false;
})
.catch((error) => {
this.$console.error(error);
});
},
deleteHeaderImage() {
this.updateHeaderImage({collectionId: this.collectionId, headerImageId: 0})
.then(() => {
this.collection.header_image = false;
})
.catch((error) => {
this.$console.error(error);
});
},
},
created(){
@ -584,7 +684,11 @@ export default {
this.form.status = this.collection.status;
this.form.enable_cover_page = this.collection.enable_cover_page;
this.form.cover_page_id = this.collection.cover_page_id;
this.form.parent = this.collection.parent;
this.moderators = JSON.parse(JSON.stringify(this.collection.moderators));
// Generates CoverPage from current cover_page_id info
if (this.form.cover_page_id != undefined && this.form.cover_page_id != '') {
this.isFetchingPages = true;
@ -600,11 +704,23 @@ export default {
this.$console.error(error);
this.isFetchingPages = false;
});
}
}
// Generates options for parent collection
this.isFetchingCollections = true;
this.fetchCollectionsForParent()
.then((collections) => {
this.collections = collections;
this.isFetchingCollections = false;
})
.catch((error) => {
this.$console.error(error);
this.isFetchingCollections = false;
});
this.isLoading = false;
});
}
}
}
}
@ -612,21 +728,48 @@ export default {
<style lang="scss" scoped>
.thumbnail-field {
width: 128px;
height: 128px;
max-width: 128px;
@import "../../scss/_variables.scss";
.thumbnail-field {
max-height: 128px;
margin-bottom: 96px;
margin-top: -20px;
.content {
padding: 10px;
font-size: 0.8em;
}
img {
bottom: 0;
position: absolute;
}
.image-placeholder {
position: absolute;
margin-left: 10px;
margin-right: 10px;
bottom: 50%;
font-size: 0.8rem;
font-weight: bold;
z-index: 99;
text-align: center;
color: gray;
}
#button-edit-thumbnail, #button-edit-header-image {
border-radius: 100px !important;
height: 40px !important;
width: 40px !important;
bottom: -20px;
left: -20px;
z-index: 99;
.icon {
display: inherit;
padding: 0;
margin: 0;
margin-left: -8px;
margin-top: 3px;
}
}
.thumbnail-buttons-row {
display: none;
}
@ -634,13 +777,37 @@ export default {
.thumbnail-buttons-row {
display: inline-block;
position: relative;
bottom: 31px;
background-color: rgba(255,255,255,0.8);
top: -128px;
background-color: rgba(255, 255, 255, 0.9);
padding: 2px 8px;
border-radius: 0px 4px 0px 0px;
border-radius: 0px 0px 0px 4px;
left: 88px;
}
}
}
.selected-cover-page {
background-color: $tainacan-input-color;
padding: 8px;
font-size: .85rem;
.span { vertical-align: middle;}
.selected-cover-page-control {
float: right;
}
}
.moderators-list {
padding: 10px;
display: flex;
.tags {
margin-right: 5px;
}
}
.moderators-empty-list {
color: gray;
font-size: 0.85rem;
}
</style>

View File

@ -1,125 +1,178 @@
<template>
<form
id="fieldEditForm"
class="tainacan-form"
@submit.prevent="saveEdition(editForm)">
<b-field
<form
id="fieldEditForm"
class="tainacan-form"
@submit.prevent="saveEdition(editForm)">
<b-field
:addons="false"
:type="formErrors['name'] != undefined ? 'is-danger' : ''"
:message="formErrors['name'] != undefined ? formErrors['name'] : ''">
:type="formErrors['name'] != undefined ? 'is-danger' : ''"
:message="formErrors['name'] != undefined ? formErrors['name'] : ''">
<label class="label">
{{ $i18n.get('label_name') }}
<span
class="required-field-asterisk"
:class="formErrors['name'] != undefined ? 'is-danger' : ''">*</span>
<help-button
:title="$i18n.getHelperTitle('fields', 'name')"
{{ $i18n.get('label_name') }}
<span
class="required-field-asterisk"
:class="formErrors['name'] != undefined ? 'is-danger' : ''">*</span>
<help-button
:title="$i18n.getHelperTitle('fields', 'name')"
:message="$i18n.getHelperMessage('fields', 'name')"/>
</label>
<b-input
v-model="editForm.name"
name="name"
<b-input
v-model="editForm.name"
name="name"
@focus="clearErrors('name')"/>
</b-field>
<b-field
:addons="false"
:type="formErrors['description'] != undefined ? 'is-danger' : ''"
:type="formErrors['description'] != undefined ? 'is-danger' : ''"
:message="formErrors['description'] != undefined ? formErrors['description'] : ''">
<label class="label">
{{ $i18n.get('label_description') }}
<help-button
:title="$i18n.getHelperTitle('fields', 'description')"
<help-button
:title="$i18n.getHelperTitle('fields', 'description')"
:message="$i18n.getHelperMessage('fields', 'description')"/>
</label>
<b-input
type="textarea"
name="description"
v-model="editForm.description"
@focus="clearErrors('description')" />
<b-input
type="textarea"
name="description"
v-model="editForm.description"
@focus="clearErrors('description')"/>
</b-field>
<b-field
<b-field
:addons="false"
:type="formErrors['status'] != undefined ? 'is-danger' : ''"
:type="formErrors['status'] != undefined ? 'is-danger' : ''"
:message="formErrors['status'] != undefined ? formErrors['status'] : ''">
<label class="label">
{{ $i18n.get('label_status') }}
<help-button
:title="$i18n.getHelperTitle('fields', 'status')"
{{ $i18n.get('label_status') }}
<help-button
:title="$i18n.getHelperTitle('fields', 'status')"
:message="$i18n.getHelperMessage('fields', 'status')"/>
</label>
<div class="inline-block">
<b-radio
<b-radio
@focus="clearErrors('label_status')"
id="tainacan-select-status-publish"
name="status"
name="status"
v-model="editForm.status"
native-value="publish">
{{ $i18n.get('publish_visibility') }}
</b-radio>
<br>
<b-radio
<b-radio
@focus="clearErrors('label_status')"
id="tainacan-select-status-private"
name="status"
name="status"
v-model="editForm.status"
native-value="private">
{{ $i18n.get('private_visibility') }}
</b-radio>
</div>
</b-field>
<br>
<b-field
<!-- Display on listing -->
<b-field
:addons="false">
<label class="label">
{{ $i18n.get('label_display') }}
<help-button
:title="$i18n.getHelperTitle('fields', 'display')"
:message="$i18n.getHelperMessage('fields', 'display')"/>
</label>
<b-field
:type="formErrors['display'] != undefined ? 'is-danger' : ''"
:message="formErrors['display'] != undefined ? formErrors['display'] : ''">
<b-radio
size="is-small"
@input="clearErrors('display')"
v-model="editForm.display"
native-value="yes"
name="display">
{{ $i18n.get('label_display_default') }}
</b-radio>
</b-field>
<b-field>
<b-radio
size="is-small"
@input="clearErrors('display')"
v-model="editForm.display"
native-value="no"
name="display">
{{ $i18n.get('label_not_display') }}
</b-radio>
</b-field>
<b-field
:type="formErrors['display'] != undefined ? 'is-danger' : ''"
:message="formErrors['display'] != undefined ? formErrors['display'] : ''">
<b-radio
size="is-small"
v-model="editForm.display"
@input="clearErrors('display')"
native-value="never"
name="display">
{{ $i18n.get('label_display_never') }}
</b-radio>
</b-field>
</b-field>
<b-field
:addons="false"
:label="$i18n.get('label_options')">
<b-field
:type="formErrors['required'] != undefined ? 'is-danger' : ''"
:type="formErrors['required'] != undefined ? 'is-danger' : ''"
:message="formErrors['required'] != undefined ? formErrors['required'] : ''">
<b-checkbox
size="is-small"
@input="clearErrors('required')"
v-model="editForm.required"
true-value="yes"
true-value="yes"
false-value="no"
name="required">
{{ $i18n.get('label_required') }}
</b-checkbox>
<help-button
:title="$i18n.getHelperTitle('fields', 'required')"
<help-button
:title="$i18n.getHelperTitle('fields', 'required')"
:message="$i18n.getHelperMessage('fields', 'required')"/>
</b-field>
<b-field
:type="formErrors['multiple'] != undefined ? 'is-danger' : ''"
:type="formErrors['multiple'] != undefined ? 'is-danger' : ''"
:message="formErrors['multiple'] != undefined ? formErrors['multiple'] : ''">
<b-checkbox
<b-checkbox
size="is-small"
@input="clearErrors('multiple')"
v-model="editForm.multiple"
true-value="yes"
true-value="yes"
false-value="no"
name="multiple">
{{ $i18n.get('label_allow_multiple') }}
</b-checkbox>
<help-button
:title="$i18n.getHelperTitle('fields', 'multiple')"
<help-button
:title="$i18n.getHelperTitle('fields', 'multiple')"
:message="$i18n.getHelperMessage('fields', 'multiple')"/>
</b-field>
<b-field
:type="formErrors['unique'] != undefined ? 'is-danger' : ''"
<b-field
:type="formErrors['unique'] != undefined ? 'is-danger' : ''"
:message="formErrors['unique'] != undefined ? formErrors['unique'] : ''">
<b-checkbox
<b-checkbox
size="is-small"
@input="clearErrors('unique')"
v-model="editForm.unique"
true-value="yes"
true-value="yes"
false-value="no"
name="collecion_key">
{{ $i18n.get('label_unique_value') }}
</b-checkbox>
<help-button
:title="$i18n.getHelperTitle('fields', 'unique')"
:message="$i18n.getHelperMessage('fields', 'unique')"/>
<help-button
:title="$i18n.getHelperTitle('fields', 'unique')"
:message="$i18n.getHelperMessage('fields', 'unique')"/>
</b-field>
</b-field>
@ -129,21 +182,23 @@
:is="editForm.field_type_object.form_component"
:field="editForm"
v-model="editForm.field_type_options"/>
<div
v-html="editForm.edit_form"
<div
v-html="editForm.edit_form"
v-else/>
<div class="field is-grouped form-submit">
<div class="field is-grouped form-submit">
<div class="control">
<button
class="button is-outlined"
@click.prevent="cancelEdition()"
slot="trigger">{{ $i18n.get('cancel') }}</button>
<button
class="button is-outlined"
@click.prevent="cancelEdition()"
slot="trigger">{{ $i18n.get('cancel') }}
</button>
</div>
<div class="control">
<button
class="button is-success"
type="submit">{{ $i18n.get('save') }}</button>
<button
class="button is-success"
type="submit">{{ $i18n.get('save') }}
</button>
</div>
</div>
<p class="help is-danger">{{ formErrorMessage }}</p>
@ -151,117 +206,129 @@
</template>
<script>
import { mapActions } from 'vuex';
import {mapActions} from 'vuex';
export default {
name: 'FieldEditionForm',
data(){
return {
editForm: {},
oldForm: {},
formErrors: {},
formErrorMessage: '',
closedByForm: false
}
},
props: {
index: '',
editedField: Object,
originalField: Object,
isRepositoryLevel: false,
collectionId: ''
},
created() {
this.editForm = this.editedField;
this.formErrors = this.editForm.formErrors != undefined ? this.editForm.formErrors : {};
this.formErrorMessage = this.editForm.formErrors != undefined ? this.editForm.formErrorMessage : '';
this.oldForm = JSON.parse(JSON.stringify(this.originalField));
export default {
name: 'FieldEditionForm',
data() {
return {
editForm: {},
oldForm: {},
formErrors: {},
formErrorMessage: '',
closedByForm: false
}
},
props: {
index: '',
editedField: Object,
originalField: Object,
isRepositoryLevel: false,
collectionId: ''
},
created() {
},
beforeDestroy() {
if (this.closedByForm) {
this.editedField.saved = true;
} else {
this.oldForm.saved = this.editForm.saved;
if (JSON.stringify(this.editForm) != JSON.stringify(this.oldForm))
this.editedField.saved = false;
else
this.editForm = this.editedField;
this.formErrors = this.editForm.formErrors != undefined ? this.editForm.formErrors : {};
this.formErrorMessage = this.editForm.formErrors != undefined ? this.editForm.formErrorMessage : '';
this.oldForm = JSON.parse(JSON.stringify(this.originalField));
},
beforeDestroy() {
if (this.closedByForm) {
this.editedField.saved = true;
}
},
methods: {
...mapActions('fields', [
'updateField'
]),
saveEdition(field) {
if ((field.field_type_object && field.field_type_object.form_component) || field.edit_form == '') {
this.updateField({collectionId: this.collectionId, fieldId: field.id, isRepositoryLevel: this.isRepositoryLevel, index: this.index, options: this.editForm})
.then(() => {
this.editForm = {};
this.formErrors = {};
this.formErrorMessage = '';
this.closedByForm = true;
this.$emit('onEditionFinished');
})
.catch((errors) => {
for (let error of errors.errors) {
for (let attribute of Object.keys(error))
this.formErrors[attribute] = error[attribute];
}
this.formErrorMessage = errors.error_message;
this.$emit('onErrorFound');
this.editForm.formErrors = this.formErrors;
this.editForm.formErrorMessage = this.formErrorMessage;
});
} else {
let formElement = document.getElementById('fieldEditForm');
let formData = new FormData(formElement);
let formObj = {}
this.oldForm.saved = this.editForm.saved;
if (JSON.stringify(this.editForm) != JSON.stringify(this.oldForm))
this.editedField.saved = false;
else
this.editedField.saved = true;
}
},
methods: {
...mapActions('fields', [
'updateField'
]),
saveEdition(field) {
for (let [key, value] of formData.entries())
formObj[key] = value;
this.updateField({collectionId: this.collectionId, fieldId: field.id, isRepositoryLevel: this.isRepositoryLevel, index: this.index, options: formObj})
.then(() => {
this.editForm = {};
this.formErrors = {};
this.formErrorMessage = '';
this.closedByForm = true;
this.$emit('onEditionFinished');
if ((field.field_type_object && field.field_type_object.form_component) || field.edit_form == '') {
this.updateField({
collectionId: this.collectionId,
fieldId: field.id,
isRepositoryLevel: this.isRepositoryLevel,
index: this.index,
options: this.editForm
})
.catch((errors) => {
for (let error of errors.errors) {
for (let attribute of Object.keys(error))
this.formErrors[attribute] = error[attribute];
}
this.formErrorMessage = errors.error_message;
this.$emit('onErrorFound');
.then(() => {
this.editForm = {};
this.formErrors = {};
this.formErrorMessage = '';
this.closedByForm = true;
this.$emit('onEditionFinished');
})
.catch((errors) => {
for (let error of errors.errors) {
for (let attribute of Object.keys(error))
this.formErrors[attribute] = error[attribute];
}
this.formErrorMessage = errors.error_message;
this.$emit('onErrorFound');
this.editForm.formErrors = this.formErrors;
this.editForm.formErrorMessage = this.formErrorMessage;
});
}
},
clearErrors(attribute) {
this.formErrors[attribute] = undefined;
},
cancelEdition() {
this.closedByForm = true;
this.$emit('onEditionCanceled');
},
this.editForm.formErrors = this.formErrors;
this.editForm.formErrorMessage = this.formErrorMessage;
});
} else {
let formElement = document.getElementById('fieldEditForm');
let formData = new FormData(formElement);
let formObj = {};
for (let [key, value] of formData.entries())
formObj[key] = value;
this.updateField({
collectionId: this.collectionId,
fieldId: field.id,
isRepositoryLevel: this.isRepositoryLevel,
index: this.index,
options: formObj
})
.then(() => {
this.editForm = {};
this.formErrors = {};
this.formErrorMessage = '';
this.closedByForm = true;
this.$emit('onEditionFinished');
})
.catch((errors) => {
for (let error of errors.errors) {
for (let attribute of Object.keys(error))
this.formErrors[attribute] = error[attribute];
}
this.formErrorMessage = errors.error_message;
this.$emit('onErrorFound');
this.editForm.formErrors = this.formErrors;
this.editForm.formErrorMessage = this.formErrorMessage;
});
}
},
clearErrors(attribute) {
this.formErrors[attribute] = undefined;
},
cancelEdition() {
this.closedByForm = true;
this.$emit('onEditionCanceled');
},
}
}
}
</script>
<style lang="scss" scoped>
@import "../../scss/_variables.scss";
form {
padding: 1.0em 2.0em;
border-top: 1px solid $draggable-border-color;

View File

@ -14,19 +14,13 @@
<!-- Thumbnail -------------------------------- -->
<b-field :label="$i18n.get('label_image')">
<div class="thumbnail-field">
<b-upload
<button
v-if="item.featured_image == undefined || item.featured_image == false"
v-model="thumbnail"
drag-drop
@input="uploadThumbnail($event)">
<div class="content has-text-centered">
<p>
<b-icon
icon="upload"/>
</p>
<p>{{ $i18n.get('instruction_image_upload_box') }}</p>
</div>
</b-upload>
@click="editThumbnail($event)"
class="button is-primary">
<b-icon icon="upload" />
<span>{{ $i18n.get('label_choose_thumb') }}</span>
</button>
<div v-else>
<figure class="image is-128x128">
<img
@ -34,17 +28,18 @@
:src="item.featured_image">
</figure>
<div class="thumbnail-buttons-row">
<b-upload
model="thumbnail"
@input="uploadThumbnail($event)">
<a
id="button-edit"
:aria-label="$i18n.get('label_button_edit_thumb')"><b-icon icon="pencil"/></a>
</b-upload>
<a
@click="editThumbnail($event)"
id="button-edit"
:aria-label="$i18n.get('label_button_edit_thumb')">
<b-icon icon="pencil"/>
</a>
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteThumbnail()"><b-icon icon="delete"/></a>
@click="deleteThumbnail()">
<b-icon icon="delete"/>
</a>
</div>
</div>
</div>
@ -188,6 +183,8 @@ export default {
label: this.$i18n.get('trash')
}],
formErrorMessage: '',
// Frame Uploader variables
frameUploader: undefined
}
},
methods: {
@ -287,6 +284,52 @@ export default {
});
}
},
editThumbnail(event) {
'use strict';
event.preventDefault();
// If the media frame already exists, reopen it.
if ( this.frameUploader != undefined ) {
this.frameUploader.open();
return;
}
// Create a new media frame
this.frameUploader = wp.media({
frame: 'select',
title: 'Select or Upload Media Of Your Chosen Persuasion',
button: {
text: 'Use this media'
},
multiple: false,
library: {
type: 'image',
uploadedTo: this.itemId
},
uploader: true
});
wp.media.view.settings.post = {
id: this.itemId,
featuredImageId: this.item.featured_img_id
}
this.frameUploader.on('select', () => {
let media = this.frameUploader.state().get( 'selection' ).first().toJSON();
this.updateThumbnail({itemId: this.itemId, thumbnailId: media.id})
.then((res) => {
this.item.featured_image = res.featured_image;
})
.catch((error) => {
this.$console.error(error);
});
});
this.frameUploader.open();
},
uploadThumbnail($event) {
this.sendAttachment({ item_id: this.itemId, file: $event[0] })

View File

@ -27,7 +27,7 @@
:key="index"
:custom-key="column.slug"
:label="column.name"
:visible="column.visible"
:visible="column.display"
:class="column.field == 'row_creation' ? 'row-creation' : ''"
:width="column.field == 'row_actions' ? 78 : column.field == 'row_thumbnail' ? 55 : undefined ">

View File

@ -0,0 +1,92 @@
<template>
<div>
<div
class="tile is-ancestor"
v-if="event.log_diffs.constructor === Object &&
Object.keys(event.log_diffs).length > 0 ||
event.log_diffs.length > 0">
<div class="tile is-parent">
<article class="tile box is-child">
<div class="content">
<div
v-for="(diff, key) in event.log_diffs"
:key="key">
<p/>
<div class="has-text-weight-bold is-capitalized">
{{ `${key.replace('_', ' ')}:` }}
</div>
<div v-if="key === 'featured_image'">
<div class="image is-128x128">
<img :src="diff.new">
</div>
</div>
<div
v-else
v-for="(d, i) in diff.new"
:key="i"
class="content is-inline" >
<div v-if="d.hasOwnProperty('mime_type') && d.mime_type.includes('image') && key === 'attachments'">
<article class="media">
<div class="media-left">
<p class="image is-64x64"><img :src="d.url"></p>
</div>
<div class="media-content">
<div class="content">
<p>
<strong class="is-capitalized">{{ d.title }}</strong> <small class="tag is-light">{{ d.mime_type }}</small>
<br>
{{ d.description }}
</p>
</div>
</div>
</article>
</div>
<div
v-else-if="key === 'fields_order' || key === 'filters_order'"
class="is-capitalized">
{{ `ID: ${d.id} Enabled: ${d.enabled}` }}
</div>
<div
class="is-inline"
v-else-if="!Array.isArray(d) && d.constructor.name !== 'Object' ">{{ d }}
</div>
<div
v-else
v-for="(e, i2) in d"
:key="i2"
class="is-inline">
<div class="is-capitalized">
{{ `${i2.replace('_', ' ')}: ${e} ` }}
</div>
</div>
</div>
</div>
</div>
</article>
</div>
</div>
</div>
</template>
<script>
export default {
name: "EventNoDiff",
props: {
event: Object
}
}
</script>
<style scoped>
</style>

View File

@ -2,19 +2,19 @@
<span>
<div class="header-item">
<b-dropdown>
<button
class="button"
<button
class="button"
slot="trigger">
<span>{{ $i18n.get('label_table_fields') }}</span>
<b-icon icon="menu-down"/>
</button>
<b-dropdown-item
v-for="(column, index) in tableFields"
<b-dropdown-item
v-for="(column, index) in tableFields"
:key="index"
class="control"
class="control"
custom>
<b-checkbox
v-model="column.visible"
v-model="column.display"
:native-value="column.field">
{{ column.name }}
</b-checkbox>
@ -24,23 +24,24 @@
<div class="header-item">
<b-field>
<b-select
@input="onChangeOrderBy($event)"
@input="onChangeOrderBy($event)"
:placeholder="$i18n.get('label_sorting')">
<option
v-for="field in tableFields"
v-if="
v-for="field in tableFields"
v-if="
field.id == 'date' || (
field.id != undefined &&
field.field_type_object.related_mapped_prop != 'description' &&
field.field_type_object.primitive_type != 'term' &&
field.field_type_object.primitive_type != 'item' &&
field.field_type_object.primitive_type != 'compound')"
:value="field"
:key="field.id">
field.id != undefined &&
field.field_type_object.related_mapped_prop != 'description' &&
field.field_type_object.primitive_type != 'term' &&
field.field_type_object.primitive_type != 'item' &&
field.field_type_object.primitive_type != 'compound'
)"
:value="field"
:key="field.id">
{{ field.name }}
</option>
</b-select>
<button
<button
class="button is-small"
@click="onChangeOrder()">
<b-icon :icon="order == 'ASC' ? 'sort-ascending' : 'sort-descending'"/>
@ -51,41 +52,41 @@
</template>
<script>
import { mapGetters } from 'vuex';
import {mapGetters} from 'vuex';
export default {
name: 'SearchControl',
data() {
return {
prefTableFields: []
}
},
props: {
collectionId: Number,
isRepositoryLevel: false,
tableFields: Array
},
computed: {
orderBy() {
return this.getOrderBy();
export default {
name: 'SearchControl',
data() {
return {
prefTableFields: []
}
},
order() {
return this.getOrder();
}
},
methods: {
...mapGetters('search', [
'getOrderBy',
'getOrder'
]),
onChangeOrderBy(field) {
this.$eventBusSearch.setOrderBy(field);
props: {
collectionId: Number,
isRepositoryLevel: false,
tableFields: Array
},
onChangeOrder() {
this.order == 'DESC' ? this.$eventBusSearch.setOrder('ASC') : this.$eventBusSearch.setOrder('DESC');
computed: {
orderBy() {
return this.getOrderBy();
},
order() {
return this.getOrder();
}
},
methods: {
...mapGetters('search', [
'getOrderBy',
'getOrder'
]),
onChangeOrderBy(field) {
this.$eventBusSearch.setOrderBy(field);
},
onChangeOrder() {
this.order == 'DESC' ? this.$eventBusSearch.setOrder('ASC') : this.$eventBusSearch.setOrder('DESC');
}
}
}
}
</script>
<style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

View File

@ -1,3 +1,7 @@
// Overrides lodash by original WordPress Underscore Library
window.lodash = _.noConflict();
window.underscore = _.noConflict();
// Main imports
import Vue from 'vue';
import Buefy from 'buefy';
@ -86,4 +90,4 @@ new Vue({
store,
router,
render: h => h(AdminPage)
});
});

View File

@ -1,37 +1,53 @@
<template>
<div
class="page-container-small"
<template>
<div
class="page-container-small"
:class="{'primary-page': isRepositoryLevel}">
<div class="sub-header">
<b-loading
:is-full-page="false"
<b-loading
:is-full-page="false"
:active.sync="isLoadingFields"/>
<div class="header-item">
<router-link
id="button-create-item"
tag="button"
class="button is-secondary"
:to="{ path: $routerHelper.getNewItemPath(collectionId) }">
{{ $i18n.getFrom('items', 'new_item') }}
</router-link>
<b-dropdown>
<button
class="button is-secondary"
slot="trigger">
<span>{{ `${$i18n.get('add')} ${$i18n.get('item')}` }}</span>
<b-icon icon="menu-down"/>
</button>
<b-dropdown-item class="tainacan-dropdown-item">
<router-link
id="a-create-item"
tag="div"
:to="{ path: $routerHelper.getNewItemPath(collectionId) }">
{{ `${$i18n.get('add_one_item')}` }}
</router-link>
</b-dropdown-item>
<b-dropdown-item>Adicionar itens em massa <br>
<small class="is-small">Eu quero café</small>
</b-dropdown-item>
<b-dropdown-item>Adicionar item de fonte externa</b-dropdown-item>
</b-dropdown>
</div>
<search-control
v-if="fields.length > 0 && (items.length != 0 || isLoadingItems)"
:is-repository-level="isRepositoryLevel"
v-if="fields.length > 0 && (items.length > 0 || isLoadingItems)"
:is-repository-level="isRepositoryLevel"
:collection-id="collectionId"
:table-fields="tableFields"
:pref-table-fields="prefTableFields"/>
</div>
<div class="columns">
<aside class="column filters-menu">
<b-loading
:is-full-page="false"
<b-loading
:is-full-page="false"
:active.sync="isLoadingFilters"/>
<h3>{{ $i18n.get('filters') }}</h3>
<filters-items-list
v-if="!isLoadingFilters && filters.length > 0"
<filters-items-list
v-if="!isLoadingFilters && filters.length > 0"
:filters="filters"/>
<section
<section
v-else
class="is-grouped-centered section">
<div class="content has-text-gray has-text-centered">
@ -40,29 +56,30 @@
icon="filter-outline"
size="is-large"/>
</p>
<p>{{ $i18n.get('info_there_is_no_filter' ) }}</p>
<p>{{ $i18n.get('info_there_is_no_filter' ) }}</p>
<router-link
id="button-create-filter"
:to="isRepositoryLevel ? $routerHelper.getNewFilterPath() : $routerHelper.getNewCollectionFilterPath(collectionId)"
tag="button"
tag="button"
class="button is-secondary is-centered">
{{ $i18n.getFrom('filters', 'new_item') }}</router-link>
{{ $i18n.getFrom('filters', 'new_item') }}
</router-link>
</div>
</section>
</aside>
<div class="column">
<div class="table-container above-subheader">
<b-loading
:is-full-page="false"
<b-loading
:is-full-page="false"
:active.sync="isLoadingItems"/>
<items-list
v-if="!isLoadingItems && items.length > 0"
:collection-id="collectionId"
:table-fields="tableFields"
:items="items"
:items="items"
:is-loading="isLoading"/>
<section
v-if="!isLoadingItems && items.length <= 0"
<section
v-if="!isLoadingItems && items.length <= 0"
class="section">
<div class="content has-text-grey has-text-centered">
<p>
@ -70,11 +87,12 @@
icon="inbox"
size="is-large"/>
</p>
<p>{{ hasFiltered ? $i18n.get('info_no_item_found') : $i18n.get('info_no_item_created') }}</p>
<p>{{ hasFiltered ? $i18n.get('info_no_item_found') : $i18n.get('info_no_item_created')
}}</p>
<router-link
v-if="!hasFiltered"
id="button-create-item"
tag="button"
id="button-create-item"
tag="button"
class="button is-primary"
:to="{ path: $routerHelper.getNewItemPath(collectionId) }">
{{ $i18n.getFrom('items', 'new_item') }}
@ -85,127 +103,180 @@
<pagination v-if="items.length > 0"/>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import SearchControl from '../../components/search/search-control.vue'
import ItemsList from '../../components/lists/items-list.vue';
import FiltersItemsList from '../../components/search/filters-items-list.vue';
import Pagination from '../../components/search/pagination.vue'
import { mapActions, mapGetters } from 'vuex';
import SearchControl from '../../components/search/search-control.vue'
import ItemsList from '../../components/lists/items-list.vue';
import FiltersItemsList from '../../components/search/filters-items-list.vue';
import Pagination from '../../components/search/pagination.vue'
import {mapActions, mapGetters} from 'vuex';
export default {
name: 'ItemsPage',
data(){
return {
isRepositoryLevel: false,
tableFields: [],
prefTableFields: [],
isLoadingItems: false,
isLoadingFilters: false,
isLoadingFields: false,
hasFiltered: false
}
},
props: {
collectionId: Number
},
components: {
SearchControl,
ItemsList,
FiltersItemsList,
Pagination
},
methods: {
...mapGetters('collection', [
'getItems'
]),
...mapActions('fields', [
'fetchFields'
]),
...mapGetters('fields', [
'getFields'
]),
...mapActions('filter',[
'fetchFilters'
]),
...mapGetters('filter', [
'getFilters'
])
},
computed: {
items(){
return this.getItems();
},
filters(){
return this.getFilters();
},
fields() {
return this.getFields();
}
},
created() {
this.isRepositoryLevel = (this.collectionId == undefined);
this.$eventBusSearch.$on('isLoadingItems', isLoadingItems => {
this.isLoadingItems = isLoadingItems;
});
this.$eventBusSearch.$on('hasFiltered', hasFiltered => {
this.hasFiltered = hasFiltered;
});
this.isLoadingFilters = true;
this.fetchFilters( { collectionId: this.collectionId, isRepositoryLevel: this.isRepositoryLevel, isContextEdit: true })
.then(() => this.isLoadingFilters = false)
.catch(() => this.isLoadingFilters = false);
this.isLoadingFields = true;
this.fetchFields({ collectionId: this.collectionId, isRepositoryLevel: this.isRepositoryLevel, isContextEdit: false }).then(() => {
this.tableFields.push({ name: this.$i18n.get('label_thumbnail'), field: 'row_thumbnail', field_type: undefined, slug: 'featured_image', id: undefined, visible: true });
for (let field of this.fields) {
this.tableFields.push(
{name: field.name, field: field.description, slug: field.slug, field_type: field.field_type, field_type_object: field.field_type_object, id: field.id, visible: true }
);
export default {
name: 'ItemsPage',
data() {
return {
isRepositoryLevel: false,
tableFields: [],
prefTableFields: [],
isLoadingItems: false,
isLoadingFilters: false,
isLoadingFields: false,
hasFiltered: false
}
this.tableFields.push({ name: this.$i18n.get('label_creation'), field: 'row_creation', field_type: undefined, slug: 'creation', id: 'date', visible: true});
this.tableFields.push({ name: this.$i18n.get('label_actions'), field: 'row_actions', field_type: undefined, slug: 'actions', id: undefined, visible: true });
//this.prefTableFields = this.tableFields;
// this.$userPrefs.get('table_columns_' + this.collectionId)
// .then((value) => {
// this.prefTableFields = value;
// })
// .catch((error) => {
// this.$userPrefs.set('table_columns_' + this.collectionId, this.prefTableFields, null);
// });
this.isLoadingFields = false;
},
props: {
collectionId: Number
},
components: {
SearchControl,
ItemsList,
FiltersItemsList,
Pagination
},
methods: {
...mapGetters('collection', [
'getItems'
]),
...mapActions('fields', [
'fetchFields'
]),
...mapGetters('fields', [
'getFields'
]),
...mapActions('filter', [
'fetchFilters'
]),
...mapGetters('filter', [
'getFilters'
])
},
computed: {
items() {
return this.getItems();
},
filters() {
return this.getFilters();
},
fields() {
return this.getFields();
}
},
created() {
this.isRepositoryLevel = (this.collectionId == undefined);
this.$eventBusSearch.$on('isLoadingItems', isLoadingItems => {
this.isLoadingItems = isLoadingItems;
});
this.$eventBusSearch.$on('hasFiltered', hasFiltered => {
this.hasFiltered = hasFiltered;
});
this.isLoadingFilters = true;
this.fetchFilters({
collectionId: this.collectionId,
isRepositoryLevel: this.isRepositoryLevel,
isContextEdit: true
})
.then(() => this.isLoadingFilters = false)
.catch(() => this.isLoadingFilters = false);
this.isLoadingFields = true;
this.fetchFields({
collectionId: this.collectionId,
isRepositoryLevel: this.isRepositoryLevel,
isContextEdit: false
})
.then(() => {
this.tableFields.push({
name: this.$i18n.get('label_thumbnail'),
field: 'row_thumbnail',
field_type: undefined,
slug: 'featured_image',
id: undefined,
display: true
});
for (let field of this.fields) {
if (field.display !== 'never') {
// Will be pushed on array
let display = true;
if (field.display === 'no') {
display = false;
}
this.tableFields.push(
{
name: field.name,
field: field.description,
slug: field.slug,
field_type: field.field_type,
field_type_object: field.field_type_object,
id: field.id,
display: display
}
);
}
}
this.tableFields.push({
name: this.$i18n.get('label_creation'),
field: 'row_creation',
field_type: undefined,
slug: 'creation',
id: 'date',
display: true
});
this.tableFields.push({
name: this.$i18n.get('label_actions'),
field: 'row_actions',
field_type: undefined,
slug: 'actions',
id: undefined,
display: true
});
// this.prefTableFields = this.tableFields;
// this.$userPrefs.get('table_columns_' + this.collectionId)
// .then((value) => {
// this.prefTableFields = value;
// })
// .catch((error) => {
// this.$userPrefs.set('table_columns_' + this.collectionId, this.prefTableFields, null);
// });
this.isLoadingFields = false;
})
.catch(() => {
this.isLoadingFields = false;
});
},
mounted() {
this.$eventBusSearch.setCollectionId(this.collectionId);
this.$eventBusSearch.updateStoreFromURL();
this.$eventBusSearch.loadItems();
}
}).catch(() => {
this.isLoadingFields = false;
});
},
mounted(){
this.$eventBusSearch.setCollectionId(this.collectionId);
this.$eventBusSearch.updateStoreFromURL();
this.$eventBusSearch.loadItems();
}
}
</script>
<style lang="scss" scoped>
@import '../../scss/_variables.scss';
.page-container-small>.columns {
.page-container-small > .columns {
margin-top: 0;
}
.sub-header {
@ -219,7 +290,7 @@ export default {
padding-right: $page-small-side-padding;
border-bottom: 0.5px solid #ddd;
position: relative;
@media screen and (max-width: 769px) {
height: 60px;
margin-top: -0.5em;
@ -235,7 +306,7 @@ export default {
margin-bottom: 0;
margin-top: 0;
min-height: 100%;
height: auto;
height: auto;
}
.filters-menu {
@ -245,12 +316,12 @@ export default {
background-color: $tainacan-input-color;
margin-left: -$page-small-side-padding;
padding: $page-small-side-padding;
.label {
font-size: 12px;
font-weight: normal;
}
}
.table-container {
@ -260,7 +331,7 @@ export default {
}
@media screen and (max-width: 769px) {
.filters-menu {
.filters-menu {
display: none;
}
.table-container {
@ -269,7 +340,9 @@ export default {
}
}
.tainacan-dropdown-item:hover {
background-color: rgba(192, 218, 223, 1) !important;
}
</style>

View File

@ -3,7 +3,9 @@
<div class="is-fullheight">
<div class="page-container primary-page">
<div class="title">{{ event.description }}</div>
<div class="level">
<div
class="level"
v-if="event.title !== undefined && event.title.includes('updated')">
<div class="level-left"/>
<div class="level-right">
<div class="level-item">
@ -20,9 +22,16 @@
<hr class="divider">
<component
:is="comp"
:event="event"/>
<div v-if="event.title !== undefined && event.title.includes('updated')">
<component
:is="comp"
:event="event"/>
</div>
<div v-else-if="event.title !== undefined">
<no-diff :event="event" />
</div>
</div>
</div>
</div>
@ -31,8 +40,9 @@
<script>
import {mapActions, mapGetters} from 'vuex';
import Split from '../../components/other/event-diff/event-split.vue';
import Unified from '../../components/other/event-diff/event-unified.vue';
import Split from '../../components/other/event/diff-exhibition/event-split.vue';
import Unified from '../../components/other/event/diff-exhibition/event-unified.vue';
import NoDiff from '../../components/other/event/unique-exhibition/event-nodiff.vue';
export default {
name: 'EventPage',
@ -57,7 +67,8 @@
},
components: {
Split,
Unified
Unified,
NoDiff
},
created() {
this.eventId = parseInt(this.$route.params.eventId);

View File

@ -15,7 +15,7 @@ $primary-lighter: lighten($primary-light, 15%);
$primary-dark: #55A0AF;
$primary-darker: darken($primary-dark, 5%);
$success: #25a189;
$success: #25a088;
$success-invert: findColorInvert($success);
$separator-color: #2a6e77;

View File

@ -21,9 +21,11 @@ return [
// Actions
'edit' => __( 'Edit', 'tainacan' ),
'new' => __( 'New', 'tainacan' ),
'add' => __( 'Add', 'tainacan' ),
'import' => __( 'Import', 'tainacan' ),
'export' => __( 'Export', 'tainacan' ),
'cancel' => __( 'Cancel', 'tainacan' ),
'remove' => __( 'Remove', 'tainacan' ),
'save' => __( 'Save', 'tainacan' ),
'next' => __( 'Next', 'tainacan' ),
'see' => __( 'See', 'tainacan' ),
@ -32,6 +34,7 @@ return [
'continue' => __( 'Continue', 'tainacan' ),
'approve_item' => __( 'Approve', 'tainacan' ),
'not_approve_item' => __( 'Not approve', 'tainacan' ),
'add_one_item' => __( 'Add one item', 'tainacan' ),
// Wordpress Status
'publish' => __( 'Publish', 'tainacan' ),
@ -54,8 +57,8 @@ return [
'title_item_page' => __( 'Item Page', 'tainacan' ),
'title_field_page' => __( 'Field Page', 'tainacan' ),
/* translators: alkdjklasdj laksjd klsadj */
'title_collection_page' => __( 'Collection Page', 'tainacan' ),
/* translators: alkdjklasdj laksjd klsadj */
'title_collection_page' => __( 'Collection Page', 'tainacan' ),
'title_filter_page' => __( 'Filter Page', 'tainacan' ),
'title_category_page' => __( 'Category Page', 'tainacan' ),
'title_term_page' => __( 'Term Page', 'tainacan' ),
@ -71,10 +74,10 @@ return [
'title_collection_fields_edition' => __( 'Collection Fields Edition Page', 'tainacan' ),
// Labels (used mainly on Aria Labels and Inputs)
'label_clean' => __( 'Clear', 'tainacan' ),
'label_selected' => __( 'Selected', 'tainacan' ),
'label_relationship_new_search' => __( 'New Search', 'tainacan' ),
'label_relationship_items_found' => __( 'Items found', 'tainacan' ),
'label_clean' => __( 'Clear', 'tainacan' ),
'label_selected' => __( 'Selected', 'tainacan' ),
'label_relationship_new_search' => __( 'New Search', 'tainacan' ),
'label_relationship_items_found' => __( 'Items found', 'tainacan' ),
'label_menu' => __( 'Menu', 'tainacan' ),
'label_main_menu' => __( 'Main Menu', 'tainacan' ),
'label_collection_menu' => __( 'Collection Menu', 'tainacan' ),
@ -86,10 +89,16 @@ return [
'label_slug' => __( 'Slug', 'tainacan' ),
'label_image' => __( 'Image', 'tainacan' ),
'label_thumbnail' => __( 'Thumbnail', 'tainacan' ),
'label_empty_thumbnail' => __( 'Empty Thumbnail', 'tainacan' ),
'label_moderators' => __( 'Moderators', 'tainacan' ),
'label_parent_collection' => __( 'Parent collection', 'tainacan' ),
'label_no_parent_collection' => __( 'No parent collection', 'tainacan' ),
'label_button_view' => __( 'Button View', 'tainacan' ),
'label_button_edit' => __( 'Button Edit', 'tainacan' ),
'label_button_delete' => __( 'Button Delete', 'tainacan' ),
'label_button_edit_thumb' => __( 'Button Edit Thumbnail', 'tainacan' ),
'label_button_edit_header_image' => __( 'Button Edit Header Image', 'tainacan' ),
'label_choose_thumb' => __( 'Choose Thumbnail', 'tainacan' ),
'label_button_delete_thumb' => __( 'Button Delete Thumbnail', 'tainacan' ),
'label_collections_per_page' => __( 'Collections per Page:', 'tainacan' ),
'label_categories_per_page' => __( 'Categories per Page:', 'tainacan' ),
@ -126,18 +135,24 @@ return [
'label_collection_fields' => __( 'Collection Fields', 'tainacan' ),
'label_collection_filters' => __( 'Collection Filters', 'tainacan' ),
'label_parent_term' => __( 'Parent Term', 'tainacan' ),
'label_new_term' => __( 'New Term', 'tainacan' ),
'label_new_term' => __( 'New Term', 'tainacan' ),
'label_new_child' => __( 'New Child', 'tainacan' ),
'label_category_terms' => __( 'Category Terms', 'tainacan' ),
'label_no_parent_term' => __( 'No parent term', 'tainacan' ),
'label_term_without_name' => __( 'Term without name', 'tainacan' ),
'label_inherited' => __( 'Inherited', 'tainacan' ),
'label_sorting' => __( 'Sorting', 'tainacan' ),
'label_inherited' => __( 'Inherited', 'tainacan' ),
'label_sorting' => __( 'Sorting', 'tainacan' ),
'label_who_when' => __( 'Who and when', 'tainacan' ),
'label_event_title' => __( 'Event', 'tainacan' ),
'label_cover_image' => __( 'Cover Image', 'tainacan' ),
'label_header_image' => __( 'Header Image', 'tainacan' ),
'label_empty_header_image' => __( 'Empty Header Image', 'tainacan' ),
'label_enable_cover_page' => __( 'Enable Cover Page', 'tainacan' ),
'label_cover_page' => __( 'Cover Page', 'tainacan' ),
'label_cover_page' => __( 'Cover Page', 'tainacan' ),
'label_default_displayed_fields' => __( 'Default Displayed Fields', 'tainacan' ),
'label_display' => __( 'Display on Listing', 'tainacan' ),
'label_display_default' => __( 'Display by default', 'tainacan' ),
'label_display_never' => __( 'Never displayed', 'tainacan' ),
'label_not_display' => __( 'Not display by default', 'tainacan' ),
// Instructions. More complex sentences to guide user and placeholders
'instruction_dragndrop_fields_collection' => __( 'Drag and drop Fields here to Collection.', 'tainacan' ),
@ -151,13 +166,19 @@ return [
'instruction_select_a_status' => __( 'Select a status:', 'tainacan' ),
'instruction_select_a_filter_type' => __( 'Select a filter type:', 'tainacan' ),
'instruction_select_a_parent_term' => __( 'Select a parent term:', 'tainacan' ),
'instruction_cover_page' => __( 'Type to search a Page to choose.', 'tainacan'),
'instruction_moderators' => __( 'Type to search a User to add.', 'tainacan'),
'instruction_select_a_parent_collection' => __( 'Select a parent colection.', 'tainacan' ),
// Info. Other feedback to user.
'info_name_is_required' => __( 'Name is required.', 'tainacan' ),
'info_no_collection_created' => __( 'No collection was created in this repository.', 'tainacan' ),
'info_no_category_created' => __( 'No category was created in this repository.', 'tainacan' ),
'info_no_item_created' => __( 'No item was created in this collection.', 'tainacan' ),
'info_no_page_found' => __( 'No page was found with this name.', 'tainacan' ),
'info_no_user_found' => __( 'No user was found with this name.', 'tainacan' ),
'info_no_item_found' => __( 'No item was found here with these filters.', 'tainacan' ),
'info_no_moderator_on_collection' => __( "This collection doesn't have any moderator yet.", 'tainacan' ),
'info_error_deleting_collection' => __( 'Error on deleting collection.', 'tainacan' ),
'info_error_deleting_category' => __( 'Error on deleting category', 'tainacan' ),
'info_collection_deleted' => __( 'Collection deleted.', 'tainacan' ),
@ -180,18 +201,18 @@ return [
'info_by' => __( 'By: ', 'tainacan' ),
'info_date' => __( 'Date: ', 'tainacan' ),
'info_not_saved' => __( 'Not saved ', 'tainacan' ),
'info_warning_fields_not_saved' => __('Are you sure? There are fields not saved, changes will be lost.', 'tainacan'),
'info_warning_filters_not_saved' => __('Are you sure? There are filters not saved, changes will be lost.', 'tainacan'),
'info_no_description_provided' => __('No description provided.', 'tainacan'),
'info_warning_category_not_saved' => __('Are you sure? The category is not saved, changes will be lost.', 'tainacan'),
'info_warning_terms_not_saved' => __('Are you sure? There are terms not saved, changes will be lost.', 'tainacan'),
'info_warning_orphan_terms' => __('Are you sure? This term is parent of other terms. These will be converted to root terms.', 'tainacan'),
'info_there_is_no_field' => __('There is no field here.', 'tainacan' ),
'info_warning_fields_not_saved' => __( 'Are you sure? There are fields not saved, changes will be lost.', 'tainacan' ),
'info_warning_filters_not_saved' => __( 'Are you sure? There are filters not saved, changes will be lost.', 'tainacan' ),
'info_no_description_provided' => __( 'No description provided.', 'tainacan' ),
'info_warning_category_not_saved' => __( 'Are you sure? The category is not saved, changes will be lost.', 'tainacan' ),
'info_warning_terms_not_saved' => __( 'Are you sure? There are terms not saved, changes will be lost.', 'tainacan' ),
'info_warning_orphan_terms' => __( 'Are you sure? This term is parent of other terms. These will be converted to root terms.', 'tainacan' ),
'info_there_is_no_field' => __( 'There is no field here.', 'tainacan' ),
'info_no_events' => __( 'No events', 'tainacan' ),
'info_logs_before' => __( 'Before updating', 'tainacan' ),
'info_logs_after' => __( 'What was updated', 'tainacan' ),
'info_there_is_no_field' => __('There is no field here yet.', 'tainacan' ),
'info_there_is_no_filter' => __('There is no filter here yet.', 'tainacan' ),
'info_there_is_no_field' => __( 'There is no field here yet.', 'tainacan' ),
'info_there_is_no_filter' => __( 'There is no filter here yet.', 'tainacan' ),
'info_changes' => __( 'Changes', 'tainacan' ),
// Tainacan Field Types

View File

@ -84,6 +84,7 @@ class REST_Collections_Controller extends REST_Controller {
* @param \WP_REST_Request $request
*
* @return \WP_Error|\WP_REST_Response
* @throws \Exception
*/
public function get_items($request){
$args = $this->prepare_filters($request);
@ -147,9 +148,28 @@ class REST_Collections_Controller extends REST_Controller {
$item_arr = $item->__toArray();
if ( $request['context'] === 'edit' ) {
$moderators_ids = $item_arr['moderators_ids'];
$moderators = [];
foreach ($moderators_ids as $id){
$user_data = get_userdata($id);
if($user_data){
$user['name'] = $user_data->display_name;
//$user['roles'] = $user_data->roles;
$user['id'] = $user_data->ID;
$moderators[] = $user;
}
}
$item_arr['moderators'] = $moderators;
$item_arr['current_user_can_edit'] = $item->can_edit();
}
unset($item_arr['moderators_ids']);
} else {
$attributes_to_filter = $request['fetch_only'];

View File

@ -98,15 +98,15 @@ class REST_Items_Controller extends REST_Controller {
$item_metadata = $item_object->get_fields();
foreach($item_metadata as $index => $me){
$field = $me->get_field();
$slug = $field->get_slug();
$field = $me->get_field();
$slug = $field->get_slug();
$item_metadata_array = $me->__toArray();
$item_array['metadata'][$slug]['name'] = $field->get_name();
$item_array['metadata'][$slug]['value'] = $item_metadata_array['value'];
$item_array['metadata'][$slug]['value_as_html'] = $item_metadata_array['value_as_html'];
$item_array['metadata'][$slug]['value_as_string'] = $item_metadata_array['value_as_string'];
$item_array['metadata'][$slug]['multiple'] = $field->get_multiple();
$item_array['metadata'][ $slug ]['name'] = $field->get_name();
$item_array['metadata'][ $slug ]['value'] = $item_metadata_array['value'];
$item_array['metadata'][ $slug ]['value_as_html'] = $item_metadata_array['value_as_html'];
$item_array['metadata'][ $slug ]['value_as_string'] = $item_metadata_array['value_as_string'];
$item_array['metadata'][ $slug ]['multiple'] = $field->get_multiple();
}
return $item_array;
@ -158,6 +158,7 @@ class REST_Items_Controller extends REST_Controller {
* @param \WP_REST_Request $request
*
* @return \WP_Error|\WP_REST_Response
* @throws \Exception
*/
public function get_items( $request ) {
$args = $this->prepare_filters($request);

View File

@ -69,12 +69,6 @@ class REST_Logs_Controller extends REST_Controller {
if(!isset($request['fetch_only'])) {
$item_array = $item->__toArray();
// if ( $request['context'] === 'edit' ) {
// $log_diff = $item->diff();
//
// $item_array['log_diff'] = $log_diff;
// }
unset($item_array['value']);
unset($item_array['old_value']);

View File

@ -31,6 +31,7 @@ class Collection extends Entity {
$enable_cover_page,
$cover_page_id,
$header_image_id,
$header_image,
$moderators_ids;
/**
@ -68,8 +69,7 @@ class Collection extends Entity {
$array_collection = parent::__toArray();
$array_collection['featured_image'] = $this->get_featured_image();
$array_collection['featured_img_id'] = $this->get_featured_img_id();
$array_collection['attachments'] = $this->get_attachments();
$array_collection['header_image'] = $this->get_header_image();
$array_collection['author_name'] = $this->get_author_name();
return $array_collection;
@ -208,6 +208,13 @@ class Collection extends Entity {
return get_the_post_thumbnail_url( $this->get_id(), 'full' );
}
/**
* @return false|string
*/
function get_header_image(){
return wp_get_attachment_url( $this->get_header_image_id() );
}
/**
* @param $id
*/

View File

@ -16,6 +16,7 @@ class Field extends Entity {
$description,
$required,
$multiple,
$display,
$cardinality,
$collection_key,
$mask,
@ -40,6 +41,21 @@ class Field extends Entity {
return 'Hello, my name is '. $this->get_name();
}
/**
* @param $display
*/
function set_display( $display ){
$this->set_mapped_property('display', $display);
}
/**
* @return mixed
*/
function get_display(){
return $this->get_mapped_property('display');
}
/**
* Return the field name
*
@ -315,7 +331,7 @@ class Field extends Entity {
* @param bool $value
*/
function set_accept_suggestion( $value ) {
return $this->set_mapped_property('accept_suggestion', $value);
$this->set_mapped_property('accept_suggestion', $value);
}
/**

View File

@ -54,7 +54,6 @@ class Item extends Entity {
$array_item['featured_image'] = $this->get_featured_image();
$array_item['featured_img_id'] = $this->get_featured_img_id();
$array_item['attachments'] = $this->get_attachments();
$array_item['author_name'] = $this->get_author_name();
return $array_item;

View File

@ -67,7 +67,7 @@
:message="$i18n.getHelperMessage('tainacan-relationship', 'repeated')"/>
</label>
<div class="block">
<b-checkbox
<b-checkbox
v-model="modelRepeated"
@input="emitValues()"
true-value="yes"
@ -116,6 +116,7 @@
this.hasFields = false;
this.modelSearch = [];
}
this.emitValues();
},
modelSearch( value ){
this.modelSearch = value;
@ -178,6 +179,7 @@
let fields = res.data;
if( fields.length > 0 ){
this.fields = [];
for( let field of fields ){
if( field.field_type !== "Tainacan\\Field_Types\\Relationship"){
@ -227,8 +229,8 @@
collection_id: this.collection,
search: this.modelSearch,
repeated: this.modelRepeated
})
});
}
}
}
</script>
</script>

View File

@ -47,7 +47,6 @@
<script>
import { tainacan as axios } from '../../../js/axios/axios';
import _ from 'lodash';
export default {
created(){
@ -169,7 +168,7 @@
},
// emit the operation for listeners
emit: _.debounce(( vm ) => {
emit:( vm ) => {
let values = [];
let type = '';
@ -197,7 +196,7 @@
collection_id: ( vm.collection_id ) ? vm.collection_id : vm.filter.collection_id,
value: values
});
}, 700)
}
}
}
</script>

View File

@ -36,59 +36,59 @@ class Collections extends Repository {
*/
public function get_map() {
return apply_filters( 'tainacan-get-map-' . $this->get_name(), [
'name' => [
'name' => [
'map' => 'post_title',
'title' => __( 'Name', 'tainacan' ),
'type' => 'string',
'description' => __( 'Name of the collection', 'tainacan' ),
'validation' => v::stringType()->notEmpty(),
],
'status' => [
'status' => [
'map' => 'post_status',
'title' => __( 'Status', 'tainacan' ),
'type' => 'string',
'default' => '',
'description' => __( 'The posts status', 'tainacan' )
],
'author_id' => [
'author_id' => [
'map' => 'post_author',
'title' => __( 'Author ID', 'tainacan' ),
'type' => 'string',
'description' => __( 'The collection author\'s user ID (numeric string)', 'tainacan' )
],
'creation_date' => [
'creation_date' => [
'map' => 'post_date',
'title' => __( 'Creation Date', 'tainacan' ),
'type' => 'string',
'description' => __( 'The collection creation date', 'tainacan' )
],
'modification_date' => [
'modification_date' => [
'map' => 'post_modified',
'title' => __( 'Modification Date', 'tainacan' ),
'type' => 'string',
'description' => __( 'The collection modification date', 'tainacan' )
],
'url' => [
'url' => [
'map' => 'guid',
'title' => __( 'Collection URL', 'tainacan' ),
'type' => 'string',
'description' => __( 'The collection URL', 'tainacan' )
],
'order' => [
'order' => [
'map' => 'menu_order',
'title' => __( 'Order', 'tainacan' ),
'type' => 'string',
'description' => __( 'Collection order. Field used if collections are manually ordered', 'tainacan' ),
//'validation' => v::stringType(),
],
'parent' => [
'parent' => [
'map' => 'post_parent',
'title' => __( 'Parent Collection', 'tainacan' ),
'type' => 'integer',
'description' => __( 'Parent collection ID', 'tainacan' ),
//'validation' => v::stringType(),
],
'description' => [
'description' => [
'map' => 'post_content',
'title' => __( 'Description', 'tainacan' ),
'type' => 'string',
@ -96,14 +96,14 @@ class Collections extends Repository {
'default' => '',
//'validation' => v::stringType(),
],
'slug' => [
'slug' => [
'map' => 'post_name',
'title' => __( 'Slug', 'tainacan' ),
'type' => 'string',
'description' => __( 'A unique and santized string representation of the collection, used to build the collection URL', 'tainacan' ),
//'validation' => v::stringType(),
],
'default_orderby' => [
'default_orderby' => [
'map' => 'meta',
'title' => __( 'Default Order field', 'tainacan' ),
'type' => 'string',
@ -111,7 +111,7 @@ class Collections extends Repository {
'default' => 'name',
//'validation' => v::stringType(),
],
'default_order' => [
'default_order' => [
'map' => 'meta',
'title' => __( 'Default order', 'tainacan' ),
'description' => __( 'Default order for items in this collection. ASC or DESC', 'tainacan' ),
@ -119,7 +119,7 @@ class Collections extends Repository {
'default' => 'ASC',
'validation' => v::stringType()->in( [ 'ASC', 'DESC' ] ),
],
'default_displayed_fields' => [
'default_displayed_fields' => [
'map' => 'meta',
'title' => __( 'Default Displayed Fields', 'tainacan' ),
'type' => 'array/object/string',
@ -128,14 +128,14 @@ class Collections extends Repository {
'description' => __( 'List of collections property that will be displayed in the table view.', 'tainacan' ),
//'validation' => v::stringType(),
],
'default_view_mode' => [
'default_view_mode' => [
'map' => 'meta',
'title' => __( 'Default view mode', 'tainacan' ),
'type' => 'string',
'description' => __( 'Collection default visualization mode', 'tainacan' ),
//'validation' => v::stringType(),
],
'fields_order' => [
'fields_order' => [
'map' => 'meta',
'title' => __( 'Ordination fields', 'tainacan' ),
'type' => 'array/object/string',
@ -143,7 +143,7 @@ class Collections extends Repository {
'description' => __( 'Collection fields ordination', 'tainacan' ),
//'validation' => v::stringType(),
],
'filters_order' => [
'filters_order' => [
'map' => 'meta',
'title' => __( 'Ordination filters', 'tainacan' ),
'type' => 'array/object/string',
@ -151,40 +151,45 @@ class Collections extends Repository {
'description' => __( 'Collection filters ordination', 'tainacan' ),
//'validation' => v::stringType(),
],
'enable_cover_page' => [
'map' => 'meta',
'title' => __('Enable Cover Page', 'tainacan'),
'type' => 'string',
'description'=> __('Use page as the home page of this collection', 'tainacan'),
'on_error' => __('Value should be yes or no', 'tainacan'),
'validation' => v::stringType()->in(['yes', 'no']), // yes or no
'default' => 'no'
],
'cover_page_id' => [
'map' => 'meta',
'title' => __('Cover Page ID', 'tainacan'),
'type' => 'string',
'description'=> __('The page to be used as cover for this collection', 'tainacan'),
'on_error' => __('Invalid page', 'tainacan'),
//'validation' => v::numeric(),
'default' => ''
],
'header_image_id' => [
'map' => 'meta',
'title' => __('Header Image', 'tainacan'),
'type' => 'string',
'description'=> __('The image to be used in collection header', 'tainacan'),
'on_error' => __('Invalid image', 'tainacan'),
//'validation' => v::numeric(),
'default' => ''
],
'moderators_ids' => [
'enable_cover_page' => [
'map' => 'meta',
'title' => __( 'Enable Cover Page', 'tainacan' ),
'type' => 'string',
'description' => __( 'Use page as the home page of this collection', 'tainacan' ),
'on_error' => __( 'Value should be yes or no', 'tainacan' ),
'validation' => v::stringType()->in( [ 'yes', 'no' ] ), // yes or no
'default' => 'no'
],
'cover_page_id' => [
'map' => 'meta',
'title' => __( 'Cover Page ID', 'tainacan' ),
'type' => 'string',
'description' => __( 'The page to be used as cover for this collection', 'tainacan' ),
'on_error' => __( 'Invalid page', 'tainacan' ),
//'validation' => v::numeric(),
'default' => ''
],
'header_image_id' => [
'map' => 'meta',
'title' => __( 'Header Image', 'tainacan' ),
'type' => 'string',
'description' => __( 'The image to be used in collection header', 'tainacan' ),
'on_error' => __( 'Invalid image', 'tainacan' ),
//'validation' => v::numeric(),
'default' => ''
],
'moderators_ids' => [
'map' => 'meta_multi',
'title' => __( 'Moderators', 'tainacan' ),
'type' => 'array',
'description' => __( 'The IDs of users assigned as moderators of this collection', 'tainacan' ),
'validation' => ''
],
'featured_img_id' => [
'map' => 'meta',
'title' => __( 'Featured image ID', 'tainacan' ),
'description' => __( 'Featured image ID', 'tainacan' )
]
] );
}
@ -276,7 +281,7 @@ class Collections extends Repository {
$deleted = new Entities\Collection( wp_delete_post( $args[0], $args[1] ) );
if($deleted) {
do_action( 'tainacan-deleted', $deleted, $is_update = false, $is_delete_permanently = true );
do_action( 'tainacan-deleted', $deleted, [], false, true );
}
return $deleted;
@ -285,7 +290,7 @@ class Collections extends Repository {
$trashed = new Entities\Collection( wp_trash_post( $args[0] ) );
if($trashed) {
do_action( 'tainacan-trashed', $trashed, $is_update = false, $is_delete_permanently = false );
do_action( 'tainacan-trashed', $trashed, [], false, false, true );
}
return $trashed;

View File

@ -41,138 +41,148 @@ class Fields extends Repository {
public function get_map() {
return apply_filters('tainacan-get-map-'.$this->get_name(), [
'name' => [
'map' => 'post_title',
'title' => __('Name', 'tainacan'),
'type' => 'string',
'description'=> __('Name of the field', 'tainacan'),
'on_error' => __('The name should be a text value and not empty', 'tainacan'),
'validation' => v::stringType()->notEmpty(),
],
'slug' => [
'map' => 'post_name',
'title' => __('Slug', 'tainacan'),
'type' => 'string',
'description'=> __('A unique and santized string representation of the field', 'tainacan'),
//'validation' => v::stringType(),
],
'order' => [
'map' => 'menu_order',
'title' => __('Order', 'tainacan'),
'type' => 'string/integer',
'description'=> __('Field order. Field used if collections are manually ordered', 'tainacan'),
'on_error' => __('The menu order should be a numeric value', 'tainacan'),
//'validation' => v::numeric(),
],
'parent' => [
'map' => 'post_parent',
'title' => __('Parent', 'tainacan'),
'type' => 'integer',
'description'=> __('Parent field', 'tainacan'),
'default' => 0
//'on_error' => __('The Parent should be numeric value', 'tainacan'),
//'validation' => v::numeric(),
],
'description' => [
'map' => 'post_content',
'title' => __('Description', 'tainacan'),
'type' => 'string',
'description'=> __('The field description', 'tainacan'),
'default' => '',
//'on_error' => __('The description should be a text value', 'tainacan'),
//'validation' => v::stringType()->notEmpty(),
],
'field_type' => [
'map' => 'meta',
'title' => __('Type', 'tainacan'),
'type' => 'string',
'description'=> __('The field type', 'tainacan'),
'on_error' => __('Field type is empty', 'tainacan'),
'validation' => v::stringType()->notEmpty(),
],
'required' => [
'map' => 'meta',
'title' => __('Required', 'tainacan'),
'type' => 'string',
'description'=> __('The field is required', 'tainacan'),
'on_error' => __('Field required field is invalid', 'tainacan'),
'validation' => v::stringType()->in(['yes', 'no']), // yes or no
'default' => 'no'
],
'collection_key' => [
'map' => 'meta',
'title' => __('Collection key', 'tainacan'),
'type' => 'string',
'description'=> __('Field value should not be repeated', 'tainacan'),
'on_error' => __('Collection key is invalid', 'tainacan'),
'validation' => v::stringType()->in(['yes', 'no']), // yes or no
'default' => 'no'
],
'multiple' => [
'map' => 'meta',
'title' => __('Multiple', 'tainacan'),
'type' => 'string',
'description'=> __('Allow multiple fields for the field', 'tainacan'),
'on_error' => __('Multiple fields is invalid', 'tainacan'),
'validation' => v::stringType()->in(['yes', 'no']), // yes or no. It cant be multiple if its collection_key
'default' => 'no'
],
'cardinality' => [
'map' => 'meta',
'title' => __('Cardinality', 'tainacan'),
'type' => 'string/number',
'description'=> __('Number of multiples possible fields', 'tainacan'),
'on_error' => __('The number of fields not allowed', 'tainacan'),
'validation' => v::numeric()->positive(),
'default' => 1
],
'mask' => [
'map' => 'meta',
'title' => __('Mask', 'tainacan'),
'type' => 'string',
'description'=> __('The mask to be used in the field', 'tainacan'),
//'on_error' => __('Mask is invalid', 'tainacan'),
//'validation' => ''
],
'default_value' => [
'map' => 'meta',
'title' => __('Default value', 'tainacan'),
'type' => 'string',
'description'=> __('The value default fot the field', 'tainacan'),
],
'field_type_options' => [ // not showed in form
'map' => 'meta',
'title' => __('Field Type options', 'tainacan'),
'type' => 'array/object/string',
'items' => ['type' => 'array/string/integer/object'],
'description'=> __('Options specific for field type', 'tainacan'),
// 'validation' => ''
],
'collection_id' => [ // not showed in form
'map' => 'meta',
'title' => __('Collection', 'tainacan'),
'type' => 'integer/string',
'description'=> __('The collection ID', 'tainacan'),
//'validation' => ''
],
'accept_suggestion' => [
'map' => 'meta',
'title' => __('Field Value Accepts Suggestions', 'tainacan'),
'type' => 'bool',
'description'=> __('Allow the community suggest a different values for that field', 'tainacan'),
'default' => false,
'validation' => v::boolType()
],
'exposer_mapping' => [
'map' => 'meta',
'title' => __('exposer_mapping', 'tainacan'),
'type' => 'array',
'description'=> __('The field mapping options', 'tainacan'),
'on_error' => __('Invalid Field Mapping', 'tainacan'),
//'validation' => v::arrayType(),
'default' => []
],
]);
'name' => [
'map' => 'post_title',
'title' => __( 'Name', 'tainacan' ),
'type' => 'string',
'description' => __( 'Name of the field', 'tainacan' ),
'on_error' => __( 'The name should be a text value and not empty', 'tainacan' ),
'validation' => v::stringType()->notEmpty(),
],
'slug' => [
'map' => 'post_name',
'title' => __( 'Slug', 'tainacan' ),
'type' => 'string',
'description' => __( 'A unique and santized string representation of the field', 'tainacan' ),
//'validation' => v::stringType(),
],
'order' => [
'map' => 'menu_order',
'title' => __( 'Order', 'tainacan' ),
'type' => 'string/integer',
'description' => __( 'Field order. Field used if collections are manually ordered', 'tainacan' ),
'on_error' => __( 'The menu order should be a numeric value', 'tainacan' ),
//'validation' => v::numeric(),
],
'parent' => [
'map' => 'post_parent',
'title' => __( 'Parent', 'tainacan' ),
'type' => 'integer',
'description' => __( 'Parent field', 'tainacan' ),
'default' => 0
//'on_error' => __('The Parent should be numeric value', 'tainacan'),
//'validation' => v::numeric(),
],
'description' => [
'map' => 'post_content',
'title' => __( 'Description', 'tainacan' ),
'type' => 'string',
'description' => __( 'The field description', 'tainacan' ),
'default' => '',
//'on_error' => __('The description should be a text value', 'tainacan'),
//'validation' => v::stringType()->notEmpty(),
],
'field_type' => [
'map' => 'meta',
'title' => __( 'Type', 'tainacan' ),
'type' => 'string',
'description' => __( 'The field type', 'tainacan' ),
'on_error' => __( 'Field type is empty', 'tainacan' ),
'validation' => v::stringType()->notEmpty(),
],
'required' => [
'map' => 'meta',
'title' => __( 'Required', 'tainacan' ),
'type' => 'string',
'description' => __( 'The field is required', 'tainacan' ),
'on_error' => __( 'Field required field is invalid', 'tainacan' ),
'validation' => v::stringType()->in( [ 'yes', 'no' ] ), // yes or no
'default' => 'no'
],
'collection_key' => [
'map' => 'meta',
'title' => __( 'Collection key', 'tainacan' ),
'type' => 'string',
'description' => __( 'Field value should not be repeated', 'tainacan' ),
'on_error' => __( 'Collection key is invalid', 'tainacan' ),
'validation' => v::stringType()->in( [ 'yes', 'no' ] ), // yes or no
'default' => 'no'
],
'multiple' => [
'map' => 'meta',
'title' => __( 'Multiple', 'tainacan' ),
'type' => 'string',
'description' => __( 'Allow multiple fields for the field', 'tainacan' ),
'on_error' => __( 'Multiple fields is invalid', 'tainacan' ),
'validation' => v::stringType()->in( [ 'yes', 'no' ] ),
// yes or no. It cant be multiple if its collection_key
'default' => 'no'
],
'cardinality' => [
'map' => 'meta',
'title' => __( 'Cardinality', 'tainacan' ),
'type' => 'string/number',
'description' => __( 'Number of multiples possible fields', 'tainacan' ),
'on_error' => __( 'The number of fields not allowed', 'tainacan' ),
'validation' => v::numeric()->positive(),
'default' => 1
],
'mask' => [
'map' => 'meta',
'title' => __( 'Mask', 'tainacan' ),
'type' => 'string',
'description' => __( 'The mask to be used in the field', 'tainacan' ),
//'on_error' => __('Mask is invalid', 'tainacan'),
//'validation' => ''
],
'default_value' => [
'map' => 'meta',
'title' => __( 'Default value', 'tainacan' ),
'type' => 'string',
'description' => __( 'The value default fot the field', 'tainacan' ),
],
'field_type_options' => [ // not showed in form
'map' => 'meta',
'title' => __( 'Field Type options', 'tainacan' ),
'type' => 'array/object/string',
'items' => [ 'type' => 'array/string/integer/object' ],
'description' => __( 'Options specific for field type', 'tainacan' ),
// 'validation' => ''
],
'collection_id' => [ // not showed in form
'map' => 'meta',
'title' => __( 'Collection', 'tainacan' ),
'type' => 'integer/string',
'description' => __( 'The collection ID', 'tainacan' ),
//'validation' => ''
],
'accept_suggestion' => [
'map' => 'meta',
'title' => __( 'Field Value Accepts Suggestions', 'tainacan' ),
'type' => 'bool',
'description' => __( 'Allow the community suggest a different values for that field', 'tainacan' ),
'default' => false,
'validation' => v::boolType()
],
'exposer_mapping' => [
'map' => 'meta',
'title' => __( 'exposer_mapping', 'tainacan' ),
'type' => 'array/object/string',
'items' => [ 'type' => 'array/string/integer/object' ],
'description' => __( 'The field mapping options', 'tainacan' ),
'on_error' => __( 'Invalid Field Mapping', 'tainacan' ),
//'validation' => v::arrayType(),
'default' => []
],
'display' => [
'map' => 'meta',
'title' => __( 'Display', 'tainacan' ),
'type' => __( 'string' ),
'validation' => v::stringType()->in( [ 'yes', 'no', 'never' ] ),
'description' => __( 'Display by default on listing or not display or never display.', 'tainacan' ),
'default' => 'yes'
]
] );
}
/**
@ -454,7 +464,7 @@ class Fields extends Repository {
$deleted = new Entities\Field( wp_trash_post( $field_id ) );
if($deleted) {
do_action( 'tainacan-deleted', $deleted, $is_update = false, $is_delete_permanently = true );
do_action( 'tainacan-deleted', $deleted, [], false, true );
}
return $deleted;

View File

@ -190,7 +190,7 @@ class Filters extends Repository {
$deleted = new Entities\Filter(wp_delete_post($args[0], $args[1]));
if($deleted){
do_action('tainacan-deleted', $deleted, $is_update = false, $is_delete_permanently = true);
do_action('tainacan-deleted', $deleted, [], false, true);
}
return $deleted;
@ -200,7 +200,7 @@ class Filters extends Repository {
$trashed = new Entities\Filter(wp_trash_post($args[0]));
if($trashed){
do_action('tainacan-trashed', $trashed, $is_update = false, $is_delete_permanently = false);
do_action('tainacan-trashed', $trashed, [], false, false, true);
}
return $trashed;

View File

@ -28,84 +28,89 @@ class Items extends Repository {
}
public function get_map() {
return apply_filters( 'tainacan-get-map-' . $this->get_name(), [
'title' => [
'map' => 'post_title',
'title' => __( 'Title', 'tainacan' ),
'type' => 'string',
'description' => __( 'Title of the item', 'tainacan' ),
'on_error' => __( 'The title should be a text value and not empty', 'tainacan' ),
'validation' => v::stringType()->notEmpty(),
],
'status' => [
'map' => 'post_status',
'title' => __( 'Status', 'tainacan' ),
'type' => 'string',
'default' => 'draft',
'description' => __( 'The posts status', 'tainacan' )
],
'description' => [
'map' => 'post_content',
'title' => __( 'Description', 'tainacan' ),
'type' => 'string',
'description' => __( 'The item description', 'tainacan' ),
'default' => '',
'validation' => ''
],
'collection_id' => [
'map' => 'meta',
'title' => __( 'Collection', 'tainacan' ),
'type' => 'integer',
'description' => __( 'The collection ID', 'tainacan' ),
'validation' => ''
],
'author_id' => [
'map' => 'post_author',
'title' => __( 'Author', 'tainacan' ),
'type' => 'string',
'description' => __( 'The item author\'s user ID (numeric string)', 'tainacan' )
],
'creation_date' => [
'map' => 'post_date',
'title' => __( 'Creation Date', 'tainacan' ),
'type' => 'string',
'description' => __( 'The item creation date', 'tainacan' )
],
'modification_date' => [
'map' => 'post_modified',
'title' => __( 'Modification Date', 'tainacan' ),
'type' => 'string',
'description' => __( 'The item modification date', 'tainacan' )
],
'url' => [
'map' => 'guid',
'title' => __( 'Item URL', 'tainacan' ),
'type' => 'string',
'description' => __( 'The item URL', 'tainacan' )
],
'terms' => [
'map' => 'terms',
'title' => __( 'Term IDs', 'tainacan' ),
'type' => 'array',
'description' => __( 'The item term IDs', 'tainacan' ),
],
'document_type' => [
'map' => 'meta',
'title' => __('Document Type', 'tainacan'),
'type' => 'string',
'description'=> __('The document type, can be a local attachment, an external URL or a text', 'tainacan'),
'on_error' => __('Invalid document type', 'tainacan'),
'validation' => v::stringType()->in(['attachment', 'url', 'text']),
'default' => 'attachment'
],
'document' => [
'map' => 'meta',
'title' => __('Document', 'tainacan'),
'type' => 'string',
'description'=> __('The document itself. An ID in case of attachment, an URL in case of url or a text in the case of text', 'tainacan'),
'on_error' => __('Invalid document', 'tainacan'),
'default' => ''
],
return apply_filters( 'tainacan-get-map-' . $this->get_name(), [
'title' => [
'map' => 'post_title',
'title' => __( 'Title', 'tainacan' ),
'type' => 'string',
'description' => __( 'Title of the item', 'tainacan' ),
'on_error' => __( 'The title should be a text value and not empty', 'tainacan' ),
'validation' => v::stringType()->notEmpty(),
],
'status' => [
'map' => 'post_status',
'title' => __( 'Status', 'tainacan' ),
'type' => 'string',
'default' => 'draft',
'description' => __( 'The posts status', 'tainacan' )
],
'description' => [
'map' => 'post_content',
'title' => __( 'Description', 'tainacan' ),
'type' => 'string',
'description' => __( 'The item description', 'tainacan' ),
'default' => '',
'validation' => ''
],
'collection_id' => [
'map' => 'meta',
'title' => __( 'Collection', 'tainacan' ),
'type' => 'integer',
'description' => __( 'The collection ID', 'tainacan' ),
'validation' => ''
],
'author_id' => [
'map' => 'post_author',
'title' => __( 'Author', 'tainacan' ),
'type' => 'string',
'description' => __( 'The item author\'s user ID (numeric string)', 'tainacan' )
],
'creation_date' => [
'map' => 'post_date',
'title' => __( 'Creation Date', 'tainacan' ),
'type' => 'string',
'description' => __( 'The item creation date', 'tainacan' )
],
'modification_date' => [
'map' => 'post_modified',
'title' => __( 'Modification Date', 'tainacan' ),
'type' => 'string',
'description' => __( 'The item modification date', 'tainacan' )
],
'url' => [
'map' => 'guid',
'title' => __( 'Item URL', 'tainacan' ),
'type' => 'string',
'description' => __( 'The item URL', 'tainacan' )
],
'terms' => [
'map' => 'terms',
'title' => __( 'Term IDs', 'tainacan' ),
'type' => 'array',
'description' => __( 'The item term IDs', 'tainacan' ),
],
'document_type' => [
'map' => 'meta',
'title' => __( 'Document Type', 'tainacan' ),
'type' => 'string',
'description' => __( 'The document type, can be a local attachment, an external URL or a text', 'tainacan' ),
'on_error' => __( 'Invalid document type', 'tainacan' ),
'validation' => v::stringType()->in( [ 'attachment', 'url', 'text' ] ),
'default' => 'attachment'
],
'document' => [
'map' => 'meta',
'title' => __( 'Document', 'tainacan' ),
'type' => 'string',
'description' => __( 'The document itself. An ID in case of attachment, an URL in case of url or a text in the case of text', 'tainacan' ),
'on_error' => __( 'Invalid document', 'tainacan' ),
'default' => ''
],
'featured_img_id' => [
'map' => 'meta',
'title' => __( 'Featured image ID', 'tainacan' ),
'description' => __( 'Featured image ID', 'tainacan' )
]
] );
}
@ -220,10 +225,9 @@ class Items extends Repository {
$collections_objects[] = $col;
}
}
}
foreach ( $collections_objects as $collection ) {
foreach ( $collections_objects as $collection ) {
/**
* If no specific status is defined in the query, WordPress will fetch
* public items and private items for users withe the correct permission.
@ -295,7 +299,7 @@ class Items extends Repository {
$deleted = new Entities\Item( wp_delete_post( $args[0], $args[1] ) );
if($deleted) {
do_action( 'tainacan-deleted', $deleted, $is_update = false, $is_delete_permanently = true );
do_action( 'tainacan-deleted', $deleted, false, true );
}
return $deleted;
@ -304,7 +308,7 @@ class Items extends Repository {
$trashed = new Entities\Item( wp_trash_post( $args[0] ) );
if($trashed) {
do_action( 'tainacan-trashed', $trashed, $is_update = false, $is_delete_permanently = false );
do_action( 'tainacan-trashed', $trashed, [], false, false, true );
}
return $trashed;

View File

@ -28,12 +28,11 @@ class Logs extends Repository {
protected function __construct() {
parent::__construct();
add_action( 'tainacan-insert', array( $this, 'insert_log' ), 10, 4 );
add_action( 'tainacan-deleted', array( $this, 'insert_log'), 10, 4 );
add_action( 'tainacan-trashed', array( $this, 'insert_log'), 10, 4 );
add_action( 'tainacan-insert', array( $this, 'insert_log' ), 10, 5 );
add_action( 'tainacan-deleted', array( $this, 'insert_log'), 10, 5 );
add_action( 'tainacan-trashed', array( $this, 'insert_log'), 10, 5 );
add_action( 'add_attachment', array( $this, 'prepare_attachment_log_before_insert' ), 10 );
add_action( 'attachment_updated', array( $this, 'prepare_attachment_log_before_insert' ), 10, 3);
}
public function get_map() {
@ -110,8 +109,9 @@ class Logs extends Repository {
'validation' => ''
],
'log_diffs' => [
'map' => 'meta',
'title' => __( 'Log differences', 'tainacan' ),
'map' => 'meta',
'title' => __( 'Log differences', 'tainacan' ),
'description' => __( 'Differences between old and new versions of object', 'tainacan' )
]
] );
}
@ -223,51 +223,46 @@ class Logs extends Repository {
}
public function prepare_attachment_log_before_insert( $post_ID, $post_after = null, $post_before = null ) {
public function prepare_attachment_log_before_insert( $post_ID ) {
$attachment = get_post( $post_ID );
$post = $attachment->post_parent;
if ( ! $post_after && ! $post_before ) {
// is add attachment
$attachment = get_post( $post_ID );
$post = $attachment->post_parent;
if ( $post ) {
// was added attachment on a tainacan object
if ( $post ) {
// was added attachment on a tainacan object
$tainacan_post = Repository::get_entity_by_post( $post );
$tainacan_post = Repository::get_entity_by_post( $post );
if($tainacan_post) {
// was added a normal attachment
if($tainacan_post) {
// was added a normal attachment
// get all attachments except the new
$old_attachments = $tainacan_post->get_attachments( $post_ID );
foreach ( $old_attachments as $attachment ) {
unset( $attachment['id'] );
}
$new_attachments[] = [
'title' => $attachment->post_title,
'description' => $attachment->post_content,
'mime_type' => $attachment->post_mime_type,
'url' => $attachment->guid,
];
$array_diff_with_index = array_map( 'unserialize',
array_diff_assoc( array_map( 'serialize', $new_attachments ), array_map( 'serialize', $old_attachments ) ) );
$diff['attachments'] = [
'new' => $new_attachments,
'old' => $old_attachments,
'diff_with_index' => $array_diff_with_index
];
$this->insert_log( $tainacan_post, $diff, true );
// get all attachments except the new
$old_attachments = $tainacan_post->get_attachments( $post_ID );
foreach ( $old_attachments as $index => $a ) {
unset( $old_attachments[$index]['id'] );
}
$new_attachments[] = [
'title' => $attachment->post_title,
'description' => $attachment->post_content,
'mime_type' => $attachment->post_mime_type,
'url' => $attachment->guid,
];
$array_diff_with_index = array_map( 'unserialize',
array_diff_assoc( array_map( 'serialize', $new_attachments ), array_map( 'serialize', $old_attachments ) ) );
$diff['attachments'] = [
'new' => $new_attachments,
'old' => $old_attachments,
'diff_with_index' => $array_diff_with_index
];
$this->insert_log( $tainacan_post, $diff, true );
}
} else {
// TODO: Save a log when a attachment is updated
}
}
/**
@ -275,15 +270,17 @@ class Logs extends Repository {
*
* @param Entity $new_value
* @param array $diffs
* @param null $is_update
* @param bool $is_update
*
* @param bool $is_delete
* @param bool $is_trash
*
* @return Entities\Log new created log
*/
public function insert_log( $new_value, $diffs = [], $is_update = null, $is_delete_permanently = null ) {
$msn = "";
$description = "";
public function insert_log( $new_value, $diffs = [], $is_update = false, $is_delete = false, $is_trash = false ) {
$msn = null;
$description = null;
// TODO: Continue with is_delete_permanently
if ( is_object( $new_value ) ) {
// do not log a log
if ( ( method_exists( $new_value, 'get_post_type' ) && $new_value->get_post_type() === 'tainacan-log' ) || $new_value->get_status() === 'auto-draft' ) {
@ -308,51 +305,80 @@ class Logs extends Repository {
$name = $new_value->get_status();
}
$articleA = 'A';
$articleAn = 'An';
$vowels = 'aeiou';
if ( $is_update ) {
if ( substr_count( $vowels, strtolower( substr( $class_name, 0, 1 ) ) ) > 0 ) {
$msn = sprintf( __( '%s %s has been updated.', 'tainacan' ), $articleAn, $class_name );
} else {
$msn = sprintf( __( '%s %s has been updated.', 'tainacan' ), $articleA, $class_name );
}
$description = sprintf( __( "The \"%s\" %s has been updated.", 'tainacan' ), $name, strtolower( $class_name ) );
} else {
if ( substr_count( $vowels, strtolower( substr( $class_name, 0, 1 ) ) ) > 0 ) {
$msn = sprintf( __( '%s %s has been created.', 'tainacan' ), $articleAn, $class_name );
} else {
$msn = sprintf( __( '%s %s has been created.', 'tainacan' ), $articleA, $class_name );
}
$msn = $this->prepare_event_message($class_name, 'updated');
$description = $this->prepare_description_message($new_value, $name, $class_name, 'updated');
} elseif( $is_delete ){
// was deleted
$msn = $this->prepare_event_message($class_name, 'deleted');
$description = $this->prepare_description_message($new_value, $name, $class_name, 'deleted');
} elseif( !empty($diffs) ) {
// was created
$msn = $this->prepare_event_message($class_name, 'created');
$description = $this->prepare_description_message($new_value, $name, $class_name, 'created');
if ( $new_value instanceof Entities\Field ) {
$collection = $new_value->get_collection();
$parent = $collection;
if ( $collection ) {
$parent = $collection->get_name();
if ( ! $parent ) {
$parent = $collection->get_status();
}
}
$description = sprintf( __( "The \"%s\" %s has been created on %s.", 'tainacan' ), $name, strtolower( $class_name ), $parent );
} else {
$description = sprintf( __( "The \"%s\" %s has been created.", 'tainacan' ), $name, strtolower( $class_name ) );
}
} elseif( $is_trash ) {
// was trashed
$msn = $this->prepare_event_message($class_name, 'trashed');
$description = $this->prepare_description_message($new_value, $name, $class_name, 'trashed');
}
$msn = apply_filters( 'tainacan-insert-log-message-title', $msn, $type, $new_value );
$description = apply_filters( 'tainacan-insert-log-description', $description, $type, $new_value );
}
$msn = apply_filters( 'tainacan-insert-log-message-title', $msn, $type, $new_value );
$description = apply_filters( 'tainacan-insert-log-description', $description, $type, $new_value );
if ( ! empty( $diffs ) ) {
if ( ! empty( $diffs ) || $is_delete || $is_trash ) {
return Entities\Log::create( $msn, $description, $new_value, $diffs );
}
}
private function prepare_event_message($class_name, $action_message){
$articleA = 'A';
$articleAn = 'An';
$vowels = 'aeiou';
if ( substr_count( $vowels, strtolower( substr( $class_name, 0, 1 ) ) ) > 0 ) {
$msn = sprintf( __( '%s %s has been %s.', 'tainacan' ), $articleAn, $class_name, $action_message );
} else {
$msn = sprintf( __( '%s %s has been %s.', 'tainacan' ), $articleA, $class_name, $action_message );
}
return $msn;
}
/**
* This will prepare the event description for objects
*
* @param $object
* @param $name
* @param $class_name
*
* @param $action_message
*
* @return string
*/
private function prepare_description_message($object, $name, $class_name, $action_message){
if ( $object instanceof Entities\Field || $object instanceof Entities\Item || $object instanceof Entities\Filter) {
$collection = $object->get_collection();
$parent = $collection;
if ( $collection ) {
$parent = $collection->get_name();
if ( ! $parent ) {
$parent = $collection->get_status();
}
}
$description = sprintf( __( "The \"%s\" %s has been %s (parent %s).", 'tainacan' ), $name, strtolower( $class_name ), $action_message, $parent );
} else {
$description = sprintf( __( "The \"%s\" %s has been %s.", 'tainacan' ), $name, strtolower( $class_name ), $action_message );
}
return $description;
}
/**
*
* @param Entities\Log $log
@ -366,11 +392,13 @@ class Logs extends Repository {
/** @var Entity $value * */
$value = $log->get_value();
//$value->set_status('publish'); // TODO check if publish the entity on approve
$value->set_status('publish'); // TODO check if publish the entity on approve
$repository = self::get_repository( $value );
return $repository->insert( $value );
if($value->validate()) {
return $repository->insert( $value );
}
}
return false;

View File

@ -117,7 +117,6 @@ abstract class Repository {
}
$post_t = $collection->get_db_identifier();
$obj->WP_Post->post_type = $post_t;
}
@ -134,44 +133,9 @@ abstract class Repository {
}
}
if ( method_exists( $obj, 'get_featured_img_id' ) ) {
if ( ! get_post_thumbnail_id( $obj->WP_Post->ID ) ) {
// was added a thumbnail
$diffs = $this->insert_thumbnail( $obj, $diffs );
$settled = set_post_thumbnail( $obj->WP_Post, $obj->get_featured_img_id( $obj->WP_Post->ID ) );
if ( $settled ) {
$thumbnail_url = get_the_post_thumbnail_url( $obj->WP_Post->ID );
$diffs['featured_image'] = [
'new' => $thumbnail_url,
'old' => '',
'diff_with_index' => 0,
];
}
} else {
// was update a thumbnail
$old_thumbnail = get_the_post_thumbnail_url( $obj->WP_Post->ID );
$settled = set_post_thumbnail( $obj->WP_Post, $obj->get_featured_img_id( $obj->WP_Post->ID ) );
if ( $settled ) {
$thumbnail_url = get_the_post_thumbnail_url( $obj->WP_Post->ID );
$diffs['featured_image'] = [
'new' => $thumbnail_url,
'old' => $old_thumbnail,
'diff_with_index' => 0,
];
}
}
}
// TODO: Logs for header image insert and update
do_action( 'tainacan-insert', $obj, $diffs, $is_update );
do_action( 'tainacan-insert-' . $obj->get_post_type(), $obj );
@ -681,7 +645,12 @@ abstract class Repository {
$old_entity = new $entity_type; // there is no saved entity, let compare with a new empty one
}
} else {
$old_entity = $old;
if($old->get_status() === 'auto-draft'){
$entity_type = get_class( $new );
$old_entity = new $entity_type;
} else {
$old_entity = $old;
}
}
$new_entity = $new;
@ -691,6 +660,7 @@ abstract class Repository {
$diff = [];
foreach ( $map as $prop => $mapped ) {
// I can't verify differences on item, because it attributes are added when item is a auto-draft
if ( $old_entity->get_mapped_property( $prop ) != $new_entity->get_mapped_property( $prop ) ) {
if ( $mapped['map'] === 'meta_multi' || ( $mapped['map'] === 'meta' && is_array( $new_entity->get_mapped_property( $prop ) ) ) ) {
@ -729,11 +699,66 @@ abstract class Repository {
}
}
unset($diff['id'], $diff['collection_id'], $diff['author_id'], $diff['creation_date'], $diff['featured_img_id']);
$diff = apply_filters( 'tainacan-entity-diff', $diff, $new, $old );
return $diff;
}
/**
* @param $obj
* @param $diffs
*
* @return mixed
*/
protected function insert_thumbnail( $obj, $diffs ) {
if ( method_exists( $obj, 'get_featured_img_id' ) ) {
if ( ! get_post_thumbnail_id( $obj->WP_Post->ID ) ) {
// was added a thumbnail
$settled = set_post_thumbnail( $obj->WP_Post, (int) $obj->get_featured_img_id() );
if ( $settled ) {
$thumbnail_url = get_the_post_thumbnail_url( $obj->WP_Post->ID );
$diffs['featured_image'] = [
'new' => $thumbnail_url,
'old' => '',
'diff_with_index' => 0,
];
}
} else {
// was update a thumbnail
$old_thumbnail = get_the_post_thumbnail_url( $obj->WP_Post->ID );
$fid = $obj->get_featured_img_id();
if ( ! $fid ) {
$settled = delete_post_thumbnail( $obj->WP_Post );
} else {
$settled = set_post_thumbnail( $obj->WP_Post, (int) $fid );
}
if ( $settled ) {
$thumbnail_url = get_the_post_thumbnail_url( $obj->WP_Post->ID );
$diffs['featured_image'] = [
'new' => $thumbnail_url,
'old' => $old_thumbnail,
'diff_with_index' => 0,
];
}
}
}
return $diffs;
}
}
?>

View File

@ -199,7 +199,7 @@ class Taxonomies extends Repository {
return $deleted;
}
do_action('tainacan-deleted', $deleted, $is_update = false, $is_delete_permanently = true);
do_action('tainacan-deleted', $deleted, [], false, true);
return $deleted;
}
@ -210,7 +210,7 @@ class Taxonomies extends Repository {
return $trashed;
}
do_action('tainacan-trashed', $trashed, $diffs = [], $is_update = false, $is_delete_permanently = false );
do_action('tainacan-trashed', $trashed, [], false, false, true );
return $trashed;
}

View File

@ -15,85 +15,84 @@ class Terms extends Repository {
private static $instance = null;
public static function get_instance()
{
if(!isset(self::$instance))
{
self::$instance = new self();
}
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
return self::$instance;
}
protected function __construct()
{
parent::__construct();
}
protected function __construct() {
parent::__construct();
}
public function get_map() {
return apply_filters('tainacan-get-map-'.$this->get_name(), [
'term_id' => [
'map' => 'term_id',
'title' => __('ID', 'tainacan'),
'type' => 'integer',
'description'=> __('Unique identifier', 'tainacan'),
//'validation' => ''
],
'name' => [
'map' => 'name',
'title' => __('Name', 'tainacan'),
'type' => 'string',
'description'=> __('Name of the term', 'tainacan'),
'on_error' => __('The name is empty', 'tainacan'),
'validation' => v::stringType()->notEmpty(),
],
'parent' => [
'map' => 'parent',
'title' => __('Parent', 'tainacan'),
'type' => 'integer',
'description'=> __('The parent of the term', 'tainacan'),
'default' => 0,
'validation' => ''
],
'description' => [
'map' => 'description',
'title' => __('Description', 'tainacan'),
'type' => 'string',
'description'=> __('The term description', 'tainacan'),
'default' => '',
'validation' => ''
],
'taxonomy' => [
'map' => 'taxonomy',
'title' => __('Taxonomy', 'tainacan'),
'type' => 'string',
'description'=> __('The term taxonomy', 'tainacan'),
'on_error' => __('The taxonomy is empty', 'tainacan'),
'validation' => v::stringType()->notEmpty(),
],
'user' => [
'map' => 'termmeta',
'title' => __('User', 'tainacan'),
'type' => 'integer',
'description'=> __('The term creator', 'tainacan'),
'on_error' => __('The user is empty or invalid', 'tainacan'),
'default' => get_current_user_id(),
'validation' => v::numeric(),
],
'header_image_id' => [
'map' => 'termmeta',
'title' => __('Header Image', 'tainacan'),
'type' => 'string',
'description'=> __('The image to be used in term header', 'tainacan'),
'on_error' => __('Invalid image', 'tainacan'),
//'validation' => v::numeric(),
'default' => ''
],
'hide_empty' => [
'map' => 'hide_empty',
'type' => 'bool'
return apply_filters( 'tainacan-get-map-' . $this->get_name(), [
'term_id' => [
'map' => 'term_id',
'title' => __( 'ID', 'tainacan' ),
'type' => 'integer',
'description' => __( 'Unique identifier', 'tainacan' ),
//'validation' => ''
],
'name' => [
'map' => 'name',
'title' => __( 'Name', 'tainacan' ),
'type' => 'string',
'description' => __( 'Name of the term', 'tainacan' ),
'on_error' => __( 'The name is empty', 'tainacan' ),
'validation' => v::stringType()->notEmpty(),
],
'parent' => [
'map' => 'parent',
'title' => __( 'Parent', 'tainacan' ),
'type' => 'integer',
'description' => __( 'The parent of the term', 'tainacan' ),
'default' => 0,
'validation' => ''
],
'description' => [
'map' => 'description',
'title' => __( 'Description', 'tainacan' ),
'type' => 'string',
'description' => __( 'The term description', 'tainacan' ),
'default' => '',
'validation' => ''
],
'taxonomy' => [
'map' => 'taxonomy',
'title' => __( 'Taxonomy', 'tainacan' ),
'type' => 'string',
'description' => __( 'The term taxonomy', 'tainacan' ),
'on_error' => __( 'The taxonomy is empty', 'tainacan' ),
'validation' => v::stringType()->notEmpty(),
],
'user' => [
'map' => 'termmeta',
'title' => __( 'User', 'tainacan' ),
'type' => 'integer',
'description' => __( 'The term creator', 'tainacan' ),
'on_error' => __( 'The user is empty or invalid', 'tainacan' ),
'default' => get_current_user_id(),
'validation' => v::numeric(),
],
'header_image_id' => [
'map' => 'termmeta',
'title' => __( 'Header Image', 'tainacan' ),
'type' => 'string',
'description' => __( 'The image to be used in term header', 'tainacan' ),
'on_error' => __( 'Invalid image', 'tainacan' ),
//'validation' => v::numeric(),
'default' => ''
],
'hide_empty' => [
'map' => 'hide_empty',
'title' => __( 'Hide empty', 'tainacan' ),
'type' => 'bool',
'description' => __( 'Hide empty terms', 'tainacan' )
]
]);
] );
}
public function get_default_properties($map) {
@ -239,7 +238,7 @@ class Terms extends Repository {
if($deleted) {
$deleted_term_tainacan = new Entities\Term($args[0], $args[1]);
do_action( 'tainacan-deleted', $deleted_term_tainacan, $is_update = false, $is_delete_permanently = true );
do_action( 'tainacan-deleted', $deleted_term_tainacan, [], false, true );
}
return $deleted;

View File

@ -27,8 +27,6 @@ class DevInterface {
add_action('save_post', array(&$this, 'save_post'), 10, 2);
add_action('admin_enqueue_scripts', array(&$this, 'add_admin_js'));
add_filter('post_type_link', array(&$this, 'permalink_filter'), 10, 3);
$Tainacan_Collections = \Tainacan\Repositories\Collections::get_instance();
$Tainacan_Filters = \Tainacan\Repositories\Filters::get_instance();
$Tainacan_Logs = \Tainacan\Repositories\Logs::get_instance();
@ -62,34 +60,6 @@ class DevInterface {
wp_localize_script( 'tainacan-dev-admin', 'tainacan_plugin', $settings );
}
/**
* Filters the permalink for posts to:
*
* * Replace Collectino single permalink with the link to the post type archive for items of that collection
*
* @return string new permalink
*/
function permalink_filter($permalink, $post, $leavename) {
$collection_post_type = \Tainacan\Entities\Collection::get_post_type();
if (!is_admin() && $post->post_type == $collection_post_type) {
$collection = new \Tainacan\Entities\Collection($post);
$items_post_type = $collection->get_db_identifier();
$post_type_object = get_post_type_object($items_post_type);
if (isset($post_type_object->rewrite) && is_array($post_type_object->rewrite) && isset($post_type_object->rewrite['slug']))
return site_url($post_type_object->rewrite['slug']);
}
return $permalink;
}
/**
* Run through all post types attributes and add metaboxes for them.

View File

@ -401,19 +401,18 @@ abstract class Importer {
}
}
$item->set_status('publish' );
$insertedItem->set_status('publish' );
// inserted the id on processed item with its index as array index
$this->processed_items[ $index ] = $item->get_id();
if($item->validate()) {
$Tainacan_Items->update( $item );
$this->processed_items[ $index ] = $insertedItem->get_id();
if($insertedItem->validate()) {
$insertedItem = $Tainacan_Items->update( $insertedItem );
} else {
$this->add_log( 'error', 'Item ' . $index . ': ' ); // TODO add the $item->get_errors() array
$this->add_log( 'error', 'Item ' . $index . ': ' . $insertedItem->get_errors()[0]['title'] ); // TODO add the $item->get_errors() array
return false;
}
return $item;
return $insertedItem;
} else {
$this->add_log( 'error', 'Collection not set');
return false;

View File

@ -11,7 +11,31 @@ namespace Tainacan\Importer;
class Old_Tainacan extends Importer
{
public function __construct($import_structure_and_mapping = false) {
public $avoid = [
'ID',
'post_author',
'post_date',
'post_date_gmt',
/*'post_content',
'post_title',*/
'post_excerpt',
'post_status',
'comment_status',
'ping_status',
'post_name',
'post_modified',
'post_modified_gmt',
'post_content_filtered',
'post_parent',
'guid',
'comment_count',
'filter',
'link',
'thumbnail'
];
public function __construct($import_structure_and_mapping = false)
{
parent::__construct();
$this->remove_import_method('file');
@ -49,18 +73,33 @@ class Old_Tainacan extends Importer
if(!empty($link))
{
$items = wp_remote_get( $link."/items/?includeMetadata=1" );
$info = wp_remote_get( $link."/items/?includeMetadata=1" );
$info = json_decode($info['body']);
$count_total_pages = ceil($info->found_items / $info->items_per_page);
if(isset($items['body']))
$items_json = wp_remote_get( $link."/items/?includeMetadata=1&filter[page]=1" );
if(isset($items_json['body']))
{
$items_array = json_decode($items['body']);
$file = fopen( $this->get_id().'.txt', 'w' );
fwrite( $file, serialize($items_array));
fclose( $file );
return $this->set_file( $this->get_id().'.txt' );
$items = json_decode($items_json['body']);
for ($i = 2; $i <= $count_total_pages; $i++)
{
$part = wp_remote_get($link . "/items/?includeMetadata=1&filter[page]=".$i);
if(isset($part['body']))
{
$part_array = json_decode($part['body'])->items;
foreach ($part_array as $item)
{
$items->items[] = $item;
}
}
}
}
$file = fopen( $this->get_id().'.txt', 'w' );
fwrite( $file, serialize($items));
fclose( $file );
return $this->set_file( $this->get_id().'.txt' );
}
}
}
@ -78,8 +117,18 @@ class Old_Tainacan extends Importer
$item = $file_content->items[0];
$fields = array_keys((array)$item->item);
$fields = [];
//Default meta
foreach ($item->item as $meta_name => $value)
{
if(!in_array($meta_name, $this->avoid))
{
$fields[] = $meta_name;
}
}
//Added meta
foreach ($item->metadata as $metadata)
{
$fields[] = ['name' => $metadata->name, 'type' => $metadata->type];
@ -105,7 +154,6 @@ class Old_Tainacan extends Importer
// search the index in the file and get values
$file = new \SplFileObject( $this->tmp_file, 'r' );
$file_content = unserialize($file->fread($file->getSize()));
$values = $file_content->items[$index];
foreach ($headers as $header)
{
@ -147,31 +195,10 @@ class Old_Tainacan extends Importer
public function create_fields_and_mapping()
{
$Tainacan_Fields = \Tainacan\Repositories\Fields::get_instance();
$fields_repository = \Tainacan\Repositories\Fields::get_instance();
$file_fields = $this->get_fields();
$avoid = [
/*'ID',
'post_author',
'post_date',
'post_date_gmt',
'post_content',
'post_title',
'post_excerpt',
'post_status',
'comment_status',
'ping_status',
'post_name',
'post_modified',
'post_modified_gmt',
'post_content_filtered',
'post_parent',
'guid',
'comment_count',
'filter',
'link',
'thumbnail'*/
];
foreach($file_fields as $index => $meta_info)
{
@ -186,7 +213,7 @@ class Old_Tainacan extends Importer
$type = 'Text';
}
if(!in_array($meta_name, $avoid))
if(!in_array($meta_name, $this->avoid))
{
$newField = new \Tainacan\Entities\Field();
@ -200,6 +227,16 @@ class Old_Tainacan extends Importer
$newField = $fields_repository->insert($newField);
$mapping[$newField->get_id()] = $file_fields[$index];
}else
{
$fields = $Tainacan_Fields->fetch_by_collection( $this->collection, [], 'OBJECT' ) ;
foreach ($fields as $field)
{
if($field->WP_Post->post_name === 'title' || $field->WP_Post->post_name === 'description')
{
$mapping[$field->get_id()] = $file_fields[$meta_name];
}
}
}
}
@ -209,7 +246,7 @@ class Old_Tainacan extends Importer
public function define_type($type)
{
$type = strtolower($type);
$tainacan_types = ['text', 'textarea', 'numerica', 'date'];
$tainacan_types = ['text', 'textarea', 'numeric', 'date'];
$types_to_work = ['item', 'tree'];
if(in_array($type, $tainacan_types))

View File

@ -62,7 +62,7 @@ export const fetchCollections = ({commit} , { page, collectionsPerPage }) => {
export const fetchCollection = ({ commit }, id) => {
commit('cleanCollection');
return new Promise((resolve, reject) =>{
axios.tainacan.get('/collections/' + id)
axios.tainacan.get('/collections/' + id + '?context=edit')
.then(res => {
let collection = res.data;
commit('setCollection', collection);
@ -103,7 +103,7 @@ export const deleteCollection = ({ commit }, id) => {
});
}
export const updateCollection = ({ commit }, { collection_id, name, description, slug, status, enable_cover_page, cover_page_id }) => {
export const updateCollection = ({ commit }, { collection_id, name, description, slug, status, enable_cover_page, cover_page_id, moderators_ids, parent }) => {
return new Promise((resolve, reject) => {
axios.tainacan.patch('/collections/' + collection_id, {
name: name,
@ -111,9 +111,21 @@ export const updateCollection = ({ commit }, { collection_id, name, description,
status: status,
slug: slug,
cover_page_id: "" + cover_page_id,
enable_cover_page: enable_cover_page
enable_cover_page: enable_cover_page,
moderators_ids: moderators_ids,
parent: parent
}).then( res => {
commit('setCollection', { id: collection_id, name: name, description: description, slug: slug, status: status, enable_cover_page: enable_cover_page, cover_page_id: cover_page_id });
commit('setCollection', {
id: collection_id,
name: name,
description: description,
slug: slug,
status: status,
enable_cover_page: enable_cover_page,
cover_page_id: cover_page_id,
moderators_ids: moderators_ids.name,
parent: parent
});
resolve( res.data );
}).catch( error => {
reject({ error_message: error['response']['data'].error_message, errors: error['response']['data'].errors });
@ -194,10 +206,10 @@ export const updateThumbnail = ({ commit }, { collectionId, thumbnailId }) => {
});
};
export const updateCover = ({ commit }, { collectionId, coverId }) => {
export const updateHeaderImage = ({ commit }, { collectionId, headerImageId }) => {
return new Promise((resolve, reject) => {
axios.tainacan.patch('/collections/' + collectionId, {
cover_img_id: coverId
header_image_id: headerImageId + ''
}).then( res => {
let collection = res.data
commit('setCollection', collection);
@ -210,9 +222,9 @@ export const updateCover = ({ commit }, { collectionId, coverId }) => {
};
// Collection Cover Page
export const fetchPages = () => {
export const fetchPages = ({ commit }, search ) => {
return new Promise((resolve, reject) => {
axios.wp.get('/pages/')
axios.wp.get('/pages?search=' + search)
.then(res => {
let pages = res.data;
resolve( pages );
@ -234,4 +246,38 @@ export const fetchPage = ({ commit }, pageId ) => {
reject( error );
});
});
};
};
// Users for moderators configuration
export const fetchUsers = ({ commit }, { search, exceptions }) => {
let endpoint = '/users?search=' + search;
if (exceptions.length > 0)
endpoint += '&exclude=' + exceptions.toString();
return new Promise((resolve, reject) => {
axios.wp.get(endpoint)
.then(res => {
let users = res.data;
resolve( users );
})
.catch(error => {
reject( error );
});
});
};
// Fetch Collections for choosing Parent Collection
export const fetchCollectionsForParent = ({ commit }) => {
return new Promise((resolve, reject) =>{
axios.tainacan.get('/collections/?fetch_only[0]=name&fetch_only[1]=id')
.then(res => {
let collections = res.data;
resolve( collections );
})
.catch(error => {
reject(error);
})
});
}

View File

@ -1,11 +1,11 @@
import axios from '../../../axios/axios';
import qs from 'qs';
export const fetchFields = ({ commit }, {collectionId, isRepositoryLevel, isContextEdit }) => {
export const fetchFields = ({commit}, {collectionId, isRepositoryLevel, isContextEdit}) => {
return new Promise((resolve, reject) => {
let endpoint = '';
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/fields/';
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/fields/';
else
endpoint = '/fields/';
@ -14,116 +14,119 @@ export const fetchFields = ({ commit }, {collectionId, isRepositoryLevel, isCont
endpoint += '&context=edit';
axios.tainacan.get(endpoint)
.then((res) => {
let fields= res.data;
commit('setFields', fields);
resolve (fields);
})
.catch((error) => {
console.log(error);
reject(error);
});
.then((res) => {
let fields = res.data;
commit('setFields', fields);
resolve(fields);
})
.catch((error) => {
console.log(error);
reject(error);
});
});
}
};
export const sendField = ( { commit }, { collectionId, name, fieldType, status, isRepositoryLevel, newIndex }) => {
return new Promise(( resolve, reject ) => {
export const sendField = ({commit}, {collectionId, name, fieldType, status, isRepositoryLevel, newIndex}) => {
return new Promise((resolve, reject) => {
let endpoint = '';
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/fields/';
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/fields/';
else
endpoint = '/fields/';
axios.tainacan.post(endpoint + '?context=edit', {
name: name,
field_type: fieldType,
field_type: fieldType,
status: status
})
.then( res => {
.then(res => {
let field = res.data;
commit('setSingleField', { field: field, index: newIndex});
resolve( res.data );
commit('setSingleField', {field: field, index: newIndex});
resolve(res.data);
})
.catch(error => {
reject( error.response );
reject(error.response);
});
});
};
export const updateField = ( { commit }, { collectionId, fieldId, isRepositoryLevel, index, options }) => {
return new Promise(( resolve, reject ) => {
export const updateField = ({commit}, {collectionId, fieldId, isRepositoryLevel, index, options}) => {
return new Promise((resolve, reject) => {
let endpoint = '';
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/fields/' + fieldId;
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/fields/' + fieldId;
else
endpoint = '/fields/' + fieldId;
axios.tainacan.put(endpoint + '?context=edit', options)
.then( res => {
let field = res.data
commit('setSingleField', { field: field, index: index });
resolve( field );
.then(res => {
let field = res.data;
commit('setSingleField', {field: field, index: index});
resolve(field);
})
.catch(error => {
reject({ error_message: error['response']['data'].error_message, errors: error['response']['data'].errors });
reject({
error_message: error['response']['data'].error_message,
errors: error['response']['data'].errors
});
});
});
};
export const updateFields = ( { commit }, fields) => {
export const updateFields = ({commit}, fields) => {
commit('setFields', fields);
};
export const deleteField = ({ commit }, { collectionId, fieldId, isRepositoryLevel }) => {
export const deleteField = ({commit}, {collectionId, fieldId, isRepositoryLevel}) => {
let endpoint = '';
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/fields/' + fieldId;
if (!isRepositoryLevel)
endpoint = '/collection/' + collectionId + '/fields/' + fieldId;
else
endpoint = '/fields/' + fieldId;
return new Promise((resolve, reject) => {
axios.tainacan.delete(endpoint)
.then( res => {
commit('deleteField', res.data );
resolve( res.data );
}).catch((error) => {
console.log(error);
reject( error );
});
});
};
export const updateCollectionFieldsOrder = ({ commit, dispatch }, { collectionId, fieldsOrder }) => {
return new Promise((resolve, reject) => {
axios.tainacan.patch('/collections/' + collectionId, {
fields_order: fieldsOrder
}).then( res => {
// dispatch('collection/setCollection', res.data, {root: true});
resolve( res.data );
}).catch( error => {
reject( error.response );
});
});
}
export const fetchFieldTypes = ({ commit} ) => {
return new Promise((resolve, reject) => {
axios.tainacan.get('/field-types')
.then((res) => {
let fieldTypes = res.data;
commit('setFieldTypes', fieldTypes);
resolve (fieldTypes);
})
.catch((error) => {
.then(res => {
commit('deleteField', res.data);
resolve(res.data);
}).catch((error) => {
console.log(error);
reject(error);
});
});
};
export const updateCollectionFieldsOrder = ({commit, dispatch}, {collectionId, fieldsOrder}) => {
return new Promise((resolve, reject) => {
axios.tainacan.patch('/collections/' + collectionId, {
fields_order: fieldsOrder
}).then(res => {
// dispatch('collection/setCollection', res.data, {root: true});
resolve(res.data);
}).catch(error => {
reject(error.response);
});
});
}
export const fetchFieldTypes = ({commit}) => {
return new Promise((resolve, reject) => {
axios.tainacan.get('/field-types')
.then((res) => {
let fieldTypes = res.data;
commit('setFieldTypes', fieldTypes);
resolve(fieldTypes);
})
.catch((error) => {
console.log(error);
reject(error);
});
});
}
export const updateFieldTypes = ( { commit }, fieldTypes) => {
export const updateFieldTypes = ({commit}, fieldTypes) => {
commit('setFieldTypes', fieldTypes);
};

View File

@ -7,6 +7,8 @@ use Tainacan\Entities;
class Theme_Helper {
private static $instance = null;
public $visiting_collection_cover = false;
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
@ -161,6 +163,8 @@ class Theme_Helper {
global $wp_query;
$wp_query = new \WP_Query('page_id=' . $cover_page_id);
$this->visiting_collection_cover = $collection->get_id();
}
}

View File

@ -42,6 +42,8 @@ function tainacan_the_metadata($field = null, $hide_empty = true) {
function tainacan_get_collection_id() {
if ( is_post_type_archive() || is_single() ) {
return Repositories\Collections::get_instance()->get_id_by_db_identifier(get_post_type());
} elseif ( false !== \Tainacan\Theme_Helper::get_instance()->visiting_collection_cover ) {
return \Tainacan\Theme_Helper::get_instance()->visiting_collection_cover;
}
return false;
}

View File

@ -92,5 +92,50 @@ class CoreFieldTypes extends TAINACAN_UnitTestCase {
$this->assertEquals('changed description', $check_item_metadata->get_value());
}
function test_validate_required_title() {
$Tainacan_Item_Metadata = \Tainacan\Repositories\Item_Metadata::get_instance();
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
$Tainacan_Fields = \Tainacan\Repositories\Fields::get_instance();
$collection = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'test',
),
true
);
$i = $this->tainacan_entity_factory->create_entity(
'item',
array(
'description' => 'adasdasdsa',
'collection' => $collection,
'status' => 'draft'
),
true
);
$fields = $Tainacan_Fields->fetch_by_collection( $collection, [], 'OBJECT' ) ;
foreach ( $fields as $index => $field ){
if ( $field->get_field_type_object()->get_core() && $field->get_field_type_object()->get_related_mapped_prop() == 'title') {
$core_title = $field;
}
}
$item_metadata = new \Tainacan\Entities\Item_Metadata_Entity($i, $core_title);
$item_metadata->set_value('title');
$item_metadata->validate();
$Tainacan_Item_Metadata->insert($item_metadata);
$i->set_status('publish' );
$this->assertTrue($i->validate(), 'Item with empy title should validate because core title field has value');
}
}

View File

@ -228,13 +228,11 @@ class ImporterTests extends TAINACAN_UnitTestCase {
$this->assertEquals(2, $_SESSION['tainacan_importer'][$id]->run(), 'first step should import 2 items');
$this->assertEquals(4, $_SESSION['tainacan_importer'][$id]->run(), 'second step should import 2 items');
$this->assertEquals(5, $_SESSION['tainacan_importer'][$id]->run(), 'third step should import 3 items');
$this->assertEquals(5, $_SESSION['tainacan_importer'][$id]->run(), 'if call run again after finish, do nothing');
$items = $Tainacan_Items->fetch( [], $collection, 'OBJECT' );
$this->assertEquals( $_SESSION['tainacan_importer'][$id]->get_total_items(), count( $items ) );
}
/**
@ -243,7 +241,7 @@ class ImporterTests extends TAINACAN_UnitTestCase {
public function test_fetch_file(){
$csv_importer = new Importer\CSV();
$id = $csv_importer->get_id();
//$_SESSION['tainacan_importer'][$id]->fetch_from_remote( 'http://localhost/wordpress-test/wp-json' );
//$this->assertTrue( isset( $_SESSION['tainacan_importer'][$id]->tmp_file ) );
$_SESSION['tainacan_importer'][$id]->fetch_from_remote( 'http://localhost/wordpress-test/wp-json' );
$this->assertTrue( isset( $_SESSION['tainacan_importer'][$id]->tmp_file ) );
}
}

View File

@ -3,7 +3,7 @@ let webpack = require('webpack');
module.exports = {
entry: {
dev_admin: './src/js/main.js',
//dev_admin: './src/js/main.js',
user_search: './src/admin/js/theme-main.js',
user_admin: './src/admin/js/main.js'
},
@ -25,10 +25,7 @@ module.exports = {
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
// vue-loader options go here
}
loader: 'vue-loader'
},
{
test: /\.js$/,