Merge pull request #577 from tainacan/feature/358
Related Items - Feature/358
This commit is contained in:
commit
4d2e1e3674
|
@ -40,7 +40,9 @@ sass -E 'UTF-8' --cache-location .tmp/sass-cache-15 src/views/gutenberg-blocks/t
|
|||
|
||||
sass -E 'UTF-8' --cache-location .tmp/sass-cache-16 src/views/gutenberg-blocks/tainacan-items/item-submission-form/item-submission-form.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/gutenberg-blocks-style.scss:src/assets/css/tainacan-gutenberg-block-common-styles.css
|
||||
sass -E 'UTF-8' --cache-location .tmp/sass-cache-17 src/views/gutenberg-blocks/tainacan-items/carousel-related-items/carousel-related-items.scss:src/assets/css/tainacan-gutenberg-block-carousel-related-items.css
|
||||
|
||||
sass -E 'UTF-8' --cache-location .tmp/sass-cache-18 src/views/gutenberg-blocks/gutenberg-blocks-style.scss:src/assets/css/tainacan-gutenberg-block-common-styles.css
|
||||
|
||||
echo "Compilação do Sass Concluído!"
|
||||
exit 0
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
color: var(--tainacan-block-gray5, #454647);
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
padding: 8px 16px;
|
||||
padding: 8px 12px;
|
||||
display: block;
|
||||
line-height: 1.2em;
|
||||
word-break: break-word; }
|
||||
|
|
|
@ -129,7 +129,7 @@
|
|||
color: var(--tainacan-block-gray5, #454647);
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
padding: 8px 16px;
|
||||
padding: 8px 12px;
|
||||
display: block;
|
||||
line-height: 1.2em;
|
||||
word-break: break-word; }
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
.wp-block-tainacan-carousel-related-items {
|
||||
margin: 0.5em auto;
|
||||
width: 100%; }
|
||||
.wp-block-tainacan-carousel-related-items .spinner-container {
|
||||
min-height: 56px;
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: var(--tainacan-block-gray4, #555758); }
|
||||
@-webkit-keyframes skeleton-animation {
|
||||
0% {
|
||||
opacity: 1.0; }
|
||||
50% {
|
||||
opacity: 0.2; }
|
||||
100% {
|
||||
opacity: 1.0; } }
|
||||
@-moz-keyframes skeleton-animation {
|
||||
0% {
|
||||
opacity: 1.0; }
|
||||
50% {
|
||||
opacity: 0.2; }
|
||||
100% {
|
||||
opacity: 1.0; } }
|
||||
@-o-keyframes skeleton-animation {
|
||||
0% {
|
||||
opacity: 1.0; }
|
||||
50% {
|
||||
opacity: 0.2; }
|
||||
100% {
|
||||
opacity: 1.0; } }
|
||||
@keyframes skeleton-animation {
|
||||
0% {
|
||||
opacity: 1.0; }
|
||||
50% {
|
||||
opacity: 0.2; }
|
||||
100% {
|
||||
opacity: 1.0; } }
|
||||
.wp-block-tainacan-carousel-related-items .skeleton {
|
||||
border-radius: 2px;
|
||||
background: var(--tainacan-block-gray1, #f2f2f2);
|
||||
-webkit-animation: skeleton-animation 1.8s ease infinite;
|
||||
-moz-animation: skeleton-animation 1.8s ease infinite;
|
||||
-o-animation: skeleton-animation 1.8s ease infinite;
|
||||
animation: skeleton-animation 1.8s ease infinite; }
|
||||
.wp-block-tainacan-carousel-related-items .carousel-related-items-edit-container {
|
||||
position: relative; }
|
||||
.wp-block-tainacan-carousel-related-items .carousel-related-items-edit-container .skeleton {
|
||||
min-height: 150px; }
|
||||
|
||||
/*# sourceMappingURL=tainacan-gutenberg-block-carousel-related-items.css.map */
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"version": 3,
|
||||
"mappings": "AAEA,yCAA0C;EACtC,MAAM,EAAE,UAAU;EAClB,KAAK,EAAE,IAAI;EAGX,4DAAmB;IACf,UAAU,EAAE,IAAI;IAChB,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,IAAI;IACb,eAAe,EAAE,MAAM;IACvB,WAAW,EAAE,MAAM;IACnB,KAAK,EAAE,oCAAmC;AAI9C,qCAIC;EAHG,EAAE;IAAC,OAAO,EAAE,GAAG;EACf,GAAG;IAAC,OAAO,EAAE,GAAG;EAChB,IAAI;IAAC,OAAO,EAAE,GAAG;AAErB,kCAIC;EAHG,EAAE;IAAC,OAAO,EAAE,GAAG;EACf,GAAG;IAAC,OAAO,EAAE,GAAG;EAChB,IAAI;IAAC,OAAO,EAAE,GAAG;AAErB,gCAIC;EAHG,EAAE;IAAC,OAAO,EAAE,GAAG;EACf,GAAG;IAAC,OAAO,EAAE,GAAG;EAChB,IAAI;IAAC,OAAO,EAAE,GAAG;AAErB,6BAIC;EAHG,EAAE;IAAC,OAAO,EAAE,GAAG;EACf,GAAG;IAAC,OAAO,EAAE,GAAG;EAChB,IAAI;IAAC,OAAO,EAAE,GAAG;EAErB,mDAAU;IACN,aAAa,EAAE,GAAG;IAClB,UAAU,EAAE,oCAAmC;IAE/C,iBAAiB,EAAE,qCAAqC;IACxD,cAAc,EAAE,qCAAqC;IACrD,YAAY,EAAE,qCAAqC;IACnD,SAAS,EAAE,qCAAqC;EAIpD,gFAAuC;IACnC,QAAQ,EAAE,QAAQ;IAElB,0FAAY;MACR,UAAU,EAAE,KAAK",
|
||||
"sources": ["../../views/gutenberg-blocks/tainacan-items/carousel-related-items/carousel-related-items.scss"],
|
||||
"names": [],
|
||||
"file": "tainacan-gutenberg-block-carousel-related-items.css"
|
||||
}
|
|
@ -122,7 +122,7 @@
|
|||
color: var(--tainacan-block-gray5, #454647);
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
padding: 8px 16px;
|
||||
padding: 8px 12px;
|
||||
display: block;
|
||||
line-height: 1.2em;
|
||||
word-break: break-word; }
|
||||
|
|
|
@ -189,6 +189,24 @@ class REST_Items_Controller extends REST_Controller {
|
|||
return $item_array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Tainacan\Entities\Item $item|int
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_context_edit($item) {
|
||||
if(is_numeric($item))
|
||||
$item = new Entities\Item($item);
|
||||
|
||||
return array(
|
||||
'current_user_can_edit' => $item->can_edit(),
|
||||
'current_user_can_delete' => $item->can_delete(),
|
||||
'nonces' => array(
|
||||
'update-post_' . $item->get_id() => wp_create_nonce('update-post_' . $item->get_id())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $item
|
||||
* @param \WP_REST_Request $request
|
||||
|
@ -256,6 +274,12 @@ class REST_Items_Controller extends REST_Controller {
|
|||
$attributes_to_filter .= ',id,collection_id';
|
||||
}
|
||||
|
||||
if ( $request['context'] === 'edit' ) {
|
||||
add_filter( 'taiancan_add_related_item', function( $related_item ) {
|
||||
return array_merge($related_item, $this->get_context_edit($related_item['id']));
|
||||
}, 10, 2 );
|
||||
}
|
||||
|
||||
$item_arr = $this->filter_object_by_attributes($item, $attributes_to_filter);
|
||||
|
||||
$item_arr = array_merge($extra_metadata_values, $item_arr);
|
||||
|
@ -274,11 +298,7 @@ class REST_Items_Controller extends REST_Controller {
|
|||
}
|
||||
|
||||
if ( $request['context'] === 'edit' ) {
|
||||
$item_arr['current_user_can_edit'] = $item->can_edit();
|
||||
$item_arr['current_user_can_delete'] = $item->can_delete();
|
||||
$item_arr['nonces'] = array(
|
||||
'update-post_' . $item->get_id() => wp_create_nonce('update-post_' . $item->get_id())
|
||||
);
|
||||
$item_arr = array_merge($item_arr, $this->get_context_edit($item));
|
||||
}
|
||||
if( isset($item_arr['thumbnail']) ) {
|
||||
$item_arr['thumbnail_alt'] = get_post_meta( $item->get__thumbnail_id(), '_wp_attachment_image_alt', true );
|
||||
|
|
|
@ -816,4 +816,15 @@ class Item extends Entity {
|
|||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return related items withs the item
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_related_items($args = []) {
|
||||
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
|
||||
$related_items = $Tainacan_Items->fetch_related_items($this, $args);
|
||||
return $related_items;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -523,7 +523,6 @@ class Test_Importer extends Importer {
|
|||
'type' => 'Tainacan\Metadata_Types\Relationship',
|
||||
'options' => [
|
||||
'collection_id' => $col2->get_id(),
|
||||
'repeated' => 'yes',
|
||||
'search' => $col2_core_title->get_id()
|
||||
]
|
||||
], $col1 );
|
||||
|
|
|
@ -116,7 +116,7 @@ class Items extends Repository {
|
|||
'description' => __( 'Item comment status: "open" means comments are allowed, "closed" means comments are not allowed.', 'tainacan' ),
|
||||
'default' => get_default_comment_status(Entities\Collection::get_post_type()),
|
||||
'validation' => v::optional(v::stringType()->in( [ 'open', 'closed' ] )),
|
||||
]
|
||||
],
|
||||
] );
|
||||
}
|
||||
|
||||
|
@ -573,5 +573,95 @@ class Items extends Repository {
|
|||
return $caps;
|
||||
}
|
||||
|
||||
private function get_related_items_by_collection($item, $collection, $metadata, $args=[]) {
|
||||
$Tainacan_Metadata = \Tainacan\Repositories\Metadata::get_instance();
|
||||
if (!$collection instanceof \Tainacan\Entities\Collection || !$metadata instanceof \Tainacan\Entities\Metadatum || !$Tainacan_Metadata->metadata_is_enabled($collection, $metadata))
|
||||
return false;
|
||||
|
||||
$prepared_items = array();
|
||||
$items = $this->fetch(array_merge([
|
||||
'meta_query' => [
|
||||
[
|
||||
'key' => $metadata->get_id(),
|
||||
'value' => $item->get_id()
|
||||
]
|
||||
]
|
||||
], $args), $collection->get_id(), 'WP_Query');
|
||||
|
||||
if ($items->have_posts()) {
|
||||
while ( $items->have_posts() ) {
|
||||
$items->the_post();
|
||||
$item_related = new \Tainacan\Entities\Item($items->post);
|
||||
$item_arr = $item_related->_toArray();
|
||||
$item_arr['thumbnail'] = $item_related->get_thumbnail();
|
||||
array_push($prepared_items, apply_filters( 'taiancan_add_related_item', $item_arr ) );
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
return array(
|
||||
"found_posts" => $items->found_posts,
|
||||
'items' => $prepared_items
|
||||
);
|
||||
}
|
||||
|
||||
public function fetch_related_items($item, $args=[]) {
|
||||
$Tainacan_Metadata = \Tainacan\Repositories\Metadata::get_instance();
|
||||
$Tainacan_Collections = \Tainacan\Repositories\Collections::get_instance();
|
||||
$current_collection = $item->get_collection();
|
||||
$metadatas = $Tainacan_Metadata->fetch([
|
||||
'meta_query' => [
|
||||
[
|
||||
'key' => 'metadata_type',
|
||||
'value' => 'Tainacan\Metadata_Types\Relationship'
|
||||
],
|
||||
[
|
||||
'key' => '_option_collection_id',
|
||||
'value' => $current_collection->get_id()
|
||||
],
|
||||
[
|
||||
'key' => '_option_display_in_related_items',
|
||||
'value' => 'yes'
|
||||
]
|
||||
]
|
||||
], 'OBJECT');
|
||||
|
||||
$response = array();
|
||||
foreach($metadatas as $metadata) {
|
||||
if($metadata->get_collection_id() == $Tainacan_Metadata->get_default_metadata_attribute()) {
|
||||
$collections = $Tainacan_Collections->fetch([], 'OBJECT');
|
||||
foreach($collections as $collection) {
|
||||
$related_items = $this->get_related_items_by_collection($item, $collection, $metadata, $args);
|
||||
if($related_items == false) continue;
|
||||
$response[$metadata->get_id() . '_' . $collection->get_id()] = array(
|
||||
'collection_id' => $collection->get_id(),
|
||||
'collection_name' => $collection->get_name(),
|
||||
'collection_url' => $collection->get_url(),
|
||||
'collection_slug' => $collection->get_slug(),
|
||||
'metadata_id' => $metadata->get_id(),
|
||||
'metadata_name' => $metadata->get_name(),
|
||||
'total_items' => $related_items['found_posts'],
|
||||
'items' => $related_items['items']
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$collection = $metadata->get_collection();
|
||||
$related_items = $this->get_related_items_by_collection($item, $collection, $metadata, $args);
|
||||
if($related_items == false) continue;
|
||||
$response[$metadata->get_id()] = array(
|
||||
'collection_id' => $collection->get_id(),
|
||||
'collection_name' => $collection->get_name(),
|
||||
'collection_url' => $collection->get_url(),
|
||||
'collection_slug' => $collection->get_slug(),
|
||||
'metadata_id' => $metadata->get_id(),
|
||||
'metadata_name' => $metadata->get_name(),
|
||||
'total_items' => $related_items['found_posts'],
|
||||
'items' => $related_items['items']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ class Metadata extends Repository {
|
|||
'map' => 'post_content',
|
||||
'title' => __( 'Description', 'tainacan' ),
|
||||
'type' => 'string',
|
||||
'description' => __( 'The metadata description', '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.', 'tainacan' ),
|
||||
'default' => '',
|
||||
//'on_error' => __('The description should be a text value', 'tainacan'),
|
||||
//'validation' => v::stringType()->notEmpty(),
|
||||
|
@ -134,7 +134,7 @@ class Metadata extends Repository {
|
|||
'type' => ['string', 'number'],
|
||||
'description' => __( 'Number of multiples possible metadata', 'tainacan' ),
|
||||
'on_error' => __( 'This number of multiples metadata is not allowed', 'tainacan' ),
|
||||
'validation' => v::numeric()->positive(),
|
||||
//'validation' => v::numeric()->positive(),
|
||||
'default' => 1
|
||||
],
|
||||
'mask' => [
|
||||
|
@ -1681,4 +1681,28 @@ class Metadata extends Repository {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a metadata is enabled on collection.
|
||||
*
|
||||
* @param \Tainacan\Entities\Collection $collection
|
||||
* @param \Tainacan\Entities\Metadatum $metadata
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function metadata_is_enabled($collection, $metadata) {
|
||||
$order = $collection->get_metadata_order();
|
||||
if($order == false) return true;
|
||||
$order = ( is_array( $order ) ) ? $order : unserialize( $order );
|
||||
if( is_array($order) ) {
|
||||
foreach ($order as $metadata_order) {
|
||||
if( $metadata_order['id'] == $metadata->get_id() || $metadata_order['id'] == $metadata->get_parent() ) {
|
||||
if($metadata_order['enabled'] == false)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@ class Theme_Helper {
|
|||
|
||||
add_shortcode( 'tainacan-search', array($this, 'search_shortcode'));
|
||||
add_shortcode( 'tainacan-item-submission', array($this, 'item_submission_shortcode'));
|
||||
add_shortcode( 'tainacan-items-carousel', array($this, 'get_tainacan_items_carousel'));
|
||||
add_shortcode( 'tainacan-related-items-carousel', array($this, 'get_tainacan_related_items_carousel'));
|
||||
|
||||
add_action( 'generate_rewrite_rules', array( &$this, 'rewrite_rules' ), 10, 1 );
|
||||
add_filter( 'query_vars', array( &$this, 'rewrite_rules_query_vars' ) );
|
||||
|
@ -122,6 +124,49 @@ class Theme_Helper {
|
|||
wp_localize_script('tainacan-search', 'tainacan_plugin', \Tainacan\Admin::get_instance()->get_admin_js_localization_params());
|
||||
}
|
||||
}
|
||||
|
||||
public function enqueue_items_carousel_scripts() {
|
||||
global $post;
|
||||
global $TAINACAN_BASE_URL;
|
||||
global $TAINACAN_VERSION;
|
||||
global $wp_version;
|
||||
|
||||
$settings = [
|
||||
'wp_version' => $wp_version,
|
||||
'root' => esc_url_raw( rest_url() ) . 'tainacan/v2',
|
||||
'nonce' => is_user_logged_in() ? wp_create_nonce( 'wp_rest' ) : false,
|
||||
'base_url' => $TAINACAN_BASE_URL,
|
||||
'admin_url' => admin_url(),
|
||||
'site_url' => site_url(),
|
||||
'theme_items_list_url' => esc_url_raw( get_site_url() ) . '/' . \Tainacan\Theme_Helper::get_instance()->get_items_list_slug()
|
||||
];
|
||||
|
||||
wp_enqueue_script(
|
||||
'carousel-items-list-theme',
|
||||
$TAINACAN_BASE_URL . '/assets/js/block_carousel_items_list_theme.js',
|
||||
array('wp-components')
|
||||
);
|
||||
wp_enqueue_style(
|
||||
'carousel-items-list',
|
||||
$TAINACAN_BASE_URL . '/assets/css/tainacan-gutenberg-block-' . 'carousel-items-list' . '.css',
|
||||
array('tainacan-blocks-common-styles'),
|
||||
$TAINACAN_VERSION
|
||||
);
|
||||
wp_set_script_translations('carousel-items-list-theme', 'tainacan');
|
||||
wp_localize_script('carousel-items-list-theme', 'tainacan_blocks', $settings);
|
||||
}
|
||||
|
||||
public function enqueue_related_items_carousel_scripts() {
|
||||
global $TAINACAN_BASE_URL;
|
||||
global $TAINACAN_VERSION;
|
||||
|
||||
wp_enqueue_style(
|
||||
'carousel-related-items',
|
||||
$TAINACAN_BASE_URL . '/assets/css/tainacan-gutenberg-block-' . 'carousel-related-items' . '.css',
|
||||
array('tainacan-blocks-common-styles'),
|
||||
$TAINACAN_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
public function is_post_an_item(\WP_Post $post) {
|
||||
$post_type = $post->post_type;
|
||||
|
@ -428,7 +473,6 @@ class Theme_Helper {
|
|||
public function search_shortcode($args) {
|
||||
return $this->get_tainacan_items_list($args, true);
|
||||
}
|
||||
|
||||
public function get_tainacan_items_list($args, $force_enqueue = false) {
|
||||
$props = ' ';
|
||||
|
||||
|
@ -828,5 +872,175 @@ class Theme_Helper {
|
|||
return $adjacent_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the div used by Vue to render the Carousel of Related Items
|
||||
*
|
||||
* @param array $args {
|
||||
* Optional. Array of arguments.
|
||||
* @type string $collection_id The Collection ID
|
||||
* @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 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_tems_per_screen Maximum columns of items to be displayed on a row of the carousel
|
||||
* @type string $arrows_position How the arrows will be positioned regarding the carousel ('around', 'left', 'right')
|
||||
* @type bool $large_arrows Should large arrows be displayed?
|
||||
* @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 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 $crop_images_to_square Should it use the `tainacan-medium-size` instead of the `tainacan-medium-large-size`?
|
||||
* @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 string $collection_background_color Color of the collection header background
|
||||
* @type string $collection_text_color Color of the collection header text
|
||||
* @type string $tainacan_api_root Path of the Tainacan api root (to make the items request)
|
||||
* @type string $tainacan_base_url Path of the Tainacan base URL (to make the links to the items)
|
||||
* @type string $class_name Extra class to add to the wrapper, besides the default wp-block-tainacan-carousel-items-list
|
||||
* @return string The HTML div to be used for rendering the items carousel vue component
|
||||
*/
|
||||
public function get_tainacan_items_carousel($args = []) {
|
||||
if (!is_array($args))
|
||||
return __('There are missing parameters for Tainacan Items Carousel shortcode', 'tainacan');
|
||||
|
||||
$defaults = array(
|
||||
'max_items_number' => 12,
|
||||
'max_items_per_screen' => 7,
|
||||
'arrows_position' => 'around',
|
||||
'large_arrows' => false,
|
||||
'auto_play' => false,
|
||||
'auto_play_speed' => 3,
|
||||
'loop_slides' => false,
|
||||
'hide_title' => false,
|
||||
'crop_images_to_square' => true,
|
||||
'show_collection_header' => false,
|
||||
'show_collection_label' => false,
|
||||
'collection_background_color' => '#454647',
|
||||
'collection_text_color' => '#ffffff',
|
||||
'tainacan_api_root' => '',
|
||||
'tainacan_base_url' => '',
|
||||
'class_name' => '',
|
||||
);
|
||||
$args = wp_parse_args($args, $defaults);
|
||||
|
||||
$props = ' ';
|
||||
|
||||
// Always pass the class needed by Vue to mount the component;
|
||||
$args['class'] = $args['class_name'] . ' wp-block-tainacan-carousel-items-list';
|
||||
unset($args['class_name']);
|
||||
|
||||
// Builds parameters to the html div rendered by Vue
|
||||
foreach ($args as $key => $value) {
|
||||
if (is_bool($value))
|
||||
$value = $value ? 'true' : 'false';
|
||||
// Changes from PHP '_' notation to HTML '-' notation
|
||||
$props .= (str_replace('_', '-', $key) . "='" . $value . "' ");
|
||||
}
|
||||
|
||||
$this->enqueue_items_carousel_scripts();
|
||||
|
||||
return "<div id='tainacan-items-carousel-shortcode' $props ></div>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a group of related items carousels
|
||||
* For each metatada, the collection name, the metadata name and a button linking
|
||||
* the items list filtered is presented
|
||||
*
|
||||
* @param array $args {
|
||||
* Optional. Array of arguments.
|
||||
* @type string $item_id The Item ID
|
||||
* @type string $class_name Extra class to add to the wrapper, besides the default wp-block-tainacan-carousel-related-items
|
||||
* @type string $collection_heading_class_name Extra class to add to the collection name wrapper. Defaults to ''
|
||||
* @type string $collection_heading_tag Tag to be used as wrapper of the collection name. Defaults to h2
|
||||
* @type string $metadata_label_class_name Extra class to add to the metadata label wrapper. Defaults to ''
|
||||
* @type string $metadata_label_tag Tag to be used as wrapper of the metadata label. Defaults to p
|
||||
* @type array $carousel_args Array of arguments to be passed to the get_tainacan_items_carousel function
|
||||
* @return string The HTML div to be used for rendering the related items vue component
|
||||
*/
|
||||
public function get_tainacan_related_items_carousel($args = []) {
|
||||
|
||||
$defaults = array(
|
||||
'class_name' => '',
|
||||
'collection_heading_class_name' => '',
|
||||
'collection_heading_tag' => 'h2',
|
||||
'metadata_label_class_name' => '',
|
||||
'metadata_label_tag' => 'p',
|
||||
'carousel_args' => []
|
||||
);
|
||||
$args = wp_parse_args($args, $defaults);
|
||||
|
||||
// Gets the current Item
|
||||
$item = isset($args['item_id']) ? $this->tainacan_get_item($args['item_id']) : $this->tainacan_get_item();
|
||||
if (!$item)
|
||||
return;
|
||||
|
||||
// Then fetches related ones
|
||||
$related_items = $item->get_related_items();
|
||||
if (!count($related_items))
|
||||
return;
|
||||
|
||||
// Enqueues necessary CSS
|
||||
$this->enqueue_related_items_carousel_scripts();
|
||||
|
||||
// Always pass the default class;
|
||||
$output = '<div class="' . $args['class_name'] . ' wp-block-tainacan-carousel-related-items' . '">';
|
||||
|
||||
foreach($related_items as $collection_id => $related_group) {
|
||||
|
||||
if ( isset($related_group['items']) && isset($related_group['total_items']) && $related_group['total_items'] ) {
|
||||
|
||||
// Adds a heading with the collection name
|
||||
$collection_heading = '';
|
||||
if ( isset($related_group['collection_name']) ) {
|
||||
$collection_heading = '<' . $args['collection_heading_tag'] . ' class="' . $args['collection_heading_class_name'] . '">' . $related_group['collection_name'] . '</' . $args['collection_heading_tag'] . '>';
|
||||
}
|
||||
|
||||
// Adds a paragraph with the metadata name
|
||||
$metadata_label = '';
|
||||
if ( isset($related_group['metadata_name']) ) {
|
||||
$metadata_label = '<' . $args['metadata_label_tag'] . ' class="' . $args['metadata_label_class_name'] . '">' . $related_group['metadata_name'] . '</' . $args['metadata_label_tag'] . '>';
|
||||
}
|
||||
|
||||
// Sets the carousel, from the items carousel template tag.
|
||||
$carousel_div = '';
|
||||
if ( isset($related_group['collection_id']) ) {
|
||||
|
||||
$carousel_args = wp_parse_args([
|
||||
'collection_id' => $related_group['collection_id'],
|
||||
'load_strategy' => 'parent',
|
||||
'selected_items' => json_encode($related_group['items'])
|
||||
], $args['carousel_args']);
|
||||
|
||||
$carousel_div = $this->get_tainacan_items_carousel($carousel_args);
|
||||
}
|
||||
|
||||
$output .= '<div class="wp-block-group">
|
||||
<div class="wp-block-group__inner-container">' .
|
||||
$collection_heading .
|
||||
$metadata_label .
|
||||
$carousel_div .
|
||||
(
|
||||
$related_group['total_items'] > 1 ?
|
||||
'<div class="wp-block-buttons">
|
||||
<div class="wp-block-button">
|
||||
<a class="wp-block-button__link" href="/' . $related_group['collection_slug'] . '?metaquery[0][key]=' . $related_group['metadata_id'] . '&metaquery[0][value][0]=' . $item->get_ID() . '&metaquery[0][compare]=IN">
|
||||
' . sprintf( __('View all %s related items', 'tainacan'), $related_group['total_items'] ) . '
|
||||
</a>
|
||||
</div>
|
||||
</div>'
|
||||
: ''
|
||||
)
|
||||
. '<div style="height:30px" aria-hidden="true" class="wp-block-spacer">
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
}
|
||||
|
||||
$output .= '</div>';
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -998,3 +998,70 @@ function tainacan_get_the_mime_type_icon($mime_type, $image_size = 'medium') {
|
|||
|
||||
return $images_path . $icon_file . $image_size . '.png';
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a carousel of items, the same of the gutenberg block
|
||||
*
|
||||
* @param array $args {
|
||||
* Optional. Array of arguments.
|
||||
* @type string $collection_id The Collection ID
|
||||
* @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 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_tems_per_screen Maximum columns of items to be displayed on a row of the carousel
|
||||
* @type string $arrows_position How the arrows will be positioned regarding the carousel ('around', 'left', 'right')
|
||||
* @type bool $large_arrows Should large arrows be displayed?
|
||||
* @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 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 $crop_images_to_square Should it use the `tainacan-medium-size` instead of the `tainacan-medium-large-size`?
|
||||
* @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 string $collection_background_color Color of the collection header background
|
||||
* @type string $collection_text_color Color of the collection header text
|
||||
* @type string $tainacan_api_root Path of the Tainacan api root (to make the items request)
|
||||
* @type string $tainacan_base_url Path of the Tainacan base URL (to make the links to the items)
|
||||
* @type string $class_name Extra class to add to the wrapper, besides the default wp-block-tainacan-carousel-items-list
|
||||
* @return void The HTML div to be used for rendering the items carousel vue component
|
||||
*/
|
||||
function tainacan_the_items_carousel($args = []) {
|
||||
echo \Tainacan\Theme_Helper::get_instance()->get_tainacan_items_carousel($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a group of related items carousels
|
||||
* For each metatada, the collection name, the metadata name and a button linking
|
||||
* the items list filtered is presented
|
||||
*
|
||||
* @param array $args {
|
||||
* Optional. Array of arguments.
|
||||
* @type string $item_id The Item ID
|
||||
* @return void
|
||||
*/
|
||||
function tainacan_the_related_items_carousel($args = []) {
|
||||
echo \Tainacan\Theme_Helper::get_instance()->get_tainacan_related_items_carousel($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current item has or not related items
|
||||
*/
|
||||
function tainacan_has_related_items($item_id = false) {
|
||||
// Gets the current Item
|
||||
$item = $item_id ? \Tainacan\Theme_Helper::get_instance()->tainacan_get_item($item_id) : \Tainacan\Theme_Helper::get_instance()->tainacan_get_item();
|
||||
if (!$item)
|
||||
return;
|
||||
|
||||
// Then fetches related ones
|
||||
$related_items = $item->get_related_items();// TODO: handle this inside the item so we don't have to load things here.
|
||||
if ( !$related_items || !is_array($related_items) || !count($related_items) )
|
||||
return false;
|
||||
|
||||
// If we have at least one total_items, there are related items
|
||||
foreach($related_items as $related_group) {
|
||||
if ( isset($related_group['total_items']) && (int)$related_group['total_items'] > 0 )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -3,39 +3,40 @@
|
|||
id="tainacan-admin-app"
|
||||
class="columns is-fullheight"
|
||||
:class="{
|
||||
'tainacan-admin-iframe-mode': $route.query.iframemode,
|
||||
'tainacan-admin-read-mode': $route.query.readmode
|
||||
'tainacan-admin-iframe-mode': isIframeMode,
|
||||
'tainacan-admin-read-mode': isReadMode
|
||||
}">
|
||||
<template v-if="activeRoute == 'HomePage'">
|
||||
<tainacan-header />
|
||||
<router-view />
|
||||
</template>
|
||||
<template v-else>
|
||||
<primary-menu
|
||||
:active-route="activeRoute"
|
||||
:is-menu-compressed="isMenuCompressed"/>
|
||||
<button
|
||||
class="is-hidden-mobile"
|
||||
id="menu-compress-button"
|
||||
@click="isMenuCompressed = !isMenuCompressed">
|
||||
<span
|
||||
v-tooltip="{
|
||||
content: isMenuCompressed ? $i18n.get('label_expand_menu') : $i18n.get('label_shrink_menu'),
|
||||
autoHide: true,
|
||||
placement: 'auto-end',
|
||||
classes: ['tooltip', 'repository-tooltip']
|
||||
}"
|
||||
class="icon">
|
||||
<i
|
||||
:class="{ 'tainacan-icon-arrowleft' : !isMenuCompressed, 'tainacan-icon-arrowright' : isMenuCompressed }"
|
||||
class="tainacan-icon tainacan-icon-1-25em"
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
<tainacan-header />
|
||||
<tainacan-repository-subheader
|
||||
:is-repository-level="isRepositoryLevel"
|
||||
:is-menu-compressed="isMenuCompressed"/>
|
||||
<template v-if="!isIframeMode">
|
||||
<primary-menu
|
||||
:active-route="activeRoute"
|
||||
:is-menu-compressed="isMenuCompressed"/>
|
||||
<button
|
||||
class="is-hidden-mobile"
|
||||
id="menu-compress-button"
|
||||
@click="isMenuCompressed = !isMenuCompressed">
|
||||
<span
|
||||
v-tooltip="{
|
||||
content: $i18n.get('label_shrink_menu'),
|
||||
autoHide: true,
|
||||
placement: 'auto-end',
|
||||
classes: ['tooltip', 'repository-tooltip']
|
||||
}"
|
||||
class="icon">
|
||||
<i
|
||||
:class="{ 'tainacan-icon-arrowleft' : !isMenuCompressed, 'tainacan-icon-arrowright' : isMenuCompressed }"
|
||||
class="tainacan-icon tainacan-icon-1-25em"/>
|
||||
</span>
|
||||
</button>
|
||||
<tainacan-header />
|
||||
<tainacan-repository-subheader
|
||||
:is-repository-level="isRepositoryLevel"
|
||||
:is-menu-compressed="isMenuCompressed"/>
|
||||
</template>
|
||||
<div
|
||||
id="repository-container"
|
||||
class="column is-main-content">
|
||||
|
@ -65,6 +66,14 @@
|
|||
activeRoute: '/collections'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isReadMode () {
|
||||
return this.$route && this.$route.query && this.$route.query.readmode;
|
||||
},
|
||||
isIframeMode () {
|
||||
return this.$route && this.$route.query && this.$route.query.iframemode;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$route' (to) {
|
||||
this.isMenuCompressed = (to.params.collectionId != undefined);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -451,6 +451,10 @@
|
|||
.field > .field:not(:last-child) {
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
.field:first-child {
|
||||
-webkit-column-span: all;
|
||||
column-span: all;
|
||||
}
|
||||
.help-wrapper {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
|
||||
<!-- Context menu for right click selection -->
|
||||
<div
|
||||
v-if="cursorPosY > 0 && cursorPosX > 0 && !$route.query.readmode"
|
||||
v-if="cursorPosY > 0 && cursorPosX > 0 && !isReadMode"
|
||||
class="context-menu">
|
||||
|
||||
<!-- Backdrop for escaping context menu -->
|
||||
|
@ -95,12 +95,12 @@
|
|||
trap-focus>
|
||||
<b-dropdown-item
|
||||
@click="openItem()"
|
||||
v-if="!isOnTrash && !$route.query.iframemode">
|
||||
v-if="!isOnTrash && !isIframeMode">
|
||||
{{ $i18n.getFrom('items','view_item') }}
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
@click="openItemOnNewTab()"
|
||||
v-if="!isOnTrash && !$route.query.iframemode">
|
||||
v-if="!isOnTrash && !isIframeMode">
|
||||
{{ $i18n.get('label_open_item_new_tab') }}
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
|
@ -110,22 +110,22 @@
|
|||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
@click="goToItemEditPage(contextMenuItem)"
|
||||
v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !$route.query.iframemode">
|
||||
v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !isIframeMode">
|
||||
{{ $i18n.getFrom('items','edit_item') }}
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
@click="makeCopiesOfOneItem(contextMenuItem.id)"
|
||||
v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !$route.query.iframemode">
|
||||
v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !isIframeMode">
|
||||
{{ $i18n.get('label_make_copies_of_item') }}
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
@click="deleteOneItem(contextMenuItem.id)"
|
||||
v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !$route.query.iframemode">
|
||||
v-if="contextMenuItem != null && contextMenuItem.current_user_can_edit && !isIframeMode">
|
||||
{{ $i18n.get('label_delete_item') }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- GRID (THUMBNAILS) VIEW MODE -->
|
||||
<div
|
||||
role="list"
|
||||
|
@ -142,17 +142,23 @@
|
|||
<!-- Checkbox -->
|
||||
<!-- TODO: Remove v-if="collectionId" from this element when the bulk edit in repository is done -->
|
||||
<div
|
||||
v-if="collectionId && !$route.query.readmode && ($route.query.iframemode || collection && collection.current_user_can_bulk_edit)"
|
||||
v-if="collectionId && !isReadMode && (isIframeMode || collection && collection.current_user_can_bulk_edit)"
|
||||
:class="{ 'is-selecting': isSelectingItems }"
|
||||
class="grid-item-checkbox">
|
||||
<b-checkbox
|
||||
v-if="!isSingleSelectionMode"
|
||||
:value="getSelectedItemChecked(item.id)"
|
||||
@input="setSelectedItemChecked(item.id)"/>
|
||||
<b-radio
|
||||
v-else
|
||||
name="item-single-selection"
|
||||
:native-value="item.id"
|
||||
v-model="singleItemSelection"/>
|
||||
</div>
|
||||
|
||||
<!-- Title -->
|
||||
<div
|
||||
:style="{ 'padding-left': !collectionId || !($route.query.iframemode || collection && collection.current_user_can_bulk_edit) || $route.query.readmode ? '0.5em !important' : (isOnAllItemsTabs ? '1.875em' : '2.75em') }"
|
||||
:style="{ 'padding-left': !collectionId || !(isIframeMode || collection && collection.current_user_can_bulk_edit) || isReadMode? '0.5em !important' : (isOnAllItemsTabs ? '1.875em' : '2.75em') }"
|
||||
class="metadata-title">
|
||||
<p
|
||||
v-tooltip="{
|
||||
|
@ -203,7 +209,7 @@
|
|||
|
||||
<!-- Actions -->
|
||||
<div
|
||||
v-if="item.current_user_can_edit && !$route.query.iframemode"
|
||||
v-if="item.current_user_can_edit && !isIframeMode"
|
||||
class="actions-area"
|
||||
:label="$i18n.get('label_actions')">
|
||||
<a
|
||||
|
@ -277,16 +283,23 @@
|
|||
<!-- Checkbox -->
|
||||
<!-- TODO: Remove v-if="collectionId" from this element when the bulk edit in repository is done -->
|
||||
<div
|
||||
v-if="collectionId && !$route.query.readmode && ($route.query.iframemode || collection && collection.current_user_can_bulk_edit)"
|
||||
v-if="collectionId && !isReadMode && (isIframeMode || collection && collection.current_user_can_bulk_edit)"
|
||||
:class="{ 'is-selecting': isSelectingItems }"
|
||||
class="masonry-item-checkbox">
|
||||
<label
|
||||
tabindex="0"
|
||||
class="b-checkbox checkbox is-small">
|
||||
:class="(!isSingleSelectionMode ? 'b-checkbox checkbox' : 'b-radio radio') + ' is-small'">
|
||||
<input
|
||||
v-if="!isSingleSelectionMode"
|
||||
type="checkbox"
|
||||
:checked="getSelectedItemChecked(item.id)"
|
||||
@input="setSelectedItemChecked(item.id)">
|
||||
<input
|
||||
v-else
|
||||
type="radio"
|
||||
name="item-single-selection"
|
||||
:value="item.id"
|
||||
v-model="singleItemSelection">
|
||||
<span class="check" />
|
||||
<span class="control-label" />
|
||||
</label>
|
||||
|
@ -295,7 +308,7 @@
|
|||
<!-- Title -->
|
||||
<div
|
||||
:style="{
|
||||
'padding-left': !collectionId || !($route.query.iframemode || collection && collection.current_user_can_bulk_edit) || $route.query.readmode ? '0 !important' : (isOnAllItemsTabs ? '0.5em' : '1em')
|
||||
'padding-left': !collectionId || !(isIframeMode || collection && collection.current_user_can_bulk_edit) || isReadMode ? '0 !important' : (isOnAllItemsTabs ? '0.5em' : '1em')
|
||||
}"
|
||||
@click.left="onClickItem($event, item)"
|
||||
@click.right="onRightClickItem($event, item)"
|
||||
|
@ -336,7 +349,7 @@
|
|||
|
||||
<!-- Actions -->
|
||||
<div
|
||||
v-if="item.current_user_can_edit && !$route.query.iframemode"
|
||||
v-if="item.current_user_can_edit && !isIframeMode"
|
||||
class="actions-area"
|
||||
:label="$i18n.get('label_actions')">
|
||||
<a
|
||||
|
@ -405,18 +418,24 @@
|
|||
<!-- Checkbox -->
|
||||
<!-- TODO: Remove v-if="collectionId" from this element when the bulk edit in repository is done -->
|
||||
<div
|
||||
v-if="collectionId && !$route.query.readmode && ($route.query.iframemode || collection && collection.current_user_can_bulk_edit)"
|
||||
v-if="collectionId && !isReadMode && (isIframeMode || collection && collection.current_user_can_bulk_edit)"
|
||||
:class="{ 'is-selecting': isSelectingItems }"
|
||||
class="card-checkbox">
|
||||
<b-checkbox
|
||||
v-if="!isSingleSelectionMode"
|
||||
:value="getSelectedItemChecked(item.id)"
|
||||
@input="setSelectedItemChecked(item.id)"/>
|
||||
<b-radio
|
||||
v-else
|
||||
name="item-single-selection"
|
||||
:native-value="item.id"
|
||||
v-model="singleItemSelection"/>
|
||||
</div>
|
||||
|
||||
<!-- Title -->
|
||||
<div
|
||||
:style="{
|
||||
'padding-left': !collectionId || $route.query.readmode || !($route.query.iframemode || collection && collection.current_user_can_bulk_edit) ? '0.5em !important' : (isOnAllItemsTabs ? '2.125em' : '2.75em'),
|
||||
:style="{
|
||||
'padding-left': !collectionId || !(isIframeMode || collection && collection.current_user_can_bulk_edit) || isReadMode ? '0.5em !important' : (isOnAllItemsTabs ? '2.125em' : '2.75em'),
|
||||
}"
|
||||
class="metadata-title">
|
||||
<p
|
||||
|
@ -451,7 +470,7 @@
|
|||
</div>
|
||||
<!-- Actions -->
|
||||
<div
|
||||
v-if="item.current_user_can_edit && !$route.query.iframemode"
|
||||
v-if="item.current_user_can_edit && !isIframeMode"
|
||||
class="actions-area"
|
||||
:label="$i18n.get('label_actions')">
|
||||
<a
|
||||
|
@ -592,16 +611,23 @@
|
|||
<!-- Checkbox -->
|
||||
<!-- TODO: Remove v-if="collectionId" from this element when the bulk edit in repository is done -->
|
||||
<div
|
||||
v-if="collectionId && !$route.query.readmode && ($route.query.iframemode || collection && collection.current_user_can_bulk_edit)"
|
||||
v-if="collectionId && !isReadMode && (isIframeMode || collection && collection.current_user_can_bulk_edit)"
|
||||
:class="{ 'is-selecting': isSelectingItems }"
|
||||
class="record-checkbox">
|
||||
<label
|
||||
tabindex="0"
|
||||
class="b-checkbox checkbox is-small">
|
||||
:class="(!isSingleSelectionMode ? 'b-checkbox checkbox' : 'b-radio radio') + ' is-small'">
|
||||
<input
|
||||
v-if="!isSingleSelectionMode"
|
||||
type="checkbox"
|
||||
:checked="getSelectedItemChecked(item.id)"
|
||||
@input="setSelectedItemChecked(item.id)">
|
||||
<input
|
||||
v-else
|
||||
type="radio"
|
||||
name="item-single-selection"
|
||||
:value="item.id"
|
||||
v-model="singleItemSelection">
|
||||
<span class="check" />
|
||||
<span class="control-label" />
|
||||
</label>
|
||||
|
@ -611,7 +637,7 @@
|
|||
<div
|
||||
class="metadata-title"
|
||||
:style="{
|
||||
'padding-left': !collectionId || !($route.query.iframemode || collection && collection.current_user_can_bulk_edit) || $route.query.readmode ? '1.5em !important' : '2.75em'
|
||||
'padding-left': !collectionId || !(isIframeMode || collection && collection.current_user_can_bulk_edit) || isReadMode ? '1.5em !important' : '2.75em'
|
||||
}">
|
||||
<span
|
||||
v-if="isOnAllItemsTabs && $statusHelper.hasIcon(item.status)"
|
||||
|
@ -664,7 +690,7 @@
|
|||
</div>
|
||||
<!-- Actions -->
|
||||
<div
|
||||
v-if="item.current_user_can_edit && !$route.query.iframemode"
|
||||
v-if="item.current_user_can_edit && !isIframeMode"
|
||||
class="actions-area"
|
||||
:label="$i18n.get('label_actions')">
|
||||
<a
|
||||
|
@ -779,7 +805,7 @@
|
|||
<tr>
|
||||
<!-- Checking list -->
|
||||
<th
|
||||
v-if="collectionId && !$route.query.readmode && ($route.query.iframemode || collection && collection.current_user_can_bulk_edit)">
|
||||
v-if="collectionId && !isReadMode && (isIframeMode || collection && collection.current_user_can_bulk_edit)">
|
||||
|
||||
<!-- nothing to show on header for checkboxes -->
|
||||
</th>
|
||||
|
@ -828,12 +854,18 @@
|
|||
<!-- Checking list -->
|
||||
<!-- TODO: Remove v-if="collectionId" from this element when the bulk edit in repository is done -->
|
||||
<td
|
||||
v-if="collectionId && !$route.query.readmode && ($route.query.iframemode || collection && collection.current_user_can_bulk_edit)"
|
||||
v-if="collectionId && !isReadMode && (isIframeMode || collection && collection.current_user_can_bulk_edit)"
|
||||
:class="{ 'is-selecting': isSelectingItems }"
|
||||
class="checkbox-cell">
|
||||
<b-checkbox
|
||||
v-if="!isSingleSelectionMode"
|
||||
:value="getSelectedItemChecked(item.id)"
|
||||
@input="setSelectedItemChecked(item.id)"/>
|
||||
<b-radio
|
||||
v-else
|
||||
name="item-single-selection"
|
||||
:native-value="item.id"
|
||||
v-model="singleItemSelection"/>
|
||||
</td>
|
||||
<td
|
||||
v-if="isOnAllItemsTabs"
|
||||
|
@ -972,7 +1004,7 @@
|
|||
|
||||
<!-- Actions -->
|
||||
<td
|
||||
v-if="(item.current_user_can_edit || item.current_user_can_delete) && !$route.query.iframemode"
|
||||
v-if="(item.current_user_can_edit || item.current_user_can_delete) && !isIframeMode"
|
||||
class="actions-cell"
|
||||
:label="$i18n.get('label_actions')">
|
||||
<div class="actions-container">
|
||||
|
@ -1043,16 +1075,23 @@
|
|||
:class="{ 'selected-list-item': getSelectedItemChecked(item.id) == true }">
|
||||
|
||||
<div
|
||||
v-if="collectionId && !$route.query.readmode && ($route.query.iframemode || collection && collection.current_user_can_bulk_edit)"
|
||||
v-if="collectionId && !isReadMode && (isIframeMode || collection && collection.current_user_can_bulk_edit)"
|
||||
:class="{ 'is-selecting': isSelectingItems }"
|
||||
class="list-checkbox">
|
||||
<label
|
||||
tabindex="0"
|
||||
class="b-checkbox checkbox is-small">
|
||||
:class="(!isSingleSelectionMode ? 'b-checkbox checkbox' : 'b-radio radio') + ' is-small'">
|
||||
<input
|
||||
v-if="!isSingleSelectionMode"
|
||||
type="checkbox"
|
||||
:checked="getSelectedItemChecked(item.id)"
|
||||
@input="setSelectedItemChecked(item.id)">
|
||||
<input
|
||||
v-else
|
||||
type="radio"
|
||||
name="item-single-selection"
|
||||
:value="item.id"
|
||||
v-model="singleItemSelection">
|
||||
<span class="check" />
|
||||
<span class="control-label" />
|
||||
</label>
|
||||
|
@ -1099,7 +1138,7 @@
|
|||
|
||||
<!-- Actions -->
|
||||
<div
|
||||
v-if="item.current_user_can_edit && !$route.query.iframemode"
|
||||
v-if="item.current_user_can_edit && !isIframeMode"
|
||||
class="actions-area"
|
||||
:label="$i18n.get('label_actions')">
|
||||
<a
|
||||
|
@ -1227,6 +1266,7 @@ export default {
|
|||
cursorPosX: -1,
|
||||
cursorPosY: -1,
|
||||
contextMenuItem: null,
|
||||
singleItemSelection: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -1237,7 +1277,7 @@ export default {
|
|||
return this.getHighlightedItem();
|
||||
},
|
||||
selectedItems () {
|
||||
if (this.$route.query.iframemode)
|
||||
if (this.isIframeMode)
|
||||
this.$eventBusSearch.setSelectedItemsForIframe(this.getSelectedItems());
|
||||
|
||||
return this.getSelectedItems();
|
||||
|
@ -1259,7 +1299,16 @@ export default {
|
|||
return this.getItemsPerPage();
|
||||
},
|
||||
totalPages(){
|
||||
return Math.ceil(Number(this.totalItems)/Number(this.itemsPerPage));
|
||||
return Math.ceil(Number(this.totalItems)/Number(this.itemsPerPage));
|
||||
},
|
||||
isIframeMode () {
|
||||
return this.$route && this.$route.query && this.$route.query.iframemode;
|
||||
},
|
||||
isReadMode () {
|
||||
return this.$route && this.$route.query && this.$route.query.readmode;
|
||||
},
|
||||
isSingleSelectionMode () {
|
||||
return this.$route && this.$route.query && this.$route.query.singleselectionmode;
|
||||
},
|
||||
isOnAllItemsTabs() {
|
||||
const currentStatus = this.getStatus();
|
||||
|
@ -1281,6 +1330,11 @@ export default {
|
|||
allItemsOnPageSelected(value) {
|
||||
if (!value)
|
||||
this.queryAllItemsSelected = {};
|
||||
},
|
||||
singleItemSelection() {
|
||||
|
||||
if (this.isSingleSelectionMode && this.isIframeMode)
|
||||
this.$eventBusSearch.setSelectedItemsForIframe([this.singleItemSelection], true);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -1321,14 +1375,18 @@ export default {
|
|||
'getItemsPerPage'
|
||||
]),
|
||||
setSelectedItemChecked(itemId) {
|
||||
if (this.selectedItems.find((item) => item == itemId) != undefined)
|
||||
this.removeSelectedItem(itemId);
|
||||
else {
|
||||
this.addSelectedItem(itemId);
|
||||
if (this.isSingleSelectionMode) {
|
||||
this.singleItemSelection = itemId;
|
||||
} else {
|
||||
if (this.selectedItems.find((item) => item == itemId) != undefined)
|
||||
this.removeSelectedItem(itemId);
|
||||
else {
|
||||
this.addSelectedItem(itemId);
|
||||
}
|
||||
}
|
||||
},
|
||||
getSelectedItemChecked(itemId) {
|
||||
return this.selectedItems.find(item => item == itemId) != undefined;
|
||||
return this.isSingleSelectionMode ? this.singleItemSelection == itemId : this.selectedItems.find(item => item == itemId) != undefined;
|
||||
},
|
||||
openBulkEditionModal(){
|
||||
this.$buefy.modal.open({
|
||||
|
@ -1558,9 +1616,9 @@ export default {
|
|||
}
|
||||
|
||||
} else {
|
||||
if (this.$route.query.iframemode && !this.$route.query.readmode) {
|
||||
if (this.isIframeMode && !this.isReadMode) {
|
||||
this.setSelectedItemChecked(item.id)
|
||||
} else if (!this.$route.query.iframemode && !this.$route.query.readmode) {
|
||||
} else if (!this.isIframeMode && !this.isReadMode) {
|
||||
if(this.isOnTrash){
|
||||
this.$buefy.toast.open({
|
||||
duration: 3000,
|
||||
|
@ -1575,7 +1633,7 @@ export default {
|
|||
}
|
||||
},
|
||||
onRightClickItem($event, item) {
|
||||
if (!this.$route.query.readmode) {
|
||||
if (!this.isReadMode) {
|
||||
$event.preventDefault();
|
||||
|
||||
this.cursorPosX = $event.clientX;
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="table-container">
|
||||
<b-loading
|
||||
is-full-page="false"
|
||||
:active.sync="displayLoading" />
|
||||
<div class="table-wrapper">
|
||||
<div class="related-items-list">
|
||||
<div
|
||||
v-for="(relatedItemGroup, index) of relatedItemsArray"
|
||||
:key="index"
|
||||
class="related-item-group">
|
||||
<div class="columns is-vcentered is-multiline">
|
||||
<div class="column is-narrow">
|
||||
<div class="section-status">
|
||||
<div class="field has-addons">
|
||||
<span>
|
||||
<span class="icon">
|
||||
<i class="tainacan-icon tainacan-icon-collection"/>
|
||||
</span>
|
||||
{{ relatedItemGroup.collection_name ? relatedItemGroup.collection_name : '' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-narrow">
|
||||
<div class="section-status">
|
||||
<div class="field has-addons">
|
||||
<span>
|
||||
<span class="icon">
|
||||
<i class="tainacan-icon tainacan-icon-metadata"/>
|
||||
</span>
|
||||
{{ relatedItemGroup.metadata_name ? relatedItemGroup.metadata_name : '' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="relatedItemGroup.total_items && relatedItemGroup.total_items > 1"
|
||||
style="margin-left: auto;"
|
||||
class="column is-narrow">
|
||||
<div class="section-status">
|
||||
<div class="field has-addons">
|
||||
<b-button
|
||||
class="button is-secondary"
|
||||
tag="router-link"
|
||||
:to="$routerHelper.getCollectionItemsPath(collectionId, { metaquery: [{ key: relatedItemGroup.metadata_id, value: itemId, compare: 'IN' }] })">
|
||||
{{ $i18n.getWithVariables('label_view_all_%s_related_items', [relatedItemGroup.total_items]) }}
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="related-item-group__items-list">
|
||||
<li
|
||||
v-for="(relatedItem, itemIndex) of relatedItemGroup.items"
|
||||
:key="itemIndex">
|
||||
|
||||
<div
|
||||
class="status-cell"
|
||||
@click="openItemOnNewTab(relatedItem)">
|
||||
<span
|
||||
v-if="$statusHelper.hasIcon(relatedItem.status)"
|
||||
class="icon has-text-gray"
|
||||
v-tooltip="{
|
||||
content: $i18n.get('status_' + relatedItem.status),
|
||||
autoHide: true,
|
||||
placement: 'auto-start'
|
||||
}">
|
||||
<i
|
||||
class="tainacan-icon tainacan-icon-1em"
|
||||
:class="$statusHelper.getIcon(relatedItem.status)"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div @click="openItemOnNewTab(relatedItem)">
|
||||
<span class="table-thumb">
|
||||
<blur-hash-image
|
||||
:width="$thumbHelper.getWidth(relatedItem['thumbnail'], 'tainacan-small', 40)"
|
||||
:height="$thumbHelper.getHeight(relatedItem['thumbnail'], 'tainacan-small', 40)"
|
||||
:hash="$thumbHelper.getBlurhashString(relatedItem['thumbnail'], 'tainacan-small')"
|
||||
:src="$thumbHelper.getSrc(relatedItem['thumbnail'], 'tainacan-small', relatedItem.document_mimetype)"
|
||||
:alt="relatedItem.thumbnail_alt ? relatedItem.thumbnail_alt : $i18n.get('label_thumbnail')"
|
||||
:transition-duration="500"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
@click="openItemOnNewTab(relatedItem)"
|
||||
style="width: 100%">
|
||||
<p
|
||||
v-tooltip="{
|
||||
delay: {
|
||||
show: 500,
|
||||
hide: 300,
|
||||
},
|
||||
content: relatedItem.title != undefined && relatedItem.title != '' ? relatedItem.title : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`,
|
||||
html: true,
|
||||
autoHide: false,
|
||||
placement: 'auto-start'
|
||||
}"
|
||||
v-html="(relatedItem.title != undefined && relatedItem.title != '') ? relatedItem.title : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`"/>
|
||||
</div>
|
||||
<div
|
||||
v-if="isEditable && relatedItem.current_user_can_edit"
|
||||
class="actions-cell"
|
||||
:label="$i18n.get('label_actions')">
|
||||
<div class="actions-container">
|
||||
<a
|
||||
v-if="!relatedItem.status != 'trash'"
|
||||
id="button-edit"
|
||||
@click.prevent.stop="editItemModal = true; editItemId = relatedItem.id; editMetadataId = relatedItemGroup.metadata_id;"
|
||||
:aria-label="$i18n.getFrom('items','edit_item')">
|
||||
<span
|
||||
v-tooltip="{
|
||||
content: $i18n.get('edit'),
|
||||
autoHide: true,
|
||||
placement: 'auto'
|
||||
}"
|
||||
class="icon">
|
||||
<i class="has-text-secondary tainacan-icon tainacan-icon-1-25em tainacan-icon-edit" />
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<b-modal
|
||||
:width="1200"
|
||||
:active.sync="editItemModal"
|
||||
@close="reloadRelatedItems"
|
||||
custom-class="tainacan-modal">
|
||||
<iframe
|
||||
width="100%"
|
||||
style="height: 85vh"
|
||||
:src="adminFullURL + $routerHelper.getItemEditPath(collectionId, editItemId) + '?iframemode=true&editingmetadata=' + editMetadataId" />
|
||||
</b-modal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
export default {
|
||||
name: 'RelatedItemsList',
|
||||
props: {
|
||||
relatedItems: Object,
|
||||
isLoading: Boolean,
|
||||
isEditable: Boolean,
|
||||
itemId: String,
|
||||
collectionId: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editMetadataId: false,
|
||||
editItemId: false,
|
||||
editItemModal: false,
|
||||
adminFullURL: tainacan_plugin.admin_url + 'admin.php?page=tainacan_admin#',
|
||||
isUpdatingRelatedItems: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
relatedItemsArray() {
|
||||
return this.relatedItems ? Object.values(this.relatedItems).filter((aRelatedItemGroup) => aRelatedItemGroup.total_items) : [];
|
||||
},
|
||||
displayLoading() {
|
||||
return this.isLoading || this.isUpdatingRelatedItems;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
editItemModal() {
|
||||
if (this.editItemModal) {
|
||||
window.addEventListener('message', this.updateReloadItemsAfterModal, false);
|
||||
} else {
|
||||
this.editItemId = false;
|
||||
this.editMetadataId = false;
|
||||
window.removeEventListener('message', this.updateReloadItemsAfterModal);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('item', [
|
||||
'fetchOnlyRelatedItems'
|
||||
]),
|
||||
openItemOnNewTab(relatedItem) {
|
||||
if (relatedItem && relatedItem.id) {
|
||||
let routeData = this.$router.resolve(this.$routerHelper.getItemPath(this.collectionId, relatedItem.id));
|
||||
window.open(routeData.href, '_blank');
|
||||
}
|
||||
},
|
||||
reloadRelatedItems() {
|
||||
this.isUpdatingRelatedItems = true;
|
||||
this.fetchOnlyRelatedItems({
|
||||
itemId: this.itemId,
|
||||
contextEdit: true
|
||||
})
|
||||
.then(() => this.isUpdatingRelatedItems = false)
|
||||
.catch((error) => {
|
||||
this.$console.error(error);
|
||||
this.isUpdatingRelatedItems = false;
|
||||
});
|
||||
},
|
||||
updateReloadItemsAfterModal(event) {
|
||||
const message = event.message ? 'message' : 'data';
|
||||
const data = event[message];
|
||||
|
||||
if (data.type == 'itemCreationMessage') {
|
||||
this.editItemModal = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.section-status {
|
||||
margin-left: -0.875rem;
|
||||
font-size: 0.875em;
|
||||
|
||||
.field {
|
||||
|
||||
.icon {
|
||||
font-size: 1.125em !important;
|
||||
color: var(--tainacan-info-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
.related-items-list {
|
||||
.related-item-group {
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px dashed var(--tainacan-info-color);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.related-item-group__items-list {
|
||||
list-style: none;
|
||||
padding: 0px;
|
||||
margin-bottom: 1rem;
|
||||
-moz-column-count: 2;
|
||||
-webkit-column-count: 2;
|
||||
column-count: 2;
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
-moz-column-count: 1;
|
||||
-webkit-column-count: 1;
|
||||
column-count: 1;
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 32px 8px 6px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background-color: var(--tainacan-item-hover-background-color);
|
||||
.actions-cell {
|
||||
opacity: 1;
|
||||
visibility: 1;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.actions-cell {
|
||||
position: absolute;
|
||||
right: -32px;
|
||||
padding: 0 6px;
|
||||
min-height: 28px;
|
||||
min-width: 28px;
|
||||
opacity: 0;
|
||||
visibility: 0;
|
||||
transition: right 0.3s ease;
|
||||
}
|
||||
.table-thumb {
|
||||
display: block;
|
||||
min-height: 28px;
|
||||
min-width: 28px;
|
||||
margin-left: 2px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -52,6 +52,7 @@
|
|||
</div>
|
||||
<tainacan-form-item
|
||||
v-else
|
||||
v-show="(metadataNameFilterString == '' || filterByMetadatumName(childItemMetadatum))"
|
||||
:key="groupIndex + '-' + childIndex"
|
||||
:item-metadatum="childItemMetadatum"
|
||||
:is-collapsed="childItemMetadatum.collapse"
|
||||
|
@ -105,7 +106,8 @@
|
|||
props: {
|
||||
itemMetadatum: Object,
|
||||
value: [String, Number, Array],
|
||||
disabled: false
|
||||
disabled: false,
|
||||
metadataNameFilterString: ''
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -306,6 +308,9 @@
|
|||
} else {
|
||||
this.childItemMetadataGroups.splice(groupIndex, 1);
|
||||
}
|
||||
},
|
||||
filterByMetadatumName(itemMetadatum) {
|
||||
return itemMetadatum.metadatum.name.toString().toLowerCase().indexOf(this.metadataNameFilterString.toString().toLowerCase()) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -331,7 +336,7 @@
|
|||
.field {
|
||||
padding-right: 0;
|
||||
margin-left: 3px;
|
||||
margin-bottom: 0.875em;
|
||||
margin-bottom: 0em !important;
|
||||
}
|
||||
.is-last-input.field {
|
||||
border-bottom: none;
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
v-model="collection"
|
||||
@change.native="emitValues()"
|
||||
@focus="clear()"
|
||||
:loading="loading">
|
||||
:loading="loading"
|
||||
expanded>
|
||||
<option
|
||||
v-for="option in collections"
|
||||
:value="option.id"
|
||||
|
@ -40,42 +41,36 @@
|
|||
:title="$i18n.getHelperTitle('tainacan-relationship', 'search')"
|
||||
:message="$i18n.getHelperMessage('tainacan-relationship', 'search')"/>
|
||||
</label>
|
||||
<b-select
|
||||
name="metadata_type_relationship[search]"
|
||||
v-model="modelSearch">
|
||||
|
||||
<option
|
||||
v-for="(option, index) in metadata"
|
||||
:key="index"
|
||||
:value="option.id"
|
||||
class="field">
|
||||
{{ option.name }}
|
||||
</option>
|
||||
|
||||
</b-select>
|
||||
|
||||
<b-select
|
||||
name="metadata_type_relationship[search]"
|
||||
v-model="modelSearch"
|
||||
expanded>
|
||||
<option
|
||||
v-for="(option, index) in metadata"
|
||||
:key="index"
|
||||
:value="option.id"
|
||||
class="field">
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
|
||||
</transition>
|
||||
|
||||
|
||||
<b-field :addons="false">
|
||||
<label class="label">
|
||||
{{ $i18n.get('label_allow_repeated_items') }}
|
||||
<help-button
|
||||
:title="$i18n.getHelperTitle('tainacan-relationship', 'repeated')"
|
||||
:message="$i18n.getHelperMessage('tainacan-relationship', 'repeated')"/>
|
||||
</label>
|
||||
<div class="block">
|
||||
<b-checkbox
|
||||
v-model="modelRepeated"
|
||||
@input="emitValues()"
|
||||
true-value="yes"
|
||||
false-value="no">
|
||||
{{ labelRepeated() }}
|
||||
</b-checkbox>
|
||||
</div>
|
||||
<b-field
|
||||
:addons="false"
|
||||
:label="$i18n.getHelperTitle('tainacan-relationship', 'display_in_related_items')">
|
||||
|
||||
<b-switch
|
||||
size="is-small"
|
||||
v-model="modelDisplayInRelatedItems"
|
||||
@input="emitValues()"
|
||||
true-value="yes"
|
||||
false-value="no" />
|
||||
<help-button
|
||||
:title="$i18n.getHelperTitle('tainacan-relationship', 'display_in_related_items')"
|
||||
:message="$i18n.getHelperMessage('tainacan-relationship', 'display_in_related_items')"/>
|
||||
</b-field>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
|
||||
|
@ -86,7 +81,6 @@
|
|||
props: {
|
||||
search: [ String ],
|
||||
collection_id: [ Number ],
|
||||
repeated: [ String ],
|
||||
value: [ String, Object, Array ],
|
||||
metadatum: [ String, Object ],
|
||||
errors: [ String, Object, Array ]
|
||||
|
@ -100,7 +94,7 @@
|
|||
collection: '',
|
||||
hasMetadata: false,
|
||||
loadingMetadata: false,
|
||||
modelRepeated: 'yes',
|
||||
modelDisplayInRelatedItems: 'no',
|
||||
modelSearch:'',
|
||||
collectionType: '',
|
||||
collectionMessage: ''
|
||||
|
@ -114,7 +108,7 @@
|
|||
this.setErrorsAttributes( '', '' );
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
collection( value ){
|
||||
|
@ -125,7 +119,7 @@
|
|||
this.metadata = [];
|
||||
this.hasMetadata = false;
|
||||
this.modelSearch = '';
|
||||
|
||||
this.modelDisplayInRelatedItems = 'no';
|
||||
this.emitValues();
|
||||
}
|
||||
},
|
||||
|
@ -143,11 +137,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
if( this.repeated ){
|
||||
this.modelRepeated = this.repeated;
|
||||
} else if( this.value ) {
|
||||
this.modelRepeated = this.value.repeated;
|
||||
}
|
||||
this.modelDisplayInRelatedItems = this.value && this.value.display_in_related_items ? this.value.display_in_related_items : 'no';
|
||||
},
|
||||
methods:{
|
||||
setErrorsAttributes( type, message ){
|
||||
|
@ -157,14 +147,10 @@
|
|||
fetchCollections(){
|
||||
return axios.get('/collections?nopaging=1')
|
||||
.then(res => {
|
||||
let collections = res.data;
|
||||
this.loading = false;
|
||||
const collections = res.data;
|
||||
|
||||
if( collections ){
|
||||
this.collections = collections;
|
||||
} else {
|
||||
this.collections = [];
|
||||
}
|
||||
this.loading = false;
|
||||
this.collections = collections ? collections : [];
|
||||
})
|
||||
.catch(error => {
|
||||
this.$console.log(error);
|
||||
|
@ -231,9 +217,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
labelRepeated(){
|
||||
return ( this.modelRepeated === 'yes' ) ? this.$i18n.get('label_yes') : this.$i18n.get('label_no');
|
||||
},
|
||||
clear(){
|
||||
this.collectionType = '';
|
||||
this.collectionMessage = '';
|
||||
|
@ -242,7 +225,7 @@
|
|||
this.$emit('input',{
|
||||
collection_id: this.collection,
|
||||
search: this.modelSearch,
|
||||
repeated: this.modelRepeated
|
||||
display_in_related_items: this.modelDisplayInRelatedItems
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -251,6 +234,9 @@
|
|||
|
||||
<style scoped>
|
||||
.help-wrapper {
|
||||
font-size: 1.25em;
|
||||
font-size: 1em;
|
||||
}
|
||||
.switch.is-small {
|
||||
margin-top: -0.5em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -59,25 +59,25 @@ class Relationship extends Metadata_Type {
|
|||
'title' => __( 'Related Metadatum', 'tainacan' ),
|
||||
'description' => __( 'Select the metadata to use as search criteria in the target collection and as a label when representing the relationship', 'tainacan' ),
|
||||
],
|
||||
'repeated' => [
|
||||
'title' =>__( 'Allow repeated items', 'tainacan' ),
|
||||
'description' => __( 'Allows different items to be related to the same item selected in another collection.', 'tainacan' ),
|
||||
'display_in_related_items' => [
|
||||
'title' =>__( 'Display in related items', 'tainacan' ),
|
||||
'description' => __( 'Include items on related item list.', 'tainacan' ),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets print-ready version of the options list in html
|
||||
*
|
||||
* Checks if at least one option exists, otherwise return an empty string
|
||||
*
|
||||
* @return string An html content with labels and values for the options or an empty string
|
||||
*/
|
||||
public function get_options_as_html() {
|
||||
$options_as_html = '';
|
||||
$options = $this->get_options();
|
||||
* Gets print-ready version of the options list in html
|
||||
*
|
||||
* Checks if at least one option exists, otherwise return an empty string
|
||||
*
|
||||
* @return string An html content with labels and values for the options or an empty string
|
||||
*/
|
||||
public function get_options_as_html() {
|
||||
$options_as_html = '';
|
||||
$options = $this->get_options();
|
||||
|
||||
if ( count($options) > 0 ) {
|
||||
if ( count($options) > 0 ) {
|
||||
|
||||
// Remove this option that is not relevant for the user
|
||||
if ( isset($options['related_primitive_type']) )
|
||||
|
@ -110,7 +110,7 @@ class Relationship extends Metadata_Type {
|
|||
$readable_option_value = $option_value;
|
||||
break;
|
||||
|
||||
case 'repeated':
|
||||
case 'display_in_related_items':
|
||||
if ($option_value == 'yes')
|
||||
$readable_option_value = __('Yes', 'tainacan');
|
||||
else if ($option_value == 'no')
|
||||
|
@ -124,10 +124,10 @@ class Relationship extends Metadata_Type {
|
|||
}
|
||||
$options_as_html .= '<div class="value">' . $readable_option_value . '</div></div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $options_as_html;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $options_as_html;
|
||||
}
|
||||
|
||||
public function validate_options(\Tainacan\Entities\Metadatum $metadatum) {
|
||||
if ( !in_array($metadatum->get_status(), apply_filters('tainacan-status-require-validation', ['publish','future','private'])) )
|
||||
|
@ -148,6 +148,12 @@ class Relationship extends Metadata_Type {
|
|||
'search' => __('Search option must be a numeric Metadatum ID','tainacan')
|
||||
];
|
||||
}
|
||||
// empty is ok
|
||||
if ( !empty($this->get_option('display_in_related_items')) && !in_array($this->get_option('display_in_related_items'), ['yes', 'no']) ) {
|
||||
return [
|
||||
'search' => __('Display in related items must be a option yes or no','tainacan')
|
||||
];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
<template>
|
||||
<b-field
|
||||
:class="hideCollapses ? 'has-collapses-hidden' : ''"
|
||||
:class="{
|
||||
'has-collapses-hidden': hideCollapses,
|
||||
'hightlighted-metadatum': isHighlightedMetadatum
|
||||
}"
|
||||
:ref="isHighlightedMetadatum ? 'hightlighted-metadatum': 'null'"
|
||||
:addons="false"
|
||||
:message="errorMessage"
|
||||
:type="errorMessage ? 'is-danger' : ''">
|
||||
|
@ -17,17 +21,7 @@
|
|||
}"
|
||||
class="has-text-secondary tainacan-icon tainacan-icon-1-25em"/>
|
||||
</span>
|
||||
<label
|
||||
v-tooltip="{
|
||||
delay: {
|
||||
show: 500,
|
||||
hide: 300,
|
||||
},
|
||||
content: itemMetadatum.metadatum.name,
|
||||
autoHide: false,
|
||||
placement: 'auto-end'
|
||||
}"
|
||||
class="label">
|
||||
<label class="label">
|
||||
{{ itemMetadatum.metadatum.name }}
|
||||
</label>
|
||||
<span
|
||||
|
@ -50,12 +44,13 @@
|
|||
<div
|
||||
v-show="hideCollapses || (isCollapsed || errorMessage)"
|
||||
v-if="isTextInputComponent">
|
||||
<component
|
||||
<component
|
||||
:is="metadatumComponent"
|
||||
v-model="values[0]"
|
||||
:item-metadatum="itemMetadatum"
|
||||
@input="changeValue"
|
||||
@blur="performValueChange"/>
|
||||
@blur="performValueChange"
|
||||
:metadata-name-filter-string="metadataNameFilterString" />
|
||||
<template v-if="isMultiple && values.length > 1">
|
||||
<transition-group
|
||||
name="filter-item"
|
||||
|
@ -68,7 +63,8 @@
|
|||
v-model="values[index]"
|
||||
:item-metadatum="itemMetadatum"
|
||||
@input="changeValue"
|
||||
@blur="performValueChange"/>
|
||||
@blur="performValueChange"
|
||||
:metadata-name-filter-string="metadataNameFilterString" />
|
||||
<a
|
||||
v-if="index > 0"
|
||||
@click="removeValue(index)"
|
||||
|
@ -105,7 +101,8 @@
|
|||
:item-metadatum="itemMetadatum"
|
||||
@input="changeValue"
|
||||
@blur="performValueChange"
|
||||
:is-last-metadatum="isLastMetadatum" />
|
||||
:is-last-metadatum="isLastMetadatum"
|
||||
:metadata-name-filter-string="metadataNameFilterString" />
|
||||
</div>
|
||||
</transition>
|
||||
</b-field>
|
||||
|
@ -120,12 +117,14 @@
|
|||
itemMetadatum: Object,
|
||||
isCollapsed: true,
|
||||
hideCollapses: false,
|
||||
isLastMetadatum: false
|
||||
isLastMetadatum: false,
|
||||
metadataNameFilterString: ''
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
values: [],
|
||||
errorMessage: ''
|
||||
errorMessage: '',
|
||||
isHighlightedMetadatum: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -157,6 +156,20 @@
|
|||
if (this.itemMetadatum && this.itemMetadatum.metadatum)
|
||||
eventBusItemMetadata.$off('updateErrorMessageOf#' + (this.itemMetadatum.parent_meta_id ? this.itemMetadatum.metadatum.id + '-' + this.itemMetadatum.parent_meta_id : this.itemMetadatum.metadatum.id));
|
||||
},
|
||||
mounted () {
|
||||
if (this.$route && this.$route.query && this.$route.query.editingmetadata) {
|
||||
this.isHighlightedMetadatum = this.$route.query.editingmetadata == (this.itemMetadatum.parent_meta_id ? this.itemMetadatum.metadatum.id + '-' + this.itemMetadatum.parent_meta_id : this.itemMetadatum.metadatum.id);
|
||||
|
||||
if (this.isHighlightedMetadatum) {
|
||||
|
||||
this.$nextTick(() => {
|
||||
let highlightedMetadatum = this.$refs['hightlighted-metadatum'];
|
||||
if (highlightedMetadatum && highlightedMetadatum.$el && highlightedMetadatum.$el.scrollIntoView)
|
||||
setTimeout(() => highlightedMetadatum.$el.scrollIntoView(), 500);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 'this.values' is always an array for this component, even if it is single valued.
|
||||
setInitialValues() {
|
||||
|
@ -256,6 +269,14 @@
|
|||
border-bottom: 1px solid var(--tainacan-input-border-color);
|
||||
padding: 10px var(--tainacan-container-padding);
|
||||
|
||||
&.hightlighted-metadatum {
|
||||
background-color: var(--tainacan-white);
|
||||
transition: background-color 0.8s;
|
||||
animation-name: metadatum-highlight;
|
||||
animation-duration: 3s;
|
||||
animation-iteration-count: 2;
|
||||
}
|
||||
|
||||
&.has-collapses-hidden {
|
||||
border-bottom: none;
|
||||
padding: 10px !important;
|
||||
|
@ -275,25 +296,21 @@
|
|||
margin-left: 15px;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0.15em;
|
||||
max-width: 50%;
|
||||
}
|
||||
.metadata-type {
|
||||
font-size: 0.8125em;
|
||||
font-weight: 400;
|
||||
color: var(--tainacan-info-color);
|
||||
opacity: 0.75;
|
||||
top: -0.1em;
|
||||
position: relative;
|
||||
}
|
||||
.help-wrapper {
|
||||
top: -0.2em;
|
||||
}
|
||||
.collapse-handle {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
margin-left: -42px;
|
||||
bottom: 0.1em;
|
||||
white-space: nowrap;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
.collapse-handle+div {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
.add-link {
|
||||
font-size: 0.75em;
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
v-model="taxonomy_id"
|
||||
@input="emitValues()"
|
||||
@focus="clear"
|
||||
:loading="loading">
|
||||
:loading="loading"
|
||||
expanded>
|
||||
<option value="">{{ $i18n.get('label_selectbox_init') }}...</option>
|
||||
<option
|
||||
v-for="option in taxonomies"
|
||||
|
@ -41,7 +42,8 @@
|
|||
name="metadata_type_options[component_type]"
|
||||
placeholder="Select the input type for the taxonomy metadatum"
|
||||
@input="emitValues()"
|
||||
v-model="input_type">
|
||||
v-model="input_type"
|
||||
expanded>
|
||||
<option
|
||||
v-for="(option, index) in single_types"
|
||||
:value="index"
|
||||
|
@ -55,7 +57,8 @@
|
|||
placeholder="Select the input type for the taxonomy metadatum"
|
||||
v-model="input_type"
|
||||
@input="emitValues()"
|
||||
v-else>
|
||||
v-else
|
||||
expanded>
|
||||
<option
|
||||
v-for="(option, index) in multiple_types"
|
||||
:value="index"
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
tabindex="-1"
|
||||
aria-modal
|
||||
ref="availableExportersModal">
|
||||
<div
|
||||
class="tainacan-modal-content"
|
||||
style="width: auto">
|
||||
<div style="width: auto">
|
||||
<header class="tainacan-modal-title">
|
||||
<h2>{{ this.$i18n.get('exporters') }}</h2>
|
||||
<hr>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<template>
|
||||
<div>
|
||||
<figure
|
||||
class="document-item">
|
||||
<!-- <figure
|
||||
class="document-item"
|
||||
@click.prevent="isPreviewModalActive = true">
|
||||
@click.prevent="isPreviewModalActive = true"> -->
|
||||
<div
|
||||
class="image-wrapper"
|
||||
v-html="documentHtml" />
|
||||
|
@ -15,6 +17,7 @@
|
|||
trap-focus
|
||||
aria-modal
|
||||
aria-role="dialog"
|
||||
:append-to-body="true"
|
||||
custom-class="tainacan-modal">
|
||||
<!-- <div class="tainacan-modal-content">
|
||||
<div class="tainacan-modal-title">
|
||||
|
|
|
@ -333,7 +333,11 @@ export default {
|
|||
this.$store.dispatch('search/setAdminViewMode', adminViewMode);
|
||||
this.updateURLQueries();
|
||||
},
|
||||
setSelectedItemsForIframe(selectedItems) {
|
||||
setSelectedItemsForIframe(selectedItems, singleSelection) {
|
||||
|
||||
if (singleSelection)
|
||||
this.$store.dispatch('search/cleanSelectedItems');
|
||||
|
||||
this.$store.dispatch('search/setSelectedItems', selectedItems);
|
||||
|
||||
let currentSelectedItems = this.$store.getters['search/getSelectedItems'];
|
||||
|
|
|
@ -200,6 +200,26 @@ export const updateItemDocument = ({ commit }, { item_id, document, document_typ
|
|||
});
|
||||
};
|
||||
|
||||
export const fetchOnlyRelatedItems = ({ commit }, { itemId, contextEdit } ) => {
|
||||
|
||||
let endpoint = '/items/'+ itemId + '?';
|
||||
|
||||
if (contextEdit)
|
||||
endpoint += '&context=edit';
|
||||
|
||||
endpoint += '&fetch_only=related_items'
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.tainacan.get(endpoint)
|
||||
.then(res => {
|
||||
let relatedItems = res.data && res.data.related_items ? res.data.related_items : [];
|
||||
commit('setOnlyRelatedItemsToItem', {itemId: itemId, relatedItems: relatedItems });
|
||||
resolve( relatedItems );
|
||||
})
|
||||
.catch((thrown) => reject(thrown));
|
||||
});
|
||||
};
|
||||
|
||||
// Attachments =======================================
|
||||
export const sendAttachment = ( { commit }, { item_id, file }) => {
|
||||
commit('cleanAttachment');
|
||||
|
|
|
@ -62,6 +62,12 @@ export const cleanItemMetadata = (state) => {
|
|||
state.itemMetadata = [];
|
||||
}
|
||||
|
||||
export const setOnlyRelatedItemsToItem = (state, { itemId, relatedItems }) => {
|
||||
if (state.item && state.item.id && state.item.id == itemId) {
|
||||
state.item.related_items = relatedItems;
|
||||
}
|
||||
}
|
||||
|
||||
export const setSingleMetadatum = (state, itemMetadatum) => {
|
||||
|
||||
if (itemMetadatum.metadatum.parent <= 0) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<!-- PAGE TITLE --------------------- -->
|
||||
<tainacan-title
|
||||
v-if="!$route.query.iframemode && !$route.query.readmode && !openAdvancedSearch"
|
||||
v-if="!isIframeMode && !isReadMode && !openAdvancedSearch"
|
||||
:bread-crumb-items="[{ path: '', label: this.$i18n.get('items') }]"/>
|
||||
<div
|
||||
v-else-if="openAdvancedSearch"
|
||||
|
@ -101,7 +101,7 @@
|
|||
<!-- Item Creation Dropdown, only on Admin -->
|
||||
<div
|
||||
class="search-control-item"
|
||||
v-if="!$route.query.iframemode &&
|
||||
v-if="!isIframeMode &&
|
||||
!openAdvancedSearch &&
|
||||
collection &&
|
||||
collection.current_user_can_edit_items">
|
||||
|
@ -413,7 +413,7 @@
|
|||
|
||||
<!-- Exposers or alternative links modal button -->
|
||||
<div
|
||||
v-if="!$route.query.iframemode"
|
||||
v-if="!isIframeMode"
|
||||
class="search-control-item">
|
||||
<button
|
||||
class="button is-white"
|
||||
|
@ -494,7 +494,7 @@
|
|||
|
||||
<!-- STATUS TABS, only on Admin -------- -->
|
||||
<items-status-tabs
|
||||
v-if="!openAdvancedSearch && !$route.query.iframemode"
|
||||
v-if="!openAdvancedSearch && !isIframeMode"
|
||||
:is-repository-level="isRepositoryLevel"/>
|
||||
|
||||
<!-- FILTERS TAG LIST-->
|
||||
|
@ -595,7 +595,7 @@
|
|||
</p>
|
||||
|
||||
<router-link
|
||||
v-if="!isRepositoryLevel && !isSortingByCustomMetadata && !hasFiltered && (status == undefined || status == '') && !$route.query.iframemode"
|
||||
v-if="!isRepositoryLevel && !isSortingByCustomMetadata && !hasFiltered && (status == undefined || status == '') && !isIframeMode"
|
||||
id="button-create-item"
|
||||
tag="button"
|
||||
class="button is-secondary"
|
||||
|
@ -603,7 +603,7 @@
|
|||
{{ $i18n.getFrom('items', 'add_new') }}
|
||||
</router-link>
|
||||
<button
|
||||
v-else-if="isRepositoryLevel && !isSortingByCustomMetadata && !hasFiltered && (status == undefined || status == '') && !$route.query.iframemode"
|
||||
v-else-if="isRepositoryLevel && !isSortingByCustomMetadata && !hasFiltered && (status == undefined || status == '') && !isIframeMode"
|
||||
id="button-create-item"
|
||||
class="button is-secondary"
|
||||
@click="onOpenCollectionsModal">
|
||||
|
@ -731,7 +731,13 @@
|
|||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
},
|
||||
isReadMode () {
|
||||
return this.$route && this.$route.query && this.$route.query.readmode;
|
||||
},
|
||||
isIframeMode () {
|
||||
return this.$route && this.$route.query && this.$route.query.iframemode;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
displayedMetadata() {
|
||||
|
|
|
@ -23,104 +23,8 @@
|
|||
</div>
|
||||
<div class="tainacan-form">
|
||||
<div class="columns">
|
||||
<div class="column is-5">
|
||||
|
||||
<!-- Hook for extra Form options -->
|
||||
<template
|
||||
v-if="formHooks != undefined &&
|
||||
formHooks['view-item'] != undefined &&
|
||||
formHooks['view-item']['begin-left'] != undefined">
|
||||
<div
|
||||
id="view-item-begin-left"
|
||||
class="form-hook-region"
|
||||
v-html="formHooks['view-item']['begin-left'].join('')"/>
|
||||
</template>
|
||||
|
||||
<!-- Document -------------------------------- -->
|
||||
<div class="section-label">
|
||||
<label>{{ item.document !== undefined && item.document !== null && item.document !== ''
|
||||
?
|
||||
$i18n.get('label_document') : $i18n.get('label_document_empty') }}</label>
|
||||
</div>
|
||||
<div class="section-box document-field">
|
||||
<div
|
||||
v-if="item.document !== undefined && item.document !== null &&
|
||||
item.document_type !== undefined && item.document_type !== null &&
|
||||
item.document !== '' && item.document_type !== 'empty'">
|
||||
|
||||
<div v-if="item.document_type === 'attachment'">
|
||||
<!-- <div v-html="item.document_as_html"/> -->
|
||||
<document-item :document-html="item.document_as_html"/>
|
||||
</div>
|
||||
|
||||
<div v-else-if="item.document_type === 'text'">
|
||||
<div v-html="item.document_as_html"/>
|
||||
</div>
|
||||
|
||||
<div v-else-if="item.document_type === 'url'">
|
||||
<div v-html="item.document_as_html"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>{{ $i18n.get('info_no_document_to_item') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Thumbnail -------------------------------- -->
|
||||
<div class="section-label">
|
||||
<label>{{ $i18n.get('label_thumbnail') }}</label>
|
||||
</div>
|
||||
<div 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="178"
|
||||
: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
|
||||
v-if="item.document_type == 'empty'"
|
||||
class="image-placeholder">
|
||||
{{ $i18n.get('label_empty_thumbnail') }}
|
||||
</span>
|
||||
<img
|
||||
:alt="$i18n.get('label_thumbnail')"
|
||||
:src="$thumbHelper.getEmptyThumbnailPlaceholder(item.document_mimetype)">
|
||||
</figure>
|
||||
</div>
|
||||
<br>
|
||||
<div
|
||||
v-if="item.thumbnail_id"
|
||||
class="thumbnail-alt-input">
|
||||
<label class="label">{{ $i18n.get('label_thumbnail_alt') }}</label>
|
||||
<help-button
|
||||
:title="$i18n.get('label_thumbnail_alt')"
|
||||
:message="$i18n.get('info_thumbnail_alt')"/>
|
||||
<p> {{ item.thumbnail_alt }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hook for extra Form options -->
|
||||
<template
|
||||
v-if="formHooks != undefined &&
|
||||
formHooks['view-item'] != undefined &&
|
||||
formHooks['view-item']['end-left'] != undefined">
|
||||
<div
|
||||
id="view-item-end-left"
|
||||
class="form-hook-region"
|
||||
v-html="formHooks['view-item']['end-left'].join('')"/>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<div class="column is-7">
|
||||
<div class="column is-7">
|
||||
|
||||
<!-- Hook for extra Form options -->
|
||||
<template
|
||||
|
@ -253,7 +157,7 @@
|
|||
<b-tabs v-model="activeTab">
|
||||
<b-tab-item>
|
||||
<template slot="header">
|
||||
<span class="icon has-text-gray4">
|
||||
<span class="icon has-text-gray5">
|
||||
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-metadata"/>
|
||||
</span>
|
||||
<span>{{ $i18n.get('metadata') }}</span>
|
||||
|
@ -291,9 +195,38 @@
|
|||
</template>
|
||||
</b-tab-item>
|
||||
|
||||
<!-- Related items -->
|
||||
<b-tab-item v-if="totalRelatedItems">
|
||||
<template slot="header">
|
||||
<span class="icon has-text-gray5">
|
||||
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-processes tainacan-icon-rotate-270"/>
|
||||
</span>
|
||||
<span>
|
||||
{{ $i18n.get('label_related_items') }}
|
||||
<span class="has-text-gray">
|
||||
({{ totalRelatedItems }})
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<div class="attachments-list-heading">
|
||||
<p>
|
||||
{{ $i18n.get("info_related_items") }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<related-items-list
|
||||
:item-id="itemId"
|
||||
:collection-id="collectionId"
|
||||
:related-items="item.related_items"
|
||||
:is-editable="false"
|
||||
:is-loading.sync="isLoading" />
|
||||
|
||||
</b-tab-item>
|
||||
|
||||
<b-tab-item>
|
||||
<template slot="header">
|
||||
<span class="icon has-text-gray4">
|
||||
<span class="icon has-text-gray5">
|
||||
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-attachments"/>
|
||||
</span>
|
||||
<span>
|
||||
|
@ -315,16 +248,118 @@
|
|||
|
||||
<b-tab-item>
|
||||
<template slot="header">
|
||||
<span class="icon has-text-gray4">
|
||||
<span class="icon has-text-gray5">
|
||||
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-activities"/>
|
||||
</span>
|
||||
<span>{{ $i18n.get('activities') }}</span>
|
||||
</template>
|
||||
|
||||
<activities-page v-if="activeTab == 2"/>
|
||||
<activities-page v-if="activeTab == 3"/>
|
||||
</b-tab-item>
|
||||
</b-tabs>
|
||||
</div>
|
||||
|
||||
<div class="column is-5">
|
||||
<div class="sticky-container">
|
||||
|
||||
<!-- Hook for extra Form options -->
|
||||
<template
|
||||
v-if="formHooks != undefined &&
|
||||
formHooks['view-item'] != undefined &&
|
||||
formHooks['view-item']['begin-left'] != undefined">
|
||||
<div
|
||||
id="view-item-begin-left"
|
||||
class="form-hook-region"
|
||||
v-html="formHooks['view-item']['begin-left'].join('')"/>
|
||||
</template>
|
||||
|
||||
<!-- Document -------------------------------- -->
|
||||
<div class="section-label">
|
||||
<label>{{ item.document !== undefined && item.document !== null && item.document !== ''
|
||||
?
|
||||
$i18n.get('label_document') : $i18n.get('label_document_empty') }}</label>
|
||||
</div>
|
||||
<div class="section-box document-field">
|
||||
<div
|
||||
v-if="item.document !== undefined && item.document !== null &&
|
||||
item.document_type !== undefined && item.document_type !== null &&
|
||||
item.document !== '' && item.document_type !== 'empty'">
|
||||
|
||||
<div v-if="item.document_type === 'attachment'">
|
||||
<!-- <div v-html="item.document_as_html"/> -->
|
||||
<document-item :document-html="item.document_as_html"/>
|
||||
</div>
|
||||
|
||||
<div v-else-if="item.document_type === 'text'">
|
||||
<div v-html="item.document_as_html"/>
|
||||
</div>
|
||||
|
||||
<div v-else-if="item.document_type === 'url'">
|
||||
<div v-html="item.document_as_html"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>{{ $i18n.get('info_no_document_to_item') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Thumbnail -------------------------------- -->
|
||||
<div class="section-label">
|
||||
<label>{{ $i18n.get('label_thumbnail') }}</label>
|
||||
</div>
|
||||
<div 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="148"
|
||||
: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
|
||||
v-if="item.document_type == 'empty'"
|
||||
class="image-placeholder">
|
||||
{{ $i18n.get('label_empty_thumbnail') }}
|
||||
</span>
|
||||
<img
|
||||
:alt="$i18n.get('label_thumbnail')"
|
||||
:src="$thumbHelper.getEmptyThumbnailPlaceholder(item.document_mimetype)">
|
||||
</figure>
|
||||
</div>
|
||||
<br>
|
||||
<div
|
||||
v-if="item.thumbnail_id"
|
||||
class="thumbnail-alt-input">
|
||||
<label class="label">{{ $i18n.get('label_thumbnail_alt') }}</label>
|
||||
<help-button
|
||||
:title="$i18n.get('label_thumbnail_alt')"
|
||||
:message="$i18n.get('info_thumbnail_alt')"/>
|
||||
<p> {{ item.thumbnail_alt }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hook for extra Form options -->
|
||||
<template
|
||||
v-if="formHooks != undefined &&
|
||||
formHooks['view-item'] != undefined &&
|
||||
formHooks['view-item']['end-left'] != undefined">
|
||||
<div
|
||||
id="view-item-end-left"
|
||||
class="form-hook-region"
|
||||
v-html="formHooks['view-item']['end-left'].join('')"/>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<footer class="footer">
|
||||
<div class="form-submission-footer">
|
||||
|
@ -380,6 +415,7 @@
|
|||
import ActivitiesPage from '../lists/activities-page.vue';
|
||||
import ExposersModal from '../../components/modals/exposers-modal.vue';
|
||||
import AttachmentsList from '../../components/lists/attachments-list.vue';
|
||||
import RelatedItemsList from '../../components/lists/related-items-list.vue';
|
||||
|
||||
export default {
|
||||
name: 'ItemPage',
|
||||
|
@ -387,6 +423,7 @@
|
|||
FileItem,
|
||||
DocumentItem,
|
||||
ActivitiesPage,
|
||||
RelatedItemsList,
|
||||
AttachmentsList
|
||||
},
|
||||
mixins: [formHooks],
|
||||
|
@ -414,6 +451,9 @@
|
|||
metadatumList() {
|
||||
return JSON.parse(JSON.stringify(this.getItemMetadata()));
|
||||
},
|
||||
totalRelatedItems() {
|
||||
return (this.item && this.item.related_items) ? Object.values(this.item.related_items).reduce((totalItems, aRelatedItemsGroup) => totalItems + parseInt(aRelatedItemsGroup.total_items), 0) : false;
|
||||
},
|
||||
totalAttachments() {
|
||||
return this.getTotalAttachments();
|
||||
},
|
||||
|
@ -437,7 +477,7 @@
|
|||
this.fetchItem({
|
||||
itemId: this.itemId,
|
||||
contextEdit: true,
|
||||
fetchOnly: 'title,thumbnail,status,modification_date,document_type,document_mimetype,document,comment_status,document_as_html'
|
||||
fetchOnly: 'title,thumbnail,status,modification_date,document_type,document_mimetype,document,comment_status,document_as_html,related_items'
|
||||
})
|
||||
.then((resp) => {
|
||||
resp.request.then((item) => {
|
||||
|
@ -558,13 +598,20 @@
|
|||
padding-left: var(--tainacan-one-column);
|
||||
padding-right: var(--tainacan-one-column);
|
||||
|
||||
.sticky-container {
|
||||
position: relative;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
margin: 3px 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 769px) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.column.is-7 {
|
||||
padding-left: 0;
|
||||
padding-right: var(--tainacan-one-column);
|
||||
padding-left: var(--tainacan-one-column);
|
||||
padding-right: 0;
|
||||
|
||||
.columns {
|
||||
flex-wrap: wrap;
|
||||
|
@ -580,7 +627,7 @@
|
|||
}
|
||||
|
||||
@media screen and (max-width: 769px) {
|
||||
padding-left: var(--tainacan-one-column);
|
||||
padding-right: var(--tainacan-one-column);
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
@ -625,8 +672,8 @@
|
|||
.section-box {
|
||||
background-color: var(--tainacan-white);
|
||||
padding: 0 var(--tainacan-one-column) 0 0;
|
||||
margin-top: 18px;
|
||||
margin-bottom: 32px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 18px;
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
|
@ -700,20 +747,31 @@
|
|||
font-size: 0.8em;
|
||||
}
|
||||
img {
|
||||
height: 178px;
|
||||
width: 178px;
|
||||
height: 148px;
|
||||
width: 148px;
|
||||
}
|
||||
.image-placeholder {
|
||||
position: absolute;
|
||||
margin-left: 45px;
|
||||
margin-right: 45px;
|
||||
margin-left: 32px;
|
||||
margin-right: 32px;
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
z-index: 99;
|
||||
text-align: center;
|
||||
color: var(--tainacan-info-color);
|
||||
top: 70px;
|
||||
max-width: 90px;
|
||||
top: 60px;
|
||||
max-width: 84px;
|
||||
}
|
||||
}
|
||||
|
||||
.attachments-list-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 24px;
|
||||
|
||||
button {
|
||||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -548,4 +548,13 @@
|
|||
-moz-animation: skeleton-animation 1.8s ease infinite;
|
||||
-o-animation: skeleton-animation 1.8s ease infinite;
|
||||
animation: skeleton-animation 1.8s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes metadatum-highlight {
|
||||
from {
|
||||
background-color: var(--tainacan-primary1);
|
||||
}
|
||||
to {
|
||||
background-color: var(--tainacan-white);
|
||||
}
|
||||
}
|
|
@ -76,7 +76,8 @@
|
|||
.tainacan-table {
|
||||
tr.selected-row {
|
||||
background-color: var(--tainacan-blue1) !important;
|
||||
.checkbox-cell .checkbox, .actions-cell .actions-container {
|
||||
.checkbox-cell .checkbox, .actions-cell .actions-container,
|
||||
.checkbox-cell .radio, .actions-cell .actions-container {
|
||||
background-color: var(--tainacan-blue2) !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@
|
|||
top: auto;
|
||||
display: table-cell;
|
||||
|
||||
label.checkbox {
|
||||
label.checkbox,
|
||||
label.radio {
|
||||
border-radius: 0px;
|
||||
background-color: var(--tainacan-white);
|
||||
padding: 0;
|
||||
|
@ -69,7 +70,8 @@
|
|||
justify-content: center;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
.b-checkbox.checkbox .control-label {
|
||||
.b-checkbox.checkbox .control-label,
|
||||
.b-radio.radio .control-label {
|
||||
display: none;
|
||||
}
|
||||
&.is-selecting {
|
||||
|
@ -258,6 +260,9 @@
|
|||
.checkbox {
|
||||
background-color: var(--tainacan-item-heading-hover-background-color) !important;
|
||||
}
|
||||
.radio {
|
||||
background-color: var(--tainacan-item-heading-hover-background-color) !important;
|
||||
}
|
||||
}
|
||||
.actions-cell {
|
||||
.actions-container {
|
||||
|
|
|
@ -29,11 +29,8 @@
|
|||
text-transform: inherit;
|
||||
font-size: 0.875em;
|
||||
color: var(--tainacan-label-color);
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
vertical-align: top;
|
||||
display: inline;
|
||||
line-height: 2.0em;
|
||||
}
|
||||
.section-label>label {
|
||||
cursor: default;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
bottom: 0;
|
||||
margin-bottom: -25px;
|
||||
padding-right: 12px;
|
||||
margin-bottom: -25px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
visibility: hidden;
|
||||
|
|
|
@ -12,6 +12,7 @@ const TAINACAN_BLOCKS = [
|
|||
'carousel-items-list' => [ 'has_theme_script' => true ],
|
||||
'carousel-terms-list' => [ 'has_theme_script' => true ],
|
||||
'carousel-collections-list' => [ 'has_theme_script' => true ],
|
||||
'carousel-related-items' => [],
|
||||
'terms-list' => [ 'extra_editor_script_deps' => array('undescore') ],
|
||||
];
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@
|
|||
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
|
||||
<path
|
||||
d="M0 0h24v24H0z"
|
||||
fill="none"/>
|
||||
fill="none"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -142,7 +142,7 @@
|
|||
color: var(--tainacan-block-gray5, $gray5);
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
padding: 8px 16px;
|
||||
padding: 8px 12px;
|
||||
display: block;
|
||||
line-height: 1.2em;
|
||||
word-break: break-word;
|
||||
|
|
|
@ -11,7 +11,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
|
||||
// Gets all divs with content created by our block;
|
||||
let blocks = document.getElementsByClassName('wp-block-tainacan-carousel-items-list');
|
||||
|
||||
|
||||
if (blocks) {
|
||||
let blockIds = Object.values(blocks).map((block) => block.id);
|
||||
|
||||
|
|
|
@ -284,7 +284,15 @@ export default {
|
|||
|
||||
this.itemsRequestSource = axios.CancelToken.source();
|
||||
|
||||
if (this.loadStrategy == 'selection') {
|
||||
if (this.loadStrategy == 'parent') {
|
||||
|
||||
for (let item of this.selectedItems)
|
||||
this.items.push(item);
|
||||
|
||||
this.isLoading = false;
|
||||
this.totalItems = this.items.length;
|
||||
|
||||
} else if (this.loadStrategy == 'selection') {
|
||||
let endpoint = '/collection/' + this.collectionId + '/items?' + qs.stringify({ postin: this.selectedItems, perpage: this.selectedItems.length }) + '&fetch_only=title,url,thumbnail';
|
||||
|
||||
this.tainacanAxios.get(endpoint, { cancelToken: this.itemsRequestSource.token })
|
||||
|
@ -354,7 +362,7 @@ export default {
|
|||
fetchCollectionForHeader() {
|
||||
if (this.showCollectionHeader) {
|
||||
|
||||
this.isLoadingCollection = true;
|
||||
this.isLoadingCollection = true;
|
||||
|
||||
this.tainacanAxios.get('/collections/' + this.collectionId + '?fetch_only=name,thumbnail,header_image')
|
||||
.then(response => {
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
color: var(--tainacan-block-gray5, $gray5);
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
padding: 8px 16px;
|
||||
padding: 8px 12px;
|
||||
display: block;
|
||||
line-height: 1.2em;
|
||||
word-break: break-word;
|
||||
|
|
|
@ -219,23 +219,35 @@ registerBlockType('tainacan/carousel-items-list', {
|
|||
);
|
||||
}
|
||||
|
||||
function setContent(){
|
||||
function setContent() {
|
||||
isLoading = true;
|
||||
|
||||
setAttributes({
|
||||
isLoading: isLoading
|
||||
});
|
||||
|
||||
if (itemsRequestSource != undefined && typeof itemsRequestSource == 'function')
|
||||
itemsRequestSource.cancel('Previous items search canceled.');
|
||||
|
||||
itemsRequestSource = axios.CancelToken.source();
|
||||
|
||||
items = [];
|
||||
|
||||
if (loadStrategy == 'selection') {
|
||||
let endpoint = '/collection/' + collectionId + '/items?'+ qs.stringify({ postin: selectedItems, perpage: selectedItems.length }) + '&fetch_only=title,url,thumbnail';
|
||||
if (loadStrategy == 'parent') {
|
||||
|
||||
for (let item of selectedItems)
|
||||
items.push(prepareItem(item));
|
||||
|
||||
setAttributes({
|
||||
content: <div></div>,
|
||||
items: items,
|
||||
isLoading: false
|
||||
});
|
||||
|
||||
} else if (loadStrategy == 'selection') {
|
||||
|
||||
if (itemsRequestSource != undefined && typeof itemsRequestSource == 'function')
|
||||
itemsRequestSource.cancel('Previous items search canceled.');
|
||||
|
||||
itemsRequestSource = axios.CancelToken.source();
|
||||
|
||||
let endpoint = '/collection/' + collectionId + '/items?'+ qs.stringify({ postin: selectedItems, perpage: selectedItems.length }) + '&fetch_only=title,url,thumbnail';
|
||||
|
||||
tainacan.get(endpoint, { cancelToken: itemsRequestSource.token })
|
||||
.then(response => {
|
||||
|
||||
|
@ -255,6 +267,11 @@ registerBlockType('tainacan/carousel-items-list', {
|
|||
let query = endpoint.split('?')[1];
|
||||
let queryObject = qs.parse(query);
|
||||
|
||||
if (itemsRequestSource != undefined && typeof itemsRequestSource == 'function')
|
||||
itemsRequestSource.cancel('Previous items search canceled.');
|
||||
|
||||
itemsRequestSource = axios.CancelToken.source();
|
||||
|
||||
// Set up max items to be shown
|
||||
if (maxItemsNumber != undefined && maxItemsNumber > 0)
|
||||
queryObject.perpage = maxItemsNumber;
|
||||
|
@ -365,32 +382,35 @@ registerBlockType('tainacan/carousel-items-list', {
|
|||
|
||||
{ items.length ?
|
||||
<BlockControls>
|
||||
{ loadStrategy != 'search' ?
|
||||
TainacanBlocksCompatToolbar({
|
||||
label: __('Add more items', 'tainacan'),
|
||||
icon: <svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
height="24px"
|
||||
width="24px">
|
||||
<path d="M16,6H12a2,2,0,0,0-2,2v6.52A6,6,0,0,1,12,19a6,6,0,0,1-.73,2.88A1.92,1.92,0,0,0,12,22h8a2,2,0,0,0,2-2V12Zm-1,6V7.5L19.51,12ZM15,2V4H8v9.33A5.8,5.8,0,0,0,6,13V4A2,2,0,0,1,8,2ZM10.09,19.05,7,22.11V16.05L8,17l2,2ZM5,16.05v6.06L2,19.11Z"/>
|
||||
</svg>,
|
||||
onClick: openCarouseltemsModal,
|
||||
onClickParams: 'selection'
|
||||
})
|
||||
:
|
||||
TainacanBlocksCompatToolbar({
|
||||
label: __('Configure a search', 'tainacan'),
|
||||
icon: <svg
|
||||
{ loadStrategy != 'parent' ?
|
||||
(
|
||||
loadStrategy != 'search' ?
|
||||
TainacanBlocksCompatToolbar({
|
||||
label: __('Add more items', 'tainacan'),
|
||||
icon: <svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
height="24px"
|
||||
width="24px">
|
||||
<path d="M16,6H12a2,2,0,0,0-2,2v6.52A6,6,0,0,1,12,19a6,6,0,0,1-.73,2.88A1.92,1.92,0,0,0,12,22h8a2,2,0,0,0,2-2V12Zm-1,6V7.5L19.51,12ZM15,2V4H8v9.33A5.8,5.8,0,0,0,6,13V4A2,2,0,0,1,8,2ZM10.09,19.05,7,22.11V16.05L8,17l2,2ZM5,16.05v6.06L2,19.11Z"/>
|
||||
</svg>,
|
||||
onClick: openCarouseltemsModal,
|
||||
onClickParams: 'search'
|
||||
})
|
||||
viewBox="0 0 24 24"
|
||||
height="24px"
|
||||
width="24px">
|
||||
<path d="M16,6H12a2,2,0,0,0-2,2v6.52A6,6,0,0,1,12,19a6,6,0,0,1-.73,2.88A1.92,1.92,0,0,0,12,22h8a2,2,0,0,0,2-2V12Zm-1,6V7.5L19.51,12ZM15,2V4H8v9.33A5.8,5.8,0,0,0,6,13V4A2,2,0,0,1,8,2ZM10.09,19.05,7,22.11V16.05L8,17l2,2ZM5,16.05v6.06L2,19.11Z"/>
|
||||
</svg>,
|
||||
onClick: openCarouseltemsModal,
|
||||
onClickParams: 'selection'
|
||||
})
|
||||
:
|
||||
TainacanBlocksCompatToolbar({
|
||||
label: __('Configure a search', 'tainacan'),
|
||||
icon: <svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
height="24px"
|
||||
width="24px">
|
||||
<path d="M16,6H12a2,2,0,0,0-2,2v6.52A6,6,0,0,1,12,19a6,6,0,0,1-.73,2.88A1.92,1.92,0,0,0,12,22h8a2,2,0,0,0,2-2V12Zm-1,6V7.5L19.51,12ZM15,2V4H8v9.33A5.8,5.8,0,0,0,6,13V4A2,2,0,0,1,8,2ZM10.09,19.05,7,22.11V16.05L8,17l2,2ZM5,16.05v6.06L2,19.11Z"/>
|
||||
</svg>,
|
||||
onClick: openCarouseltemsModal,
|
||||
onClickParams: 'search'
|
||||
})
|
||||
) : null
|
||||
}
|
||||
</BlockControls>
|
||||
: null }
|
||||
|
@ -461,18 +481,22 @@ registerBlockType('tainacan/carousel-items-list', {
|
|||
initialOpen={ true }
|
||||
>
|
||||
<div>
|
||||
<RangeControl
|
||||
label={ __('Maximum items per slide on a wide screen', 'tainacan') }
|
||||
help={ maxItemsPerScreen <= 4 ? __('Warning: with such a small number of items per slide, the image size is greater, thus the cropped version of the thumbnail won\'t be used.', 'tainacan') : null }
|
||||
value={ maxItemsPerScreen ? maxItemsPerScreen : 7 }
|
||||
onChange={ ( aMaxItemsPerScreen ) => {
|
||||
maxItemsPerScreen = aMaxItemsPerScreen;
|
||||
setAttributes( { maxItemsPerScreen: aMaxItemsPerScreen } );
|
||||
setContent();
|
||||
}}
|
||||
min={ 1 }
|
||||
max={ 9 }
|
||||
/>
|
||||
{
|
||||
loadStrategy != 'parent' ?
|
||||
<RangeControl
|
||||
label={ __('Maximum items per slide on a wide screen', 'tainacan') }
|
||||
help={ maxItemsPerScreen <= 4 ? __('Warning: with such a small number of items per slide, the image size is greater, thus the cropped version of the thumbnail won\'t be used.', 'tainacan') : null }
|
||||
value={ maxItemsPerScreen ? maxItemsPerScreen : 7 }
|
||||
onChange={ ( aMaxItemsPerScreen ) => {
|
||||
maxItemsPerScreen = aMaxItemsPerScreen;
|
||||
setAttributes( { maxItemsPerScreen: aMaxItemsPerScreen } );
|
||||
setContent();
|
||||
}}
|
||||
min={ 1 }
|
||||
max={ 9 }
|
||||
/>
|
||||
: null
|
||||
}
|
||||
<ToggleControl
|
||||
label={__('Crop Images', 'tainacan')}
|
||||
help={ cropImagesToSquare && maxItemsPerScreen > 4 ? __('Do not use square cropeed version of the item thumbnail.', 'tainacan') : __('Toggle to use square cropped version of the item thumbnail.', 'tainacan') }
|
||||
|
@ -696,19 +720,25 @@ registerBlockType('tainacan/carousel-items-list', {
|
|||
</svg>
|
||||
{__('List items on a Carousel, using search or item selection.', 'tainacan')}
|
||||
</p>
|
||||
<Button
|
||||
isPrimary
|
||||
type="button"
|
||||
onClick={ () => openCarouseltemsModal('selection') }>
|
||||
{__('Select Items', 'tainacan')}
|
||||
</Button>
|
||||
<p style={{ margin: '0 12px' }}>{__('or', 'tainacan')}</p>
|
||||
<Button
|
||||
isPrimary
|
||||
type="button"
|
||||
onClick={ () => openCarouseltemsModal('search') }>
|
||||
{__('Configure a search', 'tainacan')}
|
||||
</Button>
|
||||
{
|
||||
loadStrategy != 'parent' ?
|
||||
<div>
|
||||
<Button
|
||||
isPrimary
|
||||
type="button"
|
||||
onClick={ () => openCarouseltemsModal('selection') }>
|
||||
{__('Select Items', 'tainacan')}
|
||||
</Button>
|
||||
<p style={{ margin: '0 12px' }}>{__('or', 'tainacan')}</p>
|
||||
<Button
|
||||
isPrimary
|
||||
type="button"
|
||||
onClick={ () => openCarouseltemsModal('search') }>
|
||||
{__('Configure a search', 'tainacan')}
|
||||
</Button>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</Placeholder>
|
||||
) : null
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export default [];
|
|
@ -0,0 +1,348 @@
|
|||
import tainacan from '../../js/axios.js';
|
||||
import axios from 'axios';
|
||||
|
||||
const { __ } = wp.i18n;
|
||||
|
||||
const { TextControl, Button, Modal, RadioControl, SelectControl, Spinner } = wp.components;
|
||||
|
||||
export default class CarouselRelatedItemsModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
// Initialize state
|
||||
this.state = {
|
||||
collectionsPerPage: 24,
|
||||
collectionId: undefined,
|
||||
itemId: undefined,
|
||||
collectionName: '',
|
||||
isLoadingCollections: false,
|
||||
modalCollections: [],
|
||||
totalModalCollections: 0,
|
||||
collectionOrderBy: 'date-desc',
|
||||
collectionPage: 1,
|
||||
temporaryCollectionId: '',
|
||||
temporaryItemId: '',
|
||||
searchCollectionName: '',
|
||||
collections: [],
|
||||
collectionsRequestSource: undefined,
|
||||
searchURL: '',
|
||||
itemsPerPage: 12
|
||||
};
|
||||
|
||||
// Bind events
|
||||
this.resetCollections = this.resetCollections.bind(this);
|
||||
this.selectCollection = this.selectCollection.bind(this);
|
||||
this.fetchCollections = this.fetchCollections.bind(this);
|
||||
this.fetchModalCollections = this.fetchModalCollections.bind(this);
|
||||
this.fetchCollection = this.fetchCollection.bind(this);
|
||||
this.applyRelatedItem = this.applyRelatedItem.bind(this);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
|
||||
this.setState({
|
||||
collectionId: this.props.existingCollectionId,
|
||||
itemId: this.props.existingItemId
|
||||
});
|
||||
|
||||
if (this.props.existingCollectionId != null && this.props.existingCollectionId != undefined) {
|
||||
this.fetchCollection(this.props.existingCollectionId);
|
||||
this.setState({
|
||||
searchURL: tainacan_blocks.admin_url + 'admin.php?page=tainacan_admin#/collections/'+ this.props.existingCollectionId + '/items/?singleselectionmode=true&iframemode=true&status=publish'
|
||||
});
|
||||
} else {
|
||||
this.setState({ collectionPage: 1 });
|
||||
this.fetchModalCollections();
|
||||
}
|
||||
}
|
||||
|
||||
// COLLECTIONS RELATED --------------------------------------------------
|
||||
fetchModalCollections() {
|
||||
|
||||
let someModalCollections = this.state.modalCollections;
|
||||
if (this.state.collectionPage <= 1)
|
||||
someModalCollections = [];
|
||||
|
||||
let endpoint = '/collections/?perpage=' + this.state.collectionsPerPage + '&paged=' + this.state.collectionPage;
|
||||
|
||||
if (this.state.collectionOrderBy == 'date')
|
||||
endpoint += '&orderby=date&order=asc';
|
||||
else if (this.state.collectionOrderBy == 'date-desc')
|
||||
endpoint += '&orderby=date&order=desc';
|
||||
else if (this.state.collectionOrderBy == 'title')
|
||||
endpoint += '&orderby=title&order=asc';
|
||||
else if (this.state.collectionOrderBy == 'title-desc')
|
||||
endpoint += '&orderby=title&order=desc';
|
||||
|
||||
this.setState({
|
||||
isLoadingCollections: true,
|
||||
collectionPage: this.state.collectionPage + 1,
|
||||
modalCollections: someModalCollections
|
||||
});
|
||||
|
||||
tainacan.get(endpoint)
|
||||
.then(response => {
|
||||
|
||||
let otherModalCollections = this.state.modalCollections;
|
||||
for (let collection of response.data) {
|
||||
otherModalCollections.push({
|
||||
name: collection.name,
|
||||
id: collection.id
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isLoadingCollections: false,
|
||||
modalCollections: otherModalCollections,
|
||||
totalModalCollections: response.headers['x-wp-total']
|
||||
});
|
||||
|
||||
return otherModalCollections;
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('Error trying to fetch collections: ' + error);
|
||||
});
|
||||
}
|
||||
|
||||
fetchCollection(collectionId) {
|
||||
tainacan.get('/collections/' + collectionId)
|
||||
.then((response) => {
|
||||
this.setState({ collectionName: response.data.name });
|
||||
}).catch(error => {
|
||||
console.log('Error trying to fetch collection: ' + error);
|
||||
});
|
||||
}
|
||||
|
||||
selectCollection(selectedCollectionId) {
|
||||
this.setState({
|
||||
collectionId: selectedCollectionId,
|
||||
searchURL: tainacan_blocks.admin_url + 'admin.php?page=tainacan_admin#/collections/' + selectedCollectionId + '/items/?singleselectionmode=true&iframemode=true&status=publish'
|
||||
});
|
||||
|
||||
this.props.onSelectCollection(selectedCollectionId);
|
||||
this.fetchCollection(selectedCollectionId);
|
||||
}
|
||||
|
||||
fetchCollections(name) {
|
||||
|
||||
if (this.state.collectionsRequestSource != undefined)
|
||||
this.state.collectionsRequestSource.cancel('Previous collections search canceled.');
|
||||
|
||||
let aCollectionRequestSource = axios.CancelToken.source();
|
||||
|
||||
this.setState({
|
||||
collectionsRequestSource: aCollectionRequestSource,
|
||||
isLoadingCollections: true,
|
||||
collections: [],
|
||||
items: []
|
||||
});
|
||||
|
||||
let endpoint = '/collections/?perpage=' + this.state.collectionsPerPage;
|
||||
if (name != undefined && name != '')
|
||||
endpoint += '&search=' + name;
|
||||
|
||||
if (this.state.collectionOrderBy == 'date')
|
||||
endpoint += '&orderby=date&order=asc';
|
||||
else if (this.state.collectionOrderBy == 'date-desc')
|
||||
endpoint += '&orderby=date&order=desc';
|
||||
else if (this.state.collectionOrderBy == 'title')
|
||||
endpoint += '&orderby=title&order=asc';
|
||||
else if (this.state.collectionOrderBy == 'title-desc')
|
||||
endpoint += '&orderby=title&order=desc';
|
||||
|
||||
tainacan.get(endpoint, { cancelToken: aCollectionRequestSource.token })
|
||||
.then(response => {
|
||||
let someCollections = response.data.map((collection) => ({ name: collection.name, id: collection.id + '' }));
|
||||
|
||||
this.setState({
|
||||
isLoadingCollections: false,
|
||||
collections: someCollections
|
||||
});
|
||||
|
||||
return someCollections;
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('Error trying to fetch collections: ' + error);
|
||||
});
|
||||
}
|
||||
|
||||
applyRelatedItem() {
|
||||
let iframe = document.getElementById("itemsFrame");
|
||||
if (iframe) {
|
||||
let params = new URLSearchParams(iframe.contentWindow.location.search);
|
||||
let selectedItems = params.getAll('selecteditems');
|
||||
params.delete('selecteditems')
|
||||
this.props.onApplyRelatedItem(selectedItems[0]);
|
||||
}
|
||||
}
|
||||
|
||||
resetCollections() {
|
||||
|
||||
this.setState({
|
||||
collectionId: null,
|
||||
collectionPage: 1,
|
||||
modalCollections: []
|
||||
});
|
||||
this.fetchModalCollections();
|
||||
}
|
||||
|
||||
cancelSelection() {
|
||||
|
||||
this.setState({
|
||||
modalCollections: []
|
||||
});
|
||||
|
||||
this.props.onCancelSelection();
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.state.collectionId != null && this.state.collectionId != undefined ? (
|
||||
// Items modal
|
||||
<Modal
|
||||
className="wp-block-tainacan-modal dynamic-modal"
|
||||
title={ __('Select one item that has relations', 'tainacan') }
|
||||
onRequestClose={ () => this.cancelSelection() }
|
||||
shouldCloseOnClickOutside={ false }
|
||||
contentLabel={ __('Select onte item that has relations', 'tainacan') }>
|
||||
<iframe
|
||||
id="itemsFrame"
|
||||
src={ this.state.searchURL } />
|
||||
<div className="modal-footer-area">
|
||||
<Button
|
||||
isSecondary
|
||||
onClick={ () => { this.resetCollections() }}>
|
||||
{__('Switch collection', 'tainacan')}
|
||||
</Button>
|
||||
<Button
|
||||
style={{ marginLeft: 'auto' }}
|
||||
isPrimary
|
||||
onClick={ () => this.applyRelatedItem() }>
|
||||
{__('Get relations of this item', 'tainacan')}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
) : (
|
||||
// Collections modal
|
||||
<Modal
|
||||
className="wp-block-tainacan-modal"
|
||||
title={__('Select a collection to fetch items from', 'tainacan')}
|
||||
onRequestClose={ () => this.cancelSelection() }
|
||||
shouldCloseOnClickOutside={ false }
|
||||
contentLabel={__('Select item', 'tainacan')}>
|
||||
<div>
|
||||
<div className="modal-search-area">
|
||||
<TextControl
|
||||
label={__('Search for a collection', 'tainacan')}
|
||||
placeholder={ __('Search by collection\'s name', 'tainacan') }
|
||||
value={ this.state.searchCollectionName }
|
||||
onChange={(value) => {
|
||||
this.setState({
|
||||
searchCollectionName: value
|
||||
});
|
||||
_.debounce(this.fetchCollections(value), 300);
|
||||
}}/>
|
||||
<SelectControl
|
||||
label={__('Order by', 'tainacan')}
|
||||
value={ this.state.collectionOrderBy }
|
||||
options={ [
|
||||
{ label: __('Latest', 'tainacan'), value: 'date-desc' },
|
||||
{ label: __('Oldest', 'tainacan'), value: 'date' },
|
||||
{ label: __('Name (A-Z)', 'tainacan'), value: 'title' },
|
||||
{ label: __('Name (Z-A)', 'tainacan'), value: 'title-desc' }
|
||||
] }
|
||||
onChange={ ( aCollectionOrderBy ) => {
|
||||
this.state.collectionOrderBy = aCollectionOrderBy;
|
||||
this.state.collectionPage = 1;
|
||||
this.setState({
|
||||
collectionOrderBy: this.state.collectionOrderBy,
|
||||
collectionPage: this.state.collectionPage
|
||||
});
|
||||
if (this.state.searchCollectionName && this.state.searchCollectionName != '') {
|
||||
this.fetchCollections(this.state.searchCollectionName);
|
||||
} else {
|
||||
this.fetchModalCollections();
|
||||
}
|
||||
}}/>
|
||||
</div>
|
||||
{(
|
||||
this.state.searchCollectionName != '' ? (
|
||||
this.state.collections.length > 0 ?
|
||||
(
|
||||
<div>
|
||||
<div className="modal-radio-list">
|
||||
{
|
||||
<RadioControl
|
||||
selected={ this.state.temporaryCollectionId }
|
||||
options={
|
||||
this.state.collections.map((collection) => {
|
||||
return { label: collection.name, value: '' + collection.id }
|
||||
})
|
||||
}
|
||||
onChange={ ( aCollectionId ) => {
|
||||
this.setState({ temporaryCollectionId: aCollectionId });
|
||||
} } />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
) :
|
||||
this.state.isLoadingCollections ? (
|
||||
<Spinner />
|
||||
) :
|
||||
<div className="modal-loadmore-section">
|
||||
<p>{ __('Sorry, no collection found.', 'tainacan') }</p>
|
||||
</div>
|
||||
):
|
||||
this.state.modalCollections.length > 0 ?
|
||||
(
|
||||
<div>
|
||||
<div className="modal-radio-list">
|
||||
{
|
||||
<RadioControl
|
||||
selected={ this.state.temporaryCollectionId }
|
||||
options={
|
||||
this.state.modalCollections.map((collection) => {
|
||||
return { label: collection.name, value: '' + collection.id }
|
||||
})
|
||||
}
|
||||
onChange={ ( aCollectionId ) => {
|
||||
this.setState({ temporaryCollectionId: aCollectionId });
|
||||
} } />
|
||||
}
|
||||
</div>
|
||||
<div className="modal-loadmore-section">
|
||||
<p>{ __('Showing', 'tainacan') + " " + this.state.modalCollections.length + " " + __('of', 'tainacan') + " " + this.state.totalModalCollections + " " + __('collections', 'tainacan') + "."}</p>
|
||||
{
|
||||
this.state.modalCollections.length < this.state.totalModalCollections ? (
|
||||
<Button
|
||||
isSecondary
|
||||
isSmall
|
||||
onClick={ () => this.fetchModalCollections() }>
|
||||
{__('Load more', 'tainacan')}
|
||||
</Button>
|
||||
) : null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
) : this.state.isLoadingCollections ? <Spinner/> :
|
||||
<div className="modal-loadmore-section">
|
||||
<p>{ __('Sorry, no collection found.', 'tainacan') }</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="modal-footer-area">
|
||||
<Button
|
||||
isSecondary
|
||||
onClick={ () => { this.cancelSelection() }}>
|
||||
{__('Cancel', 'tainacan')}
|
||||
</Button>
|
||||
<Button
|
||||
isPrimary
|
||||
disabled={ this.state.temporaryCollectionId == undefined || this.state.temporaryCollectionId == null || this.state.temporaryCollectionId == ''}
|
||||
onClick={ () => { this.selectCollection(this.state.temporaryCollectionId); } }>
|
||||
{ __('Select item', 'tainacan') }
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
@import '../../gutenberg-blocks-variables.scss';
|
||||
|
||||
.wp-block-tainacan-carousel-related-items {
|
||||
margin: 0.5em auto;
|
||||
width: 100%;
|
||||
|
||||
// Spinner
|
||||
.spinner-container {
|
||||
min-height: 56px;
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: var(--tainacan-block-gray4, $gray4);
|
||||
}
|
||||
|
||||
// Skeleton loading
|
||||
@-webkit-keyframes skeleton-animation {
|
||||
0%{opacity: 1.0}
|
||||
50%{opacity: 0.2}
|
||||
100%{opacity: 1.0}
|
||||
}
|
||||
@-moz-keyframes skeleton-animation {
|
||||
0%{opacity: 1.0}
|
||||
50%{opacity: 0.2}
|
||||
100%{opacity: 1.0}
|
||||
}
|
||||
@-o-keyframes skeleton-animation {
|
||||
0%{opacity: 1.0}
|
||||
50%{opacity: 0.2}
|
||||
100%{opacity: 1.0}
|
||||
}
|
||||
@keyframes skeleton-animation {
|
||||
0%{opacity: 1.0}
|
||||
50%{opacity: 0.2}
|
||||
100%{opacity: 1.0}
|
||||
}
|
||||
.skeleton {
|
||||
border-radius: 2px;
|
||||
background: var(--tainacan-block-gray1, $gray1);
|
||||
|
||||
-webkit-animation: skeleton-animation 1.8s ease infinite;
|
||||
-moz-animation: skeleton-animation 1.8s ease infinite;
|
||||
-o-animation: skeleton-animation 1.8s ease infinite;
|
||||
animation: skeleton-animation 1.8s ease infinite;
|
||||
}
|
||||
|
||||
// Placeholder on editor side ----------------------------------------------------
|
||||
.carousel-related-items-edit-container {
|
||||
position: relative;
|
||||
|
||||
& .skeleton {
|
||||
min-height: 150px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
const { registerBlockType } = wp.blocks;
|
||||
|
||||
const { __ } = wp.i18n;
|
||||
|
||||
const { Spinner, Button, Placeholder } = wp.components;
|
||||
|
||||
const { InnerBlocks} = ( tainacan_blocks.wp_version < '5.2' ? wp.editor : wp.blockEditor );
|
||||
|
||||
import CarouselRelatedItemsModal from './carousel-related-items-modal.js';
|
||||
import tainacan from '../../js/axios.js';
|
||||
import axios from 'axios';
|
||||
import DeprecatedBlocks from './carousel-related-items-deprecated.js';
|
||||
import 'swiper/css/swiper.min.css';
|
||||
|
||||
registerBlockType('tainacan/carousel-related-items', {
|
||||
title: __('Tainacan Related Items Carousel', 'tainacan'),
|
||||
icon:
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
height="24px"
|
||||
width="24px">
|
||||
<path
|
||||
fill="#298596"
|
||||
d="M16,6H12a2,2,0,0,0-2,2v6.52A6,6,0,0,1,12,19a6,6,0,0,1-.73,2.88A1.92,1.92,0,0,0,12,22h8a2,2,0,0,0,2-2V12Zm-1,6V7.5L19.51,12ZM15,2V4H8v9.33A5.8,5.8,0,0,0,6,13V4A2,2,0,0,1,8,2ZM10.09,19.05,7,22.11V16.05L8,17l2,2ZM5,16.05v6.06L2,19.11Z"/>
|
||||
</svg>,
|
||||
category: 'tainacan-blocks',
|
||||
keywords: [ __( 'items', 'tainacan' ), __( 'carousel', 'tainacan' ), __( 'slider', 'tainacan' ), __( 'relationship', 'tainacan' ) ],
|
||||
description: __('A set of carousels to list items related to a certain item via relationship metadata.', 'tainacan'),
|
||||
example: {
|
||||
attributes: {
|
||||
content: 'preview'
|
||||
}
|
||||
},
|
||||
parent: [], // Hides this block while we manage better update logic for its inner blocks.
|
||||
attributes: {
|
||||
content: {
|
||||
type: 'array',
|
||||
source: 'children',
|
||||
selector: 'div'
|
||||
},
|
||||
collectionId: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
itemId: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
isModalOpen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
relatedItems: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
relatedItemsTemplate: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
itemRequestSource: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
},
|
||||
supports: {
|
||||
align: ['full', 'wide'],
|
||||
html: false,
|
||||
multiple: true,
|
||||
},
|
||||
edit({ attributes, setAttributes, className, isSelected }) {
|
||||
|
||||
let {
|
||||
content,
|
||||
collectionId,
|
||||
itemId,
|
||||
isModalOpen,
|
||||
relatedItems,
|
||||
isLoading,
|
||||
itemRequestSource,
|
||||
relatedItemsTemplate
|
||||
} = attributes;
|
||||
|
||||
|
||||
function setContent(){
|
||||
isLoading = true;
|
||||
|
||||
setAttributes({
|
||||
isLoading: isLoading
|
||||
});
|
||||
|
||||
if (itemRequestSource != undefined && typeof itemRequestSource == 'function')
|
||||
itemRequestSource.cancel('Previous items search canceled.');
|
||||
|
||||
itemRequestSource = axios.CancelToken.source();
|
||||
|
||||
let endpoint = '/items/'+ itemId + '?fetch_only=related_items';
|
||||
|
||||
tainacan.get(endpoint, { cancelToken: itemRequestSource.token })
|
||||
.then(response => {
|
||||
|
||||
relatedItems = response.data && response.data.related_items ? Object.values(response.data.related_items) : [];
|
||||
|
||||
setAttributes({
|
||||
relatedItems: relatedItems,
|
||||
isLoading: false,
|
||||
itemRequestSource: itemRequestSource
|
||||
});
|
||||
getRelatedItemsTemplates();
|
||||
});
|
||||
}
|
||||
|
||||
function openRelatedItemsModal() {
|
||||
isModalOpen = true;
|
||||
setAttributes( {
|
||||
isModalOpen: isModalOpen
|
||||
} );
|
||||
}
|
||||
|
||||
function getRelatedItemsTemplates() {
|
||||
relatedItemsTemplate = [];
|
||||
relatedItems.forEach((collection) => {
|
||||
|
||||
if (collection.total_items) {
|
||||
relatedItemsTemplate.push([
|
||||
'core/group',
|
||||
{},
|
||||
[
|
||||
[
|
||||
'core/heading',
|
||||
{
|
||||
placeholder: __( 'Collection name', 'tainacan' ),
|
||||
content: collection.collection_name
|
||||
}
|
||||
],
|
||||
[
|
||||
'core/paragraph',
|
||||
{
|
||||
placeholder: __( 'Relationship metadadum name', 'tainacan' ),
|
||||
content: collection.metadata_name
|
||||
}
|
||||
],
|
||||
[
|
||||
'tainacan/carousel-items-list',
|
||||
{
|
||||
content: [{ type: 'innerblock' }],
|
||||
selectedItems: collection.items,
|
||||
loadStrategy: 'parent',
|
||||
collectionId: collection.collection_id
|
||||
}
|
||||
],
|
||||
[
|
||||
'core/buttons',
|
||||
{},
|
||||
[
|
||||
[
|
||||
'core/button',
|
||||
{
|
||||
text: __( 'View all related items', 'tainacan' ),
|
||||
url: collection.collection_slug ? (collection.collection_slug + '?metaquery[0][key]=' + collection.metadata_id + '&metaquery[0][value][0]=' + itemId + '&metaquery[0][compare]=IN') : ''
|
||||
}
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
'core/spacer',
|
||||
{ height: 30 }
|
||||
]
|
||||
]
|
||||
]);
|
||||
}
|
||||
});
|
||||
setAttributes({ relatedItemsTemplate: relatedItemsTemplate});
|
||||
}
|
||||
|
||||
// Executed only on the first load of page
|
||||
if(content && content.length && content[0].type)
|
||||
setContent();
|
||||
|
||||
return content == 'preview' ?
|
||||
<div className={className}>
|
||||
<img
|
||||
width="100%"
|
||||
src={ `${tainacan_blocks.base_url}/assets/images/related-carousel-items.png` } />
|
||||
</div>
|
||||
: (
|
||||
<div className={className}>
|
||||
|
||||
{ isSelected ?
|
||||
(
|
||||
<div>
|
||||
{ isModalOpen ?
|
||||
<CarouselRelatedItemsModal
|
||||
existingCollectionId={ collectionId }
|
||||
existingItemId={ itemId }
|
||||
onSelectCollection={ (selectedCollectionId) => {
|
||||
if (collectionId != selectedCollectionId)
|
||||
relatedItems = [];
|
||||
|
||||
collectionId = selectedCollectionId;
|
||||
setAttributes({
|
||||
collectionId: collectionId,
|
||||
relatedItems: relatedItems
|
||||
});
|
||||
}}
|
||||
onApplyRelatedItem={ (selectedItemId) => {
|
||||
if (itemId != selectedItemId) {
|
||||
relatedItems = [];
|
||||
relatedItemsTemplate = [];
|
||||
}
|
||||
|
||||
itemId = selectedItemId;
|
||||
setAttributes({
|
||||
itemId: itemId,
|
||||
relatedItems: relatedItems,
|
||||
relatedItemsTemplate: relatedItemsTemplate,
|
||||
isModalOpen: false
|
||||
});
|
||||
setContent();
|
||||
}}
|
||||
onCancelSelection={ () => setAttributes({ isModalOpen: false }) }/>
|
||||
: null
|
||||
}
|
||||
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
|
||||
{ !relatedItems.length && !isLoading ? (
|
||||
<Placeholder
|
||||
className="tainacan-block-placeholder"
|
||||
icon={(
|
||||
<img
|
||||
width={148}
|
||||
src={ `${tainacan_blocks.base_url}/assets/images/tainacan_logo_header.svg` }
|
||||
alt="Tainacan Logo"/>
|
||||
)}>
|
||||
<p>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
height="24px"
|
||||
width="24px">
|
||||
<path d="M16,6H12a2,2,0,0,0-2,2v6.52A6,6,0,0,1,12,19a6,6,0,0,1-.73,2.88A1.92,1.92,0,0,0,12,22h8a2,2,0,0,0,2-2V12Zm-1,6V7.5L19.51,12ZM15,2V4H8v9.33A5.8,5.8,0,0,0,6,13V4A2,2,0,0,1,8,2ZM10.09,19.05,7,22.11V16.05L8,17l2,2ZM5,16.05v6.06L2,19.11Z"/>
|
||||
</svg>
|
||||
{__('List items on a Carousel, using search or item selection.', 'tainacan')}
|
||||
</p>
|
||||
<Button
|
||||
isPrimary
|
||||
type="button"
|
||||
onClick={ () => openRelatedItemsModal() }>
|
||||
{__('Select Item', 'tainacan')}
|
||||
</Button>
|
||||
</Placeholder>
|
||||
) : null
|
||||
}
|
||||
|
||||
{ isLoading ?
|
||||
<div class="spinner-container">
|
||||
<Spinner />
|
||||
</div> :
|
||||
<div>
|
||||
{ relatedItems.length ? (
|
||||
|
||||
<div className={ 'carousel-related-items-edit-container' }>
|
||||
<InnerBlocks
|
||||
allowedBlocks={[
|
||||
'core/heading',
|
||||
'core/paragraph',
|
||||
'tainacan/carousel-items-list',
|
||||
'core/buttons'
|
||||
]}
|
||||
template={ relatedItemsTemplate } />
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
);
|
||||
},
|
||||
save({ className }){
|
||||
return <div className={ className }><InnerBlocks.Content /></div>
|
||||
},
|
||||
deprecated: DeprecatedBlocks
|
||||
});
|
|
@ -142,7 +142,7 @@
|
|||
color: var(--tainacan-block-gray5, $gray5);
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
padding: 8px 16px;
|
||||
padding: 8px 12px;
|
||||
display: block;
|
||||
line-height: 1.2em;
|
||||
word-break: break-word;
|
||||
|
|
|
@ -736,10 +736,10 @@ export default {
|
|||
max-width: 100%;
|
||||
}
|
||||
.field:not(:last-child) {
|
||||
margin-bottom: 0.5em;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
.field {
|
||||
padding: 10px 0px 14px 34px;
|
||||
padding: 12px 0px 12px 34px;
|
||||
|
||||
}
|
||||
.columns {
|
||||
|
|
|
@ -220,7 +220,6 @@ return apply_filters( 'tainacan-admin-i18n', [
|
|||
'label_approved' => __( 'Approved', 'tainacan' ),
|
||||
'label_collection_related' => __( 'Collection related', 'tainacan' ),
|
||||
'label_metadata_for_search' => __( 'Metadata for search', 'tainacan' ),
|
||||
'label_allow_repeated_items' => __( 'Allow repeated items', 'tainacan' ),
|
||||
'label_select_taxonomy' => __( 'Select taxonomy', 'tainacan' ),
|
||||
'label_select_taxonomy_input_type' => __( 'Input type', 'tainacan' ),
|
||||
'label_taxonomy_allow_new_terms' => __( 'Allow new terms', 'tainacan' ),
|
||||
|
@ -586,6 +585,9 @@ return apply_filters( 'tainacan-admin-i18n', [
|
|||
'label_pan_selection' => __( 'Pan selection', 'tainacan'),
|
||||
'label_reset_zoom' => __( 'Reset zoom', 'tainacan'),
|
||||
'label_chart_export_options' => __( 'Chart export options', 'tainacan'),
|
||||
'label_related_items' => __( 'Items related to this', 'tainacan'),
|
||||
'label_view_all_%s_related_items' => __( 'View all %s related items', 'tainacan'),
|
||||
'label_back_to_related_item' => __( 'Back to related item', 'tainacan'),
|
||||
|
||||
// Instructions. More complex sentences to guide user and placeholders
|
||||
'instruction_delete_selected_collections' => __( 'Delete selected collections', 'tainacan' ),
|
||||
|
@ -870,7 +872,8 @@ return apply_filters( 'tainacan-admin-i18n', [
|
|||
'info_no_taxonomy_metadata_created' => __( 'No taxonomy metadata created yet', 'tainacan'),
|
||||
'label_amount_of_metadata_of_type' => __( 'Amount of metadata of this type', 'tainacan'),
|
||||
'info_child_terms_chart' => __( 'Click on the term bar on the chart aside to see its child terms (if any) in this panel', 'tainacan' ),
|
||||
|
||||
'info_related_items' => __( 'These are items that are related to this item via their own relationship type metadata. You can edit such relation on their pages.', 'tainacan'),
|
||||
|
||||
/* Activity actions */
|
||||
'action_update-metadata-value' => __( 'Item Metadata Value Updates', 'tainacan'),
|
||||
'action_update' => __( 'General Updates', 'tainacan'),
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
|
||||
namespace Tainacan\Tests;
|
||||
|
||||
/**
|
||||
* Class TestCollections
|
||||
*
|
||||
* @package Test_Tainacan
|
||||
*/
|
||||
|
||||
use Tainacan\Entities;
|
||||
|
||||
/**
|
||||
* Sample test case.
|
||||
*/
|
||||
class RelationshipMetadatumTypes extends TAINACAN_UnitTestCase {
|
||||
|
||||
private $collection_author = null;
|
||||
private $collection_book = null;
|
||||
private $collection_article = null;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->collection_book = $this->tainacan_entity_factory->create_entity('collection', ['name' => 'Book', 'status' => 'publish'], true);
|
||||
$this->collection_author = $this->tainacan_entity_factory->create_entity('collection', ['name' => 'Author', 'status' => 'publish'], true);
|
||||
$this->collection_article = $this->tainacan_entity_factory->create_entity('collection', ['name' => 'Article','status' => 'publish'], true);
|
||||
|
||||
$this->metadatum_author_book = $this->tainacan_entity_factory->create_entity(
|
||||
'metadatum',
|
||||
array(
|
||||
'name' => 'author',
|
||||
'description' => 'author',
|
||||
'collection' => $this->collection_book,
|
||||
'metadata_type' => 'Tainacan\Metadata_Types\Relationship',
|
||||
'status' => 'publish',
|
||||
'metadata_type_options' => [
|
||||
'display_in_related_items' => 'yes',
|
||||
'collection_id' => $this->collection_author->get_id(),
|
||||
'search' => ''
|
||||
],
|
||||
'multiple' => 'yes'
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
$this->metadatum_author_article = $this->tainacan_entity_factory->create_entity(
|
||||
'metadatum',
|
||||
array(
|
||||
'name' => 'author',
|
||||
'description' => 'author',
|
||||
'collection' => $this->collection_article,
|
||||
'metadata_type' => 'Tainacan\Metadata_Types\Relationship',
|
||||
'status' => 'publish',
|
||||
'metadata_type_options' => [
|
||||
'display_in_related_items' => 'yes',
|
||||
'collection_id' => $this->collection_author->get_id(),
|
||||
'search' => ''
|
||||
],
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
$this->metadatum_second_author_article = $this->tainacan_entity_factory->create_entity(
|
||||
'metadatum',
|
||||
array(
|
||||
'name' => 'secound author',
|
||||
'description' => 'secound author',
|
||||
'collection' => $this->collection_article,
|
||||
'metadata_type' => 'Tainacan\Metadata_Types\Relationship',
|
||||
'status' => 'publish',
|
||||
'metadata_type_options' => [
|
||||
'display_in_related_items' => 'no',
|
||||
'collection_id' => $this->collection_author->get_id(),
|
||||
'search' => ''
|
||||
]
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function test_related_items() {
|
||||
|
||||
$a1 = $this->tainacan_entity_factory->create_entity(
|
||||
'item',
|
||||
array(
|
||||
'title' => 'Lopes da silva',
|
||||
'description' => 'autor fisico',
|
||||
'collection' => $this->collection_author,
|
||||
'status' => 'publish'
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
$a2 = $this->tainacan_entity_factory->create_entity(
|
||||
'item',
|
||||
array(
|
||||
'title' => 'Siqueira da martins',
|
||||
'description' => 'autor simuante',
|
||||
'collection' => $this->collection_author,
|
||||
'status' => 'publish'
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
$b1 = $this->tainacan_entity_factory->create_entity(
|
||||
'item',
|
||||
array(
|
||||
'title' => 'O livro dos livros',
|
||||
'description' => 'livro broxura',
|
||||
'collection' => $this->collection_book,
|
||||
'status' => 'publish'
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
$j1 = $this->tainacan_entity_factory->create_entity(
|
||||
'item',
|
||||
array(
|
||||
'title' => 'O artigo da semana',
|
||||
'description' => 'artigo mais que cientifico',
|
||||
'collection' => $this->collection_article,
|
||||
'status' => 'publish'
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
$j2 = $this->tainacan_entity_factory->create_entity(
|
||||
'item',
|
||||
array(
|
||||
'title' => 'Não é magia é tecnologias',
|
||||
'description' => 'So digo que não digo nada',
|
||||
'collection' => $this->collection_article,
|
||||
'status' => 'publish'
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
$this->tainacan_item_metadata_factory->create_item_metadata($j1, $this->metadatum_author_article, $a1->get_id());
|
||||
$this->tainacan_item_metadata_factory->create_item_metadata($j1, $this->metadatum_second_author_article, $a2->get_id());
|
||||
|
||||
$this->tainacan_item_metadata_factory->create_item_metadata($j2, $this->metadatum_author_article, $a1->get_id());
|
||||
$this->tainacan_item_metadata_factory->create_item_metadata($j2, $this->metadatum_second_author_article, $a2->get_id());
|
||||
|
||||
$this->tainacan_item_metadata_factory->create_item_metadata($b1, $this->metadatum_author_book, [$a1->get_id(), $a2->get_id()]);
|
||||
|
||||
|
||||
$a1_related_items = $a1->get_related_items();
|
||||
$a2_related_items = $a1->get_related_items();
|
||||
|
||||
$this->assertTrue(isset($a1_related_items[$this->metadatum_author_article->get_id()]));
|
||||
$this->assertEquals(2, count($a1_related_items[$this->metadatum_author_article->get_id()]['items']));
|
||||
$this->assertTrue(!isset($a2_related_items[$this->metadatum_second_author_article->get_id()])); //não existe esse
|
||||
|
||||
$this->assertTrue(isset($a1_related_items[$this->metadatum_author_book->get_id()]));
|
||||
$this->assertTrue(isset($a2_related_items[$this->metadatum_author_book->get_id()]));
|
||||
|
||||
$order = array([
|
||||
'id' => $this->metadatum_author_article->get_id(),
|
||||
'enabled' => false,
|
||||
]);
|
||||
$this->collection_article->set_metadata_order($order);
|
||||
$this->collection_article->validate();
|
||||
\tainacan_collections()->insert($this->collection_article);
|
||||
\tainacan_items()->fetch($a1->get_id());
|
||||
$a1_related_items = $a1->get_related_items();
|
||||
$this->assertTrue(!isset($a1_related_items[$this->metadatum_author_article->get_id()]));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -28,7 +28,9 @@ module.exports = {
|
|||
|
||||
block_carousel_collections_list: './src/views/gutenberg-blocks/tainacan-collections/carousel-collections-list/index.js',
|
||||
block_carousel_collections_list_theme: './src/views/gutenberg-blocks/tainacan-collections/carousel-collections-list/carousel-collections-list-theme.js',
|
||||
|
||||
|
||||
block_carousel_related_items: './src/views/gutenberg-blocks/tainacan-items/carousel-related-items/index.js',
|
||||
|
||||
block_facets_list: './src/views/gutenberg-blocks/tainacan-facets/facets-list/index.js',
|
||||
block_facets_list_theme: './src/views/gutenberg-blocks/tainacan-facets/facets-list/facets-list-theme.js',
|
||||
|
||||
|
|
Loading…
Reference in New Issue