Merge branch 'release/0.19'

This commit is contained in:
vnmedeiros 2022-08-23 12:53:24 -03:00
commit cac77f3908
584 changed files with 139471 additions and 95231 deletions

View File

@ -24,15 +24,19 @@ module.exports = {
'vue/prop-name-casing': 'off', 'vue/prop-name-casing': 'off',
'vue/no-confusing-v-for-v-if': 'off', 'vue/no-confusing-v-for-v-if': 'off',
'vue/no-use-v-if-with-v-for': 'off', 'vue/no-use-v-if-with-v-for': 'off',
'vue/require-default-prop': 'off' // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/require-default-prop.md 'vue/multi-word-component-names': 'off',
'vue/require-default-prop': 'off',
'vue/no-v-text-v-html-on-component': 'off'
}, },
globals: { globals: {
'wp': true,
'tainacan_plugin': true, 'tainacan_plugin': true,
'tainacan_blocks': true, 'tainacan_blocks': true,
'_': true, '_': true,
'jQuery': true, 'jQuery': true,
'tainacan_extra_components': true, 'tainacan_extra_components': true,
'tainacan_extra_plugins': true, 'tainacan_extra_plugins': true,
'grecaptcha': true 'grecaptcha': true,
'webkit': true
} }
} }

View File

@ -1,59 +1,68 @@
[![Build Status](https://travis-ci.org/tainacan/tainacan.svg?branch=develop)](https://travis-ci.org/tainacan/tainacan) [![Build Status](https://travis-ci.org/tainacan/tainacan.svg?branch=develop)](https://travis-ci.org/tainacan/tainacan)
# Tainacan # Tainacan
- Tainacan's [plugin](https://wordpress.org/plugins/tainacan/) and [theme](https://wordpress.org/themes/tainacan-interface/) on WordPress.org - Tainacan's [plugin](https://wordpress.org/plugins/tainacan/) and [theme](https://wordpress.org/themes/tainacan-interface/) on WordPress.org
- [Access our website](http://tainacan.org) - [Access our website](http://tainacan.org)
- [Read our official documentation](https://wiki.tainacan.org/) - [Read our official documentation](https://wiki.tainacan.org/)
- [Conctact us in our forum](https://tainacan.discourse.group/)
- [Explore our blog](http://tainacan.org/blog/) - [Explore our blog](http://tainacan.org/blog/)
- [Join our mailing list](https://lists.riseup.net/www/info/tainacan)
- [Follow us on Twitter](https://twitter.com/tainacan_l3p) - [Follow us on Twitter](https://twitter.com/tainacan_l3p)
### What is Tainacan? ### What is Tainacan?
[![Screenshot](https://user-images.githubusercontent.com/29989176/54926885-f8cf5b80-4eef-11e9-870f-92b264f13dea.gif)][youtube_demo] [![Screenshot](https://user-images.githubusercontent.com/29989176/54926885-f8cf5b80-4eef-11e9-870f-92b264f13dea.gif)][youtube_demo]
[youtube_demo]: https://www.youtube.com/watch?v=6q42dlcwW5g [youtube_demo]: https://www.youtube.com/watch?v=6q42dlcwW5g
Get to know Tainacan with our [introduction video](https://www.youtube.com/watch?v=6q42dlcwW5g). Get to know Tainacan with our [introduction video](https://www.youtube.com/watch?v=6q42dlcwW5g).
Tainacan is a software solution for building, managing and publishing digital repositories of any kind on WordPress. Manage and publish you digital collections as easily as publishing a post to your blog, while having all the tools of a professional repository platform. It is composed of a WordPress plugin, which is being developed on this repository, and an optional [companion WordPress theme](https://github.com/tainacan/tainacan-theme) especially designed to produce beautiful digital exhibits. [Try it out!](http://demo.tainacan.org/) Tainacan is a software solution for building, managing and publishing digital repositories of any kind on WordPress. Manage and publish you digital collections as easily as publishing a post to your blog, while having all the tools of a professional repository platform. It is composed of a WordPress plugin, which is being developed on this repository, and an optional [companion WordPress theme](https://github.com/tainacan/tainacan-theme) specially designed to produce beautiful digital exhibits. [Try it out!](http://demo.tainacan.org/)
### Features ### Features
#### Easy install #### Easy install
- As a WordPress plugin, Tainacan can be easily installed on and integrated to an existing WordPress website.
- As a WordPress plugin, Tainacan can be easily installed on and integrated into an existing WordPress website.
#### Metadata and filters #### Metadata and filters
- Use standard metadata or choose whatever set of metadata you want to describe the items in your collections. You can choose which metadata will be used as a filter when browsing the collection. - Use standard metadata or choose whatever set of metadata you want to describe the items in your collections. You can choose which metadata will be used as a filter when browsing the collection.
#### Faceted search #### Faceted search
- Browse (and let the public browse it) your collection using a faceted search interface with filters you have chosen. - Browse (and let the public browse it) your collection using a faceted search interface with filters you have chosen.
#### Manage taxonomies #### Manage taxonomies
- Manage vocabularies that can be used accross all your collections.
- Manage vocabularies that can be used across all your collections.
#### Themes #### Themes
- Tainacan [has its own default theme](https://wordpress.org/themes/tainacan-interface/), which helps you present your collections in a beautiful and effective way as it is developed to incorporate all of Tainacan functionalities. However, it will also work with any WordPress theme. For developers, it will be easy to add Tainacan specific features to an existing theme. - Tainacan [has its own default theme](https://wordpress.org/themes/tainacan-interface/), which helps you present your collections in a beautiful and effective way as it is developed to incorporate all of Tainacan functionalities. However, it will also work with any WordPress theme. For developers, it will be easy to add Tainacan specific features to an existing theme.
#### API and interoperability #### API and interoperability
- Tainacan implements a RESTful API (read and write) to allow other applications to interact with your repository. Expose you collection in different formats, such as JSON, JSON-LD and OAI-PMH. If your collection uses a custom standard, you can map it to well-known stardards such as DublinCore.
- Tainacan implements a RESTful API (read and write) to allow other applications to interact with your repository. Expose you collection in different formats, such as JSON, JSON-LD and OAI-PMH. If your collection uses a custom standard, you can map it to well-known standards such as DublinCore.
### Showcases ### Showcases
Check out the digital exhibits from [Museu do Índio](http://tainacan.museudoindio.gov.br/) and [Museu Histórico Nacional](http://mhn.acervos.museus.gov.br/) to see Tainacan in action! Check out the digital exhibits in our [Showcase page](https://tainacan.org/en/tainacan-showcase/) to see Tainacan in action!
### Support ### Support
In addition to [our documentation](https://wiki.tainacan.org/) and [instructional videos](https://youtu.be/oEl9bWe_rWI), we provide technical support on our [mailing list](https://lists.riseup.net/www/info/tainacan) in English, Portuguese and Spanish. You are welcome to send all of your questions! In addition to [our documentation](https://wiki.tainacan.org/) and [instructional videos](https://youtu.be/oEl9bWe_rWI), we provide technical support on our [online forum](https://tainacan.discourse.group) in English, Portuguese and Spanish. You are welcome to send all of your questions!
### Developers ### Developers
Please refer to our [Developers Documentation](https://tainacan.github.io/tainacan-wiki/#/dev/) if you want to develop tainacan plugins, themes or if you want to contribute to the core. Please refer to our [Developers Documentation](https://tainacan.github.io/tainacan-wiki/#/dev/) if you want to develop Tainacan plugins, themes or if you want to contribute to the core.
### Contributing ### Contributing
Tainacan is a free, open source software licensed under **GPLv3**. Contributions to the codebase will abide to the same license; other contributions may be under additional or other terms.
To contribute with our project, you can report bugs and other issues, or suggest new features. You are also free to submit pull requests or translate Tainacan to multiple languages. If you are interested in contributing, you can get started by reading our [contribution guidelines](docs/CONTRIBUTING.md). Tainacan is a free, open-source software licensed under **GPLv3**. Contributions to the codebase will abide to the same license; other contributions may be under additional or other terms.
To contribute to our project, you can report bugs and other issues, or suggest new features. You are also free to submit pull requests or translate Tainacan to multiple languages. If you are interested in contributing, you can get started by reading our [contribution guidelines](docs/CONTRIBUTING.md).
### Acknowledgements ### Acknowledgements
Tainacan is the results of continuous efforts from developers, researchers, policy makers and GLAMs in Brazil. We are eternally grateful for all of [our amazing contributors](https://github.com/tainacan/tainacan/graphs/contributors)! Tainacan is the results of continuous efforts from developers, researchers, policy makers and GLAMs in Brazil. We are eternally grateful for all of [our amazing contributors](https://github.com/tainacan/tainacan/graphs/contributors)!

View File

@ -93,7 +93,7 @@ mkdir $wp_plugin_dir
rsync -axz --exclude='vendor/bin/phpc*' --exclude='vendor/squizlabs' --exclude='vendor/wimg' \ rsync -axz --exclude='vendor/bin/phpc*' --exclude='vendor/squizlabs' --exclude='vendor/wimg' \
--exclude='vendor/respect/validation/.git' --exclude='vendor/symfony/polyfill-mbstring/.git' \ --exclude='vendor/respect/validation/.git' --exclude='vendor/symfony/polyfill-mbstring/.git' \
--exclude='vendor/respect/validation/docs' --exclude='vendor/respect/validation/tests' \ --exclude='vendor/respect/validation/docs' --exclude='vendor/respect/validation/tests' \
--exclude='pdf-viewer/pdfjs-dist/web/compressed.tracemonkey-pldi-09.pdf' \ --exclude='views/libs/pdf-viewer/pdfjs-dist/web/compressed.tracemonkey-pldi-09.pdf' \
--exclude='vendor/tecnickcom/tcpdf/fonts' \ --exclude='vendor/tecnickcom/tcpdf/fonts' \
--exclude='vendor/smalot/pdfparser/src/Smalot/PdfParser/Tests/' \ --exclude='vendor/smalot/pdfparser/src/Smalot/PdfParser/Tests/' \
--exclude='vendor/tecnickcom/tcpdf/examples' \ --exclude='vendor/tecnickcom/tcpdf/examples' \

View File

@ -14,37 +14,39 @@ sass -E 'UTF-8' --cache-location .tmp/sass-cache-2 src/views/roles/tainacan-role
sass -E 'UTF-8' --cache-location .tmp/sass-cache-3 src/views/reports/tainacan-reports.scss:src/assets/css/tainacan-reports.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-3 src/views/reports/tainacan-reports.scss:src/assets/css/tainacan-reports.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-4 src/views/gutenberg-blocks/blocks/item-gallery/style.scss:src/assets/css/tainacan-gutenberg-block-item-gallery.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-4 src/views/mobile-app/tainacan-mobile-app.scss:src/assets/css/tainacan-mobile-app.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-5 src/views/gutenberg-blocks/blocks/collections-list/style.scss:src/assets/css/tainacan-gutenberg-block-collections-list.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-5 src/views/gutenberg-blocks/blocks/item-gallery/style.scss:src/assets/css/tainacan-gutenberg-block-item-gallery.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-6 src/views/gutenberg-blocks/blocks/carousel-collections-list/style.scss:src/assets/css/tainacan-gutenberg-block-carousel-collections-list.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-6 src/views/gutenberg-blocks/blocks/collections-list/style.scss:src/assets/css/tainacan-gutenberg-block-collections-list.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-7 src/views/gutenberg-blocks/blocks/items-list/style.scss:src/assets/css/tainacan-gutenberg-block-items-list.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-7 src/views/gutenberg-blocks/blocks/carousel-collections-list/style.scss:src/assets/css/tainacan-gutenberg-block-carousel-collections-list.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-8 src/views/gutenberg-blocks/blocks/dynamic-items-list/style.scss:src/assets/css/tainacan-gutenberg-block-dynamic-items-list.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-8 src/views/gutenberg-blocks/blocks/items-list/style.scss:src/assets/css/tainacan-gutenberg-block-items-list.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-9 src/views/gutenberg-blocks/blocks/search-bar/style.scss:src/assets/css/tainacan-gutenberg-block-search-bar.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-9 src/views/gutenberg-blocks/blocks/dynamic-items-list/style.scss:src/assets/css/tainacan-gutenberg-block-dynamic-items-list.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-10 src/views/gutenberg-blocks/blocks/carousel-items-list/style.scss:src/assets/css/tainacan-gutenberg-block-carousel-items-list.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-10 src/views/gutenberg-blocks/blocks/search-bar/style.scss:src/assets/css/tainacan-gutenberg-block-search-bar.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-12 src/views/gutenberg-blocks/blocks/carousel-items-list/style.scss:src/assets/css/tainacan-gutenberg-block-carousel-items-list.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-11 src/views/gutenberg-blocks/blocks/carousel-items-list/style.scss:src/assets/css/tainacan-gutenberg-block-carousel-items-list.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-12 src/views/gutenberg-blocks/blocks/terms-list/style.scss:src/assets/css/tainacan-gutenberg-block-terms-list.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-13 src/views/gutenberg-blocks/blocks/carousel-items-list/style.scss:src/assets/css/tainacan-gutenberg-block-carousel-items-list.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-13 src/views/gutenberg-blocks/blocks/facets-list/style.scss:src/assets/css/tainacan-gutenberg-block-facets-list.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-14 src/views/gutenberg-blocks/blocks/terms-list/style.scss:src/assets/css/tainacan-gutenberg-block-terms-list.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-14 src/views/gutenberg-blocks/blocks/carousel-terms-list/style.scss:src/assets/css/tainacan-gutenberg-block-carousel-terms-list.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-15 src/views/gutenberg-blocks/blocks/facets-list/style.scss:src/assets/css/tainacan-gutenberg-block-facets-list.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-15 src/views/gutenberg-blocks/blocks/faceted-search/style.scss:src/assets/css/tainacan-gutenberg-block-faceted-search.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-16 src/views/gutenberg-blocks/blocks/carousel-terms-list/style.scss:src/assets/css/tainacan-gutenberg-block-carousel-terms-list.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-16 src/views/gutenberg-blocks/blocks/item-submission-form/style.scss:src/assets/css/tainacan-gutenberg-block-item-submission-form.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-17 src/views/gutenberg-blocks/blocks/faceted-search/style.scss:src/assets/css/tainacan-gutenberg-block-faceted-search.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-17 src/views/gutenberg-blocks/blocks/related-items-list/style.scss:src/assets/css/tainacan-gutenberg-block-related-items-list.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-18 src/views/gutenberg-blocks/blocks/item-submission-form/style.scss:src/assets/css/tainacan-gutenberg-block-item-submission-form.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-18 src/views/gutenberg-blocks/scss/gutenberg-blocks-editor-style.scss:src/assets/css/tainacan-gutenberg-block-common-editor-styles.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-19 src/views/gutenberg-blocks/blocks/related-items-list/style.scss:src/assets/css/tainacan-gutenberg-block-related-items-list.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-19 src/views/gutenberg-blocks/scss/gutenberg-blocks-theme-style.scss:src/assets/css/tainacan-gutenberg-block-common-theme-styles.css sass -E 'UTF-8' --cache-location .tmp/sass-cache-20 src/views/gutenberg-blocks/scss/gutenberg-blocks-editor-style.scss:src/assets/css/tainacan-gutenberg-block-common-editor-styles.css
sass -E 'UTF-8' --cache-location .tmp/sass-cache-21 src/views/gutenberg-blocks/scss/gutenberg-blocks-theme-style.scss:src/assets/css/tainacan-gutenberg-block-common-theme-styles.css
echo "Compilação do Sass Concluído!" echo "Compilação do Sass Concluído!"
exit 0 exit 0

View File

@ -1,6 +0,0 @@
{
"projectId": "tubzok",
"videoRecording": false,
"viewportWidth": 1280,
"viewportHeight": 720
}

1
docs/README.md Normal file
View File

@ -0,0 +1 @@
You can find all of Tainacan documentation in our Wiki: [https://wiki.tainacan.org](https://wiki.tainacan.org)

11919
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,62 +4,63 @@
"author": "Eduardo <eduardo.humberto1992@gmail.com>", "author": "Eduardo <eduardo.humberto1992@gmail.com>",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "cross-env NODE_ENV=development webpack --config webpack.dev.js --display-error-details --progress --hide-modules", "build": "cross-env NODE_ENV=development webpack --config webpack.dev.js --progress --mode development",
"build-prod": "cross-env NODE_ENV=production webpack --config webpack.prod.js --display-error-details --progress --hide-modules" "build-prod": "cross-env NODE_ENV=production webpack --config webpack.prod.js --progress --mode production"
}, },
"dependencies": { "dependencies": {
"apexcharts": "^3.29.0", "apexcharts": "^3.35.5",
"axios": "^0.21.4", "axios": "^0.27.2",
"blurhash": "^1.1.3", "blurhash": "^1.1.5",
"buefy": "^0.9.11", "buefy": "^0.9.21",
"bulma": "^0.9.3", "bulma": "^0.9.4",
"conditioner-core": "^2.3.3", "conditioner-core": "^2.3.3",
"countup.js": "^2.0.8", "countup.js": "^2.3.2",
"css-vars-ponyfill": "^2.4.7", "css-vars-ponyfill": "^2.4.8",
"moment": "^2.29.1", "floating-vue": "^1.0.0-beta.18",
"node-sass": "^4.14.1", "masonry-layout": "^4.2.2",
"photoswipe": "^4.1.3", "moment": "^2.29.4",
"qs": "^6.9.4", "node-sass": "^7.0.1",
"react": "^16.13.1", "photoswipe": "^5.3.0",
"react-dom": "^16.13.1", "qs": "^6.10.5",
"swiper": "^5.2.0", "react": "^17.0.2",
"react-dom": "^17.0.2",
"swiper": "^8.3.2",
"t": "^0.5.1", "t": "^0.5.1",
"v-tooltip": "^2.1.3",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-apexcharts": "^1.6.2", "vue-apexcharts": "^1.6.2",
"vue-awesome-swiper": "^4.1.1",
"vue-blurhash": "^0.1.4", "vue-blurhash": "^0.1.4",
"vue-countup-v2": "^4.0.0", "vue-countup-v2": "^4.0.0",
"vue-masonry-css": "^1.0.3", "vue-router": "^3.5.4",
"vue-router": "^3.1.6",
"vue-the-mask": "^0.11.1", "vue-the-mask": "^0.11.1",
"vuedraggable": "^2.24.3", "vuedraggable": "^2.24.3",
"vuex": "^3.4.0" "vuex": "^3.6.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.9.6", "@babel/core": "^7.18.5",
"@babel/preset-env": "^7.9.6", "@babel/preset-env": "^7.18.2",
"@babel/preset-react": "^7.9.4", "@babel/preset-react": "^7.17.12",
"acorn": "^6.0.0", "@types/masonry-layout": "^4.2.5",
"autoprefixer": "^9.7.6", "acorn": "^8.7.1",
"babel-loader": "^8.1.0", "autoprefixer": "^10.4.7",
"cross-env": "^5.2.1", "babel-loader": "^8.2.5",
"css-loader": "^1.0.1", "circular-dependency-plugin": "5.2.2",
"eslint": "^5.16.0", "cross-env": "^7.0.3",
"eslint-loader": "^2.2.1", "css-loader": "^6.7.1",
"eslint-plugin-vue": "^5.2.3", "eslint": "^8.18.0",
"file-loader": "^2.0.0", "eslint-plugin-vue": "^9.1.1",
"eslint-webpack-plugin": "^3.1.1",
"file-loader": "^6.2.0",
"moment-locales-webpack-plugin": "^1.2.0", "moment-locales-webpack-plugin": "^1.2.0",
"postcss-loader": "^3.0.0", "postcss-loader": "7.0.0",
"sass-loader": "^7.3.1", "sass-loader": "^13.0.0",
"style-loader": "^0.23.1", "style-loader": "^3.3.1",
"terser-webpack-plugin": "3.0.0", "terser-webpack-plugin": "5.3.3",
"vue-loader": "^15.9.8", "vue-loader": "^15.9.8",
"vue-template-compiler": "^2.6.14", "vue-template-compiler": "^2.6.14",
"webpack": "^4.45.0", "webpack": "^5.73.0",
"webpack-bundle-analyzer": "^3.7.0", "webpack-bundle-analyzer": "^4.6.1",
"webpack-cli": "^3.3.12", "webpack-cli": "^4.10.0",
"webpack-dev-server": "^3.11.2", "webpack-dev-server": "^4.9.2",
"webpack-merge": "^5.4.0" "webpack-merge": "^5.8.0"
} }
} }

View File

@ -69,7 +69,7 @@
margin: 2em auto; margin: 2em auto;
--swiper-navigation-color: var(--tainacan-block-primary, $primary); --swiper-navigation-color: var(--tainacan-block-primary, $primary);
--swiper-theme-color: var(--tainacan-block-primary, $primary); } --swiper-theme-color: var(--tainacan-block-primary, $primary); }
.wp-block-tainacan-carousel-collections-list .spinner-container { .wp-block-tainacan-carousel-collections-list .spinner {
min-height: 56px; min-height: 56px;
padding: 1em; padding: 1em;
display: flex; display: flex;
@ -115,10 +115,14 @@
position: relative; position: relative;
width: calc(100% + 40px); width: calc(100% + 40px);
left: -20px; } left: -20px; }
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container { .wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper {
margin: 0 var(--spaceAroundCarousel, 50px); } margin: 0 var(--spaceAroundCarousel, 50px); }
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container a > span, .wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper ul.swiper-wrapper {
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container a:hover > span { list-style: none;
padding: 0;
margin: 0; }
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper a > span,
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper a:hover > span {
color: inherit; color: inherit;
font-weight: bold; font-weight: bold;
text-decoration: none; text-decoration: none;
@ -126,19 +130,20 @@
display: block; display: block;
line-height: 1.2em; line-height: 1.2em;
word-break: break-word; } word-break: break-word; }
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container a > img { .wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper a > img {
width: 100%; width: 100%;
height: auto; } height: auto; }
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container a, .wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper a,
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container a:hover { .wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper a:hover {
color: inherit; color: inherit;
text-decoration: none; } text-decoration: none;
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container .swiper-slide-duplicate img { display: block; }
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper .swiper-slide-duplicate img {
display: initial !important; } display: initial !important; }
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container .swiper-slide.collection-list-item-grid a { .wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper .swiper-slide.collection-list-item-grid a {
width: 100%; width: 100%;
display: block; } display: block; }
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container .swiper-slide.collection-list-item-grid .collection-items-grid { .wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper .swiper-slide.collection-list-item-grid .collection-items-grid {
flex-wrap: wrap; flex-wrap: wrap;
display: flex; display: flex;
display: -ms-grid; display: -ms-grid;
@ -149,7 +154,7 @@
grid-gap: 5px; grid-gap: 5px;
gap: 5px; gap: 5px;
box-sizing: border-box; } box-sizing: border-box; }
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container .swiper-slide.collection-list-item-grid .collection-items-grid > *:first-of-type { .wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper .swiper-slide.collection-list-item-grid .collection-items-grid > *:first-of-type {
flex-basis: 100%; flex-basis: 100%;
-ms-grid-column: 1; -ms-grid-column: 1;
-ms-grid-column-span: 2; -ms-grid-column-span: 2;
@ -158,13 +163,13 @@
grid-column: 1/3; grid-column: 1/3;
grid-row: 1/3; grid-row: 1/3;
padding-bottom: 100% !important; } padding-bottom: 100% !important; }
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container .swiper-slide.collection-list-item-grid .collection-items-grid > * { .wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper .swiper-slide.collection-list-item-grid .collection-items-grid > * {
flex-basis: 50%; flex-basis: 50%;
width: 100%; width: 100%;
height: auto; height: auto;
margin-bottom: 0px; margin-bottom: 0px;
padding-bottom: 100% !important; } padding-bottom: 100% !important; }
.wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper-container .swiper-slide.collection-list-item-grid .collection-items-grid img { .wp-block-tainacan-carousel-collections-list .tainacan-carousel .swiper .swiper-slide.collection-list-item-grid .collection-items-grid img {
object-fit: cover; object-fit: cover;
object-position: center; } object-position: center; }
.wp-block-tainacan-carousel-collections-list .preview-warning { .wp-block-tainacan-carousel-collections-list .preview-warning {
@ -248,7 +253,8 @@
margin: 0 var(--spaceAroundCarousel, 50px); margin: 0 var(--spaceAroundCarousel, 50px);
padding: 0; padding: 0;
scroll-snap-type: x mandatory; scroll-snap-type: x mandatory;
scroll-padding-left: 10px; } scroll-padding-left: 10px;
max-width: calc(100% - 2 * var(--spaceAroundCarousel)); }
.wp-block-tainacan-carousel-collections-list ul.collections-list-edit li.collection-list-item { .wp-block-tainacan-carousel-collections-list ul.collections-list-edit li.collection-list-item {
position: relative; position: relative;
display: block; display: block;
@ -474,8 +480,8 @@
.block-editor-block-list__block > .wp-block-tainacan-carousel-collections-list { .block-editor-block-list__block > .wp-block-tainacan-carousel-collections-list {
max-width: calc(100% - 72px); } max-width: calc(100% - 72px); }
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-collections-list .swiper-container a > span, .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-collections-list .swiper a > span,
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-collections-list .swiper-container a:hover > span, .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-collections-list .swiper a:hover > span,
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-collections-list li.collection-list-item a > span, .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-collections-list li.collection-list-item a > span,
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-collections-list li.collection-list-item a:hover > span { .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-collections-list li.collection-list-item a:hover > span {
color: var(--tainacan-block-gray5, #454647); } color: var(--tainacan-block-gray5, #454647); }

File diff suppressed because one or more lines are too long

View File

@ -122,10 +122,14 @@
position: relative; position: relative;
width: calc(100% + 40px); width: calc(100% + 40px);
left: -20px; } left: -20px; }
.wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper-container { .wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper {
margin: 0 var(--spaceAroundCarousel, 50px); } margin: 0 var(--spaceAroundCarousel, 50px); }
.wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper-container a > span, .wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper ul.swiper-wrapper {
.wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper-container a:hover > span { list-style: none;
padding: 0;
margin: 0; }
.wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper a > span,
.wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper a:hover > span {
color: inherit; color: inherit;
font-weight: bold; font-weight: bold;
text-decoration: none; text-decoration: none;
@ -133,16 +137,17 @@
display: block; display: block;
line-height: 1.2em; line-height: 1.2em;
word-break: break-word; } word-break: break-word; }
.wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper-container a > img { .wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper a > img {
width: 100%; width: 100%;
height: auto; } height: auto; }
.wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper-container a, .wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper a,
.wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper-container a:hover { .wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper a:hover {
color: inherit; color: inherit;
text-decoration: none; } text-decoration: none;
.wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper-container .is-forced-square > a > div { display: block; }
.wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper .is-forced-square > a > div {
padding-bottom: 100% !important; } padding-bottom: 100% !important; }
.wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper-container .is-forced-square > a > div img { .wp-block-tainacan-carousel-items-list .tainacan-carousel .swiper .is-forced-square > a > div img {
object-fit: cover; object-fit: cover;
object-position: center; } object-position: center; }
.wp-block-tainacan-carousel-items-list .preview-warning { .wp-block-tainacan-carousel-items-list .preview-warning {
@ -227,7 +232,8 @@
margin: 0 var(--spaceAroundCarousel, 50px); margin: 0 var(--spaceAroundCarousel, 50px);
padding: 0; padding: 0;
scroll-snap-type: x mandatory; scroll-snap-type: x mandatory;
scroll-padding-left: 10px; } scroll-padding-left: 10px;
max-width: calc(100% - 2 * var(--spaceAroundCarousel)); }
.wp-block-tainacan-carousel-items-list ul.items-list-edit li.item-list-item { .wp-block-tainacan-carousel-items-list ul.items-list-edit li.item-list-item {
position: relative; position: relative;
display: block; display: block;
@ -446,8 +452,8 @@
.block-editor-block-list__block > .wp-block-tainacan-carousel-items-list { .block-editor-block-list__block > .wp-block-tainacan-carousel-items-list {
max-width: calc(100% - 72px); } max-width: calc(100% - 72px); }
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-items-list .swiper-container a > span, .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-items-list .swiper a > span,
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-items-list .swiper-container a:hover > span, .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-items-list .swiper a:hover > span,
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-items-list li.item-list-item a > span, .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-items-list li.item-list-item a > span,
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-items-list li.item-list-item a:hover > span { .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-items-list li.item-list-item a:hover > span {
color: var(--tainacan-block-gray5, #454647); } color: var(--tainacan-block-gray5, #454647); }

File diff suppressed because one or more lines are too long

View File

@ -115,10 +115,14 @@
position: relative; position: relative;
width: calc(100% + 40px); width: calc(100% + 40px);
left: -20px; } left: -20px; }
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container { .wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper {
margin: 0 var(--spaceAroundCarousel, 50px); } margin: 0 var(--spaceAroundCarousel, 50px); }
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container a > span, .wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper ul.swiper-wrapper {
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container a:hover > span { list-style: none;
padding: 0;
margin: 0; }
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper a > span,
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper a:hover > span {
color: inherit; color: inherit;
font-weight: bold; font-weight: bold;
text-decoration: none; text-decoration: none;
@ -126,19 +130,20 @@
display: block; display: block;
line-height: 1.2em; line-height: 1.2em;
word-break: break-word; } word-break: break-word; }
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container a > img { .wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper a > img {
width: 100%; width: 100%;
height: auto; } height: auto; }
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container a, .wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper a,
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container a:hover { .wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper a:hover {
color: inherit; color: inherit;
text-decoration: none; } text-decoration: none;
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container .swiper-slide-duplicate img { display: block; }
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper .swiper-slide-duplicate img {
display: initial !important; } display: initial !important; }
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container .swiper-slide.term-list-item-grid a { .wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper .swiper-slide.term-list-item-grid a {
width: 100%; width: 100%;
display: block; } display: block; }
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container .swiper-slide.term-list-item-grid .term-items-grid { .wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper .swiper-slide.term-list-item-grid .term-items-grid {
flex-wrap: wrap; flex-wrap: wrap;
display: flex; display: flex;
display: -ms-grid; display: -ms-grid;
@ -149,7 +154,7 @@
grid-gap: 5px; grid-gap: 5px;
gap: 5px; gap: 5px;
box-sizing: border-box; } box-sizing: border-box; }
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container .swiper-slide.term-list-item-grid .term-items-grid > *:first-of-type { .wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper .swiper-slide.term-list-item-grid .term-items-grid > *:first-of-type {
flex-basis: 100%; flex-basis: 100%;
-ms-grid-column: 1; -ms-grid-column: 1;
-ms-grid-column-span: 2; -ms-grid-column-span: 2;
@ -158,13 +163,13 @@
grid-column: 1/3; grid-column: 1/3;
grid-row: 1/3; grid-row: 1/3;
padding-bottom: 100% !important; } padding-bottom: 100% !important; }
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container .swiper-slide.term-list-item-grid .term-items-grid > * { .wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper .swiper-slide.term-list-item-grid .term-items-grid > * {
flex-basis: 50%; flex-basis: 50%;
width: 100%; width: 100%;
height: auto; height: auto;
margin-bottom: 0px; margin-bottom: 0px;
padding-bottom: 100% !important; } padding-bottom: 100% !important; }
.wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper-container .swiper-slide.term-list-item-grid .term-items-grid img { .wp-block-tainacan-carousel-terms-list .tainacan-carousel .swiper .swiper-slide.term-list-item-grid .term-items-grid img {
object-fit: cover; object-fit: cover;
object-position: center; } object-position: center; }
.wp-block-tainacan-carousel-terms-list .preview-warning { .wp-block-tainacan-carousel-terms-list .preview-warning {
@ -248,7 +253,8 @@
margin: 0 var(--spaceAroundCarousel, 50px); margin: 0 var(--spaceAroundCarousel, 50px);
padding: 0; padding: 0;
scroll-snap-type: x mandatory; scroll-snap-type: x mandatory;
scroll-padding-left: 10px; } scroll-padding-left: 10px;
max-width: calc(100% - 2 * var(--spaceAroundCarousel)); }
.wp-block-tainacan-carousel-terms-list ul.terms-list-edit li.term-list-item { .wp-block-tainacan-carousel-terms-list ul.terms-list-edit li.term-list-item {
position: relative; position: relative;
display: block; display: block;
@ -473,8 +479,8 @@
.block-editor-block-list__block > .wp-block-tainacan-carousel-terms-list { .block-editor-block-list__block > .wp-block-tainacan-carousel-terms-list {
max-width: calc(100% - 72px); } max-width: calc(100% - 72px); }
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-terms-list .swiper-container a > span, .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-terms-list .swiper a > span,
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-terms-list .swiper-container a:hover > span, .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-terms-list .swiper a:hover > span,
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-terms-list li.term-list-item a > span, .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-terms-list li.term-list-item a > span,
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-terms-list li.term-list-item a:hover > span { .block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-carousel-terms-list li.term-list-item a:hover > span {
color: var(--tainacan-block-gray5, #454647); } color: var(--tainacan-block-gray5, #454647); }

File diff suppressed because one or more lines are too long

View File

@ -47,7 +47,8 @@
color: inherit; color: inherit;
border: none; border: none;
font-weight: bold; font-weight: bold;
line-height: normal; } line-height: normal;
display: block; }
.wp-block-tainacan-collections-list ul.collections-list.collections-layout-grid li.collection-list-item img, .wp-block-tainacan-collections-list ul.collections-list.collections-layout-grid li.collection-list-item img,
.wp-block-tainacan-collections-list ul.collections-list-edit.collections-layout-grid li.collection-list-item img { .wp-block-tainacan-collections-list ul.collections-list-edit.collections-layout-grid li.collection-list-item img {
height: auto; height: auto;

View File

@ -1,6 +1,6 @@
{ {
"version": 3, "version": 3,
"mappings": "AAEA,mCAAoC;EAChC,MAAM,EAAE,QAAQ;EAGhB,uDAAoB;IAChB,QAAQ,EAAE,QAAQ;IAClB,KAAK,EAAE,CAAC;EAIZ;gGAC2D;IACvD,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,MAAM;IAClB,OAAO,EAAE,CAAC;EAId;8FACyD;IACrD,qBAAqB,EAAE,wBAAwB;IAC/C,eAAe,EAAE,iBAAiB;IAClC,kBAAkB,EAAE,eAAe;IAEnC;mGAAG;MACC,UAAU,EAAE,YAAY;MACxB,YAAY,EAAE,YAAY;MAC1B,WAAW,EAAE,YAAY;MACzB,MAAM,EAAE,gBAAgB;MAExB;yGAAI;QACA,MAAM,EAAE,gBAAgB;QACxB,aAAa,EAAE,cAAc;EAIzC;sFACiD;IAC7C,OAAO,EAAE,CAAC;ICtCd,SAAS,EAAE,IAAI;IACf,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,IAAI;IDqCT,gBAAgB,EAAE,6BAA6B;IAC/C,qBAAqB,EAAE,wBAAwB;IAC/C,QAAQ,EAAE,GAAG;IACb,eAAe,EAAE,YAAY;IAC7B,eAAe,EAAE,IAAI;IAErB;gHAAwB;MACpB,QAAQ,EAAE,QAAQ;MAClB,OAAO,EAAE,KAAK;MACd,MAAM,EAAE,mBAAmB;MAC3B,aAAa,EAAE,IAAI;MACnB,KAAK,EAAE,KAAK;MAEZ;oHAAE;QACE,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,IAAI;QACZ,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,MAAM;MAGvB;sHAAI;QACA,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,KAAK;QACZ,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE,GAAG;QACZ,aAAa,EAAE,KAAK;MAGxB;iJAA+B;QAC3B,OAAO,EAAE,IAAI;MAGjB;;0HACU;QACN,KAAK,EAAE,OAAO;QACd,eAAe,EAAE,IAAI;EAIjC,oFAAiD;IAC7C,OAAO,EAAE,IAAI;IACb,WAAW,EAAE,UAAU;IAEvB,2FAAO;MACH,QAAQ,EAAE,mBAAmB;MAC7B,gBAAgB,EAAE,yBAAyB;MAC3C,KAAK,EAAE,oCAAmC;MAC1C,OAAO,EAAE,GAAG;MACZ,WAAW,EAAE,GAAG;MAChB,SAAS,EAAE,IAAI;MACf,UAAU,EAAE,MAAM;MAClB,QAAQ,EAAE,QAAQ;MAClB,OAAO,EAAE,CAAC;MACV,KAAK,EAAE,KAAK;MACZ,GAAG,EAAE,GAAG;MACR,eAAe,EAAE,MAAM;MACvB,OAAO,EAAE,GAAG;MAEZ,qGAAU;QAAE,MAAM,EAAE,GAAG;IAG3B,iGAAe;MACX,MAAM,EAAE,IAAI;MACZ,UAAU,EAAE,OAAO;MACnB,gBAAgB,EAAE,gBAAiC;MACnD,OAAO,EAAE,CAAC;MACV,KAAK,EAAE,IAAI;MACX,GAAG,EAAE,IAAI;MACT,MAAM,EAAE,8CAA6C;MACrD,aAAa,EAAE,IAAI;MACnB,UAAU,EAAE,wCAAwC;IAExD,uGAAqB;MACjB,gBAAgB,EAAE,gBAAiC;MACnD,MAAM,EAAE,yDAAwD;EAGxE,yCAA0C;IAEtC;wFACiD;MAC7C,qBAAqB,EAAE,uBAAuB;MAE9C;kHAAwB;QACpB,KAAK,EAAE,IAAI;QACX;wHAAI;UAAE,KAAK,EAAE,IAAI;EAM7B;sFACiD;IAC7C,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,MAAM;IACnB,eAAe,EAAE,IAAI;IAErB;gHAAwB;MACpB,QAAQ,EAAE,QAAQ;MAClB,MAAM,EAAE,mBAAmB;MAC3B,aAAa,EAAE,IAAI;MACnB,UAAU,EAAE,IAAI;MAChB,SAAS,EAAE,gBAAgB;MAC3B,KAAK,EAAE,gBAAgB;MAEvB;oHAAE;QACE,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,MAAM;QACnB,UAAU,EAAE,SAAS;QACrB,UAAU,EAAE,UAAU;MAG1B;sHAAI;QACA,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,IAAI;QACX,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,GAAG;QACZ,YAAY,EAAE,IAAI;MAItB;iJAA+B;QAC3B,OAAO,EAAE,IAAI;MAGjB;;0HACU;QACN,KAAK,EAAE,OAAO;QACd,eAAe,EAAE,IAAI;MAGzB,0CAA2C;QApC/C;oHAAwB;UAqChB,SAAS,EAAE,gBAAgB;UAC3B,KAAK,EAAE,gBAAgB;MAG3B,0CAA2C;QAzC/C;oHAAwB;UA0ChB,SAAS,EAAE,oBAAoB;UAC/B,KAAK,EAAE,oBAAoB;MAG/B,yCAA0C;QA9C9C;oHAAwB;UA+ChB,SAAS,EAAE,gBAAgB;UAC3B,KAAK,EAAE,gBAAgB;MAG3B,yCAA0C;QAnD9C;oHAAwB;UAoDhB,SAAS,EAAE,iBAAiB;UAC5B,KAAK,EAAE,iBAAiB;;AAOhC;iIACa;EACT,KAAK,EAAE,OAAO", "mappings": "AAEA,mCAAoC;EAChC,MAAM,EAAE,QAAQ;EAGhB,uDAAoB;IAChB,QAAQ,EAAE,QAAQ;IAClB,KAAK,EAAE,CAAC;EAIZ;gGAC2D;IACvD,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,MAAM;IAClB,OAAO,EAAE,CAAC;EAId;8FACyD;IACrD,qBAAqB,EAAE,wBAAwB;IAC/C,eAAe,EAAE,iBAAiB;IAClC,kBAAkB,EAAE,eAAe;IAEnC;mGAAG;MACC,UAAU,EAAE,YAAY;MACxB,YAAY,EAAE,YAAY;MAC1B,WAAW,EAAE,YAAY;MACzB,MAAM,EAAE,gBAAgB;MAExB;yGAAI;QACA,MAAM,EAAE,gBAAgB;QACxB,aAAa,EAAE,cAAc;EAIzC;sFACiD;IAC7C,OAAO,EAAE,CAAC;ICtCd,SAAS,EAAE,IAAI;IACf,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,IAAI;IDqCT,gBAAgB,EAAE,6BAA6B;IAC/C,qBAAqB,EAAE,wBAAwB;IAC/C,QAAQ,EAAE,GAAG;IACb,eAAe,EAAE,YAAY;IAC7B,eAAe,EAAE,IAAI;IAErB;gHAAwB;MACpB,QAAQ,EAAE,QAAQ;MAClB,OAAO,EAAE,KAAK;MACd,MAAM,EAAE,mBAAmB;MAC3B,aAAa,EAAE,IAAI;MACnB,KAAK,EAAE,KAAK;MAEZ;oHAAE;QACE,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,IAAI;QACZ,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,MAAM;QACnB,OAAO,EAAE,KAAK;MAGlB;sHAAI;QACA,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,KAAK;QACZ,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE,GAAG;QACZ,aAAa,EAAE,KAAK;MAGxB;iJAA+B;QAC3B,OAAO,EAAE,IAAI;MAGjB;;0HACU;QACN,KAAK,EAAE,OAAO;QACd,eAAe,EAAE,IAAI;EAIjC,oFAAiD;IAC7C,OAAO,EAAE,IAAI;IACb,WAAW,EAAE,UAAU;IAEvB,2FAAO;MACH,QAAQ,EAAE,mBAAmB;MAC7B,gBAAgB,EAAE,yBAAyB;MAC3C,KAAK,EAAE,oCAAmC;MAC1C,OAAO,EAAE,GAAG;MACZ,WAAW,EAAE,GAAG;MAChB,SAAS,EAAE,IAAI;MACf,UAAU,EAAE,MAAM;MAClB,QAAQ,EAAE,QAAQ;MAClB,OAAO,EAAE,CAAC;MACV,KAAK,EAAE,KAAK;MACZ,GAAG,EAAE,GAAG;MACR,eAAe,EAAE,MAAM;MACvB,OAAO,EAAE,GAAG;MAEZ,qGAAU;QAAE,MAAM,EAAE,GAAG;IAG3B,iGAAe;MACX,MAAM,EAAE,IAAI;MACZ,UAAU,EAAE,OAAO;MACnB,gBAAgB,EAAE,gBAAiC;MACnD,OAAO,EAAE,CAAC;MACV,KAAK,EAAE,IAAI;MACX,GAAG,EAAE,IAAI;MACT,MAAM,EAAE,8CAA6C;MACrD,aAAa,EAAE,IAAI;MACnB,UAAU,EAAE,wCAAwC;IAExD,uGAAqB;MACjB,gBAAgB,EAAE,gBAAiC;MACnD,MAAM,EAAE,yDAAwD;EAGxE,yCAA0C;IAEtC;wFACiD;MAC7C,qBAAqB,EAAE,uBAAuB;MAE9C;kHAAwB;QACpB,KAAK,EAAE,IAAI;QACX;wHAAI;UAAE,KAAK,EAAE,IAAI;EAM7B;sFACiD;IAC7C,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,MAAM;IACnB,eAAe,EAAE,IAAI;IAErB;gHAAwB;MACpB,QAAQ,EAAE,QAAQ;MAClB,MAAM,EAAE,mBAAmB;MAC3B,aAAa,EAAE,IAAI;MACnB,UAAU,EAAE,IAAI;MAChB,SAAS,EAAE,gBAAgB;MAC3B,KAAK,EAAE,gBAAgB;MAEvB;oHAAE;QACE,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,MAAM;QACnB,UAAU,EAAE,SAAS;QACrB,UAAU,EAAE,UAAU;MAG1B;sHAAI;QACA,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,IAAI;QACX,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,GAAG;QACZ,YAAY,EAAE,IAAI;MAItB;iJAA+B;QAC3B,OAAO,EAAE,IAAI;MAGjB;;0HACU;QACN,KAAK,EAAE,OAAO;QACd,eAAe,EAAE,IAAI;MAGzB,0CAA2C;QApC/C;oHAAwB;UAqChB,SAAS,EAAE,gBAAgB;UAC3B,KAAK,EAAE,gBAAgB;MAG3B,0CAA2C;QAzC/C;oHAAwB;UA0ChB,SAAS,EAAE,oBAAoB;UAC/B,KAAK,EAAE,oBAAoB;MAG/B,yCAA0C;QA9C9C;oHAAwB;UA+ChB,SAAS,EAAE,gBAAgB;UAC3B,KAAK,EAAE,gBAAgB;MAG3B,yCAA0C;QAnD9C;oHAAwB;UAoDhB,SAAS,EAAE,iBAAiB;UAC5B,KAAK,EAAE,iBAAiB;;AAOhC;iIACa;EACT,KAAK,EAAE,OAAO",
"sources": ["../../views/gutenberg-blocks/blocks/collections-list/style.scss","../../views/gutenberg-blocks/scss/gutenberg-blocks-variables.scss"], "sources": ["../../views/gutenberg-blocks/blocks/collections-list/style.scss","../../views/gutenberg-blocks/scss/gutenberg-blocks-variables.scss"],
"names": [], "names": [],
"file": "tainacan-gutenberg-block-collections-list.css" "file": "tainacan-gutenberg-block-collections-list.css"

View File

@ -129,7 +129,8 @@
align-items: center; align-items: center;
border-bottom: 1px solid var(--tainacan-block-gray3, #cbcbcb); border-bottom: 1px solid var(--tainacan-block-gray3, #cbcbcb);
padding: 1.00em 0.5em 0.75em 0.5em; padding: 1.00em 0.5em 0.75em 0.5em;
position: relative; } position: relative;
box-sizing: border-box; }
@media only screen and (max-width: 768px) { @media only screen and (max-width: 768px) {
.wp-block-tainacan-dynamic-items-list .dynamic-items-search-bar { .wp-block-tainacan-dynamic-items-list .dynamic-items-search-bar {
flex-wrap: wrap; } flex-wrap: wrap; }

File diff suppressed because one or more lines are too long

View File

@ -122,7 +122,8 @@
display: flex; display: flex;
align-items: center; align-items: center;
border-bottom: 1px solid var(--tainacan-block-gray3, #cbcbcb); border-bottom: 1px solid var(--tainacan-block-gray3, #cbcbcb);
padding: 1.00em 0.5em 0.75em 0.5em; } padding: 1.00em 0.5em 0.75em 0.5em;
box-sizing: border-box; }
@media only screen and (max-width: 768px) { @media only screen and (max-width: 768px) {
.wp-block-tainacan-facets-list .facets-search-bar { .wp-block-tainacan-facets-list .facets-search-bar {
flex-wrap: wrap; } flex-wrap: wrap; }

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,40 @@
html {
overflow-y: hidden; }
body.admin_page_tainacan_mobile_app {
background-color: white;
padding: 0px;
margin: 0px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden; }
body.admin_page_tainacan_mobile_app #adminmenumain,
body.admin_page_tainacan_mobile_app #wpadminbar,
body.admin_page_tainacan_mobile_app #wpfooter {
display: none; }
body.admin_page_tainacan_mobile_app #wp-auth-check-wrap {
z-index: 9999999; }
body.admin_page_tainacan_mobile_app #wpcontent,
body.admin_page_tainacan_mobile_app #wpbody,
body.admin_page_tainacan_mobile_app #wpbody-content {
padding: 0px;
margin: 0; }
body.admin_page_tainacan_mobile_app h1 {
display: none; }
body.admin_page_tainacan_mobile_app .wrap {
margin: 0px !important;
padding: 1em 2em;
display: flex;
justify-content: space-between;
align-items: center;
height: calc(100vh - 2em);
width: calc(100vw - 4em);
text-align: center;
background-image: url("../../assets/images/tainacan_loading.gif");
background-repeat: no-repeat;
background-position: center; }
/*# sourceMappingURL=tainacan-mobile-app.css.map */

View File

@ -0,0 +1,7 @@
{
"version": 3,
"mappings": "AACA,IAAK;EACD,UAAU,EAAE,MAAM;;AAEtB,mCAAoC;EAChC,gBAAgB,EAAE,KAAK;EACvB,OAAO,EAAE,GAAG;EACZ,MAAM,EAAE,GAAG;EACX,QAAQ,EAAE,QAAQ;EAClB,GAAG,EAAE,CAAC;EACN,MAAM,EAAE,CAAC;EACT,IAAI,EAAE,CAAC;EACP,KAAK,EAAE,CAAC;EACR,QAAQ,EAAE,MAAM;EAEhB;;+CAEU;IACN,OAAO,EAAE,IAAI;EAEjB,uDAAoB;IAChB,OAAO,EAAE,OAAO;EAGpB;;qDAEgB;IACZ,OAAO,EAAE,GAAG;IACZ,MAAM,EAAE,CAAC;EAEb,sCAAG;IACC,OAAO,EAAE,IAAI;EAEjB,yCAAM;IACF,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,IAAI;IACb,eAAe,EAAE,aAAa;IAC9B,WAAW,EAAE,MAAM;IACnB,MAAM,EAAE,iBAAiB;IACzB,KAAK,EAAE,iBAAiB;IACxB,UAAU,EAAE,MAAM;IAClB,gBAAgB,EAAE,+CAA+C;IACjE,iBAAiB,EAAE,SAAS;IAC5B,mBAAmB,EAAE,MAAM",
"sources": ["../../views/mobile-app/tainacan-mobile-app.scss"],
"names": [],
"file": "tainacan-mobile-app.css"
}

View File

@ -24,6 +24,7 @@
letter-spacing: normal !important; letter-spacing: normal !important;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
overflow-wrap: normal;
} }
@ -150,6 +151,9 @@
.tainacan-icon-items:before { .tainacan-icon-items:before {
content: "items"; content: "items";
} }
.tainacan-icon-item:before {
content: "item";
}
.tainacan-icon-menu:before { .tainacan-icon-menu:before {
content: "menu"; content: "menu";
} }

View File

@ -81,14 +81,44 @@ class REST_Collections_Controller extends REST_Controller {
), ),
'schema' => [$this, 'get_schema'], 'schema' => [$this, 'get_schema'],
)); ));
register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<collection_id>[\d]+)/metadata_order', array( register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<collection_id>[\d]+)/metadata_section_order', array(
array(
'methods' => \WP_REST_Server::EDITABLE,
'callback' => array($this, 'update_metadata_section_order'),
'permission_callback' => array($this, 'update_metadata_section_order_permissions_check'),
'args' => [
'metadata_section_order' => [
'description' => __( 'The order of the metadata section in the collection, an array of objects with integer ID and bool enabled.', 'tainacan' ),
'required' => true,
'validate_callback' => [$this, 'validate_metadata_section_order']
]
],
),
'schema' => [$this, 'get_schema'],
));
register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<collection_id>[\d]+)/metadata_section/default_section/metadata_order', array(
array( array(
'methods' => \WP_REST_Server::EDITABLE, 'methods' => \WP_REST_Server::EDITABLE,
'callback' => array($this, 'update_metadata_order'), 'callback' => array($this, 'update_metadata_order'),
'permission_callback' => array($this, 'update_metadata_order_permissions_check'), 'permission_callback' => array($this, 'update_metadata_order_permissions_check'),
'args' => [ 'args' => [
'metadata_order' => [ 'metadata_order' => [
'description' => __( 'The order of the metadata in the collection, an array of objects with integer ID and bool enabled.', 'tainacan' ), 'description' => __( 'The order of the metadata in the section, an array of objects with integer ID and bool enabled.', 'tainacan' ),
'required' => true,
'validate_callback' => [$this, 'validate_filters_metadata_order']
]
],
),
'schema' => [$this, 'get_schema'],
));
register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<collection_id>[\d]+)/metadata_section/(?P<metadata_section_id>[\d]+)/metadata_order', array(
array(
'methods' => \WP_REST_Server::EDITABLE,
'callback' => array($this, 'update_metadata_order'),
'permission_callback' => array($this, 'update_metadata_order_permissions_check'),
'args' => [
'metadata_order' => [
'description' => __( 'The order of the metadata in the section, an array of objects with integer ID and bool enabled.', 'tainacan' ),
'required' => true, 'required' => true,
'validate_callback' => [$this, 'validate_filters_metadata_order'] 'validate_callback' => [$this, 'validate_filters_metadata_order']
] ]
@ -367,7 +397,7 @@ class REST_Collections_Controller extends REST_Controller {
* @return bool|\WP_Error * @return bool|\WP_Error
* @throws \Exception * @throws \Exception
*/ */
public function get_item_permissions_check($request){ public function get_item_permissions_check($request){
$collection = $this->collections_repository->fetch($request['collection_id']); $collection = $this->collections_repository->fetch($request['collection_id']);
if(($collection instanceof Entities\Collection)) { if(($collection instanceof Entities\Collection)) {
@ -462,7 +492,7 @@ class REST_Collections_Controller extends REST_Controller {
if(! $collection instanceof Entities\Collection) { if(! $collection instanceof Entities\Collection) {
return new \WP_REST_Response([ return new \WP_REST_Response([
'error_message' => __('Collection with this ID was not found', 'tainacan' ), 'error_message' => __('Collection with this ID was not found', 'tainacan' ),
'collection_id' => $collection_id 'collection_id' => $request['collection_id']
], 400); ], 400);
} }
@ -586,6 +616,27 @@ class REST_Collections_Controller extends REST_Controller {
} }
public function validate_metadata_section_order($value, $request, $param) {
if ( is_array($value) ) {
foreach ($value as $val) {
if ( !is_array($val) ) {
return false;
}
if ( !isset($val['id']) || (!is_numeric($val['id']) && $val['id'] != \Tainacan\Entities\Metadata_Section::$default_section_slug ) ) {
return false;
}
if ( !isset($val['enabled']) || !is_bool($val['enabled']) ) {
return false;
}
if ( !isset($val['metadata_order']) || !is_array($val['metadata_order']) ) {
return false;
}
}
return true;
}
return false;
}
/** /**
* Update a collection metadata order * Update a collection metadata order
* *
@ -595,6 +646,7 @@ class REST_Collections_Controller extends REST_Controller {
*/ */
public function update_metadata_order( $request ) { public function update_metadata_order( $request ) {
$collection_id = $request['collection_id']; $collection_id = $request['collection_id'];
$metadata_section_id = isset($request['metadata_section_id']) ? $request['metadata_section_id'] : \Tainacan\Entities\Metadata_Section::$default_section_slug;
$body = json_decode($request->get_body(), true); $body = json_decode($request->get_body(), true);
@ -603,7 +655,66 @@ class REST_Collections_Controller extends REST_Controller {
$collection = $this->collections_repository->fetch($collection_id); $collection = $this->collections_repository->fetch($collection_id);
if( $collection instanceof Entities\Collection) { if( $collection instanceof Entities\Collection) {
$collection->set_metadata_order( $body['metadata_order'] ); $metadata_section_order = $collection->get_metadata_section_order();
if( !isset( $metadata_section_order ) || !is_array($metadata_section_order) ) {
$metadata_section_order = array();
}
$section_order_index = array_search( $metadata_section_id, array_column( $metadata_section_order, 'id' ) );
if ( $section_order_index !== false ) {
$metadata_section_order[$section_order_index]['metadata_order'] = $body['metadata_order'];
} else {
$metadata_section_order[] = array(
'id' => $metadata_section_id,
'metadata_order' => $body['metadata_order'],
'enabled' => true
);
}
$collection->set_metadata_section_order( $metadata_section_order );
if ( $collection->validate() ) {
$updated_collection = $this->collections_repository->update( $collection );
$response = $this->prepare_item_for_response($updated_collection, $request);
return new \WP_REST_Response( $response, 200 );
}
return new \WP_REST_Response([
'error_message' => __('One or more values are invalid.', 'tainacan'),
'errors' => $collection->get_errors(),
'collection' => $this->prepare_item_for_response($collection, $request)
], 400);
}
return new \WP_REST_Response([
'error_message' => __('Collection with this ID was not found', 'tainacan' ),
'collection_id' => $collection_id
], 400);
}
return new \WP_REST_Response([
'error_message' => __('The body could not be empty', 'tainacan'),
'body' => $body
], 400);
}
/**
* Update a collection metadata section order
*
* @param \WP_REST_Request $request
*
* @return string|\WP_Error|\WP_REST_Response
*/
public function update_metadata_section_order( $request ) {
$collection_id = $request['collection_id'];
$body = json_decode($request->get_body(), true);
if( !empty($body) && isset($body['metadata_section_order']) ) {
$collection = $this->collections_repository->fetch($collection_id);
if( $collection instanceof Entities\Collection) {
$collection->set_metadata_section_order( $body['metadata_section_order'] );
if ( $collection->validate() ) { if ( $collection->validate() ) {
$updated_collection = $this->collections_repository->update( $collection ); $updated_collection = $this->collections_repository->update( $collection );
@ -651,6 +762,25 @@ class REST_Collections_Controller extends REST_Controller {
return false; return false;
} }
/**
* Verify if current user has permission to update metadata section order
*
* @param \WP_REST_Request $request
*
* @return bool|\WP_Error
* @throws \Exception
*/
public function update_metadata_section_order_permissions_check( $request ) {
$collection = $this->collections_repository->fetch($request['collection_id']);
if($collection instanceof Entities\Collection) {
return $collection->user_can( 'edit_metadata' ); // && $collection->user_can( 'edit_metadata_section' );
}
return false;
}
/** /**
* Update a collection metadata order * Update a collection metadata order
* *
@ -680,8 +810,8 @@ class REST_Collections_Controller extends REST_Controller {
return new \WP_REST_Response([ return new \WP_REST_Response([
'error_message' => __('One or more values are invalid.', 'tainacan'), 'error_message' => __('One or more values are invalid.', 'tainacan'),
'errors' => $prepared_collection->get_errors(), 'errors' => $collection->get_errors(),
'collection' => $this->prepare_item_for_response($prepared_collection, $request) 'collection' => $this->prepare_item_for_response($collection, $request)
], 400); ], 400);
} }

View File

@ -42,6 +42,11 @@ class REST_Item_Metadata_Controller extends REST_Controller {
public function register_routes() { public function register_routes() {
register_rest_route($this->namespace, '/item/(?P<item_id>[\d]+)/' . $this->rest_base . '/(?P<metadatum_id>[\d]+)', register_rest_route($this->namespace, '/item/(?P<item_id>[\d]+)/' . $this->rest_base . '/(?P<metadatum_id>[\d]+)',
array( array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_item_metadatum_value'),
'permission_callback' => array($this, 'get_items_permissions_check'),
),
array( array(
'methods' => \WP_REST_Server::EDITABLE, 'methods' => \WP_REST_Server::EDITABLE,
'callback' => array($this, 'update_item'), 'callback' => array($this, 'update_item'),
@ -55,7 +60,7 @@ class REST_Item_Metadata_Controller extends REST_Controller {
), ),
) )
); );
register_rest_route($this->namespace, '/item/(?P<item_id>[\d]+)/'. $this->rest_base, register_rest_route($this->namespace, '/item/(?P<item_id>[\d]+)/' . $this->rest_base,
array( array(
array( array(
'methods' => \WP_REST_Server::READABLE, 'methods' => \WP_REST_Server::READABLE,
@ -65,15 +70,6 @@ class REST_Item_Metadata_Controller extends REST_Controller {
) )
) )
); );
register_rest_route($this->namespace, '/item/(?P<item_id>[\d]+)/'. $this->rest_base. '/(?P<metadatum_id>[\d]+)',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_item_metadatum_value'),
'permission_callback' => array($this, 'get_items_permissions_check'),
)
)
);
} }
/** /**

View File

@ -750,13 +750,12 @@ class REST_Items_Controller extends REST_Controller {
private function get_items_permissions_check_for_taxonomy($taxonomies) { private function get_items_permissions_check_for_taxonomy($taxonomies) {
foreach ($taxonomies as $tax) { foreach ($taxonomies as $tax) {
if( !isset($tax['taxonomy']) ) if ( isset($tax['taxonomy']) ) {
return false; $taxonomy = \tainacan_taxonomies()->fetch_by_db_identifier( $tax['taxonomy'] );
$taxonomy = \tainacan_taxonomies()->fetch_by_db_identifier( $tax['taxonomy'] );
if( $taxonomy instanceof Entities\Taxonomy ) { if ( $taxonomy instanceof Entities\Taxonomy ) {
if(!$taxonomy->can_read()) { if (!$taxonomy->can_read())
return false; return false;
} }
} }
} }
@ -997,16 +996,32 @@ class REST_Items_Controller extends REST_Controller {
$errors = []; $errors = [];
foreach ($metadata as $item_metadatum) { foreach ($metadata as $item_metadatum) {
if ( $item_metadatum->get_metadatum()->get_metadata_type() == 'Tainacan\Metadata_Types\Compound' ) {
$new_item_metadatum = new Entities\Item_Metadata_Entity( $new_item, $item_metadatum->get_metadatum() ); $multiple_values = $item_metadatum->is_multiple() ? $item_metadatum->get_value() : [$item_metadatum->get_value()] ;
$new_item_metadatum->set_value( $item_metadatum->get_value() ); foreach ($multiple_values as $value) {
$parent_meta_id = null;
if ( $new_item_metadatum->validate() ) { foreach ( $value as $meta_id => $meta ) {
Repositories\Item_Metadata::get_instance()->insert( $new_item_metadatum ); if ( $meta instanceof Entities\Item_Metadata_Entity) {
$item_metadata = new Entities\Item_Metadata_Entity($new_item, $meta->get_metadatum(), null, $parent_meta_id);
$item_metadata->set_value( $meta->get_value() );
if ( $item_metadata->validate() ) {
$item_metadata = Repositories\Item_Metadata::get_instance()->insert( $item_metadata );
$parent_meta_id = $item_metadata->get_parent_meta_id();
} else {
$errors[] = $item_metadata->get_errors();
}
}
}
}
} else { } else {
$errors[] = $new_item_metadatum->get_errors(); $new_item_metadatum = new Entities\Item_Metadata_Entity( $new_item, $item_metadatum->get_metadatum() );
$new_item_metadatum->set_value( $item_metadatum->get_value() );
if ( $new_item_metadatum->validate() ) {
Repositories\Item_Metadata::get_instance()->insert( $new_item_metadatum );
} else {
$errors[] = $new_item_metadatum->get_errors();
}
} }
} }
if ($args['status'] != 'draft') { if ($args['status'] != 'draft') {

View File

@ -148,22 +148,14 @@ class REST_Metadata_Controller extends REST_Controller {
* @return \WP_Error|\WP_REST_Response * @return \WP_Error|\WP_REST_Response
*/ */
public function get_item( $request ) { public function get_item( $request ) {
$collection_id = isset($request['collection_id']) ? $request['collection_id'] : false;
$metadatum_id = $request['metadatum_id']; $metadatum_id = $request['metadatum_id'];
$offset = '';
$number = '';
if($request['offset'] >= 0 && $request['number'] >= 1){
$offset = $request['offset'];
$number = $request['number'];
}
$result = $this->metadatum_repository->fetch($metadatum_id, 'OBJECT'); $result = $this->metadatum_repository->fetch($metadatum_id, 'OBJECT');
if (! $result instanceof Entities\Metadatum) { if (! $result instanceof Entities\Metadatum) {
return new \WP_REST_Response([ return new \WP_REST_Response([
'error_message' => __('Metadata with this ID was not found', 'tainacan'), 'error_message' => __('Metadata with this ID was not found', 'tainacan'),
'item_id' => $item_id 'item_id' => $metadatum_id
], 400); ], 400);
} }
@ -187,7 +179,7 @@ class REST_Metadata_Controller extends REST_Controller {
} }
/** /**
* @param \WP_REST_Request $request * @param String $request
* *
* @param null $collection_id * @param null $collection_id
* *
@ -444,7 +436,7 @@ class REST_Metadata_Controller extends REST_Controller {
if (! $metadatum instanceof Entities\Metadatum) { if (! $metadatum instanceof Entities\Metadatum) {
return new \WP_REST_Response([ return new \WP_REST_Response([
'error_message' => __('Metadata with this ID was not found', 'tainacan'), 'error_message' => __('Metadata with this ID was not found', 'tainacan'),
'item_id' => $item_id 'item_id' => $metadatum_id
], 400); ], 400);
} }
@ -595,9 +587,9 @@ class REST_Metadata_Controller extends REST_Controller {
$endpoint_args = []; $endpoint_args = [];
if($method === \WP_REST_Server::READABLE) { if($method === \WP_REST_Server::READABLE) {
$endpoint_args = array_merge( $endpoint_args = array_merge(
$endpoint_args, $endpoint_args,
parent::get_wp_query_params() parent::get_wp_query_params()
); );
} elseif ($method === \WP_REST_Server::CREATABLE || $method === \WP_REST_Server::EDITABLE) { } elseif ($method === \WP_REST_Server::CREATABLE || $method === \WP_REST_Server::EDITABLE) {
$map = $this->metadatum_repository->get_map(); $map = $this->metadatum_repository->get_map();

View File

@ -0,0 +1,664 @@
<?php
namespace Tainacan\API\EndPoints;
use \Tainacan\API\REST_Controller;
use Tainacan\Entities;
use Tainacan\Repositories;
class REST_Metadata_Sections_Controller extends REST_Controller {
public function __construct() {
parent::__construct();
$this->rest_base = 'metadata-sections';
add_action('init', array(&$this, 'init_objects'), 11);
}
/**
* Initialize objects after post_type register
*
* @throws \Exception
*/
public function init_objects() {
$this->metadata_sections_repository = Repositories\Metadata_Sections::get_instance();
$this->metadata_repository = Repositories\Metadata::get_instance();
$this->collection_repository = Repositories\Collections::get_instance();
}
/**
* If POST on metadatum/collection/<collection_id>, then
* a metadatum will be created in matched collection and all your item will receive this metadatum
*
* If POST on metadatum/item/<item_id>, then a value will be added in a metadatum and metadatum passed
* id body of requisition
*
* Both of GETs return the metadatum of matched objects
*
* @throws \Exception
*/
public function register_routes() {
register_rest_route($this->namespace, '/collection/(?P<collection_id>[\d]+)/' . $this->rest_base . '/(?P<metadata_section_id>[\d|default_section]+)',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_item'),
'permission_callback' => array($this, 'get_item_permissions_check'),
'args' => array(
'context' => array(
'type' => 'string',
'default' => 'view',
'description' => 'The context in which the request is made.',
'enum' => array(
'view',
'edit'
)
),
),
),
array(
'methods' => \WP_REST_Server::EDITABLE,
'callback' => array($this, 'update_item'),
'permission_callback' => array($this, 'update_item_permissions_check'),
'args' => $this->get_endpoint_args_for_item_schema(\WP_REST_Server::EDITABLE)
),
array(
'methods' => \WP_REST_Server::DELETABLE,
'callback' => array($this, 'delete_item'),
'permission_callback' => array($this, 'delete_item_permissions_check'),
),
'schema' => [$this, 'get_schema']
)
);
register_rest_route($this->namespace, '/collection/(?P<collection_id>[\d]+)/' . $this->rest_base,
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_items'),
'permission_callback' => array($this, 'get_items_permissions_check'),
'args' => $this->get_wp_query_params(),
),
array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array($this, 'create_item'),
'permission_callback' => array($this, 'create_item_permissions_check'),
'args' => $this->get_endpoint_args_for_item_schema(\WP_REST_Server::CREATABLE),
),
'schema' => [$this, 'get_schema']
)
);
register_rest_route($this->namespace, '/collection/(?P<collection_id>[\d]+)/' . $this->rest_base . '/(?P<metadata_section_id>[\d|default_section]+)/metadata',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_metadata_list'),
'permission_callback' => array($this, 'get_item_permissions_check'),
'args' => $this->get_endpoint_args_for_item_schema(\WP_REST_Server::CREATABLE),
),
array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array($this, 'add_metadata'),
'permission_callback' => array($this, 'update_item_permissions_check'),
'args' => $this->get_endpoint_args_for_item_schema(\WP_REST_Server::EDITABLE),
),
array(
'methods' => \WP_REST_Server::DELETABLE,
'callback' => array($this, 'delete_metadata'),
'permission_callback' => array($this, 'update_item_permissions_check'),
'args' => $this->get_endpoint_args_for_item_schema(\WP_REST_Server::EDITABLE),
),
'schema' => [$this, 'get_schema']
)
);
}
/**
* @param \WP_REST_Request|string $request
*
* @param $collection_id
*
* @return object|void|\WP_Error
* @throws \Exception
*/
public function prepare_item_for_database( $request, $collection_id = null) {
if($collection_id == null) {
throw new \InvalidArgumentException('You need provide a collection id');
}
$metadata_section = new Entities\Metadata_Section();
$meta = json_decode( $request, true );
foreach ( $meta as $key => $value ) {
$set_ = 'set_' . $key;
$metadata_section->$set_( $value );
}
$collection = new Entities\Collection( $collection_id );
$metadata_section->set_collection( $collection );
return $metadata_section;
}
/**
* @param Entities\Metadata_Section $item
* @param \WP_REST_Request $request
*
* @return array|\WP_Error|\WP_REST_Response
*/
public function prepare_item_for_response( $item, $request ) {
if (!empty($item)){
$item_arr = $item->_toArray();
if ($request['context'] === 'edit') {
$item_arr['current_user_can_edit'] = $item->can_edit();
$item_arr['current_user_can_delete'] = $item->can_delete();
$item_arr['enabled'] = $item->get_enabled_for_collection();
}
$args = [];
if ($request['include_disabled'] === 'true') {
$args['include_disabled'] = true;
}
$metadata_list = $item->get_metadata_object_list($args);
$item_arr['metadata_object_list'] = [];
if($metadata_list != false) {
foreach($metadata_list as $metadata) {
$meta_arr = $this->prepare_metadata_for_response($metadata, $request);
$item_arr['metadata_object_list'][] = $meta_arr;
}
}
/**
* Use this filter to add additional post_meta to the api response
* Use the $request object to get the context of the request and other variables
* For example, id context is edit, you may want to add your meta or not.
*
* Also take care to do any permissions verification before exposing the data
*/
$extra_metadata = apply_filters('tainacan-api-response-metadata-section-meta', [], $request);
foreach ($extra_metadata as $extra_meta) {
$item_arr[$extra_meta] = get_post_meta($item_arr['id'], $extra_meta, true);
}
return $item_arr;
}
return $item;
}
/**
* @param Entities\Metadata $item
* @param \WP_REST_Request $request
*
* @return array|\WP_Error|\WP_REST_Response
*/
public function prepare_metadata_for_response( $item, $request ) {
if(!empty($item)){
$item_arr = $item->_toArray();
$item_arr['metadata_type_object'] = $item->get_metadata_type_object()->_toArray();
if ( isset($request['include_options_as_html']) && $request['include_options_as_html'] == 'yes' )
$item_arr['options_as_html'] = $item->get_metadata_type_object()->get_options_as_html();
if ( isset($item_arr['metadata_type_options']) && isset($item_arr['metadata_type_options']['taxonomy_id']) ) {
$taxonomy = Repositories\Taxonomies::get_instance()->get_db_identifier_by_id( $item_arr['metadata_type_options']['taxonomy_id'] );
$item_arr['metadata_type_options']['taxonomy'] = $taxonomy;
}
if ($request['context'] === 'edit') {
$item_arr['current_user_can_edit'] = $item->can_edit();
$item_arr['current_user_can_delete'] = $item->can_delete();
ob_start();
$item->get_metadata_type_object()->form();
$form = ob_get_clean();
$item_arr['edit_form'] = $form;
$item_arr['enabled'] = $item->get_enabled_for_collection();
if(isset($item_arr['metadata_type_options']) && isset($item_arr['metadata_type_options']['children_objects'])) {
foreach ($item_arr['metadata_type_options']['children_objects'] as $index => $children) {
$item_arr['metadata_type_options']['children_objects'][$index]['current_user_can_edit'] = $item->can_edit();
$item_arr['metadata_type_options']['children_objects'][$index]['current_user_can_delete'] = $item->can_delete();
}
}
}
/**
* Use this filter to add additional post_meta to the api response
* Use the $request object to get the context of the request and other variables
* For example, id context is edit, you may want to add your meta or not.
*
* Also take care to do any permissions verification before exposing the data
*/
$extra_metadata = apply_filters('tainacan-api-response-metadatum-meta', [], $request);
foreach ($extra_metadata as $extra_meta) {
$item_arr[$extra_meta] = get_post_meta($item_arr['id'], $extra_meta, true);
}
$item_arr['inherited'] = $item_arr['collection_id'] != $request['collection_id'];
return $item_arr;
}
return $item;
}
/**
* @param \WP_REST_Request $request
*
* @return \WP_Error|\WP_REST_Response
*/
public function get_item( $request ) {
$metadata_section_id = $request['metadata_section_id'];
if($metadata_section_id == \Tainacan\Entities\Metadata_Section::$default_section_slug) {
$collection_id = is_numeric($request['collection_id']) ? (int)$request['collection_id'] : null;
$result = $this->metadata_sections_repository->get_default_section($collection_id);
} else {
$result = $this->metadata_sections_repository->fetch($metadata_section_id, 'OBJECT');
}
if (! $result instanceof Entities\Metadata_Section) {
return new \WP_REST_Response([
'error_message' => __('Metadata section with this ID was not found', 'tainacan'),
'item_id' => $metadata_section_id
], 400);
}
return new \WP_REST_Response($this->prepare_item_for_response($result, $request), 200);
}
/**
* @param \WP_REST_Request $request
*
* @return bool|\WP_Error
* @throws \Exception
*/
public function get_item_permissions_check( $request ) {
if(!isset($request['collection_id']) || !isset($request['metadata_section_id'])) {
return false;
}
$collection = $this->collection_repository->fetch($request['collection_id']);
if($collection instanceof Entities\Collection && $collection->can_read()) {
$metadata_section_id = $request['metadata_section_id'];
if($metadata_section_id == \Tainacan\Entities\Metadata_Section::$default_section_slug) {
$metadatum_section = $this->metadata_sections_repository->get_default_section($collection);
} else {
$metadatum_section = $this->metadata_sections_repository->fetch($metadata_section_id);
}
return $metadatum_section instanceof Entities\Metadata_Section && $metadatum_section->can_read();
}
return false;
}
/**
* @param \WP_REST_Request $request
*
* @return \WP_Error|\WP_REST_Response
* @throws \Exception
*/
public function create_item( $request ) {
if(!empty($request->get_body()) && isset($request['collection_id'])){
$collection_id = $request['collection_id'];
try {
$prepared = $this->prepare_item_for_database( $request->get_body(), $collection_id );
} catch (\Exception $exception) {
return new \WP_REST_Response($exception->getMessage(), 400);
}
if($prepared->validate()) {
$metadata_section = $this->metadata_sections_repository->insert($prepared);
$response = $this->prepare_item_for_response($metadata_section, $request);
return new \WP_REST_Response($response, 201);
} else {
return new \WP_REST_Response([
'error_message' => __('One or more values are invalid.', 'tainacan'),
'errors' => $prepared->get_errors(),
'metadatum' => $this->prepare_item_for_response($prepared, $request),
], 400);
}
}
return new \WP_REST_Response([
'error_message' => __('Body cannot be empty.', 'tainacan'),
'item' => $request->get_body()
], 400);
}
// @TODO: fix the permissions check
/**
* @param $request
*
* @return bool|\WP_Error
* @throws \Exception
*/
public function create_item_permissions_check( $request ) {
return true;
if( isset($request['collection_id']) ) {
$collection = $this->collection_repository->fetch( $request['collection_id'] );
if ( $collection instanceof Entities\Collection ) {
return $collection->user_can( 'edit_metadata_section' );
}
} else {
return current_user_can( 'tnc_rep_edit_metadata_section' );
}
return false;
}
/**
* @param \WP_REST_Request $request
*
* @return \WP_Error|\WP_REST_Response
* @throws \Exception
*/
public function get_items( $request ) {
if(isset($request['collection_id'])) {
$collection_id = $request['collection_id'];
$args = $this->prepare_filters( $request );
if ($request['include_disabled'] === 'true') {
$args['include_disabled'] = true;
}
$collection = new Entities\Collection( $collection_id );
$result = $this->metadata_sections_repository->fetch_by_collection( $collection, $args );
}
$prepared_item = [];
foreach ( $result as $item ) {
$prepared_item[] = $this->prepare_item_for_response( $item, $request );
}
return new \WP_REST_Response($prepared_item, 200);
}
/**
* @param \WP_REST_Request $request
*
* @return bool|\WP_Error
* @throws \Exception
*/
public function get_items_permissions_check( $request ) {
if(!isset($request['collection_id'])) {
return true;
}
$collection = $this->collection_repository->fetch($request['collection_id']);
if($collection instanceof Entities\Collection){
if ( ! $collection->can_read() ) {
return false;
}
return true;
}
return false;
}
/**
* @param \WP_REST_Request $request
*
* @return \WP_Error|\WP_REST_Response
*/
public function delete_item( $request ) {
$metadata_section_id = $request['metadata_section_id'];
$metadatum_section = $this->metadata_sections_repository->fetch($metadata_section_id);
if (! $metadatum_section instanceof Entities\Metadata_Section) {
return new \WP_REST_Response([
'error_message' => __('Metadata section with this ID was not found', 'tainacan'),
'item_id' => $metadata_section_id
], 400);
}
$metadatum_section_trashed = $this->metadata_sections_repository->delete($metadatum_section);
$prepared = $this->prepare_item_for_response($metadatum_section_trashed, $request);
return new \WP_REST_Response($prepared, 200);
}
/**
* @param \WP_REST_Request $request
*
* @return bool|\WP_Error
* @throws \Exception
*/
public function delete_item_permissions_check( $request ) {
$metadata_section = $this->metadata_sections_repository->fetch($request['metadata_section_id']);
if ($metadata_section instanceof Entities\Metadata_Section) {
return $metadata_section->can_delete();
}
return false;
}
/**
* @param \WP_REST_Request $request
*
* @return \WP_Error|\WP_REST_Response
*/
public function update_item( $request ) {
$collection_id = is_numeric($request['collection_id']) ? $request['collection_id'] : null;
$body = json_decode($request->get_body(), true);
if(!empty($body)){
$metadata_section_id = $request['metadata_section_id'];
if($metadata_section_id == \Tainacan\Entities\Metadata_Section::$default_section_slug) {
$metadata_section = $this->metadata_sections_repository->get_default_section($collection_id);
} else {
$metadata_section = $this->metadata_sections_repository->fetch($metadata_section_id);
if ( $collection_id != $metadata_section->get_collection_id() ) {
return new \WP_REST_Response( [
'error_message' => __('This metadata section not found in collection', 'tainacan'),
'metadata_section_id' => $metadata_section_id
] );
}
}
if ($metadata_section) {
$attributes = [];
foreach ($body as $att => $value) {
$attributes[$att] = $value;
}
$prepared = $this->prepare_item_for_updating($metadata_section, $attributes);
if($prepared->validate()) {
$updated_metadata_section = $this->metadata_sections_repository->update($prepared);
$response = $this->prepare_item_for_response($updated_metadata_section, $request);
return new \WP_REST_Response($response, 200);
}
return new \WP_REST_Response([
'error_message' => __('One or more values are invalid.', 'tainacan'),
'errors' => $prepared->get_errors(),
'metadatum_section' => $this->prepare_item_for_response($prepared, $request)
], 400);
}
return new \WP_REST_Response( [
'error_message' => __('Metadata with this ID was not found', 'tainacan'),
'metadata_section_id' => $metadata_section_id
] );
}
return new \WP_REST_Response([
'error_message' => __('The body could not be empty', 'tainacan'),
'body' => $body
], 400);
}
public function add_metadata( $request ) {
if( !empty($request->get_body()) && isset($request['metadata_section_id']) ){
$body = json_decode($request->get_body(), true);
$metadata_section_id = $request['metadata_section_id'];
$metadata_list = $body['metadata_list'];
try {
$metadata_section = $this->metadata_sections_repository->add_metadata($metadata_section_id, $metadata_list);
if($metadata_section == false) {
return new \WP_REST_Response([
'error_message' => __('One or more values are invalid.', 'tainacan'),
'item' => $request->get_body()
], 400);
}
$response = $this->prepare_item_for_response($metadata_section, $request);
return new \WP_REST_Response($response, 201);
} catch (\Exception $exception) {
return new \WP_REST_Response($exception->getMessage(), 400);
}
}
return new \WP_REST_Response([
'error_message' => __('Body cannot be empty.', 'tainacan'),
'item' => $request->get_body()
], 400);
}
public function delete_metadata( $request ) {
if( !empty($request->get_body()) && isset($request['metadata_section_id']) ){
$body = json_decode($request->get_body(), true);
$metadata_section_id = $request['metadata_section_id'];
$metadata_list = $body['metadata_list'];
try {
$metadata_section = $this->metadata_sections_repository->delete_metadata($metadata_section_id, $metadata_list);
if($metadata_section == false) {
return new \WP_REST_Response([
'error_message' => __('One or more values are invalid.', 'tainacan'),
'item' => $request->get_body()
], 400);
}
$response = $this->prepare_item_for_response($metadata_section, $request);
return new \WP_REST_Response($response, 201);
} catch (\Exception $exception) {
return new \WP_REST_Response($exception->getMessage(), 400);
}
}
return new \WP_REST_Response([
'error_message' => __('Body cannot be empty.', 'tainacan'),
'item' => $request->get_body()
], 400);
}
public function get_metadata_list( $request ) {
if(isset($request['metadata_section_id']) ){
$metadata_section_id = $request['metadata_section_id'];
try {
$result = $this->metadata_sections_repository->get_metadata_object_list($metadata_section_id);
$prepared_item = [];
foreach ( $result as $item ) {
$prepared_item[] = $item->_toArray();
}
return new \WP_REST_Response($prepared_item, 200);
} catch (\Exception $exception) {
return new \WP_REST_Response($exception->getMessage(), 400);
}
}
return new \WP_REST_Response([
'error_message' => __('Metadata section id cannot be empty.', 'tainacan'),
'item' => $request->get_body()
], 400);
}
/**
* @param \WP_REST_Request $request
*
* @return bool|\WP_Error
* @throws \Exception
*/
public function update_item_permissions_check( $request ) {
return true;
$metadatum = $this->metadata_sections_repository->fetch($request['metadatum_id']);
if ($metadatum instanceof Entities\Metadatum) {
return $metadatum->can_edit();
}
return false;
}
/**
* @param null $object_name
*
* @return array|void
*/
public function get_wp_query_params() {
$query_params['context']['default'] = 'view';
$query_params = array_merge($query_params, parent::get_wp_query_params());
$query_params['name'] = array(
'description' => __('Limits the result set to metadata with a specific name'),
'type' => 'string',
);
$query_params = array_merge($query_params, parent::get_meta_queries_params());
return $query_params;
}
/**
* @param null $method
*
* @return array
* @throws \Exception
*/
public function get_endpoint_args_for_item_schema( $method = null ) {
$endpoint_args = [];
if($method === \WP_REST_Server::READABLE) {
$endpoint_args = array_merge(
$endpoint_args,
parent::get_wp_query_params()
);
} elseif ($method === \WP_REST_Server::CREATABLE || $method === \WP_REST_Server::EDITABLE) {
$map = $this->metadata_sections_repository->get_map();
foreach ($map as $mapped => $value){
$set_ = 'set_'. $mapped;
// Show only args that has a method set
if( !method_exists(new Entities\Metadatum(), "$set_") ){
unset($map[$mapped]);
}
}
$endpoint_args = $map;
}
return $endpoint_args;
}
function get_schema() {
$schema = [
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'metadatum',
'type' => 'object'
];
$main_schema = parent::get_repository_schema( $this->metadata_sections_repository );
$permissions_schema = parent::get_permissions_schema();
// $item_metadata_scheme = parent::get_repository_schema( $this->item_metadata_repository );
// $item_scheme = parent::get_repository_schema( $this->item_repository );
// $collection_scheme = parent::get_repository_schema( $this->collection_repository );
$schema['properties'] = array_merge(
parent::get_base_properties_schema(),
$main_schema,
$permissions_schema
// $item_metadata_scheme,
// $item_scheme,
// $collection_scheme
);
return $schema;
}
}
?>

View File

@ -738,8 +738,15 @@ class REST_Reports_Controller extends REST_Controller {
return new \WP_REST_Response($response, 200); return new \WP_REST_Response($response, 200);
} }
private function get_activities_general($collection_id = false, $interval) { private function get_activities_general($collection_id = false, $interval = false) {
global $wpdb; global $wpdb;
if($interval == false) {
$end = (new \DateTime())->add(new \DateInterval('P1D'))->setTime(0,0,0);
$interval = [
'end' => $end->format('Y-m-d H:i:s'),
'start' => $end->sub(new \DateInterval('P1Y1D'))->format('Y-m-d H:i:s')
];
}
$collection_from = ""; $collection_from = "";
$start = $interval['start']; $start = $interval['start'];
$end = $interval['end']; $end = $interval['end'];
@ -756,8 +763,15 @@ class REST_Reports_Controller extends REST_Controller {
return $wpdb->get_results($sql_statement); return $wpdb->get_results($sql_statement);
} }
private function get_activities_general_by_user($collection_id = false, $interval) { private function get_activities_general_by_user($collection_id = false, $interval = false) {
global $wpdb; global $wpdb;
if($interval == false) {
$end = (new \DateTime())->add(new \DateInterval('P1D'))->setTime(0,0,0);
$interval = [
'end' => $end->format('Y-m-d H:i:s'),
'start' => $end->sub(new \DateInterval('P1Y1D'))->format('Y-m-d H:i:s')
];
}
$collection_from = ""; $collection_from = "";
$start = $interval['start']; $start = $interval['start'];
$end = $interval['end']; $end = $interval['end'];

View File

@ -388,6 +388,7 @@ class REST_Roles_Controller extends REST_Controller {
'name' => translate_user_role($name), 'name' => translate_user_role($name),
'capabilities' => $caps 'capabilities' => $caps
]; ];
$return = apply_filters('tainacan-api-role-prepare-for-response', $return, $request);
return $return; return $return;
} }

View File

@ -22,6 +22,7 @@ $rest_oaipmh_expose_controller = new \Tainacan\API\EndPoints\REST_Oaipmh_
$rest_item_metadata_controller = new \Tainacan\API\EndPoints\REST_Item_Metadata_Controller(); $rest_item_metadata_controller = new \Tainacan\API\EndPoints\REST_Item_Metadata_Controller();
$rest_sequence_edit_controller = new \Tainacan\API\EndPoints\REST_Sequence_Edit_Controller(); $rest_sequence_edit_controller = new \Tainacan\API\EndPoints\REST_Sequence_Edit_Controller();
$rest_metadata_types_controller = new \Tainacan\API\EndPoints\REST_Metadata_Types_Controller(); $rest_metadata_types_controller = new \Tainacan\API\EndPoints\REST_Metadata_Types_Controller();
$rest_metadata_sections_controller = new \Tainacan\API\EndPoints\REST_Metadata_Sections_Controller();
$rest_metadatum_mappers_controller = new \Tainacan\API\EndPoints\REST_Metadatum_Mappers_Controller(); $rest_metadatum_mappers_controller = new \Tainacan\API\EndPoints\REST_Metadatum_Mappers_Controller();
$rest_background_processes_controller = new \Tainacan\API\EndPoints\REST_Background_Processes_Controller(); $rest_background_processes_controller = new \Tainacan\API\EndPoints\REST_Background_Processes_Controller();
// Add here other endpoints imports // Add here other endpoints imports

View File

@ -40,7 +40,7 @@ class Elastic_Press {
//activates the inclusion of the complete hierarchy of terms. //activates the inclusion of the complete hierarchy of terms.
add_filter('ep_sync_terms_allow_hierarchy', '__return_true'); add_filter('ep_sync_terms_allow_hierarchy', '__return_true');
add_filter('tainacan_fetch_args', [$this, 'filter_args'], 10, 2); add_filter('tainacan-fetch-args', [$this, 'filter_args'], 10, 2);
add_filter('tainacan-api-items-filters-response', function($filters) { return $this->last_aggregations; }); add_filter('tainacan-api-items-filters-response', function($filters) { return $this->last_aggregations; });
add_filter('tainacan-fetch-all-metadatum-values', [$this, 'fetch_all_metadatum_values'], 10, 3); add_filter('tainacan-fetch-all-metadatum-values', [$this, 'fetch_all_metadatum_values'], 10, 3);
@ -478,7 +478,7 @@ class Elastic_Press {
$custom_filter = $default_filters; $custom_filter = $default_filters;
$temp = []; $temp = [];
foreach ($custom_filter['bool']['must'] as $item) { foreach ($custom_filter['bool']['must'] as $item) {
if ( isset($item['bool'])) { if ( isset($item['bool']) && isset($item['bool']["must"]) ) {
foreach ($item['bool']["must"] as $item_filter) { foreach ($item['bool']["must"] as $item_filter) {
if ( !isset( $item_filter["terms"][$filter['key']] ) ) { //do use array_filter ? if ( !isset( $item_filter["terms"][$filter['key']] ) ) { //do use array_filter ?
$temp[] = $item; $temp[] = $item;

View File

@ -77,7 +77,7 @@ class Embed {
public function pdf_embed_handler($matches, $attr, $url, $rawattr) { public function pdf_embed_handler($matches, $attr, $url, $rawattr) {
global $TAINACAN_BASE_URL; global $TAINACAN_BASE_URL;
$viewer_url = $TAINACAN_BASE_URL . '/views/libs/pdf-viewer/pdf-viewer.html?file=' . $url; $viewer_url = $TAINACAN_BASE_URL . '/views/libs/pdf-viewer/pdfjs-dist/web/viewer.html?file=' . $url;
//$viewer_url = $TAINACAN_BASE_URL . '/assets/pdfjs-dist/web/viewer.html?file=' . $url; //$viewer_url = $TAINACAN_BASE_URL . '/assets/pdfjs-dist/web/viewer.html?file=' . $url;
$defaults = array( $defaults = array(

View File

@ -74,6 +74,7 @@ class Media {
return $this->insert_attachment_from_blob($file, basename($url), $post_id); return $this->insert_attachment_from_blob($file, basename($url), $post_id);
} catch (\Exception $e) { } catch (\Exception $e) {
error_log($e);
return false; return false;
} }
@ -96,19 +97,22 @@ class Media {
} }
/** /**
* Avoid memory overflow problems with large files (Exceeded maximum memory limit of PHP) * Avoid memory overflow problems with large files (Exceeded maximum memory limit of PHP)
* *
* @param $url * @param $url
* @return string the file path * @return string the file path
*/ */
public function save_remote_file($url) { public function save_remote_file($url) {
$filename = download_url($url, 900); // Include file.php
if( is_wp_error($filename) ) { require_once( ABSPATH . 'wp-admin/includes/file.php' );
throw new \Exception( "[save_remote_file]:" . implode("\n", $filename->get_error_messages()));
} $filename = \download_url($url, 900);
return $filename; if( is_wp_error($filename) ) {
throw new \Exception( "[save_remote_file]:" . implode("\n", $filename->get_error_messages()));
} }
return $filename;
}
/** /**
@ -330,7 +334,7 @@ class Media {
$embed = $wp_embed->autoembed($url); $embed = $wp_embed->autoembed($url);
if ( $embed == $url ) { if ( esc_url($embed) == esc_url($url) ) {
$output .= sprintf("<a href='%s' target='blank'>%s</a>", $url, $url); $output .= sprintf("<a href='%s' target='blank'>%s</a>", $url, $url);
} else { } else {
$output .= $embed; $output .= $embed;

View File

@ -25,6 +25,7 @@ class Roles {
private function __construct() { private function __construct() {
$this->meta_caps = (new \Tainacan\Entities\Metadatum())->get_capabilities(); $this->meta_caps = (new \Tainacan\Entities\Metadatum())->get_capabilities();
$this->meta_section_caps = (new \Tainacan\Entities\Metadata_Section())->get_capabilities();
$this->filters_caps = (new \Tainacan\Entities\Filter())->get_capabilities(); $this->filters_caps = (new \Tainacan\Entities\Filter())->get_capabilities();
$this->capabilities = [ $this->capabilities = [
@ -177,6 +178,7 @@ class Roles {
'scope' => 'collection', 'scope' => 'collection',
'dependencies' => [ 'dependencies' => [
$this->meta_caps->read_private_posts, $this->meta_caps->read_private_posts,
$this->meta_section_caps->read_private_posts,
$this->filters_caps->read_private_posts $this->filters_caps->read_private_posts
], ],
'supercaps' => [ 'supercaps' => [
@ -217,6 +219,17 @@ class Roles {
'tnc_col_all_edit_metadata', 'tnc_col_all_edit_metadata',
] ]
], ],
'tnc_col_%d_edit_metasection' => [
'display_name' => __('Manage metadata sections', 'tainacan'),
'description' => __('Create/edit metadata section in this collection', 'tainacan'),
'scope' => 'collection',
'supercaps' => [
'manage_tainacan',
'manage_tainacan_collection_all',
'manage_tainacan_collection_%d',
'tnc_col_all_edit_metasection',
]
],
'tnc_col_%d_edit_filters' => [ 'tnc_col_%d_edit_filters' => [
'display_name' => __('Manage filters', 'tainacan'), 'display_name' => __('Manage filters', 'tainacan'),
'description' => __('Create/edit filters in this collection', 'tainacan'), 'description' => __('Create/edit filters in this collection', 'tainacan'),
@ -239,6 +252,17 @@ class Roles {
'tnc_col_all_delete_metadata', 'tnc_col_all_delete_metadata',
] ]
], ],
'tnc_col_%d_delete_metasection' => [
'display_name' => __('Delete metadata sections', 'tainacan'),
'description' => __('Delete metadata section in this collection', 'tainacan'),
'scope' => 'collection',
'supercaps' => [
'manage_tainacan',
'manage_tainacan_collection_all',
'manage_tainacan_collection_%d',
'tnc_col_all_delete_metasection',
]
],
'tnc_col_%d_delete_filters' => [ 'tnc_col_%d_delete_filters' => [
'display_name' => __('Delete filters', 'tainacan'), 'display_name' => __('Delete filters', 'tainacan'),
'description' => __('Delete filters in this collection', 'tainacan'), 'description' => __('Delete filters in this collection', 'tainacan'),
@ -264,6 +288,21 @@ class Roles {
'tnc_col_all_read_private_metadata', 'tnc_col_all_read_private_metadata',
] ]
], ],
'tnc_col_%d_read_private_metasection' => [
'display_name' => __('View private metadata sections', 'tainacan'),
'description' => __('Access private metadata section in this collection', 'tainacan'),
'scope' => 'collection',
'dependencies' => [
$this->meta_caps->read_private_posts, // e.g.: 'read_private_tainacan-metasection'
$this->meta_section_caps->read_private_posts,
],
'supercaps' => [
'manage_tainacan',
'manage_tainacan_collection_all',
'manage_tainacan_collection_%d',
'tnc_col_all_read_private_metasection',
]
],
'tnc_col_%d_read_private_filters' => [ 'tnc_col_%d_read_private_filters' => [
'display_name' => __('View private filters', 'tainacan'), 'display_name' => __('View private filters', 'tainacan'),
'description' => __('Access private filters in this collection', 'tainacan'), 'description' => __('Access private filters in this collection', 'tainacan'),
@ -552,6 +591,7 @@ class Roles {
if( in_array($requested_cap, [ if( in_array($requested_cap, [
$this->meta_caps->read_private_posts, $this->meta_caps->read_private_posts,
$this->meta_section_caps->read_private_posts,
$this->filters_caps->read_private_posts] $this->filters_caps->read_private_posts]
) && ( ) && (
$user->has_cap('manage_tainacan') || $user->has_cap('manage_tainacan') ||
@ -581,7 +621,7 @@ class Roles {
* We are only interested in checks for a specific collection. * We are only interested in checks for a specific collection.
* $args[2] will be set if this came from a meta cap of a specific collection ( e.g. current_user_can('tnc_rep_edit_collection', 3) ). * $args[2] will be set if this came from a meta cap of a specific collection ( e.g. current_user_can('tnc_rep_edit_collection', 3) ).
*/ */
if ( isset( $args[2] ) && is_numeric( $args[2] ) ) { if ( in_array( $cap, (array) $collection_capabilities ) && isset( $args[2] ) && is_numeric( $args[2] ) ) {
$col_id = $args[2]; $col_id = $args[2];
/** /**
* Or we extract the collection id from the capability itself. Example: tnc_col_3_delete_items * Or we extract the collection id from the capability itself. Example: tnc_col_3_delete_items
@ -662,6 +702,9 @@ class Roles {
$meta_caps = new \Tainacan\Entities\Metadatum(); $meta_caps = new \Tainacan\Entities\Metadatum();
$meta_caps = $meta_caps->get_capabilities(); $meta_caps = $meta_caps->get_capabilities();
$meta_section_caps = new \Tainacan\Entities\Metadata_Section();
$meta_section_caps = $meta_section_caps->get_capabilities();
$filters_caps = new \Tainacan\Entities\Filter(); $filters_caps = new \Tainacan\Entities\Filter();
$filters_caps = $filters_caps->get_capabilities(); $filters_caps = $filters_caps->get_capabilities();
@ -699,6 +742,23 @@ class Roles {
$filters_caps->read_private_posts $filters_caps->read_private_posts
]; ];
$edit_meta_section = [
$meta_section_caps->edit_posts,
$meta_section_caps->edit_others_posts,
$meta_section_caps->publish_posts,
$meta_section_caps->delete_posts,
$meta_section_caps->delete_private_posts,
$meta_section_caps->delete_published_posts,
$meta_section_caps->delete_others_posts,
$meta_section_caps->edit_private_posts,
$meta_section_caps->edit_published_posts,
$meta_section_caps->create_posts,
];
$read_private_meta_section = [
$meta_section_caps->read_private_posts
];
if ( !is_array( $args ) || !array_key_exists( 0, $args ) ) { if ( !is_array( $args ) || !array_key_exists( 0, $args ) ) {
return $caps; return $caps;
} }
@ -713,6 +773,19 @@ class Roles {
foreach ($caps as $i => $c) { foreach ($caps as $i => $c) {
// Handle edit metadata section
if ( in_array($c, $edit_meta_section) ) {
if (is_numeric($object)) {
$object = tainacan_metadata_sections()->fetch ( (int) $object );
}
if ( $object instanceof \Tainacan\Entities\Metadata_Section ) {
if ( is_numeric($object->get_collection_id()) ) {
unset($caps[$i]);
$caps[] = 'tnc_col_' . $object->get_collection_id() . '_' . $action. '_metasection';
}
}
}
// Handle edit metadata // Handle edit metadata
if ( in_array($c, $edit_meta) ) { if ( in_array($c, $edit_meta) ) {
if (is_numeric($object)) { if (is_numeric($object)) {
@ -755,6 +828,19 @@ class Roles {
foreach ($caps as $i => $c) { foreach ($caps as $i => $c) {
// Handle read private metadata section
if ( in_array($c, $read_private_meta_section) ) {
if (is_numeric($object)) {
$object = tainacan_metadata_sections()->fetch ( (int) $object );
}
if ( $object instanceof \Tainacan\Entities\Metadata_Section ) {
if ( is_numeric($object->get_collection_id()) ) {
unset($caps[$i]);
$caps[] = 'tnc_col_' . $object->get_collection_id() . '_read_private_metasection';
}
}
}
// Handle read private metadata // Handle read private metadata
if ( in_array($c, $read_private_meta) ) { if ( in_array($c, $read_private_meta) ) {
if (is_numeric($object)) { if (is_numeric($object)) {

View File

@ -28,6 +28,7 @@ class Collection extends Entity {
$default_view_mode, $default_view_mode,
$enabled_view_modes, $enabled_view_modes,
$metadata_order, $metadata_order,
$metadata_section_order,
$filters_order, $filters_order,
$enable_cover_page, $enable_cover_page,
$cover_page_id, $cover_page_id,
@ -405,12 +406,21 @@ class Collection extends Entity {
/** /**
* Get collection metadata ordination * Get collection metadata ordination
* *
* @return string * @return Object | string
*/ */
function get_metadata_order() { function get_metadata_order() {
return $this->get_mapped_property( 'metadata_order' ); return $this->get_mapped_property( 'metadata_order' );
} }
/**
* Get collection metadata section ordination
*
* @return Array | Object | string
*/
function get_metadata_section_order() {
return $this->get_mapped_property( 'metadata_section_order' );
}
/** /**
* Get enable cover page attribute * Get enable cover page attribute
* *
@ -594,6 +604,17 @@ class Collection extends Entity {
return $this->get_mapped_property( 'submission_use_recaptcha' ); return $this->get_mapped_property( 'submission_use_recaptcha' );
} }
/**
* Get the default metadata section properties.
*
* @param [string] $value
*
* @return void
*/
function get_default_metadata_section_properties( ) {
return $this->get_mapped_property( 'default_metadata_section_properties' );
}
/** /**
* Set the collection name * Set the collection name
* *
@ -721,6 +742,24 @@ class Collection extends Entity {
$this->set_mapped_property( 'metadata_order', $value ); $this->set_mapped_property( 'metadata_order', $value );
} }
/**
* Set collection metadata section ordination
*
* @param [string] $value
*
* @return void
*/
function set_metadata_section_order( $value ) {
if( !empty($value) ) {
$metadata_order = array( );
foreach($value as $section) {
$metadata_order = array_merge($metadata_order, $section['metadata_order']);
}
$this->set_metadata_order($metadata_order);
}
$this->set_mapped_property( 'metadata_section_order', $value );
}
/** /**
* Set collection filters ordination * Set collection filters ordination
* *
@ -838,6 +877,17 @@ class Collection extends Entity {
return $this->set_mapped_property( 'submission_use_recaptcha', $value); return $this->set_mapped_property( 'submission_use_recaptcha', $value);
} }
/**
* Set the default metadata section properties.
*
* @param [string] $value
*
* @return void
*/
function set_default_metadata_section_properties( $value ) {
return $this->set_mapped_property( 'default_metadata_section_properties', $value);
}
/** /**
* Validate Collection * Validate Collection
* *
@ -857,6 +907,20 @@ class Collection extends Entity {
return false; return false;
} }
$metadata_section_order = $this->get_metadata_section_order();
if ( isset($metadata_section_order['metadata_section_order']) ) {
$section_order = $metadata_section_order['metadata_section_order'];
$metadata_order = $this->get_metadata_order();
$order_general = array();
foreach($section_order as $section) {
$order_general = array_merge($order_general, $section['metadata_order']);
}
if( count($order_general) != count($metadata_order) ) {
return false;
}
}
return parent::validate(); return parent::validate();
} }

View File

@ -14,49 +14,49 @@ class Entity {
* @var \Tainacan\Repositories\Repository * @var \Tainacan\Repositories\Repository
*/ */
protected $repository; protected $repository;
/** /**
* Array of errors, for example, register validations errors * Array of errors, for example, register validations errors
* @var array * @var array
*/ */
private $errors = []; private $errors = [];
/** /**
* The WordPress post_type for store this class if is needed, false otherwise * The WordPress post_type for store this class if is needed, false otherwise
* @var string * @var string
*/ */
protected static $post_type = false; protected static $post_type = false;
/** /**
* The WordPress capability for the entity post type. Default is to be equal to $post_type * The WordPress capability for the entity post type. Default is to be equal to $post_type
* @var string * @var string
*/ */
protected static $capability_type = false; protected static $capability_type = false;
/** /**
* Store the WordPress post object * Store the WordPress post object
* @var \WP_Post * @var \WP_Post
*/ */
public $WP_Post; public $WP_Post;
/** /**
* Indicates wether an entity was validated, calling the validate() method * Indicates wether an entity was validated, calling the validate() method
* *
* Entities MUST be validated before attempt to save * Entities MUST be validated before attempt to save
* *
* @var boolean * @var boolean
*/ */
private $validated = false; private $validated = false;
/** /**
* Capabilities of the post_type, one of: * Capabilities of the post_type, one of:
* - edit_posts - Controls whether objects of this post type can be edited. * - edit_posts - Controls whether objects of this post type can be edited.
* - edit_others_posts - Controls whether objects of this type owned by other users * - edit_others_posts - Controls whether objects of this type owned by other users
* can be edited. If the post type does not support an author, then this will * can be edited. If the post type does not support an author, then this will
* behave like edit_posts. * behave like edit_posts.
* - publish_posts - Controls publishing objects of this post type. * - publish_posts - Controls publishing objects of this post type.
* - read_private_posts - Controls whether private objects can be read. * - read_private_posts - Controls whether private objects can be read.
* - read - Controls whether objects of this post type can be read. * - read - Controls whether objects of this post type can be read.
* - delete_posts - Controls whether objects of this post type can be deleted. * - delete_posts - Controls whether objects of this post type can be deleted.
* - delete_private_posts - Controls whether private objects can be deleted. * - delete_private_posts - Controls whether private objects can be deleted.
* - delete_published_posts - Controls whether published objects can be deleted. * - delete_published_posts - Controls whether published objects can be deleted.
@ -65,9 +65,9 @@ class Entity {
* behave like delete_posts. * behave like delete_posts.
* - edit_private_posts - Controls whether private objects can be edited. * - edit_private_posts - Controls whether private objects can be edited.
* - edit_published_posts - Controls whether published objects can be edited. * - edit_published_posts - Controls whether published objects can be edited.
* @var object * @var object
*/ */
public $cap; public $cap;
/** /**
* Create an instance of Entity * Create an instance of Entity
@ -80,65 +80,65 @@ class Entity {
* *
* @throws \Exception * @throws \Exception
*/ */
function __construct($which = 0) { function __construct($which = 0) {
if (is_numeric($which) && $which > 0) { if (is_numeric($which) && $which > 0) {
$post = get_post($which); $post = get_post($which);
if ($post instanceof \WP_Post) { if ($post instanceof \WP_Post) {
$this->WP_Post = get_post($which); $this->WP_Post = get_post($which);
} else { } else {
throw new \Exception( 'No entity was found with ID ' . $which ); throw new \Exception( 'No entity was found with ID ' . $which );
} }
} elseif ($which instanceof \WP_Post) { } elseif ($which instanceof \WP_Post) {
$this->WP_Post = $which; $this->WP_Post = $which;
} elseif ( // is a stdClass Post object, like returned by delete } elseif ( // is a stdClass Post object, like returned by delete
$which instanceof \stdClass && $which instanceof \stdClass &&
property_exists($which, 'post_type') && property_exists($which, 'post_type') &&
property_exists($which, 'ID') && property_exists($which, 'ID') &&
property_exists($which, 'post_status') property_exists($which, 'post_status')
) { ) {
$this->WP_Post = new \WP_Post($which); $this->WP_Post = new \WP_Post($which);
} elseif (is_array($which) && isset($which['ID'])) { } elseif (is_array($which) && isset($which['ID'])) {
$this->WP_Post = new \WP_Post( (object)$which ); $this->WP_Post = new \WP_Post( (object)$which );
} else { } else {
$this->WP_Post = new \StdClass(); $this->WP_Post = new \StdClass();
} }
$collection_pt_pattern = '/' . Collection::$db_identifier_prefix . '\d+' . Collection::$db_identifier_sufix . '/'; $collection_pt_pattern = '/' . Collection::$db_identifier_prefix . '\d+' . Collection::$db_identifier_sufix . '/';
if( if(
$this->WP_Post instanceof \WP_Post && $this->WP_Post instanceof \WP_Post &&
isset( $this->WP_Post->ID ) && isset( $this->WP_Post->ID ) &&
( (
( $this->get_post_type() !== false && $this->WP_Post->post_type != $this->get_post_type() ) || ( $this->get_post_type() !== false && $this->WP_Post->post_type != $this->get_post_type() ) ||
// Lets check if it is a collection and have rigth post_type // Lets check if it is a collection and have rigth post_type
( $this->get_post_type() === false && $this->WP_Post->post_type && ! preg_match($collection_pt_pattern, $this->WP_Post->post_type) ) ( $this->get_post_type() === false && $this->WP_Post->post_type && ! preg_match($collection_pt_pattern, $this->WP_Post->post_type) )
) )
) { ) {
if($this->get_post_type() === false) { if($this->get_post_type() === false) {
throw new \Exception('the returned post is not the same type of the entity! expected: '.Collection::$db_identifier_prefix.$this->get_db_identifier().Collection::$db_identifier_sufix.' and actual: '.$this->WP_Post->post_type ); throw new \Exception('the returned post is not the same type of the entity! expected: '.Collection::$db_identifier_prefix.$this->get_db_identifier().Collection::$db_identifier_sufix.' and actual: '.$this->WP_Post->post_type );
} }
else { else {
throw new \Exception('the returned post is not the same type of the entity! expected: '.$this->get_post_type().' and actual: '.$this->WP_Post->post_type ); throw new \Exception('the returned post is not the same type of the entity! expected: '.$this->get_post_type().' and actual: '.$this->WP_Post->post_type );
} }
} }
if($this->get_post_type() !== false) { if($this->get_post_type() !== false) {
$this->cap = $this->get_capabilities(); $this->cap = $this->get_capabilities();
} elseif ($this instanceof Item) { } elseif ($this instanceof Item) {
$item_collection = $this->get_collection(); $item_collection = $this->get_collection();
if ($item_collection) { if ($item_collection) {
$this->cap = $item_collection->get_items_capabilities(); $this->cap = $item_collection->get_items_capabilities();
} }
} }
} }
public function get_repository() { public function get_repository() {
$namespace = '\Tainacan\Repositories\\'.$this->repository; $namespace = '\Tainacan\Repositories\\'.$this->repository;
$repository = $namespace::get_instance(); $repository = $namespace::get_instance();
return $repository; return $repository;
} }
/** /**
* @param $date * @param $date
@ -156,52 +156,52 @@ class Entity {
return ''; return '';
} }
/** /**
* return the value for a mapped property * return the value for a mapped property
* @param string $prop id of property * @param string $prop id of property
* @return mixed property value * @return mixed property value
*/ */
public function get_mapped_property($prop) { public function get_mapped_property($prop) {
if ( isset($this->$prop) ){ if ( isset($this->$prop) ){
return $this->$prop; return $this->$prop;
} }
//prop is not set at object, try to get from database //prop is not set at object, try to get from database
$repository = $this->get_repository(); $repository = $this->get_repository();
$value = $repository->get_mapped_property($this, $prop); $value = $repository->get_mapped_property($this, $prop);
return apply_filters('tainacan-entity-get-property', $value, $prop, $this); return apply_filters('tainacan-entity-get-property', $value, $prop, $this);
} }
/**
* set the value of a mapped property
*
* This is a protected method. If you want to set an entity prop
* using the prop name dynamically, use the set() method
*
* @param string $prop id of the property
* @param mixed $value the value to be setted
*/
protected function set_mapped_property($prop, $value) {
$this->set_validated(false);
$value = apply_filters('tainacan-entity-set-property', $value, $prop, $this);
$this->$prop = $value;
}
/** /**
* set the value property * set the value of a mapped property
* *
* * This is a protected method. If you want to set an entity prop
* @param string $prop id of the property * using the prop name dynamically, use the set() method
* @param mixed $value the value to be setted *
* @return null|mixed Null on failure, the value that was set on success * @param string $prop id of the property
*/ * @param mixed $value the value to be setted
public function set($prop, $value) { */
$method = 'set_' . $prop; protected function set_mapped_property($prop, $value) {
$this->set_validated(false);
$value = apply_filters('tainacan-entity-set-property', $value, $prop, $this);
$this->$prop = $value;
}
/**
* set the value property
*
*
* @param string $prop id of the property
* @param mixed $value the value to be setted
* @return null|mixed Null on failure, the value that was set on success
*/
public function set($prop, $value) {
$method = 'set_' . $prop;
if ( method_exists($this, $method) ) { if ( method_exists($this, $method) ) {
return $this->$method($value); return $this->$method($value);
} }
} }
/** /**
* get the value property * get the value property
@ -217,162 +217,162 @@ class Entity {
} }
} }
/** /**
* set the status of the entity * set the status of the entity
* @param string $value * @param string $value
*/ */
public function set_status($value){ public function set_status($value){
$value = apply_filters('tainacan-set-post-status', $value); $value = apply_filters('tainacan-set-post-status', $value);
$this->set_mapped_property('status', $value); $this->set_mapped_property('status', $value);
} }
/** /**
* Validate the class values/properties, to be used before insert/save/update * Validate the class values/properties, to be used before insert/save/update
* *
* If Entity is not valid, validation error messages are available via get_errors() method * If Entity is not valid, validation error messages are available via get_errors() method
* *
* @return boolean * @return boolean
*/ */
public function validate() { public function validate() {
$repository = $this->get_repository(); $repository = $this->get_repository();
$map = $repository->get_map(); $map = $repository->get_map();
$is_valid = true; $is_valid = true;
$this->reset_errors(); $this->reset_errors();
foreach ($map as $prop => $mapped) { foreach ($map as $prop => $mapped) {
if (!$this->validate_prop($prop)) { if (!$this->validate_prop($prop)) {
$is_valid = false; $is_valid = false;
} }
} }
if($is_valid){ if($is_valid){
$this->set_as_valid(); $this->set_as_valid();
} }
return $is_valid; return $is_valid;
} }
/** /**
* Validate a single property * Validate a single property
* @param string $prop id of the property to be validate * @param string $prop id of the property to be validate
* @return boolean * @return boolean
*/ */
public function validate_prop($prop) { public function validate_prop($prop) {
$repository = $this->get_repository(); $repository = $this->get_repository();
$map = $repository->get_map(); $map = $repository->get_map();
$mapped = $map[$prop]; $mapped = $map[$prop];
$is_valid = true; $is_valid = true;
if ( if (
isset($mapped['validation']) && isset($mapped['validation']) &&
is_object($mapped['validation']) && is_object($mapped['validation']) &&
method_exists($mapped['validation'], 'validate') method_exists($mapped['validation'], 'validate')
) { ) {
$validation = $mapped['validation']; $validation = $mapped['validation'];
$prop_value = $this->get_mapped_property($prop); $prop_value = $this->get_mapped_property($prop);
$message = ( isset( $mapped['on_error'] ) ) ? $mapped['on_error'] : $prop. __(' is invalid', 'tainacan'); $message = ( isset( $mapped['on_error'] ) ) ? $mapped['on_error'] : $prop. __(' is invalid', 'tainacan');
if (is_array($prop_value)) { if (is_array($prop_value)) {
foreach ($prop_value as $val) { foreach ($prop_value as $val) {
if (!$validation->validate($val)) { if (!$validation->validate($val)) {
$this->add_error($prop, $message); $this->add_error($prop, $message);
$is_valid = false; $is_valid = false;
} }
} }
} else { } else {
if (!$validation->validate($prop_value)) { if (!$validation->validate($prop_value)) {
$this->add_error($prop, $message); $this->add_error($prop, $message);
$is_valid = false; $is_valid = false;
} }
} }
} }
return $is_valid; return $is_valid;
} }
public function get_errors() { public function get_errors() {
return $this->errors; return $this->errors;
} }
public static function get_post_type() { public static function get_post_type() {
return static::$post_type; return static::$post_type;
} }
public static function get_capability_type() { public static function get_capability_type() {
return false !== static::$capability_type ? static::$capability_type : static::$post_type; return false !== static::$capability_type ? static::$capability_type : static::$post_type;
} }
public function get_status(){ public function get_status(){
$value = $this->get_mapped_property('status'); $value = $this->get_mapped_property('status');
if(empty($value)) $value = 'draft'; if(empty($value)) $value = 'draft';
return apply_filters('tainacan-get-post-status', $value); return apply_filters('tainacan-get-post-status', $value);
} }
/** /**
* Get entity DB identifier * Get entity DB identifier
* *
* This identifier is used to register the entity on database, ex.: post_type * This identifier is used to register the entity on database, ex.: post_type
* *
* @return string * @return string
*/ */
function get_db_identifier() { function get_db_identifier() {
return self::get_post_type(); return self::get_post_type();
} }
/** /**
* Get the entity ID * Get the entity ID
* *
* @return integer * @return integer
*/ */
public function get_id() { public function get_id() {
return $this->get_mapped_property('id'); return $this->get_mapped_property('id');
} }
public function add_error($type, $message) { public function add_error($type, $message) {
$this->errors[] = [$type => $message]; $this->errors[] = [$type => $message];
$this->set_validated(false); $this->set_validated(false);
} }
/** /**
* Clear the errors array * Clear the errors array
*/ */
public function reset_errors() { public function reset_errors() {
$this->errors = []; $this->errors = [];
} }
public function get_validated() { public function get_validated() {
return $this->validated; return $this->validated;
} }
protected function set_validated($value) { protected function set_validated($value) {
$this->validated = $value; $this->validated = $value;
} }
protected function set_as_valid() { protected function set_as_valid() {
$this->reset_errors(); $this->reset_errors();
$this->set_validated(true); $this->set_validated(true);
return true; return true;
} }
public function _toArray(){ public function _toArray(){
$repository = $this->get_repository(); $repository = $this->get_repository();
$map = $repository->get_map(); $map = $repository->get_map();
$attributes = []; $attributes = [];
foreach($map as $prop => $content) { foreach($map as $prop => $content) {
$attributes[$prop] = $this->get($prop); $attributes[$prop] = $this->get($prop);
} }
$hook_prefix = self::get_post_type(); $hook_prefix = self::get_post_type();
return apply_filters("{$hook_prefix}-to-array", $attributes, $this); return apply_filters("{$hook_prefix}-to-array", $attributes, $this);
} }
public function _toJson(){ public function _toJson(){
return json_encode($this->_toArray(), JSON_NUMERIC_CHECK); return json_encode($this->_toArray(), JSON_NUMERIC_CHECK);
@ -384,7 +384,7 @@ class Entity {
* @return bool * @return bool
*/ */
public function can_read($user = null) { public function can_read($user = null) {
$repository = $this->get_repository(); $repository = $this->get_repository();
return $repository->can_read($this, $user); return $repository->can_read($this, $user);
} }
@ -394,7 +394,7 @@ class Entity {
* @return bool * @return bool
*/ */
public function can_edit($user = null) { public function can_edit($user = null) {
$repository = $this->get_repository(); $repository = $this->get_repository();
return $repository->can_edit($this, $user); return $repository->can_edit($this, $user);
} }
@ -404,7 +404,7 @@ class Entity {
* @return bool * @return bool
*/ */
public function can_delete($user = null) { public function can_delete($user = null) {
$repository = $this->get_repository(); $repository = $this->get_repository();
return $repository->can_delete($this, $user); return $repository->can_delete($this, $user);
} }
@ -414,7 +414,7 @@ class Entity {
* @return bool * @return bool
*/ */
public function can_publish($user = null) { public function can_publish($user = null) {
$repository = $this->get_repository(); $repository = $this->get_repository();
return $repository->can_publish($this, $user); return $repository->can_publish($this, $user);
} }
@ -429,7 +429,7 @@ class Entity {
* @return object Object with all the capabilities as member variables. * @return object Object with all the capabilities as member variables.
*/ */
public function get_capabilities() { public function get_capabilities() {
$args = [ $args = [
'map_meta_cap' => true, 'map_meta_cap' => true,
'capability_type' => self::get_capability_type(), 'capability_type' => self::get_capability_type(),
'capabilities' => array() 'capabilities' => array()
@ -444,7 +444,7 @@ class Entity {
* @return array * @return array
*/ */
public function diff($which = 0) { public function diff($which = 0) {
$repository = $this->get_repository(); $repository = $this->get_repository();
return $repository->diff($which, $this); return $repository->diff($which, $this);
} }

View File

@ -19,7 +19,8 @@ class Filter extends Entity {
$metadatum_id, $metadatum_id,
$max_options, $max_options,
$filter_type, $filter_type,
$filter_type_options; $filter_type_options,
$begin_with_filter_collapsed;
static $post_type = 'tainacan-filter'; static $post_type = 'tainacan-filter';
public $enabled_for_collection = true; public $enabled_for_collection = true;
@ -178,6 +179,16 @@ class Filter extends Entity {
return $this->get_mapped_property('filter_type_options'); return $this->get_mapped_property('filter_type_options');
} }
/**
* Return 'yes' or 'no' to the option of begining the filter collapsed
*
* @return string
*/
public function get_begin_with_filter_collapsed() {
return $this->get_mapped_property('begin_with_filter_collapsed');
}
/** /**
* Define the filter name * Define the filter name
* *
@ -248,9 +259,17 @@ class Filter extends Entity {
* @param string | \Tainacan\Filter_Types\Filter_Type $value The name of the class or the instance * @param string | \Tainacan\Filter_Types\Filter_Type $value The name of the class or the instance
*/ */
public function set_filter_type($value){ public function set_filter_type($value){
$this->set_mapped_property('filter_type', ( is_object( $value ) ) ? get_class( $value ) : $value ); $this->set_mapped_property('filter_type', ( is_object( $value ) ) ? get_class( $value ) : $value );
} }
/**
* Tells if filter should begin collapsed, not loading facets
*
* @param string $begin_with_filter_collapsed
*/
public function set_begin_with_filter_collapsed($begin_with_filter_collapsed) {
$this->set_mapped_property('begin_with_filter_collapsed', $begin_with_filter_collapsed);
}
/** /**
* Transient property used to store the status of the filter for a particular collection * Transient property used to store the status of the filter for a particular collection

View File

@ -500,6 +500,9 @@ class Item_Metadata_Entity extends Entity {
$one_filled = true; $one_filled = true;
if ($this->is_collection_key()) { if ($this->is_collection_key()) {
if ( !isset($dupe_array[$val]) ) {
$dupe_array[$val] = 1;
} else
if (++$dupe_array[$val] > 1) { if (++$dupe_array[$val] > 1) {
$this->add_error( 'key_exists', sprintf( __('%s is a collection key and there is another item with the same value', 'tainacan'), $metadatum->get_name() ) ); $this->add_error( 'key_exists', sprintf( __('%s is a collection key and there is another item with the same value', 'tainacan'), $metadatum->get_name() ) );
return false; return false;
@ -553,7 +556,31 @@ class Item_Metadata_Entity extends Entity {
if ($this->is_collection_key()) { if ($this->is_collection_key()) {
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance(); $Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
if($metadatum->get_parent()) {
$patent_metadatum = \tainacan_metadata()->fetch( $metadatum->get_parent(), 'OBJECT' );
if($patent_metadatum->is_multiple()) {
global $wpdb;
$test = get_post_meta( $item->get_id(), $this->metadatum->get_id(), true);
$rows = $wpdb->get_results(
$wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = %s AND meta_value = %s AND meta_id <> %d",
$item->get_id(), $this->metadatum->get_id(), $value, $this->get_meta_id()),
ARRAY_A );
if ( is_array( $rows ) && count($rows) > 0 ) {
if( !$this->get_meta_id() ) {
$current_meta_value = array_column($rows, "meta_value");
if ( count($current_meta_value) !== count(array_unique($current_meta_value)) ) {
// translators: %s = metadatum name. ex: Register ID is a collection key and there is another item with the same value
$this->add_error( 'key_exists', sprintf( __('%s is a collection key and there is another item with the same value', 'tainacan'), $metadatum->get_name() ) );
return false;
}
} else {
// translators: %s = metadatum name. ex: Register ID is a collection key and there is another item with the same value
$this->add_error( 'key_exists', sprintf( __('%s is a collection key and there is another item with the same value', 'tainacan'), $metadatum->get_name() ) );
return false;
}
}
}
}
$test = $Tainacan_Items->fetch([ $test = $Tainacan_Items->fetch([
'meta_query' => [ 'meta_query' => [
[ [

View File

@ -539,10 +539,8 @@ class Item extends Entity {
* *
* @type bool $hide_empty Wether to hide or not metadata the item has no value to * @type bool $hide_empty Wether to hide or not metadata the item has no value to
* Default: true * Default: true
*
* @type string $empty_value_message Message string to display if $hide_empty is false and there is not metadata value. * @type string $empty_value_message Message string to display if $hide_empty is false and there is not metadata value.
* Default: '' * Default: ''
*
* @type bool $display_slug_as_class Show metadata slug as a class in the div before the metadata block * @type bool $display_slug_as_class Show metadata slug as a class in the div before the metadata block
* Default: false * Default: false
* @type string $before String to be added before each metadata block * @type string $before String to be added before each metadata block
@ -569,42 +567,52 @@ class Item extends Entity {
$return = ''; $return = '';
$defaults = array( $defaults = array(
'metadata' => null, 'metadata' => null,
'metadata__in' => null, 'metadata__in' => null,
'metadata__not_in' => null, 'metadata__not_in' => null,
'exclude_title' => false, 'exclude_title' => false,
'exclude_description' => false, 'exclude_description' => false,
'exclude_core' => false, 'exclude_core' => false,
'hide_empty' => true, 'hide_empty' => true,
'empty_value_message' => '', 'empty_value_message' => '',
'display_slug_as_class' => false, 'display_slug_as_class' => false,
'before' => '<div class="metadata-type-$type $id">', 'before' => '<div class="metadata-type-$type" $id>',
'after' => '</div>', 'after' => '</div>',
'before_title' => '<h3>', 'before_title' => '<h3>',
'after_title' => '</h3>', 'after_title' => '</h3>',
'before_value' => '<p>', 'before_value' => '<p>',
'after_value' => '</p>', 'after_value' => '</p>'
); );
$args = wp_parse_args($args, $defaults); $args = wp_parse_args($args, $defaults);
$item_metadata = array();
if (!is_null($args['metadata'])) { // If a single metadata is passed, we use it instead of fetching more
if ( !is_null($args['metadata']) ) {
$metadatum = $args['metadata']; $metadatum = $args['metadata'];
$metadatum_object = null; $metadatum_object = null;
// A metadatum object was passed
if ( $metadatum instanceof \Tainacan\Entities\Metadatum ) { if ( $metadatum instanceof \Tainacan\Entities\Metadatum ) {
$metadatum_object = $metadatum; $metadatum_object = $metadatum;
// A metadatum ID was passed
} elseif ( is_int($metadatum) ) { } elseif ( is_int($metadatum) ) {
$metadatum_object = $Tainacan_Metadata->fetch($metadatum); $metadatum_object = $Tainacan_Metadata->fetch($metadatum);
// A metadatum slug was passed
} elseif ( is_string($metadatum) ) { } elseif ( is_string($metadatum) ) {
$query = $Tainacan_Metadata->fetch(['slug' => $metadatum], 'OBJECT'); $query = $Tainacan_Metadata->fetch(['slug' => $metadatum], 'OBJECT');
if ( is_array($query) && sizeof($query) == 1 && isset($metadatum[0])) { if ( is_array($query) && sizeof($query) == 1 && isset($metadatum[0])) {
$metadatum_object = $metadatum[0]; $metadatum_object = $metadatum[0];
} }
} }
if ( $metadatum_object instanceof \Tainacan\Entities\Metadatum ) {
// Some checks to see if things are really ok
if ( !($metadatum instanceof \Tainacan\Entities\Metadatum) ) {
return $return;
} else {
// Makes sure the current Metadatum is desired
if ( is_array($args['metadata__not_in']) if ( is_array($args['metadata__not_in'])
&& ( && (
in_array($metadatum_object->get_slug(), $args['metadata__not_in']) || in_array($metadatum_object->get_slug(), $args['metadata__not_in']) ||
@ -613,114 +621,211 @@ class Item extends Entity {
) { ) {
return $return; return $return;
} }
}
$mto = $metadatum_object->get_metadata_type_object(); // Add it to the array which will be looped bellow
$item_meta = new \Tainacan\Entities\Item_Metadata_Entity($this, $metadatum_object); $item_metadata[] = new \Tainacan\Entities\Item_Metadata_Entity($this, $metadatum_object);
if ($item_meta->has_value() || !$args['hide_empty']) {
$before = str_replace('$type', $mto->get_slug(), $args['before']); // If not single metadatum is passed, we query them
if ($args['display_slug_as_class']) { } else {
$before = str_replace('$id', 'metadata-slug-'.$item_meta->get_metadatum()->get_slug() , $before);
// Build query args ready to be passed to the API fetch
$query_args = [];
$post__in = [];
$post__not_in = [];
$post__name_in = [];
if (is_array($args['metadata__in'])) {
$post__in[] = -1; // If metadata__in is an empty array, this forces empty result
foreach ($args['metadata__in'] as $meta) {
if (is_numeric($meta)) {
$post__in[] = $meta;
} elseif (is_string($meta)) {
$post__name_in[] = $meta;
} }
else { }
$before = str_replace(' $id', '', $before); }
if (is_array($args['metadata__not_in'])) {
foreach ($args['metadata__not_in'] as $meta) {
if (is_integer($meta)) {
$post__not_in[] = $meta;
} }
$return .= $before;
$return .= $args['before_title'] . $metadatum_object->get_name() . $args['after_title'];
$return .= $args['before_value'] . ( $item_meta->has_value() ? $item_meta->get_value_as_html() : $args['empty_value_message'] ) . $args['after_value'];
$return .= $args['after'];
} }
} }
return wp_kses_tainacan($return); if (sizeof($post__in) > 0) {
$query_args['post__in'] = $post__in;
}
$query_args = [];
$post__in = [];
$post__not_in = [];
$post__name_in = [];
if (is_array($args['metadata__in'])) {
$post__in[] = -1; // If metadata__in is an empty array, this forces empty result
foreach ($args['metadata__in'] as $meta) {
if (is_numeric($meta)) {
$post__in[] = $meta;
} elseif (is_string($meta)) {
$post__name_in[] = $meta;
}
} }
} if (sizeof($post__not_in) > 0) {
if (is_array($args['metadata__not_in'])) { $query_args['post__not_in'] = $post__not_in;
foreach ($args['metadata__not_in'] as $meta) {
if (is_integer($meta)) {
$post__not_in[] = $meta;
}
} }
if (sizeof($post__name_in) > 0) {
$query_args['post__name_in'] = $post__name_in;
}
// Get the item metadata objects from the item repository
$item_metadata = $this->get_metadata($query_args);
} }
if (sizeof($post__in) > 0) { // Loop item metadata to print their "values" as html
$query_args['post__in'] = $post__in; $metadatum_index = 0;
} foreach ( $item_metadata as $item_metadatum ) {
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;
}
// Gets the metadata type object to perform some checks
$metadata_type_object = $item_metadatum->get_metadatum()->get_metadata_type_object();
$metadata = $this->get_metadata($query_args); // Core metadata may not be desired as they may be displayed differently
if ( $metadata_type_object->get_core() ) {
foreach ( $metadata as $item_meta ) {
$fto = $item_meta->get_metadatum()->get_metadata_type_object();
if ( $fto->get_core() ) {
if ( $args['exclude_core'] ) { if ( $args['exclude_core'] ) {
continue; continue;
} elseif ( $args['exclude_title'] && $fto->get_related_mapped_prop() == 'title' ) { } elseif ( $args['exclude_title'] && $metadata_type_object->get_related_mapped_prop() == 'title' ) {
continue; continue;
} elseif ( $args['exclude_description'] && $fto->get_related_mapped_prop() == 'description' ) { } elseif ( $args['exclude_description'] && $metadata_type_object->get_related_mapped_prop() == 'description' ) {
continue; continue;
} }
} }
if ($item_meta->has_value() || !$args['hide_empty']) { // Get the metadatum representation in html, with its label and value
$before = str_replace('$type', $fto->get_slug(), $args['before']); $return .= $this->get_item_metadatum_as_html($item_metadatum, $args, $metadatum_index);
if ($args['display_slug_as_class']) {
$before = str_replace('$id', 'metadata-slug-'.$item_meta->get_metadatum()->get_slug() , $before);
}
else {
$before = str_replace(' $id', '', $before);
}
$return .= $before;
$return .= $args['before_title'] . $item_meta->get_metadatum()->get_name() . $args['after_title'];
$return .= $args['before_value'] . ( $item_meta->has_value() ? $item_meta->get_value_as_html() : $args['empty_value_message'] ) . $args['after_value'];
$return .= $args['after'];
} $metadatum_index++;
} }
// Returns the html content created by the function
return wp_kses_tainacan($return); return wp_kses_tainacan($return);
} }
/**
* Return a single item metadata as a HTML string to be used as output.
*
* Each metadata is a label with the metadatum name and the value.
*
* This function expects a $item_metadatum object. For a more generic approach, check the get_metadata_as_html function
*
* @param object $item_metadatum The Item Metadatum object
* @param array|string $args {
* Optional. Array or string of arguments.
*
* @type bool $hide_empty Wether to hide or not metadata the item has no value to
* Default: true
* @type string $empty_value_message Message string to display if $hide_empty is false and there is not metadata value.
* Default: ''
* @type bool $display_slug_as_class Show metadata slug as a class in the div before the metadata block
* Default: false
* @type string $before String to be added before each metadata block
* Default '<div class="metadata-type-$type">' where $type is the metadata type slug
* @type string $after String to be added after each metadata block
* Default '</div>'
* @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 int $section_index The Metadatum index, if passed from an array
*
* @return string The HTML output
*/
public function get_item_metadatum_as_html($item_metadatum, $args = array(), $metadatum_index = null) {
$return = '';
$defaults = array(
'hide_empty' => true,
'empty_value_message' => '',
'display_slug_as_class' => false,
'before' => '<div class="metadata-type-$type" $id>',
'after' => '</div>',
'before_title' => '<h3>',
'after_title' => '</h3>',
'before_value' => '<p>',
'after_value' => '</p>'
);
$args = wp_parse_args($args, $defaults);
if ($item_metadatum->has_value() || !$args['hide_empty']) {
// Gets the metadata type object to use it if we need the slug
$metadata_type_object = $item_metadatum->get_metadatum()->get_metadata_type_object();
// Get metadatum wrapper tag.
$before = str_replace('$type', $metadata_type_object->get_slug(), $args['before']);
// Adds class with slug and adds metadatum id
if ($args['display_slug_as_class']) {
if ( !strpos($before, 'class="') ) {
$before = str_replace('>', ' class="metadata-slug-'. $item_metadatum->get_metadatum()->get_slug() . '">', $before);
} else
$before = str_replace('class="', 'class="metadata-slug-'. $item_metadatum->get_metadatum()->get_slug() . ' ', $before);
}
$before = str_replace('$id', ' id="metadata-id-' . $item_metadatum->get_metadatum()->get_id() . '"', $before);
// Let theme authors tweak the wrapper opener
$before = apply_filters( 'tainacan-get-item-metadatum-as-html-before', $before, $item_metadatum );
$before = apply_filters( 'tainacan-get-item-metadatum-as-html-before--type-' . $item_metadatum->get_metadatum()->get_metadata_type(), $before, $item_metadatum );
$before = apply_filters( 'tainacan-get-item-metadatum-as-html-before--id-' . $item_metadatum->get_metadatum()->get_id(), $before, $item_metadatum );
if ( is_numeric($metadatum_index) ) {
$before = apply_filters( 'tainacan-get-item-metadatum-as-html-before--index-' . $metadatum_index, $before, $item_metadatum );
}
// Renders the metadatum opener
$return .= $before;
// Renders the metadatum name
$metadatum_title_before = $args['before_title'];
$metadatum_title_before = apply_filters( 'tainacan-get-item-metadatum-as-html-before-title', $metadatum_title_before, $item_metadatum );
$metadatum_title_after = $args['after_title'];
$metadatum_title_after = apply_filters( 'tainacan-get-item-metadatum-as-html-after-title', $metadatum_title_after, $item_metadatum );
$return .= $metadatum_title_before . $item_metadatum->get_metadatum()->get_name() . $metadatum_title_after;
// Renders the metadatum value
$metadatum_value_before = $args['before_value'];
$metadatum_value_before = apply_filters( 'tainacan-get-item-metadatum-as-html-before-value', $metadatum_value_before, $item_metadatum );
$metadatum_value_after = $args['after_value'];
$metadatum_value_after = apply_filters( 'tainacan-get-item-metadatum-as-html-after-value', $metadatum_value_after, $item_metadatum );
$return .= $metadatum_value_before . ( $item_metadatum->has_value() ? $item_metadatum->get_value_as_html() : $args['empty_value_message'] ) . $metadatum_value_after;
$after = $args['after'];
// Let theme authors tweak the wrapper closer
if ( is_numeric($metadatum_index) ) {
$after = apply_filters( 'tainacan-get-item-metadatum-as-html-after--index-' . $metadatum_index, $after, $item_metadatum );
}
$after = apply_filters( 'tainacan-get-item-metadatum-as-html-after--id-' . $item_metadatum->get_metadatum()->get_id(), $after, $item_metadatum );
$after = apply_filters( 'tainacan-get-item-metadatum-as-html-after--type-' . $item_metadatum->get_metadatum()->get_metadata_type(), $after, $item_metadatum );
$after = apply_filters( 'tainacan-get-item-metadatum-as-html-after', $after, $item_metadatum );
// Closes the wrapper
$return .= $after;
}
// Returns the html content created by the function
return $return;
}
/**
* Gets the document as a html. May be a text, link, iframe, image, audio...
*/
public function get_document_as_html($img_size = 'large') { public function get_document_as_html($img_size = 'large') {
$type = $this->get_document_type(); $type = $this->get_document_type();
$document_options = $this->get_document_options(); $document_options = $this->get_document_options();
$output = ''; $output = '';
if ( $type == 'url' ) { if ( $type == 'url' ) {
global $wp_embed; global $wp_embed;
$_embed = $wp_embed->autoembed($this->get_document()); $_embed = $wp_embed->autoembed($this->get_document());
$url = $this->get_document(); $url = $this->get_document();
if ( $_embed == $url ) { if ( esc_url($_embed) == esc_url($url) ) {
if ( $document_options && isset($document_options['forced_iframe']) && $document_options['forced_iframe'] === true ) { if ( $document_options && isset($document_options['forced_iframe']) && $document_options['forced_iframe'] === true ) {
// URL points to an image file // URL points to an image file
if (isset($document_options['is_image']) && $document_options['is_image'] === true) { if (isset($document_options['is_image']) && $document_options['is_image'] === true) {
$_embed = sprintf('<a href="%s" target="blank"><img src="%s" /></a>', $url, $url); $_embed = sprintf('<a href="%s" target="blank"><img src="%s" /></a>', $url, $url);
@ -760,7 +865,7 @@ class Item extends Entity {
$embed = $wp_embed->autoembed($url); $embed = $wp_embed->autoembed($url);
if ( $embed == $url ) { if ( esc_url($embed) == esc_url($url) ) {
$output .= sprintf("<a href='%s' target='blank'>%s</a>", $url, $url); $output .= sprintf("<a href='%s' target='blank'>%s</a>", $url, $url);
} else { } else {
$tainacan_embed = \Tainacan\Embed::get_instance(); $tainacan_embed = \Tainacan\Embed::get_instance();
@ -775,7 +880,7 @@ class Item extends Entity {
} }
/** /**
* Gets the attachment as a html, can be iframe, image, audio... * Gets the attachment as a html. May be an iframe, image, audio...
*/ */
public function get_attachment_as_html($attachment, $img_size = 'large') { public function get_attachment_as_html($attachment, $img_size = 'large') {
@ -796,7 +901,7 @@ class Item extends Entity {
$embed = $wp_embed->autoembed($url); $embed = $wp_embed->autoembed($url);
if ( $embed == $url ) { if ( esc_url($embed) == esc_url($url) ) {
$output .= sprintf("<a href='%s' target='blank'>%s</a>", $url, $url); $output .= sprintf("<a href='%s' target='blank'>%s</a>", $url, $url);
} else { } else {
$tainacan_embed = \Tainacan\Embed::get_instance(); $tainacan_embed = \Tainacan\Embed::get_instance();
@ -851,4 +956,343 @@ class Item extends Entity {
$related_items = $Tainacan_Items->fetch_related_items($this, $args); $related_items = $Tainacan_Items->fetch_related_items($this, $args);
return $related_items; return $related_items;
} }
/**
* Return the item metadata sections as a HTML string to be used as output.
*
* Each metadata section is a label with the list of its metadata name and value.
*
* If an ID, a slug or a Tainacan\Entities\Metadata_Section object is passed in the 'metadata_section' argument, it returns only one metadata section, otherwise
* it returns all metadata section
*
* @param array|string $args {
* Optional. Array or string of arguments.
*
* @type mixed $metadata_section Metadatum object, ID or slug to retrieve only one metadatum. empty returns all metadata_sections
*
* @type array $metadata_sections__in Array of metadata_sections IDs or Slugs to be retrieved. Default none
*
* @type array $metadata_sections__not_in Array of metadata_sections IDs (slugs not accepted) to excluded. Default none
*
* @type bool $hide_name Do not display the Metadata Section name. Default false
*
* @type bool $hide_description Do not display the Metadata Section description. Default true
*
* @type bool $hide_empty Wether to hide or not metadata sections if there are no metadata list or they are empty
* Default: true
* @type string $empty_metadata_list_message Message string to display if $hide_empty is false and there is not metadata section metadata list.
* Default: ''
* @type string $before String to be added before each metadata section block
* Default '<section class="metadata-section-slug-$slug" id="$id">'
* @type string $after String to be added after each metadata section block
* Default '</section>'
* @type string $before_name String to be added before each metadata section name
* Default '<h2 id="metadata-section-$slug">'
* @type string $after_name String to be added after each metadata section name
* Default '</h2>'
* @type string $before_description String to be added before each metadata section description
* Default '<p>'
* @type string $after_description String to be added after each metadata section description
* Default '</p>'
* @type string $before_metadata_list String to be added before each metadata section inner metadata list
* Default '<div class="metadata-section__metadata-list" aria-labelledby="metadata-section-$slug">'
* @type string $after_metadata_list String to be added after each metadata section inner metadata list
* Default '</div>'
* @type array $metadata_list_args Arguments to be passed to the get_metadata_as_html function when calling section metadata
* }
*
* @return string The HTML output
*/
public function get_metadata_sections_as_html($args = array()) {
$Tainacan_Metadata_Sections = \Tainacan\Repositories\Metadata_Sections::get_instance();
$return = '';
$defaults = array(
'metadata_section' => null,
'metadata_sections__in' => null,
'metadata_sections__not_in' => null,
'hide_name' => false,
'hide_description' => true,
'hide_empty' => true,
'empty_metadata_list_message' => '',
'before' => '<section class="metadata-section-slug-$slug" id="$id">',
'after' => '</section>',
'before_name' => '<h2 id="metadata-section-$slug">',
'after_name' => '</h2>',
'before_metadata_list' => '<div class="metadata-section__metadata-list" aria-labelledby="metadata-section-$slug">',
'after_metadata_list' => '</div>',
'metadata_list_args' => []
);
$args = wp_parse_args($args, $defaults);
$metadata_sections = array();
// If a single metadata section is passed, we use it instead of fetching more
if ( !is_null($args['metadata_section']) ) {
$metadata_section = $args['metadata_section'];
$metadata_section_object = null;
// A metadata section object was passed
if ( $metadata_section instanceof \Tainacan\Entities\Metadata_Section ) {
$metadata_section_object = $metadata_section;
// A metadata section ID was passed
} elseif ( is_int($metadata_section) ) {
$metadata_section_object = $Tainacan_Metadata_Sections->fetch($metadata_section);
// A metadata section slug was passed
} elseif ( is_string($metadata_section) ) {
$query = $Tainacan_Metadata_Sections->fetch(['slug' => $metadata_section], 'OBJECT');
if ( is_array($query) && sizeof($query) == 1 && isset($metadata_section[0]) ) {
$metadata_section_object = $metadata_section[0];
}
}
// Some checks to see if things are really ok
if ( !($metadata_section_object instanceof \Tainacan\Entities\Metadata_Section) ) {
return $return;
} else {
// Makes sure the current Metadata Section is desired
if ( is_array($args['metadata_sections__not_in'])
&& (
in_array($metadata_section_object->get_slug(), $args['metadata_sections__not_in']) ||
in_array($metadata_section_object->get_id(), $args['metadata_sections__not_in'])
)
) {
return $return;
}
}
// Add it to the array which will be looped bellow
$metadata_sections[] = $metadata_section_object;
// If not single metadata section is passed, we query them
} else {
// Build query args ready to be passed to the API fetch
$query_args = [];
$post__in = [];
$post__not_in = [];
$post__name_in = [];
if (is_array($args['metadata_sections__in'])) {
$post__in[] = -1; // If metadata_sections__in is an empty array, this forces empty result
foreach ($args['metadata_sections__in'] as $metadata_section) {
if (is_numeric($metadata_section) || $metadata_section === \Tainacan\Entities\Metadata_Section::$default_section_slug) {
$post__in[] = $metadata_section;
} elseif (is_string($metadata_section)) {
$post__name_in[] = $metadata_section;
}
}
}
if (is_array($args['metadata_sections__not_in'])) {
foreach ($args['metadata_sections__not_in'] as $metadata_section) {
if (is_integer($metadata_section) || $metadata_section === \Tainacan\Entities\Metadata_Section::$default_section_slug) {
$post__not_in[] = $metadata_section;
}
}
}
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;
}
// Get metadata section objects from the metadata sections repository
$metadata_sections = $Tainacan_Metadata_Sections->fetch_by_collection($this->get_collection(), $query_args);
}
// Loop metadata sections to print their "values" as html
$section_index = 0;
foreach ( $metadata_sections as $metadata_section_object ) {
$return .= $this->get_metadata_section_as_html($metadata_section_object, $args, $section_index);
$section_index++;
}
// Returns the html content created by the function
return $return;
}
/**
* Return a single item metadata section as a HTML string to be used as output.
*
* A metadata section is a label with the list of its metadata name and value.
*
* This function expects a $metadata_section object. For a more generic approach, check the get_metadata_sections_as_html function
*
* @param object $metadata_section The Metadata Section object
* @param array|string $args {
* Optional. Array or string of arguments.
*
* @type bool $hide_name Do not display the Metadata Section name. Default false
*
* @type bool $hide_description Do not display the Metadata Section description. Default true
*
* @type bool $hide_empty Wether to hide or not metadata sections if there are no metadata list or they are empty
* Default: true
* @type string $empty_metadata_list_message Message string to display if $hide_empty is false and there is not metadata section metadata list.
* Default: ''
* @type string $before String to be added before each metadata section block
* Default '<section class="metadata-section-slug-$slug" id="$id">'
* @type string $after String to be added after each metadata section block
* Default '</section>'
* @type string $before_name String to be added before each metadata section name
* Default '<h2 id="metadata-section-$slug">'
* @type string $after_name String to be added after each metadata section name
* Default '</h2>'
* @type string $before_description String to be added before each metadata section description
* Default '<p>'
* @type string $after_description String to be added after each metadata section description
* Default '</p>'
* @type string $before_metadata_list String to be added before each metadata section inner metadata list
* Default '<div class="metadata-section__metadata-list" aria-labelledby="metadata-section-$slug">'
* @type string $after_metadata_list String to be added after each metadata section inner metadata list
* Default '</div>'
*
* @type array $metadata_list_args Arguments to be passed to the get_metadata_as_html function when calling section metadata
* }
* @param int $section_index The Metadata Section index, if passed from an array
*
* @return string The HTML output
*/
public function get_metadata_section_as_html($metadata_section, $args = array(), $section_index = null) {
$return = '';
$defaults = array(
'hide_name' => false,
'hide_description' => true,
'hide_empty' => true,
'empty_metadata_list_message' => '',
'before' => '<section class="metadata-section-slug-$slug" id="$id">',
'after' => '</section>',
'before_name' => '<h2 id="metadata-section-$slug">',
'after_name' => '</h2>',
'before_metadata_list' => '<div class="metadata-section__metadata-list" aria-labelledby="metadata-section-$slug">',
'after_metadata_list' => '</div>',
'metadata_list_args' => []
);
$args = wp_parse_args($args, $defaults);
// Gets the metadata section inner metadata list
$metadata_section_metadata_list = $metadata_section->get_metadata_object_list();
$has_metadata_list = (is_array($metadata_section_metadata_list) && count($metadata_section_metadata_list) > 0 );
if ( $has_metadata_list || !$args['hide_empty'] ) {
// Slug and ID are used in numerous situations
$section_slug = $metadata_section->get_slug();
$section_id = $metadata_section->get_id();
// Get section wrapper tag
$before = $args['before'];
$before = str_replace('$id', $section_id, $before);
$before = str_replace('$slug', $section_slug, $before);
// Let theme authors tweak the wrapper opener
$before = apply_filters( 'tainacan-get-metadata-section-as-html-before', $before, $metadata_section );
$before = apply_filters( 'tainacan-get-metadata-section-as-html-before--id-' . $section_id, $before, $metadata_section );
if ( is_numeric($section_index) && $section_index >= 0 ) {
$before = apply_filters( 'tainacan-get-metadata-section-as-html-before--index-' . $section_index, $before, $metadata_section );
}
// Renders the wrapper opener
$return .= $before;
// Adds section label (name)
if ( !$args['hide_name'] ) {
// Get section name wrapper
$before_name = $args['before_name'];
$before_name = str_replace('$id', $section_id, $before_name);
$before_name = str_replace('$slug', $section_slug, $before_name);
// Let theme authors tweak the name wrapper
$before_name = apply_filters( 'tainacan-get-metadata-section-as-html-before-name', $before_name, $metadata_section );
$before_name = apply_filters( 'tainacan-get-metadata-section-as-html-before-name--id-' . $section_id, $before_name, $metadata_section );
if ( is_numeric($section_index) && $section_index >= 0 ) {
$before_name = apply_filters( 'tainacan-get-metadata-section-as-html-before-name--index-' . $section_index, $before_name, $metadata_section );
}
// Get section name closer
$after_name = $args['after_name'];
// Let theme authors tweak the name wrapper
$after_name = apply_filters( 'tainacan-get-metadata-section-as-html-after-name', $after_name, $metadata_section );
$after_name = apply_filters( 'tainacan-get-metadata-section-as-html-after-name--id-' . $section_id, $after_name, $metadata_section );
if ( is_numeric($section_index) && $section_index >= 0 ) {
$after_name = apply_filters( 'tainacan-get-metadata-section-as-html-after-name--index-' . $section_index, $after_name, $metadata_section );
}
// Renders the metadata section name
$return .= $before_name . $metadata_section->get_name() . $after_name;
}
// Adds section description
if ( !$args['hide_description'] ) {
$return .= $args['before_description'] . $metadata_section->get_description() . $args['after_description'];
}
// Gets the section metadata list wrapper
$before_metadata_list = $args['before_metadata_list'];
$before_metadata_list = str_replace('$id', $section_id, $before_metadata_list);
$before_metadata_list = str_replace('$slug', $section_slug, $before_metadata_list);
// Let theme authors tweak the metadata list wrapper
$before_description = isset($args['before_description']) ? $args['before_description'] : '';
$before_description = apply_filters( 'tainacan-get-metadata-section-as-html-before-metadata-list', $before_description, $metadata_section );
$before_description = apply_filters( 'tainacan-get-metadata-section-as-html-before-metadata-list--id-' . $section_id, $before_description, $metadata_section );
if ( is_numeric($section_index) && $section_index >= 0 ) {
$before_description = apply_filters( 'tainacan-get-metadata-section-as-html-before-metadata-list--index-' . $section_index, $before_description, $metadata_section );
}
// Renders the section metadata list wrapper
$return .= $before_metadata_list;
// Renders the section metadata list, using Items' get_metadata_as_html()
// Note that this is already escaped in the calling function
if ($has_metadata_list) {
foreach( $metadata_section_metadata_list as $metadata_object) {
$return .= $this->get_metadata_as_html( wp_parse_args($args['metadata_list_args'], [ 'metadata' => $metadata_object ]) );
}
} else {
$return .= $args['empty_metadata_list_message'];
}
// Gets the wrapper closer
$after_metadata_list = $args['after_metadata_list'];
// Let theme authors tweak the metadata list closer
$after_description = isset($args['after_description']) ? $args['after_description'] : '';
$after_description = apply_filters( 'tainacan-get-metadata-section-as-html-after-metadata-list', $after_description, $metadata_section );
$after_description = apply_filters( 'tainacan-get-metadata-section-as-html-after-metadata-list--id-' . $section_id, $after_description, $metadata_section );
if ( is_numeric($section_index) && $section_index >= 0 ) {
$after_description = apply_filters( 'tainacan-get-metadata-section-as-html-after-metadata-list--index-' . $section_index, $after_description, $metadata_section );
}
// Renders the section metadata list wrapper
$return .= $after_metadata_list;
// Gets the wrapper closer
$after = $args['after'];
// Let theme authors tweak the wrapper closer
if ( is_numeric($section_index) && $section_index >= 0 ) {
$after = apply_filters( 'tainacan-get-metadata-section-as-html-after--index-' . $section_index, $after, $metadata_section );
}
$after = apply_filters( 'tainacan-get-metadata-section-as-html-after--id-' . $section_id, $after, $metadata_section );
$after = apply_filters( 'tainacan-get-metadata-section-as-html-after', $after, $metadata_section );
// Closes the wrapper
$return .= $after;
}
// Returns the html content created by the function
return $return;
}
} }

View File

@ -0,0 +1,185 @@
<?php
namespace Tainacan\Entities;
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
/**
* Represents the Entity Metadatum
*/
class Metadata_Section extends Entity {
// Collection getter and setter declared here
use \Tainacan\Traits\Entity_Collection_Relation;
static $post_type = 'tainacan-metasection';
static $default_section_slug = 'default_section';
protected
$name,
$slug,
$description,
$description_bellow_name;
/**
* {@inheritDoc}
* @see \Tainacan\Entities\Entity::repository
* @var string
*/
protected $repository = 'Metadata_Sections';
public $enabled_for_collection = true;
public function __toString() {
return apply_filters("tainacan-metadata-section-to-string", $this->get_name(), $this);
}
/**
* Get the entity ID
*
* @return integer
*/
public function get_id() {
$id = $this->get_mapped_property('id');
return isset($id) ? $id : static::$default_section_slug;
}
/**
* Return the metadata section name
*
* @return string
*/
function get_name() {
return $this->get_mapped_property('name');
}
/**
* Get metadata section slug
*
* @return string
*/
function get_slug() {
return $this->get_mapped_property('slug');
}
/**
* Return the metadata section description
*
* @return string
*/
function get_description() {
return $this->get_mapped_property('description');
}
/**
* Return the metadatum description_bellow_name
*
* @return string
*/
function get_description_bellow_name() {
return $this->get_mapped_property('description_bellow_name');
}
/**
* Return the metadata_list of section
*
* @return [int]
*/
function get_metadata_object_list($args = []) {
$tainacan_metadata_sections = \Tainacan\Repositories\Metadata_Sections::get_instance();
$metadata_section_id = $this->get_id();
if ($metadata_section_id == static::$default_section_slug)
return $tainacan_metadata_sections->get_default_section_metadata_object_list($this->get_collection(), $args);
return $tainacan_metadata_sections->get_metadata_object_list($this->get_id(), $args);
}
/**
* Set the metadata section name
*
* @param [string] $value
* @return void
*/
function set_name($value) {
$this->set_mapped_property('name', $value);
}
/**
* Set the metadata section slug
*
* If you dont set the metadata slug, it will be set automatically based on the name and
* following WordPress default behavior of creating slugs for posts.
*
* If you set the slug for an existing one, WordPress will append a number at the end of in order
* to make it unique (e.g slug-1, slug-2)
*
* @param [string] $value
* @return void
*/
function set_slug($value) {
$this->set_mapped_property('slug', $value);
}
/**
* Set metadata section description
*
* @param [string] $value The text description
* @return void
*/
function set_description($value) {
$this->set_mapped_property('description', $value);
}
/**
* Set metadatum description_bellow_name
*
* @param [string] $value If the description will be displayed bellow the name instead of inside a tooltip (yes/no)
* @return void
*/
function set_description_bellow_name($value) {
$this->set_mapped_property('description_bellow_name', $value);
}
/**
* Transient property used to store the status of the metadatum section for a particular collection
*
* Used by the API to tell front end when a metadatum section is disabled
*
*/
public function get_enabled_for_collection() {
return $this->enabled_for_collection;
}
public function set_enabled_for_collection($value) {
$this->enabled_for_collection = $value;
}
/**
* {@inheritdoc }
*
* Also validates the metadata, calling the validate_options callback of the Metadatum Type
*
* @return bool valid or not
* @throws \Exception
*/
public function validate() {
$no_errors = true;
$name = $this->get_name();
$collection = $this->get_collection();
if( empty($collection) ) {
$this->add_error($this->get_id(), __("collection is required", 'tainacan'));
$no_errors = false;
}
if ( !isset($name) ) {
$this->add_error($this->get_id(), __("name is required", 'tainacan'));
$no_errors = false;
}
if($no_errors) {
$this->set_as_valid();
}
return $no_errors;
}
}

View File

@ -14,6 +14,7 @@ class Metadatum extends Entity {
$order, $order,
$parent, $parent,
$description, $description,
$description_bellow_name,
$placeholder, $placeholder,
$required, $required,
$multiple, $multiple,
@ -23,7 +24,8 @@ class Metadatum extends Entity {
$mask, $mask,
$default_value, $default_value,
$metadata_type, $metadata_type,
$metadata_type_options; $metadata_type_options,
$metadata_section_id;
// Collection getter and setter declared here // Collection getter and setter declared here
use \Tainacan\Traits\Entity_Collection_Relation; use \Tainacan\Traits\Entity_Collection_Relation;
@ -112,6 +114,15 @@ class Metadatum extends Entity {
return $this->get_mapped_property('description'); return $this->get_mapped_property('description');
} }
/**
* Return the metadatum description_bellow_name
*
* @return string
*/
function get_description_bellow_name() {
return $this->get_mapped_property('description_bellow_name');
}
/** /**
* Return the metadatum placeholder * Return the metadatum placeholder
* *
@ -242,6 +253,15 @@ class Metadatum extends Entity {
return $this->get_mapped_property('semantic_uri'); return $this->get_mapped_property('semantic_uri');
} }
/**
* Return the metadata_section_id
*
* @return string
*/
function get_metadata_section_id(){
return $this->get_mapped_property('metadata_section_id');
}
/** /**
* Set the metadatum name * Set the metadatum name
* *
@ -298,6 +318,16 @@ class Metadatum extends Entity {
$this->set_mapped_property('description', $value); $this->set_mapped_property('description', $value);
} }
/**
* Set metadatum description_bellow_name
*
* @param [string] $value If the description will be displayed bellow the name instead of inside a tooltip (yes/no)
* @return void
*/
function set_description_bellow_name($value) {
$this->set_mapped_property('description_bellow_name', $value);
}
/** /**
* Set metadatum placeholder * Set metadatum placeholder
* *
@ -412,6 +442,17 @@ class Metadatum extends Entity {
function set_semantic_uri( $value ){ function set_semantic_uri( $value ){
$this->set_mapped_property('semantic_uri', $value); $this->set_mapped_property('semantic_uri', $value);
} }
/**
* Set metadatum section ID for the metadatum
*
* @param [string] $value
* @return void
*/
function set_metadata_section_id( $value) {
return $this->set_mapped_property('metadata_section_id', $value);
}
/** /**
* Transient property used to store the status of the metadatum for a particular collection * Transient property used to store the status of the metadatum for a particular collection

View File

@ -162,7 +162,7 @@ class CSV extends Exporter {
$last_id = get_post_meta( $item_id, '_user_edit_lastr', true ); $last_id = get_post_meta( $item_id, '_user_edit_lastr', true );
if ( $last_id ) { if ( $last_id ) {
$last_user = get_userdata( $last_id ); $last_user = get_userdata( $last_id );
return apply_filters( 'the_modified_author', $last_user->display_name ); return apply_filters( 'tainacan-the-modified-author', $last_user->display_name );
} }
return ""; return "";
} }

View File

@ -250,7 +250,7 @@ abstract class Exporter {
} }
public function get_step_length_items() { public function get_step_length_items() {
return apply_filters('exporter_step_length_items', 20, $this->get_current_step()); return apply_filters('tainacan-exporter-step-length-items', 20, $this->get_current_step());
} }
public function set_current_collection_item($value) { public function set_current_collection_item($value) {

View File

@ -148,7 +148,7 @@ class Exposers_Handler {
$type_responde = $exposer->rest_request_after_callbacks($response, $handler, $request); $type_responde = $exposer->rest_request_after_callbacks($response, $handler, $request);
if(self::request_has_url_param($request)) { if(self::request_has_url_param($request)) {
header(implode('', $response->get_headers())); header(implode('', $response->get_headers()));
echo esc_attr(stripcslashes($response->get_data())); echo wp_kses_tainacan(stripcslashes($response->get_data()));
exit(); exit();
} }
return $type_responde; return $type_responde;

View File

@ -815,12 +815,16 @@ class CSV extends Importer {
if( (!empty( $itemMetadataArray ) || $special_columns) && $collection instanceof Entities\Collection ) { if( (!empty( $itemMetadataArray ) || $special_columns) && $collection instanceof Entities\Collection ) {
$item->set_collection( $collection ); $item->set_collection( $collection );
if( $item->validate() ) { if ( !$updating_item ) {
$insertedItem = $Tainacan_Items->insert( $item ); if( $item->validate() ) {
$insertedItem = $Tainacan_Items->insert( $item );
} else {
$this->add_error_log( 'Error inserting Item Title: ' . $item->get_title() );
$this->add_error_log( $item->get_errors() );
return false;
}
} else { } else {
$this->add_error_log( 'Error inserting Item Title: ' . $item->get_title() ); $insertedItem = $item;
$this->add_error_log( $item->get_errors() );
return false;
} }
global $wpdb; global $wpdb;
$wpdb->query( 'SET autocommit = 0;' ); $wpdb->query( 'SET autocommit = 0;' );
@ -900,7 +904,7 @@ class CSV extends Importer {
$compound_item_metadata_value = $this->is_assoc($compound_item_metadata_value) ? [$compound_item_metadata_value] : $compound_item_metadata_value; $compound_item_metadata_value = $this->is_assoc($compound_item_metadata_value) ? [$compound_item_metadata_value] : $compound_item_metadata_value;
foreach($compound_item_metadata_value as $item_metadata_value) { foreach($compound_item_metadata_value as $item_metadata_value) {
foreach ($item_metadata_value as $itemMetadata) { foreach ($item_metadata_value as $itemMetadata) {
$Tainacan_Item_Metadata->remove_compound_value($item, $compound_metadata, $itemMetadata->get_parent_meta_id()); $Tainacan_Item_Metadata->remove_compound_value($itemMetadata->get_parent_meta_id());
} }
} }
} }

View File

@ -921,7 +921,7 @@ abstract class Importer {
} }
return [$parent_compound, $children_mapping]; return [$parent_compound, $children_mapping];
} }
$properties = array_filter( explode('|', $metadata_description) ); $properties = array_filter( explode('|', $metadata_description) );
if( is_array($properties) && count($properties) < 2 ){ if( is_array($properties) && count($properties) < 2 ){
$properties[1] = 'text'; $properties[1] = 'text';
@ -974,7 +974,7 @@ abstract class Importer {
} else { } else {
$newMetadatum->set_metadata_type_options([ $newMetadatum->set_metadata_type_options([
'taxonomy_id' => $inserted_tax->get_id(), 'taxonomy_id' => $inserted_tax->get_id(),
'allow_new_terms' => 'no', 'allow_new_terms' => 'yes',
'input_type' => 'tainacan-taxonomy-radio' 'input_type' => 'tainacan-taxonomy-radio'
]); ]);
} }

View File

@ -131,6 +131,13 @@ class Collections extends Repository {
'items' => [ 'type' => 'string' ], 'items' => [ 'type' => 'string' ],
//'validation' => v::stringType(), //'validation' => v::stringType(),
], ],
'metadata_section_order' => [
'map' => 'meta',
'title' => __( 'Metadata order', 'tainacan' ),
'type' => ['array', 'object', 'string'],
'items' => [ 'type' => ['array', 'string', 'integer', 'object'] ],
'description' => __( 'The order of the metadata section in the collection', 'tainacan' ),
],
'metadata_order' => [ 'metadata_order' => [
'map' => 'meta', 'map' => 'meta',
'title' => __( 'Metadata order', 'tainacan' ), 'title' => __( 'Metadata order', 'tainacan' ),
@ -179,21 +186,21 @@ class Collections extends Repository {
'title' => __( 'Thumbnail', 'tainacan' ), 'title' => __( 'Thumbnail', 'tainacan' ),
'description' => __( 'Squared reduced-size version of a picture that helps recognizing and organizing files', 'tainacan' ) 'description' => __( 'Squared reduced-size version of a picture that helps recognizing and organizing files', 'tainacan' )
], ],
'comment_status' => [ 'comment_status' => [
'map' => 'comment_status', 'map' => 'comment_status',
'title' => __( 'Comment Status', 'tainacan' ), 'title' => __( 'Comment Status', 'tainacan' ),
'type' => 'string', 'type' => 'string',
'description' => __( 'Collection comment status: "open" means comments are allowed, "closed" means comments are not allowed.', 'tainacan' ), 'description' => __( 'Collection comment status: "open" means comments are allowed, "closed" means comments are not allowed.', 'tainacan' ),
'default' => get_default_comment_status(Entities\Collection::get_post_type()), 'default' => get_default_comment_status(Entities\Collection::get_post_type()),
'validation' => v::optional(v::stringType()->in( [ 'open', 'closed' ] )), 'validation' => v::optional(v::stringType()->in( [ 'open', 'closed' ] )),
], ],
'allow_comments' => [ 'allow_comments' => [
'map' => 'meta', 'map' => 'meta',
'title' => __( 'Allow enabling comments on items', 'tainacan' ), 'title' => __( 'Allow enabling comments on items', 'tainacan' ),
'type' => 'string', 'type' => 'string',
'description' => __( 'If this option is enabled, items of this collection can be set to enable a comments section on their page. "open" means comments are allowed, "closed" means comments are not allowed.', 'tainacan' ), 'description' => __( 'If this option is enabled, items of this collection can be set to enable a comments section on their page. "open" means comments are allowed, "closed" means comments are not allowed.', 'tainacan' ),
'default' => 'closed', 'default' => 'closed',
'validation' => v::optional(v::stringType()->in( [ 'open', 'closed' ] )), 'validation' => v::optional(v::stringType()->in( [ 'open', 'closed' ] )),
], ],
'submission_anonymous_user' => [ 'submission_anonymous_user' => [
'map' => 'meta', 'map' => 'meta',
@ -238,7 +245,13 @@ class Collections extends Repository {
'on_error' => __( 'Value should be yes or no', 'tainacan' ), 'on_error' => __( 'Value should be yes or no', 'tainacan' ),
'validation' => v::stringType()->in( [ 'yes', 'no' ] ), // yes or no 'validation' => v::stringType()->in( [ 'yes', 'no' ] ), // yes or no
], ],
'default_metadata_section_properties' => [
'map' => 'meta',
'title' => __( 'Default metadata section properties', 'tainacan' ),
'type' => 'object',
'items' => [ 'name' => 'string', 'description' => 'string', 'description_bellow_name' => 'string' ],
'description' => __( 'The default metadata section properties', 'tainacan' ),
],
] ); ] );
} }
@ -304,7 +317,7 @@ class Collections extends Repository {
* @see \Tainacan\Repositories\Repository::insert() * @see \Tainacan\Repositories\Repository::insert()
*/ */
public function insert( $collection ) { public function insert( $collection ) {
$this->pre_process( $collection ); $this->pre_process( $collection );
$this->handle_parent_order_clone( $collection ); $this->handle_parent_order_clone( $collection );
$new_collection = parent::insert( $collection ); $new_collection = parent::insert( $collection );
@ -343,7 +356,11 @@ class Collections extends Repository {
$existing_post = get_post( $args ); $existing_post = get_post( $args );
if ( $existing_post instanceof \WP_Post ) { if ( $existing_post instanceof \WP_Post ) {
try { try {
return new Entities\Collection( $existing_post ); $col = new Entities\Collection( $existing_post );
if ( $col->can_read() ) {
return $col;
}
return [];
} catch (\Exception $e) { } catch (\Exception $e) {
return []; return [];
} }
@ -362,7 +379,7 @@ class Collections extends Repository {
// TODO: Pegar coleções registradas via código // TODO: Pegar coleções registradas via código
$args = apply_filters( 'tainacan_fetch_args', $args, 'collections' ); $args = apply_filters( 'tainacan-fetch-args', $args, 'collections' );
$wp_query = new \WP_Query( $args ); $wp_query = new \WP_Query( $args );
@ -425,6 +442,7 @@ class Collections extends Repository {
function handle_parent_order_clone( &$collection ) { function handle_parent_order_clone( &$collection ) {
if ($collection instanceof Entities\Collection && $collection->get_parent() != 0) { if ($collection instanceof Entities\Collection && $collection->get_parent() != 0) {
$parent_collection = $this->fetch( $collection->get_parent() ); $parent_collection = $this->fetch( $collection->get_parent() );
$collection->set_metadata_section_order($parent_collection->get_metadata_section_order());
$collection->set_metadata_order($parent_collection->get_metadata_order()); $collection->set_metadata_order($parent_collection->get_metadata_order());
$collection->set_filters_order($parent_collection->get_filters_order()); $collection->set_filters_order($parent_collection->get_filters_order());

View File

@ -68,6 +68,15 @@ class Filters extends Repository {
'description' => __( 'The filter type class name, such as filter_type: Tainacan\Filter_Types\Checkbox', 'tainacan' ), 'description' => __( 'The filter type class name, such as filter_type: Tainacan\Filter_Types\Checkbox', 'tainacan' ),
'validation' => '' 'validation' => ''
], ],
'begin_with_filter_collapsed' => [
'map' => 'meta',
'title' => __( 'Begin with filter collapsed', 'tainacan' ),
'type' => 'string',
'description' => __( 'With this option enabled, the filter will appear as a button with an add icon, that should be pressed prior to loading any facet information.', 'tainacan' ),
'on_error' => __( 'Please set the "Begin with filter collapsed" value as "yes" or "no"', 'tainacan' ),
'validation' => v::stringType()->in( [ 'yes', 'no' ] ), // yes or no
'default' => 'no'
],
'collection_id' => [ 'collection_id' => [
'map' => 'meta', 'map' => 'meta',
'title' => __( 'Collection', 'tainacan' ), 'title' => __( 'Collection', 'tainacan' ),
@ -233,7 +242,7 @@ class Filters extends Repository {
$args['post_type'] = Entities\Filter::get_post_type(); $args['post_type'] = Entities\Filter::get_post_type();
$args = apply_filters( 'tainacan_fetch_args', $args, 'filters' ); $args = apply_filters( 'tainacan-fetch-args', $args, 'filters' );
$wp_query = new \WP_Query( $args ); $wp_query = new \WP_Query( $args );

View File

@ -237,7 +237,7 @@ class Item_Metadata extends Repository {
$item_metadata->set_value([]); $item_metadata->set_value([]);
$this->save_terms_metadatum_value( $item_metadata ); $this->save_terms_metadatum_value( $item_metadata );
} elseif ( $metadata_type->get_primitive_type() == 'compound' ) { } elseif ( $metadata_type->get_primitive_type() == 'compound' ) {
$this->remove_compound_value($item_metadata->get_item(), $item_metadata->get_metadatum(), $item_metadata->get_parent_meta_id() ); $this->remove_compound_value($item_metadata->get_parent_meta_id() );
} else { } else {
delete_post_meta( $item_metadata->get_item()->get_id(), $item_metadata->get_metadatum()->get_id() ); delete_post_meta( $item_metadata->get_item()->get_id(), $item_metadata->get_metadatum()->get_id() );
} }
@ -249,8 +249,7 @@ class Item_Metadata extends Repository {
return $item_metadata; return $item_metadata;
} }
public function remove_compound_value(\Tainacan\Entities\Item $item, $metadatum, $parent_meta_id ) { public function remove_compound_value($parent_meta_id ) {
$post_id = $item->get_id();
$current_childrens = get_metadata_by_mid( 'post', $parent_meta_id ); $current_childrens = get_metadata_by_mid( 'post', $parent_meta_id );
if ( is_object( $current_childrens ) ) { if ( is_object( $current_childrens ) ) {
$current_childrens = $current_childrens->meta_value; $current_childrens = $current_childrens->meta_value;
@ -260,7 +259,7 @@ class Item_Metadata extends Repository {
$current_childrens = []; $current_childrens = [];
} }
foreach($current_childrens as $meta_children) { foreach($current_childrens as $meta_children) {
delete_post_meta('post', $meta_children); delete_metadata_by_mid('post', $meta_children);
} }
delete_metadata_by_mid('post', $parent_meta_id); delete_metadata_by_mid('post', $parent_meta_id);
return $current_childrens; return $current_childrens;
@ -438,7 +437,7 @@ class Item_Metadata extends Repository {
if ( is_array( $ids ) ) { if ( is_array( $ids ) ) {
foreach ( $ids as $id ) { foreach ( $ids as $id ) {
$post_meta_object = get_metadata_by_mid( 'post', $id ); $post_meta_object = get_metadata_by_mid( 'post', $id );
if ( is_object( $post_meta_object ) && get_post($post_meta_object->meta_key) !== null ) { if ( is_object( $post_meta_object ) && get_post($post_meta_object->meta_key) !== null && get_post_status($post_meta_object->meta_key) !== 'trash' ) {
$metadatum = new Entities\Metadatum( $post_meta_object->meta_key ); $metadatum = new Entities\Metadatum( $post_meta_object->meta_key );
$return_value[ $metadatum->get_id() ] = new Entities\Item_Metadata_Entity( $item, $metadatum, $id, (int)$compound_meta_id ); $return_value[ $metadatum->get_id() ] = new Entities\Item_Metadata_Entity( $item, $metadatum, $id, (int)$compound_meta_id );
} }

View File

@ -252,7 +252,12 @@ class Items extends Repository {
$existing_post = get_post( $args ); $existing_post = get_post( $args );
if ( $existing_post instanceof \WP_Post ) { if ( $existing_post instanceof \WP_Post ) {
try { try {
return new Entities\Item( $existing_post ); $item = new Entities\Item( $existing_post );
$collection = $item->get_collection();
if (isset($collection) && $collection->can_read()) {
return $item;
}
return [];
} catch (\Exception $e) { } catch (\Exception $e) {
return []; return [];
} }
@ -351,7 +356,7 @@ class Items extends Repository {
$args = $this->parse_relationship_metaquery($args); $args = $this->parse_relationship_metaquery($args);
} }
$args = apply_filters( 'tainacan_fetch_args', $args, 'items' ); $args = apply_filters( 'tainacan-fetch-args', $args, 'items' );
$should_filter = is_user_logged_in() && sizeof($cpt) > 1; $should_filter = is_user_logged_in() && sizeof($cpt) > 1;

View File

@ -214,7 +214,7 @@ class Logs extends Repository {
$args['post_type'] = Entities\Log::get_post_type(); $args['post_type'] = Entities\Log::get_post_type();
$args = apply_filters( 'tainacan_fetch_args', $args, 'logs' ); $args = apply_filters( 'tainacan-fetch-args', $args, 'logs' );
$wp_query = new \WP_Query( $args ); $wp_query = new \WP_Query( $args );

View File

@ -0,0 +1,485 @@
<?php
namespace Tainacan\Repositories;
use Tainacan\Entities;
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
use \Respect\Validation\Validator as v;
/**
* Class Metadata
*/
class Metadata_Sections extends Repository {
public $entities_type = '\Tainacan\Entities\Metadata_Section';
private static $instance = null;
protected function __construct() {
parent::__construct();
}
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* {@inheritDoc}
* @see \Tainacan\Repositories\Repository::get_map()
*/
protected function _get_map() {
return apply_filters( 'tainacan-get-map-' . $this->get_name(), [
'name' => [
'map' => 'post_title',
'title' => __( 'Name', 'tainacan' ),
'type' => 'string',
'description' => __( 'Name of the metadata section', 'tainacan' ),
'on_error' => __( 'The name should be a text value and not empty', 'tainacan' ),
'validation' => v::stringType()->notEmpty(),
],
'slug' => [
'map' => 'post_name',
'title' => __( 'Slug', 'tainacan' ),
'type' => 'string',
'description' => __( 'A unique and sanitized string representation of the metadata sction', 'tainacan' ),
],
'status' => [
'map' => 'post_status',
'title' => __( 'Status', 'tainacan' ),
'type' => 'string',
'default' => 'publish',
'description' => __( 'Status', 'tainacan' )
],
'description' => [
'map' => 'post_content',
'title' => __( 'Description', 'tainacan' ),
'type' => 'string',
'description' => __( 'The metadata section description.', 'tainacan' ),
'default' => '',
],
'description_bellow_name' => [
'map' => 'meta',
'title' => __( 'Description bellow name', 'tainacan' ),
'type' => 'string',
'description' => __( 'Whether the section metadata description should be displayed bellow the name instead of inside a tooltip.', 'tainacan' ),
'on_error' => __( 'Please set the "Description bellow name" value as "yes" or "no"', 'tainacan' ),
'validation' => v::stringType()->in( [ 'yes', 'no' ] ), // yes or no
'default' => 'no'
],
'collection_id' => [
'map' => 'meta',
'title' => __( 'Collection', 'tainacan' ),
'type' => ['integer', 'string'],
'description' => __( 'The collection ID', 'tainacan' ),
]
] );
}
/**
* Get the labels for the custom post type of this repository
*
* @return array Labels in the format expected by register_post_type()
*/
public function get_cpt_labels() {
return array(
'name' => __( 'Metadata Sections', 'tainacan' ),
'singular_name' => __( 'Metadata Section', 'tainacan' ),
'add_new' => __( 'Add new', 'tainacan' ),
'add_new_item' => __( 'Add new Metadata Section', 'tainacan' ),
'edit_item' => __( 'Edit Metadata Section', 'tainacan' ),
'new_item' => __( 'New Metadata Section', 'tainacan' ),
'view_item' => __( 'View Metadata Section', 'tainacan' ),
'search_items' => __( 'Search Metadata Section', 'tainacan' ),
'not_found' => __( 'No Metadata Section found ', 'tainacan' ),
'not_found_in_trash' => __( 'No Metadata Section found in trash', 'tainacan' ),
'parent_item_colon' => __( 'Parent Metadata Section:', 'tainacan' ),
'menu_name' => __( 'Metadata Section', 'tainacan' )
);
}
public function register_post_type() {
$labels = $this->get_cpt_labels();
$args = array(
'labels' => $labels,
'hierarchical' => true,
'public' => true,
'show_ui' => tnc_enable_dev_wp_interface(),
'show_in_menu' => tnc_enable_dev_wp_interface(),
'publicly_queryable' => true,
'exclude_from_search' => true,
'has_archive' => false,
'query_var' => true,
'can_export' => true,
'rewrite' => true,
'map_meta_cap' => true,
'show_in_nav_menus' => false,
'capabilities' => (array) $this->get_capabilities(),
'supports' => [
'title',
'editor',
'page-attributes'
]
);
register_post_type( Entities\Metadata_Section::get_post_type(), $args );
}
/**
* Get the default metadata section of the collection
*
* @param \Tainacan\Entities\Collection|int the collection of the metadata section
*
* @return \Tainacan\Entities\Metadata_Section|false return de the default metadata section or false otherwise.
*/
public function get_default_section ($collection) {
if($collection instanceof Entities\Collection) {
$collection_id = $collection->get_id();
} else if (is_int($collection)) {
$collection_id = $collection;
$collection = \tainacan_collections()->fetch($collection, 'OBJECT');
} else {
return false;
}
$name = __('Metadata', 'tainacan');
$description = __('Metadata section', 'tainacan');
$description_bellow_name = 'no';
$default_metadata_section_properties = $collection->get_default_metadata_section_properties();
if( !empty($default_metadata_section_properties) ) {
$name = isset($default_metadata_section_properties['name']) ? $default_metadata_section_properties['name'] : $name;
$description = isset($default_metadata_section_properties['description']) ? $default_metadata_section_properties['description'] : $description;
$description_bellow_name = isset($default_metadata_section_properties['description_bellow_name']) ? $default_metadata_section_properties['description_bellow_name'] : $description_bellow_name;
}
$defaul_section = new Entities\Metadata_Section();
$defaul_section->set_slug(\Tainacan\Entities\Metadata_Section::$default_section_slug);
$defaul_section->set_name($name);
$defaul_section->set_description($description);
$defaul_section->set_description_bellow_name($description_bellow_name);
$defaul_section->set_collection_id($collection_id);
return $defaul_section;
}
/**
* fetch metadata section based on ID or WP_Query args
*
* metadata section are stored as posts. Check WP_Query docs
* to learn all args accepted in the $args parameter (@see https://developer.wordpress.org/reference/classes/wp_query/)
* You can also use a mapped property, such as name and description, as an argument and it will be mapped to the
* appropriate WP_Query argument
*
* If a number is passed to $args, it will return a \Tainacan\Entities\Metadata_Section object. But if the post is not found or
* does not match the entity post type, it will return an empty array
*
* @param array $args WP_Query args || int $args the metadata section id
* @param string $output The desired output format (@see \Tainacan\Repositories\Repository::fetch_output() for possible values)
*
* @return Entities\Metadata_Section|\WP_Query|Array an instance of wp query OR array of entities;
* @throws \Exception
*/
public function fetch( $args, $output = null ) {
if ( is_numeric( $args ) ) {
$existing_post = get_post( $args );
if ( $existing_post instanceof \WP_Post ) {
try {
return new Entities\Metadata_Section( $existing_post );
} catch (\Exception $e) {
return [];
}
} else {
return [];
}
} elseif ( is_array( $args ) ) {
$args = array_merge( [
'posts_per_page' => - 1,
], $args );
$args = $this->parse_fetch_args( $args );
$args['post_type'] = Entities\Metadata_Section::get_post_type();
$args = apply_filters( 'tainacan-fetch-args', $args, 'metadata-section' );
$wp_query = new \WP_Query( $args );
return $this->fetch_output( $wp_query, $output );
}
}
/**
* fetch metadata sections IDs based on WP_Query args
*
* to learn all args accepted in the $args parameter (@see https://developer.wordpress.org/reference/classes/wp_query/)
* You can also use a mapped property, such as name and description, as an argument and it will be mapped to the
* appropriate WP_Query argument
*
* @param array $args WP_Query args || int $args the item id
*
* @return Array array of IDs;
* @throws \Exception
*/
public function fetch_ids( $args = [] ) {
$args['fields'] = 'ids';
return $this->fetch( $args )->get_posts();
}
/**
* fetch metadata section by collection
*
* @param Entities\Collection $collection
* @param array $args WP_Query args
*
* @return array Entities\Metadata_Section
* @throws \Exception
*/
public function fetch_by_collection( Entities\Collection $collection, $args = [] ) {
$collection_id = $collection->get_id();
//get parent collections
$parents = get_post_ancestors( $collection_id );
//insert the actual collection
if ( is_numeric($collection_id) ) {
$parents[] = $collection_id;
}
$results = [];
$args = array_merge( [
'parent' => 0
], $args );
$original_meta_q = isset( $args['meta_query'] ) ? $args['meta_query'] : [];
/**
* Since we introduced roles & capabalities management, we cannot rely
* on WordPress behavior when handling default post status values.
* WordPress checks if the current user can read_priva_posts, but this is
* not enough for us. We have to handle this ourselves to mimic WordPress behavior
* considering how tainacan manages metadata capabilities
*/
if ( ! isset($args['post_status']) ) {
foreach ( $parents as $parent_id ) {
// Add public states.
$statuses = get_post_stati( array( 'public' => true ) );
$read_private_cap = 'tnc_col_' . $parent_id . '_read_private_metadata_section';
if ( current_user_can($read_private_cap) ) {
$statuses = array_merge( $statuses, get_post_stati( array( 'private' => true ) ) );
}
$args['post_status'] = $statuses;
$meta_query = array(
'key' => 'collection_id',
'value' => $parent_id,
);
$args['meta_query'] = $original_meta_q;
$args['meta_query'][] = $meta_query;
$results = array_merge($results, $this->fetch( $args, 'OBJECT' ));
}
} else {
$meta_query = array(
'key' => 'collection_id',
'value' => $parents,
'compare' => 'IN',
);
$args['meta_query'] = $original_meta_q;
$args['meta_query'][] = $meta_query;
$results = $this->fetch( $args, 'OBJECT' );
}
$results[] = $this->get_default_section($collection->get_id());
return $this->order_result(
$results,
$collection,
isset( $args['include_disabled'] ) ? $args['include_disabled'] : false
);
}
/**
* @param \Tainacan\Entities\Metadata_Section $metadata_section
*
* @return \Tainacan\Entities\Metadata_Section
* {@inheritDoc}
* @see \Tainacan\Repositories\Repository::insert()
*/
public function insert( $metadata_section ) {
$new_metadata_section = parent::insert( $metadata_section );
return $new_metadata_section;
}
/**
* @param \Tainacan\Entities\Metadata_Section $object
* @param $new_values
*
* @return mixed|string|Entities\Entity
* @throws \Exception
*/
public function update( $object, $new_values = null ) {
if($object->get_id() == \Tainacan\Entities\Metadata_Section::$default_section_slug) {
$collection = $object->get_collection();
if($collection instanceof \Tainacan\Entities\Collection) {
$properties = array(
'name' => $object->get_name(),
'description' => $object->get_description(),
'description_bellow_name' => $object->get_description_bellow_name()
);
$collection->set_default_metadata_section_properties($properties);
if($collection->validate()) {
\tainacan_collections()->update($collection);
return $object;
}
}
return false;
}
return $this->insert( $object );
}
public function add_metadata($metadata_section_id, $metadata_list) {
$metadata_section = $this->fetch($metadata_section_id, 'OBJECT');
if ($metadata_section) {
foreach($metadata_list as $metadata_id) {
//update_post_meta($metadata_id, 'metadata_section_id', $metadata_section_id);
add_post_meta($metadata_id, 'metadata_section_id', $metadata_section_id);
}
return $metadata_section;
}
return false;
}
public function delete_metadata($metadata_section_id, $metadata_list) {
$metadata_section = $this->fetch($metadata_section_id, 'OBJECT');
if ($metadata_section) {
foreach($metadata_list as $metadata_id) {
delete_post_meta($metadata_id, 'metadata_section_id', $metadata_section_id);
}
return $metadata_section;
}
return false;
}
public function get_metadata_object_list($metadata_section_id, $args = []) {
$metadata_section = $this->fetch($metadata_section_id);
if ($metadata_section) {
$metadata_repository = \Tainacan\Repositories\Metadata::get_instance();
$metadata_list = $metadata_repository->fetch_by_metadata_section($metadata_section, $args);
return $metadata_list;
}
return false;
}
public function get_default_section_metadata_object_list (Entities\Collection $collection, $args = []) {
$metadata_sections_ids = $this->fetch_ids();
$args = array_merge(
$args,
array(
'meta_query' => array(
array(
'relation' => 'OR',
array(
'key' => 'metadata_section_id',
'value' => \Tainacan\Entities\Metadata_Section::$default_section_slug,
'compare' => '='
),
array(
array(
'key' => 'metadata_section_id',
'compare' => 'NOT EXISTS'
)
),
array(
'key' => 'metadata_section_id',
'value' => $metadata_sections_ids,
'compare' => 'NOT IN'
),
)
)
)
);
$metadata_repository = \Tainacan\Repositories\Metadata::get_instance();
$metadata_list = $metadata_repository->fetch_by_collection($collection, $args);
return $metadata_list;
}
/**
* @inheritDoc
*/
public function delete( Entities\Entity $entity, $permanent = true ) {
//test if not exist a metadata using this section
if ( !empty( $this->get_metadata_object_list($entity->get_id() ) ) ) {
throw new \Exception( 'The metadata section must not contain metadata before deleted' );
}
return parent::delete($entity, $permanent);
}
public function order_result( $result, Entities\Collection $collection, $include_disabled = false ) {
$order = $collection->get_metadata_section_order();
if ( $order ) {
$order = ( is_array( $order ) ) ? $order : unserialize( $order );
if ( is_array( $result ) ) {
$result_ordinate = [];
$not_ordinate = [];
foreach ( $result as $item ) {
$id = $item->get_id();
$index = array_search( $id, array_column( $order, 'id' ) );
if ( $index !== false ) {
// skipping metadata disabled if the arg is set
if ( ! $include_disabled && isset( $order[ $index ]['enabled'] ) && ! $order[ $index ]['enabled'] ) {
continue;
}
$enable = ( isset( $order[ $index ]['enabled'] ) ) ? $order[ $index ]['enabled'] : true;
$item->set_enabled_for_collection( $enable );
$result_ordinate[ $index ] = $item;
} else {
$not_ordinate[] = $item;
}
}
ksort( $result_ordinate );
$result_ordinate = array_merge( $result_ordinate, $not_ordinate );
return $result_ordinate;
}
}
return $result;
}
/**
* Check if $user can read the entity
*
* @param Entities\Metadata_Section|Entities\Entity $entity
* @param int|\WP_User|null $user default is null for the current user
*
* @return boolean
* @throws \Exception
*/
public function can_read( Entities\Entity $entity, $user = null ) {
if ( is_null($entity) )
return false;
if ($entity instanceof Entities\Metadata_Section && $entity->get_id() == Entities\Metadata_Section::$default_section_slug ) {
$collection = $entity->get_collection();
if($collection instanceof Entities\Collection) {
return $collection->can_read();
}
return false;
}
return parent::can_read($entity, $user);
}
}

View File

@ -42,6 +42,7 @@ class Metadata extends Repository {
add_action('tainacan-insert-tainacan-taxonomy', [$this, 'hook_taxonomies_saved_as_private']); add_action('tainacan-insert-tainacan-taxonomy', [$this, 'hook_taxonomies_saved_as_private']);
add_action('tainacan-insert-tainacan-taxonomy', [$this, 'hook_taxonomies_saved_not_allow_insert_new_terms']); add_action('tainacan-insert-tainacan-taxonomy', [$this, 'hook_taxonomies_saved_not_allow_insert_new_terms']);
add_action('tainacan-insert-tainacan-metadatum', [$this, 'hook_metadata_update_order']);
} }
@ -49,7 +50,7 @@ class Metadata extends Repository {
* {@inheritDoc} * {@inheritDoc}
* @see \Tainacan\Repositories\Repository::get_map() * @see \Tainacan\Repositories\Repository::get_map()
*/ */
protected function _get_map() { protected function _get_map() {
return apply_filters( 'tainacan-get-map-' . $this->get_name(), [ return apply_filters( 'tainacan-get-map-' . $this->get_name(), [
'name' => [ 'name' => [
'map' => 'post_title', 'map' => 'post_title',
@ -87,11 +88,20 @@ class Metadata extends Repository {
'map' => 'post_content', 'map' => 'post_content',
'title' => __( 'Description', 'tainacan' ), 'title' => __( 'Description', 'tainacan' ),
'type' => 'string', 'type' => 'string',
'description' => __( 'The metadatum description. This may provide information on how to fill this metadatum, which will appear inside a tooltip alongside the input label.', 'tainacan' ), 'description' => __( 'The metadatum description. This may provide information on how to fill this metadatum, which will appear inside a tooltip alongside the input label, or bellow it.', 'tainacan' ),
'default' => '', 'default' => '',
//'on_error' => __('The description should be a text value', 'tainacan'), //'on_error' => __('The description should be a text value', 'tainacan'),
//'validation' => v::stringType()->notEmpty(), //'validation' => v::stringType()->notEmpty(),
], ],
'description_bellow_name' => [
'map' => 'meta',
'title' => __( 'Description bellow name', 'tainacan' ),
'type' => 'string',
'description' => __( 'Whether the metadatum description should be displayed bellow the input label instead of inside a tooltip.', 'tainacan' ),
'on_error' => __( 'Please set the "Description bellow name" value as "yes" or "no"', 'tainacan' ),
'validation' => v::stringType()->in( [ 'yes', 'no' ] ), // yes or no
'default' => 'no'
],
'placeholder' => [ 'placeholder' => [
'map' => 'meta', 'map' => 'meta',
'title' => __( 'Placeholder', 'tainacan' ), 'title' => __( 'Placeholder', 'tainacan' ),
@ -216,6 +226,13 @@ class Metadata extends Repository {
// yes or no. It cant be multiple if its collection_key // yes or no. It cant be multiple if its collection_key
'default' => 'no' 'default' => 'no'
], ],
'metadata_section_id' => [
'map' => 'meta',
'title' => __( 'Metadata section', 'tainacan' ),
'type' => ['integer', 'string', 'array'],
'description' => __( 'The metadata section ID', 'tainacan' ),
'default' => \Tainacan\Entities\Metadata_Section::$default_section_slug
],
] ); ] );
} }
@ -359,7 +376,7 @@ class Metadata extends Repository {
$args['post_type'] = Entities\Metadatum::get_post_type(); $args['post_type'] = Entities\Metadatum::get_post_type();
$args = apply_filters( 'tainacan_fetch_args', $args, 'metadata' ); $args = apply_filters( 'tainacan-fetch-args', $args, 'metadata' );
$wp_query = new \WP_Query( $args ); $wp_query = new \WP_Query( $args );
@ -447,6 +464,33 @@ class Metadata extends Repository {
$args['meta_query'] = $original_meta_q; $args['meta_query'] = $original_meta_q;
$args['meta_query'][] = $meta_query; $args['meta_query'][] = $meta_query;
if ($this->get_default_metadata_attribute() != $parent_id) {
$read_private_metasection_cap = "tnc_col_{$parent_id}_read_private_metasection";
if ( !current_user_can($read_private_metasection_cap) ) {
$private_metadata_sections_ids = \tainacan_metadata_sections()->fetch_ids(
array(
'post_status' => get_post_stati( array( 'private' => true ) ),
'meta_query' => array(
'key' => 'collection_id',
'value' => $parent_id,
)
));
$args['meta_query'][] = array(
'relation' => 'OR',
array(
'key' => 'metadata_section_id',
'value' => $private_metadata_sections_ids,
'compare' => 'NOT IN'
),
array( //note: using the comparete 'NOT EXISTS' to cases where metadata section id is not present in mapped property (meta) of metadatum
'key' => 'metadata_section_id',
'compare' => 'NOT EXISTS'
)
);
}
}
$results = array_merge($results, $this->fetch( $args, 'OBJECT' )); $results = array_merge($results, $this->fetch( $args, 'OBJECT' ));
} }
@ -577,6 +621,40 @@ class Metadata extends Repository {
return $results; return $results;
} }
/**
* fetch metadatum by metadata section, considering order
*
* @param Entities\Metadata_Section $collection
* @param array $args WP_Query args plus disabled_metadata
*
* @return array Entities\Metadatum
* @throws \Exception
*/
public function fetch_by_metadata_section( Entities\Metadata_Section $metadata_section, $args = [] ) {
$results = [];
if ($metadata_section && $metadata_section->can_read()) {
$metadata_section_id = $metadata_section->get_id();
$collection = $metadata_section->get_collection();
$args = array_merge($args, array(
'parent' => 0,
'meta_query' => [
[
'key' => 'metadata_section_id',
'value' => $metadata_section_id,
'compare' => '='
]
]
));
$results = $this->fetch($args, 'OBJECT');
return $this->order_result(
$results,
$collection,
isset( $args['include_disabled'] ) ? $args['include_disabled'] : false
);
}
return $results;
}
/** /**
* Ordinate the result from fetch response if $collection has an ordination, * Ordinate the result from fetch response if $collection has an ordination,
* metadata not ordinated appear on the end of the list * metadata not ordinated appear on the end of the list
@ -590,6 +668,7 @@ class Metadata extends Repository {
*/ */
public function order_result( $result, Entities\Collection $collection, $include_disabled = false ) { public function order_result( $result, Entities\Collection $collection, $include_disabled = false ) {
$order = $collection->get_metadata_order(); $order = $collection->get_metadata_order();
$section_order = $collection->get_metadata_section_order();
if ( $order ) { if ( $order ) {
$order = ( is_array( $order ) ) ? $order : unserialize( $order ); $order = ( is_array( $order ) ) ? $order : unserialize( $order );
@ -601,11 +680,23 @@ class Metadata extends Repository {
foreach ( $result as $item ) { foreach ( $result as $item ) {
$id = $item->WP_Post->ID; $id = $item->WP_Post->ID;
$index = array_search( $id, array_column( $order, 'id' ) ); $index = array_search( $id, array_column( $order, 'id' ) );
$metadata_section_ids = get_post_meta( $id, 'metadata_section_id');
$enabled_metadata_section = true;
if(!empty($metadata_section_ids) && $metadata_section_ids !== false && !empty($section_order)) {
foreach( $metadata_section_ids as $metadata_section_id) {
$section_order_index = array_search( $metadata_section_id, array_column( $section_order, 'id' ) );
if ( $section_order_index !== false ) {
$enabled_metadata_section = boolval($section_order[$section_order_index]['enabled']);
break;
}
}
}
if ( $index !== false ) { if ( $index !== false ) {
// skipping metadata disabled if the arg is set // skipping metadata disabled if the arg is set
if ( ! $include_disabled && isset( $order[ $index ]['enabled'] ) && ! $order[ $index ]['enabled'] ) { if ( ! $include_disabled && (!$enabled_metadata_section || isset( $order[ $index ]['enabled'] ) && ! $order[ $index ]['enabled'] )) {
continue; continue;
} }
@ -614,6 +705,14 @@ class Metadata extends Repository {
$result_ordinate[ $index ] = $item; $result_ordinate[ $index ] = $item;
} else { } else {
// skipping if metadata coumpound is disabled if the arg is set
if ($item->get_parent() > 0) {
$parent_metadatum = new \Tainacan\Entities\Metadatum($item->get_parent());
$parent_index = array_search( $parent_metadatum->get_id(), array_column( $order, 'id' ) );
if ( ! $include_disabled && (!$enabled_metadata_section || isset( $order[ $parent_index ]['enabled'] ) && ! $order[ $parent_index ]['enabled'] )) {
continue;
}
}
$not_ordinate[] = $item; $not_ordinate[] = $item;
} }
} }
@ -639,10 +738,8 @@ class Metadata extends Repository {
public function insert( $metadatum ) { public function insert( $metadatum ) {
$this->pre_update_taxonomy_metadatum( $metadatum ); $this->pre_update_taxonomy_metadatum( $metadatum );
$new_metadatum = parent::insert( $metadatum ); $new_metadatum = parent::insert( $metadatum );
$this->update_taxonomy_metadatum( $new_metadatum ); $this->update_taxonomy_metadatum( $new_metadatum );
$this->update_metadata_type_index( $new_metadatum ); $this->update_metadata_type_index( $new_metadatum );
return $new_metadatum; return $new_metadatum;
} }
@ -742,7 +839,7 @@ class Metadata extends Repository {
*/ */
private function get_data_core_metadata( Entities\Collection $collection ) { private function get_data_core_metadata( Entities\Collection $collection ) {
return $data_core_metadata = [ $data_core_metadata = [
'core_title' => [ 'core_title' => [
'name' => __('Title', 'tainacan'), 'name' => __('Title', 'tainacan'),
'collection_id' => $collection->get_id(), 'collection_id' => $collection->get_id(),
@ -757,6 +854,7 @@ class Metadata extends Repository {
'status' => 'publish', 'status' => 'publish',
] ]
]; ];
return $data_core_metadata;
} }
@ -1706,4 +1804,38 @@ class Metadata extends Repository {
return false; return false;
} }
/**
* When a metadata is saved, if the metadata section changes, the ordering needs to be updated
*
* @param \Tainacan\Entities\Metadatum $metadata
* @return void
*/
public function hook_metadata_update_order($metadata) {
$tainacan_metadata_sections_repository = \tainacan_metadata_sections();
$tainacan_collections_repository = \tainacan_collections();
$metadata_section_id = $metadata->get_metadata_section_id();
$metadata_section = $tainacan_metadata_sections_repository->fetch($metadata_section_id);
if ( $metadata_section instanceof \Tainacan\Entities\Metadata_Section ) {
$collection = $metadata_section->get_collection();
$metadata_sections_order = $collection->get_metadata_section_order();
if( empty($metadata_sections_order) ) {
return;
}
foreach( $metadata_sections_order as &$metadata_section_order ) {
$pos = array_search($metadata->get_id(), array_column($metadata_section_order['metadata_order'], 'id'));
if($pos !== false) {
if( $metadata_section_id != $metadata_section_order['id']) {
array_splice($metadata_section_order['metadata_order'], $pos, 1);
}
} else if($metadata_section_id == $metadata_section_order['id']) {
$metadata_section_order['metadata_order'][] = ["id" => $metadata->get_id(), "enabled" => $metadata->get_enabled_for_collection()];
}
}
$collection->set_metadata_section_order($metadata_sections_order);
if($collection->validate()) {
$tainacan_collections_repository->update($collection);
}
}
}
} }

View File

@ -515,6 +515,7 @@ abstract class Repository {
$Tainacan_Metadata = Repositories\Metadata::get_instance(); $Tainacan_Metadata = Repositories\Metadata::get_instance();
$Tainacan_Taxonomies = Repositories\Taxonomies::get_instance(); $Tainacan_Taxonomies = Repositories\Taxonomies::get_instance();
$Tainacan_Terms = Repositories\Terms::get_instance(); $Tainacan_Terms = Repositories\Terms::get_instance();
$Tainacan_Metadata_Sections = Repositories\Metadata_Sections::get_instance();
$tnc_globals = [ $tnc_globals = [
$Tainacan_Collections, $Tainacan_Collections,
@ -522,7 +523,8 @@ abstract class Repository {
$Tainacan_Filters, $Tainacan_Filters,
$Tainacan_Taxonomies, $Tainacan_Taxonomies,
$Tainacan_Terms, $Tainacan_Terms,
$Tainacan_Logs $Tainacan_Logs,
$Tainacan_Metadata_Sections
]; ];
foreach ( $tnc_globals as $tnc_repository ) { foreach ( $tnc_globals as $tnc_repository ) {
$tnc_entity = new $tnc_repository->entities_type(); $tnc_entity = new $tnc_repository->entities_type();
@ -725,7 +727,10 @@ abstract class Repository {
$entity_cap = $entity->get_capabilities(); $entity_cap = $entity->get_capabilities();
if ( ! isset( $entity_cap->read ) ) { if ( ! isset( $entity_cap->read ) ) {
if ( $entity->get_post_type() === false ) { // Allow read of not post entities $prefix = Entities\Collection::$db_identifier_prefix;
$sufix = Entities\Collection::$db_identifier_sufix;
$is_a_item = preg_match('/^'. $prefix . '[0-9]*' . $sufix . '$/i', $entity->WP_Post->post_type);
if ( $entity->get_post_type() === false && !$is_a_item) { // Allow read of not post entities
return true; return true;
} }

View File

@ -191,7 +191,7 @@ class Taxonomies extends Repository {
$args['post_type'] = Entities\Taxonomy::get_post_type(); $args['post_type'] = Entities\Taxonomy::get_post_type();
$args = apply_filters( 'tainacan_fetch_args', $args, 'taxonomies' ); $args = apply_filters( 'tainacan-fetch-args', $args, 'taxonomies' );
$wp_query = new \WP_Query( $args ); $wp_query = new \WP_Query( $args );

View File

@ -133,6 +133,8 @@ $Tainacan_Item_Metadata = \Tainacan\Repositories\Item_Metadata::get_instance();
$Metadata_Type_Helper = \Tainacan\Metadata_Types\Metadata_Type_Helper::get_instance(); $Metadata_Type_Helper = \Tainacan\Metadata_Types\Metadata_Type_Helper::get_instance();
$Tainacan_Metadata_Section = \Tainacan\Repositories\Metadata_Sections::get_instance();
$Filter_Type_Helper = \Tainacan\Filter_Types\Filter_Type_Helper::get_instance(); $Filter_Type_Helper = \Tainacan\Filter_Types\Filter_Type_Helper::get_instance();
$Tainacan_Taxonomies = \Tainacan\Repositories\Taxonomies::get_instance(); $Tainacan_Taxonomies = \Tainacan\Repositories\Taxonomies::get_instance();

View File

@ -71,3 +71,12 @@ function tainacan_terms() {
function tainacan_roles() { function tainacan_roles() {
return \Tainacan\Roles::get_instance(); return \Tainacan\Roles::get_instance();
} }
/**
* Retrieve the singleton Metadata Sections Repository instance
* @return \Tainacan\Repositories\Metadata_Sections The Tainacan Metadata Repository
*/
function tainacan_metadata_sections() {
return \Tainacan\Repositories\Metadata_Sections::get_instance();
}

View File

@ -914,7 +914,7 @@ class Theme_Helper {
* @type integer $auto_play_speed The time in s to translate to the next slide automatically * @type integer $auto_play_speed The time in s to translate to the next slide automatically
* @type bool $loop_slides Should slides loop when reached the end of the Carousel? * @type bool $loop_slides Should slides loop when reached the end of the Carousel?
* @type bool $hide_title Should the title of the items be displayed? * @type bool $hide_title Should the title of the items be displayed?
* @type bool $crop_images_to_square Should it use the `tainacan-medium-size` instead of the `tainacan-medium-large-size`? * @type string $image_size Item image size. Defaults to 'tainacan-medium'
* @type bool $show_collection_header Should it display a small version of the collection header? * @type bool $show_collection_header Should it display a small version of the collection header?
* @type bool $show_collection_label Should it displar a 'Collection' label before the collection name on the collection header? * @type bool $show_collection_label Should it displar a 'Collection' label before the collection name on the collection header?
* @type string $collection_background_color Color of the collection header background * @type string $collection_background_color Color of the collection header background
@ -937,7 +937,7 @@ class Theme_Helper {
'auto_play_speed' => 3, 'auto_play_speed' => 3,
'loop_slides' => false, 'loop_slides' => false,
'hide_title' => false, 'hide_title' => false,
'crop_images_to_square' => true, 'image_size' => 'tainacan-medium',
'show_collection_header' => false, 'show_collection_header' => false,
'show_collection_label' => false, 'show_collection_label' => false,
'collection_background_color' => '#454647', 'collection_background_color' => '#454647',
@ -948,6 +948,11 @@ class Theme_Helper {
); );
$args = wp_parse_args($args, $defaults); $args = wp_parse_args($args, $defaults);
/* Compatibility with previous version */
if ( isset($args['crop_images_to_square ']) && !$args['crop_images_to_square'] ) {
$args['image_size'] = 'tainacan-medium-full';
}
$props = ' '; $props = ' ';
// Always pass the class needed by Vue to mount the component; // Always pass the class needed by Vue to mount the component;
@ -988,7 +993,7 @@ class Theme_Helper {
* @type string $show_name Show the item title * @type string $show_name Show the item title
* @type string $show_image Show the item thumbnail * @type string $show_image Show the item thumbnail
* @type string $layout Either 'grid', 'list' or 'mosaic' * @type string $layout Either 'grid', 'list' or 'mosaic'
* @type string $crop_images_to_square Force images shape to be squared * @type string $image_size Item image size. Defaults to 'tainacan-medium'
* @type bool $show_collection_header Should it display a small version of the collection header? * @type bool $show_collection_header Should it display a small version of the collection header?
* @type bool $show_collection_label Should it displar a 'Collection' label before the collection name on the collection header? * @type bool $show_collection_label Should it displar a 'Collection' label before the collection name on the collection header?
* @type string $collection_background_color Color of the collection header background * @type string $collection_background_color Color of the collection header background
@ -1015,7 +1020,7 @@ class Theme_Helper {
'show_name' => true, 'show_name' => true,
'show_image' => true, 'show_image' => true,
'layout' => 'grid', 'layout' => 'grid',
'crop_images_to_square' => true, 'image_size' => 'tainacan-medium',
'show_collection_header' => false, 'show_collection_header' => false,
'show_collection_label' => false, 'show_collection_label' => false,
'collection_background_color' => '#454647', 'collection_background_color' => '#454647',
@ -1032,6 +1037,11 @@ class Theme_Helper {
); );
$args = wp_parse_args($args, $defaults); $args = wp_parse_args($args, $defaults);
/* Compatibility with previous version */
if ( isset($args['crop_images_to_square ']) && !$args['crop_images_to_square'] ) {
$args['image_size'] = 'tainacan-medium-full';
}
$props = ' '; $props = ' ';
// Always pass the class needed by Vue to mount the component; // Always pass the class needed by Vue to mount the component;
@ -1153,7 +1163,7 @@ class Theme_Helper {
$related_group['total_items'] > 1 ? $related_group['total_items'] > 1 ?
'<div class="wp-block-buttons"> '<div class="wp-block-buttons">
<div class="wp-block-button"> <div class="wp-block-button">
<a class="wp-block-button__link" href="/' . esc_url($related_group['collection_slug']) . '?metaquery[0][key]=' . esc_attr($related_group['metadata_id']) . '&metaquery[0][value][0]=' . esc_attr($item->get_ID()) . '&metaquery[0][compare]=IN"> <a class="wp-block-button__link" href="' . esc_url('/' . $related_group['collection_slug']) . '?metaquery[0][key]=' . esc_attr($related_group['metadata_id']) . '&metaquery[0][value][0]=' . esc_attr($item->get_ID()) . '&metaquery[0][compare]=IN">
' . sprintf( __('View all %s related items', 'tainacan'), $related_group['total_items'] ) . ' ' . sprintf( __('View all %s related items', 'tainacan'), $related_group['total_items'] ) . '
</a> </a>
</div> </div>
@ -1181,5 +1191,304 @@ class Theme_Helper {
$args = wp_parse_args($args, [ 'items_list_layout' => 'carousel' ]); $args = wp_parse_args($args, [ 'items_list_layout' => 'carousel' ]);
return $this->get_tainacan_related_items_list($args); return $this->get_tainacan_related_items_list($args);
} }
/**
* Returns an item gallery, containing document,
* attachments and other information in a slider, carousel and lightbox
*
* @param array $args {
* Optional. Array of arguments.
* @type string $item_id The Item ID
* @type string $blockId A unique identifier for the gallery, will be generated automatically if not provided,
* @type array $layoutElements Array of elements present in the gallery. Possible values are 'main' and 'carousel'
* @type array $mediaSources Array of sources for the gallery. Possible values are 'document' and 'attachments'
* @type bool $hideFileNameMain Hides the Main slider file name
* @type bool $hideFileCaptionMain Hides the Main slider file caption
* @type bool $hideFileDescriptionMain Hides the Main slider file description
* @type bool $hideFileNameThumbnails Hides the Thumbnails carousel file name
* @type bool $hideFileCaptionThumbnails Hides the Thumbnails carousel file caption
* @type bool $hideFileDescriptionThumbnails Hides the Thumbnails carousel file description
* @type bool $hideFileNameLightbox Hides the Lightbox file name
* @type bool $hideFileCaptionLightbox Hides the Lightbox file caption
* @type bool $hideFileDescriptionLightbox Hides the Lightbox file description
* @type bool $openLightboxOnClick Enables the behaviour of opening a lightbox with zoom when clicking on the media item
* @type bool $showDownloadButtonMain Displays a download button bellow the Main slider
* @type bool $lightboxHasLightBackground Show a light background instead of dark in the lightbox
* @type bool $showArrowsAsSVG Decides if the swiper carousel arrows will be an SVG icon or font icon
* @return string The HTML div to be used for rendering the item galery component
*/
public function get_tainacan_item_gallery($args = []) {
$defaults = array(
'blockId' => uniqid(),
'layoutElements' => array( 'main' => true, 'thumbnails' => true ),
'mediaSources' => array( 'document' => true, 'attachments' => true, 'metadata' => false),
'hideFileNameMain' => true,
'hideFileCaptionMain' => false,
'hideFileDescriptionMain' => true,
'hideFileNameThumbnails' => true,
'hideFileCaptionThumbnails' => true,
'hideFileDescriptionThumbnails' => true,
'hideFileNameLightbox' => false,
'hideFileCaptionLightbox' => false,
'hideFileDescriptionLightbox' => false,
'openLightboxOnClick' => true,
'showDownloadButtonMain' => true,
'lightboxHasLightBackground' => false,
'showArrowsAsSVG' => true
);
$args = wp_parse_args($args, $defaults);
// Gets the current Item. This way, the function can be used in the loop without needing to pass it
$item = isset($args['itemId']) ? $this->tainacan_get_item($args['itemId']) : $this->tainacan_get_item();
if (!$item)
return;
// Gets options from block attributes
$item_id = $item->get_id();
$block_id = $args['blockId'];
$layout_elements = $args['layoutElements'];
$media_sources = $args['mediaSources'];
$hide_file_name_main = $args['hideFileNameMain'];
$hide_file_caption_main = $args['hideFileCaptionMain'];
$hide_file_description_main = $args['hideFileDescriptionMain'];
$hide_file_name_thumbnails = $args['hideFileNameThumbnails'];
$hide_file_caption_thumbnails = $args['hideFileCaptionThumbnails'];
$hide_file_description_thumbnails = $args['hideFileDescriptionThumbnails'];
$hide_file_name_lightbox = $args['hideFileNameLightbox'];
$hide_file_caption_lightbox = $args['hideFileCaptionLightbox'];
$hide_file_description_lightbox = $args['hideFileDescriptionLightbox'];
$open_lightbox_on_click = $args['openLightboxOnClick'];
$show_download_button_main = $args['showDownloadButtonMain'];
$lightbox_has_light_background = $args['lightboxHasLightBackground'];
$show_arrows_as_svg = $args['showArrowsAsSVG'];
// Prefils arrays with proper values to avoid messsy IFs
$layout_elements = array(
'main' => (isset($layout_elements['main']) && ($layout_elements['main'] === true || $layout_elements['main'] == 'true')) ? true : false,
'thumbnails' => (isset($layout_elements['thumbnails']) && ($layout_elements['thumbnails'] === true || $layout_elements['thumbnails'] == 'true')) ? true : false
);
$media_sources = array(
'document' => (isset($media_sources['document']) && ($media_sources['document'] === true || $media_sources['document'] == 'true')) ? true : false,
'attachments' => (isset($media_sources['attachments']) && ($media_sources['attachments'] === true || $media_sources['attachments'] == 'true')) ? true : false,
'metadata' => (isset($media_sources['metadata']) && ($media_sources['metadata'] === true || $media_sources['metadata'] == 'true')) ? true : false
);
$media_items_main = array();
$media_items_thumbnails = array();
if ( $media_sources['attachments'] )
$attachments = tainacan_get_the_attachments(null, $item_id);
if ( $layout_elements['main'] ) {
$class_slide_metadata = '';
if ($hide_file_name_main)
$class_slide_metadata .= ' hide-name';
if ($hide_file_description_main)
$class_slide_metadata .= ' hide-description';
if ($hide_file_caption_main)
$class_slide_metadata .= ' hide-caption';
// Checks if there is at least one image alongside the media sources
// to decide if loading the lighbox is worthy on the main slider
if ($open_lightbox_on_click) {
$media_includes_images = false;
if ( $media_sources['document'] && !empty(tainacan_get_the_document($item_id)) ) {
$document_type = tainacan_get_the_document_type($item_id);
if ($document_type === 'attachment') {
// Uses this moment to also see if we have an image
$attachment = get_post(tainacan_get_the_document_raw($item_id));
$media_includes_images = wp_attachment_is('image', $attachment->ID);
} else if ($document_type === 'url') {
$document_options = $item->get_document_options();
$media_includes_images = isset($document_options['is_image']) && $document_options['is_image'];
}
}
if ( $media_sources['attachments'] ) {
foreach ( $attachments as $attachment ) {
$is_attachment_an_image = wp_attachment_is('image', $attachment->ID);
if ($is_attachment_an_image)
$media_includes_images = true; // Do not asign directly as we want to check if at least one is true
}
}
if (!$media_includes_images)
$open_lightbox_on_click = false;
}
if ( $media_sources['document'] && !empty(tainacan_get_the_document($item_id)) ) {
$document_type = tainacan_get_the_document_type($item_id);
// Document description is a bit more tricky
if ($document_type === 'attachment') {
$attachment = get_post(tainacan_get_the_document_raw($item_id));
$document_description = ($attachment instanceof WP_Post) ? $attachment->post_content : '';
}
$media_items_main[] =
tainacan_get_the_media_component_slide(array(
'after_slide_metadata' => (( $show_download_button_main && tainacan_the_item_document_download_link($item_id) != '' ) ?
sprintf('<span class="tainacan-item-file-download">%s</span>', tainacan_the_item_document_download_link($item_id))
: ''),
'media_content' => tainacan_get_the_document($item_id),
'media_content_full' => $open_lightbox_on_click ?
(
$document_type === 'attachment' ?
tainacan_get_the_document($item_id, 'full') :
sprintf('<div class="attachment-without-image">%s</div>', tainacan_get_the_document($item_id, 'full'))
) : '',
'media_title' => $document_type === 'attachment' ? get_the_title(tainacan_get_the_document_raw($item_id)) : '',
'media_description' => $document_type === 'attachment' ? $document_description : '',
'media_caption' => $document_type === 'attachment' ? wp_get_attachment_caption(tainacan_get_the_document_raw($item_id)) : '',
'media_type' => tainacan_get_the_document_type($item_id),
'class_slide_metadata' => $class_slide_metadata
));
}
if ( $media_sources['attachments'] ) {
foreach ( $attachments as $attachment ) {
$is_attachment_an_image = wp_attachment_is('image', $attachment->ID);
$media_items_main[] =
tainacan_get_the_media_component_slide(array(
'after_slide_metadata' => (( $show_download_button_main && tainacan_the_item_attachment_download_link($attachment->ID) != '' ) ?
sprintf('<span class="tainacan-item-file-download">%s</span>', tainacan_the_item_attachment_download_link($attachment->ID))
: ''),
'media_content' => tainacan_get_attachment_as_html($attachment->ID, $item_id),
'media_content_full' => $open_lightbox_on_click ?
(
$is_attachment_an_image ?
wp_get_attachment_image( $attachment->ID, 'full', false) :
sprintf('<div class="attachment-without-image tainacan-embed-container"><iframe id="tainacan-attachment-iframe--%s" src="%s"></iframe></div>', $block_id, tainacan_get_attachment_html_url($attachment->ID))
) : '',
'media_title' => $attachment->post_title,
'media_description' => $attachment->post_content,
'media_caption' => $attachment->post_excerpt,
'media_type' => $attachment->post_mime_type,
'class_slide_metadata' => $class_slide_metadata
));
}
}
}
// Make sure we have more than one media item otherwise
// we don't need to show thumbnails if the main carousel exists
if ( $layout_elements['main'] && count($media_items_main) <= 1 )
$layout_elements['thumbnails'] = false;
if ( $layout_elements['thumbnails'] ) {
$class_slide_metadata = '';
if ($hide_file_name_thumbnails)
$class_slide_metadata .= ' hide-name';
if ($hide_file_description_thumbnails)
$class_slide_metadata .= ' hide-description';
if ($hide_file_caption_thumbnails)
$class_slide_metadata .= ' hide-caption';
if ( $media_sources['document'] && !empty(tainacan_get_the_document($item_id)) ) {
$is_document_type_attachment = tainacan_get_the_document_type($item_id) === 'attachment';
$media_items_thumbnails[] =
tainacan_get_the_media_component_slide(array(
'media_content' => get_the_post_thumbnail($item_id, 'tainacan-medium'),
'media_content_full' => $open_lightbox_on_click ? ($is_document_type_attachment ? tainacan_get_the_document($item_id, 'full') : sprintf('<div class="attachment-without-image">%s</div>', tainacan_get_the_document($item_id, 'full')) ) : '',
'media_title' => $is_document_type_attachment ? get_the_title(tainacan_get_the_document_raw($item_id)) : '',
'media_description' => $is_document_type_attachment ? get_the_content(null, false, tainacan_get_the_document_raw($item_id)) : '',
'media_caption' => $is_document_type_attachment ? wp_get_attachment_caption(tainacan_get_the_document_raw($item_id)) : '',
'media_type' => tainacan_get_the_document_type($item_id),
'class_slide_metadata' => $class_slide_metadata
));
}
if ( $media_sources['attachments'] ) {
foreach ( $attachments as $attachment ) {
$media_items_thumbnails[] =
tainacan_get_the_media_component_slide(array(
'media_content' => wp_get_attachment_image( $attachment->ID, 'tainacan-medium', false ),
'media_content_full' => ( $open_lightbox_on_click && !$layout_elements['main'] ) ? ( wp_attachment_is('image', $attachment->ID) ? wp_get_attachment_image( $attachment->ID, 'full', false) : sprintf('<div class="attachment-without-image tainacan-embed-container"><iframe id="tainacan-attachment-iframe--%s" src="%s"></iframe></div>', $block_id, tainacan_get_attachment_html_url($attachment->ID)) ) : '',
'media_title' => $attachment->post_title,
'media_description' => $attachment->post_content,
'media_caption' => $attachment->post_excerpt,
'media_type' => $attachment->post_mime_type,
'class_slide_metadata' => $class_slide_metadata
));
}
}
}
$block_custom_css = '';
// Text color. First we check for custom preset colors, then actual values
$block_custom_css .= isset($args['textColor']) ? sprintf('--tainacan-media-metadata-color: var(--wp--preset--color--%s);', $args['textColor']) : '';
$block_custom_css .= isset($args['style']['color']['text']) ? sprintf('--tainacan-media-metadata-color: %s;', $args['style']['color']['text']) : '';
// Background color. First we check for custom preset colors, then actual values
$block_custom_css .= isset($args['backgroundColor']) ? sprintf('--tainacan-media-background: var(--wp--preset--color--%s);', $args['backgroundColor']) : '';
$block_custom_css .= isset($args['style']['color']['background']) ? sprintf('--tainacan-media-background: %s;', $args['style']['color']['background']) : '';
// Link color, if enabled. Firts we check for custom preset colors, then actual values.
$block_custom_css .= isset($args['linkColor']) ? sprintf('--swiper-theme-color: var(--wp--preset--color--%s);', $args['linkColor']) : '';
if ( isset($args['style']['elements']['link']['color']['text']) ) {
$link_color = $args['style']['elements']['link']['color']['text'];
if ( strpos( $link_color, 'var:' ) !== false ) {
$link_color = str_replace('|', '--', $link_color);
$link_color = str_replace('var:', 'var(--wp--', $link_color) . ')';
}
$block_custom_css .= sprintf('--swiper-theme-color: %s;', $link_color);
}
// Other values are obtained directly from the attributes
$block_custom_css .= (isset($args['arrowsSize']) && is_numeric($args['arrowsSize'])) ? sprintf('--swiper-navigation-size: %spx;', $args['arrowsSize']) : '';
$block_custom_css .= (isset($args['mainSliderHeight']) && is_numeric($args['mainSliderHeight'])) ? sprintf('--tainacan-media-main-carousel-height: %svh;', $args['mainSliderHeight']) : '';
$block_custom_css .= (isset($args['mainSliderWidth']) && is_numeric($args['mainSliderWidth'])) ? sprintf('--tainacan-media-main-carousel-width: %s%%;', $args['mainSliderWidth']) : '';
$block_custom_css .= (isset($args['thumbnailsCarouselWidth']) && is_numeric($args['thumbnailsCarouselWidth'])) ? sprintf('--tainacan-media-thumbs-carousel-width: %s%%;', $args['thumbnailsCarouselWidth']) : '';
$block_custom_css .= (isset($args['thumbnailsCarouselItemSize']) && is_numeric($args['thumbnailsCarouselItemSize'])) ? sprintf('--tainacan-media-thumbs-carousel-item-size: %spx;', $args['thumbnailsCarouselItemSize']) : '';
$wrapper_attributes = get_block_wrapper_attributes(
array(
'style' => $block_custom_css,
'class' => 'tainacan-media-component'
)
);
return tainacan_get_the_media_component(
'tainacan-item-gallery-block_id-' . $block_id,
$layout_elements['thumbnails'] ? $media_items_thumbnails : null,
$layout_elements['main'] ? $media_items_main : null,
array(
'wrapper_attributes' => $wrapper_attributes,
'class_main_div' => '',
'class_thumbs_div' => '',
'swiper_main_options' => $layout_elements['main'] ? array(
'navigation' => array(
'nextEl' => sprintf('.swiper-navigation-next_tainacan-item-gallery-block_id-%s-main', $block_id),
'prevEl' => sprintf('.swiper-navigation-prev_tainacan-item-gallery-block_id-%s-main', $block_id),
'preloadImages' => false,
'lazy' => true
)
) : '',
'swiper_thumbs_options' => ( $layout_elements['thumbnails'] && !$layout_elements['main'] ) ? array(
'navigation' => array(
'nextEl' => sprintf('.swiper-navigation-next_tainacan-item-gallery-block_id-%s-thumbs', $block_id),
'prevEl' => sprintf('.swiper-navigation-prev_tainacan-item-gallery-block_id-%s-thumbs', $block_id),
'preloadImages' => false,
'lazy' => true
)
) : '',
'swiper_arrows_as_svg' => $show_arrows_as_svg,
'disable_lightbox' => !$open_lightbox_on_click,
'hide_media_name' => $hide_file_name_lightbox,
'hide_media_caption' => $hide_file_caption_lightbox,
'hide_media_description' => $hide_file_description_lightbox,
'lightbox_has_light_background' => $lightbox_has_light_background
)
);
}
} }

View File

@ -127,7 +127,7 @@ function tainacan_the_item_document_download_link($item_id = 0) {
if (!$link || $item->get_document_type() == 'text' || $item->get_document_type() == 'url') if (!$link || $item->get_document_type() == 'text' || $item->get_document_type() == 'url')
return; return;
return '<a name="' . __('Download the item document', 'tainacan') . '" download="'. esc_url($link) . '" href="' . esc_url($link) . '">' . __('Download', 'tainacan') . '</a>'; return '<a name="' . __('Download the item document', 'tainacan') . '" download="'. esc_url($link) . '" href="' . esc_url($link) . '" target="_blank">' . __('Download', 'tainacan') . '</a>';
} }
@ -279,23 +279,29 @@ function tainacan_the_media_component($media_id, $media_items_thumbs, $media_ite
* @param array $media_items_main Array of media items to be rendered inside main, bigger the carousel. Default to empty array * @param array $media_items_main Array of media items to be rendered inside main, bigger the carousel. Default to empty array
* @param array|string $args { * @param array|string $args {
* Optional. Array of arguments. * Optional. Array of arguments.
* @type string before_main_div String to be added before the main gallery div * @type string wrapper_attributes String containing attrs (style, class) for the wrapper div. If used, remember to pass class="tainacan-media-component"
* @type string after_main_div String to be added after the main gallery div * @type string before_main_div String to be added before the main gallery div
* @type string before_thumbs_div String to be added before the thumbs gallery div * @type string after_main_div String to be added after the main gallery div
* @type string after_thumbs_div String to be added after the thumbs gallery div * @type string before_thumbs_div String to be added before the thumbs gallery div
* @type string before_main_ul String to be added before the main gallery ul * @type string after_thumbs_div String to be added after the thumbs gallery div
* @type string after_main_ul String to be added after the main gallery ul * @type string before_main_ul String to be added before the main gallery ul
* @type string before_thumbs_ul String to be added before the thumbs gallery ul * @type string after_main_ul String to be added after the main gallery ul
* @type string after_thumbs_ul String to be added after the thumbs gallery ul * @type string before_thumbs_ul String to be added before the thumbs gallery ul
* @type string class_main_div Class to be added to the main gallery div * @type string after_thumbs_ul String to be added after the thumbs gallery ul
* @type string class_main_ul Class to be added to the main gallery ul * @type string class_main_div Class to be added to the main gallery div
* @type string class_main_li Class to be added to the main gallery li * @type string class_main_ul Class to be added to the main gallery ul
* @type string class_thumbs_div Class to be added to the thumbs gallery div * @type string class_main_li Class to be added to the main gallery li
* @type string class_thumbs_ul Class to be added to the thumbs gallery ul * @type string class_thumbs_div Class to be added to the thumbs gallery div
* @type string class_thumbs_li Class to be added to the thumbs gallery li * @type string class_thumbs_ul Class to be added to the thumbs gallery ul
* @type array swiper_main_options Object with SwiperJS options for the main gallery * @type string class_thumbs_li Class to be added to the thumbs gallery li
* @type array swiper_thumbs_options Object with SwiperJS options for the thumb gallery * @type array swiper_main_options Object with SwiperJS options for the main gallery
* @type bool show_share_button Shows share button on lightbox * @type array swiper_thumbs_options Object with SwiperJS options for the thumb gallery
* @type bool swiper_arrows_as_svg Uses SVG icons insetead of Tainacan Icon font for navigation arrows
* @type string swiper_arrow_next_custom_svg Custom SVG icon to render next navigation arrow
* @type string swiper_arrow_prev_custom_svg Custom SVG icon to render previous navigation arrow
* @type bool disable_lightbox Do not open Photoswiper layer on click
* @type bool show_share_button Shows share button on lightbox
* @type bool lightbox_has_light_background Show a light background instead of dark in the lightbox
* } * }
* @return string * @return string
*/ */
@ -309,6 +315,7 @@ function tainacan_get_the_media_component(
global $TAINACAN_BASE_URL; global $TAINACAN_BASE_URL;
$args = array_merge(array( $args = array_merge(array(
'wrapper_attributes' => 'class="tainacan-media-component"',
'before_main_div' => '', 'before_main_div' => '',
'after_main_div' => '', 'after_main_div' => '',
'before_thumbs_div' => '', 'before_thumbs_div' => '',
@ -325,7 +332,12 @@ function tainacan_get_the_media_component(
'class_thumbs_li' => '', 'class_thumbs_li' => '',
'swiper_main_options' => [], 'swiper_main_options' => [],
'swiper_thumbs_options' => [], 'swiper_thumbs_options' => [],
'show_share_button' => false 'swiper_arrows_as_svg' => false,
'swiper_arrow_next_custom_svg' => '',
'swiper_arrow_prev_custom_svg' => '',
'disable_lightbox' => false,
'show_share_button' => false,
'lightbox_has_light_background' => false
), $args); ), $args);
$args['has_media_main'] = $media_items_main && is_array($media_items_main) && count($media_items_main); $args['has_media_main'] = $media_items_main && is_array($media_items_main) && count($media_items_main);
@ -342,11 +354,26 @@ function tainacan_get_the_media_component(
return $styles; return $styles;
} }
} }
$allowed_html = array(
'svg' => array(
'xmlns' => true,
'fill' => true,
'viewbox' => true,
'role' => true,
'aria-hidden' => true,
'focusable' => true,
'width' => true,
'height' => true,
),
'path' => array(
'd' => true,
'fill' => true,
)
);
add_filter( 'safe_style_css', 'tainacan_get_default_allowed_styles'); add_filter( 'safe_style_css', 'tainacan_get_default_allowed_styles');
ob_start();
if ( $args['has_media_main'] || $args['has_media_thumbs'] ) : if ( $args['has_media_main'] || $args['has_media_thumbs'] ) :
// Modal lightbox layer for rendering photoswipe
add_action('wp_footer', 'tainacan_get_the_media_modal_layer');
wp_enqueue_style( 'tainacan-media-component', $TAINACAN_BASE_URL . '/assets/css/tainacan-gutenberg-block-item-gallery.css', array(), TAINACAN_VERSION); wp_enqueue_style( 'tainacan-media-component', $TAINACAN_BASE_URL . '/assets/css/tainacan-gutenberg-block-item-gallery.css', array(), TAINACAN_VERSION);
?> ?>
@ -361,14 +388,13 @@ function tainacan_get_the_media_component(
tainacan_plugin.tainacan_media_components['<?php echo esc_attr($args['media_id']) ?>'] = <?php echo json_encode($args) ?>; tainacan_plugin.tainacan_media_components['<?php echo esc_attr($args['media_id']) ?>'] = <?php echo json_encode($args) ?>;
</script> </script>
<div id="<?php echo esc_attr($media_id) ?>" class="tainacan-media-component" data-module='item-gallery'> <div id="<?php echo esc_attr($media_id) ?>" data-module="item-gallery" <?php echo wp_kses_post($args['wrapper_attributes']); ?>>
<?php if ( $args['has_media_main'] ) : ?> <?php if ( $args['has_media_main'] ) : ?>
<!-- Slider main container --> <!-- Slider main container -->
<?php echo wp_kses_post($args['before_main_div']) ?> <?php echo wp_kses_post($args['before_main_div']) ?>
<div id="<?php echo esc_attr($args['media_main_id']) ?>" class="tainacan-media-component__swiper-main swiper-container <?php echo esc_attr($args['class_main_div']) ?>"> <div id="<?php echo esc_attr($args['media_main_id']) ?>" class="tainacan-media-component__swiper-main swiper <?php echo esc_attr($args['class_main_div']) ?>">
<!-- Additional required wrapper --> <!-- Additional required wrapper -->
<?php echo wp_kses_post($args['before_main_ul']) ?> <?php echo wp_kses_post($args['before_main_ul']) ?>
<ul class="swiper-wrapper <?php echo esc_attr($args['class_main_ul']) ?>"> <ul class="swiper-wrapper <?php echo esc_attr($args['class_main_ul']) ?>">
@ -388,9 +414,33 @@ function tainacan_get_the_media_component(
<?php endif; ?> <?php endif; ?>
<?php if ( $args['swiper_main_options'] && isset($args['swiper_main_options']['navigation']) ) : ?> <?php if ( $args['swiper_main_options'] && isset($args['swiper_main_options']['navigation']) ) : ?>
<!-- If we need navigation buttons --> <!-- If we need navigation buttons -->
<div class="swiper-button-prev swiper-navigation-prev_<?php echo esc_attr($args['media_main_id']) ?>"></div> <div class="swiper-button-prev swiper-navigation-prev_<?php echo esc_attr($args['media_main_id']) ?> <?php echo ($args['swiper_arrows_as_svg'] ? 'swiper-button-has-svg' : '' ) ?>">
<div class="swiper-button-next swiper-navigation-next_<?php echo esc_attr($args['media_main_id']) ?>"></div> <?php if ( $args['swiper_arrows_as_svg'] ): ?>
<?php if ( $args['swiper_arrow_prev_custom_svg'] ): ?>
<?php echo wp_kses($args['swiper_arrow_prev_custom_svg'], $allowed_html); ?>
<?php else: ?>
<svg width="var(--swiper-navigation-size)" height="var(--swiper-navigation-size)" viewBox="0 0 24 24">
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
<path d="M0 0h24v24H0z" fill="none"/>
</svg>
<?php endif; ?>
<?php endif; ?>
</div>
<div class="swiper-button-next swiper-navigation-next_<?php echo esc_attr($args['media_main_id']) ?> <?php echo ($args['swiper_arrows_as_svg'] ? 'swiper-button-has-svg' : '' ) ?>">
<?php if ( $args['swiper_arrows_as_svg'] ): ?>
<?php if ( $args['swiper_arrow_next_custom_svg'] ): ?>
<?php echo wp_kses($args['swiper_arrow_next_custom_svg'], $allowed_html); ?>
<?php else: ?>
<svg width="42" height="42" viewBox="0 0 24 24">
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
<path d="M0 0h24v24H0z" fill="none"/>
</svg>
<?php endif; ?>
<?php endif; ?>
</div>
<?php endif; ?> <?php endif; ?>
</div> </div>
<?php echo wp_kses_post($args['after_main_div']) ?> <?php echo wp_kses_post($args['after_main_div']) ?>
@ -400,8 +450,8 @@ function tainacan_get_the_media_component(
<!-- Slider thumbs container --> <!-- Slider thumbs container -->
<?php echo wp_kses_post($args['before_thumbs_div']) ?> <?php echo wp_kses_post($args['before_thumbs_div']) ?>
<div id="<?php echo esc_attr($args['media_thumbs_id']) ?>" class="tainacan-media-component__swiper-thumbs swiper-container <?php echo esc_attr($args['class_thumbs_div']) ?>"> <div id="<?php echo esc_attr($args['media_thumbs_id']) ?>" class="tainacan-media-component__swiper-thumbs swiper <?php echo esc_attr($args['class_thumbs_div']) ?>">
<!-- Additional required wrapper --> <!-- Additional required wrapper -->
<?php echo wp_kses_post($args['before_thumbs_ul']) ?> <?php echo wp_kses_post($args['before_thumbs_ul']) ?>
<ul class="swiper-wrapper <?php echo esc_attr($args['class_thumbs_ul']) ?>"> <ul class="swiper-wrapper <?php echo esc_attr($args['class_thumbs_ul']) ?>">
@ -420,8 +470,32 @@ function tainacan_get_the_media_component(
<?php if ( $args['swiper_thumbs_options'] && isset($args['swiper_thumbs_options']['navigation']) ) : ?> <?php if ( $args['swiper_thumbs_options'] && isset($args['swiper_thumbs_options']['navigation']) ) : ?>
<!-- If we need navigation buttons --> <!-- If we need navigation buttons -->
<div class="swiper-button-prev swiper-navigation-prev_<?php echo esc_attr($args['media_thumbs_id']) ?>"></div>
<div class="swiper-button-next swiper-navigation-next_<?php echo esc_attr($args['media_thumbs_id']) ?>"></div> <div class="swiper-button-prev swiper-navigation-prev_<?php echo esc_attr($args['media_thumbs_id']) ?> <?php echo ($args['swiper_arrows_as_svg'] ? 'swiper-button-has-svg' : '' ) ?>">
<?php if ( $args['swiper_arrows_as_svg'] ): ?>
<?php if ( $args['swiper_arrow_prev_custom_svg'] ): ?>
<?php echo wp_kses($args['swiper_arrow_prev_custom_svg'], $allowed_html); ?>
<?php else: ?>
<svg width="var(--swiper-navigation-size)" height="var(--swiper-navigation-size)" viewBox="0 0 24 24">
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
<path d="M0 0h24v24H0z" fill="none"/>
</svg>
<?php endif; ?>
<?php endif; ?>
</div>
<div class="swiper-button-next swiper-navigation-next_<?php echo esc_attr($args['media_thumbs_id']) ?> <?php echo ($args['swiper_arrows_as_svg'] ? 'swiper-button-has-svg' : '' ) ?>">
<?php if ( $args['swiper_arrows_as_svg'] ): ?>
<?php if ( $args['swiper_arrow_next_custom_svg'] ): ?>
<?php echo wp_kses($args['swiper_arrow_next_custom_svg'], $allowed_html); ?>
<?php else: ?>
<svg width="42" height="42" viewBox="0 0 24 24">
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
<path d="M0 0h24v24H0z" fill="none"/>
</svg>
<?php endif; ?>
<?php endif; ?>
</div>
<?php endif; ?> <?php endif; ?>
<!-- These elements will create a gradient on the side of the carousel --> <!-- These elements will create a gradient on the side of the carousel -->
@ -432,12 +506,13 @@ function tainacan_get_the_media_component(
<?php endif; ?> <?php endif; ?>
</div> </div>
<?php <?php
endif; endif; // <!-- End of if ($args['has_media_main'] || $args['has_media_thumbs'] ) -->
remove_filter( 'safe_style_css', 'tainacan_get_default_allowed_styles'); remove_filter( 'safe_style_css', 'tainacan_get_default_allowed_styles');
?> <!-- End of if ($args['has_media_main'] || $args['has_media_thumbs'] ) --> $content = ob_get_contents();
<?php ob_end_clean();
return $content;
} }
@ -536,75 +611,6 @@ function tainacan_get_the_media_component_slide( $args = array() ) {
return $content; return $content;
} }
/**
* Div with content necessay to render the photowipe modal
*
* @return string
*/
function tainacan_get_the_media_modal_layer() {
?>
<!-- Root element of PhotoSwipe lightbox. Must have class pswp. -->
<div class="tainacan-photoswipe-layer pswp" tabindex="-1" role="dialog" aria-hidden="true">
<!-- Background of PhotoSwipe.
It's a separate element, as animating opacity is faster than rgba(). -->
<div class="pswp__bg"></div>
<!-- Slides wrapper with overflow:hidden. -->
<div class="pswp__scroll-wrap">
<!-- Container that holds slides. PhotoSwipe keeps only 3 slides in DOM to save memory. -->
<!-- don't modify these 3 pswp__item elements, data is added later on. -->
<div class="pswp__container">
<div class="pswp__item"></div>
<div class="pswp__item"></div>
<div class="pswp__item"></div>
</div>
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
<div class="pswp__ui pswp__ui--hidden">
<div class="pswp__top-bar">
<!-- Controls are self-explanatory. Order can be changed. -->
<div class="pswp__counter"></div>
<div class="pswp__name"></div>
<button class="pswp__button pswp__button--close" title="<?php __('Close modal (Esc)', 'tainacan') ?>"></button>
<button class="pswp__button pswp__button--share" title="<?php __('Share', 'tainacan') ?>"></button>
<button class="pswp__button pswp__button--fs" title="<?php __('Toggle fullscreen', 'tainacan') ?>"></button>
<button class="pswp__button pswp__button--zoom" title="<?php __('Zoom in/out', 'tainacan') ?>"></button>
<!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR -->
<!-- element will get class pswp__preloader--active when preloader is running -->
<div class="pswp__preloader">
<div class="pswp__preloader__icn">
<div class="pswp__preloader__cut">
<div class="pswp__preloader__donut"></div>
</div>
</div>
</div>
</div>
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
<div class="pswp__share-tooltip"></div>
</div>
<button class="pswp__button pswp__button--arrow--left" title="<?php __('Next', 'tainacan') ?>"></button>
<button class="pswp__button pswp__button--arrow--right" title="<?php __('Previous', 'tainacan') ?>"></button>
<div class="pswp__caption">
<div class="pswp__caption__center"></div>
</div>
</div>
</div>
</div>
<?php
}
/** /**
* When visiting a collection archive or single, returns the collection url link * When visiting a collection archive or single, returns the collection url link
* *
@ -1022,8 +1028,8 @@ function tainacan_get_the_mime_type_icon($mime_type, $image_size = 'medium') {
* @param array $args { * @param array $args {
* Optional. Array of arguments. * Optional. Array of arguments.
* @type string $collection_id The Collection ID * @type string $collection_id The Collection ID
* @type string $search_URL A query string to fetch items from, if load strategy is 'search' * @type string $search_URL A query string to fetch items from, if load strategy is 'search'
* @type array $selected_items An array of item IDs to fetch items from, if load strategy is 'selection' and an array of items, if the load strategy is 'parent' * @type array $selected_items An array of item IDs to fetch items from, if load strategy is 'selection' and an array of items, if the load strategy is 'parent'
* @type string $load_strategy Either 'search' or 'selection', to determine how items will be fetch * @type string $load_strategy Either 'search' or 'selection', to determine how items will be fetch
* @type integer $max_items_number Maximum number of items to be fetch * @type integer $max_items_number Maximum number of items to be fetch
* @type integer $max_tems_per_screen Maximum columns of items to be displayed on a row of the carousel * @type integer $max_tems_per_screen Maximum columns of items to be displayed on a row of the carousel
@ -1032,9 +1038,9 @@ function tainacan_get_the_mime_type_icon($mime_type, $image_size = 'medium') {
* @type bool $auto_play Should the Caroulsel start automatically to slide? * @type bool $auto_play Should the Caroulsel start automatically to slide?
* @type integer $auto_play_speed The time in s to translate to the next slide automatically * @type integer $auto_play_speed The time in s to translate to the next slide automatically
* @type bool $loop_slides Should slides loop when reached the end of the Carousel? * @type bool $loop_slides Should slides loop when reached the end of the Carousel?
* @type bool $hide_title Should the title of the items be displayed? * @type bool $hide_title Should the title of the items be displayed?
* @type bool $crop_images_to_square Should it use the `tainacan-medium-size` instead of the `tainacan-medium-large-size`? * @type string $image_size Item image size. Defaults to 'tainacan-medium'
* @type bool $show_collection_header Should it display a small version of the collection header? * @type bool $show_collection_header Should it display a small version of the collection header?
* @type bool $show_collection_label Should it displar a 'Collection' label before the collection name on the collection header? * @type bool $show_collection_label Should it displar a 'Collection' label before the collection name on the collection header?
* @type string $collection_background_color Color of the collection header background * @type string $collection_background_color Color of the collection header background
* @type string $collection_text_color Color of the collection header text * @type string $collection_text_color Color of the collection header text
@ -1095,4 +1101,101 @@ function tainacan_has_related_items($item_id = false) {
return true; return true;
} }
return false; return false;
}
/**
* Renders the content of the item gallery block
* using Tainacan template functions that create
* a Swiper.js carousel and slider, with a PhotoSwipe.js
* lightbox
*
* @param array $args {
* Optional. Array of arguments.
* @type string $item_id The Item ID
* @type string $blockId A unique identifier for the gallery, will be generated automatically if not provided,
* @type array $layoutElements Array of elements present in the gallery. Possible values are 'main' and 'carousel'
* @type array $mediaSources Array of sources for the gallery. Possible values are 'document' and 'attachments'
* @type bool $hideFileNameMain Hides the Main slider file name
* @type bool $hideFileCaptionMain Hides the Main slider file caption
* @type bool $hideFileDescriptionMain Hides the Main slider file description
* @type bool $hideFileNameThumbnails Hides the Thumbnails carousel file name
* @type bool $hideFileCaptionThumbnails Hides the Thumbnails carousel file caption
* @type bool $hideFileDescriptionThumbnails Hides the Thumbnails carousel file description
* @type bool $hideFileNameLightbox Hides the Lightbox file name
* @type bool $hideFileCaptionLightbox Hides the Lightbox file caption
* @type bool $hideFileDescriptionLightbox Hides the Lightbox file description
* @type bool $openLightboxOnClick Enables the behaviour of opening a lightbox with zoom when clicking on the media item
* @type bool $showDownloadButtonMain Displays a download button bellow the Main slider
* @type bool $lightboxHasLightBackground Show a light background instead of dark in the lightbox
* @type bool $showArrowsAsSVG Decides if the swiper carousel arrows will be an SVG icon or font icon
* @return void
*/
function tainacan_the_item_gallery($args = []) {
echo \Tainacan\Theme_Helper::get_instance()->get_tainacan_item_gallery($args);
}
/**
* Render the item metadata sections as a HTML string.
*
* Each metadata section is a label with the list of its metadata name and value.
*
* If an ID, a slug or a Tainacan\Entities\Metadata_Section object is passed in the 'metadata_section' argument, it returns only one metadata section, otherwise
* it returns all metadata section
*
* @param array|string $args {
* Optional. Array or string of arguments.
*
* @type mixed $metadata_section Metadatum object, ID or slug to retrieve only one metadatum. empty returns all metadata_sections
*
* @type array $metadata_sections__in Array of metadata_sections IDs or Slugs to be retrieved. Default none
*
* @type array $metadata_sections__not_in Array of metadata_sections IDs (slugs not accepted) to excluded. Default none
*
* @type bool $hide_name Do not display the Metadata Section name. Default false
*
* @type bool $hide_description Do not display the Metadata Section description. Default true
*
* @type bool $hide_empty Wether to hide or not metadata sections if there are no metadata list or they are empty
* Default: true
* @type string $empty_metadata_list_message Message string to display if $hide_empty is false and there is not metadata section metadata list.
* Default: ''
* @type bool $display_slug_as_class Show metadata slug as a class in the div before the metadata block
* Default: true
* @type string $before String to be added before each metadata section block
* Default '<section $id>'
* @type string $after String to be added after each metadata section block
* Default '</section>'
* @type string $before_name String to be added before each metadata section name
* Default '<h2>'
* @type string $after_name String to be added after each metadata section name
* Default '</h2>'
* @type string $before_description String to be added before each metadata section description
* Default '<p>'
* @type string $after_description String to be added after each metadata section description
* Default '</p>'
* @type string $before_metadata_list String to be added before each metadata section inner metadata list
* Default '<div class="metadata-section__metadata-list">'
* @type string $after_metadata_list String to be added after each metadata section inner metadata list
* Default '</div>'
* @type array $metadata_list_args Arguments to be passed to the get_metadata_as_html function when calling section metadata
* }
*
* @return string The HTML output
*/
function tainacan_get_the_metadata_sections($args = array(), $item_id = 0) {
$item = tainacan_get_item( $item_id );
if ($item instanceof \Tainacan\Entities\Item) {
return $item->get_metadata_sections_as_html($args);
}
return '';
}
function tainacan_the_metadata_sections($args = array()) {
echo tainacan_get_the_metadata_sections($args);
} }

View File

@ -480,6 +480,23 @@ class Migrations {
} }
} }
static function insert_meta_default_metadata_section() {
global $wpdb;
// create metadata
$wpdb->query(
$wpdb->prepare(
"INSERT INTO $wpdb->postmeta (post_id,meta_key,meta_value)
SELECT ID,'metadata_section_id', %s FROM $wpdb->posts
WHERE post_type = %s AND ID NOT IN (
SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s
)"
,\Tainacan\Entities\Metadata_Section::$default_section_slug
,\Tainacan\Entities\Metadatum::$post_type
,\Tainacan\Entities\Metadata_Section::$default_section_slug
)
);
}
} }

View File

@ -4,7 +4,7 @@ Tags: museums, libraries, archives, GLAM, collections, repository
Requires at least: 5.0 Requires at least: 5.0
Tested up to: 6.0 Tested up to: 6.0
Requires PHP: 5.6 Requires PHP: 5.6
Stable tag: 0.18.10 Stable tag: 0.19
License: GPLv2 or later License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html License URI: http://www.gnu.org/licenses/gpl-3.0.html

View File

@ -4,17 +4,17 @@ Plugin Name: Tainacan
Plugin URI: https://tainacan.org/ Plugin URI: https://tainacan.org/
Description: Open source, powerful and flexible repository platform for WordPress. Manage and publish you digital collections as easily as publishing a post to your blog, while having all the tools of a professional repository platform. Description: Open source, powerful and flexible repository platform for WordPress. Manage and publish you digital collections as easily as publishing a post to your blog, while having all the tools of a professional repository platform.
Author: Tainacan.org Author: Tainacan.org
Version: 0.18.10 Version: 0.19
Requires at least: 5.0 Requires at least: 5.0
Tested up to: 6.0 Tested up to: 6.0
Requires PHP: 5.6 Requires PHP: 5.6
Stable tag: 0.18.10 Stable tag: 0.19
Text Domain: tainacan Text Domain: tainacan
License: GPLv2 or later License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/ */
const TAINACAN_VERSION = '0.18.10'; const TAINACAN_VERSION = '0.19';
defined( 'ABSPATH' ) or die( 'No script kiddies please!' ); defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
$TAINACAN_BASE_URL = plugins_url('', __FILE__); $TAINACAN_BASE_URL = plugins_url('', __FILE__);
@ -35,8 +35,20 @@ add_action( 'after_setup_theme', function() {
add_image_size( 'tainacan-small', 40, 40, true ); add_image_size( 'tainacan-small', 40, 40, true );
add_image_size( 'tainacan-medium', 275, 275, true ); add_image_size( 'tainacan-medium', 275, 275, true );
add_image_size( 'tainacan-medium-full', 205, 1500 ); add_image_size( 'tainacan-medium-full', 205, 1500 );
add_image_size( 'tainacan-large-full', 480, 860 );
} ); } );
// This enables Tainacan media sizes in the admin interface, including Gutenberg blocks
add_filter( 'image_size_names_choose', function ( $sizes ) {
return array_merge( $sizes, array(
'tainacan-small' => __( 'Tainacan small (40x40 - cropped)', 'tainacan' ),
'tainacan-medium' => __( 'Tainacan medium (275x275 - cropped)', 'tainacan' ),
'tainacan-medium-full' => __( 'Tainacan medium full (205x1500 - not cropped)', 'tainacan' ),
'tainacan-large-full' => __( 'Tainacan large full (480x860 - not cropped)', 'tainacan' )
) );
} );
add_action('init', ['Tainacan\Migrations', 'run_migrations']); add_action('init', ['Tainacan\Migrations', 'run_migrations']);
//https://core.trac.wordpress.org/ticket/23022 //https://core.trac.wordpress.org/ticket/23022

View File

@ -3,44 +3,46 @@
id="tainacan-admin-app" id="tainacan-admin-app"
class="has-mounted columns is-fullheight" class="has-mounted columns is-fullheight"
:class="{ :class="{
'tainacan-admin-iframe-mode': isIframeMode, 'tainacan-admin-mobile-app-mode': $adminOptions.mobileAppMode
'tainacan-admin-mobile-mode': isMobileMode,
'tainacan-admin-read-mode': isReadMode
}"> }">
<template v-if="activeRoute == 'HomePage'"> <template v-if="activeRoute == 'HomePage'">
<tainacan-header /> <tainacan-header v-if="!$adminOptions.hideTainacanHeader" />
<router-view /> <router-view />
</template> </template>
<template v-else> <template v-else>
<template v-if="!isIframeMode && !isMobileMode"> <primary-menu
<primary-menu v-if="!$adminOptions.hidePrimaryMenu"
:active-route="activeRoute" :active-route="activeRoute"
:is-menu-compressed="isMenuCompressed"/> :is-menu-compressed="isMenuCompressed"/>
<button <button
class="is-hidden-mobile" v-if="!$adminOptions.hidePrimaryMenu && !$adminOptions.hidePrimaryMenuCompressButton"
id="menu-compress-button" class="is-hidden-mobile"
@click="isMenuCompressed = !isMenuCompressed"> id="menu-compress-button"
<span :style="{ top: menuCompressButtonTop }"
v-tooltip="{ @click="isMenuCompressed = !isMenuCompressed"
content: $i18n.get('label_shrink_menu'), :aria-label="$i18n.get('label_shrink_menu')">
autoHide: true, <span
placement: 'auto-end', v-tooltip="{
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'] content: $i18n.get('label_shrink_menu'),
}" autoHide: true,
class="icon"> placement: 'auto-end',
<i popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip']
:class="{ 'tainacan-icon-arrowleft' : !isMenuCompressed, 'tainacan-icon-arrowright' : isMenuCompressed }" }"
class="tainacan-icon tainacan-icon-1-25em"/> class="icon">
</span> <i
</button> :class="{ 'tainacan-icon-arrowleft' : !isMenuCompressed, 'tainacan-icon-arrowright' : isMenuCompressed }"
<tainacan-header /> class="tainacan-icon tainacan-icon-1-25em"/>
<tainacan-repository-subheader </span>
:is-repository-level="isRepositoryLevel" </button>
:is-menu-compressed="isMenuCompressed"/> <tainacan-header v-if="!$adminOptions.hideTainacanHeader" />
</template> <tainacan-repository-subheader
v-if="!$adminOptions.hideRepositorySubheader"
:is-repository-level="isRepositoryLevel"
:is-menu-compressed="isMenuCompressed"/>
<div <div
id="repository-container" id="repository-container"
class="column is-main-content"> class="column is-main-content"
:style="$adminOptions.hidePrimaryMenu ? '--tainacan-sidebar-width: 0px' : ''">
<router-view /> <router-view />
</div> </div>
</template> </template>
@ -52,7 +54,7 @@
import TainacanHeader from './components/navigation/tainacan-header.vue'; import TainacanHeader from './components/navigation/tainacan-header.vue';
import TainacanRepositorySubheader from './components/navigation/tainacan-repository-subheader.vue'; import TainacanRepositorySubheader from './components/navigation/tainacan-repository-subheader.vue';
import CustomDialog from './components/other/custom-dialog.vue'; import CustomDialog from './components/other/custom-dialog.vue';
import 'swiper/css/swiper.min.css'; import "floating-vue/dist/style.css";
export default { export default {
name: "AdminPage", name: "AdminPage",
@ -69,14 +71,24 @@
} }
}, },
computed: { computed: {
isReadMode() { menuCompressButtonTop() {
return this.$route && this.$route.query && this.$route.query.readmode; let amountOfElementsAbove = [
}, this.$adminOptions.hidePrimaryMenuRepositoryButton,
isIframeMode() { this.$adminOptions.hidePrimaryMenuCollectionsButton,
return this.$route && this.$route.query && this.$route.query.iframemode; this.$adminOptions.hidePrimaryMenuItemsButton
}, ].filter(Boolean).length;
isMobileMode() {
return this.$route && this.$route.query && this.$route.query.mobilemode; switch (amountOfElementsAbove) {
case 3:
return 'calc(2.05em + 12px)';
case 2:
return 'calc(4.65em + 12px)';
case 1:
return 'calc(7.5em + 12px)';
case 0:
default:
return 'calc(10.125em + 12px)';
}
} }
}, },
watch: { watch: {
@ -135,7 +147,7 @@
} }
@media screen and (max-width: 769px) { @media screen and (max-width: 769px) {
.is-fullheight:not(.tainacan-admin-mobile-mode):not(.tainacan-admin-collection-mobile-mode) { .is-fullheight:not(.tainacan-admin-mobile-app-mode):not(.tainacan-admin-collection-mobile-app-mode) {
height: auto; height: auto;
} }
} }
@ -155,18 +167,24 @@
margin-right: 0px; margin-right: 0px;
} }
} }
#primary-menu.is-compressed~.is-main-content {
--tainacan-sidebar-width: 3.0em;
}
#primary-menu:not(.is-compressed)~.is-main-content {
--tainacan-sidebar-width: 10em;
}
.is-secondary-content { .is-secondary-content {
padding: 0px !important; padding: 0px !important;
margin: 5.875em auto 0 auto; margin: 5.4em auto 0 auto;
position: relative; position: relative;
overflow-y: hidden; overflow-y: hidden;
overflow-x: hidden; overflow-x: hidden;
height: calc(100% - 5.875em); height: calc(100vh - 5.4em);
@media screen and (max-width: 769px) { @media screen and (max-width: 769px) {
overflow-y: visible; overflow-y: visible;
margin: 40px auto 0 auto; margin: 38px auto 0 auto;
} }
@ -179,7 +197,7 @@
#menu-compress-button { #menu-compress-button {
position: absolute; position: absolute;
z-index: 999; z-index: 999;
top: calc(11.125em + 12px); top: calc(10.125em + 12px);
left: 0px; left: 0px;
max-width: 1.5625em; max-width: 1.5625em;
height: 1.5625em; height: 1.5625em;

View File

@ -3,7 +3,7 @@
/** /**
* @see \Tainacan\Admin_Hooks->register() * @see \Tainacan\Admin_Hooks->register()
*/ */
function tainacan_register_admin_hook( $context, $callback, $position = 'end-left' ) { function tainacan_register_admin_hook( $context, $callback, $position = 'end-left', $conditional = null ) {
$admin_hooks = \Tainacan\Admin_Hooks::get_instance(); $admin_hooks = \Tainacan\Admin_Hooks::get_instance();
return $admin_hooks->register( $context, $callback, $position ); return $admin_hooks->register( $context, $callback, $position, $conditional );
} }

View File

@ -31,7 +31,7 @@ class Admin_Hooks {
} }
public function get_available_contexts() { public function get_available_contexts() {
return apply_filters('tainacan-admin-hooks-contexts', ['collection', 'metadatum', 'item', 'taxonomy', 'term', 'filter']); return apply_filters('tainacan-admin-hooks-contexts', ['collection', 'metadatum', 'item', 'taxonomy', 'term', 'filter', 'role', 'metadataSection']);
} }
public function get_registered_hooks() { public function get_registered_hooks() {
@ -41,21 +41,28 @@ class Admin_Hooks {
/** /**
* *
* @param string $context The context to add the hook to (collection, metadatum, item, taxonomy, term or filter) * @param string $context The context to add the hook to (collection, metadatum, item, taxonomy, term or filter)
* @param string $position The position inside the page to hook. (begin, end, begin-left, begin-right, end-left, end-right)
* @param callable $callback The callback that will output the form HTML * @param callable $callback The callback that will output the form HTML
* @param string $position The position inside the page to hook. (begin, end, begin-left, begin-right, end-left, end-right)
* @param array $conditional Key-named array containing an 'attribute' and a 'value' that will be checked in the context form object before rendering the hook.
*/ */
public function register( $context, $callback, $position = 'end-left' ) { public function register( $context, $callback, $position = 'end-left', $conditional = null ) {
$contexts = $this->get_available_contexts(); $contexts = $this->get_available_contexts();
$positions = $this->get_available_positions(); $positions = $this->get_available_positions();
if ( !in_array($context, $contexts) || !in_array($position, $positions) ) { if ( !in_array($context, $contexts) || !in_array($position, $positions) ) {
return false; return false;
} }
$result = call_user_func($callback); $result = call_user_func($callback);
if (is_string($result)){
$this->registered_hooks[$context][$position][] = $result; if ( is_string($result) ) {
$this->registered_hooks[$context][$position][] = [
'form' => $result,
'conditional' => !empty($conditional) ? $conditional : false
];
return true; return true;
} }
return false; return false;

View File

@ -11,7 +11,7 @@
label-width="120px"> label-width="120px">
<div class="columns"> <div class="columns">
<div class="column is-5"> <div class="column">
<!-- Name -------------------------------- --> <!-- Name -------------------------------- -->
<b-field <b-field
@ -25,177 +25,54 @@
:message="$i18n.getHelperMessage('collections', 'name')"/> :message="$i18n.getHelperMessage('collections', 'name')"/>
<b-input <b-input
id="tainacan-text-name" id="tainacan-text-name"
:placeholder="$i18n.get('instruction_collection_name')"
v-model="form.name" v-model="form.name"
@blur="updateSlug" @blur="updateSlug"
@focus="clearErrors('name')"/> @focus="clearErrors('name')"/>
</b-field> </b-field>
<!-- Hook for extra Form options --> <!-- Hook for extra Form options -->
<template <template v-if="hasBeginLeftForm">
v-if="formHooks != undefined &&
formHooks['collection'] != undefined &&
formHooks['collection']['begin-left'] != undefined">
<form <form
class="form-hook-region" class="form-hook-region"
id="form-collection-begin-left" id="form-collection-begin-left"
v-html="formHooks['collection']['begin-left'].join('')"/> v-html="getBeginLeftForm"/>
</template> </template>
<!-- Thumbnail -------------------------------- --> <!-- Description -------------------------------- -->
<b-field :addons="false">
<label class="label">{{ $i18n.get('label_thumbnail') }}</label>
<div class="thumbnail-field">
<file-item
v-if="collection.thumbnail != undefined && ((collection.thumbnail['tainacan-medium'] != undefined && collection.thumbnail['tainacan-medium'] != false) || (collection.thumbnail.medium != undefined && collection.thumbnail.medium != false))"
:show-name="false"
:modal-on-click="true"
:size="178"
:file="{
media_type: 'image',
thumbnails: { 'tainacan-medium': [ $thumbHelper.getSrc(collection['thumbnail'], 'tainacan-medium') ] },
title: $i18n.get('label_thumbnail'),
description: `<img alt='` + $i18n.get('label_thumbnail') + `' src='` + $thumbHelper.getSrc(collection['thumbnail'], 'full') + `'/>`
}"/>
<figure
v-if="collection.thumbnail == undefined || ((collection.thumbnail.medium == undefined || collection.thumbnail.medium == false) && (collection.thumbnail['tainacan-medium'] == undefined || collection.thumbnail['tainacan-medium'] == false))"
class="image">
<span class="image-placeholder">{{ $i18n.get('label_empty_thumbnail') }}</span>
<img
:alt="$i18n.get('label_thumbnail')"
:src="$thumbHelper.getEmptyThumbnailPlaceholder()">
</figure>
<div class="thumbnail-buttons-row">
<a
class="button is-rounded is-secondary"
id="button-edit-thumbnail"
:aria-label="$i18n.get('label_button_edit_thumb')"
@click.prevent="thumbnailMediaFrame.openFrame($event)">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom'
}"
class="icon">
<i class="tainacan-icon tainacan-icon-edit"/>
</span>
</a>
<a
class="button is-rounded is-secondary"
id="button-delete-header-image"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteThumbnail()">
<span
v-tooltip="{
content: $i18n.get('delete'),
autoHide: true,
placement: 'bottom'
}"
class="icon">
<i class="tainacan-icon tainacan-icon-delete"/>
</span>
</a>
</div>
</div>
</b-field>
<!-- Cover Page -------------------------------- -->
<b-field <b-field
:addons="false" :addons="false"
:label="$i18n.get('label_cover_page')" :label="$i18n.get('label_description')"
:type="editFormErrors['cover_page_id'] != undefined ? 'is-danger' : ''" :type="editFormErrors['description'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['cover_page_id'] != undefined ? editFormErrors['cover_page_id'] : ''"> :message="editFormErrors['description'] != undefined ? editFormErrors['description'] : ''">
&nbsp;
<b-switch
id="tainacan-checkbox-cover-page"
size="is-small"
true-value="yes"
false-value="no"
v-model="form.enable_cover_page" />
<help-button <help-button
:title="$i18n.getHelperTitle('collections', 'cover_page_id')" :title="$i18n.getHelperTitle('collections', 'description')"
:message="$i18n.getHelperMessage('collections', 'cover_page_id')"/> :message="$i18n.getHelperMessage('collections', 'description')"/>
<b-autocomplete <b-input
id="tainacan-text-cover-page" id="tainacan-text-description"
:placeholder="$i18n.get('instruction_cover_page')" type="textarea"
:data="coverPages" rows="3"
v-model="coverPageTitle" :placeholder="$i18n.get('instruction_collection_description')"
@select="onSelectCoverPage($event)" v-model="form.description"
:loading="isFetchingPages" @focus="clearErrors('description')"/>
@input="fecthCoverPages" </b-field>
@focus="clearErrors('cover_page_id')"
v-if="coverPage == undefined || coverPage.title == undefined" <!-- Slug -------------------------------- -->
:disabled="form.enable_cover_page != 'yes'" <b-field
check-infinite-scroll :addons="false"
@infinite-scroll="fetchMoreCoverPages"> :label="$i18n.get('label_slug')"
<template slot-scope="props"> :type="editFormErrors['slug'] != undefined ? 'is-danger' : ''"
{{ props.option.title.rendered }} :message="isUpdatingSlug ? $i18n.get('info_validating_slug') : (editFormErrors['slug'] != undefined ? editFormErrors['slug'] : '')">
</template> <help-button
<template slot="empty">{{ $i18n.get('info_no_page_found') }}</template> :title="$i18n.getHelperTitle('collections', 'slug')"
</b-autocomplete> :message="$i18n.getHelperMessage('collections', 'slug')"/>
<b-input
<div id="tainacan-text-slug"
v-if="coverPage != undefined && coverPage.title != undefined" @input="updateSlug"
class="control selected-cover-page"> v-model="form.slug"
<span v-html="coverPage.title.rendered" /> @focus="clearErrors('slug')"
<span class="selected-cover-page-control"> :disabled="isUpdatingSlug"
<a :loading="isUpdatingSlug"/>
target="_blank"
@click.prevent="removeCoverPage()">
<span
v-tooltip="{
content: $i18n.get('remove_value'),
autoHide: true,
placement: 'bottom'
}"
class="icon is-small">
<i class="tainacan-icon tainacan-icon-close"/>
</span>
</a>
</span>
</div>
<span
:class="{'disabled': form.enable_cover_page != 'yes' || coverPage == undefined || coverPage.title == undefined}"
class="selected-cover-page-buttons">
<a
target="_blank"
:href="coverPage.link">
<span
v-tooltip="{
content: $i18n.get('see'),
autoHide: true,
placement: 'bottom'
}"
class="icon is-small">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-see"/>
</span>
</a>
&nbsp;&nbsp;
<a
target="blank"
:href="coverPageEditPath">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom'
}"
class="icon is-small">
<i class="tainacan-icon tainacan-icon-edit"/>
</span>
</a>
</span>
<br>
<a
class="add-link"
style="font-size: 0.875em;"
:class="{'disabled': form.enable_cover_page != 'yes'}"
target="_blank"
:href="newPagePath">
<span class="icon is-small">
<i class="tainacan-icon tainacan-icon-add"/>
</span>
{{ $i18n.get('label_create_new_page') }}</a>
</b-field> </b-field>
<!-- Change Default OrderBy Select and Order Button--> <!-- Change Default OrderBy Select and Order Button-->
@ -245,6 +122,90 @@
</div> </div>
</b-field> </b-field>
<label class="label">{{ $i18n.get('label_view_modes_public_list') }}</label>
<div class="items-view-mode-options">
<!-- Enabled View Modes ------------------------------- -->
<div class="field">
<label class="label">{{ $i18n.get('label_view_modes_available') }}</label>
<help-button
:title="$i18n.getHelperTitle('collections', 'enabled_view_modes')"
:message="$i18n.getHelperMessage('collections', 'enabled_view_modes')"/>
<div class="control">
<b-dropdown
class="enabled-view-modes-dropdown"
ref="enabledViewModesDropdown"
:mobile-modal="true"
:disabled="Object.keys(registeredViewModes).length < 0"
aria-role="list"
trap-focus
position="is-top-right">
<button
class="button is-white"
slot="trigger"
position="is-top-right"
type="button">
<span>{{ $i18n.get('label_enabled_view_modes') }}</span>
<span class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-arrowdown"/>
</span>
</button>
<b-dropdown-item
v-for="(viewMode, index) in Object.keys(registeredViewModes)"
:key="index"
custom
aria-role="listitem">
<b-checkbox
v-if="registeredViewModes[viewMode] != undefined"
@input="updateViewModeslist(viewMode)"
:value="checkIfViewModeEnabled(viewMode)"
:disabled="checkIfViewModeEnabled(viewMode) && form.enabled_view_modes.filter((aViewMode) => (registeredViewModes[aViewMode] && registeredViewModes[aViewMode].full_screen != true)).length <= 1">
<p>
<strong>
<span
class="gray-icon"
:class="{
'has-text-secondary' : checkIfViewModeEnabled(viewMode),
'has-text-gray4' : !checkIfViewModeEnabled(viewMode)
}"
v-html="registeredViewModes[viewMode].icon"/>
&nbsp;{{ registeredViewModes[viewMode].label }}
</strong>
</p>
<p v-if="registeredViewModes[viewMode].description">{{ registeredViewModes[viewMode].description }}</p>
</b-checkbox>
</b-dropdown-item>
</b-dropdown>
</div>
</div>
<!-- Default View Mode -------------------------------- -->
<b-field
v-if="form.enabled_view_modes.length > 0"
:addons="false"
:label="$i18n.get('label_default')"
:type="editFormErrors['default_view_mode'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['default_view_mode'] != undefined ? editFormErrors['default_view_mode'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'default_view_mode')"
:message="$i18n.getHelperMessage('collections', 'default_view_mode')"/>
<b-select
expanded
id="tainacan-select-default_view_mode"
v-model="form.default_view_mode"
@focus="clearErrors('default_view_mode')">
<option
v-for="(viewMode, index) of form.enabled_view_modes"
v-if="registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen != true"
:key="index"
:value="viewMode">
{{ registeredViewModes[viewMode].label }}
</option>
</b-select>
</b-field>
</div>
<!-- Hide Items Thumbnail on Lists ------------------------ --> <!-- Hide Items Thumbnail on Lists ------------------------ -->
<b-field <b-field
:addons="false" :addons="false"
@ -261,243 +222,6 @@
:message="$i18n.getHelperMessage('collections', 'hide_items_thumbnail_on_lists')"/> :message="$i18n.getHelperMessage('collections', 'hide_items_thumbnail_on_lists')"/>
</b-field> </b-field>
<!-- Enabled View Modes ------------------------------- -->
<div class="field">
<label class="label">{{ $i18n.get('label_view_modes_available') }}</label>
<help-button
:title="$i18n.getHelperTitle('collections', 'enabled_view_modes')"
:message="$i18n.getHelperMessage('collections', 'enabled_view_modes')"/>
<div class="control">
<b-dropdown
class="two-columns-dropdown enabled-view-modes-dropdown"
ref="enabledViewModesDropdown"
:mobile-modal="true"
:disabled="Object.keys(registeredViewModes).length < 0"
aria-role="list"
trap-focus>
<button
class="button is-white"
slot="trigger"
position="is-top-right"
type="button">
<span>{{ $i18n.get('label_enabled_view_modes') }}</span>
<span class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-arrowdown"/>
</span>
</button>
<b-dropdown-item
v-for="(viewMode, index) in Object.keys(registeredViewModes)"
:key="index"
custom
aria-role="listitem">
<b-checkbox
v-if="registeredViewModes[viewMode] != undefined"
@input="updateViewModeslist(viewMode)"
:value="checkIfViewModeEnabled(viewMode)"
:disabled="checkIfViewModeEnabled(viewMode) && form.enabled_view_modes.filter((aViewMode) => (registeredViewModes[aViewMode] && registeredViewModes[aViewMode].full_screen != true)).length <= 1">
<p>
<strong>
<span
class="gray-icon"
:class="{
'has-text-secondary' : checkIfViewModeEnabled(viewMode),
'has-text-gray4' : !checkIfViewModeEnabled(viewMode)
}"
v-html="registeredViewModes[viewMode].icon"/>
&nbsp;{{ registeredViewModes[viewMode].label }}
</strong>
</p>
<p v-if="registeredViewModes[viewMode].description">{{ registeredViewModes[viewMode].description }}</p>
</b-checkbox>
</b-dropdown-item>
</b-dropdown>
</div>
</div>
<!-- Default View Mode -------------------------------- -->
<b-field
v-if="form.enabled_view_modes.length > 0"
:addons="false"
:label="$i18n.get('label_default_view_mode')"
:type="editFormErrors['default_view_mode'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['default_view_mode'] != undefined ? editFormErrors['default_view_mode'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'default_view_mode')"
:message="$i18n.getHelperMessage('collections', 'default_view_mode')"/>
<b-select
expanded
id="tainacan-select-default_view_mode"
v-model="form.default_view_mode"
@focus="clearErrors('default_view_mode')">
<option
v-for="(viewMode, index) of form.enabled_view_modes"
v-if="registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen != true"
:key="index"
:value="viewMode">
{{ registeredViewModes[viewMode].label }}
</option>
</b-select>
</b-field>
<!-- Hook for extra Form options -->
<template
v-if="formHooks != undefined &&
formHooks['collection'] != undefined &&
formHooks['collection']['end-left'] != undefined">
<form
ref="form-collection-end-left"
id="form-collection-end-left"
class="form-hook-region"
v-html="formHooks['collection']['end-left'].join('')"/>
</template>
</div>
<div class="column">
<!-- Status -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_status')"
:type="editFormErrors['status'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['status'] != undefined ? editFormErrors['status'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'status')"
:message="$i18n.getHelperMessage('collections', 'status')"/>
<div class="status-radios">
<b-radio
v-model="form.status"
v-for="(statusOption, index) of $statusHelper.getStatuses().filter((status) => status.slug != 'draft')"
:key="index"
:native-value="statusOption.slug">
<span class="icon has-text-gray">
<i
class="tainacan-icon tainacan-icon-18px"
:class="$statusHelper.getIcon(statusOption.slug)"/>
</span>
{{ statusOption.name }}
</b-radio>
</div>
</b-field>
<!-- Header Image -------------------------------- -->
<b-field :addons="false">
<label class="label">{{ $i18n.get('label_header_image') }}</label>
<div class="header-field">
<figure class="image">
<span
v-if="collection.header_image == undefined || collection.header_image == false"
class="image-placeholder">{{ $i18n.get('label_empty_header_image') }}</span>
<img
:alt="$i18n.get('label_thumbnail')"
:src="(collection.header_image == undefined || collection.header_image == false) ? headerPlaceholderPath : collection.header_image">
</figure>
<div class="header-buttons-row">
<a
class="button is-rounded is-secondary"
id="button-edit-header-image"
:aria-label="$i18n.get('label_button_edit_header_image')"
@click="headerImageMediaFrame.openFrame($event)">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom'
}"
class="icon">
<i class="tainacan-icon tainacan-icon-edit"/>
</span>
</a>
<a
class="button is-rounded is-secondary"
id="button-delete-header-image"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteHeaderImage()">
<span
v-tooltip="{
content: $i18n.get('delete'),
autoHide: true,
placement: 'bottom'
}"
class="icon">
<i class="tainacan-icon tainacan-icon-delete"/>
</span>
</a>
</div>
</div>
</b-field>
<!-- Hook for extra Form options -->
<template
v-if="formHooks != undefined &&
formHooks['collection'] != undefined &&
formHooks['collection']['begin-right'] != undefined">
<form
id="form-collection-begin-right"
class="form-hook-region"
v-html="formHooks['collection']['begin-right'].join('')"/>
</template>
<!-- Description -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_description')"
:type="editFormErrors['description'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['description'] != undefined ? editFormErrors['description'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'description')"
:message="$i18n.getHelperMessage('collections', 'description')"/>
<b-input
id="tainacan-text-description"
type="textarea"
v-model="form.description"
@focus="clearErrors('description')"/>
</b-field>
<!-- Parent Collection -------------------------------- -->
<!-- DISABLED IN 0.18 AS WE DISCUSS BETTER IMPLEMENTATION FOR COLLECTIONS HIERARCHY -->
<!-- <b-field
:addons="false"
:label="$i18n.get('label_parent_collection')"
:type="editFormErrors['parent'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['parent'] != undefined ? editFormErrors['parent'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'parent')"
:message="$i18n.getHelperMessage('collections', 'parent')"/>
<b-select
expanded
id="tainacan-select-parent"
v-model="form.parent"
@focus="clearErrors('parent')"
:loading="isFetchingCollections"
:placeholder="$i18n.get('instruction_select_a_parent_collection')">
<option value="0">{{ $i18n.get('label_no_parent_collection') }}</option>
<option
v-if="collection.id != anotherCollection.id"
v-for="anotherCollection of collections"
:key="anotherCollection.id"
:value="anotherCollection.id">{{ anotherCollection.name }}
</option>
</b-select>
</b-field> -->
<!-- Slug -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_slug')"
:type="editFormErrors['slug'] != undefined ? 'is-danger' : ''"
:message="isUpdatingSlug ? $i18n.get('info_validating_slug') : (editFormErrors['slug'] != undefined ? editFormErrors['slug'] : '')">
<help-button
:title="$i18n.getHelperTitle('collections', 'slug')"
:message="$i18n.getHelperMessage('collections', 'slug')"/>
<b-input
id="tainacan-text-slug"
@input="updateSlug"
v-model="form.slug"
@focus="clearErrors('slug')"
:disabled="isUpdatingSlug"
:loading="isUpdatingSlug"/>
</b-field>
<!-- Comment Status ------------------------ --> <!-- Comment Status ------------------------ -->
<b-field <b-field
:addons="false" :addons="false"
@ -606,14 +330,299 @@
</transition> </transition>
<!-- Hook for extra Form options --> <!-- Hook for extra Form options -->
<template <template v-if="hasEndLeftForm">
v-if="formHooks != undefined && <form
formHooks['collection'] != undefined && ref="form-collection-end-left"
formHooks['collection']['end-right'] != undefined"> id="form-collection-end-left"
class="form-hook-region"
v-html="getEndLeftForm"/>
</template>
</div>
<div class="column">
<!-- Status -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_status')"
:type="editFormErrors['status'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['status'] != undefined ? editFormErrors['status'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'status')"
:message="$i18n.getHelperMessage('collections', 'status')"/>
<div class="status-radios">
<b-radio
v-model="form.status"
v-for="(statusOption, index) of $statusHelper.getStatuses().filter((status) => status.slug != 'draft')"
:key="index"
:native-value="statusOption.slug">
<span class="icon has-text-gray">
<i
class="tainacan-icon tainacan-icon-18px"
:class="$statusHelper.getIcon(statusOption.slug)"/>
</span>
{{ statusOption.name }}
</b-radio>
</div>
</b-field>
<!-- Hook for extra Form options -->
<template v-if="hasBeginRightForm">
<form
id="form-collection-begin-right"
class="form-hook-region"
v-html="getBeginRightForm"/>
</template>
<!-- Image thumbnail & Header Image -------------------------------- -->
<b-field :addons="false">
<label class="label">
{{ $i18n.get('label_thumbnail') }} & {{ $i18n.get('label_header_image') }}
<help-button
:title="$i18n.get('label_thumbnail') + ' & ' + $i18n.get('label_header_image')"
:message="$i18n.get('info_collection_thumbnail_and_header')"/>
</label>
<!-- Header Image -------------------------------- -->
<div class="header-field">
<figure class="image">
<span
v-if="collection.header_image == undefined || collection.header_image == false"
class="image-placeholder">{{ $i18n.get('label_empty_header_image') }}</span>
<img
:alt="$i18n.get('label_thumbnail')"
:src="(collection.header_image == undefined || collection.header_image == false) ? headerPlaceholderPath : collection.header_image">
</figure>
<div class="header-buttons-row">
<a
class="button is-rounded is-secondary"
id="button-edit-header-image"
:aria-label="$i18n.get('label_button_edit_header_image')"
@click="headerImageMediaFrame.openFrame($event)">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-edit"/>
</span>
</a>
<a
class="button is-rounded is-secondary"
id="button-delete-header-image"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteHeaderImage()">
<span
v-tooltip="{
content: $i18n.get('delete'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-delete"/>
</span>
</a>
</div>
</div>
<!-- Thumbnail -------------------------------- -->
<div class="thumbnail-field">
<file-item
v-if="collection.thumbnail != undefined && ((collection.thumbnail['tainacan-medium'] != undefined && collection.thumbnail['tainacan-medium'] != false) || (collection.thumbnail.medium != undefined && collection.thumbnail.medium != false))"
:show-name="false"
:modal-on-click="true"
:size="146"
:file="{
media_type: 'image',
thumbnails: { 'tainacan-medium': [ $thumbHelper.getSrc(collection['thumbnail'], 'tainacan-medium') ] },
title: $i18n.get('label_thumbnail'),
description: `<img alt='` + $i18n.get('label_thumbnail') + `' src='` + $thumbHelper.getSrc(collection['thumbnail'], 'full') + `'/>`
}"/>
<figure
v-if="collection.thumbnail == undefined || ((collection.thumbnail.medium == undefined || collection.thumbnail.medium == false) && (collection.thumbnail['tainacan-medium'] == undefined || collection.thumbnail['tainacan-medium'] == false))"
class="image">
<span class="image-placeholder">{{ $i18n.get('label_empty_thumbnail') }}</span>
<img
:alt="$i18n.get('label_thumbnail')"
:src="$thumbHelper.getEmptyThumbnailPlaceholder()">
</figure>
<div class="thumbnail-buttons-row">
<a
class="button is-rounded is-secondary"
id="button-edit-thumbnail"
:aria-label="$i18n.get('label_button_edit_thumb')"
@click.prevent="thumbnailMediaFrame.openFrame($event)">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-edit"/>
</span>
</a>
<a
class="button is-rounded is-secondary"
id="button-delete-header-image"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteThumbnail()">
<span
v-tooltip="{
content: $i18n.get('delete'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-delete"/>
</span>
</a>
</div>
</div>
</b-field>
<!-- Cover Page -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_cover_page')"
:type="editFormErrors['cover_page_id'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['cover_page_id'] != undefined ? editFormErrors['cover_page_id'] : ''">
&nbsp;
<b-switch
id="tainacan-checkbox-cover-page"
size="is-small"
true-value="yes"
false-value="no"
v-model="form.enable_cover_page" />
<help-button
:title="$i18n.getHelperTitle('collections', 'cover_page_id')"
:message="$i18n.getHelperMessage('collections', 'cover_page_id')"/>
<b-autocomplete
id="tainacan-text-cover-page"
:placeholder="$i18n.get('instruction_cover_page')"
:data="coverPages"
v-model="coverPageTitle"
@select="onSelectCoverPage($event)"
:loading="isFetchingPages"
@input="fecthCoverPages"
@focus="clearErrors('cover_page_id')"
v-if="coverPage == undefined || coverPage.title == undefined"
:disabled="form.enable_cover_page != 'yes'"
check-infinite-scroll
@infinite-scroll="fetchMoreCoverPages">
<template slot-scope="props">
{{ props.option.title.rendered }}
</template>
<template slot="empty">{{ $i18n.get('info_no_page_found') }}</template>
</b-autocomplete>
<div
v-if="coverPage != undefined && coverPage.title != undefined"
class="control selected-cover-page">
<span v-html="coverPage.title.rendered" />
<span class="selected-cover-page-control">
<a
target="_blank"
@click.prevent="removeCoverPage()">
<span
v-tooltip="{
content: $i18n.get('remove_value'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon is-small">
<i class="tainacan-icon tainacan-icon-close"/>
</span>
</a>
</span>
</div>
<span
:class="{'disabled': form.enable_cover_page != 'yes' || coverPage == undefined || coverPage.title == undefined}"
class="selected-cover-page-buttons">
<a
target="_blank"
:href="coverPage.link">
<span
v-tooltip="{
content: $i18n.get('see'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon is-small">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-see"/>
</span>
</a>
&nbsp;&nbsp;
<a
target="blank"
:href="coverPageEditPath">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon is-small">
<i class="tainacan-icon tainacan-icon-edit"/>
</span>
</a>
</span>
<br>
<a
class="add-link"
style="font-size: 0.875em;"
:class="{'disabled': form.enable_cover_page != 'yes'}"
target="_blank"
:href="newPagePath">
<span class="icon is-small">
<i class="tainacan-icon tainacan-icon-add"/>
</span>
{{ $i18n.get('label_create_new_page') }}</a>
</b-field>
<!-- Parent Collection -------------------------------- -->
<!-- DISABLED IN 0.18 AS WE DISCUSS BETTER IMPLEMENTATION FOR COLLECTIONS HIERARCHY -->
<!-- <b-field
:addons="false"
:label="$i18n.get('label_parent_collection')"
:type="editFormErrors['parent'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['parent'] != undefined ? editFormErrors['parent'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'parent')"
:message="$i18n.getHelperMessage('collections', 'parent')"/>
<b-select
expanded
id="tainacan-select-parent"
v-model="form.parent"
@focus="clearErrors('parent')"
:loading="isFetchingCollections"
:placeholder="$i18n.get('instruction_select_a_parent_collection')">
<option value="0">{{ $i18n.get('label_no_parent_collection') }}</option>
<option
v-if="collection.id != anotherCollection.id"
v-for="anotherCollection of collections"
:key="anotherCollection.id"
:value="anotherCollection.id">{{ anotherCollection.name }}
</option>
</b-select>
</b-field> -->
<!-- Hook for extra Form options -->
<template v-if="hasEndRightForm">
<form <form
id="form-collection-end-right" id="form-collection-end-right"
class="form-hook-region" class="form-hook-region"
v-html="formHooks['collection']['end-right'].join('')"/> v-html="getEndRightForm"/>
</template> </template>
</div> </div>
@ -1310,7 +1319,7 @@ export default {
} }
} }
.header-field { .header-field {
padding-top: 24px; padding-top: 1px;
.image-placeholder { .image-placeholder {
position: absolute; position: absolute;
@ -1333,38 +1342,53 @@ export default {
top: -15px; top: -15px;
position: relative; position: relative;
} }
}
.thumbnail-field {
padding: 24px;
// margin-top: 16px;
// margin-bottom: 38px;
&+.thumbnail-field {
opacity: 1.0;
transition: opacity 0.2s ease;
}
&:hover+.thumbnail-field {
opacity: 0.3;
}
}
.thumbnail-field {
display: inline-block;
padding: 1rem;
margin-top: -120px;
margin-bottom: -30px;
position: relative;
z-index: 99;
.content { .content {
padding: 10px; padding: 10px;
font-size: 0.8em; font-size: 0.8em;
} }
img { img,
height: 178px; /deep/ .image-wrapper {
width: 178px; height: 146px;
width: 146px;
border: 6px solid var(--tainacan-background-color);
} }
.image-placeholder { .image-placeholder {
position: absolute; position: absolute;
margin-left: 45px; margin-left: 26px;
margin-right: 45px; margin-right: 26px;
font-size: 0.8em; font-size: 0.8em;
font-weight: bold; font-weight: bold;
z-index: 99; z-index: 99;
text-align: center; text-align: center;
color: var(--tainacan-info-color); color: var(--tainacan-info-color);
top: 70px; top: 64px;
max-width: 90px; max-width: 90px;
} }
.thumbnail-buttons-row { .thumbnail-buttons-row {
position: relative; position: relative;
left: 90px; left: 52px;
bottom: 1.0em; bottom: calc(1.0em + 12px);
} }
} }
.switch { .switch {
position: relative; position: relative;
top: -1px; top: -1px;
@ -1392,11 +1416,18 @@ export default {
.sorting-options { .sorting-options {
display: flex; display: flex;
align-items: center; align-items: center;
width: 100%;
.label { .label {
font-weight: normal; font-weight: normal;
margin-bottom: 0; margin-bottom: 0;
} }
.control.is-expanded {
width: 100%;
}
}
.sorting-options+.help {
opacity: 0.7;
} }
.status-radios { .status-radios {
display: flex; display: flex;
@ -1406,6 +1437,30 @@ export default {
align-items: center; align-items: center;
} }
} }
.items-view-mode-options {
display: flex;
&>.field:first-child {
width: 66.66%;
margin-right: 12px;
.dropdown-trigger>.button {
min-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
&>.field:last-child {
width: 33.33%;
}
@media screen and (min-width: 1024px) {
.dropdown-trigger>.button {
min-height: 40px;
}
}
}
.item-submission-options { .item-submission-options {
padding-left: 1em; padding-left: 1em;
padding-top: 1.25em; padding-top: 1.25em;
@ -1413,6 +1468,9 @@ export default {
border-left: 1px solid var(--tainacan-gray2); border-left: 1px solid var(--tainacan-gray2);
} }
.enabled-view-modes-dropdown { .enabled-view-modes-dropdown {
position: relative;
z-index: 101;
/deep/ .dropdown-item { /deep/ .dropdown-item {
display: flex !important; display: flex !important;
} }

View File

@ -30,7 +30,8 @@
:label="$i18n.get('label_source_collection')"> :label="$i18n.get('label_source_collection')">
<help-button <help-button
:title="$i18n.get('label_source_collection')" :title="$i18n.get('label_source_collection')"
:message="$i18n.get('info_source_collection_helper')"/> :message="$i18n.get('info_source_collection_helper')"
extra-classes="tainacan-repository-tooltip"/>
<br> <br>
<b-select <b-select
@input="formErrorMessage = null" @input="formErrorMessage = null"
@ -75,7 +76,8 @@
:label="$i18n.get('label_send_email')"> :label="$i18n.get('label_send_email')">
<help-button <help-button
:title="$i18n.get('label_send_email')" :title="$i18n.get('label_send_email')"
:message="'<span>' + $i18n.get('info_send_email') + `&nbsp;<a href='` + adminFullURL + $routerHelper.getProcessesPage() + `'>` + $i18n.get('activities') + ` ` + $i18n.get('label_page') + '</a></span>'"/> :message="'<span>' + $i18n.get('info_send_email') + `&nbsp;<a href='` + adminFullURL + $routerHelper.getProcessesPage() + `'>` + $i18n.get('activities') + ` ` + $i18n.get('label_page') + '</a></span>'"
extra-classes="tainacan-repository-tooltip"/>
<b-checkbox <b-checkbox
true-value="1" true-value="1"
false-value="0" false-value="0"
@ -101,7 +103,7 @@
:class="{'is-loading': runButtonLoading}" :class="{'is-loading': runButtonLoading}"
@click.prevent="runExporter()" @click.prevent="runExporter()"
:disabled="!formIsValid()" :disabled="!formIsValid()"
class="button is-pulled-right is-turquoise5"> class="button is-pulled-right is-success">
{{ $i18n.get('run') }} {{ $i18n.get('run') }}
</button> </button>
</div> </div>

View File

@ -2,7 +2,7 @@
<form <form
id="filterEditForm" id="filterEditForm"
class="tainacan-form" class="tainacan-form"
@submit.prevent="saveEdition(editForm)"> @submit.prevent="saveEdition(form)">
<div class="options-columns"> <div class="options-columns">
<b-field <b-field
:addons="false" :addons="false"
@ -18,20 +18,17 @@
:message="$i18n.getHelperMessage('filters', 'name')"/> :message="$i18n.getHelperMessage('filters', 'name')"/>
</label> </label>
<b-input <b-input
v-model="editForm.name" v-model="form.name"
name="name" name="name"
@focus="clearErrors('name')"/> @focus="clearErrors('name')"/>
</b-field> </b-field>
<!-- Hook for extra Form options --> <!-- Hook for extra Form options -->
<template <template v-if="hasBeginLeftForm">
v-if="formHooks != undefined &&
formHooks['filter'] != undefined &&
formHooks['filter']['begin-left'] != undefined">
<form <form
id="form-filter-begin-left" id="form-filter-begin-left"
class="form-hook-region" class="form-hook-region"
v-html="formHooks['filter']['begin-left'].join('')"/> v-html="getBeginLeftForm"/>
</template> </template>
<b-field <b-field
@ -48,7 +45,7 @@
type="textarea" type="textarea"
name="description" name="description"
:rows="3" :rows="3"
v-model="editForm.description" v-model="form.description"
@focus="clearErrors('description')" /> @focus="clearErrors('description')" />
</b-field> </b-field>
@ -67,7 +64,7 @@
@focus="clearErrors('label_status')" @focus="clearErrors('label_status')"
id="tainacan-select-status-publish" id="tainacan-select-status-publish"
name="status" name="status"
v-model="editForm.status" v-model="form.status"
native-value="publish"> native-value="publish">
<span class="icon has-text-gray3"> <span class="icon has-text-gray3">
<i class="tainacan-icon tainacan-icon-public"/> <i class="tainacan-icon tainacan-icon-public"/>
@ -79,7 +76,7 @@
@focus="clearErrors('label_status')" @focus="clearErrors('label_status')"
id="tainacan-select-status-private" id="tainacan-select-status-private"
name="status" name="status"
v-model="editForm.status" v-model="form.status"
native-value="private"> native-value="private">
<span class="icon has-text-gray3"> <span class="icon has-text-gray3">
<i class="tainacan-icon tainacan-icon-private"/> <i class="tainacan-icon tainacan-icon-private"/>
@ -91,7 +88,7 @@
<b-field <b-field
:addons="false" :addons="false"
v-if="editForm.filter_type_object && editForm.filter_type_object.use_max_options"> v-if="form.filter_type_object && form.filter_type_object.use_max_options">
<label class="label is-inline"> <label class="label is-inline">
{{ $i18n.get('label_max_options_to_show') }} {{ $i18n.get('label_max_options_to_show') }}
<help-button <help-button
@ -104,15 +101,15 @@
class="is-flex"> class="is-flex">
<b-select <b-select
name="max_options" name="max_options"
v-model="editForm.max_options" v-model="form.max_options"
:placeholder="$i18n.get('instruction_select_max_options_to_show')"> :placeholder="$i18n.get('instruction_select_max_options_to_show')">
<option value="4">4</option> <option value="4">4</option>
<option value="8">8</option> <option value="8">8</option>
<option value="12">12</option> <option value="12">12</option>
<option <option
v-if="editForm.max_options && ![4,8,12].find( (element) => element == editForm.max_options )" v-if="form.max_options && ![4,8,12].find( (element) => element == form.max_options )"
:value="editForm.max_options"> :value="form.max_options">
{{ editForm.max_options }}</option> {{ form.max_options }}</option>
</b-select> </b-select>
<button <button
class="button is-white is-pulled-right" class="button is-white is-pulled-right"
@ -122,7 +119,8 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('edit'), content: $i18n.get('edit'),
autoHide: true, autoHide: true,
placement: 'bottom' placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}" }"
class="icon"> class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-edit has-text-secondary"/> <i class="tainacan-icon tainacan-icon-18px tainacan-icon-edit has-text-secondary"/>
@ -134,7 +132,7 @@
class="is-flex"> class="is-flex">
<b-input <b-input
name="max_options" name="max_options"
v-model="editForm.max_options" v-model="form.max_options"
type="number" type="number"
step="1" /> step="1" />
<button <button
@ -144,7 +142,8 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('close'), content: $i18n.get('close'),
autoHide: true, autoHide: true,
placement: 'bottom' placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}" }"
class="icon"> class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-close has-text-secondary"/> <i class="tainacan-icon tainacan-icon-18px tainacan-icon-close has-text-secondary"/>
@ -153,25 +152,43 @@
</div> </div>
</b-field> </b-field>
<b-field
:addons="false"
:label="$i18n.getHelperTitle('filters', 'begin_with_filter_collapsed')"
:type="formErrors['begin_with_filter_collapsed'] != undefined ? 'is-danger' : ''"
:message="formErrors['begin_with_filter_collapsed'] != undefined ? formErrors['begin_with_filter_collapsed'] : ''">
&nbsp;
<b-switch
size="is-small"
@input="clearErrors('begin_with_filter_collapsed')"
v-model="form.begin_with_filter_collapsed"
:true-value="'yes'"
:false-value="'no'"
:native-value="form.begin_with_filter_collapsed == 'yes' ? 'yes' : 'no'"
name="begin_with_filter_collapsed">
<help-button
:title="$i18n.getHelperTitle('filters', 'begin_with_filter_collapsed')"
:message="$i18n.getHelperMessage('filters', 'begin_with_filter_collapsed')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</b-switch>
</b-field>
<component <component
:errors="formErrors['filter_type_options']" :errors="formErrors['filter_type_options']"
v-if="(editForm.filter_type_object && editForm.filter_type_object.form_component) || editForm.edit_form == ''" v-if="(form.filter_type_object && form.filter_type_object.form_component) || form.edit_form == ''"
:is="editForm.filter_type_object.form_component" :is="form.filter_type_object.form_component"
:filter="editForm" :filter="form"
v-model="editForm.filter_type_options"/> v-model="form.filter_type_options"/>
<div <div
v-html="editForm.edit_form" v-html="form.edit_form"
v-else/> v-else/>
<!-- Hook for extra Form options --> <!-- Hook for extra Form options -->
<template <template v-if="hasEndLeftForm">
v-if="formHooks != undefined &&
formHooks['filter'] != undefined &&
formHooks['filter']['end-left'] != undefined">
<form <form
id="form-filter-end-left" id="form-filter-end-left"
class="form-hook-region" class="form-hook-region"
v-html="formHooks['filter']['end-left'].join('')"/> v-html="getEndLeftForm"/>
</template> </template>
</div> </div>
@ -210,7 +227,7 @@ export default {
}, },
data(){ data(){
return { return {
editForm: {}, form: {},
oldForm: {}, oldForm: {},
formErrors: {}, formErrors: {},
formErrorMessage: '', formErrorMessage: '',
@ -223,9 +240,9 @@ export default {
created() { created() {
this.editForm = this.editedFilter; this.form = this.editedFilter;
this.formErrors = this.editForm.formErrors != undefined ? this.editForm.formErrors : {}; this.formErrors = this.form.formErrors != undefined ? this.form.formErrors : {};
this.formErrorMessage = this.editForm.formErrors != undefined ? this.editForm.formErrorMessage : ''; this.formErrorMessage = this.form.formErrors != undefined ? this.form.formErrorMessage : '';
this.oldForm = JSON.parse(JSON.stringify(this.originalFilter)); this.oldForm = JSON.parse(JSON.stringify(this.originalFilter));
}, },
@ -233,18 +250,18 @@ export default {
// Fills hook forms with it's real values // Fills hook forms with it's real values
this.$nextTick() this.$nextTick()
.then(() => { .then(() => {
this.updateExtraFormData(this.editForm); this.updateExtraFormData(this.form);
}); });
}, },
beforeDestroy() { beforeDestroy() {
if (this.closedByForm) { if (this.closedByForm) {
this.editedFilter.saved = true; this.$emit('onUpdateSavedState', true);
} else { } else {
this.oldForm.saved = this.editForm.saved; this.oldForm.saved = this.form.saved;
if (JSON.stringify(this.editForm) != JSON.stringify(this.oldForm)) if (JSON.stringify(this.form) != JSON.stringify(this.oldForm))
this.editedFilter.saved = false; this.$emit('onUpdateSavedState', false);
else else
this.editedFilter.saved = true; this.$emit('onUpdateSavedState', true);
} }
}, },
methods: { methods: {
@ -256,10 +273,17 @@ export default {
if ((filter.filter_type_object && filter.filter_type_object.form_component) || filter.edit_form == '') { if ((filter.filter_type_object && filter.filter_type_object.form_component) || filter.edit_form == '') {
this.isLoading = true; this.isLoading = true;
// this.fillExtraFormData(this.editForm);
this.updateFilter({ filterId: filter.id, index: this.index, options: this.editForm}) for (let [key, value] of this.form) {
if (key === 'begin_with_filter_collapsed')
this.form[key] = (value == 'yes' || value == true) ? 'yes' : 'no';
}
if (this.form['begin_with_filter_collapsed'] === undefined)
this.form['begin_with_filter_collapsed'] = 'no';
this.updateFilter({ filterId: filter.id, index: this.index, options: this.form })
.then(() => { .then(() => {
this.editForm = {}; this.form = {};
this.formErrors = {}; this.formErrors = {};
this.formErrorMessage = ''; this.formErrorMessage = '';
this.isLoading = false; this.isLoading = false;
@ -275,23 +299,28 @@ export default {
this.formErrorMessage = errors.error_message; this.formErrorMessage = errors.error_message;
this.$emit('onErrorFound'); this.$emit('onErrorFound');
this.editForm.formErrors = this.formErrors; this.form.formErrors = this.formErrors;
this.editForm.formErrorMessage = this.formErrorMessage; this.form.formErrorMessage = this.formErrorMessage;
}); });
} else { } else {
let formElement = document.getElementById('filterEditForm'); let formElement = document.getElementById('filterEditForm');
let formData = new FormData(formElement); let formData = new FormData(formElement);
let formObj = {}; let formObj = {};
for (let [key, value] of formData.entries()) { for (let [key, value] of formData.entries()) {
formObj[key] = value; if (key === 'begin_with_filter_collapsed')
formObj[key] = (value == 'yes' || value == true) ? 'yes' : 'no';
else
formObj[key] = value;
} }
if (formObj['begin_with_filter_collapsed'] === undefined)
formObj['begin_with_filter_collapsed'] = 'no';
this.fillExtraFormData(formObj); this.fillExtraFormData(formObj);
this.isLoading = true; this.isLoading = true;
this.updateFilter({ filterId: filter.id, index: this.index, options: formObj}) this.updateFilter({ filterId: filter.id, index: this.index, options: formObj })
.then(() => { .then(() => {
this.editForm = {}; this.form = {};
this.formErrors = {}; this.formErrors = {};
this.formErrorMessage = ''; this.formErrorMessage = '';
this.isLoading = false; this.isLoading = false;
@ -307,8 +336,8 @@ export default {
this.formErrorMessage = errors.error_message; this.formErrorMessage = errors.error_message;
this.$emit('onErrorFound'); this.$emit('onErrorFound');
this.editForm.formErrors = this.formErrors; this.form.formErrors = this.formErrors;
this.editForm.formErrorMessage = this.formErrorMessage; this.form.formErrorMessage = this.formErrorMessage;
}); });
} }
}, },
@ -352,7 +381,7 @@ export default {
.field > .field:not(:last-child) { .field > .field:not(:last-child) {
margin-bottom: 0em; margin-bottom: 0em;
} }
.help-wrapper { .tainacan-help-tooltip-trigger {
font-size: 1.25em; font-size: 1.25em;
} }
} }

View File

@ -24,7 +24,8 @@
<label class="label">{{ $i18n.get('label_source_file') }}</label> <label class="label">{{ $i18n.get('label_source_file') }}</label>
<help-button <help-button
:title="$i18n.get('label_source_file')" :title="$i18n.get('label_source_file')"
:message="$i18n.get('info_source_file_upload')"/> :message="$i18n.get('info_source_file_upload')"
extra-classes="tainacan-repository-tooltip"/>
<br> <br>
<b-upload <b-upload
v-if="importer.tmp_file == undefined && (importerFile == undefined || importerFile == null || importerFile == '')" v-if="importer.tmp_file == undefined && (importerFile == undefined || importerFile == null || importerFile == '')"
@ -54,7 +55,7 @@
content: $i18n.get('remove_value'), content: $i18n.get('remove_value'),
autoHide: true, autoHide: true,
placement: 'bottom', placement: 'bottom',
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
}" }"
class="icon"> class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-close"/> <i class="tainacan-icon tainacan-icon-18px tainacan-icon-close"/>
@ -75,7 +76,8 @@
:label="$i18n.get('label_url_source_link')"> :label="$i18n.get('label_url_source_link')">
<help-button <help-button
:title="$i18n.get('label_url_source_link')" :title="$i18n.get('label_url_source_link')"
:message="$i18n.get('info_url_source_link_helper')"/> :message="$i18n.get('info_url_source_link_helper')"
extra-classes="tainacan-repository-tooltip"/>
<b-input <b-input
id="tainacan-url-link-source" id="tainacan-url-link-source"
v-model="url"/> v-model="url"/>
@ -100,7 +102,8 @@
:label="$i18n.get('label_target_collection')"> :label="$i18n.get('label_target_collection')">
<help-button <help-button
:title="$i18n.get('label_target_collection')" :title="$i18n.get('label_target_collection')"
:message="$i18n.get('info_target_collection_helper')"/> :message="$i18n.get('info_target_collection_helper')"
extra-classes="tainacan-repository-tooltip"/>
<br> <br>
<div class="is-inline"> <div class="is-inline">
<b-select <b-select
@ -524,7 +527,7 @@ export default {
align-items: center; align-items: center;
} }
hr { hr {
margin: 0.5rem 0 1.5rem 0; margin: 0.5em 0 1.5em 0;
} }
</style> </style>

View File

@ -803,7 +803,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.tainacan-page-title { .tainacan-page-title {
margin-bottom: 40px; margin-bottom: 38px;
h1, h2 { h1, h2 {
font-size: 1.25em; font-size: 1.25em;

View File

@ -0,0 +1,70 @@
<template>
<div>
<!-- Attachments -------------------------------- -->
<div
v-if="!$adminOptions.hideItemEditionAttachments"
class="section-label">
<label>
<span class="icon has-text-gray4">
<i class="tainacan-icon tainacan-icon-attachments"/>
</span>
{{ $i18n.get('label_attachments') }}&nbsp;
<span
v-if="totalAttachments"
class="has-text-gray has-text-weight-normal"
style="font-size: 0.875em;">
({{ totalAttachments }})
</span>
</label>
<help-button
:title="$i18n.get('label_attachments')"
:message="$i18n.get('info_edit_attachments')"/>
<button
style="float: right; font-size: 0.875em; margin: 2px 5px;"
type="button"
class="link-style"
@click.prevent="($event) => $emit('openAttachmentsMediaFrame', $event)"
:disabled="isLoading">
<span class="icon">
<i class="tainacan-icon tainacan-icon-edit"/>
</span>
{{ $i18n.get('label_add_or_update_attachments') }}
</button>
</div>
<div
v-if="item != undefined && item.id != undefined && !$adminOptions.hideItemEditionAttachments"
class="section-box section-attachments">
<attachments-list
:item="item"
:form="form"
:is-editable="true"
:should-load-attachments="shouldLoadAttachments"
@onDeleteAttachment="($event) => $emit('onDeleteAttachment', $event)"/>
</div>
</div>
</template>
<script>
import AttachmentsList from '../lists/attachments-list.vue';
export default {
components: {
AttachmentsList
},
props: {
item: Object,
form: Object,
totalAttachments: Number,
isLoading: Boolean,
shouldLoadAttachments: Boolean
}
}
</script>
<style lang="scss" scoped>
.section-attachments {
padding-left: 0 !important;
padding-right: 0 !important;
}
</style>

View File

@ -5,7 +5,7 @@
:active.sync="isLoading" :active.sync="isLoading"
:can-cancel="false"/> :can-cancel="false"/>
<div <div
v-if="!isMobileMode" v-if="!$adminOptions.hideBulkEditionPageTitle"
class="tainacan-page-title"> class="tainacan-page-title">
<h1>{{ $i18n.get('add_items_bulk') }}</h1> <h1>{{ $i18n.get('add_items_bulk') }}</h1>
<a <a
@ -111,12 +111,13 @@
class="icon has-text-success" class="icon has-text-success"
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_document_uploaded'), content: $i18n.get('label_document_uploaded'),
autoHide: false, autoHide: false,
placement: 'auto-start' placement: 'auto-start',
popperClass: ['tainacan-tooltip', 'tooltip']
}"> }">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-approvedcircle" /> <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-approvedcircle" />
</span> </span>
@ -127,12 +128,13 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_button_delete_document'), content: $i18n.get('label_button_delete_document'),
autoHide: false, autoHide: false,
placement: 'auto-start' placement: 'auto-start',
popperClass: ['tainacan-tooltip', 'tooltip']
}" }"
class="icon has-text-secondary action-icon" class="icon has-text-secondary action-icon"
@click="deleteOneItem(item.id, index)"> @click="deleteOneItem(item.id, index)">
@ -209,9 +211,6 @@ export default {
}, },
collection() { collection() {
return this.getCollection() return this.getCollection()
},
isMobileMode() {
return this.$route && this.$route.query && this.$route.query.mobilemode;
} }
}, },
created() { created() {
@ -378,7 +377,7 @@ export default {
} }
.tainacan-page-title { .tainacan-page-title {
margin-bottom: 32px; margin-bottom: 28px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: flex-end; align-items: flex-end;
@ -507,13 +506,13 @@ export default {
} }
.footer { .footer {
padding: 18px var(--tainacan-one-column); padding: 14px var(--tainacan-one-column);
position: absolute; position: absolute;
bottom: 0; bottom: 0;
z-index: 999999; z-index: 999999;
background-color: var(--tainacan-gray1); background-color: var(--tainacan-gray1);
width: 100%; width: 100%;
height: 65px; height: 60px;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;

View File

@ -0,0 +1,198 @@
<template>
<div>
<div
v-if="!$adminOptions.hideItemEditionDocument"
class="section-label">
<label>
<span class="icon has-text-gray4">
<i :class="'tainacan-icon tainacan-icon-' + ( (!form.document_type || form.document_type == 'empty' ) ? 'item' : (form.document_type == 'attachment' ? 'attachments' : form.document_type))"/>
</span>
{{ form.document != undefined && form.document != null && form.document != '' ? $i18n.get('label_document') : $i18n.get('label_document_empty') }}
</label>
<help-button
:title="$i18n.getHelperTitle('items', 'document')"
:message="$i18n.getHelperMessage('items', 'document')"/>
</div>
<div
v-if="!$adminOptions.hideItemEditionDocument"
class="section-box document-field">
<div
v-if="form.document != undefined && form.document != null &&
form.document_type != undefined && form.document_type != null &&
form.document != '' && form.document_type != 'empty'"
class="document-field-content"
:class="'document-field-content--' + form.document_type">
<div v-html="item.document_as_html" />
<div class="document-buttons-row">
<a
class="button is-rounded is-secondary"
size="is-small"
id="button-edit-document"
:aria-label="$i18n.get('label_button_edit_document')"
@click.prevent="($event) => $emit('onSetDocument', $event, form.document_type)">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-edit"/>
</span>
</a>
<a
class="button is-rounded is-secondary"
size="is-small"
id="button-delete-document"
:aria-label="$i18n.get('label_button_delete_document')"
@click.prevent="$emit('onRemoveDocument')">
<span
v-tooltip="{
content: $i18n.get('delete'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-delete"/>
</span>
</a>
</div>
</div>
<ul
v-else
class="document-field-placeholder">
<li v-if="!$adminOptions.hideItemEditionDocumentFileInput">
<button
type="button"
@click.prevent="($event) => $emit('onSetFileDocument', $event)">
<span class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-upload"/>
</span>
</button>
<p>{{ $i18n.get('label_file') }}</p>
</li>
<li v-if="!$adminOptions.hideItemEditionDocumentTextInput">
<button
type="button"
@click.prevent="$emit('onSetTextDocument')">
<span class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-text"/>
</span>
</button>
<p>{{ $i18n.get('label_text') }}</p>
</li>
<li v-if="!$adminOptions.hideItemEditionDocumentUrlInput">
<button
type="button"
@click.prevent="$emit('onSetURLDocument')">
<span class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-url"/>
</span>
</button>
<p>{{ $i18n.get('label_url') }}</p>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: {
item: Object,
form: Object
}
}
</script>
<style lang="scss" scoped>
.document-field {
.document-field-content {
max-height: 32vh;
&.document-field-content--text {
padding-bottom: 2rem;
}
/deep/ img,
/deep/ video,
/deep/ figure {
max-width: 100%;
max-height: 32vh;
width: auto !important;
margin: 0;
}
/deep/ a {
min-height: 60px;
display: block;
}
/deep/ audio,
/deep/ iframe,
/deep/ blockquote {
max-width: 100%;
max-height: 32vh;
width: 100%;
margin: 0;
min-height: 150px;
}
/deep/ audio {
min-height: 80px;
}
@media screen and (max-height: 760px) {
max-height: 25vh;
/deep/ img,
/deep/ video,
/deep/ figure {
max-height: 25vh;
}
/deep/ audio,
/deep/ iframe,
/deep/ blockquote {
max-height: 25vh;
}
}
}
.document-field-placeholder {
display: flex;
justify-content: space-evenly;
padding: 1.5rem 1rem 2rem 1rem;
border: 1px solid var(--tainacan-input-border-color);
li {
text-align: center;
button {
border-radius: 1px;
height: 72px;
width: 72px;
border: none;
background-color: var(--tainacan-background-color);
color: var(--tainacan-secondary);
margin-bottom: 6px;
transition: background-color 0.3s ease;
&:hover {
background-color: var(--tainacan-primary);
cursor: pointer;
}
}
p {
color: var(--tainacan-secondary);
font-size: 0.8125em;
}
}
}
}
.document-buttons-row {
bottom: -12px;
left: 0.875em;
position: absolute;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,281 @@
<template>
<div class="form-submission-footer">
<!-- Item edition inside iframe -->
<template v-if="isEditingItemMetadataInsideIframe">
<button
@click="$emit('onSubmit')"
type="button"
class="button is-secondary">
{{ $i18n.get('label_back_to_related_item') }}
</button>
</template>
<!-- Normal item edition -->
<template v-else>
<!-- Sequence edition Previous -->
<button
v-if="isOnSequenceEdit && hasPreviousItemOnSequenceEdit"
@click="$emit('onPrevInSequence')"
type="button"
class="button sequence-button">
<span class="icon is-large">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-previous"/>
</span>
<span>{{ $i18n.get('previous') }}</span>
</button>
<!-- Item is an autodraft (item creation) -->
<template v-if="(status == 'auto-draft' || status == undefined)">
<button
v-if="!$adminOptions.mobileAppMode"
@click="$emit('onDiscard')"
type="button"
class="button is-outlined">{{ $i18n.get('label_discard') }}</button>
<button
@click="openItemCreationStatusDialog"
type="button"
class="button is-secondary"
:style="{ marginLeft: $adminOptions.mobileAppMode ? 'auto' : '0.5em' }">{{ $i18n.get('label_create_item') }}</button>
</template>
<!-- Item is public, draft or private -->
<template v-else>
<!-- Send items to Trash -->
<button
v-if="!isOnSequenceEdit && currentUserCanDelete && !$adminOptions.mobileAppMode"
@click="$emit('onSubmit', 'trash')"
type="button"
class="button is-outlined">
<span v-if="!isMobileScreen">{{ $i18n.get('label_send_to_trash') }}</span>
<span v-else>{{ $i18n.get('status_trash') }}</span>
</button>
<!-- Update dropdown with -->
<b-dropdown
v-if="!$adminOptions.hideItemEditionStatusOption"
ref="item-edition-footer-dropdown"
:triggers="['contextmenu']"
aria-role="list"
animation="item-appear"
:mobile-modal="false"
position="is-top-left"
class="item-edition-footer-dropdown"
:style="{ marginLeft: $adminOptions.mobileAppMode ? 'auto' : '0.5em' }">
<template #trigger>
<button
:disabled="hasSomeError && (status == 'publish' || status == 'private')"
@click="!$adminOptions.mobileAppMode && !isMobileScreen ? $emit(
'onSubmit',
( currentUserCanPublish && !$adminOptions.hideItemEditionStatusPublishOption ) ? status : 'draft',
( (isOnSequenceEdit && !isCurrentItemOnSequenceEdit) ? 'next' : null)
) : ($refs && $refs['item-edition-footer-dropdown'] && !$refs['item-edition-footer-dropdown'].isActive ? $refs['item-edition-footer-dropdown'].toggle() : null)"
type="button"
class="button"
:class="{
'is-success': status == 'publish' || status == 'private',
'is-secondary': status == 'draft'
}">
{{ $i18n.get('label_update') }}
<span
v-if="isOnSequenceEdit && !isCurrentItemOnSequenceEdit"
class="icon is-large"
style="margin-left: 0em;">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-next"/>
</span>
<span
v-if="!$adminOptions.mobileAppMode"
@mouseenter="$refs && $refs['item-edition-footer-dropdown'] && !$refs['item-edition-footer-dropdown'].isActive ? $refs['item-edition-footer-dropdown'].toggle() : null"
style="margin-left: 0.5em;"
class="icon is-small">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-arrowup" />
</span>
</button>
</template>
<b-dropdown-item
@click="$emit(
'onSubmit',
'draft',
( (isOnSequenceEdit && !isCurrentItemOnSequenceEdit) ? 'next' : null)
)"
:class="{ 'is-forced-last-option': status == 'draft' }"
aria-role="listitem">
<span class="icon has-text-gray4">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-draft"/>
</span>
{{ status == 'draft' ? $i18n.get('label_update_draft') : $i18n.get('label_change_to_draft') }}
</b-dropdown-item>
<b-dropdown-item
v-if="currentUserCanPublish && !$adminOptions.hideItemEditionStatusPublishOption"
@click="$emit(
'onSubmit',
'private',
( (isOnSequenceEdit && !isCurrentItemOnSequenceEdit) ? 'next' : null)
)"
:class="{ 'is-forced-last-option': status == 'private' }"
aria-role="listitem">
<span class="icon has-text-gray4">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-private"/>
</span>
{{ status == 'private' ? $i18n.get('label_update_as_private') : ( status == 'draft' ? $i18n.get('label_verb_publish_privately') : $i18n.get('label_change_to_private') ) }}
</b-dropdown-item>
<b-dropdown-item
v-if="currentUserCanPublish && !$adminOptions.hideItemEditionStatusPublishOption"
@click="$emit(
'onSubmit',
'publish',
( (isOnSequenceEdit && !isCurrentItemOnSequenceEdit) ? 'next' : null)
)"
aria-role="listitem">
<span class="icon has-text-gray4">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-public"/>
</span>
{{ status == 'publish' ? $i18n.get('label_update_as_public') : $i18n.get('label_verb_publish') }}
</b-dropdown-item>
</b-dropdown>
<!-- In case we do not want to show status, just an update button -->
<button
v-else
:disabled="hasSomeError && (status == 'publish' || status == 'private')"
@click="$emit('onSubmit', status)"
type="button"
class="button"
:class="{
'is-success': status == 'publish' || status == 'private',
'is-secondary': status == 'draft'
}">
{{ $i18n.get('label_update') }}
</button>
</template>
<!-- Sequence edition Next button if user cannot publish (only goes to next, without changing status) -->
<button
v-if="!currentUserCanPublish && isOnSequenceEdit && hasNextItemOnSequenceEdit"
:disabled="(status == 'publish' || status == 'private') && hasSomeError"
@click="$emit('onNextInSequence')"
type="button"
class="button is-success">
<span>{{ $i18n.get('label_next') }}</span>
<span class="icon is-large">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-next"/>
</span>
</button>
<!-- Sequence edition Finish -->
<button
v-if="isOnSequenceEdit && isCurrentItemOnSequenceEdit"
@click="$router.push($routerHelper.getCollectionPath(collectionId))"
type="button"
class="button sequence-button">
<span class="icon is-large">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-approved"/>
</span>
<span>{{ $i18n.get('finish') }}</span>
</button>
</template>
</div>
</template>
<script>
import ItemCreationStatusDialog from '../other/item-creation-status-dialog.vue';
export default {
props: {
status: String,
collectionId: Number,
isOnSequenceEdit: Boolean,
isCurrentItemOnSequenceEdit: Boolean,
hasNextItemOnSequenceEdit: Boolean,
hasPreviousItemOnSequenceEdit: Boolean,
isMobileScreen: Boolean,
hasSomeError: Boolean,
currentUserCanDelete: Boolean,
currentUserCanPublish: Boolean,
isEditingItemMetadataInsideIframe: Boolean
},
mounted() {
this.$parent.$on('toggleItemEditionFooterDropdown', () => {
if (this.$refs && this.$refs['item-edition-footer-dropdown'])
this.$refs['item-edition-footer-dropdown'].toggle();
});
},
beforeDestroy() {
this.$parent.$off('toggleItemEditionFooterDropdown');
},
methods: {
openItemCreationStatusDialog() {
this.$buefy.modal.open({
parent: this,
component: ItemCreationStatusDialog,
canCancel: false,
props: {
icon: 'item',
currentUserCanPublish: this.currentUserCanPublish,
onConfirm: (selectedStatus) => {
this.$emit('onSubmit', selectedStatus);
}
},
trapFocus: true,
customClass: 'tainacan-modal',
closeButtonAriaLabel: this.$i18n.get('close')
});
},
}
}
</script>
<style lang="scss" scoped>
.form-submission-footer {
display: flex;
flex-wrap: nowrap;
.button {
margin-left: 16px;
margin-right: 6px;
}
.button:last-of-type {
margin-right: 0px;
}
/deep/ .item-edition-footer-dropdown {
.dropdown-trigger .button>.icon.is-small {
border-left: 1px solid rgba(255,255,255,0.6);
margin-left: 0.5em;
}
.dropdown-menu>.dropdown-content {
display: flex;
flex-direction: column;
.dropdown-item.is-forced-last-option {
order: 99;
}
}
}
}
@media screen and (max-width: 782px) {
.form-submission-footer {
display: flex;
justify-content: space-between;
width: 100%;
.button {
margin-left: 6px;
margin-right: 6px;
}
.button:first-of-type {
margin-left: 0px;
}
.button.is-success {
margin-left: auto;
}
}
}
</style>

View File

@ -0,0 +1,165 @@
<template>
<div>
<div
v-if="!$adminOptions.hideItemEditionThumbnail"
class="section-label">
<label>
<span class="icon has-text-gray4">
<i class="tainacan-icon tainacan-icon-image"/>
</span>
{{ $i18n.get('label_thumbnail') }}
</label>
<help-button
:title="$i18n.getHelperTitle('items', '_thumbnail_id')"
:message="$i18n.getHelperMessage('items', '_thumbnail_id')"/>
</div>
<div
v-if="!isLoading && !$adminOptions.hideItemEditionThumbnail"
class="section-box section-thumbnail">
<div class="thumbnail-field">
<file-item
v-if="item.thumbnail != undefined && ((item.thumbnail['tainacan-medium'] != undefined && item.thumbnail['tainacan-medium'] != false) || (item.thumbnail.medium != undefined && item.thumbnail.medium != false))"
:show-name="false"
:modal-on-click="false"
:size="120"
:file="{
media_type: 'image',
thumbnails: { 'tainacan-medium': [ $thumbHelper.getSrc(item['thumbnail'], 'tainacan-medium', item.document_mimetype) ] },
title: $i18n.get('label_thumbnail'),
description: `<img alt='` + $i18n.get('label_thumbnail') + `' src='` + $thumbHelper.getSrc(item['thumbnail'], 'full', item.document_mimetype) + `'/>`
}"/>
<figure
v-if="item.thumbnail == undefined || ((item.thumbnail.medium == undefined || item.thumbnail.medium == false) && (item.thumbnail['tainacan-medium'] == undefined || item.thumbnail['tainacan-medium'] == false))"
class="image">
<span
class="image-placeholder"
v-if="item.document_type == 'empty' && item.document_mimetype == 'empty'">
{{ $i18n.get('label_empty_thumbnail') }}
</span>
<img
:alt="$i18n.get('label_thumbnail')"
:src="$thumbHelper.getEmptyThumbnailPlaceholder(item.document_mimetype)">
</figure>
<b-field
v-if="item.thumbnail_id"
:addons="false"
:label="$i18n.get('label_thumbnail_alt')">
<help-button
:title="$i18n.get('label_thumbnail_alt')"
:message="$i18n.get('info_thumbnail_alt')"/>
<textarea
id="tainacan-text-description"
class="textarea"
rows="4"
:value="form.thumbnail_alt && form.thumbnail_alt != 'false' ? form.thumbnail_alt : ''"
@input="updateThumbnailAlt" />
</b-field>
<div class="thumbnail-buttons-row">
<a
class="button is-rounded is-secondary"
id="button-edit-thumbnail"
:aria-label="$i18n.get('label_button_edit_thumb')"
@click.prevent="($event) => $emit('openThumbnailMediaFrame', $event)">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-edit"/>
</span>
</a>
<a
v-if="item.thumbnail && item.thumbnail.thumbnail != undefined && item.thumbnail.thumbnail != false"
id="button-delete-thumbnail"
class="button is-rounded is-secondary"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="$emit('onDeleteThumbnail')">
<span
v-tooltip="{
content: $i18n.get('delete'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-delete"/>
</span>
</a>
</div>
</div>
</div>
</div>
</template>
<script>
import FileItem from '../other/file-item.vue';
export default {
components: {
FileItem
},
props: {
item: Object,
form: Object
},
methods: {
updateThumbnailAlt: _.debounce(function($event) {
this.$emit('onUpdateThumbnailAlt', $event.target.value);
}, 750)
}
}
</script>
<style lang="scss" scoped>
.section-thumbnaill {
padding-right: 0;
}
.thumbnail-buttons-row {
bottom: -6px;
left: 0.875em;
position: absolute;
}
.thumbnail-field {
display: flex;
.field {
margin-left: 1em;
width: 100%;
}
.content {
padding: 10px;
font-size: 0.8em;
}
img {
height: 120px;
width: 120px;
min-width: 120px;
}
.image-placeholder {
position: absolute;
margin-left: 20px;
margin-right: 20px;
font-size: 0.8em;
font-weight: bold;
z-index: 99;
text-align: center;
color: var(--tainacan-info-color);
top: 34px;
max-width: 84px;
}
.thumbnail-alt-input {
.label {
font-size: 0.875em;
font-weight: 500;
margin-left: 15px;
margin-bottom: 0;
margin-top: 0.15em;
}
}
}
</style>

View File

@ -0,0 +1,385 @@
<template>
<form
id="metadataSectionEditForm"
@submit.prevent="saveEdition(form)"
autofocus="true"
tabindex="-1"
role="dialog"
aria-modal>
<div
v-if="form && Object.keys(form).length"
class="tainacan-modal-content">
<div class="tainacan-modal-title">
<h2 v-html="form.name ? ($i18n.get('instruction_configure_the_metadata_section') + ' <em>' + form.name + '</em>') : $i18n.get('instruction_configure_new_metadata_section')" />
<hr>
</div>
<div class="tainacan-form">
<div class="options-columns">
<b-field
:addons="false"
:type="formErrors['name'] != undefined ? 'is-danger' : ''"
:message="formErrors['name'] != undefined ? formErrors['name'] : ''">
<label class="label is-inline">
{{ $i18n.get('label_name') }}
<span
class="required-metadata-section-asterisk"
:class="formErrors['name'] != undefined ? 'is-danger' : ''">*</span>
<help-button
:title="$i18n.getHelperTitle('metadata-sections', 'name')"
:message="$i18n.getHelperMessage('metadata-sections', 'name')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</label>
<b-input
v-model="form.name"
name="name"
@focus="clearErrors('name')"/>
</b-field>
<!-- Hook for extra Form options -->
<template
v-if="hasBeginLeftForm">
<form
id="form-metadataSection-begin-left"
class="form-hook-region"
v-html="getBeginLeftForm"/>
</template>
<b-field
:addons="false"
:type="formErrors['description'] != undefined ? 'is-danger' : ''"
:message="formErrors['description'] != undefined ? formErrors['description'] : ''">
<label class="label is-inline">
{{ $i18n.get('label_description') }}
<help-button
:title="$i18n.getHelperTitle('metadata-sections', 'description')"
:message="$i18n.getHelperMessage('metadata-sections', 'description')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</label>
<b-input
type="textarea"
name="description"
rows="3"
v-model="form.description"
@focus="clearErrors('description')"/>
</b-field>
<b-field
:addons="false"
:label="$i18n.getHelperTitle('metadata-sections', 'description_bellow_name')"
:type="formErrors['description_bellow_name'] != undefined ? 'is-danger' : ''"
:message="formErrors['description_bellow_name'] != undefined ? formErrors['description_bellow_name'] : ''">
&nbsp;
<b-switch
size="is-small"
@input="clearErrors('description_bellow_name')"
v-model="form.description_bellow_name"
true-value="yes"
false-value="no"
name="description_bellow_name">
<help-button
:title="$i18n.getHelperTitle('metadata-sections', 'description_bellow_name')"
:message="$i18n.getHelperMessage('metadata-sections', 'description_bellow_name')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</b-switch>
</b-field>
<b-field
v-if="form.id !== 'default_section'"
:addons="false"
:type="formErrors['status'] != undefined ? 'is-danger' : ''"
:message="formErrors['status'] != undefined ? formErrors['status'] : ''">
<label class="label is-inline">
{{ $i18n.get('label_status') }}
<help-button
:title="$i18n.getHelperTitle('metadata-sections', 'status')"
:message="$i18n.getHelperMessage('metadata-sections', 'status')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</label>
<div class="is-flex is-justify-content-space-between">
<b-radio
@focus="clearErrors('label_status')"
id="tainacan-select-status-publish"
name="status"
v-model="form.status"
native-value="publish">
<span class="icon has-text-gray3">
<i class="tainacan-icon tainacan-icon-public"/>
</span>
{{ $i18n.get('status_public') }}
</b-radio>
<b-radio
@focus="clearErrors('label_status')"
id="tainacan-select-status-private"
name="status"
v-model="form.status"
native-value="private">
<span class="icon has-text-gray3">
<i class="tainacan-icon tainacan-icon-private"/>
</span>
{{ $i18n.get('status_private') }}
</b-radio>
</div>
</b-field>
</div>
<!-- Hook for extra Form options -->
<template v-if="hasEndLeftForm" >
<form
id="form-metadataSection-end-left"
class="form-hook-region"
v-html="getEndLeftForm"/>
</template>
</div>
</div>
<div class="field is-grouped form-submit">
<div class="control">
<button
type="button"
class="button is-outlined"
@click.prevent="cancelEdition()"
slot="trigger">{{ $i18n.get('cancel') }}
</button>
</div>
<p class="help is-danger">{{ formErrorMessage }}</p>
<div class="control">
<b-button
:loading="isUpdating"
class="button is-success"
native-type="submit">
{{ $i18n.get('save') }}
</b-button>
</div>
</div>
</form>
</template>
<script>
import { mapActions } from 'vuex';
import { formHooks } from "../../js/mixins";
export default {
name: 'MetadataSectionEditionForm',
mixins: [ formHooks ],
props: {
index: '',
originalMetadataSection: Object,
collectionId: '',
isInsideImporterFlow: false
},
data() {
return {
form: {},
formErrors: {},
formErrorMessage: '',
closedByForm: false,
entityName: 'metadataSection',
isUpdating: false
}
},
created() {
this.form = JSON.parse(JSON.stringify(this.originalMetadataSection));
if (this.form.status == 'auto-draft')
this.form.status = 'publish';
this.formErrors = this.form.formErrors != undefined ? this.form.formErrors : {};
this.formErrorMessage = this.form.formErrors != undefined ? this.form.formErrorMessage : '';
},
mounted() {
// Fills hook forms with it's real values
this.$nextTick()
.then(() => {
this.updateExtraFormData(this.form);
});
},
methods: {
...mapActions('metadata', [
'updateMetadataSection'
]),
saveEdition(metadataSection) {
if ( (metadataSection.metadata_type_object && metadataSection.metadata_type_object.form_component) || metadataSection.edit_form == '') {
this.fillExtraFormData(this.form);
this.isUpdating = true;
this.updateMetadataSection({
collectionId: this.collectionId,
metadataSectionId: metadataSection.id,
index: this.index,
options: this.form
})
.then(() => {
this.form = {};
this.formErrors = {};
this.formErrorMessage = '';
this.isUpdating = false;
this.closedByForm = true;
this.$emit('onEditionFinished');
})
.catch((errors) => {
this.isUpdating = false;
for (let error of errors.errors) {
for (let attribute of Object.keys(error))
this.formErrors[attribute] = error[attribute];
}
this.formErrorMessage = errors.error_message;
this.form.formErrors = this.formErrors;
this.form.formErrorMessage = this.formErrorMessage;
});
} else {
let formElement = document.getElementById('metadataSectionEditForm');
let formData = new FormData(formElement);
let formObj = {};
for (let [key, value] of formData.entries()) {
if (key === 'description_bellow_name')
formObj[key] = value ? 'yes' : 'no';
else
formObj[key] = value;
}
this.fillExtraFormData(formObj);
this.isUpdating = true;
this.updateMetadataSection({
collectionId: this.collectionId,
metadataSectionId: metadataSection.id,
index: this.index,
options: formObj
})
.then(() => {
this.form = {};
this.formErrors = {};
this.formErrorMessage = '';
this.isUpdating = false;
this.closedByForm = true;
this.$emit('onEditionFinished');
})
.catch((errors) => {
this.isUpdating = false;
for (let error of errors.errors) {
for (let attribute of Object.keys(error))
this.formErrors[attribute] = error[attribute];
}
this.formErrorMessage = errors.error_message;
this.$emit('onErrorFound');
this.form.formErrors = this.formErrors;
this.form.formErrorMessage = this.formErrorMessage;
});
}
},
clearErrors(attribute) {
this.formErrors[attribute] = undefined;
},
cancelEdition() {
this.closedByForm = true;
this.$emit('onEditionCanceled');
},
}
}
</script>
<style lang="scss" scoped>
form#metadataSectionEditForm {
.options-columns {
-moz-column-count: 2;
-moz-column-gap: 0;
-moz-column-rule: 1px solid var(--tainacan-gray1);
-webkit-column-count: 2;
-webkit-column-gap: 0;
-webkit-column-rule: 1px solid var(--tainacan-gray1);
column-count: 2;
column-gap: 4em;
column-rule: 1px solid var(--tainacan-gray1);
padding-left: 0.25em;
padding-right: 0.25em;
padding-bottom: 0.5em;
&>.field, &>section {
-webkit-column-break-inside: avoid;
page-break-inside: avoid;
break-inside: avoid;
}
.field > .field:not(:last-child) {
margin-bottom: 0em;
}
/deep/ .field {
-webkit-column-break-inside: avoid;
page-break-inside: avoid;
break-inside: avoid;
}
section {
display: grid;
}
.field:first-child {
-webkit-column-span: all;
column-span: all;
}
.tainacan-help-tooltip-trigger {
font-size: 1.25em;
}
}
.tainacan-form .field:not(:last-child) {
margin-bottom: 1em;
}
.tainacan-form /deep/ .control-label {
white-space: normal;
}
.metadata-form-section {
margin: 1.5em 0 0.5em -1.5em;
position: relative;
cursor: pointer;
.icon {
background: var(--tainacan-background-color);
z-index: 1;
position: relative;
}
strong {
background: var(--tainacan-background-color);
color: var(--tainacan-gray4);
font-size: 0.875em;
z-index: 1;
position: relative;
padding-right: 12px;
}
hr {
position: absolute;
top: -0.75em;
width: calc(100% - 42px);
height: 1px;
background-color: var(--tainacan-gray2);
margin-left: 42px;
}
}
@media screen and (max-width: 768px) {
.options-columns {
-moz-column-count: 1;
-webkit-column-count: 1;
column-count: 1;
}
}
}
.form-submit {
background-color: var(--tainacan-gray1);
position: sticky;
bottom: 0;
padding: 16px 4.166666667vw;
display: flex;
justify-content: space-between;
z-index: 2;
font-size: 1.125em;
}
</style>

View File

@ -1,16 +1,16 @@
<template> <template>
<form <form
id="metadatumEditForm" id="metadatumEditForm"
@submit.prevent="saveEdition(editForm)" @submit.prevent="saveEdition(form)"
autofocus="true" autofocus="true"
tabindex="-1" tabindex="-1"
role="dialog" role="dialog"
aria-modal> aria-modal>
<div <div
v-if="editForm && Object.keys(editForm).length" v-if="form && Object.keys(form).length"
class="tainacan-modal-content"> class="tainacan-modal-content">
<div class="tainacan-modal-title"> <div class="tainacan-modal-title">
<h2 v-html="editForm.name ? ($i18n.get('instruction_configure_the_metadatum') + ' <em>' + editForm.name + '</em>') : $i18n.get('instruction_configure_new_metadatum')" /> <h2 v-html="form.name ? ($i18n.get('instruction_configure_the_metadatum') + ' <em>' + form.name + '</em>') : $i18n.get('instruction_configure_new_metadatum')" />
<!-- <a <!-- <a
class="back-link" class="back-link"
@click="onEditionCanceled()"> @click="onEditionCanceled()">
@ -20,7 +20,7 @@
</div> </div>
<div <div
class="tainacan-form" class="tainacan-form"
:class="'tainacan-metadatum-edition-form--type-' + editForm.metadata_type_object.component"> :class="'tainacan-metadatum-edition-form--type-' + form.metadata_type_object.component">
<div class="options-columns"> <div class="options-columns">
<b-field <b-field
:addons="false" :addons="false"
@ -33,23 +33,22 @@
:class="formErrors['name'] != undefined ? 'is-danger' : ''">*</span> :class="formErrors['name'] != undefined ? 'is-danger' : ''">*</span>
<help-button <help-button
:title="$i18n.getHelperTitle('metadata', 'name')" :title="$i18n.getHelperTitle('metadata', 'name')"
:message="$i18n.getHelperMessage('metadata', 'name')"/> :message="$i18n.getHelperMessage('metadata', 'name')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</label> </label>
<b-input <b-input
v-model="editForm.name" v-model="form.name"
name="name" name="name"
@focus="clearErrors('name')"/> @focus="clearErrors('name')"/>
</b-field> </b-field>
<!-- Hook for extra Form options --> <!-- Hook for extra Form options -->
<template <template
v-if="formHooks != undefined && v-if="hasBeginLeftForm">
formHooks['metadatum'] != undefined &&
formHooks['metadatum']['begin-left'] != undefined">
<form <form
id="form-metadatum-begin-left" id="form-metadatum-begin-left"
class="form-hook-region" class="form-hook-region"
v-html="formHooks['metadatum']['begin-left'].join('')"/> v-html="getBeginLeftForm"/>
</template> </template>
<b-field <b-field
@ -60,18 +59,39 @@
{{ $i18n.get('label_description') }} {{ $i18n.get('label_description') }}
<help-button <help-button
:title="$i18n.getHelperTitle('metadata', 'description')" :title="$i18n.getHelperTitle('metadata', 'description')"
:message="$i18n.getHelperMessage('metadata', 'description')"/> :message="$i18n.getHelperMessage('metadata', 'description')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</label> </label>
<b-input <b-input
type="textarea" type="textarea"
name="description" name="description"
rows="3" rows="3"
v-model="editForm.description" v-model="form.description"
@focus="clearErrors('description')"/> @focus="clearErrors('description')"/>
</b-field> </b-field>
<b-field
:addons="false"
:label="$i18n.getHelperTitle('metadata', 'description_bellow_name')"
:type="formErrors['description_bellow_name'] != undefined ? 'is-danger' : ''"
:message="formErrors['description_bellow_name'] != undefined ? formErrors['description_bellow_name'] : ''">
&nbsp;
<b-switch
size="is-small"
@input="clearErrors('description_bellow_name')"
v-model="form.description_bellow_name"
true-value="yes"
false-value="no"
name="description_bellow_name">
<help-button
:title="$i18n.getHelperTitle('metadata', 'description_bellow_name')"
:message="$i18n.getHelperMessage('metadata', 'description_bellow_name')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</b-switch>
</b-field>
<b-field <b-field
v-if="editForm.metadata_type_object.component != 'tainacan-compound'" v-if="form.metadata_type_object.component != 'tainacan-compound'"
:addons="false" :addons="false"
:type="formErrors['placeholder'] != undefined ? 'is-danger' : ''" :type="formErrors['placeholder'] != undefined ? 'is-danger' : ''"
:message="formErrors['placeholder'] != undefined ? formErrors['placeholder'] : ''"> :message="formErrors['placeholder'] != undefined ? formErrors['placeholder'] : ''">
@ -79,16 +99,17 @@
{{ $i18n.getHelperTitle('metadata', 'placeholder') }} {{ $i18n.getHelperTitle('metadata', 'placeholder') }}
<help-button <help-button
:title="$i18n.getHelperTitle('metadata', 'placeholder')" :title="$i18n.getHelperTitle('metadata', 'placeholder')"
:message="$i18n.getHelperMessage('metadata', 'placeholder')"/> :message="$i18n.getHelperMessage('metadata', 'placeholder')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</label> </label>
<b-input <b-input
v-model="editForm.placeholder" v-model="form.placeholder"
name="placeholder" name="placeholder"
@focus="clearErrors('placeholder')"/> @focus="clearErrors('placeholder')"/>
</b-field> </b-field>
<b-field <b-field
v-if="editForm.parent == 0" v-if="form.parent == 0"
:addons="false" :addons="false"
:type="formErrors['status'] != undefined ? 'is-danger' : ''" :type="formErrors['status'] != undefined ? 'is-danger' : ''"
:message="formErrors['status'] != undefined ? formErrors['status'] : ''"> :message="formErrors['status'] != undefined ? formErrors['status'] : ''">
@ -96,14 +117,15 @@
{{ $i18n.get('label_status') }} {{ $i18n.get('label_status') }}
<help-button <help-button
:title="$i18n.getHelperTitle('metadata', 'status')" :title="$i18n.getHelperTitle('metadata', 'status')"
:message="$i18n.getHelperMessage('metadata', 'status')"/> :message="$i18n.getHelperMessage('metadata', 'status')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</label> </label>
<div class="is-flex is-justify-content-space-between"> <div class="is-flex is-justify-content-space-between">
<b-radio <b-radio
@focus="clearErrors('label_status')" @focus="clearErrors('label_status')"
id="tainacan-select-status-publish" id="tainacan-select-status-publish"
name="status" name="status"
v-model="editForm.status" v-model="form.status"
native-value="publish"> native-value="publish">
<span class="icon has-text-gray3"> <span class="icon has-text-gray3">
<i class="tainacan-icon tainacan-icon-public"/> <i class="tainacan-icon tainacan-icon-public"/>
@ -114,7 +136,7 @@
@focus="clearErrors('label_status')" @focus="clearErrors('label_status')"
id="tainacan-select-status-private" id="tainacan-select-status-private"
name="status" name="status"
v-model="editForm.status" v-model="form.status"
native-value="private"> native-value="private">
<span class="icon has-text-gray3"> <span class="icon has-text-gray3">
<i class="tainacan-icon tainacan-icon-private"/> <i class="tainacan-icon tainacan-icon-private"/>
@ -126,7 +148,7 @@
<!-- Display on listing --> <!-- Display on listing -->
<b-field <b-field
v-if="editForm.parent == 0" v-if="form.parent == 0"
:type="formErrors['display'] != undefined ? 'is-danger' : ''" :type="formErrors['display'] != undefined ? 'is-danger' : ''"
:message="formErrors['display'] != undefined ? formErrors['display'] : ''" :message="formErrors['display'] != undefined ? formErrors['display'] : ''"
:addons="false"> :addons="false">
@ -134,11 +156,12 @@
{{ $i18n.get('label_display') }} {{ $i18n.get('label_display') }}
<help-button <help-button
:title="$i18n.getHelperTitle('metadata', 'display')" :title="$i18n.getHelperTitle('metadata', 'display')"
:message="$i18n.getHelperMessage('metadata', 'display')"/> :message="$i18n.getHelperMessage('metadata', 'display')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</label> </label>
<b-select <b-select
expanded expanded
v-model="editForm.display" v-model="form.display"
@input="clearErrors('display')"> @input="clearErrors('display')">
<option value="yes"> <option value="yes">
{{ $i18n.get('label_display_default') }} {{ $i18n.get('label_display_default') }}
@ -157,12 +180,12 @@
<label class="label is-inline">{{ $i18n.get('label_insert_options') }}</label> <label class="label is-inline">{{ $i18n.get('label_insert_options') }}</label>
<b-field <b-field
v-if="editForm.metadata_type_object.component != 'tainacan-compound' && (editForm.parent == 0 || (editForm.parent != 0 && !isParentMultiple))" v-if="form.metadata_type_object.component != 'tainacan-compound' && (form.parent == 0 || (form.parent != 0 && !isParentMultiple))"
:type="formErrors['required'] != undefined ? 'is-danger' : ''" :type="formErrors['required'] != undefined ? 'is-danger' : ''"
:message="formErrors['required'] != undefined ? formErrors['required'] : ''"> :message="formErrors['required'] != undefined ? formErrors['required'] : ''">
<b-checkbox <b-checkbox
@input="clearErrors('required')" @input="clearErrors('required')"
v-model="editForm.required" v-model="form.required"
true-value="yes" true-value="yes"
false-value="no" false-value="no"
class="is-inline-block" class="is-inline-block"
@ -170,35 +193,37 @@
{{ $i18n.get('label_required') }} {{ $i18n.get('label_required') }}
<help-button <help-button
:title="$i18n.getHelperTitle('metadata', 'required')" :title="$i18n.getHelperTitle('metadata', 'required')"
:message="$i18n.getHelperMessage('metadata', 'required')"/> :message="$i18n.getHelperMessage('metadata', 'required')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</b-checkbox> </b-checkbox>
</b-field> </b-field>
<b-field <b-field
v-if="editForm.metadata_type_object.component != 'tainacan-compound'" v-if="form.metadata_type_object.component != 'tainacan-compound'"
:type="formErrors['collection_key'] != undefined ? 'is-danger' : ''" :type="formErrors['collection_key'] != undefined ? 'is-danger' : ''"
:message="formErrors['collection_key'] != undefined ? formErrors['collection_key'] : ''"> :message="formErrors['collection_key'] != undefined ? formErrors['collection_key'] : ''">
<b-checkbox <b-checkbox
@input="clearErrors('collection_key')" @input="clearErrors('collection_key')"
v-model="editForm.collection_key" v-model="form.collection_key"
true-value="yes" true-value="yes"
false-value="no" false-value="no"
class="is-inline-block" class="is-inline-block"
name="collecion_key"> name="collection_key">
{{ $i18n.get('label_unique_value') }} {{ $i18n.get('label_unique_value') }}
<help-button <help-button
:title="$i18n.getHelperTitle('metadata', 'collection_key')" :title="$i18n.getHelperTitle('metadata', 'collection_key')"
:message="$i18n.getHelperMessage('metadata', 'collection_key')"/> :message="$i18n.getHelperMessage('metadata', 'collection_key')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</b-checkbox> </b-checkbox>
</b-field> </b-field>
<b-field <b-field
v-if="!originalMetadatum.metadata_type_object.core && editForm.parent == 0" v-if="!originalMetadatum.metadata_type_object.core && form.parent == 0"
:type="formErrors['multiple'] != undefined ? 'is-danger' : ''" :type="formErrors['multiple'] != undefined ? 'is-danger' : ''"
:message="formErrors['multiple'] != undefined ? formErrors['multiple'] : ''"> :message="formErrors['multiple'] != undefined ? formErrors['multiple'] : ''">
<b-checkbox <b-checkbox
@input="clearErrors('multiple')" @input="clearErrors('multiple')"
v-model="editForm.multiple" v-model="form.multiple"
true-value="yes" true-value="yes"
false-value="no" false-value="no"
class="is-inline-block" class="is-inline-block"
@ -206,25 +231,26 @@
{{ $i18n.get('label_allow_multiple') }} {{ $i18n.get('label_allow_multiple') }}
<help-button <help-button
:title="$i18n.getHelperTitle('metadata', 'multiple')" :title="$i18n.getHelperTitle('metadata', 'multiple')"
:message="$i18n.getHelperMessage('metadata', 'multiple')"/> :message="$i18n.getHelperMessage('metadata', 'multiple')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</b-checkbox> </b-checkbox>
</b-field> </b-field>
</b-field> </b-field>
<b-field <b-field
v-if="!originalMetadatum.metadata_type_object.core && editForm.parent == 0" v-if="!originalMetadatum.metadata_type_object.core && form.parent == 0"
:addons="false" :addons="false"
:label="$i18n.get('label_limit_max_values')"> :label="$i18n.get('label_limit_max_values')">
&nbsp; &nbsp;
<b-switch <b-switch
size="is-small" size="is-small"
:disabled="editForm.multiple != 'yes'" :disabled="form.multiple != 'yes'"
v-model="showCardinalityOptions" /> v-model="showCardinalityOptions" />
</b-field> </b-field>
<b-field <b-field
v-if="!originalMetadatum.metadata_type_object.core && editForm.parent == 0" v-if="!originalMetadatum.metadata_type_object.core && form.parent == 0"
:type="formErrors['cardinality'] != undefined ? 'is-danger' : ''" :type="formErrors['cardinality'] != undefined ? 'is-danger' : ''"
:message="formErrors['cardinality'] != undefined ? formErrors['cardinality'] : ''" :message="formErrors['cardinality'] != undefined ? formErrors['cardinality'] : ''"
:addons="false"> :addons="false">
@ -232,34 +258,36 @@
{{ $i18n.getHelperTitle('metadata', 'cardinality') }} {{ $i18n.getHelperTitle('metadata', 'cardinality') }}
<help-button <help-button
:title="$i18n.getHelperTitle('metadata', 'cardinality')" :title="$i18n.getHelperTitle('metadata', 'cardinality')"
:message="$i18n.getHelperMessage('metadata', 'cardinality')"/> :message="$i18n.getHelperMessage('metadata', 'cardinality')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</label> </label>
<b-numberinput <b-numberinput
:disabled="!showCardinalityOptions || editForm.multiple != 'yes'" :disabled="!showCardinalityOptions || form.multiple != 'yes'"
name="cardinality" name="cardinality"
step="1" step="1"
min="2" min="2"
v-model="editForm.cardinality"/> v-model="form.cardinality"/>
</b-field> </b-field>
<b-field v-if="!isRepositoryLevel && isInsideImporterFlow"> <b-field v-if="!isRepositoryLevel && isInsideImporterFlow">
<b-checkbox <b-checkbox
class="is-inline-block" class="is-inline-block"
v-model="editForm.repository_level" v-model="form.repository_level"
@input="clearErrors('repository_level')" @input="clearErrors('repository_level')"
name="repository_level" name="repository_level"
true-value="yes" true-value="yes"
false-value="no"> false-value="no">
{{ $i18n.get('label_repository_metadata') }} {{ $i18n.get('label_repository_metadata') }}
<help-button <help-button
:title="$i18n.getHelperTitle('metadata', 'repository_level')" :title="$i18n.getHelperTitle('metadata', 'repository_level')"
:message="$i18n.getHelperMessage('metadata', 'repository_level')"/> :message="$i18n.getHelperMessage('metadata', 'repository_level')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</b-checkbox> </b-checkbox>
</b-field> </b-field>
</div> </div>
<div <div
v-if="(editForm.metadata_type_object && editForm.metadata_type_object.form_component && editForm.metadata_type_object.component != 'tainacan-compound') || editForm.edit_form != ''" v-if="(form.metadata_type_object && form.metadata_type_object.form_component && form.metadata_type_object.component != 'tainacan-compound') || form.edit_form != ''"
class="metadata-form-section" class="metadata-form-section"
@click="hideMetadataTypeOptions = !hideMetadataTypeOptions;"> @click="hideMetadataTypeOptions = !hideMetadataTypeOptions;">
<span class="icon"> <span class="icon">
@ -267,7 +295,7 @@
class="tainacan-icon" class="tainacan-icon"
:class="!hideMetadataTypeOptions ? 'tainacan-icon-arrowdown' : 'tainacan-icon-arrowright'" /> :class="!hideMetadataTypeOptions ? 'tainacan-icon-arrowdown' : 'tainacan-icon-arrowright'" />
</span> </span>
<strong>{{ $i18n.getWithVariables('label_options_of_the_%s_metadata_type', [ editForm.metadata_type_object.name ]) }}</strong> <strong>{{ $i18n.getWithVariables('label_options_of_the_%s_metadata_type', [ form.metadata_type_object.name ]) }}</strong>
<hr> <hr>
</div> </div>
@ -277,23 +305,20 @@
class="options-columns"> class="options-columns">
<component <component
:errors="formErrors['metadata_type_options']" :errors="formErrors['metadata_type_options']"
v-if="(editForm.metadata_type_object && editForm.metadata_type_object.form_component) || editForm.edit_form != ''" v-if="(form.metadata_type_object && form.metadata_type_object.form_component) || form.edit_form != ''"
:is="editForm.metadata_type_object.form_component" :is="form.metadata_type_object.form_component"
:metadatum="editForm" :metadatum="form"
v-model="editForm.metadata_type_options"/> v-model="form.metadata_type_options"/>
<div <div
v-html="editForm.edit_form" v-html="form.edit_form"
v-else/> v-else/>
<!-- Hook for extra Form options --> <!-- Hook for extra Form options -->
<template <template v-if="hasEndLeftForm" >
v-if="formHooks != undefined &&
formHooks['metadatum'] != undefined &&
formHooks['metadatum']['end-left'] != undefined">
<form <form
id="form-metadatum-end-left" id="form-metadatum-end-left"
class="form-hook-region" class="form-hook-region"
v-html="formHooks['metadatum']['end-left'].join('')"/> v-html="getEndLeftForm"/>
</template> </template>
</div> </div>
</transition> </transition>
@ -320,10 +345,11 @@
{{ $i18n.get('label_semantic_uri') }} {{ $i18n.get('label_semantic_uri') }}
<help-button <help-button
:title="$i18n.getHelperTitle('metadata', 'semantic_uri')" :title="$i18n.getHelperTitle('metadata', 'semantic_uri')"
:message="$i18n.getHelperMessage('metadata', 'semantic_uri')"/> :message="$i18n.getHelperMessage('metadata', 'semantic_uri')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</label> </label>
<b-input <b-input
v-model="editForm.semantic_uri" v-model="form.semantic_uri"
name="semantic_uri" name="semantic_uri"
type="url" type="url"
@focus="clearErrors('semantic_uri')"/> @focus="clearErrors('semantic_uri')"/>
@ -344,7 +370,7 @@
<p class="help is-danger">{{ formErrorMessage }}</p> <p class="help is-danger">{{ formErrorMessage }}</p>
<div class="control"> <div class="control">
<b-button <b-button
:loading="isLoading" :loading="isUpdating"
class="button is-success" class="button is-success"
native-type="submit"> native-type="submit">
{{ $i18n.get('save') }} {{ $i18n.get('save') }}
@ -371,7 +397,7 @@
}, },
data() { data() {
return { return {
editForm: {}, form: {},
formErrors: {}, formErrors: {},
formErrorMessage: '', formErrorMessage: '',
closedByForm: false, closedByForm: false,
@ -384,26 +410,26 @@
}, },
watch: { watch: {
showCardinalityOptions() { showCardinalityOptions() {
this.editForm.cardinality = !this.showCardinalityOptions ? 1 : 2; this.form.cardinality = !this.showCardinalityOptions ? 1 : 2;
} }
}, },
created() { created() {
this.editForm = JSON.parse(JSON.stringify(this.originalMetadatum)); this.form = JSON.parse(JSON.stringify(this.originalMetadatum));
if (this.editForm.status == 'auto-draft')
this.editForm.status = 'publish';
if (this.editForm.cardinality && this.editForm.cardinality > 1) if (this.form.status == 'auto-draft')
this.form.status = 'publish';
if (this.form.cardinality && this.form.cardinality > 1)
this.showCardinalityOptions = true; this.showCardinalityOptions = true;
this.formErrors = this.editForm.formErrors != undefined ? this.editForm.formErrors : {}; this.formErrors = this.form.formErrors != undefined ? this.form.formErrors : {};
this.formErrorMessage = this.editForm.formErrors != undefined ? this.editForm.formErrorMessage : ''; this.formErrorMessage = this.form.formErrors != undefined ? this.form.formErrorMessage : '';
}, },
mounted() { mounted() {
// Fills hook forms with it's real values // Fills hook forms with it's real values
this.$nextTick() this.$nextTick()
.then(() => { .then(() => {
this.updateExtraFormData(this.editForm); this.updateExtraFormData(this.form);
}); });
}, },
methods: { methods: {
@ -411,30 +437,27 @@
'updateMetadatum' 'updateMetadatum'
]), ]),
saveEdition(metadatum) { saveEdition(metadatum) {
if ( (metadatum.metadata_type_object && metadatum.metadata_type_object.form_component) || metadatum.edit_form == '') { if ( (metadatum.metadata_type_object && metadatum.metadata_type_object.form_component) || metadatum.edit_form == '') {
let repository = this.editForm.repository_level; let repository = this.form.repository_level;
if (repository && repository === 'yes')
this.isRepositoryLevel = true;
this.fillExtraFormData(this.editForm); this.fillExtraFormData(this.form);
this.isUpdating = true; this.isUpdating = true;
this.updateMetadatum({ this.updateMetadatum({
collectionId: this.collectionId, collectionId: this.collectionId,
metadatumId: metadatum.id, metadatumId: metadatum.id,
isRepositoryLevel: this.isRepositoryLevel, isRepositoryLevel: this.isRepositoryLevel || (repository && repository === 'yes'),
index: this.index, index: this.index,
options: this.editForm, options: this.form,
includeOptionsAsHtml: true includeOptionsAsHtml: true,
sectionId: metadatum.metadata_section_id
}) })
.then(() => { .then(() => {
this.editForm = {}; this.form = {};
this.formErrors = {}; this.formErrors = {};
this.formErrorMessage = ''; this.formErrorMessage = '';
this.isUpdating = false; this.isUpdating = false;
this.closedByForm = true; this.closedByForm = true;
this.$root.$emit('metadatumUpdated', this.isRepositoryLevel);
this.$emit('onEditionFinished'); this.$emit('onEditionFinished');
}) })
.catch((errors) => { .catch((errors) => {
@ -445,35 +468,41 @@
} }
this.formErrorMessage = errors.error_message; this.formErrorMessage = errors.error_message;
this.editForm.formErrors = this.formErrors; this.form.formErrors = this.formErrors;
this.editForm.formErrorMessage = this.formErrorMessage; this.form.formErrorMessage = this.formErrorMessage;
}); });
} else { } else {
let formElement = document.getElementById('metadatumEditForm'); let formElement = document.getElementById('metadatumEditForm');
let formData = new FormData(formElement); let formData = new FormData(formElement);
let formObj = {}; let formObj = {};
for (let [key, value] of formData.entries()) for (let [key, value] of formData.entries()) {
formObj[key] = value; if (key === 'description_bellow_name')
formObj[key] = value ? 'yes' : 'no';
else
formObj[key] = value;
}
let repository = formObj['repository_level'];
this.fillExtraFormData(formObj); this.fillExtraFormData(formObj);
this.isUpdating = true; this.isUpdating = true;
this.updateMetadatum({ this.updateMetadatum({
collectionId: this.collectionId, collectionId: this.collectionId,
metadatumId: metadatum.id, metadatumId: metadatum.id,
isRepositoryLevel: this.isRepositoryLevel, isRepositoryLevel: this.isRepositoryLevel || (repository && repository === 'yes'),
index: this.index, index: this.index,
options: formObj, options: formObj,
includeOptionsAsHtml: true includeOptionsAsHtml: true,
sectionId: metadatum.metadata_section_id
}) })
.then(() => { .then(() => {
this.editForm = {}; this.form = {};
this.formErrors = {}; this.formErrors = {};
this.formErrorMessage = ''; this.formErrorMessage = '';
this.isUpdating = false; this.isUpdating = false;
this.closedByForm = true; this.closedByForm = true;
this.$root.$emit('metadatumUpdated', this.isRepositoryLevel);
this.$emit('onEditionFinished'); this.$emit('onEditionFinished');
}) })
.catch((errors) => { .catch((errors) => {
@ -486,8 +515,8 @@
this.formErrorMessage = errors.error_message; this.formErrorMessage = errors.error_message;
this.$emit('onErrorFound'); this.$emit('onErrorFound');
this.editForm.formErrors = this.formErrors; this.form.formErrors = this.formErrors;
this.editForm.formErrorMessage = this.formErrorMessage; this.form.formErrorMessage = this.formErrorMessage;
}); });
} }
}, },
@ -540,7 +569,7 @@
-webkit-column-span: all; -webkit-column-span: all;
column-span: all; column-span: all;
} }
.help-wrapper { .tainacan-help-tooltip-trigger {
font-size: 1.25em; font-size: 1.25em;
} }
} }

View File

@ -25,7 +25,8 @@
<span class="required-metadatum-asterisk">*</span> <span class="required-metadatum-asterisk">*</span>
<help-button <help-button
:title="$i18n.getHelperTitle('taxonomies', 'name')" :title="$i18n.getHelperTitle('taxonomies', 'name')"
:message="$i18n.getHelperMessage('taxonomies', 'name')"/> :message="$i18n.getHelperMessage('taxonomies', 'name')"
extra-classes="tainacan-repository-tooltip"/>
<b-input <b-input
id="tainacan-text-name" id="tainacan-text-name"
v-model="form.name" v-model="form.name"
@ -36,14 +37,11 @@
</b-field> </b-field>
<!-- Hook for extra Form options --> <!-- Hook for extra Form options -->
<template <template v-if="hasBeginLeftForm">
v-if="formHooks != undefined &&
formHooks['taxonomy'] != undefined &&
formHooks['taxonomy']['begin-left'] != undefined">
<form <form
id="form-taxonomy-begin-left" id="form-taxonomy-begin-left"
class="form-hook-region" class="form-hook-region"
v-html="formHooks['taxonomy']['begin-left'].join('')"/> v-html="getBeginLeftForm"/>
</template> </template>
<!-- Description -------------------------------- --> <!-- Description -------------------------------- -->
@ -54,7 +52,8 @@
:message="editFormErrors['description'] != undefined ? editFormErrors['description'] : ''"> :message="editFormErrors['description'] != undefined ? editFormErrors['description'] : ''">
<help-button <help-button
:title="$i18n.getHelperTitle('taxonomies', 'description')" :title="$i18n.getHelperTitle('taxonomies', 'description')"
:message="$i18n.getHelperMessage('taxonomies', 'description')"/> :message="$i18n.getHelperMessage('taxonomies', 'description')"
extra-classes="tainacan-repository-tooltip"/>
<b-input <b-input
id="tainacan-text-description" id="tainacan-text-description"
type="textarea" type="textarea"
@ -74,7 +73,8 @@
false-value="no" /> false-value="no" />
<help-button <help-button
:title="$i18n.getHelperTitle('taxonomies', 'allow_insert')" :title="$i18n.getHelperTitle('taxonomies', 'allow_insert')"
:message="$i18n.getHelperMessage('taxonomies', 'allow_insert')"/> :message="$i18n.getHelperMessage('taxonomies', 'allow_insert')"
extra-classes="tainacan-repository-tooltip"/>
</label> </label>
</b-field> </b-field>
</div> </div>
@ -89,7 +89,8 @@
:message="editFormErrors['status'] != undefined ? editFormErrors['status'] : ''"> :message="editFormErrors['status'] != undefined ? editFormErrors['status'] : ''">
<help-button <help-button
:title="$i18n.getHelperTitle('taxonomies', 'status')" :title="$i18n.getHelperTitle('taxonomies', 'status')"
:message="$i18n.getHelperMessage('taxonomies', 'status')"/> :message="$i18n.getHelperMessage('taxonomies', 'status')"
extra-classes="tainacan-repository-tooltip"/>
<div class="status-radios"> <div class="status-radios">
<b-radio <b-radio
v-model="form.status" v-model="form.status"
@ -114,7 +115,8 @@
:message="editFormErrors['slug'] != undefined ? editFormErrors['slug'] : ''"> :message="editFormErrors['slug'] != undefined ? editFormErrors['slug'] : ''">
<help-button <help-button
:title="$i18n.getHelperTitle('taxonomies', 'slug')" :title="$i18n.getHelperTitle('taxonomies', 'slug')"
:message="$i18n.getHelperMessage('taxonomies', 'slug')"/> :message="$i18n.getHelperMessage('taxonomies', 'slug')"
extra-classes="tainacan-repository-tooltip"/>
<b-input <b-input
@input="updateSlug()" @input="updateSlug()"
id="tainacan-text-slug" id="tainacan-text-slug"
@ -131,7 +133,8 @@
:message="editFormErrors['enabled_post_types'] != undefined ? editFormErrors['enabled_post_types'] : ''"> :message="editFormErrors['enabled_post_types'] != undefined ? editFormErrors['enabled_post_types'] : ''">
<help-button <help-button
:title="$i18n.getHelperTitle('taxonomies', 'enabled_post_types')" :title="$i18n.getHelperTitle('taxonomies', 'enabled_post_types')"
:message="$i18n.getHelperMessage('taxonomies', 'enabled_post_types')"/> :message="$i18n.getHelperMessage('taxonomies', 'enabled_post_types')"
extra-classes="tainacan-repository-tooltip"/>
<div <div
v-for="wpPostType in wpPostTypes" v-for="wpPostType in wpPostTypes"
@ -149,14 +152,11 @@
</b-field> </b-field>
<!-- Hook for extra Form options --> <!-- Hook for extra Form options -->
<template <template v-if="hasEndLeftForm">
v-if="formHooks != undefined &&
formHooks['taxonomy'] != undefined &&
formHooks['taxonomy']['end-left'] != undefined">
<form <form
id="form-taxonomy-end-left" id="form-taxonomy-end-left"
class="form-hook-region" class="form-hook-region"
v-html="formHooks['taxonomy']['end-left'].join('')"/> v-html="getEndLeftForm"/>
</template> </template>
</div> </div>
</div> </div>
@ -245,31 +245,7 @@
TermsList TermsList
}, },
mixins: [ wpAjax, formHooks ], mixins: [ wpAjax, formHooks ],
data(){ beforeRouteLeave( to, from, next ) {
return {
taxonomyId: String,
tabIndex: 0,
taxonomy: null,
isLoadingTaxonomy: false,
isUpdatingSlug: false,
isEditingTerm: false,
form: {
name: String,
status: String,
description: String,
slug: String,
allowInsert: String,
enabledPostTypes: Array
},
wpPostTypes: tainacan_plugin.wp_post_types,
editFormErrors: {},
formErrorMessage: '',
entityName: 'taxonomy',
updatedAt: undefined,
shouldReloadTermsList: false
}
},
beforeRouteLeave( to, from, next ) {
let formNotSaved = false; let formNotSaved = false;
if (this.taxonomy) { if (this.taxonomy) {
@ -323,6 +299,30 @@
next(); next();
} }
}, },
data(){
return {
taxonomyId: String,
tabIndex: 0,
taxonomy: null,
isLoadingTaxonomy: false,
isUpdatingSlug: false,
isEditingTerm: false,
form: {
name: String,
status: String,
description: String,
slug: String,
allowInsert: String,
enabledPostTypes: Array
},
wpPostTypes: tainacan_plugin.wp_post_types,
editFormErrors: {},
formErrorMessage: '',
entityName: 'taxonomy',
updatedAt: undefined,
shouldReloadTermsList: false
}
},
mounted(){ mounted(){
if (this.$route.query.tab == 'terms') if (this.$route.query.tab == 'terms')

View File

@ -7,16 +7,16 @@
id="termEditForm" id="termEditForm"
class="tainacan-form" class="tainacan-form"
:class="{ 'tainacan-modal-content': isModal }" :class="{ 'tainacan-modal-content': isModal }"
@submit.prevent="saveEdition(editForm)"> @submit.prevent="saveEdition(form)">
<component <component
:is="isModal ? 'header' : 'div'" :is="isModal ? 'header' : 'div'"
class="tainacan-page-title" class="tainacan-page-title"
:class="{ 'tainacan-modal-title': isModal }"> :class="{ 'tainacan-modal-title': isModal }">
<h2>{{ editForm & editForm.id && editForm.id != 'new' ? $i18n.get("title_term_edit") : $i18n.get("title_term_creation") }}</h2> <h2>{{ form & form.id && form.id != 'new' ? $i18n.get("title_term_edit") : $i18n.get("title_term_creation") }}</h2>
<a <a
v-if="editForm && editForm.url != undefined && editForm.url!= ''" v-if="form && form.url != undefined && form.url!= ''"
target="_blank" target="_blank"
:href="editForm.url"> :href="form.url">
<span class="icon"> <span class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-see"/> <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-see"/>
</span> </span>
@ -40,24 +40,23 @@
<span class="required-term-asterisk">*</span> <span class="required-term-asterisk">*</span>
<help-button <help-button
:title="$i18n.get('label_name')" :title="$i18n.get('label_name')"
:message="$i18n.get('info_help_term_name')"/> :message="$i18n.get('info_help_term_name')"
extra-classes="tainacan-repository-tooltip" />
</label> </label>
<b-input <b-input
:placeholder="$i18n.get('label_term_without_name')" :placeholder="$i18n.get('label_term_without_name')"
v-model="editForm.name" v-model="form.name"
name="name" name="name"
@focus="clearErrors({ name: 'name', repeated: 'repeated' })"/> @focus="clearErrors({ name: 'name', repeated: 'repeated' })"/>
</b-field> </b-field>
<!-- Hook for extra Form options --> <!-- Hook for extra Form options -->
<template <template
v-if="formHooks != undefined && v-if="hasBeginLeftForm">
formHooks['term'] != undefined &&
formHooks['term']['begin-left'] != undefined">
<form <form
id="form-term-begin-left" id="form-term-begin-left"
class="form-hook-region" class="form-hook-region"
v-html="formHooks['term']['begin-left'].join('')"/> v-html="getBeginLeftForm"/>
</template> </template>
<div class="columns is-gapless image-and-description-area"> <div class="columns is-gapless image-and-description-area">
@ -70,11 +69,11 @@
<div class="thumbnail-field"> <div class="thumbnail-field">
<figure class="image"> <figure class="image">
<span <span
v-if="editForm.header_image === undefined || editForm.header_image === false" v-if="form.header_image === undefined || form.header_image === false"
class="image-placeholder">{{ $i18n.get('label_empty_term_image') }}</span> class="image-placeholder">{{ $i18n.get('label_empty_term_image') }}</span>
<img <img
:alt="$i18n.get('label_image')" :alt="$i18n.get('label_image')"
:src="(editForm.header_image === undefined || editForm.header_image === false) ? $thumbHelper.getEmptyThumbnailPlaceholder() : editForm.header_image"> :src="(form.header_image === undefined || form.header_image === false) ? $thumbHelper.getEmptyThumbnailPlaceholder() : form.header_image">
</figure> </figure>
<div class="thumbnail-buttons-row"> <div class="thumbnail-buttons-row">
<a <a
@ -86,7 +85,7 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('edit'), content: $i18n.get('edit'),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'bottom' placement: 'bottom'
}" }"
class="icon is-small"> class="icon is-small">
@ -102,7 +101,7 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('delete'), content: $i18n.get('delete'),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'bottom' placement: 'bottom'
}" }"
class="icon is-small"> class="icon is-small">
@ -125,12 +124,13 @@
{{ $i18n.get('label_description') }} {{ $i18n.get('label_description') }}
<help-button <help-button
:title="$i18n.get('label_description')" :title="$i18n.get('label_description')"
:message="$i18n.get('info_help_term_description')"/> :message="$i18n.get('info_help_term_description')"
extra-classes="tainacan-repository-tooltip"/>
</label> </label>
<b-input <b-input
type="textarea" type="textarea"
name="description" name="description"
v-model="editForm.description" v-model="form.description"
@focus="clearErrors('description')"/> @focus="clearErrors('description')"/>
</b-field> </b-field>
</div> </div>
@ -150,7 +150,8 @@
v-model="hasParent" /> v-model="hasParent" />
<help-button <help-button
:title="$i18n.get('label_parent_term')" :title="$i18n.get('label_parent_term')"
:message="$i18n.get('info_help_parent_term')"/> :message="$i18n.get('info_help_parent_term')"
extra-classes="tainacan-repository-tooltip"/>
</label> </label>
<b-autocomplete <b-autocomplete
id="tainacan-add-parent-field" id="tainacan-add-parent-field"
@ -192,14 +193,11 @@
</b-field> </b-field>
<!-- Hook for extra Form options --> <!-- Hook for extra Form options -->
<template <template v-if="hasEndLeftForm">
v-if="formHooks != undefined &&
formHooks['term'] != undefined &&
formHooks['term']['end-left'] != undefined">
<form <form
id="form-term-end-left" id="form-term-end-left"
class="form-hook-region" class="form-hook-region"
v-html="formHooks['term']['end-left'].join('')"/> v-html="getEndLeftForm"/>
</template> </template>
<!-- Submit buttons -------------- --> <!-- Submit buttons -------------- -->
@ -234,7 +232,7 @@
name: 'TermEditionForm', name: 'TermEditionForm',
mixins: [ formHooks ], mixins: [ formHooks ],
props: { props: {
editForm: Object, originalForm: Object,
taxonomyId: '', taxonomyId: '',
isModal: false isModal: false
}, },
@ -252,27 +250,31 @@
entityName: 'term', entityName: 'term',
isLoading: false, isLoading: false,
parentTermSearchQuery: '', parentTermSearchQuery: '',
parentTermSearchOffset: 0 parentTermSearchOffset: 0,
form: {}
} }
}, },
created() {
this.form = JSON.parse(JSON.stringify(this.originalForm));
},
mounted() { mounted() {
// Fills hook forms with it's real values // Fills hook forms with it's real values
this.$nextTick() this.$nextTick()
.then(() => { .then(() => {
this.updateExtraFormData(this.editForm); this.updateExtraFormData(this.form);
document.getElementById('termEditForm').scrollIntoView({ behavior: 'smooth' }); document.getElementById('termEditForm').scrollIntoView({ behavior: 'smooth' });
}); });
this.showCheckboxesWarning = false; this.showCheckboxesWarning = false;
this.hasParent = this.editForm.parent != undefined && this.editForm.parent > 0; this.hasParent = this.form.parent != undefined && this.form.parent > 0;
this.initialParentId = this.editForm.parent; this.initialParentId = this.form.parent;
this.initializeMediaFrames(); this.initializeMediaFrames();
if (this.hasParent) { if (this.hasParent) {
this.isFetchingParentTerms = true; this.isFetchingParentTerms = true;
this.showCheckboxesWarning = false; this.showCheckboxesWarning = false;
this.fetchParentName({ taxonomyId: this.taxonomyId, parentId: this.editForm.parent }) this.fetchParentName({ taxonomyId: this.taxonomyId, parentId: this.form.parent })
.then((parentName) => { .then((parentName) => {
this.parentTermName = parentName; this.parentTermName = parentName;
this.isFetchingParentTerms = false; this.isFetchingParentTerms = false;
@ -299,11 +301,11 @@
if (term.id === 'new') { if (term.id === 'new') {
let data = { let data = {
name: this.editForm.name, name: this.form.name,
description: this.editForm.description, description: this.form.description,
parent: this.hasParent ? this.editForm.parent : 0, parent: this.hasParent ? this.form.parent : 0,
header_image_id: this.editForm.header_image_id, header_image_id: this.form.header_image_id,
header_image: this.editForm.header_image, header_image: this.form.header_image,
}; };
this.fillExtraFormData(data); this.fillExtraFormData(data);
this.isLoading = true; this.isLoading = true;
@ -313,7 +315,7 @@
}) })
.then((term) => { .then((term) => {
this.$emit('onEditionFinished', {term: term, hasChangedParent: this.hasChangedParent }); this.$emit('onEditionFinished', {term: term, hasChangedParent: this.hasChangedParent });
this.editForm = {}; this.form = {};
this.formErrors = {}; this.formErrors = {};
this.isLoading = false; this.isLoading = false;
if (this.isModal) if (this.isModal)
@ -333,12 +335,12 @@
} else { } else {
let data = { let data = {
id: this.editForm.id, id: this.form.id,
name: this.editForm.name, name: this.form.name,
description: this.editForm.description, description: this.form.description,
parent: this.hasParent ? this.editForm.parent : 0, parent: this.hasParent ? this.form.parent : 0,
header_image_id: this.editForm.header_image_id, header_image_id: this.form.header_image_id,
header_image: this.editForm.header_image, header_image: this.form.header_image,
} }
this.fillExtraFormData(data); this.fillExtraFormData(data);
this.isLoading = true; this.isLoading = true;
@ -364,13 +366,13 @@
} }
}, },
cancelEdition() { cancelEdition() {
this.$emit('onEditionCanceled', this.editForm); this.$emit('onEditionCanceled', this.form);
if (this.isModal) if (this.isModal)
this.$parent.close(); this.$parent.close();
}, },
deleteHeaderImage() { deleteHeaderImage() {
this.editForm = Object.assign({}, this.form = Object.assign({},
this.editForm, this.form,
{ {
header_image_id: "0", header_image_id: "0",
header_image: false header_image: false
@ -384,11 +386,11 @@
frame_title: this.$i18n.get('instruction_select_term_header_image'), frame_title: this.$i18n.get('instruction_select_term_header_image'),
frame_button: this.$i18n.get('label_select_file') frame_button: this.$i18n.get('label_select_file')
}, },
relatedPostId: this.editForm.id, relatedPostId: this.form.id,
onSave: (croppedImage) => { onSave: (croppedImage) => {
this.editForm = Object.assign({}, this.form = Object.assign({},
this.editForm, this.form,
{ {
header_image_id: croppedImage.id.toString(), header_image_id: croppedImage.id.toString(),
header_image: croppedImage.url header_image: croppedImage.url
@ -432,7 +434,7 @@
this.fetchPossibleParentTerms({ this.fetchPossibleParentTerms({
taxonomyId: this.taxonomyId, taxonomyId: this.taxonomyId,
termId: this.editForm.id, termId: this.form.id,
search: this.parentTermSearchQuery, search: this.parentTermSearchQuery,
offset: this.parentTermSearchOffset }) offset: this.parentTermSearchOffset })
.then((res) => { .then((res) => {
@ -453,7 +455,7 @@
}, 250), }, 250),
onToggleSwitch() { onToggleSwitch() {
if (this.editForm.parent == 0) { if (this.form.parent == 0) {
this.hasChangedParent = this.hasParent; this.hasChangedParent = this.hasParent;
} else { } else {
this.hasChangedParent = !this.hasParent; this.hasChangedParent = !this.hasParent;
@ -464,7 +466,7 @@
}, },
onSelectParentTerm(selectedParentTerm) { onSelectParentTerm(selectedParentTerm) {
this.hasChangedParent = this.initialParentId != selectedParentTerm.id; this.hasChangedParent = this.initialParentId != selectedParentTerm.id;
this.editForm.parent = selectedParentTerm.id; this.form.parent = selectedParentTerm.id;
this.selectedParentTerm = selectedParentTerm; this.selectedParentTerm = selectedParentTerm;
this.parentTermName = selectedParentTerm.name; this.parentTermName = selectedParentTerm.name;
this.showCheckboxesWarning = true; this.showCheckboxesWarning = true;
@ -521,7 +523,7 @@
} }
.tainacan-page-title { .tainacan-page-title {
margin-bottom: 30px; margin-bottom: 28px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: baseline; align-items: baseline;

View File

@ -1,6 +1,6 @@
<template> <template>
<div <div
:style="{ 'height': isLoadingOptions && !filtersAsModal ? (Number(filter.max_options)*28) + 'px' : 'auto' }" :style="{ 'height': isLoadingOptions && !filtersAsModal ? (Number(filter.max_options)*1.375) + 'rem' : 'auto' }"
:class="{ 'skeleton': isLoadingOptions && !filtersAsModal }" :class="{ 'skeleton': isLoadingOptions && !filtersAsModal }"
class="block"> class="block">
<template v-if="!filtersAsModal"> <template v-if="!filtersAsModal">
@ -43,6 +43,13 @@
:is-modal="false" :is-modal="false"
:filter="filter" :filter="filter"
:selected="selected" :selected="selected"
@input="(newSelected) => {
const existingValue = selected.indexOf(newSelected);
if (existingValue >= 0)
selected.splice(existingValue, 1);
else
selected.push(newSelected);
}"
:metadatum-id="metadatumId" :metadatum-id="metadatumId"
:collection-id="collectionId" :collection-id="collectionId"
:metadatum_type="metadatumType" :metadatum_type="metadatumType"
@ -72,10 +79,9 @@
}, },
watch: { watch: {
selected(newVal, oldVal) { selected(newVal, oldVal) {
const isEqual = (newVal.length == oldVal.length) && newVal.every((element, index) => { const isEqual = (Array.isArray(newVal) && Array.isArray(oldVal) && (newVal.length == oldVal.length)) && newVal.every((element, index) => {
return element === oldVal[index]; return element === oldVal[index];
}); });
if (!isEqual) if (!isEqual)
this.onSelect(); this.onSelect();
}, },
@ -88,7 +94,7 @@
}, },
}, },
mounted() { mounted() {
if (!this.isUsingElasticSearch && !this.filtersAsModal) if (!this.isUsingElasticSearch)
this.loadOptions(); this.loadOptions();
}, },
created() { created() {
@ -185,6 +191,13 @@
events: { events: {
appliedCheckBoxModal: () => { appliedCheckBoxModal: () => {
this.loadOptions(); this.loadOptions();
},
input: (newSelected) => {
const existingValue = this.selected.indexOf(newSelected);
if (existingValue >= 0)
this.selected.splice(existingValue, 1);
else
this.selected.push(newSelected);
} }
}, },
trapFocus: true, trapFocus: true,

View File

@ -36,7 +36,8 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('edit'), content: $i18n.get('edit'),
autoHide: true, autoHide: true,
placement: 'bottom' placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}" }"
class="icon"> class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-edit has-text-secondary"/> <i class="tainacan-icon tainacan-icon-18px tainacan-icon-edit has-text-secondary"/>
@ -59,7 +60,8 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('close'), content: $i18n.get('close'),
autoHide: true, autoHide: true,
placement: 'bottom' placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}" }"
class="icon"> class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-close has-text-secondary"/> <i class="tainacan-icon tainacan-icon-18px tainacan-icon-close has-text-secondary"/>

View File

@ -36,7 +36,8 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('edit'), content: $i18n.get('edit'),
autoHide: true, autoHide: true,
placement: 'bottom' placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}" }"
class="icon"> class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-edit has-text-secondary"/> <i class="tainacan-icon tainacan-icon-18px tainacan-icon-edit has-text-secondary"/>
@ -59,7 +60,8 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('close'), content: $i18n.get('close'),
autoHide: true, autoHide: true,
placement: 'bottom' placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}" }"
class="icon"> class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-close has-text-secondary"/> <i class="tainacan-icon tainacan-icon-18px tainacan-icon-close has-text-secondary"/>

View File

@ -1,24 +1,29 @@
<template> <template>
<b-field <b-field
class="filter-item-forms" class="filter-item-forms"
:ref="isMobileScreen ? ('filter-field-id-' + filter.id) : null"
@touchstart.native="setFilterFocus(filter.id)"
@mousedown.native="setFilterFocus(filter.id)"
:style="{ columnSpan: filtersAsModal && filter.filter_type_object && filter.filter_type_object.component && (filter.filter_type_object.component == 'tainacan-filter-taxonomy-checkbox' || filter.filter_type_object.component == 'tainacan-filter-checkbox') ? 'all' : 'unset'}"> :style="{ columnSpan: filtersAsModal && filter.filter_type_object && filter.filter_type_object.component && (filter.filter_type_object.component == 'tainacan-filter-taxonomy-checkbox' || filter.filter_type_object.component == 'tainacan-filter-checkbox') ? 'all' : 'unset'}">
<b-collapse <b-collapse
v-if="displayFilter"
class="show" class="show"
:open.sync="open" :open.sync="singleCollapseOpen"
animation="filter-item"> animation="filter-item">
<button <button
:for="'filter-input-id-' + filter.id" :for="'filter-input-id-' + filter.id"
:aria-controls="'filter-input-id-' + filter.id" :aria-controls="'filter-input-id-' + filter.id"
:aria-expanded="open" :aria-expanded="singleCollapseOpen"
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: filter.name, content: filter.name,
html: false, html: false,
autoHide: false, autoHide: false,
placement: 'top-start' placement: 'top-start',
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
}" }"
:id="'filter-label-id-' + filter.id" :id="'filter-label-id-' + filter.id"
:aria-label="filter.name" :aria-label="filter.name"
@ -27,7 +32,10 @@
slot-scope="props"> slot-scope="props">
<span class="icon"> <span class="icon">
<i <i
:class="{ 'tainacan-icon-arrowdown' : props.open, 'tainacan-icon-arrowright' : !props.open }" :class="{
'tainacan-icon-arrowdown' : props.open,
'tainacan-icon-arrowright' : !props.open
}"
class="tainacan-icon tainacan-icon-1-25em"/> class="tainacan-icon tainacan-icon-1-25em"/>
</span> </span>
<span class="collapse-label">{{ filter.name }}</span> <span class="collapse-label">{{ filter.name }}</span>
@ -39,13 +47,41 @@
:query="query" :query="query"
:is-using-elastic-search="isUsingElasticSearch" :is-using-elastic-search="isUsingElasticSearch"
:is-repository-level="isRepositoryLevel" :is-repository-level="isRepositoryLevel"
:is-loading-items.sync="isLoadingItems" :is-loading-items="isLoadingItems"
:current-collection-id="$eventBusSearch.collectionId" :current-collection-id="$eventBusSearch.collectionId"
@input="onInput" @input="onInput"
@updateParentCollapse="onFilterUpdateParentCollapse" @updateParentCollapse="onFilterUpdateParentCollapse"
:filters-as-modal="filtersAsModal"/> :filters-as-modal="filtersAsModal" />
</div> </div>
</b-collapse> </b-collapse>
<div
v-if="beginWithFilterCollapsed && !displayFilter"
class="collapse show disabled-filter">
<div class="collapse-trigger">
<button
:for="'filter-input-id-' + filter.id"
:aria-controls="'filter-input-id-' + filter.id"
v-tooltip="{
delay: {
shown: 500,
hide: 300,
},
content: $i18n.get('instruction_click_to_load_filter'),
html: false,
autoHide: false,
placement: 'top-start',
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
}"
@click="displayFilter = true"
class="label">
<span class="icon">
<i class="tainacan-icon tainacan-icon-arrowright tainacan-icon-1-25em"/>
</span>
<span class="collapse-label">{{ filter.name }}</span>
</button>
</div>
</div>
</b-field> </b-field>
</template> </template>
@ -56,13 +92,35 @@
filter: Object, filter: Object,
query: Object, query: Object,
isRepositoryLevel: Boolean, isRepositoryLevel: Boolean,
open: true, expandAll: true,
isLoadingItems: true, isLoadingItems: true,
filtersAsModal: Boolean filtersAsModal: Boolean,
isMobileScreen: false
}, },
data() { data() {
return { return {
isUsingElasticSearch: tainacan_plugin.wp_elasticpress == "1" ? true : false isUsingElasticSearch: tainacan_plugin.wp_elasticpress == "1" ? true : false,
displayFilter: false,
singleCollapseOpen: this.expandAll,
focusedElement: false
}
},
computed: {
beginWithFilterCollapsed() {
return this.filter && this.filter.begin_with_filter_collapsed && this.filter.begin_with_filter_collapsed === 'yes';
}
},
watch: {
expandAll() {
this.singleCollapseOpen = this.expandAll;
if (this.expandAll)
this.displayFilter = true;
},
beginWithFilterCollapsed: {
handler() {
this.displayFilter = !this.beginWithFilterCollapsed;
},
immediate: true
} }
}, },
methods: { methods: {
@ -72,7 +130,19 @@
onFilterUpdateParentCollapse(open) { onFilterUpdateParentCollapse(open) {
const componentsThatShouldCollapseIfEmpty = ['tainacan-filter-taxonomy-checkbox', 'tainacan-filter-selectbox', 'tainacan-filter-checkbox']; const componentsThatShouldCollapseIfEmpty = ['tainacan-filter-taxonomy-checkbox', 'tainacan-filter-selectbox', 'tainacan-filter-checkbox'];
if (componentsThatShouldCollapseIfEmpty.includes(this.filter.filter_type_object.component)) if (componentsThatShouldCollapseIfEmpty.includes(this.filter.filter_type_object.component))
this.open = open; this.singleCollapseOpen = open;
},
setFilterFocus(filterId) {
if (this.isMobileScreen) {
let fieldElement = this.$refs['filter-field-id-' + filterId] && this.$refs['filter-field-id-' + filterId]['$el'];
if (this.focusedElement !== filterId && fieldElement && (typeof fieldElement.scrollIntoView == 'function')) {
this.focusedElement = filterId;
fieldElement.scrollIntoView({
behavior: 'smooth',
block: 'start'
})
}
}
} }
} }
} }
@ -89,7 +159,7 @@
} }
.collapse-trigger { .collapse-trigger {
margin-left: -7px; margin-left: -8px;
button { button {
background-color: inherit !important; background-color: inherit !important;
color: inherit !important; color: inherit !important;
@ -105,6 +175,9 @@
line-height: 1.4em; line-height: 1.4em;
} }
} }
.disabled-filter {
opacity: 0.75;
}
.collapse-content { .collapse-content {
margin-top: 12px; margin-top: 12px;
} }
@ -197,6 +270,15 @@
font-weight: normal; font-weight: normal;
font-size: 1em !important; font-size: 1em !important;
margin-right: 2px; margin-right: 2px;
@media screen and (max-width: 768px) {
font-size: 1.125em !important;
.control-label {
padding-top: 0.55em;
padding-bottom: 0.55em;
}
}
} }
.datepicker { .datepicker {

View File

@ -51,6 +51,13 @@
:filter="filter" :filter="filter"
:taxonomy_id="taxonomyId" :taxonomy_id="taxonomyId"
:selected="selected" :selected="selected"
@input="(newSelected) => {
const existingValue = selected.indexOf(newSelected);
if (existingValue >= 0)
selected.splice(existingValue, 1);
else
selected.push(newSelected);
}"
:metadatum-id="metadatumId" :metadatum-id="metadatumId"
:taxonomy="taxonomy" :taxonomy="taxonomy"
:collection-id="collectionId" :collection-id="collectionId"
@ -93,7 +100,7 @@
}, },
watch: { watch: {
selected(newVal, oldVal) { selected(newVal, oldVal) {
const isEqual = (newVal.length == oldVal.length) && newVal.every((element, index) => { const isEqual = (Array.isArray(newVal) && Array.isArray(oldVal) && (newVal.length == oldVal.length)) && newVal.every((element, index) => {
return element === oldVal[index]; return element === oldVal[index];
}); });
if (!isEqual) if (!isEqual)
@ -126,7 +133,7 @@
this.$eventBusSearch.$on('has-to-reload-facets', this.reloadOptions); this.$eventBusSearch.$on('has-to-reload-facets', this.reloadOptions);
}, },
mounted(){ mounted(){
if (!this.isUsingElasticSearch && !this.filtersAsModal) if (!this.isUsingElasticSearch)
this.loadOptions(); this.loadOptions();
}, },
beforeDestroy() { beforeDestroy() {
@ -253,6 +260,13 @@
events: { events: {
appliedCheckBoxModal: () => { appliedCheckBoxModal: () => {
this.loadOptions(); this.loadOptions();
},
input: (newSelected) => {
const existingValue = this.selected.indexOf(newSelected);
if (existingValue >= 0)
this.selected.splice(existingValue, 1);
else
this.selected.push(newSelected);
} }
}, },
width: 'calc(100% - (4 * var(--tainacan-one-column)))', width: 'calc(100% - (4 * var(--tainacan-one-column)))',

View File

@ -3,109 +3,88 @@
<div class="table-wrapper"> <div class="table-wrapper">
<table class="tainacan-table is-narrow"> <table class="tainacan-table is-narrow">
<thead> <thead>
<tr> <tr>
<!-- Title --> <!-- Title -->
<th> <th>
<div class="th-wrap">{{ $i18n.get('label_activity_title') }}</div> <div class="th-wrap">{{ $i18n.get('label_activity_title') }}</div>
</th> </th>
<!-- Created by --> <!-- Created by -->
<th> <th>
<div class="th-wrap">{{ $i18n.get('label_created_by') }}</div> <div class="th-wrap">{{ $i18n.get('label_created_by') }}</div>
</th> </th>
<!-- Activity date --> <!-- Activity date -->
<th> <th>
<div class="th-wrap">{{ $i18n.get('label_activity_date') }}</div> <div class="th-wrap">{{ $i18n.get('label_activity_date') }}</div>
</th> </th>
<!--&lt;!&ndash; Approbation &ndash;&gt;--> <!--&lt;!&ndash; Approbation &ndash;&gt;-->
<!--<th>--> <!--<th>-->
<!--<div class="th-wrap">{{ $i18n.get('label_approbation') }}</div>--> <!--<div class="th-wrap">{{ $i18n.get('label_approbation') }}</div>-->
<!--</th>--> <!--</th>-->
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr <tr
:key="index" :key="index"
v-for="(activity, index) of activities"> v-for="(activity, index) of activities">
<!-- Name --> <!-- Name -->
<td <td
class="column-default-width column-main-content" class="column-default-width column-main-content"
@click="openActivityDetailsModal(activity)" @click="openActivityDetailsModal(activity)"
:label="$i18n.get('label_activity_title')" :label="$i18n.get('label_activity_title')"
:aria-label="$i18n.get('label_activity_title') + ': ' + activity.title"> :aria-label="$i18n.get('label_activity_title') + ': ' + activity.title">
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: activity.title, content: activity.title,
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}"> }">
{{ activity.title }} {{ activity.title }}
</p> </p>
</td> </td>
<!-- User --> <!-- User -->
<td <td
class="table-creation column-small-width" class="table-creation column-small-width"
@click="openActivityDetailsModal(activity)" @click="openActivityDetailsModal(activity)"
:label="$i18n.get('label_created_by')" :label="$i18n.get('label_created_by')"
:aria-label="$i18n.get('label_created_by') + ': ' + activity.user_name"> :aria-label="$i18n.get('label_created_by') + ': ' + activity.user_name">
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: activity.user_name, content: activity.user_name,
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-html="activity.user_name"/> v-html="activity.user_name"/>
</td> </td>
<!-- Activity Date --> <!-- Activity Date -->
<td <td
class="table-creation column-small-width" class="table-creation column-small-width"
@click="openActivityDetailsModal(activity)" @click="openActivityDetailsModal(activity)"
:label="$i18n.get('label_activity_date')" :label="$i18n.get('label_activity_date')"
:aria-label="$i18n.get('label_activity_date') + ': ' + activity.date"> :aria-label="$i18n.get('label_activity_date') + ': ' + activity.date">
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: activity.date, content: activity.date,
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-html="activity.date"/> v-html="activity.date"/>
</td> </td>
<!-- Approbation --> </tr>
<!--<td-->
<!--class="status-cell"-->
<!--:label="$i18n.get('label_approbation')"-->
<!--:aria-label="$i18n.get('label_approbation') + ': ' + activity.status">-->
<!--<p>-->
<!--<three-state-toggle-button-->
<!--:other-prop="activity"-->
<!--:parent="getThis()"-->
<!--:events="stateEvents"-->
<!--:state=" activity.status === 'publish' ?-->
<!--'yes_3tgbtn' : (activity.status === 'pending' ? 'neutral_3tgbtn' : 'no_3tgbtn')"/>-->
<!--&lt;!&ndash;<a v-if="activity.status !== 'pending'">&ndash;&gt;-->
<!--&lt;!&ndash;<b-icon&ndash;&gt;-->
<!--&lt;!&ndash;type="is-blue5"&ndash;&gt;-->
<!--&lt;!&ndash;custom-class="mdi-flip-h"&ndash;&gt;-->
<!--&lt;!&ndash;icon="share"/>&ndash;&gt;-->
<!--&lt;!&ndash;</a>&ndash;&gt;-->
<!--</p>-->
<!--</td>-->
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@ -130,7 +109,6 @@
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import ActivityDetailsModal from '../modals/activity-details-modal.vue'; import ActivityDetailsModal from '../modals/activity-details-modal.vue';
// import ThreeStateToggleButton from '../other/three-state-toggle-button.vue';
export default { export default {
name: 'ActivitiesList', name: 'ActivitiesList',

View File

@ -4,7 +4,7 @@
style="position: relative;" style="position: relative;"
class="table-container"> class="table-container">
<b-loading <b-loading
is-full-page="false" :is-full-page="false"
:active.sync="isLoading" /> :active.sync="isLoading" />
<div <div
v-if="attachments.length > 0" v-if="attachments.length > 0"
@ -13,20 +13,27 @@
<div <div
v-for="(attachment, index) in attachments" v-for="(attachment, index) in attachments"
:key="index" :key="index"
class="file-item-container"> class="file-item-container"
:class="{ 'is-file-document': form.document == attachment.id, 'is-file-thumbnail': item.thumbnail_id == attachment.id }">
<span
v-if="form.document == attachment.id"
class="file-attachment-document-tag">
{{ $i18n.get('label_document') }}
</span>
<file-item <file-item
:show-name="true" :show-name="true"
:modal-on-click="true" :modal-on-click="true"
:file="attachment"/> :file="attachment"/>
<span <span
v-if="isEditable" v-if="isEditable && form.document != attachment.id"
class="file-item-control"> class="file-item-control">
<a <a
@click="onDeleteAttachment(attachment)" @click="onDeleteAttachment(attachment)"
v-tooltip="{ v-tooltip="{
content: $i18n.get('delete'), content: $i18n.get('delete'),
autoHide: true, autoHide: true,
placement: 'bottom' placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}" }"
class="icon"> class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-delete"/> <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-delete"/>
@ -106,13 +113,15 @@
}, },
props: { props: {
item: Object, item: Object,
isLoading: Boolean, form: Object,
shouldLoadAttachments: Boolean,
isEditable: Boolean, isEditable: Boolean,
}, },
data() { data() {
return { return {
attachmentsPage: 1, attachmentsPage: 1,
attachmentsPerPage: 24 attachmentsPerPage: 12,
isLoading: false
} }
}, },
computed: { computed: {
@ -123,6 +132,11 @@
return this.getTotalAttachments(); return this.getTotalAttachments();
} }
}, },
watch: {
shouldLoadAttachments() {
this.loadAttachments();
}
},
created() { created() {
// Get attachments // Get attachments
this.loadAttachments(); this.loadAttachments();
@ -159,23 +173,20 @@
}, },
loadAttachments() { loadAttachments() {
this.isLoading = true; this.isLoading = true;
this.$emit('isLoadingAttachments', true);
this.fetchAttachments({ this.fetchAttachments({
page: this.attachmentsPage, page: this.attachmentsPage,
attachmentsPerPage: this.attachmentsPerPage, attachmentsPerPage: this.attachmentsPerPage,
itemId: this.item.id, itemId: this.item.id,
documentId: this.item.document, // excludeDocumentId: this.form.document,
thumbnailId: this.item.thumbnail_id // excludeThumbnailId: this.item.thumbnail_id
}) })
.then((response) => { .then((response) => {
this.isLoading = false; this.isLoading = false;
this.$emit('isLoadingAttachments', false);
this.totalAttachments = response.total; this.totalAttachments = response.total;
}) })
.catch((error) => { .catch((error) => {
this.isLoading = false; this.isLoading = false;
this.$emit('isLoadingAttachments', false);
this.$console.error(error); this.$console.error(error);
}) })
}, },
@ -188,12 +199,16 @@
<style lang="scss" scoped> <style lang="scss" scoped>
.table-container {
width: 100%;
}
.uploaded-files { .uploaded-files {
display: block; display: flex;
flex-wrap: wrap;
.file-item-container { .file-item-container {
display: inline-block; display: inline-block;
margin: 15px; margin: 10px 12px;
position: relative; position: relative;
&:hover .file-item-control { &:hover .file-item-control {
@ -202,10 +217,30 @@
opacity: 1; opacity: 1;
} }
.file-attachment-document-tag {
background-color: var(--tainacan-primary);
color: var(--tainacan-secondary);
display: block;
position: absolute;
z-index: 9;
padding: 0.25em 0.5em;
font-size: 0.6875em;
border-radius: 3px;
bottom: 10px;
left: 4px;
font-weight: 500;
border: 1px solid var(--tainacan-secondary);
opacity: 0.25;
transition: opacity 0.2s ease;
}
&:hover .file-attachment-document-tag {
opacity: 1.0;
}
.file-item-control { .file-item-control {
position: absolute; position: absolute;
background-color: var(--tainacan-gray1); background-color: var(--tainacan-gray1);
width: 112px; width: 94px;
margin: 6px 0; margin: 6px 0;
bottom: 0px; bottom: 0px;
padding: 2px 8px 4px 8px; padding: 2px 8px 4px 8px;
@ -221,4 +256,23 @@
} }
} }
} }
@media screen and (max-width: 769px) {
.table-container {
padding-left: 1em;
padding-right: 1em;
}
.pagination-area {
margin-left: 0;
margin-right: 0;
justify-content: center;
}
.uploaded-files {
justify-content: center;
.file-item-container {
margin: 5px 7px;
}
}
}
</style> </style>

View File

@ -29,7 +29,8 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('edit'), content: $i18n.get('edit'),
autoHide: true, autoHide: true,
placement: 'auto' placement: 'auto',
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip']
}" }"
class="icon"> class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-edit"/> <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-edit"/>
@ -40,7 +41,8 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('delete'), content: $i18n.get('delete'),
autoHide: true, autoHide: true,
placement: 'auto' placement: 'auto',
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip']
}" }"
class="icon"> class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-delete"/> <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-delete"/>
@ -56,7 +58,7 @@ import { mapActions } from 'vuex';
import CustomDialog from '../other/custom-dialog.vue'; import CustomDialog from '../other/custom-dialog.vue';
export default { export default {
name: 'RecursiveTermItem', name: 'BasicTermItem',
props: { props: {
term: Object, term: Object,
index: Number, index: Number,
@ -86,8 +88,7 @@ export default {
'deleteTerm' 'deleteTerm'
]), ]),
editTerm() { editTerm() {
this.term.opened = !this.term.opened; this.$emit('onUpdateTermOpenedState', !this.term.opened);
this.$eventBusTermsList.onEditTerm(this.term); this.$eventBusTermsList.onEditTerm(this.term);
}, },
tryToRemoveTerm() { tryToRemoveTerm() {
@ -136,11 +137,11 @@ export default {
}, },
eventOnTermEditionSaved() { eventOnTermEditionSaved() {
this.isEditingTerm = false; this.isEditingTerm = false;
this.term.opened = false; this.$emit('onUpdateTermOpenedState', false);
}, },
eventOnTermEditionCanceled() { eventOnTermEditionCanceled() {
this.isEditingTerm = false; this.isEditingTerm = false;
this.term.opened = false; this.$emit('onUpdateTermOpenedState', false);
} }
} }
} }

View File

@ -34,12 +34,12 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 120, hide: 120,
}, },
content: capability.display_name, content: capability.display_name,
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}"> }">
{{ capability.display_name }} {{ capability.display_name }}
@ -53,12 +53,12 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 120, hide: 120,
}, },
content: capability.description, content: capability.description,
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-html="capability.description"/> v-html="capability.description"/>
@ -75,12 +75,12 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 120, hide: 120,
}, },
content: props['complete-roles-list'], content: props['complete-roles-list'],
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-html="props['complete-roles-list']"/> v-html="props['complete-roles-list']"/>
@ -99,7 +99,7 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('edit'), content: $i18n.get('edit'),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto' placement: 'auto'
}" }"
class="icon"> class="icon">

View File

@ -0,0 +1,907 @@
<template>
<div class="column">
<b-loading :active.sync="isLoadingMetadataSections"/>
<div class="tainacan-form sub-header">
<template v-if="activeMetadataSectionsList">
<button
aria-controls="filters-items-list"
:aria-expanded="!collapseAll"
v-if="activeMetadataSectionsList.length > 0"
class="link-style collapse-all"
@click="collapseAll = !collapseAll">
<span class="icon">
<i
:class="{ 'tainacan-icon-arrowdown' : collapseAll, 'tainacan-icon-arrowright' : !collapseAll }"
class="has-text-secondary tainacan-icon tainacan-icon-1-125em"/>
</span>
<span class="collapse-all__text">
{{ collapseAll ? $i18n.get('label_show_less_details') : $i18n.get('label_show_more_details') }}
</span>
</button>
<b-field class="header-item">
<b-dropdown
:mobile-modal="true"
:disabled="activeMetadataSectionsList.length <= 0"
class="show metadata-options-dropdown"
aria-role="list"
trap-focus>
<button
:aria-label="$i18n.get('label_filter_by_metadata_type')"
class="button is-white"
slot="trigger">
<span>{{ $i18n.get('label_filter_by_metadata_type') }}</span>
<span class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-arrowdown"/>
</span>
</button>
<div class="metadata-options-container">
<b-dropdown-item
v-for="(metadataType, index) in metadataTypeFilterOptions"
:key="index"
class="control"
custom
aria-role="listitem">
<b-checkbox
v-model="metadataType.enabled"
:native-value="metadataType.enabled">
{{ metadataType.name }}
</b-checkbox>
</b-dropdown-item>
</div>
</b-dropdown>
</b-field>
<b-field class="header-item">
<b-input
:placeholder="$i18n.get('instruction_type_search_metadata_filter')"
v-model="metadataNameFilterString"
icon="magnify"
size="is-small"
icon-right="close-circle"
icon-right-clickable
@icon-right-click="metadataNameFilterString = ''" />
</b-field>
</template>
</div>
<section
v-if="activeMetadataSectionsList.length <= 0 && !isLoadingMetadataSections"
class="field is-grouped-centered section">
<div class="content has-text-gray has-text-centered">
<p>
<span class="icon is-large">
<i class="tainacan-icon tainacan-icon-36px tainacan-icon-metadata"/>
</span>
</p>
<p>{{ $i18n.get('info_there_is_no_metadata_section') }}</p>
</div>
</section>
<!-- The Metadata Sections list -->
<draggable
v-model="activeMetadataSectionsList"
class="active-metadata-sections-area"
@change="handleSectionChange($event)"
:group="{ name:'metadata-sections', pull: false, put: [ 'metadata-sections' ] }"
:sort="(openedMetadataSectionId == '' || openedMetadataSectionId == undefined) && (openedMetadatumId == '' || openedMetadatumId == undefined)"
:handle="'.handle'"
ghost-class="sortable-ghost"
chosen-class="sortable-chosen"
filter=".not-sortable-item"
:prevent-on-filter="false"
:animation="250">
<div
v-for="(metadataSection, sectionIndex) in activeMetadataSectionsList"
:key="metadataSection.id">
<div
class="active-metadata-sections-item"
:class="{
'is-compact-item': !isCollapseOpen(metadataSection.id),
'not-sortable-item':
metadataSection.id == undefined ||
openedMetadatumId != '' ||
openedMetadataSectionId != '' ||
isUpdatingMetadataOrder ||
isUpdatingMetadatum ||
isUpdatingMetadataSectionsOrder ||
metadataNameFilterString != '' ||
hasSomeMetadataTypeFilterApplied,
'not-focusable-item': openedMetadataSectionId == metadataSection.id,
'disabled-metadatum': metadataSection.enabled == false,
'inherited-metadatum': false
}">
<div
:ref="'metadata-section-handler-' + metadataSection.id"
class="handle">
<span class="sorting-buttons">
<button
:disabled="sectionIndex == 0"
class="link-button"
@click="moveMetadataSectionUpViaButon(sectionIndex)">
<span class="icon">
<i class="tainacan-icon tainacan-icon-previous tainacan-icon-rotate-90" />
</span>
</button>
<button
:disabled="sectionIndex == activeMetadataSectionsList.length - 1"
class="link-button"
@click="moveMetadataSectionDownViaButton(sectionIndex)">
<span class="icon">
<i class="tainacan-icon tainacan-icon-next tainacan-icon-rotate-90" />
</span>
</button>
</span>
<span
:style="{ opacity: !(metadataSection.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder || openedMetadataSectionId != '' || isUpdatingMetadataSectionsOrder || metadataNameFilterString != '' || hasSomeMetadataTypeFilterApplied) ? '1.0' : '0.0' }"
v-tooltip="{
content: metadataSection.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder || openedMetadataSectionId != '' || isUpdatingMetadataSectionsOrder || isUpdatingMetadatum ? $i18n.get('info_not_allowed_change_order_metadata_sections') : $i18n.get('instruction_drag_and_drop_metadata_sections_sort'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}"
class="icon grip-icon">
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="currentColor">
<path
d="M0 0h24v24H0V0z"
fill="transparent"/>
<path d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
</svg>
</span>
<span class="metadatum-name">
<h3>{{ metadataSection.name }}</h3>
</span>
<span
v-if="metadataSection.id != undefined"
class="label-details"
:class="{ 'has-text-weight-bold': metadataSection.id === 'default_section' }">
<span
v-if="metadataSection.id === 'default_section'"
v-tooltip="{
content: $i18n.get('label_required'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}">
*&nbsp;({{ $i18n.get('label_default_section') }})
</span>
<span
v-if="metadataSection.status === 'private'"
class="icon"
v-tooltip="{
content: $i18n.get('status_private'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}">
<i class="tainacan-icon tainacan-icon-private"/>
</span>
</span>
<span
class="loading-spinner"
v-if="metadataSection.id == undefined"/>
<span
class="controls"
v-if="metadataSection.id !== undefined">
<b-switch
:disabled="isUpdatingMetadataSectionsOrder"
size="is-small"
:value="metadataSection.enabled"
@input="onChangeEnableSection($event, sectionIndex)"/>
<a
v-if="metadataSection.current_user_can_edit"
:style="{ visibility:
metadataSection.collection_id != collectionId
? 'hidden' : 'visible'
}"
@click.prevent="toggleMetadataSectionEdition(metadataSection)">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}"
class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-edit"/>
</span>
</a>
<a
v-if="metadataSection.current_user_can_delete"
:disabled="metadataSection.metadata_object_list.length"
:style="{ visibility: metadataSection.collection_id != collectionId || metadataSection.id === 'default_section' || metadataSection.metadata_object_list.length ? 'hidden' : 'visible' }"
@click.prevent="removeMetadataSection(metadataSection)">
<span
v-tooltip="{
content: $i18n.get('delete'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}"
class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-delete"/>
</span>
</a>
</span>
</div>
</div>
<section
v-if="metadataSection.metadata_object_list && metadataSection.metadata_object_list.length <= 0"
class="field is-grouped-centered section">
<div class="content has-text-gray has-text-centered">
<p>
<span class="icon is-large">
<i class="tainacan-icon tainacan-icon-36px tainacan-icon-metadata"/>
</span>
</p>
<p>{{ $i18n.get('info_there_is_no_metadatum' ) }}</p>
<p>{{ $i18n.get('info_create_metadata' ) }}</p>
</div>
</section>
<b-loading :active.sync="isUpdatingMetadatum"/>
<!-- The Metadata list, inside each metadata section -->
<template v-if="metadataSection.metadata_object_list && Array.isArray(metadataSection.metadata_object_list)">
<draggable
v-model="metadataSection.metadata_object_list"
class="active-metadata-area"
@change="handleChange($event, sectionIndex)"
:group="{ name:'metadata', pull: [ 'metadata' ], put: [ 'metadata' ] }"
:sort="(openedMetadatumId == '' || openedMetadatumId == undefined)"
:handle="'.handle'"
ghost-class="sortable-ghost"
chosen-class="sortable-chosen"
filter=".not-sortable-item"
:prevent-on-filter="false"
:animation="250">
<div
v-for="(metadatum, index) in metadataSection.metadata_object_list.filter((meta) => meta != undefined && meta.parent == 0)"
:key="metadatum.id"
v-show="(metadataNameFilterString == '' || filterByMetadatumName(metadatum)) && filterByMetadatumType(metadatum)">
<div
class="active-metadatum-item"
:class="{
'is-compact-item': !isCollapseOpen(metadatum.id),
'not-sortable-item': metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder || metadataNameFilterString != '' || hasSomeMetadataTypeFilterApplied || isUpdatingMetadatum,
'not-focusable-item': openedMetadatumId == metadatum.id,
'disabled-metadatum': metadataSection.enabled == false || metadatum.enabled == false,
'inherited-metadatum': metadatum.inherited,
'child-metadatum': metadatum.parent > 0
}">
<div
:ref="'metadatum-handler-' + metadatum.id"
class="handle">
<span class="sorting-buttons">
<button
:disabled="index == 0"
class="link-button"
@click="moveMetadatumUpViaButton(index, sectionIndex)"
:aria-label="$i18n.get('label_move_up')">
<span class="icon">
<i class="tainacan-icon tainacan-icon-previous tainacan-icon-rotate-90" />
</span>
</button>
<button
:disabled="index == metadataSection.metadata_object_list.filter((meta) => meta != undefined && meta.parent == 0).length - 1"
class="link-button"
@click="moveMetadatumDownViaButton(index, sectionIndex)"
:aria-label="$i18n.get('label_move_down')">
<span class="icon">
<i class="tainacan-icon tainacan-icon-next tainacan-icon-rotate-90" />
</span>
</button>
</span>
<span
:style="{ opacity: !(metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder || metadataNameFilterString != '' || hasSomeMetadataTypeFilterApplied) ? '1.0' : '0.0' }"
v-tooltip="{
content: metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder || isUpdatingMetadatum ? $i18n.get('info_not_allowed_change_order_metadata') : $i18n.get('instruction_drag_and_drop_metadatum_sort'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}"
class="icon grip-icon">
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="currentColor">
<path
d="M0 0h24v24H0V0z"
fill="transparent"/>
<path d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
</svg>
</span>
<span
v-tooltip="{
content: $i18n.get('label_view_metadata_details'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}"
@click="$set(collapses, metadatum.id, !isCollapseOpen(metadatum.id))"
class="gray-icon icon"
:style="{ cursor: 'pointer', opacity: openedMetadatumId != metadatum.id ? '1.0' : '0.0' }">
<i :class="'tainacan-icon tainacan-icon-1-25em tainacan-icon-' + (isCollapseOpen(metadatum.id) ? 'arrowdown' : 'arrowright')" />
</span>
<span class="metadatum-name">
{{ metadatum.name }}
</span>
<span
v-if="metadatum.id != undefined && metadatum.metadata_type_object"
class="label-details"
:class="{ 'has-text-weight-bold': metadatum.metadata_type_object.core }">
<span
v-if="metadatum.required === 'yes'"
v-tooltip="{
content: $i18n.get('label_required'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}">
*&nbsp;
</span>
({{ metadatum.metadata_type_object.name }})
<span
v-if="metadatum.status === 'private'"
class="icon"
v-tooltip="{
content: $i18n.get('status_private'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}">
<i class="tainacan-icon tainacan-icon-private"/>
</span>
<span
v-tooltip="{
content: (metadatum.collection_id == 'default') ? $i18n.get('label_repository_metadatum') : $i18n.get('label_collection_metadatum'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}"
class="icon icon-level-identifier">
<i
v-if="metadatum.collection_id == 'default'"
:class="{
'has-text-blue5': metadatum.enabled,
'has-text-gray3': !metadatum.enabled
}"
class="tainacan-icon tainacan-icon-repository" />
<i
v-else
:class="{
'has-text-turquoise5': metadatum.enabled,
'has-text-gray3': !metadatum.enabled
}"
class="tainacan-icon tainacan-icon-collection" />
</span>
</span>
<span
class="loading-spinner"
v-if="metadatum.id == undefined || isUpdatingMetadatum"/>
<span
class="controls"
v-if="metadatum.id !== undefined">
<b-switch
:style="{ visibility: !metadataSection.enabled ? 'hidden' : 'visible' }"
:disabled="isUpdatingMetadataOrder || !metadataSection.enabled"
size="is-small"
:value="metadatum.enabled"
@input="onChangeEnable($event, index, sectionIndex)"/>
<a
v-if="metadatum.current_user_can_edit"
:style="{ visibility:
metadatum.collection_id != collectionId
? 'hidden' : 'visible'
}"
@click.prevent="toggleMetadatumEdition(metadatum)">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}"
class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-edit"/>
</span>
</a>
<a
v-if="metadatum.current_user_can_delete"
:style="{ visibility: metadatum.collection_id != collectionId || metadatum.metadata_type_object.core ? 'hidden' : 'visible' }"
@click.prevent="removeMetadatum(metadatum, sectionIndex)">
<span
v-tooltip="{
content: $i18n.get('delete'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip'],
placement: 'auto-start'
}"
class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-delete"/>
</span>
</a>
</span>
</div>
<transition name="form-collapse">
<metadatum-details
v-if="isCollapseOpen(metadatum.id) && openedMetadatumId !== metadatum.id"
:metadatum="metadatum" />
</transition>
</div>
<!-- Child metadata list, inside each compound metadata -->
<child-metadata-list
v-if="metadatum.metadata_type_object && metadatum.metadata_type_object.component == 'tainacan-compound'"
:parent="metadatum"
:metadata-name-filter-string="metadataNameFilterString"
:metadata-type-filter-options="metadataTypeFilterOptions"
:has-some-metadata-type-filter-applied="hasSomeMetadataTypeFilterApplied"
:is-parent-multiple="metadatum.multiple == 'yes'"
:is-repository-level="false"
:collapse-all="collapseAll"
:section-id="metadataSection.id" />
<!-- Metadata edition form, for each metadata -->
<b-modal
@close="onEditionCanceled()"
:active="openedMetadatumId == metadatum.id"
trap-focus
aria-modal
aria-role="dialog"
custom-class="tainacan-modal"
:close-button-aria-label="$i18n.get('close')">
<metadatum-edition-form
:collection-id="collectionId"
:original-metadatum="metadatum"
:is-repository-level="false"
@onEditionFinished="onEditionFinished()"
@onEditionCanceled="onEditionCanceled()"
:index="index" />
</b-modal>
</div>
</draggable><!-- End of .active-metadata-area -->
</template>
<!-- Metadata Section edition form, for each metadata section -->
<b-modal
@close="onSectionEditionCanceled()"
:active="openedMetadataSectionId == metadataSection.id"
trap-focus
aria-modal
aria-role="dialog"
custom-class="tainacan-modal"
:close-button-aria-label="$i18n.get('close')">
<metadata-section-edition-form
:collection-id="collectionId"
:original-metadata-section="metadataSection"
@onEditionFinished="onSectionEditionFinished()"
@onEditionCanceled="onSectionEditionCanceled()"
:index="sectionIndex" />
</b-modal>
</div>
</draggable> <!-- End of .active-metadata-sections-area -->
</div> <!-- End of .columns -->
</template>
<script>
import MetadatumEditionForm from '../../components/edition/metadatum-edition-form.vue';
import MetadataSectionEditionForm from '../../components/edition/metadata-section-edition-form.vue';
import MetadatumDetails from '../../components/other/metadatum-details.vue';
import ChildMetadataList from '../../components/metadata-types/compound/child-metadata-list.vue';
import CustomDialog from '../../components/other/custom-dialog.vue';
import { mapGetters, mapActions } from 'vuex';
export default {
name: 'CollectionMetadataList',
components: {
MetadatumEditionForm,
MetadataSectionEditionForm,
ChildMetadataList,
MetadatumDetails
},
props: {
metadataTypeFilterOptions: Array
},
data() {
return {
collectionId: '',
isLoadingMetadataSections: false,
isUpdatingMetadataOrder: false,
openedMetadatumId: '',
openedMetadataSectionId: '',
hightlightedMetadatum: '',
collapses: {},
collapseAll: false,
metadataNameFilterString: '',
isUpdatingMetadataSectionsOrder: false,
isUpdatingMetadatum: false,
metadataSearchCancel: undefined
}
},
computed: {
hasSomeMetadataTypeFilterApplied() {
return this.metadataTypeFilterOptions.length && this.metadataTypeFilterOptions.some((metadatumType) => metadatumType.enabled);
},
activeMetadataSectionsList: {
get() {
return this.getMetadataSections();
},
set(value) {
this.updateMetadataSections(value);
}
}
},
watch: {
'$route.query': {
handler(newQuery) {
if (newQuery.edit != undefined) {
let existingMetadataIndex = -1;
let existingMetadataSectionIndex = -1;
for (let i = 0; i < this.activeMetadataSectionsList.length; i++) {
existingMetadataIndex = this.activeMetadataSectionsList[i].metadata_object_list.findIndex((metadatum) => metadatum && (metadatum.id == newQuery.edit));
if (existingMetadataIndex >= 0) {
existingMetadataSectionIndex = i;
break;
}
}
if (existingMetadataIndex >= 0 && existingMetadataSectionIndex >= 0)
this.editMetadatum(newQuery.edit);
} else if (newQuery.sectionEdit != undefined) {
let existingMetadataSectionIndex = this.activeMetadataSectionsList.findIndex((metadataSection) => metadataSection && (metadataSection.id == newQuery.sectionEdit));
if (existingMetadataSectionIndex >= 0)
this.editMetadataSection(newQuery.sectionEdit);
}
},
immediate: true
},
collapseAll(isCollapsed) {
this.activeMetadataSectionsList.forEach((metadataSection) => {
if ( metadataSection.metadata_object_list && Array.isArray(metadataSection.metadata_object_list) )
metadataSection.metadata_object_list.forEach((metadatum) => this.$set(this.collapses, metadatum.id, isCollapsed));
});
}
},
mounted() {
this.cleanMetadataSections();
this.$eventBusMetadataList.$on('addMetadatumViaButton', this.addMetadatumViaButton);
this.$eventBusMetadataList.$on('addMetadataSectionViaButton', this.addMetadataSectionViaButton);
this.collectionId = this.$route.params.collectionId;
this.isLoadingMetadataSections = true;
this.fetchMetadataSections({ collectionId: this.collectionId, isContextEdit: true, includeDisabled: true })
.then(() => {
this.isLoadingMetadataSections = false;
})
.catch((error) => {
this.$console.error(error);
this.isLoadingMetadataSections = false;
});
},
beforeDestroy() {
// Cancels previous Request
if (this.metadataSearchCancel != undefined)
this.metadataSearchCancel.cancel('Metadata search Canceled.');
this.$eventBusMetadataList.$off('addMetadatumViaButton', this.addMetadatumViaButton);
this.$eventBusMetadataList.$off('addMetadataSectionViaButton', this.addMetadataSectionViaButton);
},
methods: {
...mapActions('metadata', [
'sendMetadatum',
'sendMetadataSection',
'deleteMetadatum',
'updateMetadatum',
'updateCollectionMetadataOrder',
'updateCollectionMetadataSectionsOrder',
'updateMetadataSections',
'fetchMetadataSections',
'deleteMetadataSection',
'cleanMetadataSections',
'moveMetadataSectionUp',
'moveMetadataSectionDown',
'moveMetadatumUp',
'moveMetadatumDown'
]),
...mapGetters('metadata',[
'getMetadataSections'
]),
handleSectionChange(event) {
if (event.added)
this.addNewMetadataSection(event.added.newIndex);
else if (event.removed)
this.removeMetadataSection(event.removed.element);
else if (event.moved)
this.updateMetadataSectionsOrder();
},
handleChange(event, sectionIndex) {
if (event.added) {
if (!event.added.element.id)
this.addNewMetadatum(event.added.element, event.added.newIndex, sectionIndex);
else {
this.updateMetadatum({
collectionId: this.collectionId,
metadatumId: event.added.element.id,
isRepositoryLevel: false,
index: event.added.newIndex,
options: {},
includeOptionsAsHtml: true,
sectionId: this.activeMetadataSectionsList[sectionIndex].id
});
this.updateMetadataSectionsOrder(sectionIndex);
}
}
else if (event.moved)
this.updateMetadataOrder(sectionIndex);
},
updateMetadataOrder(sectionIndex) {
let metadataOrder = [];
for (let metadatum of this.activeMetadataSectionsList[sectionIndex].metadata_object_list)
if (metadatum != undefined)
metadataOrder.push({
'id': metadatum.id,
'enabled': metadatum.enabled
});
this.isUpdatingMetadataOrder = true;
this.updateCollectionMetadataOrder({ collectionId: this.collectionId, metadataOrder: metadataOrder, metadataSectionId: this.activeMetadataSectionsList[sectionIndex].id })
.then(() => this.isUpdatingMetadataOrder = false)
.catch(() => this.isUpdatingMetadataOrder = false);
},
updateMetadataSectionsOrder() {
let metadataSectionsOrder = [];
for (let metadataSection of this.activeMetadataSectionsList)
if (metadataSection != undefined) {
metadataSectionsOrder.push({
'id': metadataSection.id,
'enabled': metadataSection.enabled,
'metadata_order': metadataSection.metadata_object_list.map((aMetadatum) => { return { 'id': aMetadatum.id, 'enabled': aMetadatum.enabled } })
});
}
this.isUpdatingMetadataSectionsOrder = true;
this.updateCollectionMetadataSectionsOrder({ collectionId: this.collectionId, metadataSectionsOrder: metadataSectionsOrder })
.then(() => this.isUpdatingMetadataSectionsOrder = false)
.catch(() => this.isUpdatingMetadataSectionsOrder = false);
},
onChangeEnable($event, index, sectionIndex) {
let metadataOrder = [];
for (let metadatum of this.activeMetadataSectionsList[sectionIndex].metadata_object_list)
if (metadatum != undefined)
metadataOrder.push({'id': metadatum.id, 'enabled': metadatum.enabled});
metadataOrder[index].enabled = $event;
this.isUpdatingMetadataOrder = true;
this.updateCollectionMetadataOrder({ collectionId: this.collectionId, metadataOrder: metadataOrder, metadataSectionId: this.activeMetadataSectionsList[sectionIndex].id })
.then(() => this.isUpdatingMetadataOrder = false)
.catch(() => this.isUpdatingMetadataOrder = false);
},
onChangeEnableSection($event, index) {
let metadataSectionsOrder = [];
for (let metadataSection of this.activeMetadataSectionsList)
if (metadataSection != undefined)
metadataSectionsOrder.push({
'id': metadataSection.id,
'enabled': metadataSection.enabled,
'metadata_order': metadataSection.metadata_object_list.map((aMetadatum) => { return { 'id': aMetadatum.id, 'enabled': aMetadatum.enabled } })
});
metadataSectionsOrder[index].enabled = $event;
this.isUpdatingMetadataSectionsOrder = true;
this.updateCollectionMetadataSectionsOrder({ collectionId: this.collectionId, metadataSectionsOrder: metadataSectionsOrder })
.then(() => this.isUpdatingMetadataSectionsOrder = false)
.catch(() => this.isUpdatingMetadataSectionsOrder = false);
},
addMetadatumViaButton(metadatumType) {
this.addNewMetadatum(metadatumType, this.activeMetadataSectionsList[0].metadata_object_list.length, 0);
// Higlights the clicked metadatum
this.hightlightedMetadatum = metadatumType.name;
this.$emit('onUpdatehightlightedMetadatum', this.hightlightedMetadatum);
},
addMetadataSectionViaButton() {
let lastIndex = this.activeMetadataSectionsList.length;
this.addNewMetadataSection(lastIndex);
},
addNewMetadatum(newMetadatum, newIndex, sectionIndex) {
this.isUpdatingMetadatum = true;
this.sendMetadatum({
collectionId: this.collectionId,
name: newMetadatum.name,
metadatumType: newMetadatum.className,
status: 'auto-draft',
isRepositoryLevel: false,
newIndex: newIndex,
parent: '0',
sectionId: this.activeMetadataSectionsList[sectionIndex].id
})
.then((metadatum) => {
this.updateMetadataOrder(sectionIndex);
this.toggleMetadatumEdition(metadatum)
this.hightlightedMetadatum = '';
this.isUpdatingMetadatum = false;
this.$emit('onUpdatehightlightedMetadatum', this.hightlightedMetadatum);
})
.catch((error) => {
this.isUpdatingMetadatum = false;
this.$console.error(error);
});
},
addNewMetadataSection(newIndex) {
this.isUpdatingMetadatum = true;
this.sendMetadataSection({
collectionId: this.collectionId,
name: this.$i18n.get('label_new_metadata_section'),
status: 'auto-draft',
newIndex: newIndex
})
.then((metadataSection) => {
this.updateMetadataSectionsOrder();
this.toggleMetadataSectionEdition(metadataSection);
this.isUpdatingMetadatum = false;
})
.catch((error) => {
this.$console.error(error);
this.isUpdatingMetadatum = false;
});
},
removeMetadatum(removedMetadatum, sectionIndex) {
this.$buefy.modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.$i18n.get('info_warning_metadatum_delete'),
onConfirm: () => {
this.isUpdatingMetadataOrder = true;
this.deleteMetadatum({
collectionId: this.collectionId,
metadatumId: removedMetadatum.id,
isRepositoryLevel: false
})
.then(() => {
this.updateMetadataOrder(sectionIndex);
})
.catch(() => {
this.isUpdatingMetadataOrder = false;
this.$console.log("Error deleting metadatum.")
});
}
},
trapFocus: true,
customClass: 'tainacan-modal',
closeButtonAriaLabel: this.$i18n.get('close')
});
},
removeMetadataSection(removedMetadataSection) {
this.$buefy.modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.$i18n.get('info_warning_metadata_section_delete'),
onConfirm: () => {
this.isUpdatingMetadataSectionsOrder = true;
this.deleteMetadataSection({ collectionId: this.collectionId, metadataSectionId: removedMetadataSection.id })
.then(() => {
this.updateMetadataSectionsOrder();
})
.catch(() => {
this.isUpdatingMetadataSectionsOrder = false;
this.$console.log("Error deleting metadata section.")
});
}
},
trapFocus: true,
customClass: 'tainacan-modal',
closeButtonAriaLabel: this.$i18n.get('close')
});
},
toggleMetadatumEdition(metadatum) {
this.$router.push({ query: { edit: metadatum.id } });
},
toggleMetadataSectionEdition(metadataSection) {
this.$router.push({ query: { sectionEdit: metadataSection.id } });
},
editMetadatum(metadatumId) {
this.openedMetadatumId = metadatumId;
},
editMetadataSection(metadataSectionId) {
this.openedMetadataSectionId = metadataSectionId;
},
onEditionFinished() {
this.openedMetadatumId = '';
this.$router.push({ query: {}});
},
onEditionCanceled() {
this.openedMetadatumId = '';
this.$router.push({ query: {}});
},
onSectionEditionFinished() {
this.openedMetadataSectionId = '';
this.$router.push({ query: {}});
},
onSectionEditionCanceled() {
this.openedMetadataSectionId = '';
this.$router.push({ query: {}});
},
moveMetadatumUpViaButton(index, sectionIndex) {
this.moveMetadatumUp({ index, sectionIndex });
this.updateMetadataOrder(sectionIndex);
},
moveMetadatumDownViaButton(index, sectionIndex) {
this.moveMetadatumDown({ index, sectionIndex });
this.updateMetadataOrder(sectionIndex);
},
moveMetadataSectionUpViaButon(sectionIndex) {
this.moveMetadataSectionUp(sectionIndex);
this.updateMetadataSectionsOrder();
},
moveMetadataSectionDownViaButton(sectionIndex) {
this.moveMetadataSectionDown(sectionIndex);
this.updateMetadataSectionsOrder();
},
filterByMetadatumName(metadatum) {
if (metadatum.metadata_type_object &&
metadatum.metadata_type_object.component == 'tainacan-compound' &&
metadatum.metadata_type_options &&
metadatum.metadata_type_options.children_objects &&
metadatum.metadata_type_options.children_objects.length
) {
let childNamesArray = metadatum.metadata_type_options.children_objects.map((children) => children.name);
childNamesArray.push(metadatum.name);
return childNamesArray.some((childName) => childName.toString().toLowerCase().indexOf(this.metadataNameFilterString.toString().toLowerCase()) >= 0);
}
else
return metadatum.name.toString().toLowerCase().indexOf(this.metadataNameFilterString.toString().toLowerCase()) >= 0;
},
filterByMetadatumType(metadatum) {
if (!this.hasSomeMetadataTypeFilterApplied)
return true;
if (metadatum.metadata_type_object &&
metadatum.metadata_type_object.component == 'tainacan-compound' &&
metadatum.metadata_type_options &&
metadatum.metadata_type_options.children_objects &&
metadatum.metadata_type_options.children_objects.length
) {
let childTypesArray = metadatum.metadata_type_options.children_objects.map((children) => children.metadata_type);
childTypesArray.push(metadatum.metadata_type);
for (let metadatumType of this.metadataTypeFilterOptions) {
if (metadatumType.enabled && childTypesArray.some((childType) => childType == metadatumType.type))
return true;
}
} else {
for (let metadatumType of this.metadataTypeFilterOptions) {
if (metadatumType.enabled && metadatum.metadata_type == metadatumType.type)
return true;
}
}
return false;
},
isCollapseOpen(metadatumId) {
return this.collapses[metadatumId] == true;
}
}
}
</script>

View File

@ -2,81 +2,80 @@
<div <div
style="min-height: initial; position: relative" style="min-height: initial; position: relative"
class="tainacan-cards-container"> class="tainacan-cards-container">
<template v-if="collections.length <= 0 && !isLoading && $userCaps.hasCapability('tnc_rep_edit_collections')"> <ul
<ul class="new-collection-menu"> v-if="collections.length <= 0 && !isLoading && $userCaps.hasCapability('tnc_rep_edit_collections')"
<li> class="new-collection-menu">
<router-link <li>
tag="a" <router-link
:to="$routerHelper.getNewCollectionPath()" tag="a"
class="first-card"> :to="$routerHelper.getNewCollectionPath()"
<div class="list-metadata"> class="first-card">
<span class="icon is-large"> <div class="list-metadata">
<i class="tainacan-icon tainacan-icon-36px tainacan-icon-addcollection"/> <span class="icon is-large">
</span> <i class="tainacan-icon tainacan-icon-36px tainacan-icon-addcollection"/>
<div>{{ $i18n.get('label_create_collection') }}</div> </span>
</div> <div>{{ $i18n.get('label_create_collection') }}</div>
</router-link> </div>
</li> </router-link>
<li> </li>
<router-link <li>
tag="a" <router-link
:to="{ path: $routerHelper.getNewCollectionPath() }" tag="a"
:aria-label="$i18n.get('label_collection_items')"> :to="{ path: $routerHelper.getNewCollectionPath() }"
<span :aria-label="$i18n.get('label_collection_items')">
v-tooltip="{ <span
content: $i18n.get('label_collection_items'), v-tooltip="{
autoHide: true, content: $i18n.get('label_collection_items'),
placement: 'auto' autoHide: true,
}" placement: 'auto',
class="icon is-medium"> popperClass: ['tainacan-tooltip', 'tooltip']
<i class="tainacan-icon tainacan-icon-36px tainacan-icon-items"/> }"
</span> class="icon is-medium">
<span class="menu-text">{{ $i18n.get('items') }}</span> <i class="tainacan-icon tainacan-icon-36px tainacan-icon-items"/>
</router-link> </span>
</li> <span class="menu-text">{{ $i18n.get('items') }}</span>
<li> </router-link>
<router-link </li>
tag="a" <li>
:to="{ path: $routerHelper.getNewCollectionPath() }" <router-link
:aria-label="$i18n.get('label_collection_metadata')"> tag="a"
<span :to="{ path: $routerHelper.getNewCollectionPath() }"
v-tooltip="{ :aria-label="$i18n.get('label_collection_metadata')">
content: $i18n.get('label_collection_metadata'), <span
autoHide: true, v-tooltip="{
placement: 'auto' content: $i18n.get('label_collection_metadata'),
}" autoHide: true,
class="icon is-medium"> placement: 'auto',
<i class="tainacan-icon tainacan-icon-36px tainacan-icon-metadata"/> popperClass: ['tainacan-tooltip', 'tooltip']
</span> }"
<span class="menu-text">{{ $i18n.getFrom('metadata', 'name') }}</span> class="icon is-medium">
</router-link> <i class="tainacan-icon tainacan-icon-36px tainacan-icon-metadata"/>
</li> </span>
<li> <span class="menu-text">{{ $i18n.getFrom('metadata', 'name') }}</span>
<router-link </router-link>
tag="a" </li>
:to="{ path: $routerHelper.getNewCollectionPath() }" <li>
:aria-label="$i18n.get('label_collection_filters')"> <router-link
<span tag="a"
v-tooltip="{ :to="{ path: $routerHelper.getNewCollectionPath() }"
content: $i18n.get('label_collection_filters'), :aria-label="$i18n.get('label_collection_filters')">
autoHide: true, <span
placement: 'auto' v-tooltip="{
}" content: $i18n.get('label_collection_filters'),
class="icon is-medium"> autoHide: true,
<i class="tainacan-icon tainacan-icon-36px tainacan-icon-filters"/> placement: 'auto',
</span> popperClass: ['tainacan-tooltip', 'tooltip']
<span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span> }"
</router-link> class="icon is-medium">
</li> <i class="tainacan-icon tainacan-icon-36px tainacan-icon-filters"/>
</ul> </span>
</template> <span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span>
<template v-if="collections.length > 0 && !isLoading"> </router-link>
<masonry </li>
:cols="{ default: 5, 1919: 4, 1407: 3, 1215: 2, 1023: 2, 767: 1 }" </ul>
:gutter="25" <ul v-if="collections.length > 0 && !isLoading">
style="width:100%;"> <li v-if="$userCaps.hasCapability('tnc_rep_edit_collections')">
<router-link <router-link
v-if="$userCaps.hasCapability('tnc_rep_edit_collections')"
tag="a" tag="a"
:to="$routerHelper.getNewCollectionPath()" :to="$routerHelper.getNewCollectionPath()"
class="tainacan-card new-card"> class="tainacan-card new-card">
@ -92,13 +91,15 @@
tag="a" tag="a"
:to="{ path: $routerHelper.getNewCollectionPath() }" :to="{ path: $routerHelper.getNewCollectionPath() }"
:aria-label="$i18n.get('label_collection_items')"> :aria-label="$i18n.get('label_collection_items')">
<b-tooltip <span
:label="$i18n.get('items')" v-tooltip.bottom="{
position="is-bottom"> content: $i18n.get('items'),
<span class="icon"> autoHide: true,
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-items"/> popperClass: ['tainacan-tooltip', 'tooltip']
</span> }"
</b-tooltip> class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-items"/>
</span>
<!-- <span class="menu-text">{{ $i18n.get('items') }}</span> --> <!-- <span class="menu-text">{{ $i18n.get('items') }}</span> -->
</router-link> </router-link>
</li> </li>
@ -107,13 +108,15 @@
tag="a" tag="a"
:to="{ path: $routerHelper.getNewCollectionPath() }" :to="{ path: $routerHelper.getNewCollectionPath() }"
:aria-label="$i18n.get('label_collection_metadata')"> :aria-label="$i18n.get('label_collection_metadata')">
<b-tooltip <span
:label="$i18n.getFrom('metadata', 'name')" v-tooltip.bottom="{
position="is-bottom"> content: $i18n.getFrom('metadata', 'name'),
<span class="icon"> autoHide: true,
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-metadata"/> popperClass: ['tainacan-tooltip', 'tooltip']
</span> }"
</b-tooltip> class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-metadata"/>
</span>
<!-- <span class="menu-text">{{ $i18n.getFrom('metadata', 'name') }}</span> --> <!-- <span class="menu-text">{{ $i18n.getFrom('metadata', 'name') }}</span> -->
</router-link> </router-link>
</li> </li>
@ -122,133 +125,163 @@
tag="a" tag="a"
:to="{ path: $routerHelper.getNewCollectionPath() }" :to="{ path: $routerHelper.getNewCollectionPath() }"
:aria-label="$i18n.get('label_collection_filters')"> :aria-label="$i18n.get('label_collection_filters')">
<b-tooltip <span
animated v-tooltip.bottom="{
:label="$i18n.getFrom('filters', 'name')" content: $i18n.getFrom('filters', 'name'),
position="is-bottom"> autoHide: true,
<span class="icon"> popperClass: ['tainacan-tooltip', 'tooltip']
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-filters"/> }"
</span> class="icon">
</b-tooltip> <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-filters"/>
</span>
<!-- <span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span> --> <!-- <span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span> -->
</router-link> </router-link>
</li> </li>
</ul> </ul>
</router-link> </router-link>
<div </li>
v-if="collections.length > 0 && !isLoading" <li
:key="index" v-if="collections.length > 0 && !isLoading"
v-for="(collection, index) of collections" :key="index"
class="tainacan-card"> v-for="(collection, index) of collections"
<ul class="menu-list"> class="tainacan-card"
<li> :class="{ 'always-visible-collections': $adminOptions.homeCollectionsPerPage }">
<router-link <ul class="menu-list">
tag="a" <li v-if="!$adminOptions.hideHomeCollectionItemsButton">
:to="{ path: $routerHelper.getCollectionItemsPath(collection.id, '') }" <router-link
:aria-label="$i18n.get('label_collection_items')"> tag="a"
<b-tooltip :to="{ path: $routerHelper.getCollectionItemsPath(collection.id, '') }"
:label="$i18n.get('items')" :aria-label="$i18n.get('label_collection_items')">
position="is-bottom"> <span
<span class="icon"> v-tooltip.bottom="{
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-items"/> content: $i18n.get('items'),
</span> autoHide: true,
</b-tooltip> popperClass: ['tainacan-tooltip', 'tooltip']
<!-- <span class="menu-text">{{ $i18n.get('items') }}</span> --> }"
</router-link> class="icon">
</li> <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-items"/>
<li v-if="collection.current_user_can_edit"> </span>
<router-link <!-- <span class="menu-text">{{ $i18n.get('items') }}</span> -->
tag="a" </router-link>
:to="{ path: $routerHelper.getCollectionEditPath(collection.id) }" </li>
:aria-label="$i18n.get('label_settings')"> <li v-if="collection.current_user_can_edit_items && $adminOptions.showHomeCollectionCreateItemButton">
<b-tooltip <router-link
:label="$i18n.get('label_settings')" tag="a"
position="is-bottom"> :to="{ path: $routerHelper.getNewItemPath(collection.id) }"
<span class="icon"> :aria-label="$i18n.get('add_one_item')">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-settings"/> <span
</span> v-tooltip.bottom="{
</b-tooltip> content: $i18n.get('add_one_item'),
<!-- <span class="menu-text">{{ $i18n.get('label_settings') }}</span> --> autoHide: true,
</router-link> popperClass: ['tainacan-tooltip', 'tooltip']
</li> }"
<li v-if="collection.current_user_can_edit_metadata"> class="icon">
<router-link <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-add"/>
tag="a" </span>
:to="{ path: $routerHelper.getCollectionMetadataPath(collection.id) }" <!-- <span class="menu-text">{{ $i18n.get('add_one_item') }}</span> -->
:aria-label="$i18n.get('label_collection_metadata')"> </router-link>
<b-tooltip </li>
:label="$i18n.getFrom('metadata', 'name')" <li v-if="collection.current_user_can_edit && !$adminOptions.hideHomeCollectionSettingsButton">
position="is-bottom"> <router-link
<span class="icon"> tag="a"
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-metadata"/> :to="{ path: $routerHelper.getCollectionEditPath(collection.id) }"
</span> :aria-label="$i18n.get('label_settings')">
</b-tooltip> <span
<!-- <span class="menu-text">{{ $i18n.getFrom('metadata', 'name') }}</span> --> v-tooltip.bottom="{
</router-link> content: $i18n.get('label_settings'),
</li> autoHide: true,
<li v-if="collection.current_user_can_edit_filters"> popperClass: ['tainacan-tooltip', 'tooltip']
<router-link }"
tag="a" class="icon">
:to="{ path: $routerHelper.getCollectionFiltersPath(collection.id) }" <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-settings"/>
:aria-label="$i18n.get('label_collection_filters')"> </span>
<b-tooltip <!-- <span class="menu-text">{{ $i18n.get('label_settings') }}</span> -->
animated </router-link>
:label="$i18n.getFrom('filters', 'name')" </li>
position="is-bottom"> <li v-if="collection.current_user_can_edit_metadata && !$adminOptions.hideHomeCollectionMetadataButton">
<span class="icon"> <router-link
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-filters"/> tag="a"
</span> :to="{ path: $routerHelper.getCollectionMetadataPath(collection.id) }"
</b-tooltip> :aria-label="$i18n.get('label_collection_metadata')">
<!-- <span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span> --> <span
</router-link> v-tooltip.bottom="{
</li> content: $i18n.getFrom('metadata', 'name'),
<li v-if="$userCaps.hasCapability('tnc_rep_read_logs')"> autoHide: true,
<router-link popperClass: ['tainacan-tooltip', 'tooltip']
tag="a" }"
:to="{ path: $routerHelper.getCollectionActivitiesPath(collection.id) }" class="icon">
:aria-label="$i18n.get('label_collection_activities')"> <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-metadata"/>
<b-tooltip </span>
:label="$i18n.get('activities')" <!-- <span class="menu-text">{{ $i18n.getFrom('metadata', 'name') }}</span> -->
position="is-bottom"> </router-link>
<span class="icon"> </li>
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-activities"/> <li v-if="collection.current_user_can_edit_filters && !$adminOptions.hideHomeCollectionFiltersButton">
</span> <router-link
</b-tooltip> tag="a"
<!-- <span class="menu-text">{{ $i18n.get('activities') }}</span> --> :to="{ path: $routerHelper.getCollectionFiltersPath(collection.id) }"
</router-link> :aria-label="$i18n.get('label_collection_filters')">
</li> <span
<li> v-tooltip.bottom="{
<a content: $i18n.getFrom('filters', 'name'),
:href="collection.url" autoHide: true,
target="_blank" popperClass: ['tainacan-tooltip', 'tooltip']
:aria-label="$i18n.get('label_view_collection_on_website')"> }"
<b-tooltip class="icon">
:label="$i18n.get('label_view_collection_on_website')" <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-filters"/>
position="is-bottom"> </span>
<span class="icon"> <!-- <span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span> -->
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-see"/> </router-link>
</span> </li>
</b-tooltip> <li v-if="$userCaps.hasCapability('tnc_rep_read_logs') && !$adminOptions.hideHomeCollectionActivitiesButton">
</a> <router-link
</li> tag="a"
</ul> :to="{ path: $routerHelper.getCollectionActivitiesPath(collection.id) }"
<router-link :aria-label="$i18n.get('label_collection_activities')">
tag="a" <span
:to="$routerHelper.getCollectionPath(collection.id)" v-tooltip.bottom="{
class="card-body"> content: $i18n.get('activities'),
<img autoHide: true,
:alt="$i18n.get('label_thumbnail')" popperClass: ['tainacan-tooltip', 'tooltip']
v-if="collection.thumbnail != undefined" }"
:src="$thumbHelper.getSrc(collection['thumbnail'], 'tainacan-medium')"> class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-activities"/>
<!-- Name --> </span>
<div class="metadata-title"> <!-- <span class="menu-text">{{ $i18n.get('activities') }}</span> -->
<p>{{ collection.name != undefined ? collection.name : '' }}</p> </router-link>
</div> </li>
</router-link> <li v-if="!$adminOptions.hideHomeCollectionThemeCollectionButton">
</div> <a
</masonry> :href="collection.url"
</template> target="_blank"
:aria-label="$i18n.get('label_view_collection_on_website')">
<span
v-tooltip.bottom="{
content: $i18n.get('label_view_collection_on_website'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-see"/>
</span>
</a>
</li>
</ul>
<router-link
tag="a"
:to="$routerHelper.getCollectionPath(collection.id)"
class="card-body">
<img
:alt="$i18n.get('label_thumbnail')"
v-if="collection.thumbnail != undefined"
:src="$thumbHelper.getSrc(collection['thumbnail'], 'tainacan-medium')">
<!-- Name -->
<div class="metadata-title">
<p>{{ collection.name != undefined ? collection.name : '' }}</p>
</div>
</router-link>
</li>
</ul>
</div> </div>
</template> </template>

View File

@ -155,7 +155,8 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('status_' + collection.status), content: $i18n.get('status_' + collection.status),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], html: true,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}"> }">
<i <i
@ -188,12 +189,13 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: collection.name, content: collection.name,
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], html: true,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}"> }">
{{ collection.name }}</p> {{ collection.name }}</p>
@ -208,12 +210,13 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: (collection.description != undefined && collection.description != '') ? collection.description : `<span class='has-text-gray is-italic'>` + $i18n.get('label_description_not_provided') + `</span>`, content: (collection.description != undefined && collection.description != '') ? collection.description : `<span class='has-text-gray is-italic'>` + $i18n.get('label_description_not_provided') + `</span>`,
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], html: true,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-html="(collection.description != undefined && collection.description != '') ? collection.description : `<span class='has-text-gray is-italic'>` + $i18n.get('label_description_not_provided') + `</span>`"/> v-html="(collection.description != undefined && collection.description != '') ? collection.description : `<span class='has-text-gray is-italic'>` + $i18n.get('label_description_not_provided') + `</span>`"/>
@ -228,12 +231,13 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: collection.modification_date, content: collection.modification_date,
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], html: true,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-html="collection.modification_date" /> v-html="collection.modification_date" />
@ -248,12 +252,13 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: collection.creation_date, content: collection.creation_date,
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], html: true,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-html="collection.creation_date" /> v-html="collection.creation_date" />
@ -268,12 +273,13 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: collection.author_name, content: collection.author_name,
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], html: true,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-html="collection.author_name" /> v-html="collection.author_name" />
@ -289,12 +295,13 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: getTotalItemsDetailed(collection.total_items), content: getTotalItemsDetailed(collection.total_items),
autoHide: false, autoHide: false,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], html: true,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-html="getTotalItems(collection.total_items)" /> v-html="getTotalItems(collection.total_items)" />
@ -316,7 +323,7 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('edit'), content: $i18n.get('edit'),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto', placement: 'auto',
html: true html: true
}" }"
@ -333,7 +340,7 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('delete'), content: $i18n.get('delete'),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto' placement: 'auto'
}" }"
class="icon"> class="icon">

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,14 @@
<template> <template>
<div> <div class="metadata-mappers-area">
<b-loading <b-loading
:can-cancel="false" :can-cancel="false"
:is-full-page="false"
:active.sync="isLoadingMetadatumMappers"/> :active.sync="isLoadingMetadatumMappers"/>
<b-loading
:can-cancel="false"
:is-full-page="false"
:active.sync="isLoadingMetadata"/>
<b-field> <b-field>
<p style="line-height: 2em;">{{ $i18n.get('info_metadata_mapper_helper') }}</p> <p style="line-height: 2em;">{{ $i18n.get('info_metadata_mapper_helper') }}</p>
<b-select <b-select
@ -100,7 +106,7 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('edit'), content: $i18n.get('edit'),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'repository-tooltip' : ''], popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''],
placement: 'auto-start' placement: 'auto-start'
}" }"
class="icon"> class="icon">
@ -117,7 +123,7 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('delete'), content: $i18n.get('delete'),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'repository-tooltip' : ''], popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''],
placement: 'auto-start' placement: 'auto-start'
}" }"
class="icon"> class="icon">
@ -129,7 +135,7 @@
<div <div
v-if="mapper != '' && !isLoadingMetadatumMappers" v-if="mapper != '' && !isLoadingMetadatumMappers"
class="field is-grouped form-submit"> class="field is-grouped form-submit fixed-form-submit">
<div class="control"> <div class="control">
<button <button
class="button is-outlined" class="button is-outlined"
@ -139,6 +145,7 @@
<div class="control"> <div class="control">
<button <button
@click.prevent="onUpdateMetadataMapperMetadataClick" @click.prevent="onUpdateMetadataMapperMetadataClick"
:class="{ 'is-loading': isMapperMetadataLoading }"
class="button is-success">{{ $i18n.get('save') }}</button> class="button is-success">{{ $i18n.get('save') }}</button>
</div> </div>
</div> </div>
@ -209,6 +216,7 @@ export default {
return { return {
collectionId: '', collectionId: '',
isLoadingMetadatumMappers: true, isLoadingMetadatumMappers: true,
isLoadingMetadata: false,
mapper: '', mapper: '',
mapperMetadata: [], mapperMetadata: [],
isMapperMetadataLoading: false, isMapperMetadataLoading: false,
@ -231,20 +239,36 @@ export default {
} }
}, },
mounted() { mounted() {
this.isLoadingMetadatumMappers = true;
this.fetchMetadatumMappers()
.then(() => {
this.isLoadingMetadatumMappers = false;
if (this.metadatumMappers.length == 1) /* If we're in a collection list, the metadata won't exist as they are read inside sections */
this.onSelectMetadataMapper(this.metadatumMappers[0]) if (!this.isRepositoryLevel) {
this.collectionId = this.$route.params.collectionId;
this.isLoadingMetadata = true;
this.cleanMetadata();
this.fetchMetadata({
collectionId: this.collectionId,
isRepositoryLevel: false,
isContextEdit: true,
includeDisabled: true,
includeOptionsAsHtml: false
}) })
.catch(() => { .then(() => {
this.isLoadingMetadatumMappers = false; this.loadMetadataMappers();
}); this.isLoadingMetadata = false;
})
.catch(() => {
this.isLoadingMetadata = false;
});
} else {
this.loadMetadataMappers();
}
}, },
methods: { methods: {
...mapActions('metadata', [ ...mapActions('metadata', [
'fetchMetadata',
'cleanMetadata',
'fetchMetadatumMappers', 'fetchMetadatumMappers',
'updateMetadataMapperMetadata', 'updateMetadataMapperMetadata',
]), ]),
@ -252,12 +276,25 @@ export default {
'getMetadatumMappers', 'getMetadatumMappers',
'getMetadata' 'getMetadata'
]), ]),
loadMetadataMappers() {
this.isLoadingMetadatumMappers = true;
this.fetchMetadatumMappers()
.then(() => {
this.isLoadingMetadatumMappers = false;
if (this.metadatumMappers.length >= 1)
this.onSelectMetadataMapper(this.metadatumMappers[0])
})
.catch(() => {
this.isLoadingMetadatumMappers = false;
});
},
onSelectMetadataMapper(metadatumMapper) { onSelectMetadataMapper(metadatumMapper) {
this.isMapperMetadataLoading = true; this.isMapperMetadataLoading = true;
this.mapper = metadatumMapper; //TODO try to use v-model again this.mapper = metadatumMapper; //TODO try to use v-model again
this.mapperMetadata = []; this.mapperMetadata = [];
if (metadatumMapper != '') { if (metadatumMapper != '') {
for (var k in metadatumMapper.metadata) { for (var k in metadatumMapper.metadata) {
var item = metadatumMapper.metadata[k]; var item = metadatumMapper.metadata[k];
@ -265,9 +302,9 @@ export default {
item.selected = ''; item.selected = '';
item.isCustom = false; item.isCustom = false;
this.activeMetadatumList.forEach((metadatum) => { this.activeMetadatumList.forEach((metadatum) => {
if( if (
metadatum.exposer_mapping.hasOwnProperty(metadatumMapper.slug) && Object.prototype.hasOwnProperty.call(metadatum.exposer_mapping, metadatumMapper.slug) &&
metadatum.exposer_mapping[metadatumMapper.slug] == item.slug metadatum.exposer_mapping[metadatumMapper.slug] == item.slug
) { ) {
item.selected = metadatum.id; item.selected = metadatum.id;
this.mappedMetadata.push(metadatum.id); this.mappedMetadata.push(metadatum.id);
@ -276,9 +313,9 @@ export default {
this.mapperMetadata.push(item); this.mapperMetadata.push(item);
} }
this.activeMetadatumList.forEach((metadatum) => { this.activeMetadatumList.forEach((metadatum) => {
if( if (
metadatum.exposer_mapping.hasOwnProperty(metadatumMapper.slug) && Object.prototype.hasOwnProperty.call(metadatum.exposer_mapping, metadatumMapper.slug) &&
typeof metadatum.exposer_mapping[metadatumMapper.slug] == 'object' typeof metadatum.exposer_mapping[metadatumMapper.slug] == 'object'
) { ) {
this.newMapperMetadataList.push(Object.assign({},metadatum.exposer_mapping[metadatumMapper.slug])); this.newMapperMetadataList.push(Object.assign({},metadatum.exposer_mapping[metadatumMapper.slug]));
this.mappedMetadata.push(metadatum.id); this.mappedMetadata.push(metadatum.id);
@ -442,6 +479,10 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.metadata-mappers-area {
padding: 0 1em;
}
.tainacan-form { .tainacan-form {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -546,7 +587,7 @@ export default {
} }
} }
.form-submit { .fixed-form-submit {
margin-top: 24px; margin-top: 24px;
position: sticky !important; position: sticky !important;
bottom: 0; bottom: 0;

View File

@ -0,0 +1,410 @@
<template>
<div
v-if="(isRepositoryLevel && $userCaps.hasCapability('tnc_rep_edit_metadata')) || !isRepositoryLevel"
class="column available-metadata-types-area" >
<b-loading :active.sync="isLoadingMetadataTypes"/>
<div class="field">
<h3 class="label">{{ $i18n.get('label_available_metadata_types') }}</h3>
<draggable
v-model="availableMetadatumList"
:sort="false"
:group="{ name:'metadata', pull: 'clone', put: false, revertClone: true }"
drag-class="sortable-drag">
<div
:id="metadatum.component"
@click.prevent="addMetadatumViaButton(metadatum)"
class="available-metadatum-item"
:class="{ 'hightlighted-metadatum' : hightlightedMetadatum == metadatum.name, 'inherited-metadatum': metadatum.inherited || isRepositoryLevel }"
v-for="(metadatum, index) in availableMetadatumList"
:key="index">
<span
v-tooltip="{
content: $i18n.get('instruction_click_or_drag_metadatum_create'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''],
placement: 'auto-start'
}"
class="icon grip-icon">
<!-- <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-drag"/> -->
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="currentColor">
<path
d="M0 0h24v24H0V0z"
fill="transparent"/>
<path d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
</svg>
</span>
<span class="metadatum-name">
{{ metadatum.name }}
<span
v-tooltip="{
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '', 'metadata-type-preview-tooltip'],
content: getPreviewTemplateContent(metadatum),
html: true,
delay: {
shown: 0,
hide: 100,
},
placement: 'top',
}"
class="icon preview-help-icon has-text-secondary">
<i class="tainacan-icon tainacan-icon-help"/>
</span>
</span>
<span
class="loading-spinner"
v-if="hightlightedMetadatum == metadatum.name"/>
</div>
</draggable>
<draggable
v-if="!isRepositoryLevel"
v-model="availableMetadataSectionsList"
:sort="false"
:group="{ name:'metadata-sections', pull: 'clone', put: false, revertClone: true }"
drag-class="sortable-drag">
<div
:id="metadataSection.id"
@click.prevent="addMetadataSectionViaButton()"
class="available-metadata-section-item"
v-for="(metadataSection, index) in availableMetadataSectionsList"
:key="index">
<span
v-tooltip="{
content: $i18n.get('instruction_click_or_drag_metadatum_create'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''],
placement: 'auto-start'
}"
class="icon grip-icon">
<!-- <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-drag"/> -->
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 0 24 24"
width="24px"
fill="currentColor">
<path
d="M0 0h24v24H0V0z"
fill="transparent"/>
<path d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
</svg>
</span>
<span class="metadatum-name">
{{ metadataSection.label }}
<span
v-tooltip="{
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '', 'metadata-type-preview-tooltip'],
content: $i18n.get('info_create_section'),
html: true,
delay: {
shown: 0,
hide: 100,
},
placement: 'top',
}"
class="icon preview-help-icon has-text-secondary">
<i class="tainacan-icon tainacan-icon-help"/>
</span>
</span>
</div>
</draggable>
</div>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
name: 'MetadataTypesList',
props: {
isRepositoryLevel: Boolean,
hightlightedMetadatum: String
},
data() {
return {
isLoadingMetadataTypes: true,
availableMetadataSectionsList: [{
label: this.$i18n.get('label_add_new_section'),
name: this.$i18n.get('label_new_metadata_section'),
id: 'metadataSectionCreator'
}],
}
},
computed: {
availableMetadatumList: {
get() {
return this.getMetadatumTypes();
},
set(value) {
return this.updateMetadatumTypes(value);
}
},
},
mounted() {
this.isLoadingMetadataTypes = true;
this.fetchMetadatumTypes()
.then(() => {
this.$emit('onFinishedLoadingMetadataTypes');
this.isLoadingMetadataTypes = false;
})
.catch(() => {
this.isLoadingMetadataTypes = false;
});
},
methods: {
...mapActions('metadata', [
'fetchMetadatumTypes'
]),
...mapGetters('metadata',[
'getMetadatumTypes'
]),
addMetadatumViaButton(metadatumType) {
this.$eventBusMetadataList.onAddMetadatumViaButton(metadatumType);
},
addMetadataSectionViaButton() {
this.$eventBusMetadataList.onAddMetadataSectionViaButton();
},
getPreviewTemplateContent(metadatum) {
return `<div class="metadata-type-preview tainacan-form">
<span class="metadata-type-label">` + this.$i18n.get('label_metadatum_type_preview') + `</span>
<div class="field">
<span class="collapse-handle">
<span class="icon">
<i class="has-text-secondary tainacan-icon tainacan-icon-1-25em tainacan-icon-arrowdown"></i>
</span>
<label class="label has-tooltip">`
+ metadatum.name +
`</label>
</span>
<div>` + metadatum.preview_template + `</div>
</div>
</div>`;
},
}
}
</script>
<style lang="scss">
.available-metadata-types-area {
padding: 10px 0px 10px 10px !important;
margin: 0;
max-width: 380px;
min-width: 20.8333333%;
max-height: calc(100vh - 7.75em);
top: -28px;
position: sticky;
font-size: 0.875em;
@media screen and (max-width: 769px) {
max-width: 100%;
padding: 10px;
h3 {
margin: 1em 0em 1em 0em !important;
}
.available-metadatum-item::before,
.available-metadatum-item::after,
.available-metadata-section-item::before,
.available-metadata-section-item::after {
display: none !important;
}
}
h3 {
margin: 0.875em 0em 1em 0em;
}
.available-metadatum-item,
.available-metadata-section-item {
padding: 0.6em;
margin: 4px 4px 4px 1.2em;
background-color: var(--tainacan-white);
cursor: pointer;
left: 0;
height: 2.8571em;
position: relative;
border: 1px solid var(--tainacan-gray2);
border-radius: 1px;
transition: left 0.2s ease;
.grip-icon {
color: var(--tainacan-gray3);
position: relative;
}
.icon {
position: relative;
bottom: 1px;
}
.preview-help-icon {
position: absolute;
top: 6px;
}
.metadatum-name {
text-overflow: ellipsis;
overflow-x: hidden;
white-space: nowrap;
font-weight: bold;
margin-left: 0.4em;
display: inline-block;
max-width: 180px;
width: 60%;
}
&::after,
&::before {
content: '';
display: block;
position: absolute;
right: 100%;
width: 0;
height: 0;
border-style: solid;
}
&::after {
top: -1px;
border-color: transparent white transparent transparent;
border-right-width: 16px;
border-top-width: 1.4286em;
border-bottom-width: 1.4286em;
left: -19px;
}
&::before {
top: -1px;
border-color: transparent var(--tainacan-gray2) transparent transparent;
border-right-width: 16px;
border-top-width: 1.4286em;
border-bottom-width: 1.4286em;
left: -20px;
}
}
.available-metadata-section-item {
margin-top: 2em;
color: var(--tainacan-secondary);
border-color: var(--tainacan-secondary);
&::before {
border-color: transparent var(--tainacan-secondary) transparent transparent;
}
}
.sortable-drag {
opacity: 1 !important;
}
.sortable-chosen {
.metadata-type-preview {
display: none;
}
}
@keyframes hightlighten {
0% {
color: #222;
background-color: var(--tainacan-white);
border-color: var(--tainacan-white);
}
25% {
color: var(--tainacan-white);
background-color: var(--tainacan-secondary);
border-color: var(--tainacan-secondary);
}
75% {
color: var(--tainacan-white);
background-color: var(--tainacan-secondary);
border-color: var(--tainacan-secondary);
}
100% {
color: #222;
background-color: var(--tainacan-white);
border-color: var(--tainacan-white);
}
}
@keyframes hightlighten-icon {
0% { color: var(--tainacan-gray3); }
25% { color: var(--tainacan-white); }
75% { color: var(--tainacan-white); }
100% { color: var(--tainacan-gray3); }
}
@keyframes hightlighten-arrow {
0% {
border-color: transparent white transparent transparent;
border-color: transparent white transparent transparent;
}
25% {
border-color: transparent var(--tainacan-secondary) transparent transparent;
border-color: transparent var(--tainacan-secondary) transparent transparent;
}
75% {
border-color: transparent var(--tainacan-secondary) transparent transparent;
border-color: transparent var(--tainacan-secondary)transparent transparent;
}
100% {
border-color: transparent white transparent transparent;
border-color: transparent white transparent transparent;
}
}
.hightlighted-metadatum {
background-color: var(--tainacan-white);
position: relative;
left: 0px;
animation-name: hightlighten;
animation-duration: 1.0s;
animation-iteration-count: 2;
.grip-icon{
animation-name: hightlighten-icon;
animation-duration: 1.0s;
animation-iteration-count: 2;
}
&::before,
&::after {
animation-name: hightlighten-arrow;
animation-duration: 1.0s;
animation-iteration-count: 2;
}
}
.available-metadatum-item:hover,
.available-metadata-section-item:hover {
background-color: var(--tainacan-turquoise1);
border-color: var(--tainacan-turquoise2);
position: relative;
left: -4px;
&:after {
border-color: transparent var(--tainacan-turquoise1) transparent transparent;
}
&:before {
border-color: transparent var(--tainacan-turquoise2) transparent transparent;
}
.grip-icon {
color: var(--tainacan-secondary);
}
}
}
.inherited-metadatum {
&.available-metadatum-item:hover,
&.available-metadata-section-item:hover {
background-color: var(--tainacan-blue1) !important;
border-color: var(--tainacan-blue2) !important;
.grip-icon {
color: var(--tainacan-blue5) !important;
}
&:after {
border-color: transparent var(--tainacan-blue1) transparent transparent !important;
}
&:before {
border-color: transparent var(--tainacan-blue2) transparent transparent !important;
}
}
}
</style>

View File

@ -74,11 +74,12 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: bgProcess.name ? bgProcess.name : $i18n.get('label_unnamed_process'), content: bgProcess.name ? bgProcess.name : $i18n.get('label_unnamed_process'),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}"> }">
{{ bgProcess.name ? bgProcess.name : $i18n.get('label_unnamed_process') }}</p> {{ bgProcess.name ? bgProcess.name : $i18n.get('label_unnamed_process') }}</p>
@ -91,11 +92,12 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: bgProcess.progress_label ? bgProcess.progress_label : $i18n.get('label_no_details_of_process'), content: bgProcess.progress_label ? bgProcess.progress_label : $i18n.get('label_no_details_of_process'),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}"> }">
<span :class="{'occluding-content': bgProcess.progress_value }"><span class="has-text-weight-bold">{{ $i18n.get('label_progress') + " " }}</span>{{ bgProcess.progress_label ? bgProcess.progress_label : $i18n.get('label_no_details_of_process') }}</span> <span :class="{'occluding-content': bgProcess.progress_value }"><span class="has-text-weight-bold">{{ $i18n.get('label_progress') + " " }}</span>{{ bgProcess.progress_label ? bgProcess.progress_label : $i18n.get('label_no_details_of_process') }}</span>
@ -110,11 +112,12 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: getDate(bgProcess.queued_on), content: getDate(bgProcess.queued_on),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}"> }">
<span class="has-text-weight-bold">{{ $i18n.get('label_queued_on') + " " }}</span>{{ getDate(bgProcess.queued_on) }}</p> <span class="has-text-weight-bold">{{ $i18n.get('label_queued_on') + " " }}</span>{{ getDate(bgProcess.queued_on) }}</p>
@ -133,11 +136,12 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_stop_process'), content: $i18n.get('label_stop_process'),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-if=" bgProcess.status === 'running' " v-if=" bgProcess.status === 'running' "
@ -148,11 +152,12 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_completed'), content: $i18n.get('label_process_completed'),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-if=" ( bgProcess.status === 'finished' && !bgProcess.error_log ) || bgProcess.status === null" v-if=" ( bgProcess.status === 'finished' && !bgProcess.error_log ) || bgProcess.status === null"
@ -162,11 +167,12 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_completed_with_errors'), content: $i18n.get('label_process_completed_with_errors'),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-if=" bgProcess.status === 'finished-errors' || ( bgProcess.done > 0 && bgProcess.error_log && bgProcess.status === 'finished' ) " v-if=" bgProcess.status === 'finished-errors' || ( bgProcess.done > 0 && bgProcess.error_log && bgProcess.status === 'finished' ) "
@ -176,11 +182,12 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_cancelled'), content: $i18n.get('label_process_cancelled'),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-if=" bgProcess.status === 'cancelled' " v-if=" bgProcess.status === 'cancelled' "
@ -190,11 +197,12 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_paused'), content: $i18n.get('label_process_paused'),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-if=" bgProcess.status === 'paused' " v-if=" bgProcess.status === 'paused' "
@ -204,11 +212,12 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_waiting'), content: $i18n.get('label_process_waiting'),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-if=" bgProcess.status === 'waiting' " v-if=" bgProcess.status === 'waiting' "
@ -218,11 +227,12 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_delete_process'), content: $i18n.get('label_delete_process'),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-if=" bgProcess.status === 'waiting' " v-if=" bgProcess.status === 'waiting' "
@ -233,11 +243,12 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_failed'), content: $i18n.get('label_process_failed'),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}" }"
v-if="bgProcess.status === 'errored'" v-if="bgProcess.status === 'errored'"
@ -296,11 +307,12 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
show: 500, shown: 500,
hide: 300, hide: 300,
}, },
content: getDate(bgProcess.processed_last), content: getDate(bgProcess.processed_last),
autoHide: false, classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], autoHide: false,
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'auto-start' placement: 'auto-start'
}"> }">
<span class="has-text-weight-bold">{{ $i18n.get('label_last_processed_on') + " " }}</span>{{ getDate(bgProcess.processed_last) }}</p> <span class="has-text-weight-bold">{{ $i18n.get('label_last_processed_on') + " " }}</span>{{ getDate(bgProcess.processed_last) }}</p>

View File

@ -19,7 +19,7 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('label_show_children_terms'), content: $i18n.get('label_show_children_terms'),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'bottom' placement: 'bottom'
}" }"
class="children-dropdown icon"> class="children-dropdown icon">
@ -58,7 +58,7 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('label_new_child'), content: $i18n.get('label_new_child'),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'bottom' placement: 'bottom'
}" }"
class="icon"> class="icon">
@ -71,7 +71,7 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('edit'), content: $i18n.get('edit'),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'bottom' placement: 'bottom'
}" }"
class="icon"> class="icon">
@ -83,7 +83,7 @@
v-tooltip="{ v-tooltip="{
content: $i18n.get('delete'), content: $i18n.get('delete'),
autoHide: true, autoHide: true,
classes: ['tainacan-tooltip', 'tooltip', 'repository-tooltip'], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-repository-tooltip'],
placement: 'bottom' placement: 'bottom'
}" }"
class="icon"> class="icon">
@ -113,7 +113,8 @@
:index="childIndex" :index="childIndex"
:taxonomy-id="taxonomyId" :taxonomy-id="taxonomyId"
:order="order" :order="order"
:current-user-can-edit-taxonomy="currentUserCanEditTaxonomy"/> :current-user-can-edit-taxonomy="currentUserCanEditTaxonomy"
@onUpdateTermOpenedState="(state) => childTerm.opened = state"/>
</div> </div>
</transition-group> </transition-group>
<a <a
@ -128,14 +129,10 @@
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import RecursiveTermItem from './recursive-term-item.vue';
import CustomDialog from '../other/custom-dialog.vue'; import CustomDialog from '../other/custom-dialog.vue';
export default { export default {
name: 'RecursiveTermItem', name: 'RecursiveTermItem',
components: {
RecursiveTermItem,
},
props: { props: {
term: Object, term: Object,
index: Number, index: Number,
@ -217,7 +214,7 @@ export default {
}, },
editTerm() { editTerm() {
this.term.opened = !this.term.opened; this.$emit('onUpdateTermOpenedState', !this.term.opened);
this.$eventBusTermsList.onEditTerm(this.term); this.$eventBusTermsList.onEditTerm(this.term);
@ -316,11 +313,11 @@ export default {
} }
this.isEditingTerm = false; this.isEditingTerm = false;
this.term.opened = false; this.$emit('onUpdateTermOpenedState', false);
}, },
eventOnTermEditionCanceled() { eventOnTermEditionCanceled() {
this.isEditingTerm = false; this.isEditingTerm = false;
this.term.opened = false; this.$emit('onUpdateTermOpenedState', false);
} }
} }
} }

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