Merge branch 'develop' into export

# Conflicts:
#	src/api/endpoints/class-tainacan-rest-export-controller.php
#	tests/test-api-export.php
This commit is contained in:
Jacson Passold 2018-05-15 18:33:16 -03:00
commit bfcefe1ed6
105 changed files with 11023 additions and 1756 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -28,8 +28,8 @@ These are the capabilities related to collection management.
| | Admin | Editor | Author | Collaborator |
|------------------------------|-------|--------|--------|--------------|
| Edit Collections | y | y | y | y |
| Delete Collections | y | y | y | y |
| Edit Collections | y | y | y | |
| Delete Collections | y | y | y | |
| Publish Collections | y | y | y | |
| Edit Published Collections | y | y | y | |
| Delete Published Collections | y | y | y | |
@ -42,7 +42,7 @@ These are the capabilities related to collection management.
#### Edit Collections
> Capability name: edit_tainacan-collections
Who's got it: Everyone but subscribers
Who's got it: Everyone but subscribers and colaborators
Allows to create and edit one's own collections details. Does not allow to publish them.
@ -77,7 +77,7 @@ Allows to publish one's own collections.
#### Delete Collections
> Capability name: delete_tainacan-collections
Who's got it: Everyone but subscribers
Who's got it: Everyone but subscribers and colaborators
Allows to delete one's own collections.

19
docs/search-engine.md Normal file
View File

@ -0,0 +1,19 @@
# Search engine
In addition to the faceted search, which allows users to filter items by specific metadata, Tainacan also offers a free textual search.
By default, when using this option to search, WordPress searches only inside the Title (post_title) and Description (post_content). This, of course, is very limited, and this article presents and discusses the approach Tainacan will take to face this issue.
There is'nt one silver bullet to solve this problem. In some cases, perhaps for small repositories, a simple change in the way WordPress queries for posts, including relation to metadata and taxonomies, can give users the results they were looking for. In other cases, repository managers may want to use sophisticated solutions such as Elastic Search or Solr to enable Full Text Search for their users.
An intermediary approach could be creating index tables and tokenizing strings. This would allow even to order results based on relevance.
Considering all these options, our current approach is not to touch in the way WordPress handles the search, and let it be overtaken by plugins.
Eventually we will develop our own search engine plugins, to replace the limited native WordPress approach, but for now we are investigating existing plugins that could work well with Tainacan. Since we made sure to build things in the "WordPress way", and since Tainacan search uses the native `WP_Query` class to make it queries, any plugin that filters its behavior might work with Tainacan.
We are only starting this investigation, and we will keep this page updated with our findings. This is not (yet) a list of recommendation.
* [Search Everything](https://wordpress.org/plugins/search-everything/): Expands the native WordPress search to also search in taxonomies and metadata. It does so by joining tables in `WP_Query` and therefore might have performance issues for large repositories.
* [ElasticPress](https://wordpress.org/plugins/elasticpress/): integrates WordPress with an Elastic Search server. We are starting to test Tainacan with this plugin.

View File

@ -1,4 +1,4 @@
# Setting up yout local enviroment
# Setting up your local enviroment
This document will run you through setting up your local enviroment and running the tests. If you haven't done it yet, please have a look at [key concepts](key-concepts.md) so you can have a better Understanding of the project.

BIN
src/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -55,6 +55,11 @@
height: 100%;
margin-bottom: 0px;
margin-top: 0px;
@media screen and (max-width: 769px) {
height: auto;
}
}
.is-main-content {
@ -65,9 +70,7 @@
height: 100%;
@media screen and (max-width: 769px) {
& {
overflow-y: visible;
}
overflow-y: visible;
}
.columns {
margin-left: 0px;
@ -83,9 +86,10 @@
height: calc(100% - 53px);
@media screen and (max-width: 769px) {
& {
overflow-y: visible;
}
overflow-y: visible;
margin: 0 auto;
}
.columns {
@ -102,11 +106,12 @@
height: 21px;
width: 23px;
border: none;
background-color: $primary-light;
background-color: #c1dae0;
color: $secondary;
padding: 0px;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
cursor: pointer;
.icon {
margin-top: -1px;

View File

@ -22,6 +22,7 @@ class Admin {
add_filter( 'admin_body_class', array( &$this, 'admin_body_class' ) );
add_action( 'init', array( &$this, 'register_user_meta' ) );
add_action( 'after_setup_theme', array( &$this, 'load_icon_font'));
}
@ -43,6 +44,7 @@ class Admin {
add_action( 'admin_enqueue_scripts', array( &$this, 'add_admin_js' ), 90 );
}
function login_styles_reset( $style ) {
if ( strpos( $style, 'wp-admin-css' ) !== false ) {
$style = null;
@ -50,6 +52,16 @@ class Admin {
return $style;
}
function load_icon_font() {
add_action( 'wp_enqueue_scripts', array(&$this, 'add_material_design_icon_css') );
}
function add_material_design_icon_css() {
global $TAINACAN_BASE_URL;
wp_enqueue_style( 'style', $TAINACAN_BASE_URL . '/assets/css/fonts/materialdesignicons.css' );
}
function add_admin_css() {
global $TAINACAN_BASE_URL;

View File

@ -1,13 +1,9 @@
<template>
<div>
<div class="page-container primary-page">
<b-tabs v-model="activeTab">
<tainacan-title />
<b-tabs v-model="activeTab">
<b-tab-item :label="$i18n.get('category')">
<b-tag
v-if="category != null && category != undefined"
:type="'is-' + getStatusColor(category.status)"
v-text="category.status"/>
<form
v-if="category != null && category != undefined"
class="tainacan-form"
@ -23,6 +19,7 @@
:title="$i18n.getHelperTitle('categories', 'name')"
:message="$i18n.getHelperMessage('categories', 'name')"/>
<b-input
:class="{'has-content': form.name != undefined && form.name != ''}"
id="tainacan-text-name"
v-model="form.name"
@focus="clearErrors('name')"
@ -39,6 +36,7 @@
:title="$i18n.getHelperTitle('categories', 'description')"
:message="$i18n.getHelperMessage('categories', 'description')"/>
<b-input
:class="{'has-content': form.description != undefined && form.description != ''}"
id="tainacan-text-description"
type="textarea"
v-model="form.description"
@ -79,6 +77,7 @@
:message="$i18n.getHelperMessage('categories', 'slug')"/>
<b-icon :class="{'is-loading': isUpdatingSlug}"/>
<b-input
:class="{'has-content': form.slug != undefined && form.slug != ''}"
@input="updateSlug()"
id="tainacan-text-slug"
v-model="form.slug"
@ -277,7 +276,7 @@
promise.done((result) => {
this.form.slug = result.permalink;
this.$console.info(this.form.slug);
//this.$console.info(this.form.slug);
});
this.isUpdatingSlug = false;
@ -291,20 +290,6 @@
});
},
getStatusColor(status) {
switch(status) {
case 'publish':
return 'success';
case 'draft':
return 'info';
case 'private':
return 'warning';
case 'trash':
return 'danger';
default:
return 'info';
}
},
createNewCategory() {
// Puts loading on Draft Category creation
this.isLoadingCategory = true;

View File

@ -1,5 +1,7 @@
<template>
<div :class="{'primary-page' : isNewCollection }">
<div
class="page-container"
:class="{'primary-page' : isNewCollection }">
<tainacan-title />
<form
v-if="collection != null && collection != undefined"
@ -23,12 +25,12 @@
</a>
<figure class="image is-128x128">
<span
v-if="collection.featured_image == undefined || collection.featured_image == false"
v-if="collection.thumbnail == undefined || collection.thumbnail == false"
class="image-placeholder">{{ $i18n.get('label_empty_thumbnail') }}</span>
<img
id="thumbail-image"
:alt="$i18n.get('label_thumbnail')"
:src="(collection.featured_image == undefined || collection.featured_image == false) ? thumbPlaceholderPath : collection.featured_image">
:src="(collection.thumbnail == undefined || collection.thumbnail == false) ? thumbPlaceholderPath : collection.thumbnail">
</figure>
<div class="thumbnail-buttons-row">
<a
@ -106,6 +108,7 @@
:title="$i18n.getHelperTitle('collections', 'name')"
:message="$i18n.getHelperMessage('collections', 'name')"/>
<b-input
:class="{'has-content': form.name != undefined && form.name != ''}"
id="tainacan-text-name"
v-model="form.name"
@focus="clearErrors('name')"/>
@ -121,6 +124,7 @@
:title="$i18n.getHelperTitle('collections', 'description')"
:message="$i18n.getHelperMessage('collections', 'description')"/>
<b-input
:class="{'has-content': form.description != undefined && form.description != ''}"
id="tainacan-text-description"
type="textarea"
v-model="form.description"
@ -211,7 +215,7 @@
<template slot="empty">{{ $i18n.get('info_no_user_found') }}</template>
</b-autocomplete>
<ul
class="moderators-list"
class="selected-list-box"
v-if="moderators != undefined && moderators.length > 0">
<li
:key="index"
@ -241,6 +245,7 @@
:title="$i18n.getHelperTitle('collections', 'slug')"
:message="$i18n.getHelperMessage('collections', 'slug')"/>
<b-input
:class="{'has-content': form.slug != undefined && form.slug != ''}"
id="tainacan-text-slug"
v-model="form.slug"
@focus="clearErrors('slug')"/>
@ -316,7 +321,7 @@ export default {
description: '',
slug: '',
enable_cover_page: '',
featured_image: '',
thumbnail: '',
header_image: '',
files:[],
moderators_ids: []
@ -518,7 +523,7 @@ export default {
this.updateThumbnail({collectionId: this.collectionId, thumbnailId: 0})
.then(() => {
this.collection.featured_image = false;
this.collection.thumbnail = false;
})
.catch((error) => {
this.$console.error(error);
@ -545,7 +550,7 @@ export default {
onSave: (mediaId) => {
this.updateThumbnail({collectionId: this.collectionId, thumbnailId: mediaId})
.then((res) => {
this.collection.featured_image = res.featured_image;
this.collection.thumbnail = res.thumbnail;
})
.catch(error => this.$console.error(error));
}
@ -643,6 +648,9 @@ export default {
.tainacan-form>.columns>.column {
overflow: auto;
.field {
position: relative;
}
}
.thumbnail-field {
max-height: 128px;
@ -680,8 +688,7 @@ export default {
display: inherit;
padding: 0;
margin: 0;
margin-left: -8px;
margin-top: 3px;
margin-top: 1px;
}
}
.thumbnail-buttons-row {
@ -700,7 +707,7 @@ export default {
}
}
.selected-cover-page {
background-color: $tainacan-input-color;
background-color: $tainacan-input-background;
padding: 8px;
font-size: .85rem;
.span { vertical-align: middle;}
@ -710,14 +717,6 @@ export default {
}
}
.moderators-list {
padding: 10px;
display: flex;
.tags {
margin-right: 5px;
}
}
.moderators-empty-list {
color: gray;
font-size: 0.85rem;

View File

@ -8,7 +8,7 @@
:addons="false"
:type="formErrors['name'] != undefined ? 'is-danger' : ''"
:message="formErrors['name'] != undefined ? formErrors['name'] : ''">
<label class="label">
<label class="label is-inline">
{{ $i18n.get('label_name') }}
<span
class="required-field-asterisk"
@ -18,6 +18,7 @@
:message="$i18n.getHelperMessage('fields', 'name')"/>
</label>
<b-input
:class="{'has-content': editForm.name != undefined && editForm.name != ''}"
v-model="editForm.name"
name="name"
@focus="clearErrors('name')"/>
@ -34,6 +35,7 @@
:message="$i18n.getHelperMessage('fields', 'description')"/>
</label>
<b-input
:class="{'has-content': editForm.description != undefined && editForm.description != ''}"
type="textarea"
name="description"
v-model="editForm.description"
@ -52,6 +54,7 @@
</label>
<div class="inline-block">
<b-radio
size="is-small"
@focus="clearErrors('label_status')"
id="tainacan-select-status-publish"
name="status"
@ -61,6 +64,7 @@
</b-radio>
<br>
<b-radio
size="is-small"
@focus="clearErrors('label_status')"
id="tainacan-select-status-private"
name="status"
@ -135,10 +139,10 @@
false-value="no"
name="required">
{{ $i18n.get('label_required') }}
<help-button
:title="$i18n.getHelperTitle('fields', 'required')"
:message="$i18n.getHelperMessage('fields', 'required')"/>
</b-checkbox>
<help-button
:title="$i18n.getHelperTitle('fields', 'required')"
:message="$i18n.getHelperMessage('fields', 'required')"/>
</b-field>
<b-field
@ -152,10 +156,10 @@
false-value="no"
name="multiple">
{{ $i18n.get('label_allow_multiple') }}
</b-checkbox>
<help-button
:title="$i18n.getHelperTitle('fields', 'multiple')"
:message="$i18n.getHelperMessage('fields', 'multiple')"/>
<help-button
:title="$i18n.getHelperTitle('fields', 'multiple')"
:message="$i18n.getHelperMessage('fields', 'multiple')"/>
</b-checkbox>
</b-field>
<b-field
@ -169,10 +173,10 @@
false-value="no"
name="collecion_key">
{{ $i18n.get('label_unique_value') }}
<help-button
:title="$i18n.getHelperTitle('fields', 'unique')"
:message="$i18n.getHelperMessage('fields', 'unique')"/>
</b-checkbox>
<help-button
:title="$i18n.getHelperTitle('fields', 'unique')"
:message="$i18n.getHelperMessage('fields', 'unique')"/>
</b-field>
</b-field>

View File

@ -16,7 +16,8 @@
:title="$i18n.getHelperTitle('filters', 'name')"
:message="$i18n.getHelperMessage('filters', 'name')"/>
</label>
<b-input
<b-input
:class="{'has-content': editForm.name != undefined && editForm.name != ''}"
v-model="editForm.name"
name="name"
@focus="clearErrors('name')"/>
@ -32,7 +33,8 @@
:title="$i18n.getHelperTitle('filters', 'description')"
:message="$i18n.getHelperMessage('filters', 'description')"/>
</label>
<b-input
<b-input
:class="{'has-content': editForm.description != undefined && editForm.description != ''}"
type="textarea"
name="description"
v-model="editForm.description"
@ -51,6 +53,7 @@
</label>
<div class="inline-block">
<b-radio
size="is-small"
@focus="clearErrors('label_status')"
id="tainacan-select-status-publish"
name="status"
@ -59,7 +62,8 @@
{{ $i18n.get('publish_visibility') }}
</b-radio>
<br>
<b-radio
<b-radio
size="is-small"
@focus="clearErrors('label_status')"
id="tainacan-select-status-private"
name="status"

View File

@ -1,22 +1,24 @@
<template>
<div>
<tainacan-title />
<form
v-if="!isLoading"
class="tainacan-form"
<form
v-if="!isLoading"
class="tainacan-form"
label-width="120px">
<div class="columns">
<div class="column is-4">
<!-- Status -------------------------------- -->
<label class="section-label">{{ $i18n.get('label_status') }}</label>
<span class="required-field-asterisk">*</span>
<help-button
:title="$i18n.getHelperTitle('items', 'status')"
:message="$i18n.getHelperMessage('items', 'status')"/>
<div class="document-box">
<!-- Status -------------------------------- -->
<div class="section-label">
<label>{{ $i18n.get('label_status') }}</label>
<span class="required-field-asterisk">*</span>
<help-button
:title="$i18n.getHelperTitle('items', 'status')"
:message="$i18n.getHelperMessage('items', 'status')"/>
</div>
<div class="section-box">
<div class="field">
<b-select
<b-select
v-model="form.status"
:placeholder="$i18n.get('instruction_select_a_status')">
<option
@ -27,12 +29,12 @@
:disabled="statusOption.disabled">{{ statusOption.label }}
</option>
</b-select>
<p
<p
v-if="item.status == 'auto-draft'"
class="help is-danger">
{{ $i18n.get('info_item_not_saved') }}
</p>
</div>
</div>
<div class="field is-grouped">
<div class="control">
<button
@ -40,32 +42,34 @@
@click.prevent="onSubmit"
class="button is-success">
{{ $i18n.get('save') }}
</button>
</button>
</div>
</div>
<p class="help is-danger">{{ formErrorMessage }}</p>
<p class="help is-danger">{{ formErrorMessage }}</p>
</div>
<!-- Document -------------------------------- -->
<label class="section-label">{{ form.document != undefined && form.document != null && form.document != '' ? $i18n.get('label_document') : $i18n.get('label_document_empty') }}</label>
<help-button
:title="$i18n.getHelperTitle('items', 'document')"
:message="$i18n.getHelperMessage('items', 'document')"/>
<div class="document-box">
<div
<div class="section-label">
<label>{{ form.document != undefined && form.document != null && form.document != '' ? $i18n.get('label_document') : $i18n.get('label_document_empty') }}</label>
<help-button
:title="$i18n.getHelperTitle('items', 'document')"
:message="$i18n.getHelperMessage('items', 'document')"/>
</div>
<div class="section-box">
<div
v-if="form.document != undefined && form.document != null &&
form.document_type != undefined && form.document_type != null &&
form.document != '' && form.document_type != 'empty'">
<div v-if="form.document_type == 'attachment'">
<div v-html="item.document_as_html" />
<button
class="button is-primary"
<button
class="button is-primary"
size="is-small"
@click.prevent="setFileDocument($event)">
{{ $i18n.get('edit') }}
</button>
<button
class="button is-primary"
<button
class="button is-primary"
size="is-small"
@click.prevent="removeDocument()">
{{ $i18n.get('remove') }}
@ -73,14 +77,14 @@
</div>
<div v-if="form.document_type == 'text'">
<div v-html="item.document_as_html" />
<button
class="button is-primary"
<button
class="button is-primary"
size="is-small"
@click.prevent="setTextDocument()">
{{ $i18n.get('edit') }}
</button>
<button
class="button is-primary"
<button
class="button is-primary"
size="is-small"
@click.prevent="removeDocument()">
{{ $i18n.get('remove') }}
@ -88,14 +92,14 @@
</div>
<div v-if="form.document_type == 'url'">
<div v-html="item.document_as_html" />
<button
class="button is-primary"
<button
class="button is-primary"
size="is-small"
@click.prevent="setURLDocument()">
{{ $i18n.get('edit') }}
</button>
<button
class="button is-primary"
<button
class="button is-primary"
size="is-small"
@click.prevent="removeDocument()">
{{ $i18n.get('remove') }}
@ -123,24 +127,25 @@
</li>
</ul>
</div>
<!-- Text Insert Modal ----------------- -->
<b-modal
:can-cancel="false"
:active.sync="isTextModalActive"
:width="640"
:can-cancel="false"
:active.sync="isTextModalActive"
:width="640"
scroll="keep">
<div class="tainacan-modal-content">
<div class="tainacan-modal-title">
<h2>{{ $i18n.get('instruction_write_text') }}</h2>
<hr>
</div>
<b-input
<b-input
:class="{'has-content': textContent != undefined && textContent != ''}"
type="textarea"
v-model="textContent"/>
<div class="field is-grouped form-submit">
<div class="control">
<div class="control">
<button
id="button-cancel-text-content-writing"
class="button is-outlined"
@ -153,7 +158,7 @@
id="button-submit-text-content-writing"
@click.prevent="confirmTextWriting()"
class="button is-success">
{{ $i18n.get('save') }}</button>
{{ $i18n.get('save') }}</button>
</div>
</div>
</div>
@ -161,19 +166,21 @@
<!-- URL Insert Modal ----------------- -->
<b-modal
:can-cancel="false"
:active.sync="isURLModalActive"
:width="640"
:can-cancel="false"
:active.sync="isURLModalActive"
:width="640"
scroll="keep">
<div class="tainacan-modal-content">
<div class="tainacan-modal-content">
<div class="tainacan-modal-title">
<h2>{{ $i18n.get('instruction_insert_url') }}</h2>
<hr>
</div>
<b-input v-model="urlLink"/>
<b-input
:class="{'has-content': urlLink != undefined && urlLink != ''}"
v-model="urlLink"/>
<div class="field is-grouped form-submit">
<div class="control">
<div class="control">
<button
id="button-cancel-url-link-selection"
class="button is-outlined"
@ -186,39 +193,42 @@
id="button-submit-url-link-selection"
@click.prevent="confirmURLSelection()"
class="button is-success">
{{ $i18n.get('save') }}</button>
{{ $i18n.get('save') }}</button>
</div>
</div>
</div>
</b-modal>
<!-- Thumbnail -------------------------------- -->
<label class="section-label">{{ $i18n.get('label_thumbnail') }}</label>
<help-button
:title="$i18n.getHelperTitle('items', 'featured_img_id')"
:message="$i18n.getHelperMessage('items', 'featured_img_id')"/>
<div class="document-box">
<!-- Thumbnail -------------------------------- -->
<div class="section-label">
<label>{{ $i18n.get('label_thumbnail') }}</label>
<help-button
:title="$i18n.getHelperTitle('items', '_thumbnail_id')"
:message="$i18n.getHelperMessage('items', '_thumbnail_id')"/>
</div>
<div class="section-box">
<div class="thumbnail-field">
<a
<a
class="button is-rounred is-secondary"
id="button-edit-thumbnail"
id="button-edit-thumbnail"
:aria-label="$i18n.get('label_button_edit_thumb')"
@click.prevent="thumbnailMediaFrame.openFrame($event)">
<b-icon icon="pencil" />
</a>
<figure class="image">
<span
v-if="item.featured_image == undefined || item.featured_image == false"
<span
v-if="item.thumbnail == undefined || item.thumbnail == false"
class="image-placeholder">{{ $i18n.get('label_empty_thumbnail') }}</span>
<img
id="thumbail-image"
:alt="$i18n.get('label_thumbnail')"
:src="(item.featured_image == undefined || item.featured_image == false) ? thumbPlaceholderPath : item.featured_image">
id="thumbail-image"
:alt="$i18n.get('label_thumbnail')"
:src="(item.thumbnail == undefined || item.thumbnail == false) ? thumbPlaceholderPath : item.thumbnail">
</figure>
<div class="thumbnail-buttons-row">
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete_thumb')"
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteThumbnail()">
<b-icon icon="delete" />
</a>
@ -227,52 +237,55 @@
</div>
<!-- Attachments ------------------------------------------ -->
<label class="section-label">{{ $i18n.get('label_attachments') }}</label>
<div class="document-box">
<button
<div class="section-label">
<label>{{ $i18n.get('label_attachments') }}</label>
</div>
<div class="section-box">
<button
class="button is-secondary"
@click.prevent="attachmentMediaFrame.openFrame($event)">
Attatchments (tests)
</button>
<div class="uploaded-files">
<div
<div
v-for="(attachment, index) in attachmentsList"
:key="index">
<span class="tag is-primary">
{{ attachment.title.rendered }}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="column is-1" />
<div class="column is-7">
<label class="section-label">{{ $i18n.get('fields') }}</label>
<br>
<a
class="collapse-all"
<a
class="collapse-all"
@click="toggleCollapseAll()">
{{ collapseAll ? $i18n.get('label_collapse_all') : $i18n.get('label_expand_all') }}
<b-icon
<b-icon
type="is-secondary"
:icon=" collapseAll ? 'menu-down' : 'menu-right'" />
</a>
<!-- Fields from Collection-------------------------------- -->
<tainacan-form-item
<tainacan-form-item
v-for="(field, index) of fieldList"
:key="index"
:field="field"
:is-collapsed="!fieldCollapses[index]" />
:is-collapsed="fieldCollapses[index]"
@changeCollapse="onChangeCollapse($event, index)"/>
</div>
</div>
</form>
<b-loading
:active.sync="isLoading"
<b-loading
:active.sync="isLoading"
:can-cancel="false"/>
</div>
</template>
@ -292,7 +305,7 @@ export default {
collectionId: Number,
isLoading: false,
fieldCollapses: [],
collapseAll: false,
collapseAll: false,
form: {
collectionId: Number,
status: '',
@ -301,7 +314,7 @@ export default {
},
thumbnail: {},
// Can be obtained from api later
statusOptions: [{
statusOptions: [{
value: 'publish',
label: this.$i18n.get('publish')
}, {
@ -347,9 +360,9 @@ export default {
this.isLoading = true;
let data = {item_id: this.itemId, status: this.form.status};
this.updateItem(data).then(updatedItem => {
this.updateItem(data).then(updatedItem => {
this.item = updatedItem;
// Fill this.form data with current data.
@ -362,10 +375,10 @@ export default {
this.$router.push(this.$routerHelper.getItemPath(this.form.collectionId, this.itemId));
})
.catch((errors) => {
for (let error of errors.errors) {
for (let field of Object.keys(error)){
for (let error of errors.errors) {
for (let field of Object.keys(error)){
eventBus.errors.push({ field_id: field, errors: error[field]});
}
}
}
this.formErrorMessage = errors.error_message;
@ -377,7 +390,7 @@ export default {
this.isLoading = true;
// Creates draft Item
let data = {collection_id: this.form.collectionId, status: 'auto-draft'};
let data = {collection_id: this.form.collectionId, status: 'auto-draft'};
this.sendItem(data).then(res => {
this.itemId = res.id;
@ -392,30 +405,45 @@ export default {
this.form.document_type = this.item.document_type;
this.loadMetadata();
})
.catch(error => this.$console.error(error));
},
loadMetadata() {
loadMetadata() {
// Obtains Item Field
this.fetchFields(this.itemId).then((fields) => {
this.isLoading = false;
for (let field of fields) {
this.fieldCollapses.push(false);
this.fieldCollapses.push(field.field.required == 'yes');
}
});
},
},
setFileDocument(event) {
this.fileMediaFrame.openFrame(event);
},
setTextDocument() {
this.isTextModalActive = true;
},
},
confirmTextWriting() {
this.isLoading = true;
this.isTextModalActive = false;
this.form.document_type = 'text';
this.form.document = this.textContent;
this.updateItemDocument({ item_id: this.itemId, document: this.form.document, document_type: this.form.document_type });
this.updateItemDocument({ item_id: this.itemId, document: this.form.document, document_type: this.form.document_type })
.then(item => {
this.item.document_as_html = item.document_as_html;
this.isLoading = false;
})
.catch((errors) => {
for (let error of errors.errors) {
for (let field of Object.keys(error)){
eventBus.errors.push({ field_id: field, errors: error[field]});
}
}
this.formErrorMessage = errors.error_message;
this.isLoading = false;
});
},
cancelTextWriting() {
this.isTextModalActive = false;
@ -425,10 +453,29 @@ export default {
this.isURLModalActive = true;
},
confirmURLSelection() {
this.isLoading = true;
this.isURLModalActive = false;
this.form.document_type = 'url';
this.form.document = this.urlLink;
this.updateItemDocument({ item_id: this.itemId, document: this.form.document, document_type: this.form.document_type });
this.updateItemDocument({ item_id: this.itemId, document: this.form.document, document_type: this.form.document_type })
.then(item => {
this.item.document_as_html = item.document_as_html;
this.isLoading = false;
let oldThumbnail = this.item.thumbnail;
if (item.document_type == 'url' && oldThumbnail != item.thumbnail )
this.item.thumbnail = item.thumbnail;
})
.catch((errors) => {
for (let error of errors.errors) {
for (let field of Object.keys(error)){
eventBus.errors.push({ field_id: field, errors: error[field]});
}
}
this.formErrorMessage = errors.error_message;
this.isLoading = false;
});
},
cancelURLSelection() {
this.isURLModalActive = false;
@ -444,11 +491,11 @@ export default {
deleteThumbnail() {
this.updateThumbnail({itemId: this.itemId, thumbnailId: 0})
.then(() => {
this.item.featured_image = false;
this.item.thumbnail = false;
})
.catch((error) => {
this.$console.error(error);
});
});
},
initializeMediaFrames() {
@ -460,13 +507,28 @@ export default {
},
relatedPostId: this.itemId,
onSave: (file) => {
this.isLoading = true;
this.form.document_type = 'attachment';
this.form.document = file.id + '';
this.updateItemDocument({ item_id: this.itemId, document: this.form.document, document_type: this.form.document_type })
.then((item) => {
this.isLoading = false;
this.item.document_as_html = item.document_as_html;
let oldThumbnail = this.item.thumbnail;
if (item.document_type == 'attachment' && oldThumbnail != item.thumbnail )
this.item.thumbnail = item.thumbnail;
})
.catch(error => this.$console.error(error));
.catch((errors) => {
for (let error of errors.errors) {
for (let field of Object.keys(error)){
eventBus.errors.push({ field_id: field, errors: error[field]});
}
}
this.formErrorMessage = errors.error_message;
this.isLoading = false;
});
}
}
);
@ -480,7 +542,7 @@ export default {
onSave: (mediaId) => {
this.updateThumbnail({itemId: this.itemId, thumbnailId: mediaId})
.then((res) => {
this.item.featured_image = res.featured_image;
this.item.thumbnail = res.thumbnail;
})
.catch(error => this.$console.error(error));
}
@ -500,13 +562,17 @@ export default {
}
}
);
},
toggleCollapseAll() {
this.collapseAll = !this.collapseAll;
for (let i = 0; i < this.fieldCollapses.length; i++)
this.fieldCollapses[i] = this.collapseAll;
},
onChangeCollapse(event, index) {
this.fieldCollapses.splice(index, 1, event);
}
},
computed: {
@ -520,6 +586,8 @@ export default {
created(){
// Obtains collection ID
this.cleanFields();
eventBus.clearAllErrors();
this.formErrorMessage = '';
this.collectionId = this.$route.params.collectionId;
this.form.collectionId = this.collectionId;
@ -536,7 +604,7 @@ export default {
this.fetchItem(this.itemId).then(res => {
this.item = res;
// Fill this.form data with current data.
this.form.status = this.item.status;
this.form.document = this.item.document;
@ -552,17 +620,29 @@ export default {
// Fetch current existing attachments
this.fetchAttachments(this.itemId);
}
},
beforeRouteLeave ( to, from, next ) {
if (this.item.status == 'auto-draft') {
this.$dialog.confirm({
message: this.$i18n.get('info_warning_item_not_saved'),
onConfirm: () => {
next();
},
cancelText: this.$i18n.get('cancel'),
confirmText: this.$i18n.get('continue'),
type: 'is-secondary'
});
} else {
next()
}
}
}
</script>
<style lang="scss" scoped>
@import '../../scss/_variables.scss';
@import '../../scss/_variables.scss';
.page-container{
height: calc(100% - 82px);
}
@ -572,10 +652,13 @@ export default {
}
.section-label {
font-size: 16px !important;
font-weight: 500 !important;
color: $tertiary !important;
line-height: 1.2em;
position: relative;
label {
font-size: 16px !important;
font-weight: 500 !important;
color: $tertiary !important;
line-height: 1.2em;
}
}
.collapse-all {
@ -583,13 +666,13 @@ export default {
.icon { vertical-align: bottom; }
}
.document-box {
.section-box {
border: 1px solid $draggable-border-color;
padding: 30px;
margin-top: 16px;
margin-bottom: 38px;
ul {
ul {
display: flex;
justify-content: space-evenly;
li {
@ -599,24 +682,24 @@ export default {
height: 72px;
width: 72px;
border: none;
background-color: $tainacan-input-color;
background-color: $tainacan-input-background;
color: $secondary;
margin-bottom: 6px;
&:hover {
background-color: $primary-lighter;
background-color: $primary-light;
cursor: pointer;
}
}
p { color: $secondary; }
}
}
}
}
.thumbnail-field {
max-height: 128px;
margin-bottom: 96px;
margin-top: -20px;
.content {
padding: 10px;
font-size: 0.8em;
@ -646,13 +729,12 @@ export default {
bottom: -20px;
left: -20px;
z-index: 99;
.icon {
display: inherit;
padding: 0;
margin: 0;
margin-left: -8px;
margin-top: 3px;
margin-top: 1px;
}
}
.thumbnail-buttons-row {
@ -669,10 +751,8 @@ export default {
left: 65px;
}
}
}
</style>

View File

@ -7,6 +7,12 @@
<div class="columns">
<div class="column is-narrow">
<!-- Header Image -------------------------------- -->
<a
v-if="editForm.url != undefined && editForm.url!= ''"
class="button is-success is-pulled-right"
:href="editForm.url">
{{ $i18n.get('see') + ' ' + $i18n.get('term') }}
</a>
<b-field
:addons="false"
:label="$i18n.get('label_header_image')">
@ -47,10 +53,11 @@
{{ $i18n.get('label_name') }}
<span class="required-term-asterisk">*</span>
<help-button
:title="$i18n.getHelperTitle('terms', 'name')"
:message="$i18n.getHelperMessage('terms', 'name')"/>
:title="$i18n.get('label_name')"
:message="$i18n.get('info_help_term_name')"/>
</label>
<b-input
:class="{'has-content': editForm.name != undefined && editForm.name != ''}"
v-model="editForm.name"
name="name"
@focus="clearErrors({ name: 'name', repeated: 'repeated' })"/>
@ -63,10 +70,11 @@
<label class="label">
{{ $i18n.get('label_description') }}
<help-button
:title="$i18n.getHelperTitle('terms', 'description')"
:message="$i18n.getHelperMessage('terms', 'description')"/>
:title="$i18n.get('label_description')"
:message="$i18n.get('info_help_term_description')"/>
</label>
<b-input
:class="{'has-content': editForm.description != undefined && editForm.description != ''}"
type="textarea"
name="description"
v-model="editForm.description"
@ -261,7 +269,7 @@
.icon {
display: inherit;
padding: 0;
margin: 3px 0 0 -8px;
margin-top: 1px;
}
}
.thumbnail-buttons-row {

View File

@ -93,7 +93,7 @@
tag="button"
class="button is-secondary"
:to="{ path: $routerHelper.getNewCategoryPath() }">
{{ $i18n.get('new') + ' ' + $i18n.get('category') }}
{{ $i18n.getFrom('taxonomies', 'new') }}
</router-link>
</div>
</section>

View File

@ -4,7 +4,7 @@
grouped
group-multiline>
<button
v-if="selectedCollections.length > 0"
v-if="selectedCollections.length > 0 && collections.length > 0 && collections[0].current_user_can_edit"
class="button field is-danger"
@click="deleteSelectedCollections()">
<span>{{ $i18n.get('instruction_delete_selected_collections') }} </span>
@ -19,7 +19,6 @@
checkable
:loading="isLoading"
hoverable
striped
selectable
backend-sorting>
<template slot-scope="props">
@ -28,16 +27,16 @@
tabindex="0"
:label="$i18n.get('label_thumbnail')"
:aria-label="$i18n.get('label_thumbnail')"
field="featured_image"
field="thumbnail"
width="55">
<template
v-if="props.row.featured_image"
v-if="props.row.thumbnail"
slot-scope="scope">
<router-link
tag="img"
:to="{path: $routerHelper.getCollectionPath(props.row.id)}"
class="table-thumb clickable-row"
:src="`${props.row.featured_image}`"/>
:src="`${props.row.thumbnail}`"/>
</template>
</b-table-column>
@ -86,6 +85,7 @@
<b-table-column
tabindex="0"
v-if="props.row.current_user_can_edit"
:label="$i18n.get('label_actions')"
width="78"
:aria-label="$i18n.get('label_actions')">

View File

@ -375,6 +375,7 @@ export default {
display: block;
position: relative;
cursor: grab;
opacity: 1 !important;
.handle {
padding-right: 6em;
@ -432,7 +433,7 @@ export default {
cursor: default;
.field-name {
color: $primary;
color: $secondary;
}
.handle .label-details, .handle .icon {
color: $gray !important;
@ -457,6 +458,7 @@ export default {
.switch.is-small {
input[type="checkbox"] + .check {
background-color: $secondary !important;
border: 1.5px solid white !important;
&::before { background-color: white !important; }
}

View File

@ -422,7 +422,7 @@ export default {
this.isLoadingFilterTypes = false;
});
this.fetchFilters({collectionId: this.collectionId, isRepositoryLevel: this.isRepositoryLevel, isContextEdit: true })
this.fetchFilters({collectionId: this.collectionId, isRepositoryLevel: this.isRepositoryLevel, isContextEdit: true, includeDisabled: 'yes' })
.then(() => {
this.isLoadingFilters = false;
// Needs to be done after activeFilterList exists to compare and remove chosen fields.
@ -563,7 +563,7 @@ export default {
cursor: default;
.field-name {
color: $primary;
color: $secondary;
}
.handle .label-details, .handle .icon {
color: $gray !important;
@ -588,6 +588,7 @@ export default {
.switch.is-small {
input[type="checkbox"] + .check {
background-color: $secondary !important;
border: 1.5px solid white !important;
&::before { background-color: white !important; }
}

View File

@ -4,7 +4,7 @@
grouped
group-multiline>
<button
v-if="selectedItems.length > 0"
v-if="selectedItems.length > 0 && items.length > 0 && items[0].current_user_can_edit"
class="button field is-danger"
@click="deleteSelectedItems()">
<span>{{ $i18n.get('instruction_delete_selected_items') }} </span><b-icon icon="delete"/>
@ -15,15 +15,15 @@
:data="items"
@selection-change="handleSelectionChange"
:checked-rows.sync="selectedItems"
checkable
:checkable="!isOnTheme"
:loading="isLoading"
hoverable
striped
selectable
:selectable="!isOnTheme"
backend-sorting>
<template slot-scope="props">
<b-table-column
v-for="(column, index) in tableFields"
v-if="column.field != 'row_actions' || (column.field == 'row_actions' && props.row.current_user_can_edit && !isOnTheme)"
:key="index"
:custom-key="column.slug"
:label="column.name"
@ -31,12 +31,21 @@
:class="column.field == 'row_creation' ? 'row-creation' : ''"
:width="column.field == 'row_actions' ? 78 : column.field == 'row_thumbnail' ? 55 : undefined ">
<template>
<template v-if="column.field != 'row_thumbnail' && column.field != 'row_actions' && column.field != 'row_creation'">
<span
class="clickable-row"
class="clickable-row"
v-if="!isOnTheme && props.row.metadata[column.slug].value_as_html == props.row.metadata[column.slug].value_as_string"
@click.prevent="goToItemPage(props.row.id)"
v-if="column.field != 'row_thumbnail' && column.field != 'row_actions' && column.field != 'row_creation'"
v-html="renderMetadata( props.row.metadata[column.slug] )" />
v-html="renderMetadata( props.row.metadata[column.slug] )" />
<span
class="clickable-row"
v-if="!isOnTheme && props.row.metadata[column.slug].value_as_html != props.row.metadata[column.slug].value_as_string"
v-html="renderMetadata( props.row.metadata[column.slug] )" />
<a
v-if="isOnTheme"
:href="getDecodedURI(props.row.url)"
v-html="renderMetadata( props.row.metadata[column.slug] )" />
</template>
<template v-if="column.field == 'row_thumbnail'">
@ -95,7 +104,8 @@ export default {
collectionId: Number,
tableFields: Array,
items: Array,
isLoading: false
isLoading: false,
isOnTheme: false
},
methods: {
...mapActions('collection', [
@ -178,6 +188,9 @@ export default {
},
getCreationHtml(item) {
return this.$i18n.get('info_created_by') + item['author_name'] + '<br>' + this.$i18n.get('info_date') + moment( item['creation_date'], 'YYYY-MM-DD').format('DD/MM/YYYY');
},
getDecodedURI(url) {
return decodeURIComponent(url);
}
}
}

View File

@ -11,7 +11,7 @@
<li><router-link
tag="a"
to="/collections"
:class="activeRoute == 'CollectionsPage' || isMenuCompressed ? 'is-active':''">
:class="activeRoute == 'CollectionsPage' || $route.params.collectionId != undefined ? 'is-active':''">
<b-icon
size="is-small"
icon="folder-multiple"/> <span class="menu-text">{{ $i18n.getFrom('collections', 'name') }}</span>
@ -82,7 +82,6 @@ export default {
-webkit-transition: max-width 0.2s linear; /* Safari */
transition: max-width 0.2s linear;
max-width: $side-menu-width;
box-shadow: -3px 0px 8px #111;
z-index: 99;
.separator {
@ -133,11 +132,10 @@ export default {
@media screen and (max-width: 769px) {
width: 100% !important;
max-width: 100% !important;
.menu-header {
height: 60px;
padding-top: $header-height;
.menu{
padding-top: 0px;
}
ul {
flex-flow: wrap;
display: flex;
@ -148,6 +146,9 @@ export default {
padding: 0.8em !important;
text-align: center;
}
.menu-text {
display: none;
}
}
}
}

View File

@ -65,7 +65,6 @@ export default {
background-color: $secondary;
height: $header-height;
max-height: $header-height;
box-shadow: 0px -2px 7px #000;
width: 100%;
padding: 12px;
vertical-align: middle;
@ -147,20 +146,21 @@ export default {
}
@media screen and (max-width: 769px) {
padding: 0px;
display: flex;
.level-left {
display: inline-block;
margin-left: 0px !important;
.level-item {
margin-left: 30px;
margin-left: 0px;
}
}
.level-right {
display: none;
margin-top: 0;
display: inline-block;
}
top: 206px;
&.menu-compressed {
top: 237px !important;
}
top: 0px;
margin-bottom: 0px !important;
}

View File

@ -25,61 +25,71 @@
</div>
</div>
<ul class="menu-list level-right">
<li class="level-item"><router-link
tag="a"
:to="{ path: $routerHelper.getCollectionItemsPath(id, '') }"
:class="activeRoute == 'ItemPage' || activeRoute == 'CollectionItemsPage' || activeRoute == 'ItemEditionForm' || activeRoute == 'ItemCreatePage' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_items')">
<b-icon
<li class="level-item">
<router-link
tag="a"
:to="{ path: $routerHelper.getCollectionItemsPath(id, '') }"
:class="activeRoute == 'ItemPage' || activeRoute == 'CollectionItemsPage' || activeRoute == 'ItemEditionForm' || activeRoute == 'ItemCreatePage' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_items')">
<b-icon
size="is-small"
icon="folder-outline"/>
<br>
<span class="menu-text">{{ $i18n.getFrom('collections', 'singular_name') }}</span>
</router-link>
</li>
<li class="level-item">
<router-link
tag="a"
:to="{ path: $routerHelper.getCollectionEditPath(id) }"
:class="activeRoute == 'CollectionEditionForm' ? 'is-active':''"
:aria-label="$i18n.getFrom('collections','edit_item')">
<b-icon
size="is-small"
icon="pencil"/>
<br>
<span class="menu-text">{{ $i18n.get('edit') }}</span>
</router-link>
</li>
<li class="level-item">
<router-link
tag="a"
:to="{ path: $routerHelper.getCollectionFieldsPath(id) }"
:class="activeRoute == 'FieldsList' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_fields')">
<b-icon
size="is-small"
icon="folder-outline"/>
<br>
<span class="menu-text">{{ $i18n.getFrom('collections', 'singular_name') }}</span>
</router-link></li>
<li class="level-item"><router-link
tag="a"
:to="{ path: $routerHelper.getCollectionEditPath(id) }"
:class="activeRoute == 'CollectionEditionForm' ? 'is-active':''"
:aria-label="$i18n.getFrom('collections','edit_item')">
<b-icon
size="is-small"
icon="pencil"/>
<br>
<span class="menu-text">{{ $i18n.get('edit') }}</span>
</router-link></li>
<li class="level-item"><router-link
tag="a"
:to="{ path: $routerHelper.getCollectionFieldsPath(id) }"
:class="activeRoute == 'FieldsList' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_fields')">
<b-icon
size="is-small"
icon="format-list-bulleted-type"/>
<br>
<span class="menu-text">{{ $i18n.getFrom('fields', 'name') }}</span>
</router-link></li>
<li class="level-item"><router-link
tag="a"
:to="{ path: $routerHelper.getCollectionFiltersPath(id) }"
:class="activeRoute == 'FiltersList' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_filters')">
<b-icon
size="is-small"
icon="filter"/>
<br>
<span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span>
</router-link></li>
<li class="level-item"><router-link
tag="a"
:to="{ path: $routerHelper.getCollectionEventsPath(id) }"
:class="activeRoute == 'EventsList' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_events')">
<b-icon
size="is-small"
icon="calendar-range"/>
<br>
<span class="menu-text">{{ $i18n.get('events') }}</span>
</router-link></li>
icon="format-list-bulleted-type"/>
<br>
<span class="menu-text">{{ $i18n.getFrom('fields', 'name') }}</span>
</router-link>
</li>
<li class="level-item">
<router-link
tag="a"
:to="{ path: $routerHelper.getCollectionFiltersPath(id) }"
:class="activeRoute == 'FiltersList' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_filters')">
<b-icon
size="is-small"
icon="filter"/>
<br>
<span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span>
</router-link>
</li>
<li class="level-item">
<router-link
tag="a"
:to="{ path: $routerHelper.getCollectionEventsPath(id) }"
:class="activeRoute == 'CollectionEventsPage' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_events')">
<b-icon
size="is-small"
icon="calendar-range"/>
<br>
<span class="menu-text">{{ $i18n.get('events') }}</span>
</router-link>
</li>
</ul>
</div>
@ -104,6 +114,7 @@ export default {
},
watch: {
'$route' (to) {
this.activeRoute = to.name;
this.pageTitle = this.$route.meta.title;
@ -281,11 +292,16 @@ export default {
@media screen and (max-width: 769px) {
width: 100% !important;
max-width: 100% !important;
height: 143px;
max-height: 143px;
ul {
margin-top: 12px;
flex-flow: wrap;
display: flex;
align-items: stretch;
justify-content: space-evenly;
align-items: baseline;
justify-content: space-between;
a {
padding: 0.5em 0.7em !important;
text-align: center;
@ -294,9 +310,7 @@ export default {
padding-left: 0.3em !important;
}
}
}
@media screen and (max-width: 769px) {
.level-left {
margin-left: 0px !important;
.level-item {

View File

@ -2,11 +2,11 @@
<div
class="tainacan-page-title"
id="title-row">
<h1>{{ pageTitle }} <span class="has-text-weight-bold">{{ isRepositoryLevel ? '' : entityName }}</span></h1>
<h1>{{ pageTitle }} <span class="is-italic">{{ isRepositoryLevel ? '' : entityName }}</span></h1>
<a
@click="$router.go(-1)"
class="back-link is-secondary">
{{ $i18n.get('return') }}
{{ $i18n.get('back') }}
</a>
<hr>
<nav
@ -118,7 +118,8 @@ export default {
},
created() {
this.isRepositoryLevel = (this.$route.params.collectionId == undefined);
this.pageTitle = this.$route.meta.title;
document.title = this.$route.meta.title;
this.pageTitle = document.title;
this.arrayRealPath = this.$route.path.split("/");
this.arrayRealPath = this.arrayRealPath.filter((item) => item.length != 0);
@ -136,7 +137,7 @@ export default {
#title-row {
.breadcrumbs {
font-size: 0.85em;
font-size: 12px;
}
.level-left {

View File

@ -12,20 +12,25 @@
:key="key">
<p/>
<div class="has-text-weight-bold is-capitalized">{{ `${key.replace('_', ' ')}:` }}</div>
<div class="has-text-weight-bold is-capitalized">
{{ `${key.replace(/_/g, ' ')}:` }}
</div>
<div v-if="key === 'thumbnail'">
<div class="image is-128x128">
<img :src="diff.old">
</div>
</div>
<div
v-if="!Array.isArray(diff.old)"
class="content is-inline">
v-else-if="diff.old.constructor.name !== 'Array' && diff.old.constructor.name !== 'Object'"
class="is-inline">
{{ diff.old }}
</div>
<div
v-else
v-for="(o, ind) in diff.old"
:key="ind">
<div v-if="o.hasOwnProperty('mime_type') && o.mime_type.includes('image') && key === 'attachments'">
<article class="media">
<div class="media-left bottom-space-tainacan">
<p class="image is-64x64"><img :src="o.url"></p>
@ -45,17 +50,34 @@
<div
v-else-if="key === 'fields_order' || key === 'filters_order'"
class="is-capitalized"
:class="{ 'back-hlight': diff.diff_with_index.hasOwnProperty(i) }">
{{ `ID: ${d.id} Enabled: ${d.enabled}` }}
class="is-capitalized">
{{ `ID: ${o.id} Enabled: ${o.enabled ? o.enabled : 'false'}` }}
</div>
<div
v-else-if="!(o instanceof Object)"
class="is-inline">
<div
v-if="ind.constructor.name === 'String'"
class="is-capitalized">
{{ `${ind.replace(/_/g, ' ')}: ${o} ` }}
</div>
<div v-else>
{{ `${ind}: ${o} ` }}
</div>
</div>
<div
v-else
class="content is-inline is-capitalized"
v-for="(o2, ind2) in o"
:key="ind2">
<div class="is-inline is-capitalized">{{ `${ind2.replace('_', ' ')}: ${o2} ` }}</div>
v-for="(e, i2) in o"
:key="i2"
class="is-inline">
<div
v-if="i2.constructor.name === 'String'"
class="is-capitalized">
{{ `${i2.replace(/_/g, ' ')}: ${e} ` }}
</div>
<div v-else>
{{ `${i2}: ${e} ` }}
</div>
</div>
</div>
</div>
@ -75,9 +97,9 @@
<div
class="has-text-weight-bold is-capitalized"
:class="{ 'has-text-success': !diff.old, 'back-hlight': !diff.old }">
{{ `${key.replace('_', ' ')}:` }}
{{ `${key.replace(/_/g, ' ')}:` }}
</div>
<div v-if="key === 'featured_image'">
<div v-if="key === 'thumbnail'">
<div class="image is-128x128">
<img :src="diff.new">
</div>
@ -113,13 +135,13 @@
v-else-if="key === 'fields_order' || key === 'filters_order'"
class="is-capitalized"
:class="{ 'back-hlight': diff.diff_with_index.hasOwnProperty(i) }">
{{ `ID: ${d.id} Enabled: ${d.enabled}` }}
{{ `ID: ${d.id} Enabled: ${d.enabled ? d.enabled : 'false'}` }}
</div>
<div
class="is-inline"
:class="{ 'back-hlight': diff.diff_with_index.hasOwnProperty(i) }"
v-else-if="!Array.isArray(d) && d.constructor.name !== 'Object' ">{{ d }}
v-else-if="!(d instanceof Object)">{{ d }}
</div>
<div
@ -127,11 +149,16 @@
v-for="(e, i2) in d"
:key="i2"
class="is-inline">
<div
class="is-capitalized"
:class="{ 'back-hlight': diff.diff_with_index.hasOwnProperty(i) }">
{{ `${i2.replace('_', ' ')}: ${e} ` }}
v-if="i2.constructor.name === 'String'"
class="is-capitalized"
:class="{ 'back-hlight': diff.diff_with_index.hasOwnProperty(i) }">
{{ `${i2.replace(/_/g, ' ')}: ${e} ` }}
</div>
<div
v-else
:class="{ 'back-hlight': diff.diff_with_index.hasOwnProperty(i) }">
{{ `${i2}: ${e} ` }}
</div>
</div>
@ -156,5 +183,7 @@
</script>
<style scoped>
.content {
overflow: auto;
}
</style>

View File

@ -13,13 +13,19 @@
:key="key">
<p/>
<div class="has-text-weight-bold is-capitalized">{{ `${key.replace('_', ' ')}:` }}</div>
<div class="has-text-weight-bold is-capitalized">
{{ `${key.replace(/_/g, ' ')}:` }}
</div>
<div v-if="key === 'thumbnail'">
<div class="image is-128x128">
<img :src="diff.old">
</div>
</div>
<div
v-if="!Array.isArray(diff.old)"
class="content is-inline">
v-else-if="diff.old.constructor.name !== 'Array' && diff.old.constructor.name !== 'Object'"
class="is-inline">
{{ diff.old }}
</div>
<div
v-else
v-for="(o, ind) in diff.old"
@ -27,7 +33,6 @@
<div v-if="o.hasOwnProperty('mime_type') && o.mime_type.includes('image') && key === 'attachments'">
<article class="media">
<div class="media-left bottom-space-tainacan">
<p class="image is-64x64"><img :src="o.url"></p>
@ -47,17 +52,34 @@
<div
v-else-if="key === 'fields_order' || key === 'filters_order'"
class="is-capitalized"
:class="{ 'back-hlight': diff.diff_with_index.hasOwnProperty(i) }">
{{ `ID: ${d.id} Enabled: ${d.enabled}` }}
class="is-capitalized">
{{ `ID: ${o.id} Enabled: ${o.enabled ? o.enabled : 'false'}` }}
</div>
<div
v-else-if="!(o instanceof Object)"
class="is-inline">
<div
v-if="ind.constructor.name === 'String'"
class="is-capitalized">
{{ `${ind.replace(/_/g, ' ')}: ${o} ` }}
</div>
<div v-else>
{{ `${ind}: ${o} ` }}
</div>
</div>
<div
v-else
class="content is-inline is-capitalized"
v-for="(o2, ind2) in o"
:key="ind2">
<div class="is-inline is-capitalized">{{ `${ind2.replace('_', ' ')}: ${o2} ` }}</div>
v-for="(e, i2) in o"
:key="i2"
class="is-inline">
<div
v-if="i2.constructor.name === 'String'"
class="is-capitalized">
{{ `${i2.replace(/_/g, ' ')}: ${e} ` }}
</div>
<div v-else>
{{ `${i2}: ${e} ` }}
</div>
</div>
</div>
</div>
@ -72,9 +94,9 @@
<div
class="has-text-weight-bold is-capitalized"
:class="{ 'has-text-success': !diff.old, 'back-hlight': !diff.old }">
{{ `${key.replace('_', ' ')}:` }}
{{ `${key.replace(/_/g, ' ')}:` }}
</div>
<div v-if="key === 'featured_image'">
<div v-if="key === 'thumbnail'">
<div class="image is-128x128">
<img :src="diff.new">
</div>
@ -110,28 +132,31 @@
v-else-if="key === 'fields_order' || key === 'filters_order'"
class="is-capitalized"
:class="{ 'back-hlight': diff.diff_with_index.hasOwnProperty(i) }">
{{ `ID: ${d.id} Enabled: ${d.enabled}` }}
{{ `ID: ${d.id} Enabled: ${d.enabled ? d.enabled : 'false'}` }}
</div>
<div
class="is-inline"
:class="{ 'back-hlight': diff.diff_with_index.hasOwnProperty(i) }"
v-else-if="!Array.isArray(d) && d.constructor.name !== 'Object' ">{{ d }}
v-else-if="!(d instanceof Object)">{{ d }}
</div>
<div
v-else
v-for="(e, i2) in d"
:key="i2"
class="is-inline">
<div
v-if="i2.constructor.name === 'String'"
class="is-capitalized"
:class="{ 'back-hlight': diff.diff_with_index.hasOwnProperty(i) }">
{{ `${i2.replace('_', ' ')}: ${e} ` }}
{{ `${i2.replace(/_/g, ' ')}: ${e} ` }}
</div>
<div
v-else
:class="{ 'back-hlight': diff.diff_with_index.hasOwnProperty(i) }">
{{ `${i2}: ${e} ` }}
</div>
</div>
</div>
@ -156,5 +181,7 @@
</script>
<style scoped>
.content {
overflow: auto;
}
</style>

View File

@ -16,7 +16,7 @@
<div class="has-text-weight-bold is-capitalized">
{{ `${key.replace('_', ' ')}:` }}
</div>
<div v-if="key === 'featured_image'">
<div v-if="key === 'thumbnail'">
<div class="image is-128x128">
<img :src="diff.new">
</div>

View File

@ -1,31 +1,23 @@
<template>
<span class="help-wrapper">
<a
class="help-button"
@click="isOpened = !isOpened"><b-icon
size="is-small"
icon="help-circle-outline"/></a>
<div
class="help-tooltip"
:class="{ 'opened': isOpened }">
<a class="help-button">
<b-icon
size="is-small"
icon="help-circle-outline"/></a>
<div class="help-tooltip">
<div class="help-tooltip-header">
<h5>{{ title }}</h5><a @click="isOpened = false"><b-icon icon="close"/></a>
<h5>{{ title }}</h5>
</div>
<div class="help-tooltip-body">
<p>{{ (message != '' && message != undefined) ? message : $i18n.get('info_no_description_provided') }}</p>
</div>
</div>
</div>
</span>
</template>
<script>
export default {
name: 'HelpButton',
data() {
return {
isOpened: false
}
},
props: {
title: '',
message: ''
@ -38,87 +30,68 @@ export default {
@import "../../scss/_variables.scss";
.help-wrapper {
position: relative;
position: absolute;
}
a.help-button .icon {
i, i::before { font-size: 0.9em !important; }
color: $gray;
&:hover {
color: $primary !important;
}
}
.help-tooltip.opened {
.help-wrapper:hover .help-tooltip {
margin-bottom: 12px;
margin-left: -37px;
visibility: visible;
opacity: 1;
margin-bottom: 14px;
opacity: 1;
}
.help-tooltip {
color: #000;
background-color: #e8f9f5;
border: 1px solid #338591;
border-radius: 10px;
margin: 0px 0px 0px -37px;
position: absolute;
z-index: 999999999999999;
bottom: 100%;
left: 0%;
min-width: 250px;
z-index: 99999999999999999999;
color: $tertiary;
background-color: $primary-light;
border: none;
display: block;
border-radius: 5px;
min-width: 250px;
min-width: 250px;
transition: margin-bottom 0.2s ease, opacity 0.3s ease;
position: absolute;
bottom: calc(100% - 6px);
left: 0%;
margin-bottom: -27px;
visibility: hidden;
opacity: 0;
transition: opacity 0.4s ease, margin-bottom 0.3s ease;
.help-tooltip-header {
padding: 0.8em 0.8em 0.6em 0.8em;
border-bottom: 1px solid #909293;
font-size: 18px;
font-weight: bold;
padding: 0.8em 0.8em 0em 0.8em;
h5 {
margin-right: 25px;
}
.icon {
color: #909293 !important;
right: 14px;
top: 14px;
position: absolute;
&:hover {
color: black !important;
}
font-size: 14px;
font-weight: bold;
}
}
.help-tooltip-body {
padding: 1.2em;
padding: 0.8em 1.0em 1.0em 1.0em;
font-size: 11px;
font-weight: normal;
}
&:after,
&:before {
content: "";
display: block;
position: absolute;
left: 24px;
left: 28px;
width: 0;
height: 0;
border-style: solid;
}
&:after {
border-color: #e8f9f5 transparent transparent transparent;
border-right-width: 20px;
border-top-width: 16px;
border-left-width: 20px;
}
&:before {
border-color: #338591 transparent transparent transparent;
border-right-width: 20px;
border-top-width: 16px;
border-left-width: 20px;
bottom: -20px;
border-color: $primary-light transparent transparent transparent;
border-right-width: 18px;
border-top-width: 12px;
border-left-width: 18px;
bottom: -15px;
}
}
</style>

View File

@ -6,7 +6,7 @@
v-for="(filter, index) in filters"
:key="index"
:filter="filter"
:opened="collapsed"/>
:open="collapsed"/>
</div>
</template>

View File

@ -1,12 +1,13 @@
<template>
<span>
<div class="header-item">
<div
class="header-item"
v-if="!isOnTheme">
<b-dropdown id="item-creation-options-dropdown">
<button
class="button is-secondary"
slot="trigger">
<span>{{ `${$i18n.get('add')} ${$i18n.get('item')}` }}</span>
<span>{{ $i18n.getFrom('items','add_new') }}</span>
<b-icon icon="menu-down"/>
</button>
@ -25,9 +26,9 @@
</div>
<div class="header-item">
<b-dropdown>
<b-dropdown class="show">
<button
class="button"
class="button is-white"
slot="trigger">
<span>{{ $i18n.get('label_table_fields') }}</span>
<b-icon icon="menu-down"/>
@ -53,12 +54,12 @@
<option
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'
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">
@ -66,9 +67,9 @@
</option>
</b-select>
<button
class="button is-small"
class="button is-white is-small"
@click="onChangeOrder()">
<b-icon :icon="order == 'ASC' ? 'sort-ascending' : 'sort-descending'"/>
<b-icon :icon="order === 'ASC' ? 'sort-ascending' : 'sort-descending'"/>
</button>
</b-field>
</div>
@ -88,7 +89,8 @@
props: {
collectionId: Number,
isRepositoryLevel: false,
tableFields: Array
tableFields: Array,
isOnTheme: false
},
computed: {
orderBy() {
@ -117,9 +119,15 @@
.header-item {
display: inline-block;
}
.header-item .field {
align-items: center;
}
#item-creation-options-dropdown {
margin-right: 80px;
}
.header-item .dropdown-menu {
display: block;
}
</style>

View File

@ -29,8 +29,8 @@ import FilterCategoryCheckbox from '../../classes/filter-types/category/Checkbox
import FilterCategoryTaginput from '../../classes/filter-types/category/Taginput.vue';
import FilterCategorySelectbox from '../../classes/filter-types/category/Selectbox.vue';
import TaincanFormItem from '../../classes/field-types/tainacan-form-item.vue';
import TaincanFiltersList from '../../classes/filter-types/tainacan-filter-item.vue';
import TainacanFormItem from '../../classes/field-types/tainacan-form-item.vue';
import TainacanFiltersList from '../../classes/filter-types/tainacan-filter-item.vue';
// Remaining imports
import AdminPage from '../admin.vue'
@ -61,8 +61,8 @@ Vue.component('tainacan-category', Category);
Vue.component('tainacan-form-relationship', FormRelationship);
Vue.component('tainacan-form-category', FormCategory);
Vue.component('tainacan-form-selectbox', FormSelectbox);
Vue.component('tainacan-form-item', TaincanFormItem);
Vue.component('tainacan-filter-item', TaincanFiltersList);
Vue.component('tainacan-form-item', TainacanFormItem);
Vue.component('tainacan-filter-item', TainacanFiltersList);
/* Filters */
Vue.component('tainacan-filter-custom-interval', FilterCustomInterval);

View File

@ -22,7 +22,6 @@ import CategoryEditionForm from '../components/edition/category-edition-form.vue
// Listing components
import FiltersList from '../components/lists/filters-list.vue'
import FieldsList from '../components/lists/fields-list.vue'
import EventsList from '../components/lists/events-list.vue'
Vue.use(VueRouter);
@ -47,8 +46,8 @@ const routes = [
{ path: 'edit', component: CollectionEditionForm, name: 'CollectionEditionForm', meta: {title: i18nGet('title_edit_collection'), icon: 'folder-multiple'} },
{ path: 'fields', component: FieldsList, name: 'FieldsList', meta: {title: i18nGet('title_collection_fields_edition'), icon: 'folder-multiple'} },
{ path: 'filters', component: FiltersList, name: 'FiltersList', meta: {title: i18nGet('title_collection_filters_edition'), icon: 'folder-multiple'} },
{ path: 'events', component: EventsList, name: 'EventsList', meta: {title: i18nGet('title_collection_events'), icon: 'calendar'} }
]
{ path: 'events', component: EventsPage, name: 'CollectionEventsPage', meta: {title: i18nGet('title_collection_events'), icon: 'calendar'} }
]
},
// { path: '/items', name: 'ItemsPage', component: ItemsPage, meta: {title: i18nGet('title_items_page'), icon: 'file-multiple'} },

View File

@ -76,16 +76,19 @@ Vue.component('items-page', ItemsPage);
Vue.use(eventBusSearch, { store: store, router: routerTheme});
import ThemeItemsList from '../theme-items-list.vue';
new Vue({
el: '#tainacan-items-page',
store,
router: routerTheme,
router: routerTheme,
data: {
collectionId: ''
},
template: '<items-page :collection-id="collectionId"></items-page>',
collectionId: ''
},
render: h => h(ThemeItemsList),
beforeMount () {
if (this.$el.attributes['collection-id'] != undefined)
this.collectionId = this.$el.attributes['collection-id'].value;
}
});

View File

@ -8,19 +8,25 @@ export default {
wp.media.view.settings.post = {
id: this.params.relatedPostId
}
this.frame = wp.media({
button: {
text: this.params.button_labels.frame_button
},
content: 'upload', // First view that is opened
autoSelect: true,
states: [
new wp.media.controller.Library({
new wp.media.controller.MediaLibrary({
title: this.params.button_labels.frame_title,
library: wp.media.query({
uploadedTo: this.params.relatedPostId
status: null,
type: null,
uploadedTo: wp.media.view.settings.post.id
}),
uploader: true,
multiple: true,
date: false
date: false,
uploadedTo: wp.media.view.settings.post.id
})
]
});
@ -34,10 +40,13 @@ export default {
mejsSettings = window._wpmejsSettings || {};
attachments = this.frame.state().get( 'selection' ).toJSON();
wp.media.view.settings.post = {
id: this.params.relatedPostId
}
this.params.attachments = attachments;
this.params.onSave(attachments);
// Set the Customizer setting; the callback takes care of rendering.
//this.setting( attachment.id );
node = this.container.find( 'audio, video' ).get(0);
// Initialize audio/video previews.
@ -56,7 +65,7 @@ export default {
var l10n = _wpMediaViewsL10n;
wp.media.view.settings.post = {
id: this.params.relatedPostId
id: null
}
this.params.flex_width = 0;
@ -71,16 +80,17 @@ export default {
close: false
},
uploader: true,
content: 'upload', // First view that is opened
autoSelect: true,
states: [
new wp.media.controller.Library({
title: this.params.button_labels.frame_title,
library: wp.media.query({
type: 'image',
uploadedTo: this.params.relatedPostId
uploadedTo: null
}),
multiple: false,
date: false,
filterable: true,
priority: 20,
suggestedWidth: this.params.width,
suggestedHeight: this.params.height,
@ -115,7 +125,7 @@ export default {
var l10n = _wpMediaViewsL10n;
wp.media.view.settings.post = {
id: this.params.relatedPostId
id: null
}
this.params.flex_width = tainacan_plugin.custom_header_support[0].flex_width ? 1 : 0;
this.params.flex_height = tainacan_plugin.custom_header_support[0].flex_height ? 1 : 0;
@ -128,13 +138,18 @@ export default {
text: l10n.select,
close: false
},
library: wp.media.query({
type: 'image',
uploadedTo: null
}),
uploader: true,
content: 'upload', // First view that is opened
states: [
new wp.media.controller.Library({
title: this.params.button_labels.frame_title,
library: wp.media.query({
type: 'image',
uploadedTo: this.params.relatedPostId
uploadedTo: null
}),
multiple: false,
date: false,
@ -178,11 +193,12 @@ export default {
button: {
text: this.params.button_labels.frame_button
},
content: 'upload', // First view that is opened
states: [
new wp.media.controller.Library({
title: this.params.button_labels.frame_title,
library: wp.media.query({
uploadedTo: this.params.relatedPostId
uploadedTo: null
}),
multiple: false,
date: false,

View File

@ -1,8 +1,14 @@
<template>
<div>
<div class="primary-page page-container">
<div
:class="{
'primary-page': isRepositoryLevel,
'page-container': isRepositoryLevel
}">
<tainacan-title />
<div class="columns above-subheader">
<div
class="columns"
:class="{ 'above-subheader': isRepositoryLevel }">
<div class="column table-container">
<events-list
:is-loading="isLoading"
@ -76,6 +82,7 @@
methods: {
...mapActions('event', [
'fetchEvents',
'fetchCollectionEvents',
]),
...mapGetters('event', [
'getEvents'
@ -93,14 +100,25 @@
loadEvents() {
this.isLoading = true;
this.fetchEvents({ 'page': this.page, 'eventsPerPage': this.eventsPerPage })
.then((res) => {
this.isLoading = false;
this.totalEvents = res.total;
})
.catch(() => {
this.isLoading = false;
});
if(this.isRepositoryLevel) {
this.fetchEvents({'page': this.page, 'eventsPerPage': this.eventsPerPage})
.then((res) => {
this.isLoading = false;
this.totalEvents = res.total;
})
.catch(() => {
this.isLoading = false;
});
} else {
this.fetchCollectionEvents({'page': this.page, 'eventsPerPage': this.eventsPerPage, 'collectionId': this.$route.params.collectionId})
.then((res) => {
this.isLoading = false;
this.totalEvents = res.total;
})
.catch(() => {
this.isLoading = false;
});
}
},
getLastEventNumber() {
let last = (Number(this.eventsPerPage * (this.page - 1)) + Number(this.eventsPerPage));
@ -120,7 +138,7 @@
}
},
created() {
this.isRepositoryLevel = (this.$route.params.collectionId == undefined);
this.isRepositoryLevel = (this.$route.params.collectionId === undefined);
this.$userPrefs.get('events_per_page')
.then((value) => {
this.eventsPerPage = value;
@ -171,23 +189,12 @@
min-height: 100%;
height: auto;
.filters-menu {
min-width: $side-menu-width;
max-width: $side-menu-width;
background-color: $primary-lighter;
margin-left: -$page-small-side-padding;
padding-left: $page-small-side-padding
}
.table-container {
margin-right: -$page-small-side-padding;
padding: 3em 2.5em;
}
@media screen and (max-width: 769px) {
.filters-menu {
display: none;
}
.table-container {
margin-right: 0;
padding: .85em 0em;

View File

@ -16,26 +16,31 @@
<b-field class="margin-1">
<b-input
placeholder="Search..."
:placeholder=" $i18n.get('instruction_search_collection') "
type="search"
size="is-small"
icon="magnify" />
icon="magnify"
@input="updateSearch($event)"
:value="searchQuery"/>
</b-field>
<a class="is-size-7 is-secondary is-pulled-right">Busca avançada</a>
<!-- <a class="is-size-7 is-secondary is-pulled-right">Busca avançada</a> -->
<br>
<br>
<h3 class="has-text-weight-semibold">{{ $i18n.get('filters') }}</h3>
<a
v-if="!isLoadingFilters && filters.length > 0"
class="collapse-all is-size-7"
@click="toggleCollapseAll">
@click="collapseAll = !collapseAll">
{{ collapseAll ? $i18n.get('label_collapse_all') : $i18n.get('label_expand_all') }}
<b-icon
type="is-secondary"
size="is-small"
:icon=" collapseAll ? 'menu-down' : 'menu-right'" />
</a>
<br>
<br>
<filters-items-list
@ -77,9 +82,12 @@
:is-repository-level="isRepositoryLevel"
:collection-id="collectionId"
:table-fields="tableFields"
:pref-table-fields="prefTableFields"/>
:pref-table-fields="prefTableFields"
:is-on-theme="isOnTheme"/>
</div>
<div
:items="items"
id="theme-items-list" />
<!-- LISTING RESULTS ------------------------- -->
<div class="table-container above-subheader">
<b-loading
@ -90,7 +98,8 @@
:collection-id="collectionId"
:table-fields="tableFields"
:items="items"
:is-loading="isLoading"/>
:is-loading="isLoading"
:is-on-theme="isOnTheme"/>
<section
v-if="!isLoadingItems && items.length <= 0"
class="section">
@ -108,7 +117,7 @@
tag="button"
class="button is-primary"
:to="{ path: $routerHelper.getNewItemPath(collectionId) }">
{{ $i18n.getFrom('items', 'new_item') }}
{{ $i18n.getFrom('items', 'add_new') }}
</router-link>
</div>
</section>
@ -140,6 +149,7 @@
hasFiltered: false,
isFiltersMenuCompressed: false,
collapseAll: false,
isOnTheme: false
}
},
props: {
@ -167,13 +177,12 @@
...mapGetters('filter', [
'getFilters'
]),
toggleCollapseAll() {
this.collapseAll = !this.collapseAll;
for (let i = 0; i < this.fieldCollapses.length; i++)
this.fieldCollapses[i] = this.collapseAll;
},
...mapGetters('search', [
'getSearchQuery'
]),
updateSearch(searchQuery) {
this.$eventBusSearch.setSearchQuery(searchQuery)
}
},
computed: {
items() {
@ -184,9 +193,24 @@
},
fields() {
return this.getFields();
},
searchQuery() {
return this.getSearchQuery();
}
},
created() {
/*
document.addEventListener('tainacan-items-change', () => {
var themeList = document.getElementById('theme-items-list');
var items = themeList.attributes.items.value;
var e = document.createElement('p');
e.innerHTML = items;
themeList.appendChild(e);
}); */
this.isOnTheme = (this.$route.name == null);
this.isRepositoryLevel = (this.collectionId == undefined);
this.$eventBusSearch.$on('isLoadingItems', isLoadingItems => {
@ -201,7 +225,8 @@
this.fetchFilters({
collectionId: this.collectionId,
isRepositoryLevel: this.isRepositoryLevel,
isContextEdit: true
isContextEdit: true,
includeDisabled: 'no',
})
.then(() => this.isLoadingFilters = false)
.catch(() => this.isLoadingFilters = false);
@ -219,7 +244,7 @@
name: this.$i18n.get('label_thumbnail'),
field: 'row_thumbnail',
field_type: undefined,
slug: 'featured_image',
slug: 'thumbnail',
id: undefined,
display: true
});
@ -286,7 +311,7 @@
this.$eventBusSearch.setCollectionId(this.collectionId);
this.$eventBusSearch.updateStoreFromURL();
this.$eventBusSearch.loadItems();
}
}
}
</script>
@ -314,8 +339,7 @@
@media screen and (max-width: 769px) {
height: 60px;
margin-top: -0.5em;
padding-top: 0.90em;
margin-top: 0;
.header-item {
padding-right: 0.5em;
@ -335,7 +359,7 @@
width: $filter-menu-width;
max-width: $filter-menu-width;
min-height: 100%;
background-color: $tainacan-input-color;
background-color: $tainacan-input-background;
padding: $page-small-side-padding;
float: left;
height: 100%;
@ -345,6 +369,10 @@
display: block;
transition: visibility ease 0.5s, display ease 0.5s;
h3 {
font-size: 100%;
}
.label {
font-size: 12px;
font-weight: normal;
@ -366,12 +394,10 @@
}
@media screen and (max-width: 769px) {
.filters-menu {
display: none;
}
.table-container {
margin-right: 0;
padding: .85em 0em;
padding: 16px;
}
}
@ -384,11 +410,12 @@
height: 21px;
width: 23px;
border: none;
background-color: $primary-light;
background-color: $primary-lighter;
color: $tertiary;
padding: 0px;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
cursor: pointer;
.icon {
margin-top: -1px;

View File

@ -14,7 +14,7 @@
<router-link
class="card-footer-item"
:to="{ path: $routerHelper.getCategoryEditPath(categoryId)}">
{{ $i18n.get('edit') + ' ' + $i18n.get('category') }}
{{ $i18n.getFrom('taxonomies','edit') }}
</router-link>
<a class="card-footer-item">
Edit terms

View File

@ -2,6 +2,7 @@
<div>
<div class="is-fullheight">
<div class="page-container primary-page">
<tainacan-title />
<div class="title">{{ event.description }}</div>
<div
class="level"
@ -43,6 +44,8 @@
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';
import TainacanTitle from '../../components/navigation/tainacan-title.vue';
export default {
name: 'EventPage',
@ -68,7 +71,8 @@
components: {
Split,
Unified,
NoDiff
NoDiff,
TainacanTitle,
},
created() {
this.eventId = parseInt(this.$route.params.eventId);

View File

@ -3,73 +3,87 @@
<b-loading
:active.sync="isLoading"
:can-cancel="false"/>
<div class="card">
<div class="card-content">
<div
class="card-image"
v-if="item.document">
<figure
class="image"
v-html="item.document_as_html" />
</div>
<br>
<tainacan-title />
<div class="content">
<div
v-if="item.featured_image"
class="media">
<figure
class="media-left" >
<p class="image is-128x128">
<img :src="item.featured_image">
</p>
</figure>
<div class="media-content">
{{ $i18n.get('label_thumbnail') }}
</div>
</div>
<div
v-for="(metadata, index) in item.metadata"
:key="index"
class="box">
<p
v-if="metadata.value_as_html"
class="is-size-3"
v-html="metadata.value_as_html"/>
<p
v-else>--</p>
<p>
<i>
{{ metadata.name }}
</i>
</p>
</div>
<div
class="box">
<p>--</p>
<p>
<i>
{{ $i18n.get('label_attachments') }}
</i>
</p>
</div>
<router-link
class="button is-secondary"
:to="{ path: $routerHelper.getItemEditPath(collectionId, itemId)}">
{{ $i18n.getFrom('items','edit_item') }}
</router-link>
<a
class="button is-success is-pulled-right"
:href="item.url">
{{ $i18n.getFrom('items', 'view_item') }}
</a>
<br>
<div
class="card-image"
v-if="item.document">
<figure
class="image"
v-html="item.document_as_html" />
</div>
<footer class="card-footer">
<router-link
class="card-footer-item"
:to="{ path: $routerHelper.getCollectionPath(collectionId)}">
{{ $i18n.get('see') + ' ' + $i18n.get('collection') }}
</router-link>
<router-link
class="card-footer-item"
:to="{ path: $routerHelper.getItemEditPath(collectionId, itemId)}">
{{ $i18n.get('edit') + ' ' + $i18n.get('item') }}
</router-link>
</footer>
<br>
<div
v-if="item.thumbnail"
class="media">
<figure
class="media-left" >
<p class="image is-128x128">
<img :src="item.thumbnail">
</p>
</figure>
<div class="media-content">
{{ $i18n.get('label_thumbnail') }}
</div>
</div>
<div
v-for="(metadata, index) in item.metadata"
:key="index"
class="box">
<p
v-if="metadata.value_as_html"
class="is-size-3"
v-html="metadata.value_as_html"/>
<p
v-else>--</p>
<p>
<i>
{{ metadata.name }}
</i>
</p>
</div>
<div
class="box">
<div
v-if="attachments && attachments.length > 0">
<span
v-for="(attachment, index) in attachments"
:key="index"
>
<a
target="blank"
:href="attachment.guid.rendered">{{ attachment.guid.rendered }}</a>
<br>
</span>
</div>
<p v-else>--</p>
<p>
<i>
{{ $i18n.get('label_attachments') }}
</i>
</p>
</div>
</div>
</div>
</template>
@ -88,15 +102,20 @@ export default {
},
methods: {
...mapActions('item', [
'fetchItem'
'fetchItem',
'fetchAttachments'
]),
...mapGetters('item', [
'getItem'
'getItem',
'getAttachments'
]),
},
computed: {
item(){
return this.getItem();
},
attachments(){
return this.getAttachments();
}
},
created(){
@ -112,6 +131,9 @@ export default {
this.fetchItem(this.itemId).then(() => {
loadingInstance.isLoading = false;
});
// Get attachments
this.fetchAttachments(this.itemId);
}
}

View File

@ -10,16 +10,18 @@ $secondary-invert: findColorInvert($secondary);
$tertiary: #01295c;
$tertiary-invert: findColorInvert($tertiary);
$primary-light:#A5CDD7;
$primary-light:#c1dae0;
$primary-lighter: #e6f6f8;
$primary-dark: #55A0AF;
$primary-darker: darken($primary-dark, 5%);
$success: #25a088;
$success: #25a189;
$success-invert: findColorInvert($success);
$separator-color: #2b98a4;
$tainacan-input-color: #f0f0f0;
$tainacan-input-color: #1d1d1d;
$tainacan-input-background: #e5e5e5;
$tainacan-placeholder-color: #898d8f;
$draggable-border-color: #d8d8d8;
$gray: #b1b1b1;
@ -27,6 +29,9 @@ $gray-invert: findColorInvert($gray);
$gray-light: #898d8f;
$gray-light-invert: findColorInvert($gray-light);
$danger: #a23939;
$danger-invert: findColorInvert($danger);
@import "../../../node_modules/bulma/sass/utilities/derived-variables.sass";
// Setup $colors to use as bulma classes
@ -66,13 +71,16 @@ $page-small-side-padding: 22px;
$page-small-top-padding: 22px;
$page-mobile-side-padding: 1em;
$page-mobile-top-padding: 0.5em;
$page-mobile-top-padding: 1em;
// Links
$link: $secondary;
$link-invert: $secondary-invert;
$link-invert: $secondary;
$link-focus-border: $secondary;
// Placeholder
$text-light: $tainacan-placeholder-color;
// Table
$table-head-cell-color: $gray-light;
$table-head-cell-border-width: 0 0 1px !important;

View File

@ -31,8 +31,9 @@ html {
font-family: $family-sans-serif;
}
.modal-background {
background-color: rgba(0, 0, 0, 0.70);
// Link (hover is the same color as secondary
a:hover {
color: $secondary;
}
/* Rules for sizing the icon. */
@ -52,6 +53,10 @@ html {
.primary-page {
margin-top: $header-height;
height: $page-height !important;
@media screen and (max-width: 769px) {
margin-top: 0;
}
}
.page-container {
padding: $page-top-padding $page-side-padding;
@ -76,6 +81,7 @@ html {
}
// Modal
.tainacan-page-title, .tainacan-modal-title {
h1, h2 {
font-size: 20px;
@ -104,6 +110,11 @@ html {
}
}
.modal-background {
background-color: rgba(0, 0, 0, 0.70);
}
// Custom ScrollBar (will work only in Chrome, Opera, Safari, webkit browsers)
/* width */
::-webkit-scrollbar {
@ -131,7 +142,7 @@ html {
// Input components used in forms are gray in Tainacan
.tainacan-form {
color: black;
color: $tainacan-input-color;
.form-submit {
justify-content: space-between !important;
padding: 1em 1.2em 0.4em 1.2em;
@ -140,15 +151,12 @@ html {
border-width: 1px;
padding: 2px 30px !important;
}
.button.is-outlined {
color: $tertiary;
}
&.has-only-save {
justify-content: end !important;
}
}
.label {
font-weight: normal;
font-weight: bold;
font-size: 14px;
display: inline-block;
}
@ -162,47 +170,64 @@ html {
font-size: 14px;
border: none;
border-radius: 1px !important;
background-color: $tainacan-input-color;
color: black;
background-color: $tainacan-input-background;
color: $tainacan-input-color;
box-shadow: none;
transition: background-color 0.1s;
&.is-danger {
background-color: #ece0e0;
background-color: #e7dede;
}
&:focus, &:active {
box-shadow: none !important;
background-color: white;
border: 1px solid $tainacan-input-background !important;
}
}
.radio {
margin-bottom: 0.2em;
.control{
&.has-content {
.input, .textarea {
background-color: white;
border: 1px solid $tainacan-input-background;
}
}
&.has-icons-right {
.icon {
height: 2.0em;
.mdi-alert-circle::before {
content: "\F156" !important;
font-size: 16px !important;
}
}
}
}
.checkbox {
margin-bottom: 0.2em;
.radio, .checkbox {
margin-bottom: 0.2em;
&.is-danger {
border-color: $danger;
}
}
.control-label { // The value part in checkbox, radio and switches
color: black;
color: $tainacan-input-color;
padding-left: 0.8em;
font-size: 12px;
}
.select {
padding-top: 0px !important;
select {
font-size: 14px;
border: none;
border-radius: 1px !important;
font-weight: normal;
height: 30px !important;
padding: 2px 25px 2px 15px!important;
margin-top: 0px !important;
margin-bottom: 0px !important;
background-color: $tainacan-input-color;
color: black;
color: $tainacan-input-color;
background-color: white !important;
border: 1px solid $tainacan-input-background;
&:focus>option:checked, &:focus>option:hover {
background-color: $primary-lighter !important;
}
}
&.is-empty select{
background-color: $tainacan-input-background !important;
}
&:not(.is-multiple)::after {
content: "\F35D" !important;
font: normal normal normal 24px/1 "Material Design Icons" !important;
border: none !important;
transform: none;
margin-top: -0.6em;
right: 0.95em;
color: $primary;
@ -212,73 +237,187 @@ html {
// Some components have a different style in listing pages
.button {
border-width: 0;
border-radius: 6px !important;
font-weight: normal;
padding: 2px 15px !important;
margin-top: 0px !important;
margin-bottom: 0px !important;
height: inherit !important;
box-shadow: none !important;
display: inline-flex !important;
&.is-secondary:hover, &.is-secondary:focus {
background: $secondary !important;
}
&.is-primary:hover, &.is-primary:focus {
background: $primary !important;
}
&.is-success:hover, &.is-success:focus {
background: $success !important;
}
&.is-white:hover, &.is-white:focus, &.is-outlined:hover, &.is-outlined:focus {
background: $white !important;
}
&:active {
-webkit-transform: none !important;
transform: none !important;
}
&.is-outlined {
color: #150e38 !important;
background-color: white;
border-color: $gray-light !important;
}
&:focus {
outline: 0px;
}
}
.button.is-small {
height: 26px !important;
line-height: 12px;
}
.button:not(.is-small):not(.is-medium):not(.is-large) {
height: 30px !important;
line-height: 20px !important;
font-size: 14px !important;
}
.select {
padding-top: 0px !important;
select {
border: none;
border-radius: 6px !important;
border-radius: 1px !important;
font-weight: normal;
font-size: 14px !important;
height: 30px !important;
padding: 2px 25px 2px 15px!important;
margin-top: 0px !important;
margin-bottom: 0px !important;
&:focus>option:checked, &:focus>option:hover {
color: $tainacan-input-color;
option:checked, option:hover {
background-color: $primary-lighter !important;
}
&:focus, &:active {
box-shadow: none !important;
text-decoration: none !important;
}
}
&:not(.is-multiple)::after {
content: "\F35D" !important;
font: normal normal normal 24px/1 "Material Design Icons" !important;
border: none !important;
transform: none;
margin-top: -0.6em;
right: 0.95em;
transform: none !important;
margin-top: -15px !important;
right: 10px !important;
color: $primary;
display: flex !important;
align-items: initial;
}
}
.dropdown {
.dropdown, .autocomplete {
.dropdown-trigger{
.button {
border: none;
.icon {
color: $secondary;
align-items: start;
}
}
.icon {
color: $primary;
.button.is-primary, .button.is-secondary, .button.is-success {
.icon {
color: $white;
}
}
}
.dropdown-menu {
top: 26px;
.dropdown-item {
.b-checkbox { width: 100% };
&:hover {
background-color: $primary-lighter;
.dropdown-content {
border-radius: 0px !important;
.dropdown-item {
.b-checkbox { width: 100% };
&:hover {
background-color: $primary-lighter;
}
.is-small {
color: gray;
}
}
.is-small {
color: gray;
}
}
}
.taginput-container {
padding: 0 !important;
background-color: white !important;
&:focus, &:active {
border: none !important;
}
.input { margin-bottom: 0px !important; }
.input.has-selected, .input:focus, .input:active {
background-color: white;
border: 1px solid $tainacan-input-background !important;
}
.tag {
background: white;
padding-right: 0;
padding-left: 0.5em;
&.is-delete {
color: $gray-light;
&::after {
height: 30% !important;
width: 1px !important;
}
&::before {
width: 30% !important;
height: 1px !important;
}
&:hover, &:focus {
background-color: white;
color: black;
}
}
}
}
.selected-list-box {
padding: 4px 0px;
border: 1px solid $tainacan-input-background;
background-color: white;
display: flex;
font-size: 12px;
.tags {
margin-right: 8px;
}
.tag {
background: white;
padding-right: 0;
padding-left: 0.5em;
&.is-delete {
color: $gray-light;
&::after {
height: 30% !important;
width: 1px !important;
}
&::before {
width: 30% !important;
height: 1px !important;
}
&:hover, &:focus {
background-color: white;
color: black;
}
}
}
}
.switch {
input[type="checkbox"] + .check {
background-color: transparent;
border: 1.6px solid $gray;
background-color: $gray-light;
border: 2px solid $gray-light;
width: 2.7em;
height: 1.7em;
&::before {
background-color: $gray;
background-color: white;
box-shadow: none;
}
}
@ -287,16 +426,16 @@ html {
}
input[type="checkbox"]:checked + .check {
border: 1.6px solid $secondary;
border: 2px solid $secondary;
background-color: transparent;
&::before {
background-color: $secondary;
transform: translate3d(83%, 0, 0);
transform: translate3d(78%, 0, 0);
}
}
&:hover input[type="checkbox"] + .check {
background-color: $tainacan-input-color;
background-color: $gray-light;
}
&:focus input[type="checkbox"] + .check,
@ -308,40 +447,96 @@ html {
font-size: 9px;
input[type="checkbox"] + .check {
border: 1.5px solid $gray;
border: 1.5px solid $gray-light;
width: 2.55em;
height: 1.7em;
&::before {
width: 1.05em;
height: 1.05em;
width: 1.0em;
height: 1.0em;
}
}
input[type="checkbox"]:checked + .check {
border: 1.5px solid $secondary;
&::before {
transform: translate3d(93%, 0, 0);
transform: translate3d(84%, 0, 0);
}
}
}
}
.b-checkbox.checkbox {
input[type="checkbox"] {
box-shadow: none !important;
}
input[type="checkbox"] + .check {
width: 1.0em;
height: 1.0em;
flex-shrink: 0;
border-radius: 0;
border: 1px solid $gray-light;
transition: background 150ms ease-out;
box-shadow: none !important;
}
&:focus input[type="checkbox"] + .check,
&:active input[type="checkbox"] + .check,
&:hover input[type="checkbox"] + .check {
box-shadow: none !important;
border-color: $gray-light !important;
}
input[type="checkbox"]:checked + .check {
background: white url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Cpath style='fill:%23000' d='M 0.04038059,0.6267767 0.14644661,0.52071068 0.42928932,0.80355339 0.3232233,0.90961941 z M 0.21715729,0.80355339 0.85355339,0.16715729 0.95961941,0.2732233 0.3232233,0.90961941 z'%3E%3C/path%3E%3C/svg%3E") no-repeat center center !important;
border-color: $gray-light !important;
}
}
.b-radio.radio {
input[type="radio"] + .check {
width: 13px !important;
height: 13px !important;
border: 1px solid $gray-light !important;
}
input[type="radio"] + .check::before {
background: black !important;
width: 7px !important;
height: 7px !important;
}
&:focus input[type="radio"] + .check,
&:active input[type="radio"] + .check,
&:hover input[type="radio"] + .check {
box-shadow: none !important;
}
input[type="radio"]:checked + .check {
border-color: $gray-light !important;
}
&:focus input[type="radio"]:checked + .check {
box-shadow: none !important;
}
}
// Tables
.table {
tbody {
td { border-bottom: 0px solid $gray-light !important; }
}
.b-checkbox.checkbox input[type="checkbox"] + .check {
width: 0.85em !important;
height: 0.85em !important;
border-radius: 2px !important;
border: 1px solid #7a7a7a !important;
}
.th-wrap {
font-size: 0.85em !important;
font-weight: normal !important;
.table-wrapper {
.table {
tbody {
td { border-bottom: 0px solid $gray-light !important; }
}
.b-checkbox.checkbox input[type="checkbox"] + .check {
width: 0.85em !important;
height: 0.85em !important;
border-radius: 2px !important;
border: 1px solid #7a7a7a !important;
}
.th-wrap {
font-size: 12px !important;
font-weight: normal !important;
}
}
margin-bottom: 0px !important;
}
.pagination-area {
display: flex;
@ -349,8 +544,8 @@ html {
align-items: center;
font-size: 0.85em !important;
font-weight: normal !important;
border-top: 1px solid $gray-light;
padding: 0.85em 1.0em;
border-top: 1px solid $gray;
padding: 0em 1.0em;
color: $gray-light;
.shown-items {
@ -376,6 +571,45 @@ html {
.pagination {
flex-grow: 1;
a[disabled="disabled"] {
color: $gray-light;
}
.pagination-link, .pagination-previous, .pagination-next {
background-color: transparent;
color: $secondary;
border: none;
}
.pagination-link.is-current {
color: $gray-light;
}
.pagination-link::after:not(:last-child) {
content: ',';
color: $gray-light;
}
.mdi-chevron-left::before {
content: "\F40A";
font-size: 17px;
transform: rotate(180deg);
}
.mdi-chevron-right::before {
content: "\F40A";
font-size: 17px;
}
}
}
// Tabs
.tabs {
a {
font-size: 13px;
margin-bottom: -3px;
&:hover{
border-bottom-color: transparent;
}
}
li.is-active a {
border-bottom: 5px solid $primary;
color: $primary;
}
}

View File

@ -0,0 +1,6 @@
@import "../../../node_modules/bulma/sass/utilities/_all.sass"
@import "../../../node_modules/bulma/sass/base/helpers.sass"
@import "../../../node_modules/bulma/sass/elements/form.sass"
@import "../../../node_modules/bulma/sass/components/pagination.sass"
@import "../../../node_modules/bulma/sass/elements/icon.sass"
@import "../../../node_modules/bulma/sass/elements/tag.sass"

View File

@ -5,13 +5,13 @@ return [
'repository' => __( 'Repository', 'tainacan' ),
'collections' => __( 'Collections', 'tainacan' ),
'items' => __( 'Items', 'tainacan' ),
'fields' => __( 'Fields', 'tainacan' ),
'fields' => __( 'Metadata', 'tainacan' ),
'filters' => __( 'Filters', 'tainacan' ),
'categories' => __( 'Categories', 'tainacan' ),
'events' => __( 'Events', 'tainacan' ),
'collection' => __( 'Collection', 'tainacan' ),
'item' => __( 'Item', 'tainacan' ),
'field' => __( 'Field', 'tainacan' ),
'field' => __( 'Metadata', 'tainacan' ),
'filter' => __( 'Filter', 'tainacan' ),
'category' => __( 'Category', 'tainacan' ),
'event' => __( 'Event', 'tainacan' ),
@ -28,8 +28,8 @@ return [
'remove' => __( 'Remove', 'tainacan' ),
'save' => __( 'Save', 'tainacan' ),
'next' => __( 'Next', 'tainacan' ),
'return' => __( 'Return', 'tainacan' ),
'see' => __( 'See', 'tainacan' ),
'back' => __( 'Back', 'tainacan' ),
'see' => __( 'View', 'tainacan' ),
'search' => __( 'Search', 'tainacan' ),
'advanced_search' => __( 'Advanced Search', 'tainacan' ),
'continue' => __( 'Continue', 'tainacan' ),
@ -59,6 +59,7 @@ return [
'title_collection_page' => __( 'Collection Page', 'tainacan' ),
'title_item_page' => __( 'Item Page', 'tainacan' ),
'title_field_page' => __( 'Field Page', 'tainacan' ),
'title_collection_events' => __( 'Collection Events', 'tainacan' ),
/* translators: alkdjklasdj laksjd klsadj */
'title_filter_page' => __( 'Filter Page', 'tainacan' ),
@ -177,7 +178,7 @@ return [
'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_moderators' => __( 'Type to search a User to add.', 'tainacan'),
'instruction_select_a_parent_collection' => __( 'Select a parent colection.', 'tainacan' ),
'instruction_select_collection_thumbnail' => __( 'Select a thumbnail image for collection', 'tainacan' ),
'instruction_select_item_thumbnail' => __( 'Select a thumbnail image for item', 'tainacan' ),
@ -188,6 +189,7 @@ return [
'instruction_insert_url' => __( 'Insert URL', 'tainacan' ),
'instruction_write_text' => __( 'Write Text', 'tainacan' ),
'instruction_search_repository' => __( 'Search on repository', 'tainacan' ),
'instruction_search_collection' => __( 'Search on collection', 'tainacan' ),
// Info. Other feedback to user.
'info_name_is_required' => __( 'Name is required.', 'tainacan' ),
@ -221,6 +223,7 @@ return [
'info_by' => __( 'By: ', 'tainacan' ),
'info_date' => __( 'Date: ', 'tainacan' ),
'info_not_saved' => __( 'Not saved ', 'tainacan' ),
'info_warning_item_not_saved' => __( 'Are you sure? The item is not saved, changes will be lost.', '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' ),
@ -234,6 +237,8 @@ return [
'info_there_is_no_filter' => __( 'There is no filter here yet.', 'tainacan' ),
'info_changes' => __( 'Changes', 'tainacan' ),
'info_possible_external_sources' => __( 'Possible external sources: CSV, Instagram, Youtube, etc.', 'tainacan' ),
'info_help_term_name' => __( 'The term name', 'tainacan' ),
'info_help_term_description' => __( 'The description of the Term.', 'tainacan' ),
// Tainacan Field Types
'tainacan-text' => __( 'Text', 'tainacan' ),
@ -254,4 +259,4 @@ return [
'tainacan-filter-category-checkbox' => __( 'Category Check Box', 'tainacan' ),
'tainacan-filter-category-selectbox' => __( 'Category Select Box', 'tainacan' )
]
?>
?>

View File

@ -0,0 +1,500 @@
<template>
<items-page
class="theme-items-list"
:collection-id="$root.collectionId" />
</template>
<script>
export default {
name: "ThemeItemsList",
}
</script>
<style lang="scss">
@import "./scss/theme-basics.sass";
@import "../../node_modules/buefy/src/scss/components/_datepicker.scss";
$speed-slow: 0.5s;
@import "../../node_modules/buefy/src/scss/utils/_functions.scss";
@import "../../node_modules/buefy/src/scss/components/_checkbox.scss";
@import "../../node_modules/buefy/src/scss/components/_radio.scss";
@import "../../node_modules/buefy/src/scss/components/_tag.scss";
/* Rules for sizing the icon. */
.material-icons.md-18 { font-size: 18px; }
.material-icons.md-24 { font-size: 24px; }
.material-icons.md-36 { font-size: 36px; }
.material-icons.md-48 { font-size: 48px; }
/* Rules for using icons as black on a light background. */
.material-icons.md-dark { color: rgba(0, 0, 0, 0.54); }
.material-icons.md-dark.md-inactive { color: rgba(0, 0, 0, 0.26); }
/* Rules for using icons as white on a dark background. */
.material-icons.md-light { color: rgba(255, 255, 255, 1); }
.material-icons.md-light.md-inactive { color: rgba(255, 255, 255, 0.3); }
// Tainacan custom colors
$primary: #2cb4c1;
$primary-invert: findColorInvert($primary);
$secondary: #298596;
$secondary-invert: findColorInvert($secondary);
$tertiary: #01295c;
$tertiary-invert: findColorInvert($tertiary);
$primary-light:#c1dae0;
$primary-lighter: #e6f6f8;
$primary-dark: #55A0AF;
$primary-darker: darken($primary-dark, 5%);
$success: #25a189;
$success-invert: findColorInvert($success);
$separator-color: #2b98a4;
$tainacan-input-color: #1d1d1d;
$tainacan-input-background: #e5e5e5;
$tainacan-placeholder-color: #898d8f;
$draggable-border-color: #d8d8d8;
$gray: #b1b1b1;
$gray-invert: findColorInvert($gray);
$gray-light: #898d8f;
$gray-light-invert: findColorInvert($gray-light);
$danger: #a23939;
$danger-invert: findColorInvert($danger);
.theme-items-list {
a{ color: $secondary !important }
a:hover {
cursor: pointer;
color: $secondary !important;
}
ul {
list-style: none;
}
// Some components have a different style in listing pages
.button {
height: inherit !important;
box-shadow: none !important;
border: none;
border-radius: 6px;
padding: 2px 15px;
margin-top: 0px;
margin-bottom: 0px;
display: inline-flex;
color: #1d1d1d;
font-size: 1.0em;
font-weight: normal;
cursor: pointer;
background-color: white;
&.is-secondary:hover, &.is-secondary:focus {
background: $secondary !important;
}
&.is-primary:hover, &.is-primary:focus {
background: $primary !important;
}
&.is-success:hover, &.is-success:focus {
background: $success !important;
}
&.is-white:hover, &.is-white:focus, &.is-outlined:hover, &.is-outlined:focus {
background: $white !important;
}
&:active {
-webkit-transform: none !important;
transform: none !important;
}
&.is-outlined {
color: #150e38 !important;
background-color: white;
border-color: $gray-light !important;
}
&:focus {
outline: 0px;
}
}
.button.is-small {
height: 26px !important;
line-height: 12px;
}
.button:not(.is-small):not(.is-medium):not(.is-large) {
height: 30px !important;
line-height: 20px !important;
font-size: 14px !important;
}
.select {
padding-top: 0px !important;
select {
border: none;
border-radius: 1px !important;
font-weight: normal;
font-size: 14px !important;
height: 30px !important;
padding: 2px 25px 2px 15px!important;
margin-top: 0px !important;
margin-bottom: 0px !important;
color: $tainacan-input-color;
option:checked, option:hover {
background-color: $primary-lighter !important;
}
&:focus, &:active {
box-shadow: none !important;
text-decoration: none !important;
}
}
&:not(.is-multiple)::after {
content: "\F35D" !important;
font: normal normal normal 24px/1 "Material Design Icons" !important;
border: none !important;
transform: none !important;
margin-top: -15px !important;
right: 10px !important;
color: $primary;
display: flex !important;
align-items: initial;
}
}
.dropdown {
display: inline-flex;
position: relative;
vertical-align: top;
}
.dropdown, .autocomplete {
.dropdown-trigger{
.button {
border: none;
.icon {
color: $secondary;
align-items: start;
}
}
.button.is-primary, .button.is-secondary, .button.is-success {
.icon {
color: $white;
}
}
}
.dropdown-menu {
display: block;
.dropdown-content {
font-size: 13px !important;
border-radius: 0px !important;
.dropdown-item {
.b-checkbox { width: 100% };
&:hover {
background-color: $primary-lighter;
}
.is-small {
color: gray;
}
}
}
}
}
.taginput-container {
padding: 0 !important;
background-color: white !important;
&:focus, &:active {
border: none !important;
}
.input { margin-bottom: 0px !important; }
.input.has-selected, .input:focus, .input:active {
background-color: white;
border: 1px solid $tainacan-input-background !important;
}
.tag {
background: white;
padding-right: 0;
padding-left: 0.5em;
&.is-delete {
color: $gray-light;
&::after {
height: 30% !important;
width: 1px !important;
}
&::before {
width: 30% !important;
height: 1px !important;
}
&:hover, &:focus {
background-color: white;
color: black;
}
}
}
}
.selected-list-box {
padding: 4px 0px;
border: 1px solid $tainacan-input-background;
background-color: white;
display: flex;
.tags {
margin-right: 8px;
}
.tag {
background: white;
padding-right: 0;
padding-left: 0.5em;
&.is-delete {
color: $gray-light;
&::after {
height: 30% !important;
width: 1px !important;
}
&::before {
width: 30% !important;
height: 1px !important;
}
&:hover, &:focus {
background-color: white;
color: black;
}
}
}
}
.switch {
input[type="checkbox"] + .check {
background-color: $gray-light;
border: 2px solid $gray-light;
width: 2.7em;
height: 1.7em;
&::before {
background-color: white;
box-shadow: none;
}
}
&:hover input[type="checkbox"]:checked + .check {
background-color: $primary-light;
}
input[type="checkbox"]:checked + .check {
border: 2px solid $secondary;
background-color: transparent;
&::before {
background-color: $secondary;
transform: translate3d(78%, 0, 0);
}
}
&:hover input[type="checkbox"] + .check {
background-color: $gray-light;
}
&:focus input[type="checkbox"] + .check,
&:focus input[type="checkbox"]:checked + .check {
box-shadow: none;
}
&.is-small {
font-size: 9px;
input[type="checkbox"] + .check {
border: 1.5px solid $gray-light;
width: 2.55em;
height: 1.7em;
&::before {
width: 1.0em;
height: 1.0em;
}
}
input[type="checkbox"]:checked + .check {
border: 1.5px solid $secondary;
&::before {
transform: translate3d(84%, 0, 0);
}
}
}
}
.b-checkbox.checkbox {
input[type="checkbox"] {
box-shadow: none !important;
}
input[type="checkbox"] + .check {
width: 1.0em;
height: 1.0em;
flex-shrink: 0;
border-radius: 0;
border: 1px solid $gray-light;
transition: background 150ms ease-out;
box-shadow: none !important;
}
&:focus input[type="checkbox"] + .check,
&:active input[type="checkbox"] + .check,
&:hover input[type="checkbox"] + .check {
box-shadow: none !important;
border-color: $gray-light !important;
}
input[type="checkbox"]:checked + .check {
background: white url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Cpath style='fill:%23000' d='M 0.04038059,0.6267767 0.14644661,0.52071068 0.42928932,0.80355339 0.3232233,0.90961941 z M 0.21715729,0.80355339 0.85355339,0.16715729 0.95961941,0.2732233 0.3232233,0.90961941 z'%3E%3C/path%3E%3C/svg%3E") no-repeat center center !important;
border-color: $gray-light !important;
}
}
.b-radio.radio {
input[type="radio"] + .check {
width: 13px !important;
height: 13px !important;
border: 1px solid $gray-light !important;
}
input[type="radio"] + .check::before {
background: black !important;
width: 7px !important;
height: 7px !important;
}
&:focus input[type="radio"] + .check,
&:active input[type="radio"] + .check,
&:hover input[type="radio"] + .check {
box-shadow: none !important;
}
input[type="radio"]:checked + .check {
border-color: $gray-light !important;
}
&:focus input[type="radio"]:checked + .check {
box-shadow: none !important;
}
}
.collapse-all {
font-size: 0.75rem;
}
.collapse .collapse-trigger {
display: inline;
cursor: pointer;
.label {
vertical-align: middle;
margin-bottom: 0px;
}
}
// Tables
.table-wrapper {
.table {
tbody {
td { border-bottom: 0px solid $gray-light !important; }
}
.b-checkbox.checkbox input[type="checkbox"] + .check {
width: 0.85em !important;
height: 0.85em !important;
border-radius: 2px !important;
border: 1px solid #7a7a7a !important;
}
.th-wrap {
font-size: 12px !important;
font-weight: normal !important;
}
}
margin-bottom: 0px !important;
}
.pagination-area {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.85em !important;
font-weight: normal !important;
border-top: 1px solid $gray;
padding: 0em 1.0em;
color: $gray-light;
.shown-items {
flex-grow: 1;
}
.items-per-page {
flex-grow: 3;
margin-top: 0.35em;
.field-label {
flex-grow: 5;
margin-right: 0.5em;
.label {
font-size: 1em !important;
font-weight: normal !important;
color: $gray-light;
}
}
select {
font-size: 0.85em;
}
}
.pagination {
flex-grow: 1;
ul {
margin-bottom: 0px;
padding: 0px;
}
&.is-small {
font-size: 0.85em;
}
a[disabled="disabled"] {
color: $gray-light;
}
.pagination-link, .pagination-previous, .pagination-next {
background-color: transparent;
color: $secondary;
border: none;
}
.pagination-link.is-current {
color: $gray-light;
}
.pagination-link::after:not(:last-child) {
content: ',';
color: $gray-light;
}
.mdi-chevron-left::before {
content: "\F40A";
font-size: 17px;
transform: rotate(180deg);
}
.mdi-chevron-right::before {
content: "\F40A";
font-size: 17px;
}
}
}
// Tabs
.tabs {
a {
font-size: 13px;
margin-bottom: -3px;
&:hover{
border-bottom-color: transparent;
}
}
li.is-active a {
border-bottom: 5px solid $primary;
color: $primary;
}
}
.select select{
border: none;
border-radius: 1;
padding: 4px 16px;
color: #1d1d1d;
font-size: 1.0em;
font-weight: normal;
cursor: pointer;
background-color: white;
}
}
</style>

View File

@ -25,8 +25,10 @@ class REST_Controller extends \WP_REST_Controller {
if (is_array($attributes)) {
foreach ( $attributes as $attribute ) {
try {
$get_ = 'get_' . $attribute;
$object_filtered[$attribute] = $object->$get_();
if(!is_array($attribute)) {
$get_ = 'get_' . $attribute;
$object_filtered[ $attribute ] = $object->$get_();
}
} catch ( \Error $error ) {
// Do nothing
}

View File

@ -169,7 +169,7 @@ class REST_Collections_Controller extends REST_Controller {
$item_arr['current_user_can_edit'] = $item->can_edit();
}
#unset($item_arr['moderators_ids']);
unset($item_arr['moderators_ids']);
} else {
$attributes_to_filter = $request['fetch_only'];

View File

@ -123,7 +123,11 @@ class REST_Fields_Controller extends REST_Controller {
$collection_id = $request['collection_id'];
$field_id = $request['field_id'];
if($request['fetch'] === 'all_field_values'){
if($request['fetch'] === 'all_field_values' && $request['search']){
$results = $this->field_repository->fetch_all_field_values($collection_id, $field_id, $request['search']);
return new \WP_REST_Response($results, 200);
} elseif($request['fetch'] === 'all_field_values') {
$results = $this->field_repository->fetch_all_field_values($collection_id, $field_id);
return new \WP_REST_Response($results, 200);
@ -285,6 +289,7 @@ class REST_Fields_Controller extends REST_Controller {
* @param \WP_REST_Request $request
*
* @return \WP_Error|\WP_REST_Response
* @throws \Exception
*/
public function get_items( $request ) {
if(isset($request['collection_id'])) {

View File

@ -320,6 +320,7 @@ class REST_Filters_Controller extends REST_Controller {
if($request['context'] === 'edit'){
$item_arr['current_user_can_edit'] = $item->can_edit();
$item_arr['filter_type_object'] = $item->get_filter_type_object()->__toArray();
$item_arr['enabled'] = $item->get_enabled_for_collection();
}
return $item_arr;
@ -332,10 +333,15 @@ class REST_Filters_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 );
if ($request['include_disabled'] === 'yes') {
$args['include_disabled'] = true;
}
if(!isset($request['collection_id'])) {
$args['meta_query'][] = [
'key' => 'collection_id',

View File

@ -94,8 +94,8 @@ class REST_Items_Controller extends REST_Controller {
*
* @return mixed
*/
private function add_metadata_to_item($item_object, $item_array){
$item_metadata = $item_object->get_fields();
private function add_metadata_to_item($item_object, $item_array, $args = []){
$item_metadata = $item_object->get_fields($args);
foreach($item_metadata as $index => $me){
$field = $me->get_field();
@ -141,7 +141,23 @@ class REST_Items_Controller extends REST_Controller {
$attributes_to_filter = $request['fetch_only'];
return $this->filter_object_by_attributes($item, $attributes_to_filter);
# Always returns id
if(is_array($attributes_to_filter)) {
$attributes_to_filter[] = 'id';
} else {
$attributes_to_filter = array($attributes_to_filter, 'id');
}
$item_arr = $this->filter_object_by_attributes($item, $attributes_to_filter);
if(is_array($attributes_to_filter) && array_key_exists('meta', $attributes_to_filter)){
$args = array('post__in' => $attributes_to_filter['meta']);
$item_arr = $this->add_metadata_to_item($item, $item_arr, $args);
}
return $item_arr;
}
return $item;
@ -371,7 +387,9 @@ class REST_Items_Controller extends REST_Controller {
if($prepared_item->validate()){
$updated_item = $this->items_repository->update($prepared_item);
do_action('tainacan-api-item-updated', $updated_item, $attributes);
return new \WP_REST_Response($this->prepare_item_for_response($updated_item, $request), 200);
}

View File

@ -55,6 +55,16 @@ class REST_Logs_Controller extends REST_Controller {
)
)
);
register_rest_route($this->namespace, '/collection/(?P<collection_id>[\d]+)/' . $this->rest_base,
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_items'),
'permission_callback' => array($this, 'get_items_permissions_check'),
'args' => $this->get_endpoint_args_for_item_schema( \WP_REST_Server::READABLE)
)
)
);
}
/**
@ -90,7 +100,49 @@ class REST_Logs_Controller extends REST_Controller {
* @throws \Exception
*/
public function get_items( $request ) {
$args = $this->prepare_filters($request);
$args = $this->prepare_filters( $request );
if($request['collection_id']){
$collection_id = $request['collection_id'];
$collection_repository = Repositories\Collections::get_instance();
$collection = $collection_repository->fetch($collection_id);
if(!$collection){
return new \WP_REST_Response([
'error_message' => __('A collection with that ID not exists.', 'tainacan'),
'collection_id' => $collection_id
], 400);
}
if($args &&
array_key_exists('meta_query', $args) &&
array_key_exists('relation', $args['meta_query'])){
$metaq = $args['meta_query'];
unset($args['meta_query']);
$args['meta_query'][] = $metaq;
$args['meta_query']['relation'] = 'AND';
} elseif($args &&
array_key_exists('meta_query', $args)){
$args['meta_query']['relation'] = 'AND';
}
$args = array_merge_recursive(array(
'meta_query' => array(
'collection_clause' => array(
'key' => 'collection_id',
'value' => $collection_id,
'compare' => '='
)
)
), $args);
}
$logs = $this->logs_repository->fetch($args);

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

View File

@ -78,4 +78,28 @@ class Embed {
return $pdf;
}
/**
* Retrieves the thumbnail URL, if provided, for a given URL
*
* @param $string $url the URL for the content
* @return string|null The thumbnail URL or null on failure
*/
public function oembed_get_thumbnail($url) {
add_filter( 'oembed_dataparse', [$this, 'oembed_get_thumbnail_filter'], 10, 3);
$return = wp_oembed_get($url);
remove_filter( 'oembed_dataparse', [$this, 'oembed_get_thumbnail_filter']);
return $return;
}
public function oembed_get_thumbnail_filter($return, $data, $url) {
if ( isset($data->thumbnail_url) ) {
return $data->thumbnail_url;
}
return null;
}
}

View File

@ -0,0 +1,118 @@
<?php
namespace Tainacan;
/**
* Class withe helpful methods to handle media in Tainacan
*/
class Media {
private static $instance = null;
public static function get_instance() {
if(!isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
protected function __construct() {
}
/**
* Insert an attachment from an URL address.
*
* @param String $url
* @param Int $post_id (optional) the post this attachement should be attached to. empty for none
* @return Int|false Attachment ID. False on failure
*/
public function insert_attachment_from_url($url, $post_id = null) {
if( !class_exists( '\WP_Http' ) )
include_once( ABSPATH . WPINC . '/class-http.php' );
$http = new \WP_Http();
$response = $http->request( $url );
if( !is_array($response) || !isset($response['response']) || $response['response']['code'] != 200 ) {
return false;
}
return $this->insert_attachment_from_blob($response['body'], basename($url), $post_id);
}
/**
* Insert an attachment from an URL address.
*
* @param blob $blob bitstream of the attachment
* @param String $filename The filename that will be created
* @param Int $post_id (optional) the post this attachement should be attached to. empty for none
* @return Int|false Attachment ID. False on failure
*/
public function insert_attachment_from_blob($blob, $filename, $post_id = null) {
$upload = wp_upload_bits( $filename, null, $blob );
if( !empty( $upload['error'] ) ) {
return false;
}
$file_path = $upload['file'];
$file_name = basename( $file_path );
$file_type = wp_check_filetype( $file_name, null );
$attachment_title = sanitize_file_name( pathinfo( $file_name, PATHINFO_FILENAME ) );
$wp_upload_dir = wp_upload_dir();
$post_info = array(
'guid' => $wp_upload_dir['url'] . '/' . $file_name,
'post_mime_type' => $file_type['type'],
'post_title' => $attachment_title,
'post_content' => '',
'post_status' => 'inherit',
);
// Create the attachment
$attach_id = wp_insert_attachment( $post_info, $file_path, $post_id );
// Include image.php
require_once( ABSPATH . 'wp-admin/includes/image.php' );
// Define attachment metadata
$attach_data = wp_generate_attachment_metadata( $attach_id, $file_path );
// Assign metadata to attachment
wp_update_attachment_metadata( $attach_id, $attach_data );
return $attach_id;
}
/**
* Extract an image from the first page of a pdf file
*
* @param string $filepath The pdf filepath in the server
* @return blob bitstream of the image in jpg format
*/
public function get_pdf_cover($filepath) {
$blob = apply_filters('tainacan-extract-pdf-cover', null, $filepath);
if ($blob) {
return $blob;
}
if (!class_exists('\Imagick')) {
return null;
}
if ( mime_content_type($filepath) != 'application/pdf') {
return null;
}
$imagick = new \Imagick($filepath);
$imagick->setIteratorIndex(0);
$imagick->setImageFormat('jpg');
return $imagick->getImageBlob();
}
}

View File

@ -12,7 +12,7 @@ class Collection extends Entity {
protected
$diplay_name,
$full,
$featured_img_id,
$_thumbnail_id,
$modification_date,
$creation_date,
$author_id,
@ -68,9 +68,10 @@ class Collection extends Entity {
public function __toArray() {
$array_collection = parent::__toArray();
$array_collection['featured_image'] = $this->get_featured_image();
$array_collection['header_image'] = $this->get_header_image();
$array_collection['author_name'] = $this->get_author_name();
$array_collection['thumbnail'] = $this->get_thumbnail();
$array_collection['header_image'] = $this->get_header_image();
$array_collection['author_name'] = $this->get_author_name();
$array_collection['url'] = get_permalink( $this->get_id() );
return $array_collection;
}
@ -99,6 +100,7 @@ class Collection extends Entity {
$args = array(
'labels' => $cpt_labels,
'hierarchical' => true,
'description' => $this->get_description(),
//'supports' => array('title'),
//'taxonomies' => array(self::TAXONOMY),
'public' => true,
@ -204,7 +206,7 @@ class Collection extends Entity {
/**
* @return false|string
*/
function get_featured_image() {
function get_thumbnail() {
return get_the_post_thumbnail_url( $this->get_id(), 'full' );
}
@ -218,18 +220,18 @@ class Collection extends Entity {
/**
* @param $id
*/
function set_featured_img_id( $id ) {
$this->set_mapped_property( 'featured_img_id', $id );
function set__thumbnail_id( $id ) {
$this->set_mapped_property( '_thumbnail_id', $id );
}
/**
* @return int|string
*/
function get_featured_img_id() {
$featured_img_id = $this->get_mapped_property("featured_img_id");
if ( isset( $featured_img_id ) ) {
return $featured_img_id;
function get__thumbnail_id() {
$_thumbnail_id = $this->get_mapped_property("_thumbnail_id");
if ( isset( $_thumbnail_id ) ) {
return $_thumbnail_id;
}
return get_post_thumbnail_id( $this->get_id() );

View File

@ -395,14 +395,15 @@ class Field extends Entity {
function is_required() {
return $this->get_required() === 'yes';
}
/**
* {@inheritdoc }
*
* Also validates the field, calling the validate_options callback of the Field Type
*
* @return bool valid or not
*/
/**
* {@inheritdoc }
*
* Also validates the field, calling the validate_options callback of the Field Type
*
* @return bool valid or not
* @throws \Exception
*/
public function validate() {
$is_valid = parent::validate();

View File

@ -20,8 +20,9 @@ class Filter extends Entity {
$filter_type_options;
static $post_type = 'tainacan-filter';
/**
public $enabled_for_collection = true;
/**
* {@inheritDoc}
* @see \Tainacan\Entities\Entity::repository
* @var string
@ -188,13 +189,29 @@ class Filter extends Entity {
$this->set_mapped_property('filter_type', ( is_object( $value ) ) ? get_class( $value ) : $value );
}
/**
* {@inheritdoc }
*
* Also validates the field, calling the validate_options callback of the Field Type
*
* @return bool valid or not
*/
/**
* Transient property used to store the status of the filter for a particular collection
*
* Used by the API to tell front end when a field is disabled
*
*/
public function get_enabled_for_collection() {
return $this->enabled_for_collection;
}
public function set_enabled_for_collection($value) {
$this->enabled_for_collection = $value;
}
/**
* {@inheritdoc }
*
* Also validates the field, calling the validate_options callback of the Field Type
*
* @return bool valid or not
* @throws \Exception
*/
public function validate() {
$is_valid = parent::validate();
if (false === $is_valid)

View File

@ -13,7 +13,7 @@ class Item extends Entity {
$terms,
$diplay_name,
$full,
$featured_img_id,
$_thumbnail_id,
$modification_date,
$creation_date,
$author_id,
@ -52,9 +52,10 @@ class Item extends Entity {
public function __toArray() {
$array_item = parent::__toArray();
$array_item['featured_image'] = $this->get_featured_image();
$array_item['featured_img_id'] = $this->get_featured_img_id();
$array_item['author_name'] = $this->get_author_name();
$array_item['thumbnail'] = $this->get_thumbnail();
$array_item['_thumbnail_id'] = $this->get__thumbnail_id();
$array_item['author_name'] = $this->get_author_name();
$array_item['url'] = get_permalink( $this->get_id() );
return $array_item;
}
@ -125,24 +126,24 @@ class Item extends Entity {
/**
* @return false|string
*/
function get_featured_image() {
function get_thumbnail() {
return get_the_post_thumbnail_url( $this->get_id(), 'full' );
}
/**
* @param $id
*/
function set_featured_img_id( $id ) {
$this->set_mapped_property( 'featured_img_id', $id );
function set__thumbnail_id( $id ) {
$this->set_mapped_property( '_thumbnail_id', $id );
}
/**
* @return int|string
*/
function get_featured_img_id() {
$featured_img_id = $this->get_mapped_property("featured_img_id");
if ( isset( $featured_img_id ) ) {
return $featured_img_id;
function get__thumbnail_id() {
$_thumbnail_id = $this->get_mapped_property("_thumbnail_id");
if ( isset( $_thumbnail_id ) ) {
return $_thumbnail_id;
}
return get_post_thumbnail_id( $this->get_id() );
@ -333,10 +334,10 @@ class Item extends Entity {
*
* @return array Array of ItemMetadata objects
*/
function get_fields() {
function get_fields($args = []) {
$Tainacan_Item_Metadata = \Tainacan\Repositories\Item_Metadata::get_instance();
return $Tainacan_Item_Metadata->fetch( $this, 'OBJECT' );
return $Tainacan_Item_Metadata->fetch( $this, 'OBJECT', $args );
}
@ -506,7 +507,8 @@ class Item extends Entity {
$output = '';
if ( $type == 'url' ) {
$output .= apply_filters('the_content', $this->get_document());
global $wp_embed;
$output .= $wp_embed->autoembed($this->get_document());
} elseif ( $type == 'text' ) {
$output .= $this->get_document();
} elseif ( $type == 'attachment' ) {

View File

@ -17,7 +17,8 @@ class Log extends Entity {
$blog_id,
$user_id,
$log_date,
$user_name;
$user_name,
$collection_id;
static $post_type = 'tainacan-log';
/**
@ -51,6 +52,21 @@ class Log extends Entity {
return $array_log;
}
/**
* @param $collection_id
*/
function set_collection_id($collection_id){
$this->set_mapped_property('collection_id', $collection_id);
}
/**
* @return mixed|null
*/
function get_collection_id(){
return $this->get_mapped_property('collection_id');
}
/**
* Return the Log title
*
@ -272,6 +288,12 @@ class Log extends Entity {
$log->set_log_diffs( $diffs );
if($parent > 0) $log->set_parent($parent);
if(array_search( 'Tainacan\Traits\Entity_Collection_Relation', class_uses($new_value))) {
$log->set_collection_id( $new_value->get_collection_id() );
} elseif($new_value instanceof Collection){
$log->set_collection_id( $new_value->get_id());
}
if ( ! is_null( $new_value ) ) {
$log->set_value( $new_value );
} elseif ( $msn === false ) {

View File

@ -16,7 +16,9 @@
style="padding-left: 0px;">
<b-field :label="$i18n.get('label_name')">
<b-input v-model="name"/>
<b-input
:class="{'has-content': name != undefined && name != ''}"
v-model="name"/>
</b-field>
<b-field :label="$i18n.get('label_parent_term')">

View File

@ -2,13 +2,14 @@
<div class="block">
<b-taginput
size="is-small"
rounded
icon="magnify"
:allow-new="allowNew"
@input="emitChange"
v-model="selected"
:data="labels"
field="label"
attached
:class="{'has-selected': selected != undefined && selected != []}"
autocomplete
@typing="search"/>
</div>

View File

@ -6,7 +6,7 @@
:addons="false"
:type="taxonomyType"
:message="taxonomyMessage">
<label class="label">
<label class="label is-inline">
{{ $i18n.get('label_select_category') }}<span :class="taxonomyType" >&nbsp;*&nbsp;</span>
<help-button
:title="$i18n.getHelperTitle('tainacan-category', 'taxonomy_id')"

View File

@ -1,5 +1,6 @@
<template>
<b-datepicker
:class="{'has-content': dateValue != undefined && dateValue != ''}"
:id="id"
v-model="dateValue"
@blur="onBlur"

View File

@ -1,5 +1,6 @@
<template>
<b-input
:class="{'has-content': inputValue !== undefined && inputValue !== ''}"
:id="id"
type="number"
:value="inputValue"

View File

@ -5,7 +5,7 @@
:listen="setError"
:type="collectionType"
:message="collectionMessage">
<label class="label">
<label class="label is-inline">
{{ $i18n.get('label_collection_related') }}<span :class="collectionType" >&nbsp;*&nbsp;</span>
<help-button
:title="$i18n.getHelperTitle('tainacan-relationship', 'collection_id')"
@ -115,8 +115,9 @@
this.fields = [];
this.hasFields = false;
this.modelSearch = [];
this.emitValues();
}
this.emitValues();
},
modelSearch( value ){
this.modelSearch = value;
@ -199,9 +200,12 @@
type: 'is-danger'
})
}
this.emitValues();
})
.catch(() => {
this.hasFields = false;
this.emitValues();
});
},

View File

@ -4,8 +4,11 @@
:id="id"
v-model="selected"
:data="options"
:maxtags="field.field.multiple === 'yes' ? 100 : 1"
autocomplete
attached
:loading="loading"
:class="{'has-selected': selected != undefined && selected != []}"
field="label"
@typing="search"/>
@ -139,3 +142,9 @@
}
}
</script>
<style>
.help.counter {
display: none;
}
</style>

View File

@ -5,7 +5,7 @@
:addons="false"
:type="optionType"
:message="optionMessage">
<label class="label">
<label class="label is-inline">
{{ $i18n.getHelperTitle('tainacan-selectbox', 'options') }}<span :class="optionType" >&nbsp;*&nbsp;</span>
<help-button
:title="$i18n.getHelperTitle('tainacan-selectbox', 'options')"
@ -16,6 +16,8 @@
@input="emitValues()"
@focus="clear()"
icon="label"
attached
:class="{'has-selected': options != undefined && options != []}"
:placeholder="$i18n.get('new')"/>
</b-field>
</section>

View File

@ -2,7 +2,9 @@
<div>
<b-select
:id = "id"
:placeholder="$i18n.get('label_selectbox_init')"
v-model="selected"
:class="{'is-empty': selected == undefined || selected == ''}"
@input="onChecked()">
<option
v-for="(option, index) in getOptions"
@ -24,7 +26,7 @@
},
data(){
return {
selected:''
selected: undefined
}
},
props: {
@ -52,7 +54,8 @@
methods: {
onChecked() {
this.$emit('blur');
this.onInput(this.selected)
if (this.selected != undefined)
this.onInput(this.selected)
},
onInput($event) {
this.$emit('input', $event);

View File

@ -3,62 +3,62 @@
:addons="false"
:message="getErrorMessage"
:type="fieldTypeMessage">
<b-collapse >
<span @click="isCollapsed = !isCollapsed">
<b-icon
type="is-secondary"
:icon="!isCollapsed ? 'menu-down' : 'menu-right'" />
<label class="label">{{ field.field.name }}</label>
<span
v-if="field.field.required == 'yes'"
class="required-field-asterisk"
:class="fieldTypeMessage">*</span>
<span class="field-type">({{ $i18n.get(field.field.field_type_object.component) }})</span>
</span>
<span
class="collapse-handle"
@click="$emit('changeCollapse', !isCollapsed)">
<b-icon
type="is-secondary"
:icon="isCollapsed ? 'menu-down' : 'menu-right'" />
<label class="label">{{ field.field.name }}</label>
<span
v-if="field.field.required == 'yes'"
class="required-field-asterisk"
:class="fieldTypeMessage">*</span>
<span class="field-type">({{ $i18n.get(field.field.field_type_object.component) }})</span>
<help-button
:title="field.field.name"
:message="field.field.description"/>
<div
v-show="!isCollapsed"
v-if="isTextInputComponent( field.field.field_type_object.component )">
<component
:id="field.field.field_type_object.component + '-' + field.field.slug"
:is="field.field.field_type_object.component"
v-model="inputs[0]"
:field="field"
@blur="changeValue()"/>
<div v-if="field.field.multiple == 'yes'">
<div
v-if="index > 0"
v-for="(input, index) in inputsList "
:key="index"
class="multiple-inputs">
<component
:id="field.field.field_type_object.component + '-' + field.field.slug"
:is="field.field.field_type_object.component"
v-model="inputs[index]"
:field="field"
@blur="changeValue()"/><a
class="button"
v-if="index > 0"
@click="removeInput(index)">-</a>
</div>
<a
</span>
<div
v-show="isCollapsed"
v-if="isTextInputComponent( field.field.field_type_object.component )">
<component
:id="field.field.field_type_object.component + '-' + field.field.slug"
:is="field.field.field_type_object.component"
v-model="inputs[0]"
:field="field"
@blur="changeValue()"/>
<div v-if="field.field.multiple == 'yes'">
<div
v-if="index > 0"
v-for="(input, index) in inputsList "
:key="index"
class="multiple-inputs">
<component
:id="field.field.field_type_object.component + '-' + field.field.slug"
:is="field.field.field_type_object.component"
v-model="inputs[index]"
:field="field"
@blur="changeValue()"/><a
class="button"
@click="addInput">+</a>
v-if="index > 0"
@click="removeInput(index)">-</a>
</div>
<a
class="button"
@click="addInput">+</a>
</div>
<div
v-show="!isCollapsed"
v-else>
<component
:id="field.field.field_type_object.component + '-' + field.field.slug"
:is="field.field.field_type_object.component"
v-model="inputs"
:field="field"
@blur="changeValue()"/>
</div>
</b-collapse>
</div>
<div
v-show="isCollapsed"
v-else>
<component
:id="field.field.field_type_object.component + '-' + field.field.slug"
:is="field.field.field_type_object.component"
v-model="inputs"
:field="field"
@blur="changeValue()"/>
</div>
</b-field>
</template>
@ -71,7 +71,7 @@
field: {
type: Object
},
isCollapsed: Boolean
isCollapsed: true // Field Collapses
},
data(){
return {
@ -92,7 +92,7 @@
this.setFieldTypeMessage('is-danger');
for (let error of errors) {
for (let index of Object.keys(error)) {
this.$console.log(index);
//this.$console.log(index);
msg += error[index] + '\n';
}
}
@ -133,6 +133,8 @@
},
setFieldTypeMessage( message ){
this.fieldTypeMessage = message;
if (message != '')
this.$emit('changeCollapse', true);
}
}
}
@ -166,8 +168,9 @@
.help-wrapper {
top: -0.2em;
}
.collapse .collapse-content>div {
margin-left: 45px;
.collapse-handle {
cursor: pointer;
position: relative;
}
}
</style>

View File

@ -1,5 +1,6 @@
<template>
<b-input
:class="{'has-content': inputValue !== undefined && inputValue !== ''}"
:id="id"
:value="inputValue"
@blur="onBlur"

View File

@ -1,6 +1,8 @@
<template>
<b-input
:class="{'has-content': inputValue !== undefined && inputValue !== ''}"
:id="id"
size="is-small"
type="textarea"
:value="inputValue"
@blur="onBlur"

View File

@ -1,22 +1,22 @@
<template>
<div class="block">
<b-autocomplete
rounded
icon="magnify"
size="is-small"
:id="id"
v-model="selected"
:data="options"
@input="search"
:loading="loading"
:loading="isLoading"
field="label"
@select="option => setResults(option) ">
<template slot-scope="props">
<div class="media">
<div
class="media-left"
<div
class="media-left"
v-if="props.option.img">
<img
width="32"
<img
width="32"
:src="`${props.option.img}`">
</div>
<div class="media-content">
@ -25,17 +25,18 @@
</div>
</template>
</b-autocomplete>
<br>
<div class="field has-text-centered">
<b-tag
v-if="results !== ''"
type="is-primary"
size="is-small"
closable
@close="clearSearch()">
{{ label }}
</b-tag>
</div>
<!-- <ul
class="selected-list-box"
v-if="selected !== '' && selected !== undefined">
<li>
<b-tag
attached
closable
@close="clearSearch()">
{{ label }}
</b-tag>
</li>
</ul> -->
</div>
</template>

View File

@ -4,7 +4,7 @@
v-for="(option,index) in getOptions(0)"
:key="index"
:value="index"
class="field">
class="control">
<b-checkbox
:style="{ paddingLeft: (option.level * 30) + 'px' }"
v-model="selected"

View File

@ -2,17 +2,17 @@
<div class="block">
<b-select
:id = "id"
:laoding = "isLoading"
:loading = "isLoading"
v-model = "selected"
@input = "onSelect()"
size="is-small"
expanded>
<option value="">{{ $i18n.get('label_selectbox_init') }}...</option>
<option
v-for=" (option, index) in options"
:key="index"
:label="option.name"
:value="option.id"
border>{{ option.name }}</option>
:value="option.id">{{ option.name }}</option>
</b-select>
</div>
</template>

View File

@ -2,12 +2,13 @@
<div class="block">
<b-taginput
size="is-small"
rounded
icon="magnify"
v-model="selected"
:data="options"
:loading="isLoading"
autocomplete
field="label"
attached
:class="{'has-selected': selected != undefined && selected != []}"
@typing="search" />
</div>
</template>
@ -75,12 +76,12 @@
let promise = null;
this.options = [];
const q = query;
axios.get('/collection/'+ this.collection +'/fields/' + this.field + '?context=edit')
.then( res => {
let field = res.data;
promise = this.getValuesCategory( field.field_type_options.taxonomy_id, q );
this.isLoading = true;
promise.then( () => {
this.isLoading = false;
})

View File

@ -1,32 +1,38 @@
<template>
<div>
<!-- Date -->
<div v-if="type === 'date'">
<b-datepicker
size="is-small"
:placeholder="$i18n.get('label_selectbox_init')"
:class="{'has-content': date_init !== undefined && date_init !== ''}"
v-model="date_init"
@input="validate_values()"
:readonly="false"
icon="calendar-today"/>
<br>
<b-datepicker
size="is-small"
@focus="isTouched = true"
@input="validate_values()"
icon="calendar-today"/>
<b-datepicker
:placeholder="$i18n.get('label_selectbox_init')"
:class="{'has-content': date_end !== undefined && date_end !== ''}"
v-model="date_end"
size="is-small"
@input="validate_values()"
@focus="isTouched = true"
:readonly="false"
icon="calendar-today"/>
<br>
</div>
<div
class="columns"
<!-- Numeric -->
<div
class="columns"
v-else>
<b-input
:class="{'has-content': value_init !== undefined && value_init !== ''}"
size="is-small"
type="number"
@input="validate_values()"
class="column"
v-model="value_init"/>
<b-input
:class="{'has-content': value_end !== undefined && value_end !== ''}"
size="is-small"
type="number"
@input="validate_values()"
@ -34,16 +40,18 @@
class="column"
v-model="value_end"/>
</div>
<div class="field has-text-centered">
<b-tag
v-if="isValid && !clear"
type="is-primary"
size="is-small"
closable
@close="clearSearch()">
{{ showSearch() }}
</b-tag>
</div>
<ul
class="selected-list-box"
v-if="isValid && !clear">
<li>
<b-tag
attached
closable
@close="clearSearch()">
{{ showSearch() }}
</b-tag>
</li>
</ul>
</div>
</template>
@ -73,15 +81,15 @@
return {
value_init: null,
value_end: null,
date_init: new Date,
date_end: new Date,
date_init: undefined,
date_end: undefined,
isTouched: false,
isValid: false,
clear: false,
type: 'numeric',
collection: '',
field: '',
field_object: {}
field_object: {},
}
},
props: {
@ -93,20 +101,38 @@
id: '',
query: Object
},
watch: {
isTouched( val ){
if ( val && this.date_init === null)
this.date_init = new Date();
if ( val && this.date_end === null)
this.date_end = new Date();
this.isTouched = val;
}
},
methods: {
// only validate if the first value is higher than first
validate_values(){
if( this.type === 'date' ){
if (this.date_init === undefined)
this.date_init = new Date();
if (this.date_end === undefined)
this.date_end = new Date();
if ( this.date_init > this.date_end ) {
let result = this.date_init;
result.setDate(result.getDate() + 1);
this.date_end = result;
result.setDate(result.getDate() - 1);
this.date_init = result;
//this.error_message();
}
} else {
this.value_end = (this.value_end === null) ? 0 : this.value_end;
this.value_init = (this.value_init === null) ? 0 : this.value_init;
} else {
if ( parseFloat( this.value_init ) > parseFloat( this.value_end )) {
this.value_end = parseFloat( this.value_init ) + 1;
//this.error_message();
@ -149,16 +175,19 @@
},
showSearch(){
if( this.type === 'date' ){
let date_init = ('00' + this.date_init.getUTCDate()).slice(-2) + '/' + ('00' + (this.date_init.getUTCMonth() + 1)).slice(-2)
+ '/' + this.date_init.getUTCFullYear();
let date_end = ('00' + this.date_end.getUTCDate()).slice(-2) + '/' + ('00' + (this.date_end.getUTCMonth() + 1)).slice(-2)
+ '/' + this.date_end.getUTCFullYear();
return date_init + ' - ' + date_end;
if( this.date_init === null || this.date_end === null ){
this.clear = true;
return '';
}
return this.date_init.toLocaleString().split(' ')[0] + ' - ' + this.date_end.toLocaleString().split(' ')[0];
} else {
return this.value_init + ' - ' +this.value_end;
}
},
clearSearch(){
this.clear = true;
this.$emit('input', {
filter: 'range',
@ -167,6 +196,16 @@
collection_id: ( this.collection_id ) ? this.collection_id : this.filter.collection_id,
value: ''
});
if( this.type === 'date' ){
this.date_init = null;
this.date_end = null;
this.isTouched = false;
} else {
this.value_end = null;
this.value_init = null;
this.isTouched = false;
}
},
// emit the operation for listeners
@ -175,21 +214,41 @@
let type = '';
if( vm.type === 'date' ){
let date_init = vm.date_init.getUTCFullYear() + '-' +
('00' + (vm.date_init.getUTCMonth() + 1)).slice(-2) + '-' +
('00' + vm.date_init.getUTCDate()).slice(-2);
let date_end = vm.date_end.getUTCFullYear() + '-' +
('00' + (vm.date_end.getUTCMonth() + 1)).slice(-2) + '-' +
('00' + vm.date_end.getUTCDate()).slice(-2);
values = [ date_init, date_end ];
type = 'DATE';
if( vm.date_init === null && vm.date_end === null ){
values = [];
type = 'DATE';
vm.isValid = false;
vm.clear = true;
} else {
let date_init = vm.date_init.getUTCFullYear() + '-' +
('00' + (vm.date_init.getUTCMonth() + 1)).slice(-2) + '-' +
('00' + vm.date_init.getUTCDate()).slice(-2);
let date_end = vm.date_end.getUTCFullYear() + '-' +
('00' + (vm.date_end.getUTCMonth() + 1)).slice(-2) + '-' +
('00' + vm.date_end.getUTCDate()).slice(-2);
values = [ date_init, date_end ];
type = 'DATE';
vm.isValid = true;
vm.clear = false;
}
} else {
values = [ vm.value_init, vm.value_end ];
type = 'DECIMAL';
if( vm.value_init === null || vm.value_end === null
|| vm.value_init === '' || vm.value_end === ''){
values = [];
type = 'DECIMAL';
vm.isValid = false;
vm.clear = true;
return;
} else {
values = [ vm.value_init, vm.value_end ];
type = 'DECIMAL';
vm.isValid = true;
vm.clear = false;
}
}
vm.isValid = true;
vm.clear = false;
vm.$emit('input', {
filter: 'range',
type: type,
@ -201,4 +260,4 @@
}
}
}
</script>
</script>

View File

@ -12,8 +12,14 @@ export const filter_type_mixin = {
query: {}
},
methods: {
getValuesPlainText(field_id) {
return axios.get('/collection/' + this.collection + '/fields/' + field_id + '?fetch=all_field_values')
getValuesPlainText(fieldId, search) {
let url = '/collection/' + this.collection + '/fields/' + fieldId + '?fetch=all_field_values&nopaging=1';
if( search ){
url += "&search=" + search;
}
return axios.get(url)
.then(res => {
if (res.data && res.data[0]) {
for (let metadata of res.data[0]) {
@ -40,7 +46,7 @@ export const filter_type_mixin = {
.then(res => {
if (res.data.length > 0) {
for (let item of res.data) {
this.options.push({label: item.title, value: item.id, img: item.featured_image });
this.options.push({label: item.title, value: item.id, img: item.thumbnail });
}
}
})

View File

@ -5,14 +5,15 @@
:loading = "isLoading"
v-model = "selected"
@input = "onSelect($event)"
expanded>
:placeholder="$i18n.get('label_selectbox_init')"
expanded
:class="{'is-empty': selected == undefined || selected == ''}">
<option value="">{{ $i18n.get('label_selectbox_init') }}...</option>
<option
v-for="(option, index) in options"
:key="index"
:label="option.label"
:value="option.value"
border>{{ option.label }}</option>
:value="option.value">{{ option.label }}</option>
</b-select>
</div>
</template>
@ -59,7 +60,7 @@
return metadata.value;
}
}
return '';
return undefined;
}
},
methods: {
@ -82,7 +83,7 @@
filter: 'selectbox',
field_id: this.field,
collection_id: ( this.collection_id ) ? this.collection_id : this.filter.collection_id,
value: value
value: ( value ) ? value : ''
});
},
selectedValues(){

View File

@ -2,13 +2,13 @@
<div class="block">
<b-taginput
size="is-small"
rounded
icon="magnify"
v-model="selected"
:data="options"
autocomplete
:loading="loading"
:loading="isLoading"
field="label"
attached
:class="{'has-selected': selected != undefined && selected != []}"
@typing="search"/>
</div>
</template>
@ -79,7 +79,7 @@
} else {
promise = this.getValuesPlainText( this.field, query );
}
this.isLoading = true;
promise.then(() => {
this.isLoading = false;
}).catch( error => {

View File

@ -1,12 +1,18 @@
<template>
<b-field
id="filter-item-forms"
:message="getErrorMessage"
:type="filterTypeMessage">
<b-collapse :open="opened">
<label slot="trigger">
<b-collapse
class="show"
:open="open">
<label
class="label"
slot="trigger"
slot-scope="props">
<b-icon
icon="menu-down"
size="is-small" />
:icon="props.open ? 'menu-down' : 'menu-right'"
/>
{{ filter.name }}
</label>
@ -30,7 +36,7 @@
props: {
filter: Object,
query: Object,
opened: false,
open: false,
},
data(){
return {
@ -65,4 +71,197 @@
}
}
}
</script>
</script>
<style lang="scss">
@import "../../../src/admin/scss/_variables.scss";
#filter-item-forms {
.datepicker {
.dropdown-item {
background-color: white !important;
}
@media screen and (min-width: 1024px) {
.datepicker-header {
.pagination-list {
.field.has-addons {
display: table-cell !important;
width: 78px !important;
.control {
height: 24px !important;
width: 74px !important;
select {
padding-left: 1px !important;
}
}
}
}
.pagination-previous {
margin: 0;
height: 24px;
padding: 0;
font-size: 12px;
}
.pagination-next {
margin: 0;
height: 24px;
padding: 0;
font-size: 12px;
}
}
.dropdown-item {
padding: 0.8em;
}
.dropdown-menu {
min-width: 100% !important;
max-width: 165px !important;
}
.datepicker-table {
margin-bottom: 0px;
.datepicker-cell {
padding: 0.2rem 0.1rem !important;
}
}
.select {
select {
display: unset;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.dropdown-content {
max-width: 165px !important;
border-radius: 2px !important;
padding: 0px;
}
}
}
.collapse-trigger {
margin-left: -5px;
.icon {
margin-right: 12px;
}
}
.collapse-content {
margin-top: 12px;
}
.column {
padding: 0.75rem 1px 0.75rem 0 !important;
}
.select {
padding-top: 0px !important;
select {
font-size: 14px;
border: none;
border-radius: 1px !important;
font-weight: normal;
height: 30px !important;
padding: 2px 25px 2px 15px !important;
margin-top: 0px !important;
margin-bottom: 0px !important;
background-color: white;
color: black;
&:focus > option:checked, &:focus > option:hover {
background-color: $primary-lighter !important;
}
}
&:not(.is-multiple)::after {
content: "\F35D" !important;
font: normal normal normal 24px/1 "Material Design Icons" !important;
border: none !important;
transform: none;
margin-top: -0.6em;
right: 0.95em;
color: $primary;
}
}
.label {
font-weight: normal;
font-size: 14px;
display: inline-flex;
}
.input, .textarea, .taginput-container {
font-size: 14px;
border: none !important;
border-radius: 1px !important;
background-color: white;
color: $tainacan-input-color;
box-shadow: none !important;
transition: background-color 0.1s;
height: 2.25em !important;
&:focus, &:active {
box-shadow: none !important;
border: none !important;
}
}
.taginput-container {
display: table-cell;
}
.input {
overflow: hidden;
display: unset;
white-space: nowrap;
text-overflow: ellipsis;
}
.control:not(.taginput) {
.tags {
.tag:not(a.is-delete) {
display: unset;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
border-radius: 0;
width: 86%;
}
.is-delete {
border-radius: 0;
}
}
}
.tag {
height: 2em !important;
}
.autocomplete {
.dropdown-content {
position: fixed !important;
}
}
.b-checkbox.checkbox {
font-weight: normal;
font-size: 12px;
margin-right: 2px;
}
}
</style>

View File

@ -68,12 +68,6 @@ class Collections extends Repository {
'type' => 'string',
'description' => __( 'The collection modification date', 'tainacan' )
],
'url' => [
'map' => 'guid',
'title' => __( 'Collection URL', 'tainacan' ),
'type' => 'string',
'description' => __( 'The collection URL', 'tainacan' )
],
'order' => [
'map' => 'menu_order',
'title' => __( 'Order', 'tainacan' ),
@ -186,10 +180,10 @@ class Collections extends Repository {
'description' => __( 'The IDs of users assigned as moderators of this collection', 'tainacan' ),
'validation' => ''
],
'featured_img_id' => [
'_thumbnail_id' => [
'map' => 'meta',
'title' => __( 'Featured image ID', 'tainacan' ),
'description' => __( 'Featured image ID', 'tainacan' )
'title' => __( 'Thumbnail', 'tainacan' ),
'description' => __( 'Squared reduced-size version of a picture that helps recognizing and organizing files', 'tainacan' )
]
] );

View File

@ -387,13 +387,13 @@ class Fields extends Repository {
if( $index !== false ) {
// skipping fields disabled if the arg is set
if( !$include_disabled && isset( $order[$index]['enabled'] ) && !$order[$index]['enabled'] ) {
continue;
}
// skipping fields disabled if the arg is set
if ( ! $include_disabled && isset( $order[ $index ]['enabled'] ) && ! $order[ $index ]['enabled'] ) {
continue;
}
$enable = ( isset( $order[$index]['enabled'] )) ? $order[$index]['enabled'] : true;
$item->set_enabled_for_collection($enable);
$enable = ( isset( $order[ $index ]['enabled'] ) ) ? $order[ $index ]['enabled'] : true;
$item->set_enabled_for_collection( $enable );
$result_ordinate[$index] = $item;
} else {
@ -648,10 +648,12 @@ class Fields extends Repository {
* @param $collection_id
* @param $field_id
*
* @param string $search
*
* @return array|null|object
* @throws \Exception
*/
public function fetch_all_field_values($collection_id, $field_id){
public function fetch_all_field_values($collection_id, $field_id, $search = ''){
global $wpdb;
// Clear the result cache
@ -663,17 +665,30 @@ class Fields extends Repository {
if( strpos( $field->get_field_type(), 'Core') !== false ){
$collection = new Entities\Collection( $collection_id );
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
$items = $Tainacan_Items->fetch( [], $collection, 'OBJECT');
$items = $Tainacan_Items->fetch( ['s' => $search], $collection, 'OBJECT');
$return = [];
foreach ($items as $item) {
if( strpos( $field->get_field_type(), 'Core_Title') !== false ){
$return[] = [ 'item_id' => $item->get_id(), 'field_id' => $field_id, 'mvalue' => $item->get_title() ];
$title = $item->get_title();
if(!empty($search) && stristr($title, $search) !== false) {
$return[] = [ 'item_id' => $item->get_id(), 'field_id' => $field_id, 'mvalue' => $title ];
} elseif (empty($search)) {
$return[] = [ 'item_id' => $item->get_id(), 'field_id' => $field_id, 'mvalue' => $title ];
}
} else {
$return[] = [ 'item_id' => $item->get_id(), 'field_id' => $field_id, 'mvalue' => $item->get_description() ];
$description = $item->get_description();
if(!empty($search) && stristr($description, $search) !== false) {
$return[] = [ 'item_id' => $item->get_id(), 'field_id' => $field_id, 'mvalue' => $description ];
} elseif (empty($search)) {
$return[] = [ 'item_id' => $item->get_id(), 'field_id' => $field_id, 'mvalue' => $description ];
}
}
}
$results = [];
if (!empty($return)) {
$results[] = $return;
}
@ -688,6 +703,12 @@ class Fields extends Repository {
$results = [];
$search_query = '';
if ($search) {
$search_param = '%' . $search . '%';
$search_query = $wpdb->prepare( "WHERE meta_value LIKE %s", $search_param );
}
// If no has logged user or actual user can not read private posts
if(get_current_user_id() === 0 || !current_user_can( $capabilities->read_private_posts)) {
$args = [
@ -700,6 +721,7 @@ class Fields extends Repository {
$post_statuses = get_post_stati( $args, 'names', 'and' );
foreach ($post_statuses as $post_status) {
$sql_string = $wpdb->prepare(
"SELECT item_id, field_id, mvalue
FROM (
@ -709,7 +731,7 @@ class Fields extends Repository {
) items
JOIN (
SELECT meta_key as field_id, meta_value as mvalue, post_id
FROM $wpdb->postmeta
FROM $wpdb->postmeta $search_query
) metas
ON items.item_id = metas.post_id AND metas.field_id = %d",
$item_post_type, $post_status, $field_id
@ -737,7 +759,7 @@ class Fields extends Repository {
) items
JOIN (
SELECT meta_key as field_id, meta_value as mvalue, post_id
FROM $wpdb->postmeta
FROM $wpdb->postmeta $search_query
) metas
ON items.item_id = metas.post_id AND metas.field_id = %d",
$item_post_type, $post_status, $field_id

View File

@ -339,7 +339,7 @@ class Filters extends Repository {
* @param array $args WP_Query args plus disabled_fields
* @param string $output The desired output format (@see \Tainacan\Repositories\Repository::fetch_output() for possible values)
*
* @return Array Entities\Field
* @return array Entities\Field
* @throws \Exception
*/
public function fetch_by_collection(Entities\Collection $collection, $args = [], $output = null){
@ -369,7 +369,7 @@ class Filters extends Repository {
return $this->order_result(
$this->fetch( $args, $output ),
$collection,
isset( $args['disabled_fields'] ) ? $args['disabled_fields'] : false
isset( $args['include_disabled'] ) ? $args['include_disabled'] : false
);
}
@ -382,7 +382,7 @@ class Filters extends Repository {
* @param Entities\Collection $collection
* @return array or WP_Query ordinate
*/
public function order_result( $result, Entities\Collection $collection ){
public function order_result( $result, Entities\Collection $collection, $include_disabled = false ){
$order = $collection->get_filters_order();
if($order) {
$order = ( is_array($order) ) ? $order : unserialize($order);
@ -396,6 +396,15 @@ class Filters extends Repository {
$index = array_search ( $id , array_column( $order , 'id') );
if( $index !== false ) {
// skipping fields disabled if the arg is set
if ( ! $include_disabled && isset( $order[ $index ]['enabled'] ) && ! $order[ $index ]['enabled'] ) {
continue;
}
$enable = ( isset( $order[ $index ]['enabled'] ) ) ? $order[ $index ]['enabled'] : true;
$item->set_enabled_for_collection( $enable );
$result_ordinate[$index] = $item;
} else {
$not_ordinate[] = $item;

View File

@ -185,7 +185,7 @@ class Item_Metadata extends Repository {
* @return array
* @throws \Exception
*/
public function fetch($object, $output = null ){
public function fetch($object, $output = null, $args = [] ){
if($object instanceof Entities\Item){
$Tainacan_Fields = \Tainacan\Repositories\Fields::get_instance();
@ -195,7 +195,7 @@ class Item_Metadata extends Repository {
return [];
}
$meta_list = $Tainacan_Fields->fetch_by_collection($collection, [], 'OBJECT' );
$meta_list = $Tainacan_Fields->fetch_by_collection($collection, $args, 'OBJECT' );
$return = [];

View File

@ -25,6 +25,7 @@ class Items extends Repository {
parent::__construct();
add_filter( 'posts_where', array(&$this, 'title_in_posts_where'), 10, 2 );
add_filter( 'posts_where', array(&$this, 'content_in_posts_where'), 10, 2 );
add_action( 'tainacan-api-item-updated', array(&$this, 'hook_api_updated_item'), 10, 2 );
}
public function get_map() {
@ -77,12 +78,6 @@ class Items extends Repository {
'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' ),
@ -106,10 +101,10 @@ class Items extends Repository {
'on_error' => __( 'Invalid document', 'tainacan' ),
'default' => ''
],
'featured_img_id' => [
'_thumbnail_id' => [
'map' => 'meta',
'title' => __( 'Featured image ID', 'tainacan' ),
'description' => __( 'Featured image ID', 'tainacan' )
'title' => __( 'Thumbnail', 'tainacan' ),
'description' => __( 'Squared reduced-size version of a picture that helps recognizing and organizing files', 'tainacan' )
]
] );
}
@ -365,4 +360,86 @@ class Items extends Repository {
}
return $where;
}
/**
* Get a default thumbnail ID from the item document.
*
* @param EntitiesItem $item The item
* @return int|null The thumbnail ID or null if it was not possible to find a thumbnail
*/
public function get_thumbnail_id_from_document(Entities\Item $item) {
/**
* Hook to get thumbnail from document
*/
$thumb_id = apply_filters('tainacan-get-thumbnail-id-from-document', null, $item);
if (!is_null($thumb_id)) {
return $thumb_id;
}
if ( empty($item->get_document()) ) {
return null;
}
if ( $item->get_document_type() == 'attachment' ) {
if ( wp_attachment_is_image( $item->get_document() ) ) {
return $item->get_document();
} else {
$filepath = get_attached_file($item->get_document());
$TainacanMedia = \Tainacan\Media::get_instance();
$thumb_blob = $TainacanMedia->get_pdf_cover($filepath);
if ( $thumb_blob ) {
$thumb_id = $TainacanMedia->insert_attachment_from_blob($thumb_blob, basename($filepath) . '-cover.jpg', $item->get_id());
return $thumb_id;
}
}
} elseif ( $item->get_document_type() == 'url' ) {
$TainacanEmbed = \Tainacan\Embed::get_instance();
if ( $thumb_url = $TainacanEmbed->oembed_get_thumbnail( $item->get_document() ) ) {
$meta_key = '_' . $thumb_url . '__thumb';
$existing_thumb = get_post_meta($item->get_id(), $meta_key, true);
if ( is_numeric( $existing_thumb ) ) {
return $existing_thumb;
} else {
$TainacanMedia = \Tainacan\Media::get_instance();
$thumb_id = $TainacanMedia->insert_attachment_from_url($thumb_url, $item->get_id());
update_post_meta($item->get_id(), $meta_key, $thumb_id);
return $thumb_id;
}
}
}
return $thumb_id;
}
/**
* When updating an item document, set a default thumbnail to the item if it does not have one yet
*
* @param Entities\Item $updated_item
* @param array $attributes The paramaters sent to the API
* @return void
*/
public function hook_api_updated_item(Entities\Item $updated_item, $attributes) {
if ( array_key_exists('document', $attributes)
&& empty($updated_item->get__thumbnail_id())
&& !empty($updated_item->get_document())
) {
$thumb_id = $this->get_thumbnail_id_from_document($updated_item);
if (!is_null($thumb_id)) {
set_post_thumbnail( $updated_item->get_id(), (int) $thumb_id );
}
}
}
}

View File

@ -112,7 +112,12 @@ class Logs extends Repository {
'map' => 'meta',
'title' => __( 'Log differences', 'tainacan' ),
'description' => __( 'Differences between old and new versions of object', 'tainacan' )
]
],
'collection_id' => [
'map' => 'meta',
'title' => __( 'Log collection relationship', 'tainacan' ),
'description' => __( 'The id of collection that this log is related.', 'tainacan' )
],
] );
}
@ -188,7 +193,7 @@ class Logs extends Repository {
} elseif ( is_array( $args ) ) {
$args = array_merge( [
'posts_per_page' => - 1,
'posts_per_page' => -1,
], $args );
$args = $this->parse_fetch_args( $args );
@ -307,20 +312,20 @@ class Logs extends Repository {
if ( $is_update ) {
$msn = $this->prepare_event_message($class_name, 'updated');
$description = $this->prepare_description_message($new_value, $name, $class_name, 'updated');
$description = $this->prepare_event_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');
$description = $this->prepare_event_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');
$description = $this->prepare_event_description_message($new_value, $name, $class_name, 'created');
} elseif( $is_trash ) {
// was trashed
$msn = $this->prepare_event_message($class_name, 'trashed');
$description = $this->prepare_description_message($new_value, $name, $class_name, 'trashed');
$description = $this->prepare_event_description_message($new_value, $name, $class_name, 'trashed');
}
$msn = apply_filters( 'tainacan-insert-log-message-title', $msn, $type, $new_value );
@ -358,7 +363,7 @@ class Logs extends Repository {
*
* @return string
*/
private function prepare_description_message($object, $name, $class_name, $action_message){
private function prepare_event_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;

View File

@ -129,12 +129,10 @@ abstract class Repository {
// Now run through properties stored as postmeta
foreach ( $map as $prop => $mapped ) {
if ( $mapped['map'] == 'meta' || $mapped['map'] == 'meta_multi' ) {
$this->insert_metadata( $obj, $prop );
$diffs = $this->insert_metadata( $obj, $prop, $diffs );
}
}
$diffs = $this->insert_thumbnail( $obj, $diffs );
// TODO: Logs for header image insert and update
do_action( 'tainacan-insert', $obj, $diffs, $is_update );
@ -150,9 +148,11 @@ abstract class Repository {
* @param \Tainacan\Entities $obj The entity object
* @param string $prop the property name, as declared in the map of the repository
*
* @param $diffs
*
* @return null|false on error
*/
public function insert_metadata( $obj, $prop ) {
public function insert_metadata( $obj, $prop, $diffs ) {
$map = $this->get_map();
if ( ! array_key_exists( $prop, $map ) ) {
@ -160,16 +160,26 @@ abstract class Repository {
}
if ( $map[ $prop ]['map'] == 'meta' ) {
update_post_meta( $obj->get_id(), $prop, $this->maybe_add_slashes( $obj->get_mapped_property( $prop ) ) );
if($prop === '_thumbnail_id'){
$diffs = $this->insert_thumbnail($obj, $diffs);
return $diffs;
} else {
update_post_meta( $obj->get_id(), $prop, $this->maybe_add_slashes( $obj->get_mapped_property( $prop ) ) );
}
} elseif ( $map[ $prop ]['map'] == 'meta_multi' ) {
$values = $obj->get_mapped_property( $prop );
$current_values = get_post_meta( $obj->get_id(), $prop );
if (empty($values) || !is_array($values))
if (empty($values) || !is_array($values)) {
$values = [];
if (empty($current_values) || !is_array($current_values))
}
if (empty($current_values) || !is_array($current_values)) {
$current_values = [];
}
$deleted = array_diff( $current_values, $values );
$added = array_diff( $values, $current_values );
@ -183,6 +193,8 @@ abstract class Repository {
}
}
return $diffs;
}
function maybe_add_slashes( $value ) {
@ -710,61 +722,62 @@ abstract class Repository {
}
}
unset($diff['id'], $diff['collection_id'], $diff['author_id'], $diff['creation_date'], $diff['featured_img_id']);
unset($diff['id'], $diff['collection_id'], $diff['author_id'], $diff['creation_date'], $diff['_thumbnail_id']);
$diff = apply_filters( 'tainacan-entity-diff', $diff, $new, $old );
return $diff;
}
/**
* Inserts or update thumbnail for items and collections and return an array
* with old thumbnail and new thumbnail
*
* @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
private function insert_thumbnail( $obj, $diffs ) {
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() );
$settled = set_post_thumbnail( $obj->WP_Post, (int) $obj->get__thumbnail_id() );
if ( $settled ) {
if ( $settled ) {
$thumbnail_url = get_the_post_thumbnail_url( $obj->WP_Post->ID );
$thumbnail_url = get_the_post_thumbnail_url( $obj->WP_Post->ID );
$diffs['featured_image'] = [
'new' => $thumbnail_url,
'old' => '',
'diff_with_index' => 0,
];
$diffs['thumbnail'] = [
'new' => $thumbnail_url,
'old' => '',
'diff_with_index' => 0,
];
}
}
} else {
// was updated a thumbnail
$old_thumbnail = get_the_post_thumbnail_url( $obj->WP_Post->ID );
$fid = $obj->get__thumbnail_id();
if ( ! $fid ) {
$settled = delete_post_thumbnail( $obj->WP_Post );
} else {
$settled = set_post_thumbnail( $obj->WP_Post, (int) $fid );
}
// was update a thumbnail
if ( $settled ) {
$old_thumbnail = get_the_post_thumbnail_url( $obj->WP_Post->ID );
$thumbnail_url = 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,
];
}
$diffs['thumbnail'] = [
'new' => $thumbnail_url,
'old' => $old_thumbnail,
'diff_with_index' => 0,
];
}
}

View File

@ -36,6 +36,7 @@ abstract class Importer {
* @var array
*/
public $mapping;
private $repository_mapping;
/**
* The path to the temporary file created when user uploads a file
@ -62,6 +63,7 @@ abstract class Importer {
* @var int
*/
private $start = 0;
private $inside_step_pointer = 0;
/**
* The log with everything that happened during the import process. It generates a report afterwards
@ -164,8 +166,26 @@ abstract class Importer {
*
* @param array $mapping Mapping importer-fields
*/
public function set_mapping( $mapping ){
$this->mapping = $mapping;
public function set_mapping( $mapping){
if(!empty($mapping))
{
$this->mapping = $mapping;
}
}
public function set_repository_mapping( $mapping, $item_id ){
if(!empty($mapping) && !empty($item_id))
{
$this->repository_mapping[$item_id] = $mapping;
}else return false;
}
public function get_repository_mapping($item_id)
{
if(!empty($item_id))
{
return $this->repository_mapping[$item_id];
}else return false;
}
/**
@ -197,6 +217,21 @@ abstract class Importer {
}
}
public function set_inside_step_pointer($step_pointer)
{
if(is_numeric($step_pointer) && $step_pointer >= 0)
{
$this->inside_step_pointer = $step_pointer;
}else
{
$this->inside_step_pointer = 0;
}
}
public function get_inside_step_pointer()
{
return $this->inside_step_pointer;
}
/**
* log the actions from importer
*
@ -331,6 +366,16 @@ abstract class Importer {
return false;
}
protected function get_start()
{
return $this->start;
}
protected function get_items_per_step()
{
return $this->items_per_step;
}
/**
* Sets importer as repository importer
*/
@ -344,6 +389,15 @@ abstract class Importer {
$this->steps =$steps;
}
public function is_finished()
{
if($this->current_step >= count($this->steps))
{
return true;
}
return false;
}
/**
* Removes method accepeted by the importer
*
@ -475,15 +529,19 @@ abstract class Importer {
public function run(){
if($this->is_repository && $this->current_step < count($this->steps))
{
$process_name = key($this->steps);
//$process_name = key($this->steps);
$function_name = current($this->steps);
$continue = $this->{$function_name}();//If true still there is stuff to process
$inside_step_pointer = $this->{$function_name}();//If unlike numeric this means that still there is stuff to process
if(!$continue)
if($inside_step_pointer === false || (!is_numeric($inside_step_pointer) || $inside_step_pointer < 0))
{
//Move on to the next step
next($this->steps);
$this->current_step++;
$this->set_inside_step_pointer(0);
}else if(is_numeric($inside_step_pointer) && $inside_step_pointer > 0)
{
$this->set_inside_step_pointer($inside_step_pointer);
}
}
else

View File

@ -10,38 +10,6 @@ namespace Tainacan\Importer;
class Old_Tainacan extends Importer
{
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'
],
$steps = [
'Creating all categories' => 'create_categories',
'Create empty collections' => 'create_collections',
'Create repository metadata' => 'create_repo_meta',
'Create collections metadata' => 'create_collection_metas',
'Create collections items' => 'create_collection_items',
'Setting relationships' => 'set_relationships'
], $tainacan_api_address, $wordpress_api_address;
public function __construct()
{
parent::__construct();
@ -53,19 +21,23 @@ class Old_Tainacan extends Importer
$this->wordpress_api_address = "/wp-json/wp/v2";
}
public function verify_process_result($result)
{
if(is_wp_error($result))
{
$this->add_log('error', $result->get_error_message());
return false;
}else if(isset($result['body']))
{
return json_decode($result['body']);
}
return false;
}
public $avoid = [
'socialdb_property_fixed_title',
'socialdb_property_fixed_description',
'socialdb_property_fixed_content',
'socialdb_property_fixed_thumbnail',
'socialdb_property_fixed_attachments'
],
$steps = [
'Creating all categories' => 'create_categories',
'Create empty collections' => 'create_collections',
'Creating relationships metadata' => 'create_relationships_meta',
'Create repository metadata' => 'treat_repo_meta',
'Create collections metadata' => 'treat_collection_metas',
'Create collections items' => 'create_collection_items',
"Finishing" => 'clear'
], $tainacan_api_address, $wordpress_api_address;
public function create_categories()
@ -80,8 +52,14 @@ class Old_Tainacan extends Importer
$Tainacan_Taxonomies = \Tainacan\Repositories\Taxonomies::get_instance();
$categories_array = $this->remove_same_name($categories_array);
foreach ($categories_array as $category)
list($inside_step_pointer, $end) = $this->get_begin_end($categories_array);
if($inside_step_pointer === false) return false;
$created_categories = [];
while($inside_step_pointer < $end)
{
$category = $categories_array[$inside_step_pointer];
$taxonomy = new \Tainacan\Entities\Taxonomy();
@ -92,16 +70,434 @@ class Old_Tainacan extends Importer
$Tainacan_Taxonomies->insert($taxonomy);
$inserted_taxonomy = $Tainacan_Taxonomies->fetch($taxonomy->get_id());
/*Insert old tainacan id*/
$created_categories[] = $category->term_id.",".$inserted_taxonomy->get_id().",".$category->name;
if(isset($category->children) && $inserted_taxonomy)
{
$this->add_all_terms($inserted_taxonomy, $category->children);
}
$inside_step_pointer++;
}
$this->save_in_file("categories", $created_categories);
}
return $inside_step_pointer;
}
public function create_collections()
{
$collections_link = $this->get_url() . $this->tainacan_api_address . "/collections";
$collections = wp_remote_get($collections_link);
$collections_array = $this->verify_process_result($collections);
$created_collections = [];
if($collections_array)
{
list($inside_step_pointer, $end) = $this->get_begin_end($collections_array);
if($inside_step_pointer === false) return false;
while($inside_step_pointer < $end)
{
$collection = $collections_array[$inside_step_pointer];
$new_collection = new \Tainacan\Entities\Collection();
$new_collection->set_name($collection->post_title);
$new_collection->set_status('publish');
$new_collection->validate();
$new_collection = \Tainacan\Repositories\Collections::get_instance()->insert($new_collection);
/*Add old id*/
$created_collections[] = $collection->ID.",".$new_collection->get_id().",".$collection->post_title;
$inside_step_pointer++;
}
$this->save_in_file("collections", $created_collections);
}
return $inside_step_pointer;
}
public function create_relationships_meta()
{
$relationships = [];
$created_collection = $this->read_from_file("collections");
$created_categories = $this->read_from_file("categories");
foreach ($created_categories as $category_id => $category)
{
$category_name = $category['name'];
foreach ($created_collection as $collection_id => $collection)
{
$collection_name = $collection['name'];
if(strcmp($category_name, $collection_name) === 0)
{
$relationships[] = $category_id.",".$collection['new_id'].",".$category['name'];
}
}
}
$this->save_in_file('relationships', $relationships);
return false;
}
public function treat_repo_meta()
{
$repository_meta_link = $this->get_url() . $this->tainacan_api_address . "/repository/metadata?includeMetadata=1";
$repo_meta = wp_remote_get($repository_meta_link);
$repo_meta_array = $this->verify_process_result($repo_meta);
$Fields_Repository = \Tainacan\Repositories\Fields::get_instance();
$created_categories = $this->read_from_file("categories");
$relationships = $this->read_from_file("relationships");
$this->create_meta_repo($repo_meta_array, $Fields_Repository, $created_categories, $relationships);
return false;
}
private function create_meta_repo($repo_meta_array, $Fields_Repository, $created_categories, $relationships, $compound_id = null)
{
if($repo_meta_array)
{
$repository_fields = [];
foreach ($repo_meta_array as $meta)
{
$special = [
'socialdb_property_fixed_type',
'stars'
];
if(!in_array($meta->slug, $this->avoid) && !in_array($meta->type, $special))
{
$newField = $this->set_fields_properties($meta, $created_categories, $relationships, $Fields_Repository, $compound_id);
if ($newField)
{
$newField = $Fields_Repository->insert($newField);
$repository_fields[] = $meta->id . "," . $newField->get_id() . "," . $meta->name;
}
}
}
$this->save_in_file('repository_fields', $repository_fields);
}
}
public function treat_collection_metas()
{
$created_collections = $this->read_from_file("collections");
$created_repository_fields = $this->read_from_file("repository_fields");
$created_categories = $this->read_from_file("categories");
$relationships = $this->read_from_file("relationships");
list($inside_step_pointer, $end) = $this->get_begin_end($created_collections);
if($inside_step_pointer === false) return false;
$Tainacan_Fields = \Tainacan\Repositories\Fields::get_instance();
$Fields_Repository = \Tainacan\Repositories\Fields::get_instance();
$Repository_Collections = \Tainacan\Repositories\Collections::get_instance();
for($i = 0; $i < $inside_step_pointer; $i++)
{
next($created_collections);
}
while($inside_step_pointer < $end)
{
$collection_info = current($created_collections);
$new_collection_id = $collection_info['new_id'];
$old_collection_id = key($created_collections);
$collection = $Repository_Collections->fetch($new_collection_id);
$this->set_collection($collection);
$file_fields = $this->get_collection_fields($old_collection_id);
$mapping = $this->create_collection_meta($file_fields, $Fields_Repository, $Tainacan_Fields, $created_repository_fields, $created_categories, $relationships);
$this->set_repository_mapping($mapping, $old_collection_id);
next($created_collections);
$inside_step_pointer++;
}
return $inside_step_pointer;
}
private function create_collection_meta(
$file_fields,
$Fields_Repository,
$Tainacan_Fields,
$created_repository_fields,
$created_categories,
$relationships,
$compound_id = null)
{
if($file_fields)
{
foreach($file_fields as $index => $meta)
{
$meta_slug = $meta->slug;
$old_field_id = $meta->id;
if(!in_array($meta_slug, $this->avoid) && !isset($created_repository_fields[$old_field_id]))
{
$newField = $this->set_fields_properties(
$meta,
$created_categories,
$relationships,
$Fields_Repository,
$compound_id,
$created_repository_fields,
false,
$Tainacan_Fields);
if($newField->validate())
{
$newField = $Fields_Repository->insert($newField);
$mapping[$newField->get_id()] = $file_fields[$index]->name;
}
}else /*Map to respository fields*/
{
if(isset($created_repository_fields[$old_field_id]))
{
$new_id = $created_repository_fields[$old_field_id]['new_id'];
$mapping[$new_id] = $created_repository_fields[$old_field_id]['name'];
}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') &&
($meta_slug === 'socialdb_property_fixed_title' || $meta_slug === 'socialdb_property_fixed_description'))
{
$mapping[$field->get_id()] = $field->WP_Post->post_name;
}
}
}
}
}
}
return $mapping;
}
private function set_fields_properties(
$meta,
$created_categories,
$relationships,
$Fields_Repository,
$compound_id,
$created_repository_fields = null,
$is_repository = true,
$Tainacan_Fields = null)
{
$newField = new \Tainacan\Entities\Field();
$name = $meta->name;
$type = $meta->type;
$type = $this->define_type($type);
$newField->set_name($name);
$newField->set_field_type('Tainacan\Field_Types\\'.$type);
if(strcmp($type, "Category") === 0)
{
$taxonomy_id = $meta->metadata->taxonomy;
if(isset($created_categories[$taxonomy_id]))
{
$new_category_id = $created_categories[$taxonomy_id]['new_id'];
$newField->set_field_type_options(['taxonomy_id' => $new_category_id]);
}
}else if(strcmp($type, "Relationship") === 0)
{
$taxonomy_id = $meta->metadata->object_category_id;
if(isset($relationships[$taxonomy_id]))
{
$new_collection_id = $relationships[$taxonomy_id]['new_id'];
$newField->set_field_type_options(['collection_id' => $new_collection_id]);
}
}else if(strcmp($type, "Compound") === 0)
{
if($is_repository)
{
$this->create_meta_repo(
$meta->metadata->children,
$Fields_Repository,
$created_categories,
$relationships,
$newField->get_id());
}else
{
$this->create_collection_meta(
$meta->metadata->children,
$Fields_Repository,
$Tainacan_Fields,
$created_repository_fields,
$created_categories,
$relationships,
$newField->get_id());
}
}
/*Compound treatement*/
if($compound_id === null)
{
if($is_repository)
{
$newField->set_collection_id('default');
}else
{
$newField->set_collection($this->collection);
}
}else //Set compound as field parent
{
$newField->set_parent($compound_id);
}
/*Properties of field*/
if(isset($meta->metadata))
{
if($meta->metadata->required == 1)
{
$newField->set_required(true);
}
if(!empty($meta->metadata->default_value))
{
$newField->set_default_value($meta->metadata->default_value);
}
/*if(!empty($meta->metadata->text_help))
{
}*/
if(!empty($meta->metadata->cardinality))
{
if($meta->metadata->cardinality > 1)
{
$newField->set_multiple('yes');
}
}
}
if($newField->validate()){
return $newField;
}else return false;
}
public function create_collection_items()
{
$created_collections = $this->read_from_file("collections");
if(!empty($created_collections))
{
$Repository_Collections = \Tainacan\Repositories\Collections::get_instance();
$collection_info = current($created_collections);
$new_collection_id = $collection_info['new_id'];
$old_collection_id = key($created_collections);
$collection = $Repository_Collections->fetch($new_collection_id);
$this->set_collection($collection);
$mapping = $this->get_repository_mapping($old_collection_id);
$this->set_mapping($mapping);
$this->process($this->get_start());
}
return false;
}
public function clear()
{
unlink($this->get_id()."_categories.txt");
unlink($this->get_id()."_collections.txt");
unlink($this->get_id()."_relationships.txt");
unlink($this->get_id()."_repository_fields.txt");
return false;
}
/*Aux functions*/
private function get_collection_fields($collections_id)
{
$fields_link = $this->get_url() . $this->tainacan_api_address . "/collections/".$collections_id."/metadata";
$collection = wp_remote_get($fields_link);
$collection_metadata = $this->verify_process_result($collection);
if($collection_metadata)
{
$fields = [];
foreach ($collection_metadata[0]->{'tab-properties'} as $metadata)
{
$field_details_link = $fields_link . "/". $metadata->id;
$field_details = wp_remote_get($field_details_link);
$field_details = $this->verify_process_result($field_details);
if($field_details)
{
$fields[] = $field_details[0];
}
}
return $fields;
}
return false;
}
private function read_from_file($name)
{
$file_name = $this->get_id()."_".$name.".txt";
$fp = fopen($file_name, "r");
$content = explode("|", fread($fp, filesize($file_name)));
$result = [];
foreach ($content as $ids)
{
$old_new_name = explode(",", $ids);
$result[$old_new_name[0]] = ['new_id' => $old_new_name[1], 'name' => $old_new_name[2]];
}
return $result;
}
private function save_in_file($name, $ids)
{
/*Old ID, new ID*/
$file_name = $this->get_id()."_".$name.".txt";
$content = implode("|", $ids);
if(file_exists($file_name))
{
$content = "|".$content;
}
$fp = fopen($file_name, "a+");
fwrite($fp, $content);
fclose($fp);
}
private function get_begin_end($items)
{
$inside_step_pointer = $this->get_inside_step_pointer();
$total_items = count($items);
if($inside_step_pointer >= $total_items)
{
return [false, false];
}
$end = $this->get_inside_step_pointer() + $this->get_items_per_step();
if($end > $total_items)
{
$end = $total_items;
}
return [$inside_step_pointer, $end];
}
private function add_all_terms($taxonomy_father, $children, $term_father = null)
{
$Tainacan_Terms = \Tainacan\Repositories\Terms::get_instance();
@ -122,6 +518,9 @@ class Old_Tainacan extends Importer
$inserted_term = $Tainacan_Terms->insert($new_term);
/*Insert old tainacan id*/
add_term_meta($inserted_term->get_id(), 'old_tainacan_category_id', $term->term_id );
if(isset($term->children))
{
$this->add_all_terms($taxonomy_father, $term->children, $inserted_term);
@ -129,7 +528,7 @@ class Old_Tainacan extends Importer
}
}
public function remove_same_name($terms)
private function remove_same_name($terms)
{
$unique = [];
$unique_terms = [];
@ -149,30 +548,47 @@ class Old_Tainacan extends Importer
return $unique_terms;
}
public function create_collections()
private function verify_process_result($result)
{
if(is_wp_error($result))
{
$this->add_log('error', $result->get_error_message());
return false;
}else if(isset($result['body']))
{
return json_decode($result['body']);
}
return false;
}
public function create_repo_meta()
public function define_type($type)
{
return false;
$type = strtolower($type);
$tainacan_types = ['text', 'textarea', 'numeric', 'date'];
if(in_array($type, $tainacan_types))
{
$type = ucfirst($type);
}else if(strcmp($type, 'autoincrement') === 0)
{
$type = "Numeric";
}else if(strcmp($type, 'item') === 0)
{
$type = "Relationship";
}else if(strcmp($type, 'tree') === 0)
{
$type = "Category";
}else if(strcmp($type, 'compound') === 0)
{
$type = "Compound";
}
else $type = 'Text';
return $type;
}
public function create_collection_metas()
{
return false;
}
public function create_collection_items()
{
return false;
}
public function set_relationships()
{
return false;
}
/*END aux functions*/
public function fetch_from_remote( $url ){
$url_json = explode('/colecao/', $url)[0] . "/wp-json/tainacan/v1/collections";
@ -233,38 +649,6 @@ class Old_Tainacan extends Importer
}
}
/**
* get the fields of file/url to allow mapping
* should return an array
*
* @return array $fields_source the fields from the source
*/
public function get_fields()
{
$file = new \SplFileObject( $this->tmp_file, 'r' );
$file_content = unserialize($file->fread($file->getSize()));
$item = $file_content->items[0];
$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];
}
return $fields;
}
/**
* get values for a single item
*
@ -371,20 +755,10 @@ class Old_Tainacan extends Importer
$this->set_mapping($mapping);
}
public function define_type($type)
public function get_fields()
{
$type = strtolower($type);
$tainacan_types = ['text', 'textarea', 'numeric', 'date'];
$types_to_work = ['item', 'tree'];
if(in_array($type, $tainacan_types))
{
$type = ucfirst($type);
}else $type = 'Text';
return $type;
}
/**
* Method implemented by the child importer class to return the number of items to be imported
* @return int

View File

@ -12,6 +12,7 @@ export default {
collectionId: undefined
},
created(){
this.$on('input', data => {
this.$store.dispatch('search/setPage', 1);
@ -85,6 +86,10 @@ export default {
this.$store.dispatch('search/setOrder', newOrder);
this.updateURLQueries();
},
setSearchQuery(searchQuery) {
this.$store.dispatch('search/setSearchQuery', searchQuery);
this.updateURLQueries();
},
updateURLQueries() {
this.$router.push({ query: {} });
this.$router.push({ query: this.$store.getters['search/getPostQuery'] });
@ -98,6 +103,8 @@ export default {
this.$store.dispatch('collection/fetchItems', this.collectionId).then((res) => {
this.$emit( 'isLoadingItems', false);
this.$emit( 'hasFiltered', res.hasFiltered);
//var event = new Event('tainacan-items-change')
//document.dispatchEvent(event);
})
.catch(() => {
this.$emit( 'isLoadingItems', false);

View File

@ -23,13 +23,13 @@ export const eventBus = new Vue({
const components = this.getAllComponents();
for (let eventElement of components){
eventElement.addEventListener('input', (event) => {
if (event.detail && event.detail[0] ){
this.updateValue({
item_id: $(eventElement).attr("item_id"),
field_id: $(eventElement).attr("field_id"),
this.updateValue({
item_id: $(eventElement).attr("item_id"),
field_id: $(eventElement).attr("field_id"),
values: event.detail
})
})
}
});
}
@ -39,7 +39,7 @@ export const eventBus = new Vue({
let values = ( Array.isArray( data.values[0] ) ) ? data.values[0] : data.values ;
const promisse = this.$store.dispatch('item/updateMetadata',
{ item_id: data.item_id, field_id: data.field_id, values: values });
promisse.then( () => {
let index = this.errors.findIndex( errorItem => errorItem.field_id == data.field_id );
if ( index >= 0){
@ -66,6 +66,9 @@ export const eventBus = new Vue({
let error = this.errors.find( errorItem => errorItem.field_id == field_id );
return ( error ) ? error.errors : false
},
clearAllErrors(){
this.errors = [];
},
setValues(){
const field = this.$store.getters['item/getMetadata'];
if( field ){
@ -107,4 +110,4 @@ export const eventBus = new Vue({
}
}
});
});

View File

@ -14,10 +14,10 @@ export const fetchItems = ({ rootGetters, dispatch, commit }, collectionId) => {
hasFiltered = true;
// Differentiates between repository level and collection level queries
let endpoint = '/collection/'+collectionId+'/items?'
let endpoint = '/collection/'+collectionId+'/items?context=edit&'
if (collectionId == undefined)
endpoint = '/items?'
endpoint = '/items?context=edit&'
axios.tainacan.get(endpoint + qs.stringify(postQueries) )
.then(res => {
@ -46,7 +46,7 @@ export const deleteItem = ({ commit }, item_id ) => {
export const fetchCollections = ({commit} , { page, collectionsPerPage }) => {
commit('cleanCollections');
return new Promise((resolve, reject) => {
axios.tainacan.get('/collections?paged='+page+'&perpage='+collectionsPerPage)
axios.tainacan.get('/collections?paged='+page+'&perpage='+collectionsPerPage+'&context=edit')
.then(res => {
let collections = res.data;
commit('setCollections', collections);
@ -75,7 +75,7 @@ export const fetchCollection = ({ commit }, id) => {
}
export const fetchCollectionName = ({ commit }, id) => {
commit('cleanCollectionName');
//commit('cleanCollectionName');
return new Promise((resolve, reject) =>{
axios.tainacan.get('/collections/' + id + '?fetch_only=name')
.then(res => {
@ -194,7 +194,7 @@ export const fetchAttachments = ({ commit }, collection_id) => {
export const updateThumbnail = ({ commit }, { collectionId, thumbnailId }) => {
return new Promise((resolve, reject) => {
axios.tainacan.patch('/collections/' + collectionId, {
featured_img_id: thumbnailId
_thumbnail_id: thumbnailId
}).then( res => {
let collection = res.data
commit('setCollection', collection);

View File

@ -18,6 +18,23 @@ export const fetchEvents = ({ commit }, { page, eventsPerPage } ) => {
});
};
export const fetchCollectionEvents = ({ commit }, { page, eventsPerPage, collectionId }) => {
return new Promise((resolve, reject) => {
axios.tainacan.get(`/collection/${collectionId}/logs?paged=${page}&perpage=${eventsPerPage}&context=edit`)
.then(res => {
let events = res.data;
commit('setEvents', events);
resolve({
events: events,
total: res.headers['x-wp-total']
});
})
.catch(error => reject(error));
});
};
export const fetchEvent = ({ commit }, eventId) => {
return new Promise((resolve, reject) => {
axios.tainacan.get(`/logs/${eventId}?context=edit`)

View File

@ -1,7 +1,7 @@
import axios from '../../../axios/axios';
// FILTERS --------------------------------------------------------
export const fetchFilters = ({ commit }, {collectionId, isRepositoryLevel, isContextEdit}) => {
export const fetchFilters = ({ commit }, {collectionId, isRepositoryLevel, isContextEdit, includeDisabled}) => {
return new Promise((resolve, reject) => {
let endpoint = '';
if (!isRepositoryLevel)
@ -10,8 +10,14 @@ export const fetchFilters = ({ commit }, {collectionId, isRepositoryLevel, isCon
endpoint = '/filters/';
endpoint += '?nopaging=1'
if (isContextEdit)
if (isContextEdit) {
endpoint += '&context=edit';
}
if (includeDisabled === 'yes'){
endpoint += '&include_disabled=yes'
}
axios.tainacan.get(endpoint)
.then((res) => {
@ -24,7 +30,7 @@ export const fetchFilters = ({ commit }, {collectionId, isRepositoryLevel, isCon
reject(error);
});
});
}
};
export const sendFilter = ( { commit }, { collectionId, fieldId, name, filterType, status, isRepositoryLevel, newIndex }) => {
return new Promise(( resolve, reject ) => {
@ -108,7 +114,7 @@ export const updateCollectionFiltersOrder = ({ commit }, { collectionId, filters
});
});
}
};
export const fetchFilterTypes = ({ commit} ) => {
return new Promise((resolve, reject) => {
@ -123,7 +129,7 @@ export const fetchFilterTypes = ({ commit} ) => {
reject(error);
});
});
}
};
export const updateFilteTypes = ( { commit }, filterTypes) => {
commit('setFilterTypes', filterTypes);

View File

@ -99,6 +99,7 @@ export const sendItem = ( { commit }, { collection_id, status }) => {
};
export const updateItem = ({ commit }, { item_id, status }) => {
return new Promise((resolve, reject) => {
axios.tainacan.patch('/items/' + item_id, {
status: status
@ -118,7 +119,9 @@ export const updateItemDocument = ({ commit }, { item_id, document, document_typ
document: document,
document_type: document_type
}).then( res => {
commit('setItem', res.data);
let item = res.data;
commit('setItem', item);
resolve( res.data );
}).catch( error => {
reject({ error_message: error['response']['data'].error_message, errors: error['response']['data'].errors });
@ -164,7 +167,7 @@ export const fetchAttachments = ({ commit }, item_id) => {
export const updateThumbnail = ({ commit }, { itemId, thumbnailId }) => {
return new Promise((resolve, reject) => {
axios.tainacan.patch('/items/' + itemId, {
featured_img_id: thumbnailId
_thumbnail_id: thumbnailId
}).then( res => {
let item = res.data
commit('setItem', item);

View File

@ -66,3 +66,8 @@ export const setOrderBy = ({ commit }, orderBy ) => {
export const setOrder = ({ commit }, order ) => {
commit('setPostQueryAttribute', { attr: 'order', value: order } );
};
// Set search query
export const setSearchQuery = ({ commit }, searchQuery ) => {
commit('setSearchQuery', searchQuery );
};

View File

@ -28,4 +28,8 @@ export const getOrder = state => {
export const getOrderBy = state => {
return state.postquery.orderby;
};
};
export const getSearchQuery = state => {
return state.postquery.search;
}

View File

@ -8,6 +8,7 @@ const state = {
order: 'DESC',
paged: 1,
perpage: 12,
search: '',
post_type: [],
metaquery: [],
taxquery: []

View File

@ -64,3 +64,7 @@ export const removeTaxQuery = ( state, filter ) => {
export const setTotalItems = ( state, total ) => {
state.totalItems = total;
};
export const setSearchQuery = ( state, searchQuery ) => {
state.postquery.search = searchQuery;
};

Some files were not shown because too many files have changed in this diff Show More