Merge remote-tracking branch 'origin/develop' into new-mapped-collection

# Conflicts:
#	tests/test-api-export.php
This commit is contained in:
Jacson Passold 2018-06-07 18:47:06 -03:00
commit 608da65c9b
70 changed files with 2558 additions and 1096 deletions

72
.travis.yml Normal file
View File

@ -0,0 +1,72 @@
sudo: false
language: php
php:
- 7.1
- 7.2
- 5.6
matrix:
allow_failures:
fast_finish: true
addons:
- ssh_know_hosts:
- "$ssh_host"
apt:
sources:
- mysql-5.7-trusty
- phpunit-6.1
packages:
- sshpass
- mysql-server
- mysql-client
services:
- mysql
before_install:
- sudo apt-get install sshpass
- sudo service mysql restart
- mysql -e 'CREATE DATABASE IF NOT EXISTS test;'
install:
- echo -e "Install"
- sudo mv ./tests/bootstrap-config-sample.php ./tests/bootstrap-config.php
- sudo ./tests/bin/install-wp-tests.sh test travis "" /tmp/wordpress localhost latest
true
- composer install
- sudo mkdir /tmp/wordpress/wordpress-test/wp-content/uploads
script: phpunit
before_deploy:
- echo "Seção executada antes do deploy!"
- openssl aes-256-cbc -K $encrypted_cb93ef43fcd2_key -iv $encrypted_cb93ef43fcd2_iv
-in deploy_rsa.enc -out /tmp/deploy_rsa -d
- eval "$(ssh-agent -s)"
- chmod 600 /tmp/deploy_rsa
- ssh-add /tmp/deploy_rsa
- echo -e "Host $ssh_host\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
- ssh-add -l
deploy:
- provider: script
script: ssh $ssh_user@$ssh_host $script_deploy_tainacan
skip_cleanup: true
on:
branch: develop
cache:
directories:
- vendor
- composer
notifications:
slack:
rooms:
secure: WjgA4OIad0/Ai+x1TUd7KShXpaJco9E/MfI6DWJFnBUF5JLKOxymTGbR82wspmnEwzXGWn++co1wNJh20pWobaIToL/2OpBd7xo5MHglNobH4cidmSIDPOQM8ItqBneRjayhXtfShRqQDNCk1D3d5KDUacXXeCX+GLdRuwdc/YuG7Zh3y1KrF6l10cwD/5JOJECwwMbqeLOezvzGi8ITL6pqnEEeNTb0Zr+K2Ru91RBOars4TLK3f5CmX4XxA4oQSMsrHKzTO2OZLua5CRwcBwKmtSqr0Z/W+RrXu2TLxvHYJ39t9uwssI3HmGoB/uNcahBTcE0Vk/phi3nfFO8KUGNqp3xLgUsF/xlb+WiIip2xOf9jq+XNGWwIVB2vWqiQppm58h57LgDNTF21XJOtfVPEyf9Em+VSfNgACq47u4kktgqgZ47xNEBZuv1s3as8BcgdQH78hF+qguhhHJH6RgyHt+GYAq2uRLF8z3IM8hfKpb5mA9jD3UfW3pXEtKF9K+XqtNycX8KxJ2ldEJrMguaqW3sUHSLBo+r71OqldHeuwIfyIGIROTym11GWH56rIXxd51nJuVDWMvTg7bwcjN/d61LdfsaOAgqAYSUPlJjjp67GHZP/vson3uPr//NgnAJ/4gtjwReB7IX8oBLhB5s8lU6dnfnsLbY3Rt+THNA=
on_sucess: always
on_failure: always
email:
on_success: never
on_failure: always
env:
global:
- secure: LnUpxgHL/Qgpbg20mRErlnwb8tvNs6f7uPRe9c82UuMP69uDZeD3K5GNzL6u0Y+C/zNHk7tCnUszDC7FtQAij6qi72HHW2zz4zVJ+DFI3b+hx7+rSKsjtbnJChTbknSu3rW+yHYRTIUZJQ/Tg6thDLKzU0a4VRb+ickDpRYLyP+Cf4+xs7rwAhjiboMNIGXahrCpnbhctmOhRgZaHvfnPB9prRs5lOCCBQqSwMmjEo7OJeCCUjfpU5xq3EjUEzwjzzBlSf3240PS/LOBFr2iGF30VT9LDTb1iUZU1gTcaxaK+/EjKLG/wtcH8TOaLJpsksbnMkSTrG3ICblXl1G4Itu8IHzLgOmWoiWIVXZ4y17aYyj/y7YZtX+fjB6qs9RG5ZnSpHkSDEni8CCC8Ltf9jVSkLEust/bNLgkd02hJ4xtVxOaoBYEh3hcylJ/co8BTDdbNyT3BwrFc4f2jfRh5DYzyrKaTG5IJAT2BfyjD/BsxBE3EgIuJFja1zVJKMcuCmogDiHi6sb0zhF+LbLy0nXqvysTrMEYbDppVYQloz3BKb2v2m/jc89G7v8AjnvwTUgj64PUj+p10ngfIA+FHPILLtd/fNm0zRIRDqSfE7rpGZo9EoZ9jq0wVSmy0DK8kFTX+9RFW8xYmFnTgB3beKWqdK9CAqXEeeD3ABejXTc=
- secure: ZgQILlaSklEldQIISTfQC+0vhutWYs3nWzQP6bRluHmzb0PSz/7VqoFfzj7mi3AEtvsNIfDGv1AL8NUdqj9ZKBhgcFN178UcM87ObXIhpkZ43yIcNEHGQXBu0WN9Hn2kpj8sTWUFkzDUfLznShR8FDWwyxHHdH5TAMYJ8ZvLaDWZBAKJ0V+PYJASoI9CKVT16rx+K87MSavqvgLHsRticLgK/V/KVi5CMr/4J2WSeUpgzxKPLKP2yoTspJXbcUWuZcbXR+hp/MIvFJVYw7kK6wpixAzAuw6evrYwfOxLjZ5P2pNFrpMtBfONYKFpWxZyiPeUO8kBAV5R7XpzUUzfxRgu9Ca+6VYm8mNfHck4p7NLK+IjHLi1CrL3YYu8Ck1O01ah2i1ZIEaGL+NVRdrTHNOWZfWok3Wsv4UyLsgAeM4/K6dExauUqgVE/cwm/mwQ9ycoAoqfwVteHBmb7N+2nhlQwP1K1RAArS0ldm16aOD/eYcQ9kd5IQjRHr+QnMmhm7XRLJwxxL/Wpss7DNG4zWfEFNS9yYfDa8q0CRLT68sSjd5egnGyjYrW5dMSzFSu8G6CR/NvXTExlElxmilehDoLrGqRmLedW/jlbPQmNf6T+fVOE/r5vn//wMpk/e7rc0ivXh0YSDfyZ/3I052Uqingxl0ruLsoM6zIQW3b91U=
- secure: uUM5BXTWfh6jWqBdbu7sUrVVo4dUMNdorPaB6DNo0xOcjK/+b6lI41oQODmLKz48in0N0aWU+DH4gf3kkyhd/4ebPozHP5R/31ygYiNUzPFttZteV1rzCDaK/kwR8bH1p0hYibSeuqQgLt+VA7MD87x1/V1HrxZ+BPwYcrt8zNOb1ufqanu8t2URhyng5ZySOuBtXoDi9mR3KHX/V6DI1IybuAroV6LZm6d3PKpyD4GQtj48uw2IETQqMYXkHwYKPgIBLeXVDqMV8JP3MQ5WppheL7RBwHuClIAEPK47WEcnVqWkHssH3E3whzpIOo99R6EqRfVDAGwZAu2+SDuqFu5QGDfAF99ZSbh/m96lj9/drWK+0KOHOtEqhEq5FycOkLuHREIdLIg9uGqXLaGY+noAU7jXi70Uk3v4zrDxUocIdPrMaTutrE0pUPacCgnHtkTOkpJr7PHq2Zry8kMU39IRJQ3nIVcxSoUlWv9Xd+RjMw833RdZ1m5HVzUT+zE2jr8jhJgiNb/amQpH8pYcqI+NDqk8RFn9O0fhWYJmePtgDK0++9VAdBs8A4lmiFbkB+qotdZLemFhQObNOQsK/a3YoDgvjGfnvMXyGLdEFoT962mmnMteBq/mCcSEnRqLSA5gifzoJyeLRXKmVpoRAwrtjn5u8Qa+a8BQKCpDyno=
- secure: TxMSWrKRGiDamfCdmpfVJMG9fpXrlgGhS6Pbm7iO3eMMS6v+ZF5Qo7RyGYPsJvspKuncGpuRynoKff8jWsouYDqyMFZvtmG9EyJI2GYvy7K4E2HRRrZeNZHviP0tKq++0L5VLiY3pr9uUZYbmjKTk2k5V7ddd2EVK6AIqh/7dLmf9FPZ7HE+QuEQiaijBZ/mvBW+ntZHfZoyv/yWW5zPcA6vxAdtMa1iXhv6ByGFd+odCblq6HmBqDlaASDoXrrTSc0bkXeX44tqt+OMDhwsEqtzLlI5x1WYnYt5lkFuGjTn+WG/PLmrJxbq1c4MXU1cgcaiuRP8Y/Gq1XoffbFa9KZ/jfx0c9dxwRIedJrctrGC8jSSmlM1C+p9QFGWZUhF3b0WgRvP8NYUhQ0ToV3rE4XeApElHd27FYibDkWz72cpq6EiehJoQLFLyKpWcu7gtgjMUbGIllF2k6+oV7jzpgRNktzz5gWH2i1Vj5//Wyq1Md5NJ+sBspTmTcw9s09W2ghG/9bzksS5XtpOFfYVIqkeFbBK0lcGufDNoVSci4kTs12U/OMLcXaEUymHpKCS1UWCj/nRjxUosBBQ+WQzAJixEijTs8t0WKZZ2eDZhTOnpa50WV4DDO/EZHaQ7sgm98Y/V9gwvyLTOifjT2eXDNYXdH90RBGbDoUueyavqag=
- secure: ZZBechMeYwtzFe8dsMDQ3QPLUvZ2P5+abcTZbODMRmOomm5PixOr6EVJhVaUYnEtqgc4AaNnzVGmNrfoyEZC9Kza4hyEfABHPPcMDOUoC8v5HVpX08nLvWs6e5MdFCNeqWlJpTUR1ZVpYjXuIvaVVO9aT1N7ZAZBYPEaPotxPOt1+viJmWOUFpqhap/9VPkSn16DUiz9vQcJQe7PfxclxQkyhFlIhO0LRE//sR42ED1P3/efIRoAdfMSgISuLgQhZZYJ0wrh2aVz5YjRLfq80rQEynLFfCvSVEWhde3ZRGgX7oWo7LRfXF/0t4g/52QhfpWUvFw1fvljhzd/o1xUY6j2u3OS6Atx87QOvdj9a0D33UjWyOEXumUVupoSN5jnFnb41lKSoYwmx7rEEYGtYCBIzBkZfqOiKn0KYn1yIQbW0g6ptlC5C3o0wZchdCTaWnvNd2m6lj+a2j30b88F815qe0V7H9GxzUknccLfG/v/stBOFpYv1zd4bVgcmARHNwWORN6U3C+r9A3AoJkhLRedfsfmcftnxol55Okpz6Jn0z8/KVtuZ6FNlN3qfP5RLE6vP2y1s5fu/EWnsbNkP5JdCWKrRF9rryu3CURpci9f4zYcghuIRMfuZ9muQhdS7MYLJhwldy6lzPYg2l66laRgPkxeTHAamXHalhQXi60=
- secure: VMRxLl42yXCGRsmogIoYb31jzE9dyCpmlyB2fM+VsNNp/WWp1IB5QhhmH5klxw7KG16+Mhz7E9k99v+CmOyMVWmse3l9JXUoImdUNue5csgiMziHXU6A0zXv3EZVI0MfWilBoFOlc91c0n9h1jlUJ9VSBIaac+VqM8Icpw/w2ASha4XujJ02ahnYItmz9WVG2rG7mKYpc9DDHi2zbR+LyNLuX4tvi1CQtkpRiIFbs5eX+vIwQ2bFG1vpbbsiFkFPVGRlfh4DQaNo0Bam08BfsmK4TkYRiGxXZYTBM1QWJKdnzTZOnZ8uaiKCAGxC+5VsWuuqFfn9qPfx/7S43NGwG9aJSglkRZ9S4eKodMjCg+oGosq2dkGasll7owrk1vY1/rBjJodg+Y0q5uOXYfjT/Jmq0c/u0uQewUSdG6mSMEpmbSg43cAeA/9xruM0sVelBzH5zgvzQjUF6yTsN0E3XVwxmS6l1YesnfYXmGnJ1w5vQJMbLaN1FyPoRw0AsaGGqQooL4FEwb+vu299J9x61U4GxKJrJd16mRWItu0Rj4oZ79zdElTRcjvGQz4j1qelDDfxufst9hIqkSjIEzsBPZMIp/49FJfKwgsuB2fl8L3q4XnqPG4AXRRsb25JEMPQYEpvk31kVmtCGadhAKgLrjZ2Kd6amyZ37pt2oASilGA=
- secure: C+qQ9H2aTpZAjHBEW4LcRODxdozEwerA8CF1bQZ2sJCXY0wlP9tikaaNWrCBWGv9/v7X5qIwORXJwGyEAxg331FsJNvQ7i+rNSbna5NlHozWChUQvjPe+fWpCPdAEKeAF+JyDLKRbsWo2SqiaYDsnTXD5BaancOCGqkpEDZrm7HdUL091arG8CJVjUG2OaEo0aNsnuw7Z9NVTw5zD9lmGBlpKlTwXXfjzNg1Y5ThHkfxsCoYWa8rfL+wdec6ZghJFZ6ITZbYKBPbXYIUyJO1dboJi0+EhAnL9rD1NmcK2ERz8d99HqKhzEI/KoHCtOe+czOBhi5/OMe2lza1tL+z3uFF4TS86Qdk7JARegdHdxTPlztcagTd70wUwJ1POMBRnrVdFhnXvWDX87lk0RGvGUlCTsh+lMwZBM4UdMH96Eb+mwECe5qeWE8vGkPEtny6sTKhJvEhHmHmVNL/tYdqXsEdgfSOSHrhXfvesUMvr62/KlA9mFTtAzShom+4Jpx+1OlLdNDHyRmODoRhDJnuHRCOCjXzks8W12Hbg5ej7KnqLO0ymlGQumGoVjWzOHKwdNuItN1mEGRA/p0+nxS2tSAyg9rJF4spFRugGa1yapDzj7bqUfq8oCa4qzIbuiNU22Y8SQMdYJxvHBhq4wLcRX9g7u1uNEtKyykb5+nrKug=
- secure: YQEb1NAiHbgkiaHGJ6FHxMb7CYy44uszfqyC2Yj98ueuZDFJFIJqchUe9k2H3CdayU0i7MhCEk0LL4hSZpXRhyyFs6AxWh82ISPrBaraCyd5x51EoKPeVmTW1MTLjl467HX357Do41JsooMkGX8llpaAzJP5mY7fJmx91Cnpg5dQbAeSWhwSM16yfYHHpQXvoGmTlcj89hoJ7LLTMEg6o+CgGlYnx5LB/vvWxHNiMNVB+IJEMo7MopQUVkVqTEJ+k8x0i2tBdwLNCoMl79xrsYETsSRzn85zuD/wqfY0yfvEwYsKD1YtkjJW14/y4mFFHCyW+/igORknuBRF1qRZEOHeTMiDmNOsA2yi1RXjNIeUpOctCNV29KDAyqkOfQwlKMzezBGoVKRsxd3oWZpjNjnqgQ7lEx5CwQKN5pSxMmd1pWZTkY+Ci9b+VrBvshhdPwBKsjZjS8jDHlX0uT6OHPN17PFziCtKRfh+gukSLJJcxRz9H/4F6NLpFJzx4/UsFLW45XY5BXwucYgUyk+oXeQDlzSXVpAuE2KDOaHWg12jlnWptTq7rHfKE0N61JOgolThCun5i+0L6eydaPNswqUtbB/WlDdkbpDMaUFR/HFDFNkTiJyPpTeYHdsqwq57hqI/D2Otkc28wbVHodYZyxiaLe9gozmD5IYS8Sf9tdM=

BIN
deploy_rsa.enc Normal file

Binary file not shown.

View File

@ -23,7 +23,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'));
add_action( 'after_setup_theme', array( &$this, 'load_theme_files'));
}
@ -58,14 +58,15 @@ class Admin {
return $style;
}
function load_icon_font() {
add_action( 'wp_enqueue_scripts', array(&$this, 'add_material_design_icon_css') );
function load_theme_files() {
add_action( 'wp_enqueue_scripts', array(&$this, 'add_theme_files') );
}
function add_material_design_icon_css() {
function add_theme_files() {
global $TAINACAN_BASE_URL;
wp_enqueue_style( 'style', $TAINACAN_BASE_URL . '/assets/css/fonts/materialdesignicons.css' );
wp_enqueue_script('underscore', includes_url('js') . '/underscore.min.js' );
}
function add_admin_css() {

View File

@ -0,0 +1,135 @@
<template>
<div>
<div class="columns is-multiline tnc-advanced-search-container">
<div
v-for="searchField in totalSearchMetadata"
:key="searchField"
class="field column is-12 tainacan-form">
<b-field
class="columns"
grouped>
<b-field class="column">
<b-select
@input.native="addToAdvancedSearchQuery($event)">
<option
v-for="metadata in metadataList"
v-if="metadata.enabled"
:value="metadata.id"
:key="metadata.id"
>{{ metadata.name }}</option>
</b-select>
</b-field>
<b-field class="column is-two-thirds">
<b-input
@input.native="addValueToAdvancedSearchQuery($event)"/>
</b-field>
<b-field class="column">
<b-select
@input.native="addToAdvancedSearchQuery($event)">
<option
v-for="(opt, key) in compare"
:value="key"
:key="key"
>{{ opt }}</option>
</b-select>
</b-field>
</b-field>
</div>
<div
:style="{'padding-left': '25px !important'}"
class="field column is-12">
<div class="is-inline">
<b-icon
icon="plus-circle"
size="is-small"
type="is-secondary"/>
<a
@click="addSearchMetadata"
class="is-secondary is-small">
{{ $i18n.get('add_more_one_search_field') }}</a>
</div>
</div>
<div class="column">
<div class="field is-grouped is-pulled-right">
<p class="control">
<button
@click="clearSearch"
class="button is-outlined">{{ $i18n.get('clear_search') }}</button>
</p>
<p class="control">
<button
@click="searchAdvanced"
class="button is-secondary">{{ $i18n.get('search') }}</button>
</p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "AdvancedSearch",
props: {
metadataList: Array,
isRepositoryLevel: false,
},
data(){
return {
compare: {'=':'Igual', '!=':'Diferente', 'IN':'Contém', 'NOT IN':'Não Contém'},
totalSearchMetadata: 1,
advancedSearchQuery: {},
}
},
methods: {
addSearchMetadata(){
this.totalSearchMetadata++;
},
clearSearch(){
this.totalSearchMetadata = 1;
},
addValueToAdvancedSearchQuery: _.debounce(($event) => {
console.log($event);
}, 900),
searchAdvanced(){
},
addToAdvancedSearchQuery($event){
console.log($event);
},
}
}
</script>
<style lang="scss">
@import '../../scss/_variables.scss';
.tnc-advanced-search-container {
padding-top: 47px;
padding-right: $page-side-padding;
padding-left: $page-side-padding;
padding-bottom: 47px;
.column {
padding: 0 0.3rem 0.3rem !important;
}
.control {
.select{
width: 100% !important;
select{
width: 100% !important;
}
}
}
}
</style>

View File

@ -140,6 +140,7 @@
import { mapActions, mapGetters } from 'vuex';
import TermsList from '../lists/terms-list.vue'
import htmlToJSON from 'html-to-json';
import CustomDialog from '../other/custom-dialog.vue';
export default {
name: 'CategoryEditionForm',
@ -194,17 +195,20 @@
formNotSaved = true;
if (formNotSaved) {
this.$dialog.confirm({
message: this.$i18n.get('info_warning_category_not_saved'),
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.$i18n.get('info_warning_category_not_saved'),
onConfirm: () => {
next();
},
cancelText: this.$i18n.get('cancel'),
confirmText: this.$i18n.get('continue'),
type: 'is-secondary'
});
}
}
});
} else {
next()
next();
}
},
methods: {

View File

@ -301,6 +301,7 @@
class="control"
custom>
<b-checkbox
v-if="registeredViewModes[viewMode] != undefined"
@input="updateViewModeslist(viewMode)"
:value="checkIfViewModeEnabled(viewMode)">
{{ registeredViewModes[viewMode].label }}
@ -326,6 +327,7 @@
@focus="clearErrors('default_view_mode')">
<option
v-for="(viewMode, index) of form.enabled_view_modes"
v-if="registeredViewModes[viewMode] != undefined"
:key="index"
:value="viewMode">{{ registeredViewModes[viewMode].label }}
</option>

View File

@ -21,7 +21,7 @@
:title="$i18n.getHelperTitle('items', 'status')"
:message="$i18n.getHelperMessage('items', 'status')"/>
</div>
<div class="section-box section-status">
<div class="section-status">
<div class="field">
<!-- <div class="block">
<b-radio
@ -336,6 +336,7 @@ import { mapActions, mapGetters } from 'vuex';
import { eventBus } from '../../../js/event-bus-web-components.js'
import wpMediaFrames from '../../js/wp-media-frames';
import FileItem from '../other/file-item.vue';
import CustomDialog from '../other/custom-dialog.vue';
export default {
name: 'ItemEditionForm',
@ -675,15 +676,18 @@ export default {
},
beforeRouteLeave ( to, from, next ) {
if (this.item.status == 'auto-draft') {
this.$dialog.confirm({
message: this.$i18n.get('info_warning_item_not_saved'),
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
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()
}
@ -794,7 +798,7 @@ export default {
}
}
.section-status{
width: 174px;
padding: 16px 0;
}
.section-thumbnail {
width: 174px;

View File

@ -18,7 +18,7 @@
@click="headerImageMediaFrame.openFrame($event)">
<b-icon icon="pencil"/>
</a>
<figure class="image is-128x128">
<figure class="image">
<span
v-if="editForm.header_image === undefined || editForm.header_image === false"
class="image-placeholder">{{ $i18n.get('label_empty_header_image') }}</span>
@ -29,18 +29,22 @@
<div class="thumbnail-buttons-row">
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete_header_image')"
@click="deleteHeaderImage()">
<b-icon icon="delete"/>
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteThumbnail()">
<b-icon
type="is-gray"
icon="delete" />
<span class="text">{{ $i18n.get('remove') }} </span>
</a>
</div>
<a
v-if="editForm.url != undefined && editForm.url!= ''"
class="button is-secondary"
:href="editForm.url">
{{ $i18n.get('see') + ' ' + $i18n.get('term') }}
</a>
<br>
</div>
<a
v-if="editForm.url != undefined && editForm.url!= ''"
class="button is-secondary"
:href="editForm.url">
{{ $i18n.get('see') + ' ' + $i18n.get('term') }}
</a>
</b-field>
</div>
@ -229,15 +233,22 @@
@import "../../scss/_variables.scss";
.column {
padding: 0;
&.is-narrow {
padding-right: 42px;
}
}
form {
padding: 1.0em 2.0em;
padding: 2.0rem 2rem 1rem 2rem;
border-top: 1px solid $draggable-border-color;
border-bottom: 1px solid $draggable-border-color;
margin-top: 1.0em;
.thumbnail-field {
max-height: 128px;
margin-bottom: 96px;
margin-bottom: 66px;
margin-top: -20px;
.content {
@ -245,12 +256,14 @@
font-size: 0.8em;
}
img {
position: absolute;
position: relative;
width: 128px;
}
.image-placeholder {
position: absolute;
margin-left: 10px;
margin-right: 10px;
top: 24px;
bottom: 50%;
font-size: 0.8rem;
font-weight: bold;
@ -273,18 +286,19 @@
margin-top: 1px;
}
}
.thumbnail-buttons-row {
display: none;
}
&:hover {
.thumbnail-buttons-row {
display: inline-block;
display: inline-block;
padding: 8px 0px;
border-radius: 0px 0px 0px 4px;
font-size: 14px;
a { color: $tainacan-input-color; }
.text {
top: -3px;
position: relative;
top: -128px;
background-color: rgba(255, 255, 255, 0.9);
padding: 2px 8px;
border-radius: 0px 0px 0px 4px;
left: 88px;
}
i.mdi-24px.mdi-set, i.mdi-24px.mdi::before {
font-size: 20px;
}
}
}

View File

@ -132,7 +132,8 @@
</template>
<script>
import { mapActions } from 'vuex'
import { mapActions } from 'vuex';
import CustomDialog from '../other/custom-dialog.vue';
export default {
name: 'CategoriesList',
@ -179,64 +180,76 @@
this.selectedCategories.splice(i, 1, !this.allCategoriesOnPageSelected);
},
deleteOneCategory(categoryId) {
this.$dialog.confirm({
message: this.$i18n.get('info_warning_category_delete'),
onConfirm: () => {
this.deleteCategory(categoryId)
.then(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_category_deleted'),
// position: 'is-bottom',
// type: 'is-secondary',
// queue: true
// });
for (let i = 0; i < this.selectedCategories.length; i++) {
if (this.selectedCategories[i].id === this.categoryId)
this.selectedCategories.splice(i, 1);
}
})
.catch(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_error_deleting_category'),
// position: 'is-bottom',
// type: 'is-danger',
// queue: true
// });
});
}
});
},
deleteSelectedCategories() {
this.$dialog.confirm({
message: this.$i18n.get('info_warning_selected_categories_delete'),
onConfirm: () => {
for (let i = 0; i < this.categories.length; i++) {
if (this.selectedCategories[i]) {
this.deleteCategory(this.categories[i].id)
.then(() => {
// this.loadCategories();
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_category_deleted'),
// position: 'is-bottom',
// type: 'is-secondary',
// queue: false
// })
}).catch(() => {
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.$i18n.get('info_warning_category_delete'),
onConfirm: () => {
this.deleteCategory(categoryId)
.then(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_category_deleted'),
// position: 'is-bottom',
// type: 'is-secondary',
// queue: true
// });
for (let i = 0; i < this.selectedCategories.length; i++) {
if (this.selectedCategories[i].id === this.categoryId)
this.selectedCategories.splice(i, 1);
}
})
.catch(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_error_deleting_category'),
// position: 'is-bottom',
// type: 'is-danger',
// queue: false
// queue: true
// });
});
}
}
this.allCategoriesOnPageSelected = false;
}
});
},
deleteSelectedCategories() {
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.$i18n.get('info_warning_selected_categories_delete'),
onConfirm: () => {
for (let i = 0; i < this.categories.length; i++) {
if (this.selectedCategories[i]) {
this.deleteCategory(this.categories[i].id)
.then(() => {
// this.loadCategories();
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_category_deleted'),
// position: 'is-bottom',
// type: 'is-secondary',
// queue: false
// })
}).catch(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_error_deleting_category'),
// position: 'is-bottom',
// type: 'is-danger',
// queue: false
// });
});
}
}
this.allCategoriesOnPageSelected = false;
}
}
});
},

View File

@ -181,7 +181,8 @@
</template>
<script>
import { mapActions } from 'vuex'
import { mapActions } from 'vuex';
import CustomDialog from '../other/custom-dialog.vue';
export default {
name: 'CollectionsList',
@ -229,63 +230,76 @@ export default {
this.selectedCollections.splice(i, 1, !this.allCollectionsOnPageSelected);
},
deleteOneCollection(collectionId) {
this.$dialog.confirm({
message: this.isOnTrash ? this.$i18n.get('info_warning_collection_delete') : this.$i18n.get('info_warning_collection_trash'),
onConfirm: () => {
this.deleteCollection({ collectionId: collectionId, isPermanently: this.isOnTrash })
.then(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_collection_deleted'),
// position: 'is-bottom',
// type: 'is-secondary',
// queue: true
// });
for (let i = 0; i < this.selectedCollections.length; i++) {
if (this.selectedCollections[i].id == collectionId)
this.selectedCollections.splice(i, 1);
}
}).catch(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_error_deleting_collection'),
// position: 'is-bottom',
// type: 'is-danger',
// queue: true
// })
});
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.isOnTrash ? this.$i18n.get('info_warning_collection_delete') : this.$i18n.get('info_warning_collection_trash'),
onConfirm: () => {
this.deleteCollection({ collectionId: collectionId, isPermanently: this.isOnTrash })
.then(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_collection_deleted'),
// position: 'is-bottom',
// type: 'is-secondary',
// queue: true
// });
for (let i = 0; i < this.selectedCollections.length; i++) {
if (this.selectedCollections[i].id == collectionId)
this.selectedCollections.splice(i, 1);
}
}).catch(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_error_deleting_collection'),
// position: 'is-bottom',
// type: 'is-danger',
// queue: true
// })
});
}
}
});
},
deleteSelectedCollections() {
this.$dialog.confirm({
message: this.isOnTrash ? this.$i18n.get('info_warning_selected_collections_delete') : this.$i18n.get('info_warning_selected_collections_trash'),
onConfirm: () => {
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.isOnTrash ? this.$i18n.get('info_warning_selected_collections_delete') : this.$i18n.get('info_warning_selected_collections_trash'),
onConfirm: () => {
for (let i = 0; i < this.collections.length; i++) {
if (this.selectedCollections[i]) {
this.deleteCollection({ collectionId: this.collections[i].id, isPermanently: this.isOnTrash })
.then(() => {
// this.loadCollections();
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_collection_deleted'),
// position: 'is-bottom',
// type: 'is-secondary',
// queue: false
// })
}).catch(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_error_deleting_collection'),
// position: 'is-bottom',
// type: 'is-danger',
// queue: false
// });
});
for (let i = 0; i < this.collections.length; i++) {
if (this.selectedCollections[i]) {
this.deleteCollection({ collectionId: this.collections[i].id, isPermanently: this.isOnTrash })
.then(() => {
// this.loadCollections();
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_collection_deleted'),
// position: 'is-bottom',
// type: 'is-secondary',
// queue: false
// })
}).catch(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_error_deleting_collection'),
// position: 'is-bottom',
// type: 'is-danger',
// queue: false
// });
});
}
}
}
this.allCollectionsOnPageSelected = false;
this.allCollectionsOnPageSelected = false;
},
}
});
},
@ -359,6 +373,10 @@ export default {
}
}
}
img.table-thumb {
border-radius: 50px !important;
}
</style>

View File

@ -29,9 +29,10 @@
:options="{
group: { name:'fields', pull: false, put: true },
sort: openedFieldId == '' || openedFieldId == undefined,
disabled: openedFieldId != '' && openedFieldId != undefined,
//disabled: openedFieldId != '' && openedFieldId != undefined,
handle: '.handle',
ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen',
filter: 'not-sortable-item',
animation: '250'}">
<div
@ -148,6 +149,7 @@
import { mapActions, mapGetters } from 'vuex';
import GripIcon from '../other/grip-icon.vue';
import FieldEditionForm from './../edition/field-edition-form.vue';
import CustomDialog from '../other/custom-dialog.vue';
export default {
name: 'FieldsList',
@ -194,16 +196,19 @@ export default {
hasUnsavedForms = true;
}
if ((this.openedFieldId != '' && this.openedFieldId != undefined) || hasUnsavedForms ) {
this.$dialog.confirm({
message: this.$i18n.get('info_warning_fields_not_saved'),
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.$i18n.get('info_warning_fields_not_saved'),
onConfirm: () => {
this.onEditionCanceled();
next();
},
cancelText: this.$i18n.get('cancel'),
confirmText: this.$i18n.get('continue'),
type: 'is-secondary'
});
}
});
} else {
next()
}

View File

@ -27,7 +27,7 @@
:options="{
group: { name:'filters', pull: false, put: true },
sort: openedFilterId == '' || openedFilterId == undefined,
disabled: openedFilterId != '' && openedFilterId != undefined,
//disabled: openedFilterId != '' && openedFilterId != undefined,
handle: '.handle',
ghostClass: 'sortable-ghost',
filter: 'not-sortable-item',
@ -177,6 +177,7 @@
import { mapActions, mapGetters } from 'vuex';
import GripIcon from '../other/grip-icon.vue';
import FilterEditionForm from './../edition/filter-edition-form.vue';
import CustomDialog from '../other/custom-dialog.vue';
export default {
name: 'FiltersList',
@ -221,16 +222,19 @@ export default {
hasUnsavedForms = true;
}
if ((this.openedFilterId != '' && this.openedFilterId != undefined) || hasUnsavedForms ) {
this.$dialog.confirm({
message: this.$i18n.get('info_warning_filters_not_saved'),
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.$i18n.get('info_warning_filters_not_saved'),
onConfirm: () => {
this.onEditionCanceled();
next();
},
cancelText: this.$i18n.get('cancel'),
confirmText: this.$i18n.get('continue'),
type: 'is-secondary'
});
}
});
} else {
next()
}

View File

@ -35,7 +35,149 @@
</div>
<div class="table-wrapper">
<table class="tainacan-table">
<!-- GRID VIEW MODE -->
<div
class="tainacan-grid-container"
v-if="viewMode == 'grid'">
<div
:key="index"
v-for="(item, index) of items"
:class="{ 'selected-grid-item': selectedItems[index] }"
class="tainacan-grid-item">
<!-- Checkbox -->
<div
:class="{ 'is-selecting': isSelectingItems }"
class="grid-item-checkbox">
<b-checkbox
size="is-small"
v-model="selectedItems[index]"/>
</div>
<!-- Title -->
<p
v-for="(column, index) in tableFields"
:key="index"
v-if="column.display && column.field_type_object != undefined && (column.field_type_object.related_mapped_prop == 'title')"
class="metadata-title"
@click="goToItemPage(item)"
v-html="item.metadata != undefined ? renderMetadata(item.metadata, column) : ''"/>
<!-- Thumbnail -->
<a
v-if="item.thumbnail != undefined"
@click="goToItemPage(item)">
<img :src="item['thumbnail'].medium ? item['thumbnail'].medium : thumbPlaceholderPath">
</a>
<!-- Actions -->
<div
v-if="item.current_user_can_edit"
class="actions-area"
:label="$i18n.get('label_actions')">
<a
id="button-edit"
:aria-label="$i18n.getFrom('items','edit_item')"
@click.prevent.stop="goToItemEditPage(item.id)">
<b-icon
type="is-secondary"
icon="pencil"/>
</a>
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete')"
@click.prevent.stop="deleteOneItem(item.id)">
<b-icon
type="is-secondary"
:icon="!isOnTrash ? 'delete' : 'delete-forever'"/>
</a>
</div>
</div>
</div>
<!-- CARDS VIEW MODE -->
<div
class="tainacan-cards-container"
v-if="viewMode == 'cards'">
<div
:key="index"
v-for="(item, index) of items"
:class="{ 'selected-card': selectedItems[index] }"
class="tainacan-card">
<!-- Checkbox -->
<div
:class="{ 'is-selecting': isSelectingItems }"
class="card-checkbox">
<b-checkbox
size="is-small"
v-model="selectedItems[index]"/>
</div>
<!-- Title -->
<p
v-for="(column, index) in tableFields"
:key="index"
v-if="column.display && column.field_type_object != undefined && (column.field_type_object.related_mapped_prop == 'title')"
class="metadata-title"
@click="goToItemPage(item)"
v-html="item.metadata != undefined ? renderMetadata(item.metadata, column) : ''" />
<!-- Actions -->
<div
v-if="item.current_user_can_edit"
class="actions-area"
:label="$i18n.get('label_actions')">
<a
id="button-edit"
:aria-label="$i18n.getFrom('items','edit_item')"
@click.prevent.stop="goToItemEditPage(item.id)">
<b-icon
type="is-secondary"
icon="pencil"/>
</a>
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete')"
@click.prevent.stop="deleteOneItem(item.id)">
<b-icon
type="is-secondary"
:icon="!isOnTrash ? 'delete' : 'delete-forever'"/>
</a>
</div>
<!-- Remaining metadata -->
<div
class="media"
@click="goToItemPage(item)">
<a
v-if="item.thumbnail != undefined"
@click="goToItemPage(item)">
<img :src="item['thumbnail'].medium_large ? item['thumbnail'].medium_large : thumbPlaceholderPath">
</a>
<div class="list-metadata media-body">
<span
v-for="(column, index) in tableFields"
:key="index"
v-if="column.display && column.slug != 'thumbnail' && column.field_type_object != undefined && (column.field_type_object.related_mapped_prop != 'title')">
<h3 class="metadata-label">{{ column.name }}</h3>
<p
v-html="item.metadata != undefined ? renderMetadata(item.metadata, column) : ''"
class="metadata-value"/>
</span>
</div>
</div>
</div>
</div>
<!-- TABLE VIEW MODE -->
<table
v-if="viewMode == 'table'"
class="tainacan-table">
<thead>
<tr>
<!-- Checking list -->
@ -84,8 +226,6 @@
v-for="(column, index) in tableFields"
v-if="column.display"
:label="column.name"
:aria-label="(column.field != 'row_thumbnail' && column.field != 'row_creation' && column.field != 'row_author')
? column.name + '' + (item.metadata ? item.metadata[column.slug].value_as_string : '') : ''"
class="column-default-width"
:class="{
'thumbnail-cell': column.field == 'row_thumbnail',
@ -101,10 +241,10 @@
v-if="column.field !== 'row_thumbnail' &&
column.field !== 'row_actions' &&
column.field !== 'row_creation'"
:data="renderMetadata( item.metadata[column.slug] )"/> -->
:data="renderMetadata(item.metadata, column)"/> -->
<p
v-tooltip="{
content: renderMetadata( item.metadata[column.slug] ),
content: renderMetadata(item.metadata, column),
html: true,
autoHide: false,
placement: 'auto-start'
@ -114,12 +254,12 @@
column.field !== 'row_actions' &&
column.field !== 'row_creation' &&
column.field !== 'row_author'"
v-html="renderMetadata( item.metadata[column.slug] )"/>
v-html="renderMetadata(item.metadata, column)"/>
<span v-if="column.field == 'row_thumbnail'">
<img
class="table-thumb"
:src="item[column.slug].thumb">
:src="item['thumbnail'].thumb ? item['thumbnail'].thumb : thumbPlaceholderPath">
</span>
<p
v-tooltip="{
@ -167,6 +307,7 @@
<script>
import { mapActions } from 'vuex';
import CustomDialog from '../other/custom-dialog.vue';
export default {
name: 'ItemsList',
@ -175,6 +316,7 @@ export default {
allItemsOnPageSelected: false,
isSelectingItems: false,
selectedItems: [],
thumbPlaceholderPath: tainacan_plugin.base_url + '/admin/images/placeholder_square.png',
}
},
props: {
@ -182,12 +324,13 @@ export default {
tableFields: Array,
items: Array,
isLoading: false,
isOnTrash: false
isOnTrash: false,
viewMode: 'table'
},
mounted() {
this.selectedItems = [];
for (let i = 0; i < this.items.length; i++)
this.selectedItems.push(false);
this.selectedItems.push(false);
},
watch: {
selectedItems() {
@ -213,68 +356,80 @@ export default {
this.selectedItems.splice(i, 1, !this.allItemsOnPageSelected);
},
deleteOneItem(itemId) {
this.$dialog.confirm({
message: this.isOnTrash ? this.$i18n.get('info_warning_item_delete') : this.$i18n.get('info_warning_item_trash'),
onConfirm: () => {
this.deleteItem({ itemId: itemId, isPermanently: this.isOnTrash })
.then(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_item_deleted'),
// position: 'is-bottom',
// type: 'is-secondary',
// queue: true
// });
for (let i = 0; i < this.selectedItems.length; i++) {
if (this.selectedItems[i].id == itemId)
this.selectedItems.splice(i, 1);
}
}).catch(() => {
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.isOnTrash ? this.$i18n.get('info_warning_item_delete') : this.$i18n.get('info_warning_item_trash'),
onConfirm: () => {
this.deleteItem({ itemId: itemId, isPermanently: this.isOnTrash })
// .then(() => {
// // this.$toast.open({
// // duration: 3000,
// // message: this.$i18n.get('info_item_deleted'),
// // position: 'is-bottom',
// // type: 'is-secondary',
// // queue: true
// // });
// for (let i = 0; i < this.selectedItems.length; i++) {
// if (this.selectedItems[i].id == itemId)
// this.selectedItems.splice(i, 1);
// }
// }).catch(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_error_deleting_item'),
// position: 'is-bottom',
// type: 'is-danger',
// queue: true
// })
});
// // this.$toast.open({
// // duration: 3000,
// // message: this.$i18n.get('info_error_deleting_item'),
// // position: 'is-bottom',
// // type: 'is-danger',
// // queue: true
// // })
// });
}
}
});
},
deleteSelectedItems() {
this.$dialog.confirm({
message: this.isOnTrash ? this.$i18n.get('info_warning_selected_items_delete') : this.$i18n.get('info_warning_selected_items_trash'),
onConfirm: () => {
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.isOnTrash ? this.$i18n.get('info_warning_selected_items_delete') : this.$i18n.get('info_warning_selected_items_trash'),
onConfirm: () => {
for (let i = 0; i < this.selectedItems.length; i++) {
if (this.selectedItems[i]) {
this.deleteItem({ itemId: this.items[i].id, isPermanently: this.isOnTrash })
.then(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_item_deleted'),
// position: 'is-bottom',
// type: 'is-secondary',
// queue: false
// });
for (let i = 0; i < this.selectedItems.length; i++) {
if (this.selectedItems[i].id == this.itemId)
this.selectedItems.splice(i, 1);
}
}).catch(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_error_deleting_item'),
// position: 'is-bottom',
// type: 'is-danger',
// queue: false
// });
});
for (let i = 0; i < this.selectedItems.length; i++) {
if (this.selectedItems[i]) {
this.deleteItem({ itemId: this.items[i].id, isPermanently: this.isOnTrash })
.then(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_item_deleted'),
// position: 'is-bottom',
// type: 'is-secondary',
// queue: false
// });
for (let i = 0; i < this.selectedItems.length; i++) {
if (this.selectedItems[i].id == this.itemId)
this.selectedItems.splice(i, 1);
}
}).catch(() => {
// this.$toast.open({
// duration: 3000,
// message: this.$i18n.get('info_error_deleting_item'),
// position: 'is-bottom',
// type: 'is-danger',
// queue: false
// });
});
}
}
this.allItemsOnPageSelected = false;
}
this.allItemsOnPageSelected = false;
}
});
},
@ -284,7 +439,9 @@ export default {
goToItemEditPage(itemId) {
this.$router.push(this.$routerHelper.getItemEditPath(this.collectionId, itemId));
},
renderMetadata(metadata) {
renderMetadata(itemMetadata, column) {
let metadata = itemMetadata[column.slug] != undefined ? itemMetadata[column.slug] : false;
if (!metadata) {
return '';
@ -301,6 +458,8 @@ export default {
<style lang="scss" scoped>
@import "../../scss/_variables.scss";
@import "../../scss/_view-mode-grid.scss";
@import "../../scss/_view-mode-cards.scss";
.selection-control {

View File

@ -85,7 +85,8 @@
<script>
import { mapActions, mapGetters } from 'vuex';
import TermEditionForm from '../edition/term-edition-form.vue'
import TermEditionForm from '../edition/term-edition-form.vue';
import CustomDialog from '../other/custom-dialog.vue';
export default {
name: 'TermsList',
@ -212,14 +213,16 @@ export default {
// Checks if user is deleting a term with unsaved info.
if (term.id == 'new' || !term.saved || term.opened) {
this.$dialog.confirm({
message: this.$i18n.get('info_warning_terms_not_saved'),
onCancel: () => { return },
onConfirm: () => { this.removeTerm(term);},
cancelText: this.$i18n.get('cancel'),
confirmText: this.$i18n.get('continue'),
type: 'is-secondary'
});
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.$i18n.get('info_warning_terms_not_saved'),
onConfirm: () => { this.removeTerm(term); },
}
});
} else{
this.removeTerm(term);
}

View File

@ -69,9 +69,7 @@
tag="a"
to="/events"
:class="activeRoute == 'EventsPage' ? 'is-active':''">
<b-icon
size="is-small"
icon="flash"/>
<activities-icon />
<span class="menu-text">{{ $i18n.get('events') }}</span>
</router-link>
</li>
@ -81,13 +79,17 @@
</template>
<script>
export default {
name: 'PrimaryMenu',
props: {
isMenuCompressed: false,
activeRoute: '/collections'
}
}
import ActivitiesIcon from '../other/activities-icon.vue';
export default {
name: 'PrimaryMenu',
props: {
isMenuCompressed: false,
activeRoute: '/collections'
},
components: {
ActivitiesIcon
},
}
</script>
<style lang="scss" scoped>
@ -102,6 +104,9 @@
max-width: $side-menu-width;
z-index: 99;
.menu {
padding-top: 10px;
}
.separator {
height: 2px;
background-color: $separator-color;
@ -118,10 +123,19 @@
border-radius: 0px;
-webkit-transition: padding 0.2s linear; /* Safari */
transition: padding 0.2s linear;
.activities-icon {
fill: white;
}
}
a:hover, a.is-active {
background-color: $primary;
color: $tertiary;
.activities-icon {
fill: $tertiary;
}
}
a:focus {
box-shadow: none;

View File

@ -20,7 +20,7 @@
<div class="control has-icons-right is-small is-clearfix">
<input
autocomplete="on"
:placeholder="$i18n.get('instruction_search_repository')"
:placeholder="$i18n.get('instruction_search_on_repository')"
class="input is-small"
type="search"
v-model="searchTerm">
@ -28,7 +28,7 @@
<i class="mdi mdi-magnify" />
</span>
</div>
<a href="">{{ $i18n.get('advanced_search') }}</a>
<a @click="toItemsPage">{{ $i18n.get('advanced_search') }}</a>
</span>
<a
class="level-item"
@ -50,6 +50,16 @@ export default {
searchTerm: ''
}
},
methods: {
toItemsPage(){
this.$router.push({
path: '/items',
query: {
openAdvancedSearch: true
}
});
}
},
props: {
isMenuCompressed: false
}
@ -105,12 +115,13 @@ export default {
color: $tertiary;
}
.search-area {
display: none;//display: flex;
display: flex;
align-items: center;
margin-right: 36px;
.control {
input {
border-width: 0 !important;
height: 27px;
font-size: 11px;
color: $gray-light;

View File

@ -19,7 +19,7 @@
{{ arrayViewPath[index] }}
</router-link>
<span v-if="index == arrayRealPath.length - 1">{{ arrayViewPath[index] }}</span>
<span v-if="index != arrayRealPath.length - 1"> > </span>
<span v-if="index != arrayRealPath.length - 1 && arrayViewPath[index]"> > </span>
</span>
</nav>
</div>
@ -83,9 +83,7 @@
:to="{ path: $routerHelper.getCollectionEventsPath(id) }"
:class="activeRoute == 'CollectionEventsPage' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_events')">
<b-icon
size="is-small"
icon="flash"/>
<activities-icon />
<br>
<span class="menu-text">{{ $i18n.get('events') }}</span>
</router-link>
@ -97,6 +95,7 @@
<script>
import { mapActions, mapGetters } from 'vuex';
import ActivitiesIcon from '../other/activities-icon.vue';
export default {
name: 'TainacanSubheader',
@ -109,6 +108,9 @@ export default {
activeRouteName: '',
}
},
components: {
ActivitiesIcon
},
props: {
id: Number,
},
@ -130,7 +132,8 @@ export default {
'fetchCollectionName'
]),
...mapGetters('collection', [
'getCollectionName'
'getCollectionName',
'getCollection'
]),
...mapActions('item', [
'fetchItemTitle'
@ -160,6 +163,7 @@ export default {
this.fetchCollectionName(this.arrayRealPath[i])
.then(collectionName => this.arrayViewPath.splice(i, 1, collectionName))
.catch((error) => this.$console.error(error));
break;
case 'items':
this.fetchItemTitle(this.arrayRealPath[i])
@ -179,7 +183,11 @@ export default {
}
} else {
this.arrayViewPath.splice(i, 1, this.$i18n.get(this.arrayRealPath[i]));
if(this.arrayRealPath[i] == 'undefined'){
this.arrayViewPath.splice(i, 1, '');
} else {
this.arrayViewPath.splice(i, 1, this.$i18n.get(this.arrayRealPath[i]));
}
}
}
@ -192,7 +200,7 @@ export default {
this.arrayRealPath = this.$route.path.split("/");
this.arrayRealPath = this.arrayRealPath.filter((item) => item.length != 0);
this.generateViewPath();
}
}
@ -262,7 +270,6 @@ export default {
}
.level-left {
margin-left: 5px;
.level-item {
display: inline-block;
}
@ -342,9 +349,6 @@ export default {
.level-left {
margin-left: 0px !important;
.level-item {
margin-left: 30px;
}
}
top: 206px;
margin-bottom: 0px !important;

View File

@ -0,0 +1,32 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
width="20"
height="20"
viewBox="0 0 24 24"
class="activities-icon"
xml:space="preserve">
<path
d="M20,11c0,1-0.2,2.1-0.5,3h-2.2c0.4-0.9,0.7-1.9,0.7-3c0-3.9-3.1-7-7-7s-7,3.1-7,7c0,3.5,2.6,6.5,6,6.9v2
c-4.5-0.5-8-4.3-8-8.9c0-5,4-9,9-9S20,6,20,11z M14,22h-2v-2h2V22z M14,18h-2v-2h2V18z M22,22h-6v-2h6V22z M22,18h-6v-2h6V18z M12,6
h-2l0,6l2.7,2H16l-4-3V6z"/>
</svg>
</template>
<script>
export default {
name: 'ActivitiesIcon'
}
</script>
<style type="text/scss">
svg.activities-icon {
margin-bottom: -5px;
fill:#1E2F56;
}
</style>

View File

@ -0,0 +1,25 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
width="6.44px"
height="32.202px"
viewBox="0 0 6.44 32.202"
enable-background="new 0 0 6.44 32.202"
xml:space="preserve">
<path
fill="#BB3636"
d="M0,25.761h6.44v6.44H0V25.761 M0,0h6.44v19.321H0V0"/>
</svg>
</template>
<script>
export default {
name: 'AlertIcon'
}
</script>

View File

@ -0,0 +1,25 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
width="38.819px"
height="29.746px"
viewBox="0 0 38.819 29.746"
enable-background="new 0 0 38.819 29.746"
xml:space="preserve">
<path
fill="#259F87"
d="M38.819,3.128L12.2,29.746L0,17.546l3.128-3.128l9.073,9.05L35.691,0L38.819,3.128z"/>
</svg>
</template>
<script>
export default {
name: 'CheckIcon'
}
</script>

View File

@ -0,0 +1,57 @@
<template>
<div class="tainacan-form dialog">
<div
class="modal-card"
style="width: auto">
<div
v-if="icon != undefined && icon != ''"
class="modal-custom-icon">
<component :is="icon + '-icon'"/>
</div>
<section
class="modal-card-body">
<header
class="modal-card-head">
<h1 class="modal-card-title">{{ title }}</h1>
</header>
{{ message }}
</section>
<footer class="modal-card-foot form-submit">
<button
class="button is-outline"
type="button"
@click="$parent.close()">
{{ $i18n.get('cancel') }}
</button>
<button
class="button is-success"
@click="onConfirm(); $parent.close();">
{{ $i18n.get('continue') }}
</button>
</footer>
</div>
</div>
</template>
<script>
import AlertIcon from './alert-icon.vue';
import CheckIcon from './check-icon.vue';
import QuestionIcon from './question-icon.vue';
export default {
name: 'CustomDialog',
props: {
title: String,
message: String,
icon: String,
onConfirm: {
type: Function,
default: () => {}
}
},
components: {
AlertIcon,
CheckIcon,
QuestionIcon
}
}
</script>

View File

@ -0,0 +1,28 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
width="19.749px"
height="33.073px"
viewBox="0 0 19.749 33.073"
enable-background="new 0 0 19.749 33.073"
xml:space="preserve">
<path
fill="#BB3636"
d="M6.615,28.112h4.961v4.961H6.615V28.112 M9.922,0c8.847,0.364,12.7,9.293,7.441,15.991
c-1.373,1.654-3.588,2.745-4.68,4.134c-1.108,1.373-1.108,3.026-1.108,4.68H6.615c0-2.762,0-5.093,1.108-6.747
c1.091-1.654,3.307-2.629,4.68-3.721c4.002-3.704,3.01-8.946-2.48-9.376c-2.74,0-4.961,2.221-4.961,4.961H0C0,4.442,4.442,0,9.922,0
z"/>
</svg>
</template>
<script>
export default {
name: 'QuestionIcon'
}
</script>

View File

@ -41,7 +41,7 @@ import draggable from 'vuedraggable'
import store from '../../js/store/store'
import router from './router'
import eventBusSearch from '../../js/event-bus-search';
import { I18NPlugin, UserPrefsPlugin, RouterHelperPlugin, ConsolePlugin } from './utilities';
import { I18NPlugin, UserPrefsPlugin, RouterHelperPlugin, ConsolePlugin, UserCapabilitiesPlugin } from './utilities';
import VueMask from 'v-mask';
// Configure and Register Plugins
@ -50,6 +50,7 @@ Vue.use(VTooltip)
Vue.use(I18NPlugin);
Vue.use(UserPrefsPlugin);
Vue.use(RouterHelperPlugin);
Vue.use(UserCapabilitiesPlugin);
Vue.use(ConsolePlugin, {visual: false});
Vue.use(VueMask);

View File

@ -257,8 +257,20 @@ RouterHelperPlugin.install = function (Vue, options = {}) {
},
getEventEditPath(id) {
return '/events/' + id + '/edit';
}
}
}
}
// USER CAPABILITIES PLUGIN - Allows easy checking of user capabilities.
export const UserCapabilitiesPlugin = {};
UserCapabilitiesPlugin.install = function (Vue, options = {}) {
Vue.prototype.$userCaps = {
hasCapability(key) {
for (let i = 0; i < tainacan_plugin.user_caps.length; i++)
if (tainacan_plugin.user_caps[i] == key)
return true;
return false;
}
}
}

View File

@ -4,7 +4,7 @@
<tainacan-title />
<div
class="sub-header"
v-if="checkIfUserCanEdit()">
v-if="$userCaps.hasCapability('edit_tainacan-taxonomies')">
<div class="header-item">
<router-link
id="button-create-category"
@ -135,13 +135,6 @@
this.status = status;
this.loadCategories();
},
checkIfUserCanEdit() {
for (let capability of tainacan_plugin.user_caps) {
if (capability == 'edit_tainacan-taxonomies')
return true;
}
return false;
},
onChangeCategoriesPerPage(value) {
let prevValue = this.categoriesPerPage;
this.categoriesPerPage = value;
@ -205,7 +198,7 @@
padding-top: $page-small-top-padding;
padding-left: $page-side-padding;
padding-right: $page-side-padding;
border-bottom: 0.5px solid #ddd;
border-bottom: 1px solid #ddd;
.header-item {
display: inline-block;

View File

@ -4,7 +4,7 @@
<tainacan-title />
<div
class="sub-header"
v-if="checkIfUserCanEdit()">
v-if="$userCaps.hasCapability('edit_tainacan-collections')">
<div class="header-item">
<b-dropdown id="collection-creation-options-dropdown">
<button
@ -164,13 +164,6 @@ export default {
this.status = status;
this.loadCollections();
},
checkIfUserCanEdit() {
for (let capability of tainacan_plugin.user_caps) {
if (capability == 'edit_tainacan-collections')
return true;
}
return false;
},
onChangeCollectionsPerPage(value) {
let prevValue = this.collectionsPerPage;
this.collectionsPerPage = value;
@ -244,7 +237,7 @@ export default {
padding-top: $page-small-top-padding;
padding-left: $page-side-padding;
padding-right: $page-side-padding;
border-bottom: 0.5px solid #ddd;
border-bottom: 1px solid #ddd;
.header-item {
display: inline-block;

View File

@ -167,7 +167,7 @@
padding-top: $page-small-top-padding;
padding-left: $page-small-side-padding;
padding-right: $page-small-side-padding;
border-bottom: 0.5px solid #ddd;
border-bottom: 1px solid #ddd;
.header-item {
display: inline-block;

View File

@ -4,7 +4,8 @@
<!-- SEARCH AND FILTERS --------------------- -->
<!-- Filter menu compress button -->
<button
<button
v-if="!openAdvancedSearch"
id="filter-menu-compress-button"
:class="{'filter-menu-compress-button-top-repo': isRepositoryLevel}"
:style="{ top: isHeaderShrinked ? '125px' : '152px'}"
@ -12,38 +13,34 @@
<b-icon :icon="isFiltersMenuCompressed ? 'menu-right' : 'menu-left'" />
</button>
<!-- Side bar with search and filters -->
<aside
v-show="!isFiltersMenuCompressed"
class="filters-menu">
<aside
v-show="!isFiltersMenuCompressed && !openAdvancedSearch"
class="filters-menu"
:class="{ 'tainacan-form': isOnTheme }">
<b-loading
:is-full-page="false"
:active.sync="isLoadingFilters"/>
<b-field>
<div class="control is-small is-clearfix">
<div class="search-area">
<div class="control has-icons-right is-small is-clearfix">
<input
class="input is-small"
:placeholder="$i18n.get('instruction_search')"
type="search"
autocomplete="on"
:value="searchQuery"
@input="futureSearchQuery = $event.target.value"
@keyup.enter="updateSearch()">
class="input is-small"
:placeholder="$i18n.get('instruction_search')"
type="search"
autocomplete="on"
:value="searchQuery"
@input="futureSearchQuery = $event.target.value"
@keyup.enter="updateSearch()">
<span
@click="updateSearch()"
class="icon is-right">
<i class="mdi mdi-magnify" />
</span>
</div>
<p class="control">
<button
id="collection-search-button"
type="submit"
class="button"
@click="updateSearch()">
<b-icon
icon="magnify"
size="is-small"/>
</button>
</p>
</b-field>
<!-- <a class="is-size-7 is-secondary is-pulled-right">Busca avançada</a> -->
</div>
<a
@click="openAdvancedSearch = !openAdvancedSearch"
class="is-size-7 is-secondary is-pulled-right">{{ $i18n.get('advanced_search') }}</a>
<h3 class="has-text-weight-semibold">{{ $i18n.get('filters') }}</h3>
<a
@ -76,11 +73,12 @@
<div class="content has-text-gray has-text-centered">
<p>
<b-icon
icon="filter-outline"
icon="filter"
size="is-large"/>
</p>
<p>{{ $i18n.get('info_there_is_no_filter' ) }}</p>
<router-link
v-if="!isOnTheme"
id="button-create-filter"
:to="isRepositoryLevel ? $routerHelper.getNewFilterPath() : $routerHelper.getNewCollectionFilterPath(collectionId)"
tag="button"
@ -101,7 +99,9 @@
:active.sync="isLoadingItems"/>
<!-- SEARCH CONTROL ------------------------- -->
<div class="search-control">
<div
v-if="!openAdvancedSearch"
class="search-control">
<b-loading
:is-full-page="false"
:active.sync="isLoadingFields"/>
@ -143,7 +143,7 @@
<b-dropdown
ref="displayedFieldsDropdown"
:mobile-modal="false"
:disabled="totalItems <= 0"
:disabled="totalItems <= 0 || adminViewMode == 'grid'"
class="show">
<button
class="button is-white"
@ -211,7 +211,7 @@
v-if="isOnTheme"
class="search-control-item">
<b-field>
<b-dropdown
<b-dropdown
@change="onChangeViewMode($event)"
:mobile-modal="false"
position="is-bottom-left"
@ -235,12 +235,69 @@
</b-dropdown>
</b-field>
</div>
<div
v-if="!isOnTheme"
class="search-control-item">
<b-field>
<b-dropdown
v-model="adminViewMode"
:mobile-modal="false"
position="is-bottom-left"
:aria-label="$i18n.get('label_view_mode')">
<button
class="button is-white"
slot="trigger">
<span>
<b-icon
:icon="(adminViewMode == 'table' || adminViewMode == undefined) ?
'table' : (adminViewMode == 'cards' ?
'view-list' : 'view-grid')"/>
</span>
<b-icon icon="menu-down" />
</button>
<b-dropdown-item :value="'table'">
<b-icon icon="table"/>
{{ $i18n.get('label_table') }}
</b-dropdown-item>
<b-dropdown-item :value="'cards'">
<b-icon icon="view-list"/>
{{ $i18n.get('label_cards') }}
</b-dropdown-item>
<b-dropdown-item :value="'grid'">
<b-icon icon="view-grid"/>
{{ $i18n.get('label_grid') }}
</b-dropdown-item>
</b-dropdown>
</b-field>
</div>
</div>
<!-- ADVANCED SEARCH -->
<div
v-if="openAdvancedSearch">
<div class="columns tnc-advanced-search-close">
<div class="column">
<button
@click="openAdvancedSearch = false"
class="button is-white is-pulled-right">
<b-icon
size="is-small"
icon="close"/>
</button>
</div>
</div>
<advanced-search
:is-repository-level="isRepositoryLevel"
:metadata-list="fields" />
</div>
<!-- --------------- -->
<!-- STATUS TABS, only on Admin -------- -->
<div
v-if="!isOnTheme"
v-if="!isOnTheme && !openAdvancedSearch"
class="tabs">
<ul>
<li
@ -267,7 +324,8 @@
:table-fields="tableFields"
:items="items"
:is-loading="isLoadingItems"
:is-on-trash="status == 'trash'"/>
:is-on-trash="status == 'trash'"
:view-mode="adminViewMode"/>
<!-- Theme View Modes -->
<div
@ -324,6 +382,7 @@
import ItemsList from '../../components/lists/items-list.vue';
import FiltersItemsList from '../../components/search/filters-items-list.vue';
import Pagination from '../../components/search/pagination.vue'
import AdvancedSearch from '../../components/advanced-search/advanced-search.vue';
import { mapActions, mapGetters } from 'vuex';
export default {
@ -343,7 +402,9 @@
futureSearchQuery: '',
isHeaderShrinked: false,
localTableFields: [],
registeredViewModes: tainacan_plugin.registered_view_modes
registeredViewModes: tainacan_plugin.registered_view_modes,
adminViewMode: 'table',
openAdvancedSearch: false,
}
},
props: {
@ -386,7 +447,8 @@
components: {
ItemsList,
FiltersItemsList,
Pagination
Pagination,
AdvancedSearch,
},
watch: {
tableFields() {
@ -445,11 +507,15 @@
}
}
}
let thumbnailField = this.localTableFields.find(field => field.slug == 'thumbnail');
let creationDateField = this.localTableFields.find(field => field.slug == 'creation_date');
let authorNameField = this.localTableFields.find(field => field.slug == 'author_name');
this.$eventBusSearch.addFetchOnly({
'0': 'thumbnail',
'0': thumbnailField.display ? 'thumbnail' : null,
'meta': fetchOnlyFieldIds,
'1': 'creation_date',
'2': 'author_name'
'1': creationDateField.display ? 'creation_date' : null,
'2': authorNameField.display ? 'author_name': null
});
this.$refs.displayedFieldsDropdown.toggle();
},
@ -460,23 +526,23 @@
this.fetchFilters({
collectionId: this.collectionId,
isRepositoryLevel: this.isRepositoryLevel,
isContextEdit: true,
isContextEdit: !this.isOnTheme,
includeDisabled: 'no',
})
.then(() => this.isLoadingFilters = false)
.catch(() => this.isLoadingFilters = false);
this.isLoadingFields = true;
this.tableFields = [];
// Processing is done inside a local variable
let fields = [];
this.fetchFields({
collectionId: this.collectionId,
isRepositoryLevel: this.isRepositoryLevel,
isContextEdit: false
isContextEdit: !this.isOnTheme
})
.then(() => {
this.tableFields.push({
fields.push({
name: this.$i18n.get('label_thumbnail'),
field: 'row_thumbnail',
field_type: undefined,
@ -490,13 +556,14 @@
for (let field of this.fields) {
if (field.display !== 'never') {
let display = true;
let display;
if (field.display === 'no') {
if (field.display == 'no')
display = false;
}
else if (field.display == 'yes')
display = true;
this.tableFields.push(
fields.push(
{
name: field.name,
field: field.description,
@ -507,11 +574,12 @@
display: display
}
);
fetchOnlyFieldIds.push(field.id);
if (display)
fetchOnlyFieldIds.push(field.id);
}
}
this.tableFields.push({
fields.push({
name: this.$i18n.get('label_creation_date'),
field: 'row_creation',
field_type: undefined,
@ -519,7 +587,7 @@
id: undefined,
display: true
});
this.tableFields.push({
fields.push({
name: this.$i18n.get('label_created_by'),
field: 'row_author',
field_type: undefined,
@ -543,7 +611,7 @@
'2': 'author_name'
});
this.isLoadingFields = false;
this.tableFields = fields;
})
.catch(() => {
this.isLoadingFields = false;
@ -570,13 +638,16 @@
/* This condition is to prevent a incorrect fetch by filter or fields when we come from items
* at collection level to items page at repository level
*/
if(this.collectionId === to.params.collectionId) {
if (this.collectionId === to.params.collectionId) {
this.prepareFieldsAndFilters();
}
});
this.$eventBusSearch.setViewMode(this.defaultViewMode);
if(this.$route.query.openAdvancedSearch) {
this.openAdvancedSearch = this.$route.query.openAdvancedSearch;
}
},
mounted() {
@ -598,6 +669,16 @@
@import '../../scss/_variables.scss';
.tnc-advanced-search-close {
padding-top: 47px;
padding-right: $page-side-padding;
padding-left: $page-side-padding;
.column {
padding: 0 0.3rem 0.3rem !important;
}
}
.page-container {
padding: 0px;
}
@ -612,6 +693,7 @@
padding: $page-small-side-padding;
float: left;
overflow-y: auto;
overflow-x: hidden;
visibility: visible;
display: block;
transition: visibility ease 0.5s, display ease 0.5s;
@ -622,12 +704,26 @@
margin-top: 48px;
}
#collection-search-button {
border-radius: 0 !important;
padding: 0 8px !important;
border-color: $tainacan-input-background;
&:focus, &:active {
border-color: none !important;
.search-area {
display: flex;
align-items: center;
margin-right: 36px;
.control {
input {
height: 27px;
font-size: 11px;
color: $gray-light;
width: 148px;
}
.icon {
pointer-events: all;
cursor: pointer;
color: $tertiary;
height: 27px;
font-size: 18px;
}
margin-bottom: 5px;
}
}
@ -668,22 +764,14 @@
.search-control {
min-height: $subheader-height;
height: $subheader-height;
height: auto;
padding-top: $page-small-top-padding;
padding-left: $page-side-padding;
padding-right: $page-side-padding;
border-bottom: 0.5px solid #ddd;
display: flex;
justify-content: space-between;
@media screen and (max-width: 769px) {
height: 60px;
margin-top: 0;
.search-control-item {
padding-right: 0.5em;
}
}
flex-wrap: wrap;
}
.search-control-item {
@ -744,6 +832,7 @@
.table-container {
padding-left: 8.333333%;
padding-right: 8.333333%;
min-height: 200px;
//height: calc(100% - 82px);
}

View File

@ -7,6 +7,8 @@
height: inherit !important;
box-shadow: none !important;
display: inline-flex !important;
cursor: pointer;
background-color: white;
&.is-secondary:hover, &.is-secondary:focus {
background: $secondary !important;

View File

@ -14,16 +14,19 @@
}
}
.dropdown-menu {
padding: 0;
border-radius: 0px;
.dropdown-content {
padding: 0;
border-radius: 0px !important;
.dropdown-item {
padding: 0.375rem 1rem;
label { margin-bottom: 0; }
&.control { font-size: 13px !important; }
.b-checkbox { width: 100% };
&:hover {
background-color: $primary-lighter;
}
.is-small {
color: gray;
}
&:hover { background-color: $primary-lighter; }
.is-small { color: gray; }
&.is-active { background-color: white; }
}
}
}

View File

@ -1,4 +1,3 @@
// Tainacan modals
.tainacan-modal-title {
h1, h2 {
@ -35,9 +34,74 @@
padding: 80px 0em 0.4em 0em !important;
}
}
// Bulma modals customized for Tainacan
.dialog{
.modal-background {
background-color: rgba(0, 0, 0, 0.70);
}
.modal-card {
background-color: $modal-backgound-color;
color: $secondary;
border-radius: 10px;
flex-wrap: wrap;
flex-direction: row;
padding: 35px;
margin: 0 auto !important;
.modal-background {
background-color: rgba(0, 0, 0, 0.70);
.modal-card-head, .modal-card-body, .modal-card-foot {
background-color: $modal-backgound-color;
color: $secondary;
border: none;
padding-bottom: 12px;
}
.modal-custom-icon {
background-color: white;
border-radius: 50px;
height: 80px;
width: 80px;
display: flex;
align-items: center;
justify-content: center;
}
.modal-card-head {
h1 {
color: $secondary;
}
font-weight: normal;
padding: 0;
margin-bottom: 12px;
}
.modal-card-body {
padding: 0px 0px 0px 16px;
width: 50%;
}
.modal-card-foot {
justify-content: space-between;
padding: 24px 0px 0px 0px;
width: 100%;
.button {
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;
cursor: pointer;
font-size: 13px !important;
}
.button.is-success {
border: none;
}
.button:not(.is-success) {
background-color: white;
color: $tertiary;
border: 1px solid $gray-light;
}
}
}
}
// WordPress Media Modal customization

View File

@ -23,17 +23,6 @@
top: auto;
display: table-cell;
&::before {
box-shadow: inset 50px 0 10px -12px #222;
content: " ";
width: 50px;
height: 100%;
position: absolute;
left: 0;
top: 0;
visibility: hidden;
}
label.checkbox {
border-radius: 0px;
background-color: white;
@ -141,7 +130,7 @@
&.selected-row {
background-color: $primary-lighter;
.checkbox-cell .checkbox, .actions-cell .actions-container {
background-color: $primary-lighter;
background-color: $primary-lighter-hover;
}
}
td {
@ -172,20 +161,23 @@
width: 80px;
.actions-container {
visibility: hidden;
display: flex;
position: relative;
padding: 0;
height: 100%;
width: 80px;
z-index: 9;
background-color: transparent;
background-color: white;
float: right;
}
a {
margin: auto;
font-size: 18px !important;
.mdi-settings, .mdi-settings::before {
font-size: 23px;
}
}
}
@ -197,27 +189,15 @@
.checkbox-cell {
position: sticky !important;
position: -webkit-sticky !important;
&::before { visibility: visible; }
background-color: $gray-hover;
.checkbox {
background-color: $tainacan-input-background !important;
background-color: $gray-hover !important;
}
}
.actions-cell {
.actions-container {
visibility: visible;
background: $tainacan-input-background !important;
}
&::after {
box-shadow: inset -97px 0 17px -21px #222;
content: " ";
width: 100px;
height: 100%;
position: absolute;
right: 0px;
top: 0;
background: $gray-hover !important;
}
}

View File

@ -4,7 +4,7 @@
.form-submit {
justify-content: space-between !important;
padding: 12px 30px;
padding: 12px 0px ;
margin-bottom: 0px;
.button {
border-width: 1px;
@ -18,6 +18,7 @@
font-weight: bold;
font-size: 14px;
display: inline-block;
white-space: nowrap;
}
.required-field-asterisk {
color: $gray;

View File

@ -12,17 +12,20 @@ $tertiary-invert: findColorInvert($tertiary);
$primary-light:#c1dae0;
$primary-lighter: #e6f6f8;
$primary-lighter-hover: #d1e6e6;
$primary-dark: #55A0AF;
$primary-darker: darken($primary-dark, 5%);
$success: #25a189;
$success-invert: findColorInvert($success);
$modal-backgound-color: #bfd8dd;
$separator-color: #2b98a4;
$tainacan-input-color: #1d1d1d;
$tainacan-input-background: #e5e5e5;
$tainacan-placeholder-color: #898d8f;
$draggable-border-color: #d8d8d8;
$gray-hover: #dcdcdc;
$gray: #b1b1b1;
$gray-invert: findColorInvert($gray);

View File

@ -0,0 +1,118 @@
.tainacan-cards-container {
min-height: 200px;
padding: 0;
display: flex;
flex-wrap: wrap;
flex-grow: 1;
flex-shrink: 1;
justify-content: center;
.selected-card {
background-color: $primary-lighter;
.metadata-title {
background-color: $primary-lighter-hover;
}
}
.tainacan-card {
padding: 0px;
flex-basis: 0;
margin: 0.75rem;
max-width: 410px;
min-width: 410px;
cursor: pointer;
&:hover {
background-color: $tainacan-input-background !important;
}
.card-checkbox {
position: absolute;
margin-left: 1.0rem;
margin-top: 9px;
}
.actions-area {
position: relative;
float: right;
top: -7px;
padding-right: 12px;
width: 80px;
display: flex;
justify-content: space-between;
visibility: hidden;
opacity: 0;
transition: visibility 0.2s, opacity 0.2s;
}
&:hover .actions-area {
visibility: visible;
opacity: 1.0;
}
.card-line {
height: 1px;
background-color: $tainacan-input-background;
margin-left: -44px;
margin-right: -44px;
opacity: 0;
visibility: hidden;
}
img {
width: 170px;
height: auto;
border-radius: 2px;
}
&:hover img {
border-radius: 0;
}
.metadata-title {
flex-shrink: 0;
font-size: 0.875rem;
padding: 0.75rem 2.75rem;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
margin-bottom: -27px;
}
&:hover .metadata-title {
background-color: $gray-hover !important;
}
.media {
margin-bottom: -6px;
width: 100%;
.list-metadata {
padding: 0.75rem 1.5rem;
flex: 1;
font-size: 0.6875rem;
color: gray;
overflow: hidden;
width: 100%;
.metadata-label {
font-size: 0.75rem;
line-height: 1.0;
margin-bottom: 0.2rem;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
font-weight: 500;
color: $gray-light;
}
.metadata-value {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
margin-bottom: 1rem;
}
}
}
}
}

View File

@ -0,0 +1,84 @@
.tainacan-grid-container {
min-height: 200px;
padding: 0;
display: flex;
flex-wrap: wrap;
flex-grow: 1;
flex-shrink: 1;
justify-content: center;
.selected-grid-item {
background-color: $primary-lighter;
}
.tainacan-grid-item {
max-width: 258px;
flex-basis: 0;
margin: 1rem 1.5rem 1.5rem 1.5rem;
text-align: center;
&:hover {
background-color: $tainacan-input-background;
}
.grid-item-checkbox {
position: absolute;
margin-top: 9px;
margin-left: 1rem;
}
.actions-area {
position: relative;
float: right;
width: 100%;
display: flex;
justify-content: flex-end;
visibility: hidden;
opacity: 0;
padding: 8px;
transition: visibility 0.2s, opacity 0.2s;
margin-top: -43px;
background-color: $tainacan-input-background;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
a {
margin-left: 12px;
}
}
&:hover .actions-area {
visibility: visible;
opacity: 1.0;
}
&.selected-grid-item {
.actions-area {
background-color: $primary-lighter;
}
}
img {
min-width: 258px;
max-width: 258px;
height: auto;
border-radius: 2px;
margin-bottom: -5px;
}
p.metadata-title {
flex-shrink: 0;
font-size: 0.875rem;
margin-bottom: 6px;
margin-top: 6px;
margin-right: 6px;
margin-left: 24px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
text-align: left;
padding: 6px 1rem;
cursor: pointer;
}
}
}

View File

@ -5,3 +5,4 @@
@import "../../../node_modules/bulma/sass/elements/icon.sass"
@import "../../../node_modules/bulma/sass/elements/tag.sass"
@import "../../../node_modules/bulma/sass/components/tabs.sass"
@import "../../../node_modules/bulma/sass/elements/button.sass"

View File

@ -44,6 +44,8 @@ return apply_filters('tainacan-admin-i18n', [
'new_blank_collection' => __( 'New Blank Collection', 'tainacan' ),
'split' => __( 'Split', 'tainacan' ),
'unified' => __( 'Unified', 'tainacan' ),
'add_more_one_search_field' => __( 'Add more one search field', 'tainacan' ),
'clear_search' => __( 'Clear search', 'tainacan' ),
// Wordpress Status
'publish' => __( 'Publish', 'tainacan' ),
@ -199,6 +201,11 @@ return apply_filters('tainacan-admin-i18n', [
'label_default_view_mode' => __( 'Default view mode', 'tainacan' ),
'label_enabled_view_modes' => __( 'Enabled view modes', 'tainacan' ),
'label_view_modes_available' => __( 'View modes available on theme', 'tainacan' ),
'label_warning' => __( 'Warning', 'tainacan' ),
'label_error' => __( 'Erro', 'tainacan' ),
'label_grid' => __( 'Grid', 'tainacan' ),
'label_table' => __( 'Table', 'tainacan' ),
'label_cards' => __( 'Cards', 'tainacan' ),
// Instructions. More complex sentences to guide user and placeholders
'instruction_delete_selected_collections' => __( 'Delete selected collections', 'tainacan' ),
@ -220,6 +227,7 @@ return apply_filters('tainacan-admin-i18n', [
'instruction_insert_url' => __( 'Insert URL', 'tainacan' ),
'instruction_write_text' => __( 'Write Text', 'tainacan' ),
'instruction_search' => __( 'Search', 'tainacan' ),
'instruction_search_on_repository' => __( 'Search on repository', 'tainacan' ),
// Info. Other feedback to user.
'info_name_is_required' => __( 'Name is required.', 'tainacan' ),

View File

@ -14,7 +14,12 @@ export default {
<style lang="scss">
@import "../admin/scss/_variables.scss";
// Bulma imports
@import "./scss/theme-basics.sass";
// Buefy imports
@import "../../node_modules/buefy/src/scss/components/_datepicker.scss";
$speed-slow: 0.5s;
@import "../../node_modules/buefy/src/scss/utils/_functions.scss";
@ -24,41 +29,12 @@ export default {
@import "../../node_modules/buefy/src/scss/components/_loading.scss";
@import "../../node_modules/buefy/src/scss/components/_dropdown.scss";
// 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);
$table-side-padding: 4.166666667%;
$filter-menu-width: 200px;
// Tainacan imports
@import "../admin/scss/_tables.scss";
@import "../admin/scss/_selects.scss";
@import "../admin/scss/_dropdown-and-autocomplete.scss";
@import "../admin/scss/_tooltips.scss";
@import "../admin/scss/_tainacan-form.scss";
.theme-items-list {
position: relative;
@ -83,11 +59,8 @@ export default {
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;
@ -123,202 +96,25 @@ export default {
line-height: 20px !important;
font-size: 14px !important;
}
#collection-search-button {
height: 25px !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;
}
.input, .textarea {
font-size: 14px;
border: none;
border-radius: 1px !important;
box-shadow: none !important;
&:focus, &:active {
box-shadow: none !important;
background-color: white;
border: 1px solid $tainacan-input-background !important;
}
}
.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 {
a {
color: $tainacan-input-color !important;
}
.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);
}
}
}
.dropdown-menu {
display: block;
}
.b-checkbox.checkbox {
@ -487,10 +283,13 @@ export default {
.filters-menu {
height: auto;
min-width: $filter-menu-width;
background-color: unset;
border-right: 1px solid $tainacan-input-background;
}
#items-list-area {
width: 100%;
overflow-y: unset;
}
}

View File

@ -324,10 +324,11 @@ 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();
}
$item_arr['filter_type_object'] = $item->get_filter_type_object() ? $item->get_filter_type_object()->_toArray() : $item->get_filter_type_object();
return $item_arr;
}

View File

@ -225,7 +225,8 @@ class REST_Items_Controller extends REST_Controller {
if ( isset($request['view_mode']) ) {
// TODO: Check if requested view mode is really enabled for current collection
$view_mode = \Tainacan\Theme_Helper::get_instance()->get_view_mode($request['view_mode']);
$view_mode = \Tainacan\Theme_Helper::get_instance();
$view_mode = $view_mode->get_view_mode($request['view_mode']);
if ($view_mode && $view_mode['type'] == 'template' && isset($view_mode['template']) && file_exists($view_mode['template'])) {
$return_template = true;
@ -237,11 +238,14 @@ class REST_Items_Controller extends REST_Controller {
ob_start();
global $wp_query;
global $wp_query, $view_mode_displayed_fields;
$wp_query = $items;
$displayed_metadata = array_map(function($el) { return (int) $el; }, $request['fetch_only']['meta']);
$view_mode_displayed_fields = $request['fetch_only'];
$view_mode_displayed_fields['meta'] = $displayed_metadata;
include $view_mode['template'];
$response = ob_get_clean();
} else {

View File

@ -268,6 +268,16 @@ class Capabilities {
]
],
];
public static $dependencies = [
"tainacan-items" => [
'edit_posts' => 'upload_files',
"edit_private_posts" => 'upload_files',
"edit_published_posts" => 'upload_files',
"edit_others_posts" => 'upload_files'
]
];
private static $instance = null;
public static function get_instance()
@ -349,6 +359,43 @@ class Capabilities {
return $translations;
}
protected function check_dependencies($role, $post_type, $cap, $add = true) {
if(
array_key_exists($post_type, self::$dependencies) &&
array_key_exists($cap, self::$dependencies[$post_type])
) {
$added = false;
if(! $role->has_cap(self::$dependencies[$post_type][$cap]) && $add) {
$role->add_cap(self::$dependencies[$post_type][$cap]);
$added = true;
}
if($role instanceof \WP_User && $add) { //moderator
$append_caps = get_user_meta($role->ID, '.tainacan-dependecies-caps', true);
if(! is_array($append_caps)) $append_caps = [];
if(
(! array_key_exists(self::$dependencies[$post_type][$cap], $append_caps) && $added ) || // we never added and need to add
(
array_key_exists(self::$dependencies[$post_type][$cap], $append_caps) &&
$append_caps[self::$dependencies[$post_type][$cap]] === false &&
$added
) // we added but before is not need to add
) {
$append_caps[self::$dependencies[$post_type][$cap]] = 0;
}
else { // we to not added this cap
$append_caps[self::$dependencies[$post_type][$cap]] = false;
}
if($append_caps[self::$dependencies[$post_type][$cap]] !== false) {
$append_caps[self::$dependencies[$post_type][$cap]]++; // add 1 to each collection he is a moderator
update_user_meta($role->ID, '.tainacan-dependecies-caps', $append_caps);
}
}
return self::$dependencies[$post_type][$cap];
}
return false;
}
/**
* Update post_type caps using WordPress basic roles and register tainacan roles
*/
@ -368,6 +415,7 @@ class Capabilities {
foreach ($caps as $cap) {
$role->add_cap($entity_cap->$cap);
$this->check_dependencies($role, $post_type, $cap);
}
$tainacan_roles = $this->get_tainacan_roles();
@ -384,6 +432,7 @@ class Capabilities {
foreach ($caps as $cap) {
$tainacan_role->add_cap($entity_cap->$cap);
$this->check_dependencies($tainacan_role, $post_type, $cap);
}
}
@ -414,6 +463,7 @@ class Capabilities {
foreach ($caps as $cap) {
$role->add_cap($collection_items_caps->$cap);
$this->check_dependencies($role, 'tainacan-items', $cap);
}
}
@ -464,6 +514,17 @@ class Capabilities {
$caps = $defaults_caps['tainacan-items']['editor'];
foreach ($caps as $cap) {
$user->remove_cap($collection_items_caps->$cap);
$dep_cap = $this->check_dependencies($user, 'tainacan-items', $cap, false);
if($dep_cap !== false) {
$appended_caps = get_user_meta($user->ID, '.tainacan-dependecies-caps', true);
if(array_key_exists($dep_cap, $appended_caps) && $appended_caps[$dep_cap] !== false && $appended_caps[$dep_cap] > 0) {
$appended_caps[$dep_cap]--;
update_user_meta($user->ID, '.tainacan-dependecies-caps', $appended_caps);
if($appended_caps == 0) { // they are not a moderator of a collection, remove cap at all
$user->remove_cap($cap);
}
}
}
}
}
}
@ -487,6 +548,7 @@ class Capabilities {
$caps = $defaults_caps['tainacan-items']['editor'];
foreach ($caps as $cap) {
$user->add_cap($collection_items_caps->$cap);
$this->check_dependencies($user, 'tainacan-items', $cap);
}
}
}

View File

@ -454,6 +454,73 @@ class Collection extends Entity {
return $Tainacan_Fields->fetch_by_collection( $this, [], 'OBJECT' );
}
/**
* Get the two core fields of the collection (title and description)
*
* @return array[\Tainacan\Entities\Field]
*/
function get_core_fields() {
$repo = \Tainacan\Repositories\Fields::get_instance();
return $repo->fetch_by_collection($this, [
'meta_query' => [
[
'key' => 'field_type',
'value' => ['Tainacan\Field_Types\Core_Title', 'Tainacan\Field_Types\Core_Description'],
'compare' => 'IN'
]
]
], 'OBJECT');
}
/**
* Get the Core Title Field for this collection
*
* @return \Tainacan\Entities\Field The Core Title Field
*/
function get_core_title_field() {
$repo = \Tainacan\Repositories\Fields::get_instance();
$results = $repo->fetch_by_collection($this, [
'meta_query' => [
[
'key' => 'field_type',
'value' => 'Tainacan\Field_Types\Core_Title',
]
],
'posts_per_page' => 1
], 'OBJECT');
if (is_array($results) && sizeof($results) == 1 && $results[0] instanceof \Tainacan\Entities\Field) {
return $results[0];
}
return false;
}
/**
* Get the Core Description Field for this collection
*
* @return \Tainacan\Entities\Field The Core Description Field
*/
function get_core_description_field() {
$repo = \Tainacan\Repositories\Fields::get_instance();
$results = $repo->fetch_by_collection($this, [
'meta_query' => [
[
'key' => 'field_type',
'value' => 'Tainacan\Field_Types\Core_Description',
]
],
'posts_per_page' => 1
], 'OBJECT');
if (is_array($results) && sizeof($results) == 1 && $results[0] instanceof \Tainacan\Entities\Field) {
return $results[0];
}
return false;
}
/**
* Set the collection name
*

View File

@ -30,7 +30,7 @@ class Item_Metadata_Entity extends Entity {
* @param Field $field Field Entity
* @param int $meta_id ID for a specific meta row
*/
function __construct(Item $item, Field $field, $meta_id = null, $parent_meta_id = null) {
function __construct(Item $item = null, Field $field = null, $meta_id = null, $parent_meta_id = null) {
$this->set_item($item);
$this->set_field($field);

View File

@ -451,29 +451,40 @@ class Item extends Entity {
*
* Each metadata is a label with the field name and the value.
*
* If an ID, a slug or a Tainacan\Entities\Field object is passed, it returns only one metadata, otherwise
* If an ID, a slug or a Tainacan\Entities\Field object is passed in the 'metadata' argument, it returns only one metadata, otherwise
* it returns all metadata
*
* @param int|string|Tainacan\Entities\Field $field Field object, ID or slug to retrieve only one field. empty returns all fields
* @param array|string $args {
* Optional. Array or string of arguments.
*
* @type bool $hide_empty Wether to hide or not fields the item has no value to
* Default: true
* @type string $before_title String to be added before each metadata title
* Default '<h3>'
* @type string $after_title String to be added after each metadata title
* Default '</h3>'
* @type string $before_value String to be added before each metadata value
* Default '<p>'
* @type string $after_value String to be added after each metadata value
* Default '</p>'
* }
* @param array|string $args {
* Optional. Array or string of arguments.
*
* @type mixed $metadata Field object, ID or slug to retrieve only one field. empty returns all metadata
*
* @type array $metadata__in Array of metadata IDs or Slugs to be retrieved. Default none
*
* @type array $metadata__not_in Array of metadata IDs (slugs not accepted) to excluded. Default none
*
* @type bool $exclude_title Exclude the Core Title Metadata from result. Default false
*
* @type bool $exclude_description Exclude the Core Description Metadata from result. Default false
*
* @type bool $exclude_core Exclude Core Metadata (title and description) from result. Default false
*
* @type bool $hide_empty Wether to hide or not fields the item has no value to
* Default: true
* @type string $before_title String to be added before each metadata title
* Default '<h3>'
* @type string $after_title String to be added after each metadata title
* Default '</h3>'
* @type string $before_value String to be added before each metadata value
* Default '<p>'
* @type string $after_value String to be added after each metadata value
* Default '</p>'
* }
*
* @return string The HTML output
* @throws \Exception
*/
public function get_metadata_as_html($field = null, $args = array()) {
public function get_metadata_as_html($args = array()) {
$Tainacan_Item_Metadata = \Tainacan\Repositories\Item_Metadata::get_instance();
$Tainacan_Fields = \Tainacan\Repositories\Fields::get_instance();
@ -481,6 +492,12 @@ class Item extends Entity {
$return = '';
$defaults = array(
'metadata' => null,
'metadata__in' => null,
'metadata__not_in' => null,
'exclude_title' => false,
'exclude_description' => false,
'exclude_core' => false,
'hide_empty' => true,
'before_title' => '<h3>',
'after_title' => '</h3>',
@ -489,7 +506,7 @@ class Item extends Entity {
);
$args = wp_parse_args($args, $defaults);
if (!is_null($field)) {
if (!is_null($args['metadata'])) {
$field_object = null;
@ -505,6 +522,16 @@ class Item extends Entity {
}
if ( $field_object instanceof \Tainacan\Entities\Field ) {
if ( is_array($args['metadata__not_in'])
&& (
in_array($field_object->get_slug(), $args['metadata__not_in']) ||
in_array($field_object->get_id(), $args['metadata__not_in'])
)
) {
return $return;
}
$item_meta = new \Tainacan\Entities\Item_Metadata_Entity($this, $field_object);
if ($item_meta->has_value() || !$args['hide_empty']) {
$return .= $args['before_title'] . $field_object->get_name() . $args['after_title'];
@ -516,10 +543,57 @@ class Item extends Entity {
return $return;
}
$query_args = [];
$post__in = [];
$post__not_in = [];
$post__name_in = [];
if (is_array($args['metadata__in'])) {
foreach ($args['metadata__in'] as $meta) {
if (is_string($meta)) {
$post__name_in[] = $meta;
} elseif (is_integer($meta)) {
$post__in[] = $meta;
}
}
}
if (is_array($args['metadata__not_in'])) {
foreach ($args['metadata__not_in'] as $meta) {
if (is_integer($meta)) {
$post__not_in[] = $meta;
}
}
}
if (sizeof($post__in) > 0) {
$query_args['post__in'] = $post__in;
}
if (sizeof($post__not_in) > 0) {
$query_args['post__not_in'] = $post__not_in;
}
if (sizeof($post__name_in) > 0) {
$query_args['post__name_in'] = $post__name_in;
}
$fields = $this->get_fields();
$fields = $this->get_fields($query_args);
foreach ( $fields as $item_meta ) {
$fto = $item_meta->get_field()->get_field_type_object();
if ( $fto->get_core() ) {
if ( $args['exclude_core'] ) {
continue;
} elseif ( $args['exclude_title'] && $fto->get_related_mapped_prop() == 'title' ) {
continue;
} elseif ( $args['exclude_description'] && $fto->get_related_mapped_prop() == 'description' ) {
continue;
}
}
if ($item_meta->has_value() || !$args['hide_empty']) {
$return .= $args['before_title'] . $item_meta->get_field()->get_name() . $args['after_title'];
$return .= $args['before_value'] . $item_meta->get_value_as_html() . $args['after_value'];

View File

@ -48,7 +48,10 @@ class Core_Description extends Field_Type {
*
* @param TainacanEntitiesItem_Metadata_Entity $item_metadata
* @return bool Valid or not
*/
*
* Quarantine - Core metadata should be validated as any other metadata
* and item title is no longer mandatory
public function validate(\Tainacan\Entities\Item_Metadata_Entity $item_metadata) {
$item = $item_metadata->get_item();
@ -61,6 +64,8 @@ class Core_Description extends Field_Type {
return $item->validate_prop('description');
}
*/
public function validate_options( Field $field ) {

View File

@ -49,7 +49,10 @@ class Core_Title extends Field_Type {
*
* @param TainacanEntitiesItem_Metadata_Entity $item_metadata
* @return bool Valid or not
*/
*
* Quarantine - Core metadata should be validated as any other metadata
* and item title is no longer mandatory
public function validate(\Tainacan\Entities\Item_Metadata_Entity $item_metadata) {
$item = $item_metadata->get_item();
@ -62,6 +65,7 @@ class Core_Title extends Field_Type {
return $item->validate_prop('title');
}
*/
public function validate_options( Field $field ) {

View File

@ -5,10 +5,10 @@
:type="fieldTypeMessage">
<span
class="collapse-handle"
@click="$emit('changeCollapse', !isCollapsed)">
@click="$emit('changeCollapse', fieldTypeMessage != 'is-danger' ? !isCollapsed : true)">
<b-icon
type="is-secondary"
:icon="isCollapsed ? 'menu-down' : 'menu-right'" />
:icon="isCollapsed || fieldTypeMessage == 'is-danger' ? 'menu-down' : 'menu-right'" />
<label class="label">{{ field.field.name }}</label>
<span
v-if="field.field.required == 'yes'"
@ -20,7 +20,7 @@
:message="field.field.description"/>
</span>
<div
v-show="isCollapsed"
v-show="isCollapsed || fieldTypeMessage == 'is-danger'"
v-if="isTextInputComponent( field.field.field_type_object.component )">
<component
:id="field.field.field_type_object.component + '-' + field.field.slug"
@ -87,19 +87,19 @@
let msg = '';
let errors = eventBus.getErrors(this.field.field.id);
if ( errors) {
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';
}
}
} else {
this.setFieldTypeMessage('');
}
return msg;
}
},
@ -133,8 +133,6 @@
},
setFieldTypeMessage( message ){
this.fieldTypeMessage = message;
if (message != '')
this.$emit('changeCollapse', true);
}
}
}

View File

@ -69,7 +69,7 @@
let promise = null;
this.isLoading = true;
axios.get('/collection/'+ this.collection +'/fields/' + this.field + '?context=edit')
axios.get('/collection/'+ this.collection +'/fields/' + this.field)
.then( res => {
let field = res.data;
promise = this.getValuesCategory( field.field_type_options.taxonomy_id );

View File

@ -4,7 +4,7 @@
<div v-if="type === 'date'">
<b-datepicker
:placeholder="$i18n.get('label_selectbox_init')"
:class="{'has-content': date_init !== undefined && date_init !== ''}"
:class="{'has-content': date_init != undefined && date_init != ''}"
v-model="date_init"
size="is-small"
@focus="isTouched = true"
@ -12,7 +12,7 @@
icon="calendar-today"/>
<b-datepicker
:placeholder="$i18n.get('label_selectbox_init')"
:class="{'has-content': date_end !== undefined && date_end !== ''}"
:class="{'has-content': date_end != undefined && date_end != ''}"
v-model="date_end"
size="is-small"
@input="validate_values()"
@ -25,7 +25,7 @@
class="columns"
v-else>
<b-input
:class="{'has-content': value_init !== undefined && value_init !== ''}"
:class="{'has-content': value_init != undefined && value_init != ''}"
size="is-small"
type="number"
step="any"
@ -33,7 +33,7 @@
class="column"
v-model="value_init"/>
<b-input
:class="{'has-content': value_end !== undefined && value_end !== ''}"
:class="{'has-content': value_end != undefined && value_end != ''}"
size="is-small"
type="number"
step="any"

View File

@ -266,6 +266,7 @@ class Collections extends Repository {
$Tainacan_Fields->register_core_fields( $new_collection );
$collection->register_collection_item_post_type();
flush_rewrite_rules(false); // needed to activate items post type archive url
$this->update_moderators( $new_collection );
return $new_collection;

View File

@ -318,8 +318,8 @@ class Fields extends Repository {
}
/**
* fetch field by collection, searches all field available
*
* fetch field by collection, considering inheritance
*
* @param Entities\Collection $collection
* @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)

View File

@ -36,7 +36,7 @@ class Items extends Repository {
'type' => 'string',
'description' => __( 'Title of the item', 'tainacan' ),
'on_error' => __( 'The title should be a text value and not empty', 'tainacan' ),
'validation' => v::stringType()->notEmpty(),
//'validation' => v::stringType()->notEmpty(),
],
'status' => [
'map' => 'post_status',

View File

@ -5,6 +5,7 @@ namespace Tainacan\Repositories;
use Tainacan\Entities;
use Tainacan\Entities\Entity;
use Tainacan;
use Tainacan\Repositories;
use \Respect\Validation\Validator as v;
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
@ -427,6 +428,9 @@ abstract class Repository {
*/
public static function get_entity_by_post_type( $post_type, $post = 0 ) {
$prefix = substr( $post_type, 0, strlen( Entities\Collection::$db_identifier_prefix ) );
$item_metadata = Repositories\Item_Metadata::get_instance();
$item_metadata_entity = new $item_metadata->entities_type(null, null);
$item_metadata_post_type = $item_metadata_entity::get_post_type();
// Is it a collection Item?
if ( $prefix == Entities\Collection::$db_identifier_prefix ) {
@ -436,15 +440,15 @@ abstract class Repository {
} else {
throw new \Exception( 'Collection object not found for this post' );
}
} elseif ( $post_type === \Tainacan\Repositories\Item_Metadata::get_instance()->entities_type::get_post_type() ) {
} elseif ( $post_type === $item_metadata_post_type ) {
return new Entities\Item_Metadata_Entity( null, null );
} else {
$Tainacan_Collections = \Tainacan\Repositories\Collections::get_instance();
$Tainacan_Filters = \Tainacan\Repositories\Filters::get_instance();
$Tainacan_Logs = \Tainacan\Repositories\Logs::get_instance();
$Tainacan_Fields = \Tainacan\Repositories\Fields::get_instance();
$Tainacan_Taxonomies = \Tainacan\Repositories\Taxonomies::get_instance();
$Tainacan_Terms = \Tainacan\Repositories\Terms::get_instance();
$Tainacan_Collections = Repositories\Collections::get_instance();
$Tainacan_Filters = Repositories\Filters::get_instance();
$Tainacan_Logs = Repositories\Logs::get_instance();
$Tainacan_Fields = Repositories\Fields::get_instance();
$Tainacan_Taxonomies = Repositories\Taxonomies::get_instance();
$Tainacan_Terms = Repositories\Terms::get_instance();
$tnc_globals = [
$Tainacan_Collections,
@ -455,7 +459,9 @@ abstract class Repository {
$Tainacan_Logs
];
foreach ( $tnc_globals as $tnc_repository ) {
$entity_post_type = $tnc_repository->entities_type::get_post_type();
$tnc_entity = new $tnc_repository->entities_type();
$entity_post_type = $tnc_entity::get_post_type();
if ( $entity_post_type == $post_type ) {
return new $tnc_repository->entities_type( $post );
}
@ -500,7 +506,9 @@ abstract class Repository {
$Tainacan_Logs
];
foreach ( $tnc_globals as $tnc_repository ) {
$entity_post_type = $tnc_repository->entities_type::get_post_type();
$tnc_entity = new $tnc_repository->entities_type();
$entity_post_type = $tnc_entity::get_post_type();
if ( $entity_post_type == $post_type ) {
return $tnc_repository;
}
@ -510,6 +518,31 @@ abstract class Repository {
return false;
}
/**
* Fetch one Entity based on query args.
*
* Note: Does not work with Item_Metadata Repository
*
* @param array $args Query Args as expected by fetch
*
* @return false|\Tainacan\Entities The entity or false if none was found
*/
public function fetch_one($args) {
if ($this->get_name() == 'Item_Metadata') {
return false;
}
$args['posts_per_page'] = 1;
$results = $this->fetch($args, 'OBJECT');
if (is_array($results) && sizeof($results) > 0 && $results[0] instanceof \Tainacan\Entities\Entity) {
return $results[0];
}
return false;
}
/**
* @param $object
*

View File

@ -34,7 +34,8 @@ class DevInterface {
$repositories = [$Tainacan_Collections, $Tainacan_Filters, $Tainacan_Logs, $Tainacan_Fields, $Tainacan_Taxonomies];
foreach ($repositories as $repo) {
$cpt = $repo->entities_type::get_post_type();
$tnc_entity = new $repo->entities_type();
$cpt = $tnc_entity::get_post_type();
$this->repositories[$cpt] = $repo;
}

View File

@ -5,7 +5,11 @@ use Tainacan;
class CSV extends Importer {
public function __construct() {
protected $manual_mapping = true;
protected $manual_collection = true;
public function __construct() {
parent::__construct();
$this->set_default_options([
@ -17,7 +21,7 @@ class CSV extends Importer {
/**
* @inheritdoc
*/
public function get_fields(){
public function get_source_fields(){
$file = new \SplFileObject( $this->tmp_file, 'r' );
$file->seek(0 );
return $file->fgetcsv( $this->get_option('delimiter') );
@ -27,9 +31,9 @@ class CSV extends Importer {
/**
* @inheritdoc
*/
public function process_item( $index ){
public function process_item( $index, $collection_index ){
$processedItem = [];
$headers = $this->get_fields();
$headers = $this->get_source_fields();
// search the index in the file and get values
$file = new \SplFileObject( $this->tmp_file, 'r' );
@ -50,6 +54,8 @@ class CSV extends Importer {
foreach ($headers as $index => $header) {
$processedItem[ $header ] = $values[ $index ];
}
$this->set_progress_current($index+1);
return $processedItem;
}
@ -57,7 +63,7 @@ class CSV extends Importer {
/**
* @inheritdoc
*/
public function get_total_items_from_source(){
public function get_progress_total_from_source(){
$file = new \SplFileObject( $this->tmp_file, 'r' );
$file->seek(PHP_INT_MAX);
// -1 removing header

View File

@ -5,86 +5,128 @@ use Tainacan\Entities;
abstract class Importer {
private $id;
private $processed_items = [];
/**
* indicates wether this importer will create all the fields collection and set the mapping
* without user interaction
*
* if set to true, user will have the ability to choose to create a new collection upon importing.
*
* The importer will have to implement the create_fields_and_mapping() method.
*
* @var bool
*/
protected $import_structure_and_mapping = false;
/**
* The collection the items are going to be imported to.
* The ID for this importer session
*
* When creating a new importer session via API, an id is returned and used to access this
* importer instance in the SESSION array
*
* @var \Tainacan\Entities\Collection
* @var identifier
*/
public $collection;
/**
* The mapping from the source metadata structure to the Field Ids of the destination collection
*
* The format is an array where the keys are the field IDs of the destination collection and the
* values are the identifier from the source. This coulb be an ID or a string or whatever the importer finds appropriate to http_persistent_handles_clean
*
* @var array
*/
public $mapping;
private $repository_mapping;
private $id;
/**
* The path to the temporary file created when user uploads a file
* @var string
*/
public $tmp_file;
protected $tmp_file;
/**
* The total number of items to be imported.
* @var int
*/
protected $total_items;
/**
* THe number of items to be processes in each step
* @var int
*/
private $items_per_step = 100;
/**
* The index of the item to start the import in the next step.
* Wether Tainacan must present the user with an interface to manually map
* the metadata from the source to the target collection.
*
* (items are imported in a series of steps, via ajax, to avoid timeout)
* @var int
* If set to true in the child class, it must implement the method
* get_source_fields() to return the field found in the source.
*
* Note that this will only work when importing items to one single collection.
* @var bool
*/
private $start = 0;
private $inside_step_pointer = 0;
protected $manual_mapping = false;
/**
* Wether Tainacan will let the user choose a destination collection.
*
* If set to true, the API endpoints will handle Collection creation and will assign it to
* the importer object using add_collection() method.
*
* Otherwise, the child importer class must create the collections and add them to the collections property also
* using add_collection()
*
* @var bool
*/
protected $manual_collection = true;
/**
* The log with everything that happened during the import process. It generates a report afterwards
* The total number of iterations to be imported.
*
* if not possible to calculate, inform 0 (zero) and no progress bar will be displayed.
*
* @var int
*/
protected $progress_total;
protected $progress_current;
/**
* This array holds the structure that the default step 'process_collections' will handle.
*
* Its an array of the target collections, with their IDs, the total number of items to be imported and the mapping array
* from the source structure to the ID of the metadata fields in tainacan
*
* The format of the map is an array where the keys are the metadata IDs of the destination collection and the
* values are the identifier from the source. This could be an ID or a string or whatever the importer finds appropriate to handle
*
* Example of the structure of this propery for one collection:
* 0 => [
* 'id' => 12,
* 'map' => [
* 30 => 'column1'
* 31 => 'column2'
* ],
* 'total_items' => 1234
* ],
*
* use add_collection() and remove_collection() to interact with thiis array.
*
*
* @var array
*/
protected $collections = [];
/**
* Stores the options for the importer. Each importer might use this property to save
* their own specific option
* @var array
*/
public $logs = [];
private $options = [];
private $default_options = [];
/**
* Stores the default options for the importer options
* @var array
*/
protected $default_options = [];
private $accpets = [
'file' => true,
'url' => false,
];
private $is_repository = false;
private $steps = [];
/**
* Declares what are the steps the importer will run, in the right order.
*
* By default, there is only one step, and the callback is the process_collections method
* that process items for the collections in the collections array.
*
* Child classes may declare as many steps as they want and can keep this default step to use
* this method for import the items. But it is optional.
*
* @var array
*/
protected $steps = [
[
'name' => 'Import Items',
'callback' => 'process_collections'
]
];
private $current_step = 0;
private $in_step_count = 0;
private $current_collection = 0;
private $current_collection_item = 0;
private $url = '';
@ -96,7 +138,10 @@ abstract class Importer {
$this->id = uniqid();
$_SESSION['tainacan_importer'][$this->get_id()] = $this;
}
/////////////////////
// Getters and setters
/**
* @return string
*/
@ -133,82 +178,125 @@ abstract class Importer {
return false;
}
/**
* @return array Mapping
*/
public function get_mapping(){
return $this->mapping;
public function get_current_step() {
return $this->current_step;
}
public function set_current_step($value) {
$this->current_step = $value;
}
public function get_in_step_count() {
return $this->in_step_count;
}
public function set_in_step_count($value) {
$this->in_step_count = $value;
}
public function get_current_collection() {
return $this->current_collection;
}
public function set_current_collection($value) {
$this->current_collection = $value;
}
public function get_current_collection_item() {
return $this->current_collection_item;
}
public function set_current_collection_item($value) {
$this->current_collection_item = $value;
}
public function get_tmp_file(){
return $this->tmp_file;
}
/**
* @return array Array with ids inserted in Tainacan
*/
public function get_processed_items(){
return $this->processed_items;
public function set_tmp_file($filepath){
$this->tmp_file = $filepath;
}
/**
* @return array the last index from source
public function get_progress_current() {
return $this->progress_current;
}
public function set_progress_current($value) {
$this->progress_current = $value;
}
public function get_collections() {
return $this->collections;
}
public function set_collections($value) {
$this->collections = $value;
}
/**
* Gets the options for this importer, including default values for options
* that were not set yet.
* @return array Importer options
*/
public function get_logs(){
return $this->logs;
public function get_options() {
return array_merge($this->default_options, $this->options);
}
/**
* @param Tainacan\Entities\Collection $collection
*/
public function set_collection( Entities\Collection $collection ){
$this->collection = $collection;
/**
* Set the options array
* @param array $options
*/
public function set_options($options) {
$this->options = $options;
}
/**
* Set the default options values.
*
* Must be called from the __construct method of the child importer class to set default values.
*
* @param array $options
*/
protected function set_default_options($options) {
$this->default_options = $options;
}
public function set_steps($steps) {
$this->steps = $steps;
}
/**
* save an associative array with tainacan field id as index and field from source as value
public function get_steps() {
return $this->steps;
}
/**
* return the total progress number to calculate progress
*
* @param array $mapping Mapping importer-fields
* @return int Total of items
*/
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;
}
/**
* set how many items should be processes in each step
*
* @param $size The total of items
*/
public function set_items_per_step( $size ){
$this->items_per_step = $size;
}
/**
* @param int $start the first index to init the process
*/
public function set_start( $start ){
$this->start = $start;
}
public function get_progress_total() {
if ( !isset( $this->progress_total ) ) {
if ( method_exists($this, 'get_progress_total_from_source') ) {
$this->progress_total = $this->get_progress_total_from_source();
} else {
$this->progress_total = 0;
}
}
return $this->progress_total;
}
////////////////////////////////////
// Utilities
/**
* @param $file File to be managed by importer
* @return bool
*/
public function set_file( $file ){
public function add_file( $file ){
$new_file = $this->upload_file( $file );
if ( is_numeric( $new_file ) ) {
$this->tmp_file = get_attached_file( $new_file );
@ -216,22 +304,8 @@ abstract class Importer {
return false;
}
}
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
*
@ -241,6 +315,22 @@ abstract class Importer {
public function add_log($type, $message ){
$this->logs[] = [ 'type' => $type, 'message' => $message ];
}
public function add_collection(array $collection) {
if (isset($collection['id'])) {
$this->remove_collection($collection['id']);
$this->collections[] = $collection;
}
}
public function remove_collection($col_id) {
foreach ($this->get_collections() as $index => $col) {
if ($col['id'] == $col_id) {
unset($this->collections[$index]);
break;
}
}
}
/**
* internal function to upload the file
@ -264,59 +354,13 @@ abstract class Importer {
*/
public function fetch_from_remote( $url ){
$tmp = wp_remote_get( $url );
if( isset( $tmp['body'] ) ){
if( !is_wp_error($tmp) && isset( $tmp['body'] ) ){
$file = fopen( $this->get_id().'.txt', 'w' );
fwrite( $file, $tmp['body'] );
fclose( $file );
return $this->set_file( $this->get_id().'.txt' );
return $this->add_file( $this->get_id().'.txt' );
}
}
/**
* get the fields of file/url to allow mapping
* should return an array
*
* @return array $fields_source the fields from the source
*/
abstract public function get_fields();
/**
* get values for a single item
*
* @param $index
* @return array with field_source's as the index and values for the
* item
*
* Ex: [ 'Field1' => 'value1', 'Field2' => [ 'value2','value3' ]
*/
abstract public function process_item( $index );
/**
* return the all items found
*
* @return int Total of items
*/
public function get_total_items() {
if ( !isset( $this->total_items ) ) {
$this->total_items = $this->get_total_items_from_source();
}
return $this->total_items;
}
/**
* Method implemented by the child importer class to return the number of items to be imported
* @return int
*/
abstract public function get_total_items_from_source();
/**
* Gets the options for this importer, including default values for options
* that were not set yet.
* @return array Importer options
*/
public function get_options() {
return array_merge($this->default_options, $this->options);
}
/**
* Gets one option from the options array.
@ -331,25 +375,6 @@ abstract class Importer {
return isset($options[$key]) ? $options[$key] : '';
}
/**
* Set the default options values.
*
* Must be called from the __construct method of the child importer class to set default values.
*
* @param array $options
*/
protected function set_default_options($options) {
$this->default_options = $options;
}
/**
* Set the options array
* @param array $options
*/
public function set_options($options) {
$this->options = $options;
}
/**
* Adds a new method accepeted by the importer
*
@ -366,38 +391,6 @@ 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
*/
public function set_repository()
{
$this->is_repository = true;
}
public function set_steps($steps)
{
$this->steps =$steps;
}
public function is_finished()
{
if($this->current_step >= count($this->steps))
{
return true;
}
return false;
}
/**
* Removes method accepeted by the importer
*
@ -413,60 +406,164 @@ abstract class Importer {
}
return false;
}
public function is_finished()
{
if($this->current_step >= count($this->steps))
{
return true;
}
return false;
}
///////////////////////////////
// Abstract methods
/**
* get the fields of file/url to allow mapping
* should return an array
*
* Used when $manual_mapping is set to true, to build the mapping interface
*
* @return array $fields_source the fields from the source
*/
abstract public function get_source_fields();
/**
* get values for a single item
*
* @param $index
* @return array with field_source's as the index and values for the
* item
*
* Ex: [ 'Field1' => 'value1', 'Field2' => [ 'value2','value3' ]
*/
abstract public function process_item( $index, $collection_id );
/**
* Method implemented by the child importer class to return the total number of interations the importer must run
*
* Used to build the progress bar
*
* @return int
*/
abstract public function get_progress_total_from_source();
////////////////////////////////////////
// Core methods
/**
* process a limited size of items
* process an item from the collections queue
*
* @param int $start the index of the item to start processing from
*/
public function process( $start ){
public function process_collections() {
$end = $start + $this->items_per_step;
while ( $start < $end && count( $this->get_processed_items() ) < $this->get_total_items() ) {
$processed_item = $this->process_item( $start );
if( $processed_item) {
$this->insert( $start, $processed_item );
} else {
$this->add_log('error', 'failed on item '.$start );
break;
}
$start++;
}
$current_collection = $this->get_current_collection();
$current_collection_item = $this->get_current_collection_item();
$this->set_start($start);
$processed_item = $this->process_item( $current_collection_item, $current_collection );
if( $processed_item) {
$this->insert( $processed_item, $current_collection );
} else {
$this->add_log('error', 'failed on item '. $start );
}
return $this->next_item();
}
protected function next_item() {
$current_collection = $this->get_current_collection();
$current_collection_item = $this->get_current_collection_item();
$collections = $this->get_collections();
$collection = $collections[$current_collection];
$current_collection_item ++;
$this->set_current_collection_item($current_collection_item);
if ($current_collection_item >= $collection['total_items']) {
return $this->next_collection();
}
return $current_collection_item;
}
protected function next_collection() {
$current_collection = $this->get_current_collection();
$collections = $this->get_collections();
$this->set_current_collection_item(0);
$current_collection ++;
if (isset($collections[$current_collection])) {
$this->set_current_collection($current_collection);
return $current_collection;
}
return false;
}
protected function next_step() {
$current_step = $this->get_current_step();
$steps = $this->get_steps();
$current_step ++;
$this->set_current_step($current_step);
if (isset($steps[$current_step])) {
return $current_step;
}
return false;
}
/**
* insert processed item from source to Tainacan
*
* @param int $index the source id unique for the item
* @param array $processed_item Associative array with field source's as index with
* its value or values
* @return Tainacan\Entities\Item Item inserted
*/
public function insert( $index, $processed_item ){
$Tainacan_Fields = \Tainacan\Repositories\Fields::get_instance();
public function insert( $processed_item, $collection_index ) {
$collections = $this->get_collections();
$collection_definition = isset($collections[$collection_index]) ? $collections[$collection_index] : false;
if ( !$collection_definition || !is_array($collection_definition) || !isset($collection_definition['id']) || !isset($collection_definition['map']) ) {
$this->add_log('error','Collection misconfigured');
return false;
}
$collection = \Tainacan\Repositories\Collections::get_instance()->fetch($collection_definition['id']);
$Tainacan_Fields = \Tainacan\Repositories\Fields::get_instance();
$Tainacan_Item_Metadata = \Tainacan\Repositories\Item_Metadata::get_instance();
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
$isUpdate = ( is_array( $this->processed_items ) && isset( $this->processed_items[ $index ] ) )
? $this->processed_items[ $index ] : 0;
$item = new Entities\Item( $isUpdate );
$item = new Entities\Item();
$itemMetadataArray = [];
if( !isset( $this->mapping ) ){
$this->add_log('error','Mapping is not set');
return false;
}
if( is_array( $processed_item ) ){
foreach ( $processed_item as $field_source => $values ){
$tainacan_field_id = array_search( $field_source, $this->mapping );
$tainacan_field_id = array_search( $field_source, $collection_definition['map'] );
$field = $Tainacan_Fields->fetch( $tainacan_field_id );
if( $field instanceof Entities\Field ){
$singleItemMetadata = new Entities\Item_Metadata_Entity( $item, $field);
$singleItemMetadata = new Entities\Item_Metadata_Entity( $item, $field); // *empty item will be replaced by inserted in the next foreach
$singleItemMetadata->set_value( $values );
$itemMetadataArray[] = $singleItemMetadata;
}
@ -474,8 +571,8 @@ abstract class Importer {
}
}
if( !empty( $itemMetadataArray ) && $this->collection instanceof Entities\Collection ){
$item->set_collection( $this->collection );
if( !empty( $itemMetadataArray ) && $collection instanceof Entities\Collection ){
$item->set_collection( $collection );
if( $item->validate() ){
$insertedItem = $Tainacan_Items->insert( $item );
@ -485,29 +582,27 @@ abstract class Importer {
}
foreach ( $itemMetadataArray as $itemMetadata ) {
$itemMetadata->set_item( $insertedItem );
$itemMetadata->set_item( $insertedItem ); // *I told you
if( $itemMetadata->validate() ){
$result = $Tainacan_Item_Metadata->insert( $itemMetadata );
} else {
$this->add_log( 'error', 'Item ' . $index . ' on field '. $itemMetadata->get_field()->get_name()
$this->add_log( 'error', 'Item ' . $insertedItem->get_id() . ' on field '. $itemMetadata->get_field()->get_name()
.' has error ' . $itemMetadata->get_errors() );
continue;
}
if( $result ){
$values = ( is_array( $itemMetadata->get_value() ) ) ? implode( PHP_EOL, $itemMetadata->get_value() ) : $itemMetadata->get_value();
$this->add_log( 'success', 'Item ' . $index .
$this->add_log( 'success', 'Item ' . $insertedItem->get_id() .
' has inserted the values: ' . $values . ' on field: ' . $itemMetadata->get_field()->get_name() );
} else {
$this->add_log( 'error', 'Item ' . $index . ' has an error' );
$this->add_log( 'error', 'Item ' . $insertedItem->get_id() . ' has an error' );
}
}
$insertedItem->set_status('publish' );
// inserted the id on processed item with its index as array index
$this->processed_items[ $index ] = $insertedItem->get_id();
if($insertedItem->validate()) {
$insertedItem = $Tainacan_Items->update( $insertedItem );
} else {
@ -516,6 +611,7 @@ abstract class Importer {
}
return $insertedItem;
} else {
$this->add_log( 'error', 'Collection not set');
return false;
@ -524,47 +620,36 @@ abstract class Importer {
}
/**
* run the process
* runs one iteration
*/
public function run(){
if($this->is_repository && $this->current_step < count($this->steps))
{
//$process_name = key($this->steps);
$function_name = current($this->steps);
$inside_step_pointer = $this->{$function_name}();//If unlike numeric this means that still there is stuff to process
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
{
if ( ( !isset($this->collection) || ! $this->collection instanceof Entities\Collection ) && $this->import_structure_and_mapping ) {
$new_collection = new Entities\Collection();
$new_collection->set_name('New Imported Collection');
$new_collection->set_status('publish');
$new_collection->validate();
$new_collection = Tainacan\Repositories\Collections::get_instance()->insert($new_collection);
$this->set_collection($new_collection);
if (!method_exists($this, 'create_fields_and_mapping')) {
throw new Exception('Importers with import_structure_and_mapping true must implement create_fields_and_mapping method');
}
$this->create_fields_and_mapping();
}
$this->process( $this->start );
return sizeof($this->get_processed_items());
}
if ($this->is_finished()) {
return false;
}
$steps = $this->get_steps();
$current_step = $this->get_current_step();
$method_name = $steps[$current_step]['callback'];
if (method_exists($this, $method_name)) {
$result = $this->$method_name();
} else {
$this->add_log( 'error', 'Callback not found for step ' . $steps[$current_step]['name']);
$result = false;
}
if($result === false || (!is_numeric($result) || $result < 0)) {
//Move on to the next step
$this->set_in_step_count(0);
$return = $this->next_step();
} else if(is_numeric($result) && $result > 0) {
$this->set_in_step_count($result);
$return = $result;
}
return $return;
}
}

View File

@ -8,12 +8,16 @@
namespace Tainacan\Importer;
class Old_Tainacan extends Importer
{
class Old_Tainacan extends Importer{
protected $manual_mapping = true;
protected $manual_collection = true;
public function __construct()
{
parent::__construct();
$this->set_repository();
// $this->set_repository();
$this->set_steps($this->steps);
$this->remove_import_method('file');
$this->add_import_method('url');
@ -30,13 +34,23 @@ class Old_Tainacan extends Importer
'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'
//'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',
[
'name' => 'Create categories, collections and metadata',
'callback' => 'process_collections'
],
[
'name' => 'Import Items',
'callback' => 'process_collections'
],
[
'name' => 'Finishing',
'callback' => 'clear'
]
], $tainacan_api_address, $wordpress_api_address;
@ -653,12 +667,13 @@ class Old_Tainacan extends Importer
* get values for a single item
*
* @param $index
* @param $collection_id
* @return array with field_source's as the index and values for the
* item
*
* Ex: [ 'Field1' => 'value1', 'Field2' => [ 'value2','value3' ]
*/
public function process_item($index)
public function process_item( $index, $collection_id )
{
$processedItem = [];
$headers = $this->get_fields();
@ -759,15 +774,35 @@ class Old_Tainacan extends Importer
{
}
/**
* Method implemented by the child importer class to return the number of items to be imported
* @return int
*/
public function get_total_items_from_source()
{
if(!isset($this->tmp_file)){
return 0;
}
$file = new \SplFileObject( $this->tmp_file, 'r' );
$file_content = unserialize($file->fread($file->getSize()));
return $this->total_items = $file_content->found_items;
}
}
/**
* Method implemented by the child importer class to return the number of items to be imported
* @return int
*/
public function get_progress_total_from_source(){
}
/**
* Method implemented by the child importer class to return the number of items to be imported
* @return int
*/
public function get_source_fields(){
}
}

90
src/importer/import.php Normal file
View File

@ -0,0 +1,90 @@
<?php
class ScriptTainacanOld {
var $step = 0;
var $url = '';
/**
* start the execution
*/
function __construct($argv) {
$this->parse_args($argv);
$this->run();
}
/**
* parse args from and set the attributs
* 1 - Old Tainacan url (required)
*/
function parse_args($argv) {
if (!is_array($argv))
return;
if (isset($argv[1])) {
if (filter_var($argv[1], FILTER_VALIDATE_URL)) {
$this->url = $argv[1];
}
}
if (isset($argv[2])) {
if (is_numeric($argv[2])) {
$this->step = $argv[2];
} else {
$this->run = '';
}
}
}
/**
* echo message in prompt line
*/
function log($msg) {
echo $msg . PHP_EOL;
}
function run() {
$start = $partial = microtime(true);
// Avoid warnings
$_SERVER['SERVER_PROTOCOL'] = "HTTP/1.1";
$_SERVER['REQUEST_METHOD'] = "GET";
define( 'WP_USE_THEMES', false );
define( 'SHORTINIT', false );
require( dirname(__FILE__) . '/../../../../wp-blog-header.php' );
$old_tainacan = new \Tainacan\Importer\Old_Tainacan();
$id = $old_tainacan->get_id();
$_SESSION['tainacan_importer'][$id]->set_url($url);
$_SESSION['tainacan_importer'][$id]->set_repository();
while (!$_SESSION['tainacan_importer'][$id]->is_finished()){
$_SESSION['tainacan_importer'][$id]->run();
}
$scripttime = microtime(true) - $start;
$this->log("==========================================================");
$this->log("==========================================================");
$this->log("=== Fim do script. Tempo de execução {$scripttime}s");
$this->log("==========================================================");
$this->log("==========================================================");
}
}
$x = new ScriptTainacanOld($argv);

View File

@ -122,9 +122,9 @@ export default {
loadItems(to) {
// Forces fetch_only to be filled before any search happens
if (this.$store.getters['search/getFetchOnly'] == undefined)
if (this.$store.getters['search/getFetchOnly'] == undefined) {
this.$emit( 'hasToPrepareFieldsAndFilters', to);
else {
} else {
this.$emit( 'isLoadingItems', true);
this.$store.dispatch('collection/fetchItems',
{ 'collectionId': this.collectionId,

View File

@ -36,6 +36,7 @@ export const eventBus = new Vue({
},
updateValue(data){
if ( data.item_id ){
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 });
@ -62,7 +63,7 @@ export const eventBus = new Vue({
});
}
},
getErrors(field_id){
getErrors(field_id) {
let error = this.errors.find( errorItem => errorItem.field_id == field_id );
return ( error ) ? error.errors : false
},

View File

@ -13,6 +13,13 @@ export const fetchItems = ({ rootGetters, dispatch, commit }, { collectionId, is
if (postQueries.metaquery != undefined && postQueries.metaquery.length > 0)
hasFiltered = true;
// Garanttees at least empty fetch_only are passed in case none is found
if (qs.stringify(postQueries.fetch_only) == '')
dispatch('search/add_fetchonly', {} , { root: true });
if (qs.stringify(postQueries.fetch_only['meta']) == '')
dispatch('search/add_fetchonly_meta', 0 , { root: true });
// Differentiates between repository level and collection level queries
let endpoint = '/collection/'+collectionId+'/items?'
@ -21,8 +28,8 @@ export const fetchItems = ({ rootGetters, dispatch, commit }, { collectionId, is
if (!isOnTheme)
endpoint = endpoint + 'context=edit&'
axios.tainacan.get(endpoint + qs.stringify(postQueries) )
axios.tainacan.get(endpoint + qs.stringify(postQueries))
.then(res => {
let items = res.data;
@ -36,9 +43,11 @@ export const fetchItems = ({ rootGetters, dispatch, commit }, { collectionId, is
resolve({'items': items, 'total': res.headers['x-wp-total'], hasFiltered: hasFiltered});
}
dispatch('search/setTotalItems', res.headers['x-wp-total'], { root: true } );
})
})
.catch(error => reject(error));
});
}
export const deleteItem = ({ commit }, { itemId, isPermanently }) => {

View File

@ -10,37 +10,46 @@ use \Tainacan\Repositories;
*
* Each metadata is a label with the field name and the value.
*
* If an ID, a slug or a Tainacan\Entities\Field object is passed, it returns only one metadata, otherwise
* If an ID, a slug or a Tainacan\Entities\Field object is passed in 'metadata' parameter, it returns only one metadata, otherwise
* it returns all metadata
*
* @param int|string|Tainacan\Entities\Field $field Field object, ID or slug to retrieve only one field. empty returns all fields
* @param array|string $args
* @param array|string $args {
* Optional. Array or string of arguments.
*
* @type bool $hide_empty Wether to hide or not fields the item has no value to
* Default: true
* @type string $before_title String to be added before each metadata title
* Default '<h3>'
* @type string $after_title String to be added after each metadata title
* Default '</h3>'
* @type string $before_value String to be added before each metadata value
* Default '<p>'
* @type string $after_value String to be added after each metadata value
* Default '</p>'
* }
* Optional. Array or string of arguments.
*
* @type mixed $metadata Field object, ID or slug to retrieve only one field. empty returns all metadata
*
* @type array $metadata__in Array of metadata IDs or Slugs to be retrieved. Default none
*
* @type array $metadata__not_in Array of metadata IDs (slugs not accepted) to excluded. Default none
*
* @type bool $exclude_title Exclude the Core Title Metadata from result. Default false
*
* @type bool $exclude_description Exclude the Core Description Metadata from result. Default false
*
* @type bool $exclude_core Exclude Core Metadata (title and description) from result. Default false
*
* @type bool $hide_empty Wether to hide or not fields the item has no value to
* Default: true
* @type string $before_title String to be added before each metadata title
* Default '<h3>'
* @type string $after_title String to be added after each metadata title
* Default '</h3>'
* @type string $before_value String to be added before each metadata value
* Default '<p>'
* @type string $after_value String to be added after each metadata value
* Default '</p>'
* }
* @return string The HTML output
*/
function tainacan_get_the_metadata($field = null, $args = array()) {
$post = get_post();
$theme_helper = \Tainacan\Theme_Helper::get_instance();
function tainacan_get_the_metadata($args = array()) {
if (!$theme_helper->is_post_an_item($post))
return;
$item = new Entities\Item($post);
return $item->get_metadata_as_html($field, $args);
$item = tainacan_get_item();
if ($item instanceof \Tainacan\Entities\Item) {
return $item->get_metadata_as_html($args);
}
return '';
}
@ -189,4 +198,53 @@ function tainacan_get_term() {
*/
function tainacan_register_view_mode($slug, $args = []) {
\Tainacan\Theme_Helper::get_instance()->register_view_mode($slug, $args);
}
/**
* Gets the Tainacan Item Entity object
*
* If used inside the Loop of items, will get the Item object for the current post
*/
function tainacan_get_item($post_id = 0) {
$post = get_post( $post_id );
$theme_helper = \Tainacan\Theme_Helper::get_instance();
if (!$theme_helper->is_post_an_item($post))
return null;
$item = new Entities\Item($post);
return $item;
}
/**
* To be used inside The Loop of a faceted serach view mode template.
*
* Returns true or false indicating wether a certain property or metadata is
* selected to be displayed
*
* @param string|integer The property to be checked. If a string is passed, it will check against
* one of the native property of the item, such as title, description and creation_date.
* If an integer is passed, it will check against the IDs of the metadata.
*
* @return bool
*/
function tainacan_current_view_displays($property) {
global $view_mode_displayed_fields;
// Core fields appear in fetch_only as metadata
if ($property == 'title' || $property == 'description') {
$item = tainacan_get_item();
$core_getter_method = "get_core_{$property}_field";
$property = $item->get_collection()->$core_getter_method()->get_id();
}
if (is_string($property)) {
return in_array($property, $view_mode_displayed_fields);
} elseif (is_integer($property)) {
return in_array($property, $view_mode_displayed_fields['meta']);
}
return false;
}

View File

@ -1,7 +1,8 @@
<?php
return [
'tests_dir' => '/tmp/wordpress-tests-lib',
'tests_dir' => '/tmp/wordpress/wordpress-tests-lib',
];
?>
?>

View File

@ -57,7 +57,8 @@ class Entity_Factory {
}
$this->entity = new $this->entity_type();
$this->repository = $this->repository_type::get_instance();
$repo = $this->repository_type;
$this->repository = $repo::get_instance();
if($publish) {
$this->entity->set_status('publish');

View File

@ -134,4 +134,4 @@ class TAINACAN_REST_Export_Controller extends TAINACAN_UnitApiTestCase {
}
}
?>
?>

View File

@ -170,5 +170,46 @@ class CoreFieldTypes extends TAINACAN_UnitTestCase {
$this->assertFalse($core_description->validate(), 'Core metadata should not validate because it can not allow it to have multiple');
}
function test_collection_getters() {
$Tainacan_Collections = \Tainacan\Repositories\Collections::get_instance();
$collection = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'test',
),
true
);
$fieldDescription = $this->tainacan_entity_factory->create_entity(
'field',
array(
'name' => 'just to confuse',
'description' => 'description',
'collection' => $collection,
'field_type' => 'Tainacan\Field_Types\Text'
),
true
);
$core_fields = $collection->get_core_fields();
$this->assertEquals(2, sizeof($core_fields));
$this->assertNotEquals('Tainacan\Field_Types\Text', $core_fields[0]->get_field_type());
$this->assertNotEquals('Tainacan\Field_Types\Text', $core_fields[1]->get_field_type());
$title = $collection->get_core_title_field();
$this->assertEquals('Tainacan\Field_Types\Core_Title', $title->get_field_type());
$description = $collection->get_core_description_field();
$this->assertEquals('Tainacan\Field_Types\Core_Description', $description->get_field_type());
}
}

View File

@ -49,10 +49,80 @@ class DefaultCapabilities extends TAINACAN_UnitTestCase {
$this->assertTrue(current_user_can($entity_cap->$cap), "tainacan-$role_name does not have capability {$entity_cap->$cap}");
}
}
}
}
}
/**
* @group capabilities_denpendecies
*/
function test_capabilities_denpendecies() {
$collection = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'test capabilities denpendecies',
),
true
);
$item = $this->tainacan_entity_factory->create_entity(
'item',
array(
'title' => 'test capabilities denpendecies Item',
'collection' => $collection,
),
true
);
$Tainacan_Capabilities = \Tainacan\Capabilities::get_instance();
$deps = $Tainacan_Capabilities::$dependencies;
$defaults_caps = $Tainacan_Capabilities->defaults;
$tainacan_roles = $Tainacan_Capabilities->get_tainacan_roles();
foreach ($defaults_caps as $post_type => $wp_append_roles) {
if(array_key_exists($post_type, $deps)) {
$entity = false;
$entity_cap = false;
if($post_type != 'tainacan-items') {
$entity = Repository::get_entity_by_post_type($post_type);
$entity_cap = $entity->get_capabilities();
}
foreach ($wp_append_roles as $role_name => $caps) {
$role = get_role($role_name);
$new_user = $this->factory()->user->create(array( 'role' => $role_name ));
wp_set_current_user($new_user);
foreach ($caps as $cap) {
if(array_key_exists($cap, $deps[$post_type])) {
$dep_cap = $deps[$post_type][$cap];
if($post_type == 'tainacan-items') {
$this->assertTrue(current_user_can($dep_cap), "$role_name does not have a dependency capability {$dep_cap} for tainacan-items" );
} else {
$this->assertTrue(current_user_can($dep_cap), "$role_name does not have a dependency capability {$dep_cap} for {$entity_cap->$cap}" );
}
}
}
$new_user = $this->factory()->user->create(array( 'role' => 'tainacan-' . $role_name ));
wp_set_current_user($new_user);
if(in_array($role_name, $tainacan_roles) ) {
foreach ($caps as $cap) {
if(array_key_exists($cap, $deps[$post_type])) {
$dep_cap = $deps[$post_type][$cap];
if($post_type == 'tainacan-items') {
$this->assertTrue(current_user_can($dep_cap), "tainaca-$role_name does not have a dependency capability {$dep_cap} for tainacan-items" );
} else {
$this->assertTrue(current_user_can($dep_cap), "tainaca-$role_name does not have a dependency capability {$dep_cap} for {$entity_cap->$cap}" );
}
}
}
}
}
}
}
}
}

View File

@ -5,12 +5,13 @@ use Tainacan\Importer;
/**
* Class Importer
*
* @group importer
* @package Test_Tainacan
*/
class ImporterTests extends TAINACAN_UnitTestCase {
public function test_intance_old_tainacan()
/*public function test_intance_old_tainacan()
{
$collection = $this->tainacan_entity_factory->create_entity(
'collection',
@ -26,10 +27,10 @@ class ImporterTests extends TAINACAN_UnitTestCase {
$old_tainacan_importer = new Importer\Old_Tainacan();
$id = $old_tainacan_importer->get_id();
$_SESSION['tainacan_importer'][$id]->set_collection( $collection );
$this->assertEquals( $collection->get_id(), $_SESSION['tainacan_importer'][$id]->collection->get_id() );
}
this->assertEquals( $collection->get_id(), $_SESSION['tainacan_importer'][$id]->collection->get_id() );
}*/
/*public function test_automapping_old_tainacan()
public function test_automapping_old_tainacan()
{
//$Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
//$Tainacan_Fields = \Tainacan\Repositories\Fields::get_instance();
@ -37,24 +38,31 @@ class ImporterTests extends TAINACAN_UnitTestCase {
$old_tainacan = new Importer\Old_Tainacan();
$id = $old_tainacan->get_id();
$_SESSION['tainacan_importer'][$id]->set_items_per_step(50);
//if(!copy('./tests/attachment/json_old_tainacan_base.txt', './tests/attachment/json_old_tainacan.txt'))
//{
//return false;
//}
//$_SESSION['tainacan_importer'][$id]->set_file( './tests/attachment/json_old_tainacan.txt' );
$url = 'http://localhost/';
$_SESSION['tainacan_importer'][$id]->set_url($url);
$url_repository = 'http://localhost/wordpress_tainacan/';
$url_repository = '';
if( $url_repository !== '' ){
$_SESSION['tainacan_importer'][$id]->set_url($url);
$_SESSION['tainacan_importer'][$id]->set_repository();
while (!$_SESSION['tainacan_importer'][$id]->is_finished())
{
$_SESSION['tainacan_importer'][$id]->run();
while (!$_SESSION['tainacan_importer'][$id]->is_finished())
{
$_SESSION['tainacan_importer'][$id]->run();
}
$Tainacan_Collections = \Tainacan\Repositories\Collections::get_instance();
$collections = $Tainacan_Collections->fetch([], 'OBJECT');
$this->assertEquals(3, $collections, 'total collection in this url does not match');
$this->assertTrue(true);
}
$this->assertTrue(true);
}*/
}
/*public function test_file_old_tainacan () {
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
@ -128,30 +136,7 @@ class ImporterTests extends TAINACAN_UnitTestCase {
$this->assertEquals( $_SESSION['tainacan_importer'][$id]->get_total_items(), count( $items ) );
}*/
/**
* @group importer
*/
public function test_instance_csv () {
$collection = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'Other',
'description' => 'adasdasdsa',
'default_order' => 'DESC',
'status' => 'publish'
),
true
);
$csv_importer = new Importer\CSV();
$id = $csv_importer->get_id();
$_SESSION['tainacan_importer'][$id]->set_collection( $collection );
// here the session is init already
$this->assertEquals( $collection->get_id(), $_SESSION['tainacan_importer'][$id]->collection->get_id() );
}
/**
* @group importer
*/
@ -161,9 +146,7 @@ class ImporterTests extends TAINACAN_UnitTestCase {
$file_name = 'demosaved.csv';
$csv_importer = new Importer\CSV();
$id = $csv_importer->get_id();
$_SESSION['tainacan_importer'][$id]->set_items_per_step(2);
// open the file "demosaved.csv" for writing
$file = fopen($file_name, 'w');
@ -187,16 +170,16 @@ class ImporterTests extends TAINACAN_UnitTestCase {
// Close the file
fclose($file);
$_SESSION['tainacan_importer'][$id]->set_file( $file_name );
$_SESSION['tainacan_importer'][$id]->set_tmp_file( $file_name );
// file isset on importer
$this->assertTrue( isset( $_SESSION['tainacan_importer'][$id]->tmp_file ) );
$this->assertTrue( !empty( $_SESSION['tainacan_importer'][$id]->get_tmp_file() ) );
// count size of csv
$this->assertEquals( 5, $_SESSION['tainacan_importer'][$id]->get_total_items() );
$this->assertEquals( 5, $_SESSION['tainacan_importer'][$id]->get_progress_total_from_source() );
// get fields to mapping
$headers = $_SESSION['tainacan_importer'][$id]->get_fields();
$headers = $_SESSION['tainacan_importer'][$id]->get_source_fields();
$this->assertEquals( $headers[4], 'Column 5' );
// inserting the collection
@ -210,10 +193,12 @@ class ImporterTests extends TAINACAN_UnitTestCase {
),
true
);
// set the importer
$_SESSION['tainacan_importer'][$id]->set_collection( $collection );
$collection_definition = [
'id' => $collection->get_id(),
'total_items' => $_SESSION['tainacan_importer'][$id]->get_progress_total_from_source(),
];
// get collection fields to map
$fields = $Tainacan_Fields->fetch_by_collection( $collection, [], 'OBJECT' ) ;
@ -222,32 +207,40 @@ class ImporterTests extends TAINACAN_UnitTestCase {
foreach ( $fields as $index => $field ){
$map[$field->get_id()] = $headers[$index];
}
$collection_definition['map'] = $map;
// set the mapping
$_SESSION['tainacan_importer'][$id]->set_mapping( $map );
// check is equal
$this->assertEquals( $_SESSION['tainacan_importer'][$id]->get_mapping(), $map );
// add the collection
$_SESSION['tainacan_importer'][$id]->add_collection( $collection_definition );
//execute the process
$this->assertEquals(2, $_SESSION['tainacan_importer'][$id]->run(), 'first step should import 2 items');
$this->assertEquals(4, $_SESSION['tainacan_importer'][$id]->run(), 'second step should import 2 items');
$this->assertEquals(5, $_SESSION['tainacan_importer'][$id]->run(), 'third step should import 3 items');
$this->assertEquals(5, $_SESSION['tainacan_importer'][$id]->run(), 'if call run again after finish, do nothing');
$this->assertEquals(1, $_SESSION['tainacan_importer'][$id]->run(), 'first step should import 1 item');
$this->assertEquals(2, $_SESSION['tainacan_importer'][$id]->run(), 'second step should import 2 items');
$this->assertEquals(3, $_SESSION['tainacan_importer'][$id]->run(), 'third step should import 3 items');
$this->assertEquals(4, $_SESSION['tainacan_importer'][$id]->run(), 'third step should import 4 items');
$this->assertEquals(false, $_SESSION['tainacan_importer'][$id]->run(), '5 items and return false because its finished');
$this->assertEquals(false, $_SESSION['tainacan_importer'][$id]->run(), 'if call run again after finish, do nothing');
$items = $Tainacan_Items->fetch( [], $collection, 'OBJECT' );
$this->assertEquals( $_SESSION['tainacan_importer'][$id]->get_total_items(), count( $items ) );
$this->assertEquals( $_SESSION['tainacan_importer'][$id]->get_progress_total_from_source(), count( $items ) );
}
/**
* @group importer
*/
public function test_fetch_file(){
/*
public function test_fetch_file(){
$csv_importer = new Importer\CSV();
$id = $csv_importer->get_id();
$_SESSION['tainacan_importer'][$id]->fetch_from_remote( 'http://localhost/wordpress-test/wp-json' );
if(!isset( $_SESSION['tainacan_importer'][$id]->tmp_file )){
#TODO: Remove dependence of web server (see fetch_from_remote)
$this->markTestSkipped('This test need a apache installation available.');
}
$this->assertTrue( isset( $_SESSION['tainacan_importer'][$id]->tmp_file ) );
}
}
*/
}

View File

@ -131,5 +131,46 @@ class Objects extends TAINACAN_UnitTestCase {
$this->assertEquals('', $newCol->get_name());
}
}
function test_fetch_one() {
$collection = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'teste',
'status' => 'publish'
),
true
);
$collection2 = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'teste2',
'status' => 'publish'
),
true
);
$collection3 = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'teste3',
'status' => 'publish'
),
true
);
$Tainacan_Collections = \Tainacan\Repositories\Collections::get_instance();
$one = $Tainacan_Collections->fetch_one(['name' => 'teste2']);
$this->assertTrue( $one instanceof \Tainacan\Entities\Collection );
$this->assertEquals( 'teste2', $one->get_name() );
}
}