Merge with latest develop

This commit is contained in:
Mateus Machado Luna 2018-10-26 12:19:52 -03:00
commit cce2ecdc8d
142 changed files with 8144 additions and 4981 deletions

View File

@ -68,7 +68,7 @@ rm -rf $wp_plugin_dir
mkdir $wp_plugin_dir
rsync -axz --exclude='vendor/bin/phpc*' --exclude='vendor/squizlabs' --exclude='vendor/wimg' \
--exclude='vendor/respect/validation/.git' --exclude='pdf-viewer/pdfjs-dist/web/compressed.tracemonkey-pldi-09.pdf' \
--exclude='vendor/respect/validation/.git' --exclude='vendor/symfony/polyfill-mbstring/.git' --exclude='pdf-viewer/pdfjs-dist/web/compressed.tracemonkey-pldi-09.pdf' \
src/* $wp_plugin_dir/
rm -rf $wp_plugin_dir/scss

View File

@ -1,70 +0,0 @@
# Collections
## Collection Repository
<!-- BEGIN DOC-COMMENT H3 src/classes/repositories/class-tainacan-collections.php -->
### `protected function __construct()`
Collections constructor.
### `public function get_map()`
{@inheritDoc}
### `public function get_cpt_labels()`
Get the labels for the custom post type of this repository
**Returns:** `array` — Labels in the format expected by register_post_type()
### `public function insert( $collection )`
{@inheritDoc}
**Parameters:**
* `$collection` — \Tainacan\Entities\Collection
**Returns:** \Tainacan\Entities\Collection
### `public function delete( $args )`
**Parameters:**
* `(` — $args — is a array like [post_id, [is_permanently => bool]] )
**Returns:** mixed|Collection
### `public function fetch( $args = [], $output = null )`
fetch collection based on ID or WP_Query args
Collections are stored as posts. Check WP_Query docs to learn all args accepted in the $args parameter (@see https://developer.wordpress.org/reference/classes/wp_query/) You can also use a mapped property, such as name and description, as an argument and it will be mapped to the appropriate WP_Query argument
**Parameters:**
* `$args` — array — WP_Query args || int $args the collection id
* `$output` — string — The desired output format (@see \Tainacan\Repositories\Repository::fetch_output() for possible values)
**Returns:** `\WP_Query|Array` — an instance of wp query OR array of entities;
### `public function map_meta_cap( $caps, $cap, $user_id, $args )`
Filter to handle special permissions
<!-- END DOC-COMMENT -->
## Collection Entity
<!-- BEGIN DOC-COMMENT H3 src/classes/entities/class-tainacan-collection.php -->
### `function validate()`
Validate Collection
**Returns:** bool
<!-- END DOC-COMMENT -->

View File

@ -1,516 +0,0 @@
# Metadata
## Metadatum Repository
<!-- BEGIN DOC-COMMENT H3 src/classes/repositories/class-tainacan-metadata.php -->
### `class Metadata extends Repository`
Class Metadata
### `protected function __construct()`
Register specific hooks for metadatum repository
### `public function get_cpt_labels()`
Get the labels for the custom post type of this repository
**Returns:** `array` — Labels in the format expected by register_post_type()
### `public function get_default_metadata_attribute()`
constant used in default metadatum in attribute collection_id
**Returns:** `string` — the value of constant
### `public function register_field_type( $class_name )`
register metadatum types class on array of types
**Parameters:**
* `string` — $class_name — | object The class name or the instance
### `public function unregister_field_type( $class_name )`
register metadatum types class on array of types
**Parameters:**
* `string` — $class_name — | object The class name or the instance
### `public function fetch( $args, $output = null )`
fetch metadatum based on ID or WP_Query args
metadatum are stored as posts. Check WP_Query docs to learn all args accepted in the $args parameter (@see https://developer.wordpress.org/reference/classes/wp_query/) You can also use a mapped property, such as name and description, as an argument and it will be mapped to the appropriate WP_Query argument
**Parameters:**
* `$args` — array — WP_Query args || int $args the metadatum id
* `$output` — string — The desired output format (@see \Tainacan\Repositories\Repository::fetch_output() for possible values)
**Returns:** `Entities\Metadatum|\WP_Query|Array` — an instance of wp query OR array of entities;
### `public function fetch_by_collection(Entities\Collection $collection, $args = [], $output = null)`
fetch metadatum by collection, searches all metadatum available
**Parameters:**
* `$collection` — Entities\Collection
* `$args` — array — WP_Query args plus disabled_fields
* `$output` — string — The desired output format (@see \Tainacan\Repositories\Repository::fetch_output() for possible values)
**Returns:** `array` — Entities\Metadatum
### `public function order_result( $result, Entities\Collection $collection, $include_disabled = false )`
Ordinate the result from fetch response if $collection has an ordination, metadata not ordinated appear on the end of the list
**Parameters:**
* `Response` — $result — from method fetch
* `$collection` — Entities\Collection
* `$include_disabled` — bool — Wether to include disabled metadata in the results or not
**Returns:** `array` — or WP_Query ordinate
### `public function insert($metadatum)`
{@inheritDoc}
**Parameters:**
* `$metadatum` — \Tainacan\Entities\Metadatum
**Returns:** \Tainacan\Entities\Metadatum
### `public function update($object, $new_values = null)`
**Returns:** mixed|string|Entities\Entity
### `public function fetch_field_types( $output = 'CLASS')`
fetch all registered metadatum type classes
Possible outputs are: CLASS (default) - returns the Class name of of metadatum types registered NAME - return an Array of the names of metadatum types registered
**Parameters:**
* `string` — $output — CLASS | NAME
**Returns:** `array` — of Entities\Metadatum_Types\Metadatum_Type classes path name
### `public function register_core_fields( Entities\Collection $collection )`
**Parameters:**
* `$collection` — Entities\Collection
**Returns:** bool
### `public function disable_delete_core_fields( $before, $post )`
block user from remove core metadata
**Parameters:**
* `wordpress` — $before — pass a null value
* `the` — $post — post which is moving to trash
**Returns:** null/bool
### `public function force_delete_core_fields( $before, $post, $force_delete )`
block user from remove core metadata ( if use wp_delete_post)
**Parameters:**
* `wordpress` — $before — pass a null value
* `the` — $post — post which is deleting
* `a` — $force_delete — boolean that force the deleting
**Returns:** `null` — /bool
### `public function get_core_fields( Entities\Collection $collection )`
returns all core items from a specific collection
**Parameters:**
* `$collection` — Entities\Collection
**Returns:** Array|\WP_Query
### `public function insert_array_field( $data )`
create a metadatum entity and insert by an associative array ( attribute => value )
**Parameters:**
* `$data` — Array — the array of attributes to insert a metadatum
**Returns:** `int` — the metadatum id inserted
### `public function fetch_all_field_values($collection_id, $metadatum_id)`
Fetch all values of a metadatum from a collection in all it collection items
**Returns:** array|null|object
### `private function pre_update_taxonomy_field($metadatum)`
Stores the value of the taxonomy_id option to use on update_taxonomy_field method.
### `private function update_taxonomy_field($metadatum)`
Triggers hooks when saving a Taxonomy Metadatum, indicating wich taxonomy was added or removed from a collection.
This is used by Taxonomies repository to update the collections_ids property of the taxonomy as a metadatum type taxonomy is inserted or removed
**Parameters:**
* `$metadatum` — [type] — [description]
**Returns:** `[type]` — [description]
<!-- END DOC-COMMENT -->
## Metadatum Entity
<!-- BEGIN DOC-COMMENT H3 src/classes/entities/class-tainacan-metadatum.php -->
### `class Metadatum extends Entity`
Represents the Entity Metadatum
### `protected $repository = 'Metadata'`
{@inheritDoc}
### `function get_name()`
Return the metadatum name
**Returns:** string
### `function get_slug()`
Get metadatum slug
**Returns:** string
### `function get_order()`
Return the metadatum order type
**Returns:** string
### `function get_parent()`
Return the parent ID
**Returns:** string
### `function get_description()`
Return the metadatum description
**Returns:** string
### `function get_required()`
Return if is a required metadatum
**Returns:** boolean
### `function get_multiple()`
Return if is a multiple metadatum
**Returns:** boolean
### `function get_cardinality()`
Return the cardinality
**Returns:** string
### `function get_collection_key()`
Return if metadatum is key
**Returns:** boolean
### `function get_mask()`
Return the mask
**Returns:** string
### `function get_default_value()`
Return the metadatum default value
**Returns:** `string` — || integer
### `function get_field_type_object()`
Return the an object child of \Tainacan\Metadatum_Types\Metadatum_Type with options
**Returns:** `\Tainacan\Metadatum_Types\Metadatum_Type` — The metadatum type class with filled options
### `function get_field_type()`
Return the class name for the metadatum type
**Returns:** `string` — The
### `function get_field_type_options()`
Return the actual options for the current metadatum type
**Returns:** `array` — Configurations for the metadatum type object
### `function set_name($value)`
Set the metadatum name
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function get_accept_suggestion()`
Return true if this metadatum allow community suggestions, false otherwise
**Returns:** bool
### `function set_slug($value)`
Set the metadatum slug
If you dont set the metadatum slug, it will be set automatically based on the name and following WordPress default behavior of creating slugs for posts.
If you set the slug for an existing one, WordPress will append a number at the end of in order to make it unique (e.g slug-1, slug-2)
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_order($value)`
Set manually the order of the metadatum
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_parent($value)`
Set the metadatum parent ID
**Parameters:**
* `$value` — [integer] — The ID from parent
**Returns:** void
### `function set_description($value)`
Set metadatum description
**Parameters:**
* `$value` — [string] — The text description
**Returns:** void
### `function set_required( $value )`
Allow the metadatum be required
**Parameters:**
* `$value` — [boolean]
**Returns:** void
### `function set_multiple( $value )`
Allow multiple metadata
**Parameters:**
* `$value` — [boolean]
**Returns:** void
### `function set_cardinality( $value )`
The number of possible metadata
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_collection_key( $value )`
Define if the value is key on the collection
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_mask( $value )`
Set mask for the metadatum
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_privacy( $value )`
Set privacy
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_default_value( $value )`
Set default value
**Parameters:**
* `||` — [string — integer] $value
**Returns:** void
### `public function set_field_type( $value )`
set the metadatum type class name
**Parameters:**
* `|` — string — \Tainacan\Metadatum_Types\Metadatum_Type $value The name of the class or the instance
### `function set_accept_suggestion( $value )`
Set if this metadatum allow community suggestions
**Parameters:**
* `$value` — bool
### `function set_field_type_options( $value )`
Set Metadatum type options
**Parameters:**
* `||` — [string — integer] $value
**Returns:** void
### `public function get_enabled_for_collection()`
Transient property used to store the status of the metadatum for a particular collection
Used by the API to tell front end when a metadatum is disabled
### `function is_multiple()`
Return true if is multiple, else return false
**Returns:** boolean
### `function is_collection_key()`
Return true if is collection key, else return false
**Returns:** boolean
### `function is_required()`
Return true if is required, else return false
**Returns:** boolean
### `public function validate()`
{@inheritdoc }
Also validates the metadatum, calling the validate_options callback of the Metadatum Type
**Returns:** `bool` — valid or not
<!-- END DOC-COMMENT -->

View File

@ -1,239 +0,0 @@
# Filters
## Filter Repository
<!-- BEGIN DOC-COMMENT H3 src/classes/repositories/class-tainacan-filters.php -->
### `public function delete($args)`
**Parameters:**
* `$args` — array
**Returns:** Entities\Filter
### `public function fetch($args = [], $output = null)`
fetch filter based on ID or WP_Query args
Filters are stored as posts. Check WP_Query docs to learn all args accepted in the $args parameter (@see https://developer.wordpress.org/reference/classes/wp_query/) You can also use a mapped property, such as name and description, as an argument and it will be mapped to the appropriate WP_Query argument
**Parameters:**
* `$args` — array — WP_Query args || int $args the filter id
* `$output` — string — The desired output format (@see \Tainacan\Repositories\Repository::fetch_output() for possible values)
**Returns:** `\WP_Query|Array` — an instance of wp query OR array of entities;
### `public function register_filter_type( $class_name )`
register metadatum types class on array of types
**Parameters:**
* `string` — $class_name — | object The class name or the instance
### `public function deregister_filter_type( $class_name )`
register metadatum types class on array of types
**Parameters:**
* `string` — $class_name — | object The class name or the instance
### `public function fetch_filter_types( $output = 'CLASS')`
fetch all registered filter type classes
Possible outputs are: CLASS (default) - returns the Class name of of filter types registered NAME - return an Array of the names of filter types registered
**Parameters:**
* `string` — $output — CLASS | NAME
**Returns:** `array` — of Entities\Filter_Types\Filter_Type classes path name
### `public function fetch_supported_filter_types($types)`
fetch only supported filters for the type specified
**Parameters:**
* `string` — ( — || array ) $types Primitve types of metadatum ( float, string, int)
**Returns:** `array` — Filters supported by the primitive types passed in $types
### `public function fetch_by_collection(Entities\Collection $collection, $args = [], $output = null)`
fetch filters by collection, searches all filters available
**Parameters:**
* `$collection` — Entities\Collection
* `$args` — array — WP_Query args plus disabled_fields
* `$output` — string — The desired output format (@see \Tainacan\Repositories\Repository::fetch_output() for possible values)
**Returns:** `Array` — Entities\Metadatum
### `public function order_result( $result, Entities\Collection $collection )`
Ordinate the result from fetch response if $collection has an ordination, filters not ordinated appear on the end of the list
**Parameters:**
* `Response` — $result — from method fetch
* `$collection` — Entities\Collection
**Returns:** `array` — or WP_Query ordinate
<!-- END DOC-COMMENT -->
## Filter Entity
<!-- BEGIN DOC-COMMENT H3 src/classes/entities/class-tainacan-filter.php -->
### `class Filter extends Entity`
Represents the entity Filter
### `protected $repository = 'Filters'`
{@inheritDoc}
### `public function _toArray()`
**Returns:** array
### `function get_name()`
Return the filter name
**Returns:** string
### `function get_description()`
**Returns:** mixed|null
### `function get_order()`
Return the filter order type
**Returns:** string
### `function get_color()`
Return the filter color
**Returns:** string
### `function get_field()`
Return the metadatum
**Returns:** Metadatum
### `function get_filter_type_object()`
Return the an object child of \Tainacan\Filter_Types\Filter_Type with options
**Returns:** `\Tainacan\Filter_Types\Filter_Type` — The filter type class with filled options
### `function get_filter_type()`
Return the class name for the filter type
**Returns:** `string` — The
### `function get_filter_options()`
Return the actual options for the current filter type
**Returns:** `array` — Configurations for the filter type object
### `function set_name($value)`
Define the filter name
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_order($value)`
Define the filter order type
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_description($value)`
Define the filter description
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_color( $value )`
Define the filter color
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_field( $value )`
Define the filter metadatum
**Returns:** void
### `public function set_filter_type($value)`
Save the filter type class name
**Parameters:**
* `|` — string — \Tainacan\Filter_Types\Filter_Type $value The name of the class or the instance
### `public function validate()`
{@inheritdoc }
Also validates the metadatum, calling the validate_options callback of the Metadatum Type
**Returns:** `bool` — valid or not
<!-- END DOC-COMMENT -->

View File

@ -1,216 +0,0 @@
# Item Metadata
## Item Metadata Repository
<!-- BEGIN DOC-COMMENT H3 src/classes/repositories/class-tainacan-item-metadata.php -->
### `if ( $item_metadata->get_field()->get_parent() > 0 && is_null($item_metadata->get_meta_id()) )`
When we are adding a metadatum that is child of another, this means it is inside a compound metadatum
In that case, if the Item_Metadata object is not set with a meta_id, it means we want to create a new one and not update an existing. This is the case of a multiple compound metadatum.
### `public function delete($item_metadata)`
**Returns:** mixed|void
### `public function add_compound_value(Entities\Item_Metadata_Entity $item_metadata, $meta_id)`
**Returns:** `null|ind` — the meta id of the created compound metadata
### `public function fetch($object, $output = null )`
Fetch Item Metadatum objects related to an Item
**Parameters:**
* `$object` — Entities\Item
**Returns:** array
### `public function get_value(Entities\Item_Metadata_Entity $item_metadata)`
Get the value for a Item metadatum.
**Parameters:**
* `$item_metadata` — Entities\Item_Metadata_Entity
**Returns:** mixed
### `private function extract_compound_value(array $ids, Entities\Item $item, $compund_meta_id)`
Transforms the array saved as meta_value with the IDs of post_meta saved as a value for compound metadata and converts it into an array of Item Metadatada Entitites
**Parameters:**
* `$ids` — array — The array of post_meta ids
* `$item` — Entities\Item — The item this post_meta is related to
* `$compund_meta_id` — int — the meta_id of the parent compound metadata
**Returns:** `array` — An array of Item_Metadata_Entity objects
### `public function update( $object, $new_values = null )`
**Returns:** mixed
### `public function suggest($item_metadata)`
Suggest a value to be inserted as a item Metadatum value, return a pending log
**Parameters:**
* `$item_metadata` — Entities\Item_Metadata_Entity
**Returns:** Entities\Log
<!-- END DOC-COMMENT -->
## Item Metadata Entity
<!-- BEGIN DOC-COMMENT H3 src/classes/entities/class-tainacan-item-metadata-entity.php -->
### `class Item_Metadata_Entity extends Entity`
Represents the Item Metadatum Entity
### `protected $repository = 'Item_Metadata'`
{@inheritDoc}
### `function __construct(Item $item, Metadatum $metadatum, $meta_id = null, $parent_meta_id = null)`
**Parameters:**
* `$item` — Item — Item Entity
* `$metadatum` — Metadatum — Metadatum Entity
* `$meta_id` — int — ID for a specific meta row
### `function set_item(Item $item)`
Define the item
**Parameters:**
* `$item` — Item
**Returns:** void
### `function set_value($value)`
Define the metadatum value
**Parameters:**
* `|` — [integer — string] $value
**Returns:** void
### `function set_field(Metadatum $metadatum)`
Define the metadatum
**Parameters:**
* `$metadatum` — Metadatum
**Returns:** void
### `function set_meta_id($meta_id)`
Set the specific meta ID for this metadata.
When this value is set, get_value() will use it to fetch the value from the post_meta table, instead of considering the item and metadatum IDs
**Parameters:**
* `$meta_id` — int — the ID of a specifica post_meta row
### `function set_parent_meta_id($parent_meta_id)`
Set parent_meta_id. Used when a item_metadata is inside a compound Metadatum
When you have a multiple compound metadatum, this indicates of which instace of the value this item_metadata is attached to
**Parameters:**
* `$parent_meta_id` — [type] — [description]
### `function get_item()`
Return the item
**Returns:** Item
### `function get_field()`
Return the metadatum
**Returns:** Metadatum
### `function get_meta_id()`
Return the meta_id
**Returns:** Metadatum
### `function get_parent_meta_id()`
Return the meta_id
**Returns:** Metadatum
### `function get_value()`
Return the metadatum value
**Returns:** `string` — | integer
### `function is_multiple()`
Return true if metadatum is multiple, else return false
**Returns:** boolean
### `function is_collection_key()`
Return true if metadatum is key
**Returns:** boolean
### `function is_required()`
Return true if metadatum is required
**Returns:** boolean
### `function validate()`
Validate attributes
**Returns:** boolean
<!-- END DOC-COMMENT -->

View File

@ -1,263 +0,0 @@
# Items
## Items Repository
<!-- BEGIN DOC-COMMENT H3 src/classes/repositories/class-tainacan-items.php -->
### `public function get_cpt_labels()`
Get generic labels for the custom post types created for each collection
**Returns:** `array` — Labels in the format expected by register_post_type()
### `public function register_post_type()`
Register each Item post_type {@inheritDoc}
### `public function fetch( $args = [], $collections = [], $output = null )`
fetch items based on ID or WP_Query args
Items are stored as posts. Check WP_Query docs to learn all args accepted in the $args parameter (@see https://developer.wordpress.org/reference/classes/wp_query/) You can also use a mapped property, such as name and description, as an argument and it will be mapped to the appropriate WP_Query argument
The second paramater specifies from which collections item should be fetched. You can pass the Collection ID or object, or an Array of IDs or collection objects
**Parameters:**
* `$args` — array — WP_Query args || int $args the item id
* `$collections` — array — Array Entities\Collection || Array int collections IDs || int collection id || Entities\Collection collection object
* `$output` — string — The desired output format (@see \Tainacan\Repositories\Repository::fetch_output() for possible values)
**Returns:** `\WP_Query|Array` — an instance of wp query OR array of entities;
### `if ( ! isset( $args['post_status'] ) )`
If no specific status is defined in the query, WordPress will fetch public items and private items for users withe the correct permission.
If a collection is private, it must have the same behavior, despite its items are public or not.
### `public function fetch_ids( $args = [], $collections = [] )`
fetch items IDs based on WP_Query args
to learn all args accepted in the $args parameter (@see https://developer.wordpress.org/reference/classes/wp_query/) You can also use a mapped property, such as name and description, as an argument and it will be mapped to the appropriate WP_Query argument
The second paramater specifies from which collections item should be fetched. You can pass the Collection ID or object, or an Array of IDs or collection objects
**Parameters:**
* `$args` — array — WP_Query args || int $args the item id
* `$collections` — array — Array Entities\Collection || Array int collections IDs || int collection id || Entities\Collection collection object
**Returns:** `Array` — array of IDs;
### `public function delete( $args )`
**Parameters:**
* `(` — $args — is a array like [post_id, [is_permanently => bool]] )
**Returns:** mixed|Entities\Item
### `public function title_in_posts_where( $where, $wp_query )`
allow wp query filter post by array of titles
**Returns:** string
### `public function content_in_posts_where( $where, $wp_query )`
allow wp query filter post by array of content
**Returns:** string
<!-- END DOC-COMMENT -->
## Item Entity
<!-- BEGIN DOC-COMMENT H3 src/classes/entities/class-tainacan-item.php -->
### `class Item extends Entity`
Represents the Entity Item
### `protected $repository = 'Items'`
{@inheritDoc}
### `function __construct( $which = 0 )`
{@inheritDoc}
### `function set_terms( $value )`
### `function get_terms()`
**Returns:** mixed|null
### `function get_attachments()`
**Returns:** array
### `function get_author_name()`
**Returns:** string
### `function get_featured_image()`
**Returns:** false|string
### `function set_featured_img_id( $id )`
### `function get_featured_img_id()`
**Returns:** int|string
### `function get_modification_date()`
**Returns:** mixed|null
### `function get_creation_date()`
**Returns:** mixed|null
### `function get_author_id()`
**Returns:** mixed|null
### `function get_url()`
**Returns:** mixed|null
### `function get_id()`
Return the item ID
**Returns:** integer
### `function get_title()`
Return the item title
**Returns:** string
### `function get_order()`
Return the item order type
**Returns:** string
### `function get_parent()`
Return the parent ID
**Returns:** integer
### `function get_description()`
Return the item description
**Returns:** string
### `public function get_db_identifier()`
{@inheritDoc}
### `public function get_capabilities()`
Use especial Item capabilities {@inheritDoc}
### `function set_title( $value )`
Define the title
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_order( $value )`
Define the order type
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_parent( $value )`
Define the parent ID
**Parameters:**
* `$value` — [integer]
**Returns:** void
### `function set_description( $value )`
Define the description
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function get_fields()`
Return a List of ItemMetadata objects
It will return all metadata associeated with the collection this item is part of.
If the item already has a value for any of the metadata, it will be available.
**Returns:** `array` — Array of ItemMetadata objects
### `protected function set_cap()`
set meta cap object
### `function validate()`
{@inheritDoc}
### `public function validate_core_fields()`
{@inheritDoc}
<!-- END DOC-COMMENT -->

View File

@ -1,237 +0,0 @@
# Logs
## Logs Repository
<!-- BEGIN DOC-COMMENT H3 src/classes/repositories/class-tainacan-logs.php -->
### `class Logs extends Repository`
Implement a Logs system
### `public function register_post_type()`
{@inheritDoc}
### `public function fetch($args = [], $output = null)`
fetch logs based on ID or WP_Query args
Logs are stored as posts. Check WP_Query docs to learn all args accepted in the $args parameter (@see https://developer.wordpress.org/reference/classes/wp_query/) You can also use a mapped property, such as name and description, as an argument and it will be mapped to the appropriate WP_Query argument
**Parameters:**
* `$args` — array — WP_Query args || int $args the log id
* `$output` — string — The desired output format (@see \Tainacan\Repositories\Repository::fetch_output() for possible values)
**Returns:** `\WP_Query|Array` — an instance of wp query OR array of entities;
### `public function insert_log($new_value, $value = null)`
Insert a log when a new entity is inserted
**Parameters:**
* `$new_value` — Entity
* `$value` — Entity
**Returns:** `Entities\Log` — new created log
### `public function approve($log)`
**Parameters:**
* `$log` — Entities\Log
**Returns:** `Entities\Entity|boolean` — return insert/update valeu or false
### `$value = $log->get_value()`
<!-- END DOC-COMMENT -->
## Log Entity
<!-- BEGIN DOC-COMMENT H3 src/classes/entities/class-tainacan-log.php -->
### `class Log extends Entity`
Represents entity Log
### `protected $repository = 'Logs'`
{@inheritDoc}
### `function get_title()`
Return the Log title
**Returns:** string
### `function get_order()`
Return the log order type
**Returns:** string
### `function get_parent()`
Retun the parent ID
**Returns:** integer
### `function get_description()`
Return the Log description
**Returns:** string
### `function get_blog_id()`
Return the ID of blog
**Returns:** integer
### `function get_user_id()`
Return User Id of who make the action
**Returns:** `int` — User Id of logged action
### `public function get_value()`
Get value of log entry
**Parameters:**
* `$value` — mixed
**Returns:** void
### `public function get_old_value()`
Get old value of log entry object
**Parameters:**
* `$value` — mixed
**Returns:** void
### `function set_title($value)`
Set log tittle
**Parameters:**
* `$value` — string
**Returns:** void
### `function set_order($value)`
Define the order type
**Parameters:**
* `$value` — [string]
**Returns:** void
### `function set_parent($value)`
Define the parent ID
**Parameters:**
* `$value` — [integer]
**Returns:** void
### `function set_description($value)`
Define the Log description
**Parameters:**
* `$value` — [string]
**Returns:** void
### `protected function set_user_id($value = 0)`
Define the user ID of log entry
**Parameters:**
* `$value` — [integer]
**Returns:** void
### `protected function set_blog_id($value = 0)`
Define the blog ID of log entry
**Parameters:**
* `$value` — [integer]
**Returns:** void
### `protected function set_value($value = null)`
Define the value of log entry
**Parameters:**
* `$value` — [mixed]
**Returns:** void
### `protected function set_old_value($value = null)`
Set old value of log entry
**Parameters:**
* `$value` — [mixed]
**Returns:** void
### `public static function create($msn = false, $desc = '', $new_value = null, $old_value = null, $status = 'publish')`
**Parameters:**
* `$msn` — boolean|string
* `$desc` — string
* `$new_value` — mixed
* `$old_value` — mixed
* `$status` — string — 'publish', 'private' or 'pending'
**Returns:** \Tainacan\Entities\Log
### `public function approve()`
{@inheritDoc}
<!-- END DOC-COMMENT -->

View File

@ -1,143 +0,0 @@
# Taxonomies
## Taxonomies Repository
<!-- BEGIN DOC-COMMENT H3 src/classes/repositories/class-tainacan-taxonomies.php -->
### `class Taxonomies extends Repository`
Class Tainacan_Taxonomies
### `public function get_cpt_labels()`
Get the labels for the custom post type of this repository
**Returns:** `array` — Labels in the format expected by register_post_type()
### `public function insert($taxonomy)`
**Parameters:**
* `$taxonomy` — Entities\Taxonomy
**Returns:** Entities\Entity
### `public function fetch( $args = [], $output = null )`
fetch taxonomies based on ID or WP_Query args
Taxonomies are stored as posts. Check WP_Query docs to learn all args accepted in the $args parameter (@see https://developer.wordpress.org/reference/classes/wp_query/) You can also use a mapped property, such as name and description, as an argument and it will be mapped to the appropriate WP_Query argument
**Parameters:**
* `$args` — array — WP_Query args | int $args the taxonomy id
* `$output` — string — The desired output format (@see \Tainacan\Repositories\Repository::fetch_output() for possible values)
**Returns:** `\WP_Query|Array` — an instance of wp query OR array of entities;
<!-- END DOC-COMMENT -->
## Taxonomy Entity
<!-- BEGIN DOC-COMMENT H3 src/classes/entities/class-tainacan-taxonomy.php -->
### `class Taxonomy extends Entity`
Represents the Entity Taxonomy
### `protected static $post_type = 'tainacan-taxonomy'`
{@inheritDoc}
### `protected static $capability_type = ['tainacan-taxonomy', 'tainacan-taxonomies']`
{@inheritDoc}
### `protected $repository = 'Taxonomies'`
{@inheritDoc}
### `function register_taxonomy()`
Register the taxonomy
**Returns:** bool
### `function get_name()`
Return the name
**Returns:** string
### `function get_description()`
Return the description
**Returns:** string
### `function get_allow_insert()`
Return true if allow insert or false if not allow insert
**Returns:** boolean
### `function get_slug()`
Return the slug
**Returns:** string
### `function get_db_identifier()`
Return the DB ID
**Returns:** bool|string
### `function set_name($value)`
Define the name of taxonomy
**Parameters:**
* `$value` — [string]
### `function set_slug($value)`
Define the slug
**Parameters:**
* `$value` — [string]
### `function set_description($value)`
Define the description
**Parameters:**
* `$value` — [string]
### `function set_allow_insert($value)`
Define if allow insert or not
**Parameters:**
* `$value` — [boolean]
### `function validate()`
Validate Taxonomy
**Returns:** bool
<!-- END DOC-COMMENT -->

View File

@ -1,142 +0,0 @@
# Terms
## Terms Repository
<!-- BEGIN DOC-COMMENT H3 src/classes/repositories/class-tainacan-terms.php -->
### `class Terms extends Repository`
Class Tainacan_Terms
### `public function insert($term)`
**Parameters:**
* `$term` — Entities\Entity
**Returns:** Entities\Entity|Entities\Term
### `public function fetch( $args = [], $taxonomies = [])`
fetch terms based on ID or get terms args
Terms are stored as WordPress regular terms. Check (@see https://developer.wordpress.org/reference/functions/get_terms/) get_terms() docs to learn all args accepted in the $args parameter
The second paramater specifies from which taxonomies terms should be fetched. You can pass the Taxonomy ID or object, or an Array of IDs or taxonomies objects
**Parameters:**
* `$args` — array — WP_Query args || int $args the term id
* `$taxonomies` — array — Array Entities\Taxonomy || Array int terms IDs || int collection id || Entities\Taxonomy taxonomy object
**Returns:** `array` — of Entities\Term objects || Entities\Term
<!-- END DOC-COMMENT -->
## Term Entity
<!-- BEGIN DOC-COMMENT H3 src/classes/entities/class-tainacan-term.php -->
### `class Term extends Entity`
Represents the Entity Term
### `protected $repository = 'Terms'`
{@inheritDoc}
### `function __construct($which = 0, $taxonomy = false )`
Term constructor.
**Parameters:**
* `$which` — int
* `$taxonomy` — string
### `function get_id()`
Return the unique identifier
**Returns:** integer
### `function get_name()`
Return the name
**Returns:** string
### `function get_parent()`
Return the parent ID
**Returns:** integer
### `function get_description()`
Return the description
**Returns:** string
### `function get_user()`
Return the user ID
**Returns:** integer
### `function get_taxonomy()`
Return the taxonomy
**Returns:** integer
### `function set_name($value)`
Define the name
**Parameters:**
* `$value` — [string]
### `function set_parent($value)`
Define the parent ID
**Parameters:**
* `$value` — [integer]
### `function set_description($value)`
Define the description
**Parameters:**
* `$value` — [string]
### `function set_user($value)`
Define the user associated
**Parameters:**
* `$value` — [integer]
### `function set_taxonomy($value)`
Define the taxonomy associated
**Parameters:**
* `$value` — [integer]
<!-- END DOC-COMMENT -->

View File

@ -14,8 +14,8 @@ This method takes an array as argument, with the defintion of your importer. The
```
@type string $name The name of the importer. e.g. 'Example Importer'
@type string $slug A unique slug for the importer. e.g. 'This is an example importer description'
@type string $description The importer description. e.g. 'example-importer'
@type string $slug A unique slug for the importer. e.g. 'example-importer'
@type string $description The importer description. e.g. 'This is an example importer description'
@type string $class_name The Importer Class. e.g. '\Tainacan\Importer\Test_Importer'
@type bool $manual_mapping Wether Tainacan must present the user with an interface to manually map
the metadata from the source to the target collection.

View File

@ -4,16 +4,6 @@ This page shows how the internal API works and how to create and fetch all kinds
Its important that you first get familiar with the [key concepts](key-concepts.md) of tainacan.
This page gives an overview of the API. Detailed documentation and reference on each entity can be found below:
* [Collections Reference](class-reference-collections.md)
* [Items Reference](class-reference-items.md)
* [Item Metadata Reference](class-reference-item-metadata.md)
* [Metadata Reference](class-reference-metadata.md)
* [Filters Reference](class-reference-filters.md)
* [Taxonomies Reference](class-reference-taxonomies.md)
* [Terms Reference](class-reference-terms.md)
* [Logs Reference](class-reference-logs.md)
## Overview

View File

@ -1,11 +1,11 @@
# Releasing a new version
This is a work in progress documentaion on how to release a new verion.
This is a work in progress documentaion on how to release a new version.
Assuming:
* $CURRENT_VERSION is the current "old" version (e.g. 0.2)
* $NEW_VERSION is the verion we are releasing (e.g. 0.3)
* $NEW_VERSION is the version we are releasing (e.g. 0.3)
* $GIT_PATH is where our repository is cloned
* $BUILD_PATH is where the plugin is condigured to buid
* $SVN_PATH is where the WordPress.org SVN repo is
@ -15,19 +15,22 @@ Assuming:
```
cd $GIT_PATH
git checkout develop
git pull
```
### Edit version numbers
Edit `src/readme.txt` and 'src/tainacan.php' and change the verion numbers to `$NEW_VERSION`.
Edit `src/readme.txt` and 'src/tainacan.php' and change the version numbers to `$NEW_VERSION`.
### Set build to production mode
Edit `webpack.config.js` to set production mode.
### Commit and create tag
```
git commit -am"Releasing verion $NEW_VERSION"
git tag $NEW_VERSION
git push
git push --tags
git commit -am "Releasing verion $NEW_VERSION"
```
### Build and cleanup
@ -91,6 +94,18 @@ Commit!
svn ci
```
### Create tag on git
```
git tag $NEW_VERSION
git checkout master
git merge develop
git push --all
git push --tags
```
### Set build back to development mode
Once you go back to develop branch, remember editing `webpack.config.js` to set production mode.

2567
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,43 +8,43 @@
},
"dependencies": {
"axios": "^0.18.0",
"buefy": "^0.6.6",
"bulma": "^0.7.1",
"buefy": "^0.7.0",
"bulma": "^0.7.2",
"mdi": "^2.2.43",
"moment": "^2.22.2",
"node-sass": "^4.9.3",
"node-sass": "^4.9.4",
"qs": "^6.5.2",
"t": "^0.5.1",
"v-tooltip": "^2.0.0-rc.33",
"vue": "^2.5.17",
"vue-awesome-swiper": "^3.1.3",
"vue-masonry-css": "^1.0.3",
"vue-router": "^3.0.1",
"vue-the-mask": "^0.11.1",
"vue2-hammer": "^2.0.1",
"vuedraggable": "^2.16.0",
"vuex": "^3.0.1"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"autoprefixer": "^9.1.5",
"babel-loader": "^8.0.2",
"@babel/core": "^7.1.2",
"@babel/preset-env": "^7.1.0",
"autoprefixer": "^9.2.1",
"babel-loader": "^8.0.4",
"cross-env": "^5.2.0",
"css-loader": "^1.0.0",
"element-theme-chalk": "^2.4.6",
"eslint": "^5.5.0",
"eslint-loader": "^2.1.0",
"element-theme-chalk": "^2.4.8",
"eslint": "^5.7.0",
"eslint-loader": "^2.1.1",
"eslint-plugin-vue": "^4.7.1",
"file-loader": "^2.0.0",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.0",
"uglifyjs-webpack-plugin": "^1.3.0",
"vue-custom-element": "^3.2.5",
"vue-loader": "^15.4.1",
"style-loader": "^0.23.1",
"terser-webpack-plugin": "^1.1.0",
"vue-custom-element": "^3.2.6",
"vue-loader": "^15.4.2",
"vue-template-compiler": "^2.5.17",
"webpack": "^4.17.2",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.7"
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.9"
}
}

View File

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

View File

@ -638,6 +638,9 @@
}
}
},
},
beforeDestroy() {
this.$root.$off('metadatumUpdated');
}
}
</script>

View File

@ -2,7 +2,8 @@
<div
class="page-container"
:class="{'repository-level-page' : isNewCollection }">
<tainacan-title />
<tainacan-title
:bread-crumb-items="[{ path: '', label: $i18n.get('collection') }]"/>
<form
v-if="collection != null && collection != undefined"
class="tainacan-form"
@ -835,6 +836,8 @@ export default {
},
mounted(){
this.$root.$emit('onCollectionBreadCrumbUpdate', [{ path: '', label: this.$i18n.get('settings') }]);
if (this.$route.query.fromImporter != undefined)
this.fromImporter = this.$route.query.fromImporter;

View File

@ -298,13 +298,6 @@ export default {
@import "../../scss/_variables.scss";
form#filterEditForm {
padding: 1.0em 2.0em;
border-top: 1px solid $gray2;
border-bottom: 1px solid $gray2;
margin-top: 1.0em;
}
</style>

View File

@ -1,8 +1,13 @@
<template>
<div
class="repository-level-page page-container">
<tainacan-title />
<tainacan-title
:bread-crumb-items="[
{ path: $routerHelper.getAvailableImportersPath(), label: $i18n.get('importers') },
{ path: '', label: importerType != undefined ? importerType : $i18n.get('title_importer_page') }
]"/>
<form
@click="formErrorMessage = ''"
class="tainacan-form"
label-width="120px"
v-if="importer != undefined && importer != null">
@ -80,7 +85,7 @@
<div
class="control selected-source-file"
v-if="importerFile != undefined">
<span>{{ importerFile[0].name }}</span>
<span>{{ (importerFile.length != undefined && importerFile.length > 0 ) ? importerFile[0].name : importerFile.name }}</span>
<a
target="_blank"
@click.prevent="importerFile = undefined">
@ -116,11 +121,13 @@
type="button"
@click="cancelBack">{{ $i18n.get('cancel') }}</button>
</div>
<span class="help is-danger">{{ formErrorMessage }}</span>
<div
v-if="!importer.manual_mapping"
class="control">
<button
:disabled="
(formErrorMessage != undefined && formErrorMessage != '') ||
sessionId == undefined ||
importer == undefined ||
(importer.manual_collection && collectionId == undefined) ||
@ -137,6 +144,7 @@
class="control">
<button
:disabled="
(formErrorMessage != undefined && formErrorMessage != '') ||
sessionId == undefined ||
importer == undefined ||
(importer.manual_collection && collectionId == undefined) ||
@ -169,9 +177,8 @@ export default {
isLoadingRun: false,
isLoadingUpload: false,
isFetchingCollections: false,
form: {
},
form: {},
formErrorMessage: '',
mappedCollection: {
'id': Number,
'mapping': {},
@ -248,13 +255,14 @@ export default {
},
onUploadFile() {
return new Promise((resolve, reject) => {
this.updateImporterFile({ sessionId: this.sessionId, file: this.importerFile[0] })
this.updateImporterFile({ sessionId: this.sessionId, file: (this.importerFile.length != undefined && this.importerFile.length > 0) ? this.importerFile[0] : this.importerFile})
.then(updatedImporter => {
this.importer = updatedImporter;
resolve();
})
.catch((errors) => {
this.$console.log(errors);
this.formErrorMessage = errors.error_message;
this.$console.error(errors);
reject(errors);
});
});
@ -267,7 +275,8 @@ export default {
resolve();
})
.catch((errors) => {
this.$console.log(errors);
this.formErrorMessage = errors.error_message;
this.$console.error(errors);
reject(errors);
});
});
@ -289,6 +298,7 @@ export default {
resolve();
})
.catch((errors) => {
this.formErrorMessage = errors.error_message;
this.$console.log(errors);
reject(errors);
});
@ -304,7 +314,7 @@ export default {
if (this.importer.accepts.file && !this.importer.accepts.url) {
this.onUploadFile()
.then(() => { this.isLoadingUpload = false; resolve(); })
.catch((errors) => { this.isLoadingUpload = false; this.$console.log(errors) });
.catch((errors) => { this.isLoadingUpload = false; this.$console.error(errors) });
} else if (!this.importer.accepts.file && this.importer.accepts.url) {
this.onInputURL()
.then(() => { this.isLoadingUpload = false; resolve() })

View File

@ -1,6 +1,7 @@
<template>
<div>
<b-loading
:is-full-page="false"
:active.sync="isLoading"
:can-cancel="false"/>
<button
@ -8,7 +9,19 @@
@click="isMetadataColumnCompressed = !isMetadataColumnCompressed">
<b-icon :icon="isMetadataColumnCompressed ? 'menu-left' : 'menu-right'" />
</button>
<tainacan-title />
<div class="tainacan-page-title">
<h1 v-if="isCreatingNewItem">{{ $i18n.get('title_create_item_collection') + ' ' }}<span style="font-weight: 600;">{{ collectionName }}</span></h1>
<h1 v-else>{{ $i18n.get('title_edit_item') + ' ' }}<span style="font-weight: 600;">{{ (item != null && item != undefined) ? item.title : '' }}</span></h1>
<a
@click="$router.go(-1)"
class="back-link has-text-secondary">
{{ $i18n.get('back') }}
</a>
<hr>
</div>
<transition
mode="out-in"
:name="isOnSequenceEdit && sequenceRightDirection != undefined ? (sequenceRightDirection ? 'page-right' : 'page-left') : ''">
<form
v-if="!isLoading"
class="tainacan-form"
@ -398,9 +411,26 @@
</template>
</div>
</div>
<div class="footer">
</form>
</transition>
<footer class="footer">
<!-- Sequence Progress -->
<div
v-if="isOnSequenceEdit"
class="sequence-progress-background"/>
<div
v-if="isOnSequenceEdit && itemPosition != undefined && group != null && group.items_count != undefined"
:style="{ width: (itemPosition/group.items_count)*100 + '%' }"
class="sequence-progress"/>
<!-- Last Updated Info -->
<div class="update-info-section">
<p
class="has-text-gray5"
v-if="isOnSequenceEdit">
{{ $i18n.get('label_sequence_editing_item') + " " + itemPosition + " " + $i18n.get('info_of') + " " + ((group != null && group.items_count != undefined) ? group.items_count : '') + "." }}
</p>
<p v-if="!isUpdatingValues">
{{ ($i18n.get('info_updated_at') + ' ' + lastUpdated) }}
<span class="help is-danger">{{ formErrorMessage }}</span>
@ -411,11 +441,20 @@
<b-icon icon="autorenew" />{{ $i18n.get('info_updating_metadata_values') }}
<span class="help is-danger">{{ formErrorMessage }}</span>
</p>
</div>
<div
class="form-submission-footer"
v-if="form.status == 'trash'">
<button
v-if="isOnSequenceEdit && itemPosition > 1"
@click="onPrevInSequence()"
type="button"
class="button sequence-button">
<span class="icon is-large">
<i class="mdi mdi-24px mdi-chevron-left"/>
</span>
<span>{{ $i18n.get('previous') }}</span>
</button>
<button
@click="onDeletePermanently()"
type="button"
@ -428,10 +467,30 @@
@click="onSubmit(visibility)"
type="button"
class="button is-success">{{ $i18n.get('label_publish') }}</button>
<button
v-if="isOnSequenceEdit && (group != null && group.items_count != undefined && group.items_count > itemPosition)"
@click="onNextInSequence()"
type="button"
class="button sequence-button">
<span>{{ $i18n.get('next') }}</span>
<span class="icon is-large">
<i class="mdi mdi-24px mdi-chevron-right"/>
</span>
</button>
</div>
<div
class="form-submission-footer"
v-if="form.status == 'auto-draft' || form.status == 'draft' || form.status == undefined">
<button
v-if="isOnSequenceEdit && itemPosition > 1"
@click="onPrevInSequence()"
type="button"
class="button sequence-button">
<span class="icon is-large">
<i class="mdi mdi-24px mdi-chevron-left"/>
</span>
<span>{{ $i18n.get('previous') }}</span>
</button>
<button
v-if="form.status == 'draft'"
@click="onSubmit('trash')"
@ -450,10 +509,30 @@
@click="onSubmit(visibility)"
type="button"
class="button is-success">{{ $i18n.get('label_publish') }}</button>
<button
v-if="isOnSequenceEdit && (group != null && group.items_count != undefined && group.items_count > itemPosition)"
@click="onNextInSequence()"
type="button"
class="button sequence-button">
<span>{{ $i18n.get('next') }}</span>
<span class="icon is-large">
<i class="mdi mdi-24px mdi-chevron-right"/>
</span>
</button>
</div>
<div
class="form-submission-footer"
v-if="form.status == 'publish' || form.status == 'private'">
<button
v-if="isOnSequenceEdit && itemPosition > 1"
@click="onPrevInSequence()"
type="button"
class="button sequence-button">
<span class="icon is-large">
<i class="mdi mdi-24px mdi-chevron-left"/>
</span>
<span>{{ $i18n.get('previous') }}</span>
</button>
<button
@click="onSubmit('trash')"
type="button"
@ -466,10 +545,19 @@
:disabled="formErrorMessage != undefined && formErrorMessage != ''"
@click="onSubmit(visibility)"
type="button"
class="button is-secondary">{{ $i18n.get('label_update') }}</button>
class="button is-success">{{ $i18n.get('label_update') }}</button>
<button
v-if="isOnSequenceEdit && (group != null && group.items_count != undefined && group.items_count > itemPosition)"
@click="onNextInSequence()"
type="button"
class="button sequence-button">
<span>{{ $i18n.get('next') }}</span>
<span class="icon is-large">
<i class="mdi mdi-24px mdi-chevron-right"/>
</span>
</button>
</div>
</div>
</form>
</footer>
</div>
</template>
@ -489,12 +577,17 @@ export default {
return {
pageTitle: '',
itemId: Number,
item: null,
item: {},
collectionId: Number,
sequenceId: Number,
itemPosition: Number,
isCreatingNewItem: false,
isOnSequenceEdit: false,
sequenceRightDirection: false,
isLoading: false,
isMetadataColumnCompressed: false,
metadatumCollapses: [],
collapseAll: false,
collapseAll: true,
visibility: 'publish',
form: {
collectionId: Number,
@ -542,12 +635,51 @@ export default {
},
lastUpdated() {
return this.getLastUpdated();
},
group() {
return this.getGroup();
},
itemIdInSequence() {
return this.getItemIdInSequence();
}
},
components: {
FileItem,
DocumentItem
},
watch: {
'$route.params.itemPosition'(newItemPosition, oldItemPosition) {
if (oldItemPosition == undefined)
this.sequenceRightDirection;
else if (oldItemPosition == newItemPosition)
this.sequenceRightDirection = undefined;
this.itemPosition = Number(newItemPosition);
// Saves current itemPosition to user prefs
this.$userPrefs.set('sequence_' + this.sequenceId + '_position', this.itemPosition);
// Clear form variables
this.cleanMetadata();
eventBus.clearAllErrors();
this.formErrorMessage = '';
this.isLoading = true;
// Obtains current Item ID from Sequence
this.fetchItemIdInSequence({ collectionId: this.collectionId, sequenceId: this.sequenceId, itemPosition: this.itemPosition })
.then(() => {
this.itemId = this.itemIdInSequence;
this.loadExistingItem();
})
.catch(() => {
this.isLoading = false;
});
// Obtains current Sequence Group Info
this.fetchGroup({ collectionId: this.collectionId, groupId: this.sequenceId });
}
},
methods: {
...mapActions('item', [
'sendItem',
@ -573,6 +705,14 @@ export default {
'fetchCollectionAllowComments',
'deleteItem',
]),
...mapActions('bulkedition', [
'fetchItemIdInSequence',
'fetchGroup'
]),
...mapGetters('bulkedition', [
'getItemIdInSequence',
'getGroup'
]),
onSubmit(status) {
// Puts loading on Item edition
this.isLoading = true;
@ -597,10 +737,12 @@ export default {
this.isLoading = false;
if (!this.isOnSequenceEdit) {
if (this.form.status != 'trash')
this.$router.push(this.$routerHelper.getItemPath(this.form.collectionId, this.itemId));
else
this.$router.push(this.$routerHelper.getCollectionPath(this.form.collectionId));
}
})
.catch((errors) => {
for (let error of errors.errors) {
@ -623,6 +765,12 @@ export default {
// Puts loading on Draft Item creation
this.isLoading = true;
// Updates Collection BreadCrumb
this.$root.$emit('onCollectionBreadCrumbUpdate', [
{ path: this.$routerHelper.getCollectionPath(this.collectionId), label: this.$i18n.get('items') },
{ path: '', label: this.$i18n.get('new') }
]);
// Creates draft Item
let data = {collection_id: this.form.collectionId, status: 'auto-draft', comment_status: this.form.comment_status};
this.fillExtraFormData(data);
@ -651,8 +799,9 @@ export default {
// Obtains Item Metadatum
this.fetchMetadata(this.itemId).then((metadata) => {
this.isLoading = false;
for (let metadatum of metadata) {
this.metadatumCollapses.push(metadatum.metadatum.required == 'yes');
for (let i = 0; i < metadata.length; i++) {
this.metadatumCollapses.push(false);
this.metadatumCollapses[i] = true;
}
});
},
@ -821,35 +970,35 @@ export default {
title: this.$i18n.get('label_warning'),
message: this.isOnTrash ? this.$i18n.get('info_warning_item_delete') : this.$i18n.get('info_warning_item_trash'),
onConfirm: () => {
this.deleteItem({ itemId: this.itemId, isPermanently: true })
this.deleteItem({ itemId: this.itemId, isPermanently: true });
this.$router.push(this.$routerHelper.getCollectionPath(this.form.collectionId))
}
}
});
}
},
created(){
// Obtains collection ID
this.cleanMetadata();
eventBus.clearAllErrors();
this.formErrorMessage = '';
this.collectionId = this.$route.params.collectionId;
this.form.collectionId = this.collectionId;
if (this.$route.fullPath.split("/").pop() == "new") {
this.createNewItem();
} else if (this.$route.fullPath.split("/").pop() == "edit") {
this.isLoading = true;
// Obtains current Item ID from URL
this.itemId = this.$route.params.itemId;
loadExistingItem() {
// Initializes Media Frames now that itemId exists
this.initializeMediaFrames();
this.fetchItem(this.itemId).then(res => {
this.item = res;
// Updates Collection BreadCrumb
if (this.isOnSequenceEdit) {
this.$root.$emit('onCollectionBreadCrumbUpdate', [
{ path: this.$routerHelper.getCollectionPath(this.collectionId), label: this.$i18n.get('items') },
{ path: '', label: this.$i18n.get('sequence') },
{ path: '', label: this.item.title },
{ path: '', label: this.$i18n.get('edit') }
]);
} else {
this.$root.$emit('onCollectionBreadCrumbUpdate', [
{ path: this.$routerHelper.getCollectionPath(this.collectionId), label: this.$i18n.get('items') },
{ path: this.$routerHelper.getItemPath(this.form.collectionId, this.itemId), label: this.item.title },
{ path: '', label: this.$i18n.get('edit') }
]);
}
// Fills hook forms with it's real values
this.$nextTick()
.then(() => {
@ -876,6 +1025,62 @@ export default {
// Fetch current existing attachments
this.fetchAttachments(this.itemId);
},
onNextInSequence() {
this.sequenceRightDirection = true;
this.$router.push(this.$routerHelper.getCollectionSequenceEditPath(this.collectionId, this.sequenceId, this.itemPosition + 1));
},
onPrevInSequence() {
this.sequenceRightDirection = false;
this.$router.push(this.$routerHelper.getCollectionSequenceEditPath(this.collectionId, this.sequenceId, this.itemPosition - 1));
}
},
created(){
// Obtains collection ID
this.cleanMetadata();
eventBus.clearAllErrors();
this.formErrorMessage = '';
this.collectionId = this.$route.params.collectionId;
this.form.collectionId = this.collectionId;
// CREATING NEW SINGLE ITEM
if (this.$route.fullPath.split("/").pop() == "new") {
this.isCreatingNewItem = true;
this.createNewItem();
// EDITING EXISTING ITEM
} else if (this.$route.fullPath.split("/").pop() == "edit") {
this.isLoading = true;
// Obtains current Item ID from URL
this.itemId = this.$route.params.itemId;
this.loadExistingItem();
// EDITING EXISTING SEQUENCE
} else if (this.$route.params.collectionId != undefined && this.$route.params.sequenceId != undefined){
this.isLoading = true;
this.sequenceId = this.$route.params.sequenceId;
let savedItemPosition = (this.$userPrefs.get('sequence_' + this.sequenceId + '_position') != undefined ? Number(this.$userPrefs.get('sequence_' + this.sequenceId + '_position')) : 1);
this.itemPosition = this.$route.params.itemPosition != undefined ? Number(this.$route.params.itemPosition) : savedItemPosition;
this.isOnSequenceEdit = true;
// Saves current itemPosition to user prefs
this.$userPrefs.set('sequence_' + this.sequenceId + '_position', this.itemPosition);
// Obtains current Item ID from Sequence
this.fetchItemIdInSequence({ collectionId: this.collectionId, sequenceId: this.sequenceId, itemPosition: this.itemPosition })
.then(() => {
this.itemId = this.itemIdInSequence;
this.loadExistingItem();
})
.catch(() => {
this.isLoading = false;
});
// Obtains current Sequence Group Info
this.fetchGroup({ collectionId: this.collectionId, groupId: this.sequenceId });
}
// Obtains collection name
@ -891,13 +1096,6 @@ export default {
// Sets feedback variables
eventBus.$on('isUpdatingValue', (status) => {
this.isUpdatingValues = status;
// if (this.isUpdatingValues) {
// this.$toast.open({
// duration: 2000,
// message: this.$i18n.get('info_updating_metadata_values'),
// position: 'is-bottom',
// })
// }
});
eventBus.$on('hasErrorsOnForm', (hasErrors) => {
if (hasErrors)
@ -907,6 +1105,10 @@ export default {
});
this.cleanLastUpdated();
},
beforeDestroy () {
eventBus.$off('isUpdatingValue');
eventBus.$off('hasErrorsOnForm');
},
beforeRouteLeave ( to, from, next ) {
if (this.item.status == 'auto-draft') {
this.$modal.open({
@ -962,8 +1164,33 @@ export default {
}
.tainacan-page-title {
padding-left: $page-side-padding;
padding-right: $page-side-padding;
padding: 0 $page-side-padding;
margin-bottom: 40px;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: space-between;
h1, h2 {
font-size: 20px;
font-weight: 500;
color: $gray5;
display: inline-block;
width: 80%;
flex-shrink: 1;
flex-grow: 1;
}
a.back-link{
font-weight: 500;
float: right;
margin-top: 5px;
}
hr{
margin: 3px 0px 4px 0px;
height: 1px;
background-color: $secondary;
width: 100%;
}
}
.column.is-5-5 {
@ -1143,6 +1370,9 @@ export default {
margin-left: 16px;
margin-right: 6px;
}
.is-outlined {
border: none;
}
}
@keyframes blink {
@ -1170,6 +1400,34 @@ export default {
margin-top: 0;
margin-left: 24px;
}
.sequence-progress {
height: 5px;
background: $turquoise5;
width: 0%;
position: absolute;
top: 0;
left: 0;
transition: width 0.2s;
}
.sequence-progress-background {
height: 5px;
background: $gray3;
width: 100%;
position: absolute;
top: 0;
left: 0;
}
.sequence-button {
background-color: transparent;
color: $turquoise5;
border: none;
.icon {
margin-top: 0.3rem;
}
}
}
</style>

View File

@ -188,20 +188,20 @@
</b-field>
<b-field
:type="formErrors['unique'] != undefined ? 'is-danger' : ''"
:message="formErrors['unique'] != undefined ? formErrors['unique'] : ''">
:type="formErrors['collection_key'] != undefined ? 'is-danger' : ''"
:message="formErrors['collection_key'] != undefined ? formErrors['collection_key'] : ''">
<b-checkbox
size="is-small"
@input="clearErrors('unique')"
v-model="editForm.unique"
@input="clearErrors('collection_key')"
v-model="editForm.collection_key"
true-value="yes"
false-value="no"
class="is-inline-block"
name="collecion_key">
{{ $i18n.get('label_unique_value') }}
<help-button
:title="$i18n.getHelperTitle('metadata', 'unique')"
:message="$i18n.getHelperMessage('metadata', 'unique')"/>
:title="$i18n.getHelperTitle('metadata', 'collection_key')"
:message="$i18n.getHelperMessage('metadata', 'collection_key')"/>
</b-checkbox>
</b-field>
</b-field>

View File

@ -1,7 +1,11 @@
<template>
<div>
<div class="page-container repository-level-page">
<tainacan-title />
<tainacan-title
:bread-crumb-items="[
{ path: $routerHelper.getTaxonomiesPath(), label: $i18n.get('taxonomies') },
{ path: '', label: (taxonomy!= null && taxonomy.name != undefined) ? taxonomy.name : $i18n.get('taxonomy') }
]"/>
<b-tabs
@change="onChangeTab($event)"
v-model="tabIndex">
@ -142,7 +146,9 @@
<b-tab-item :label="$i18n.get('terms')">
<!-- Terms List -->
<terms-list :taxonomy-id="taxonomyId"/>
<terms-list
@isEditingTermUpdate="isEditingTermUpdate"
:taxonomy-id="taxonomyId"/>
</b-tab-item>
<b-loading
@ -169,6 +175,7 @@
taxonomy: null,
isLoadingTaxonomy: false,
isUpdatingSlug: false,
isEditinTerm: false,
form: {
name: String,
status: String,
@ -224,6 +231,19 @@
}
}
});
} else if (this.isEditinTerm) {
this.$modal.open({
parent: this,
component: CustomDialog,
props: {
icon: 'alert',
title: this.$i18n.get('label_warning'),
message: this.$i18n.get('info_warning_terms_not_saved'),
onConfirm: () => {
next();
}
}
});
} else {
next();
}
@ -278,7 +298,7 @@
this.formErrorMessage = '';
this.editFormErrors = {};
this.$router.push(this.$routerHelper.getPath());
this.$router.push(this.$routerHelper.getTaxonomiesPath());
})
.catch((errors) => {
for (let error of errors.errors) {
@ -350,10 +370,13 @@
this.editFormErrors[attribute] = undefined;
},
cancelBack(){
this.$router.push(this.$routerHelper.getPath());
this.$router.go(-1);
},
labelNewTerms(){
return ( this.form.allowInsert === 'yes' ) ? this.$i18n.get('label_yes') : this.$i18n.get('label_no');
},
isEditingTermUpdate (value) {
this.isEditinTerm = value;
}
},
mounted(){

View File

@ -101,20 +101,28 @@ export default {
},
}
});
},
eventOnEditTerm() {
this.isEditingTerm = true;
},
eventOnTermEditionSaved() {
this.isEditingTerm = false;
this.term.opened = false;
},
eventOnTermEditionCanceled() {
this.isEditingTerm = false;
this.term.opened = false;
}
},
created() {
this.$termsListBus.$on('editTerm', () => {
this.isEditingTerm = true;
});
this.$termsListBus.$on('termEditionSaved', () => {
this.isEditingTerm = false;
this.term.opened = false;
});
this.$termsListBus.$on('termEditionCanceled', () => {
this.isEditingTerm = false;
this.term.opened = false;
});
this.$termsListBus.$on('editTerm', this.eventOnEditTerm);
this.$termsListBus.$on('termEditionSaved', this.eventOnTermEditionSaved);
this.$termsListBus.$on('termEditionCanceled', this.eventOnTermEditionCanceled);
},
beforeDestroy() {
this.$termsListBus.$off('editTerm', this.eventOnEditTerm);
this.$termsListBus.$off('termEditionSaved', this.eventOnTermEditionSaved);
this.$termsListBus.$off('termEditionCanceled', this.eventOnTermEditionCanceled);
}
}
</script>

View File

@ -144,7 +144,10 @@
// this.notApprove(eventId);
// },
goToEventPage(eventId) {
if (this.$route.params.collectionId == undefined)
this.$router.push(this.$routerHelper.getEventPath(eventId));
else
this.$router.push(this.$routerHelper.getCollectionEventPath(this.$route.params.collectionId, eventId));
}
}
}

View File

@ -35,7 +35,7 @@
<div
class="active-filter-item"
:class="{
'not-sortable-item': (filter.id == undefined || openedFilterId != '' || choosenMetadatum.name == filter.name || isUpdatingFiltersOrder == true || isRepositoryLevel),
'not-sortable-item': (isSelectingFilterType || filter.id == undefined || openedFilterId != '' || choosenMetadatum.name == filter.name || isUpdatingFiltersOrder == true || isRepositoryLevel),
'not-focusable-item': openedFilterId == filter.id,
'disabled-filter': filter.enabled == false,
'inherited-filter': filter.collection_id != collectionId || isRepositoryLevel
@ -146,12 +146,15 @@
v-model="availableMetadatumList"
:options="{
sort: false,
group: { name:'filters', pull: true, put: false, revertClone: true },
group: { name:'filters', pull: !isSelectingFilterType, put: false, revertClone: true },
dragClass: 'sortable-drag'
}">
<div
class="available-metadatum-item"
:class="{'inherited-metadatum': metadatum.collection_id != collectionId || isRepositoryLevel}"
:class="{
'inherited-metadatum': metadatum.collection_id != collectionId || isRepositoryLevel,
'disabled-metadatum': isSelectingFilterType
}"
v-if="metadatum.enabled"
v-for="(metadatum, index) in availableMetadatumList"
:key="index"
@ -207,6 +210,7 @@ export default {
isLoadingFilters: false,
isLoadingFilterTypes: false,
isLoadingFilter: false,
isSelectingFilterType: false,
isUpdatingFiltersOrder: false,
openedFilterId: '',
formWithErrors: '',
@ -325,6 +329,9 @@ export default {
.catch(() => { this.isUpdatingFiltersOrder = false; });
},
addMetadatumViaButton(metadatumType, metadatumIndex) {
if (this.isSelectingFilterType == false) {
this.isSelectingFilterType = true;
this.availableMetadatumList.splice(metadatumIndex, 1);
let lastIndex = this.activeFilterList.length;
@ -332,6 +339,8 @@ export default {
this.addTemporaryFilter(metadatumType);
this.addNewFilter(metadatumType, lastIndex);
}
},
addNewFilter(choosenMetadatum, newIndex) {
this.choosenMetadatum = choosenMetadatum;
@ -348,7 +357,6 @@ export default {
}
},
createChoosenFilter() {
this.sendFilter({
collectionId: this.collectionId,
metadatumId: this.choosenMetadatum.id,
@ -391,9 +399,11 @@ export default {
this.updateFiltersOrder();
},
confirmSelectedFilterType() {
this.isSelectingFilterType = false;
this.createChoosenFilter();
},
cancelFilterTypeSelection() {
this.isSelectingFilterType = false;
this.availableMetadatumList.push(this.choosenMetadatum);
this.choosenMetadatum = {};
this.allowedFilterTypes = [];
@ -441,10 +451,12 @@ export default {
delete this.editForms[this.openedFilterId];
this.openedFilterId = '';
}
},
mounted() {
if (!this.isRepositoryLevel)
this.$root.$emit('onCollectionBreadCrumbUpdate', [{ path: '', label: this.$i18n.get('filter') }]);
this.isRepositoryLevel = this.$route.name == 'FiltersPage' ? true : false;
if (this.isRepositoryLevel)
this.collectionId = 'default';
@ -534,6 +546,13 @@ export default {
transition: top 0.1s ease;
cursor: grab;
form.tainacan-form {
padding: 1.0em 2.0em;
margin-top: 1.0em;
border-top: 1px solid $gray2;
border-bottom: 1px solid $gray2;
}
&>.field, form {
background-color: white !important;
}
@ -738,10 +757,11 @@ export default {
.sortable-drag {
opacity: 1 !important;
}
.available-metadatum-item:hover {
.available-metadatum-item:not(.disabled-metadatum) {
&:hover{
background-color: $secondary;
border-color: $secondary;
color: white;
color: white !important;
position: relative;
left: -4px;
@ -759,6 +779,7 @@ export default {
}
}
}
}
.inherited-filter {
&.active-filter-item:hover:not(.not-sortable-item) {

View File

@ -42,7 +42,12 @@
<b-dropdown-item
v-if="$route.params.collectionId && $userCaps.hasCapability('edit_others_posts') && !isOnTrash"
@click="openBulkEditionModal()">
{{ $i18n.get('label_edit_selected_items') }}
{{ $i18n.get('label_bulk_edit_selected_items') }}
</b-dropdown-item>
<b-dropdown-item
v-if="$route.params.collectionId && $userCaps.hasCapability('edit_others_posts') && !isOnTrash"
@click="sequenceEditSelectedItems()">
{{ $i18n.get('label_sequence_edit_selected_items') }}
</b-dropdown-item>
<b-dropdown-item
v-if="collectionId"
@ -68,7 +73,7 @@
:active.sync="isLoading"/>
</div>
<!-- GRID VIEW MODE -->
<!-- GRID (THUMBNAILS) VIEW MODE -->
<div
class="tainacan-grid-container"
v-if="viewMode == 'grid'">
@ -182,8 +187,7 @@
<!-- Title -->
<div
:style="{
'padding-left': !collectionId ? '0.5rem !important' : '2.75rem',
'margin-left': !collectionId ? '0 !important' : '24px'
'padding-left': !collectionId ? '0 !important' : '1rem'
}"
@click="onClickItem($event, item, index)"
class="metadata-title">
@ -585,7 +589,7 @@
column.metadatum !== 'row_actions' &&
column.metadatum !== 'row_creation' &&
column.metadatum !== 'row_author'"
v-html="renderMetadata(item.metadata, column) != '' ? renderMetadata(item.metadata, column) : `<span class='has-text-gray is-italic'>` + $i18n.get('label_value_not_informed') + `</span>`"/>
v-html="renderMetadata(item.metadata, column) != '' ? renderMetadata(item.metadata, column, column.metadata_type_object.component) : `<span class='has-text-gray is-italic'>` + $i18n.get('label_value_not_informed') + `</span>`"/>
<span v-if="column.metadatum == 'row_thumbnail'">
<img
@ -721,6 +725,10 @@ export default {
...mapGetters('bulkedition', [
'getGroupID'
]),
...mapGetters('search', [
'getOrder',
'getOrderBy'
]),
openBulkEditionModal(){
this.$modal.open({
parent: this,
@ -735,6 +743,17 @@ export default {
width: 'calc(100% - 8.333333333%)',
});
},
sequenceEditSelectedItems() {
this.createEditGroup({
object: Object.keys(this.queryAllItemsSelected).length ? this.queryAllItemsSelected : this.selectedItemsIDs.filter(item => item !== false),
collectionID: this.collectionId,
order: this.getOrder(),
orderBy: this.getOrderBy()
}).then(() => {
let sequenceId = this.getGroupID();
this.$router.push(this.$routerHelper.getCollectionSequenceEditPath(this.collectionId, sequenceId, 1));
});
},
selectAllItemsOnPage() {
for (let i = 0; i < this.selectedItems.length; i++) {
this.selectedItems.splice(i, 1, !this.allItemsOnPageSelected);
@ -881,7 +900,7 @@ export default {
goToItemEditPage(item) {
this.$router.push(this.$routerHelper.getItemEditPath(item.collection_id, item.id));
},
renderMetadata(itemMetadata, column) {
renderMetadata(itemMetadata, column, component) {
let metadata = (itemMetadata != undefined && itemMetadata[column.slug] != undefined) ? itemMetadata[column.slug] : false;
@ -890,6 +909,9 @@ export default {
} else if (metadata.date_i18n) {
return metadata.date_i18n;
} else {
if (component != undefined && component == 'tainacan-textarea')
return metadata.value_as_string;
else
return metadata.value_as_html;
}
},

View File

@ -42,7 +42,7 @@
'not-sortable-item': isRepositoryLevel || metadatum.id == undefined || openedMetadatumId != '' || isUpdatingMetadataOrder,
'not-focusable-item': openedMetadatumId == metadatum.id,
'disabled-metadatum': metadatum.enabled == false,
'inherited-metadatum': metadatum.collection_id != collectionId || isRepositoryLevel
'inherited-metadatum': (metadatum.collection_id != collectionId && metadatum.parent == 0) || isRepositoryLevel
}"
v-for="(metadatum, index) in activeMetadatumList"
:key="index">
@ -50,7 +50,10 @@
<grip-icon/>
<span class="icon icon-level-identifier">
<i
:class="{ 'mdi-folder has-text-turquoise5': (metadatum.collection_id == collectionId && !isRepositoryLevel), 'mdi-folder-multiple has-text-blue5': metadatum.collection_id != collectionId || isRepositoryLevel}"
:class="{
'mdi-folder has-text-turquoise5': (metadatum.collection_id != 'default' && !isRepositoryLevel),
'mdi-folder-multiple has-text-blue5': (metadatum.collection_id == 'default') || isRepositoryLevel
}"
class="mdi" />
</span>
<span
@ -757,6 +760,10 @@ export default {
}
},
mounted() {
if (!this.isRepositoryLevel)
this.$root.$emit('onCollectionBreadCrumbUpdate', [{ path: '', label: this.$i18n.get('metadata') }]);
this.cleanMetadata();
this.isLoadingMetadatumTypes = true;
this.isLoadingMetadata = true;
@ -901,9 +908,9 @@ export default {
cursor: default;
background-color: white !important;
.handle .label-details, .handle .icon, {
color: $gray3 !important;
}
// .handle .label-details, .handle .icon, {
// color: $gray3 !important;
// }
}
&.not-focusable-item, &.not-focusable-item:hover {
cursor: default;

View File

@ -62,7 +62,9 @@
</a>
</span>
</div>
<transition-group name="filter-item">
<transition-group
class="children-area"
name="filter-item">
<div
class="term-item"
:style="{
@ -229,24 +231,34 @@ export default {
},
}
});
},
eventOnChildTermDeleted(parentTermId) {
if (this.term.id == parentTermId && this.totalTerms > 0)
this.totalTerms--;
},
eventOnEditTerm() {
this.isEditingTerm = true;
},
eventOnTermEditionSaved() {
this.isEditingTerm = false;
this.term.opened = false;
},
eventOnTermEditionCanceled() {
this.isEditingTerm = false;
this.term.opened = false;
}
},
created() {
this.$root.$on('onChildTermDeleted', (parentTermId) => {
if (this.term.id == parentTermId && this.totalTerms > 0)
this.totalTerms--;
});
this.$termsListBus.$on('editTerm', () => {
this.isEditingTerm = true;
});
this.$termsListBus.$on('termEditionSaved', () => {
this.isEditingTerm = false;
this.term.opened = false;
});
this.$termsListBus.$on('termEditionCanceled', () => {
this.isEditingTerm = false;
this.term.opened = false;
});
this.$root.$on('onChildTermDeleted', this.eventOnChildTermDeleted);
this.$termsListBus.$on('editTerm', this.eventOnEditTerm);
this.$termsListBus.$on('termEditionSaved', this.eventOnTermEditionSaved);
this.$termsListBus.$on('termEditionCanceled', this.eventOnTermEditionCanceled);
},
beforeDestroy() {
this.$root.$off('onChildTermDeleted', this.eventOnChildTermDeleted);
this.$termsListBus.$off('editTerm', this.eventOnEditTerm);
this.$termsListBus.$off('termEditionSaved', this.eventOnTermEditionSaved);
this.$termsListBus.$off('termEditionCanceled', this.eventOnTermEditionCanceled);
}
}
</script>
@ -279,6 +291,7 @@ export default {
}
}
.children-icon {
color: $blue2;
position: absolute;

View File

@ -175,6 +175,9 @@ export default {
},
taxonomyId() {
this.loadTerms(0);
},
isEditingTerm(value) {
this.$emit('isEditingTermUpdate', value);
}
},
components: {
@ -352,18 +355,12 @@ export default {
.catch((error) => {
this.$console.log(error);
});
}
},
created() {
if (this.taxonomyId !== String) {
this.loadTerms(0);
}
this.$root.$on('onChildTermDeleted', (parentTermId) => {
eventOnChildTermDeleted(parentTermId) {
if ((parentTermId == 0 || parentTermId == undefined ) && this.totalTerms > 0)
this.totalTerms--;
});
this.$termsListBus.$on('editTerm', (term) => {
},
eventOnEditTerm(term) {
// Position edit form in a visible area
let container = document.getElementById('repository-container');
if (container && container.scrollTop && container.scrollTop > 80)
@ -373,24 +370,37 @@ export default {
this.editTerm = term;
this.isEditingTerm = true;
});
this.$termsListBus.$on('termEditionSaved', ({hasChangedParent}) => {
},
eventOnTermEditionSaved({hasChangedParent}) {
this.isEditingTerm = false;
this.editTerm = null;
if (hasChangedParent)
this.loadTerms(0);
});
this.$termsListBus.$on('termEditionCanceled', () => {
},
eventOnTermEditionCanceled() {
this.isEditingTerm = false;
this.editTerm = null;
});
this.$termsListBus.$on('addNewChildTerm', (parentId) => {
this.addNewTerm(parentId);
});
this.$termsListBus.$on('deleteBasicTermItem', (term) => {
this.deleteBasicTerm(term);
});
}
},
created() {
if (this.taxonomyId !== String) {
this.loadTerms(0);
}
this.$root.$on('onChildTermDeleted', this.eventOnChildTermDeleted);
this.$termsListBus.$on('editTerm', this.eventOnEditTerm);
this.$termsListBus.$on('termEditionSaved', this.eventOnTermEditionSaved);
this.$termsListBus.$on('termEditionCanceled', this.eventOnTermEditionCanceled);
this.$termsListBus.$on('addNewChildTerm', this.addNewTerm);
this.$termsListBus.$on('deleteBasicTermItem', this.deleteBasicTerm);
},
beforeDestroy() {
this.$root.$off('onChildTermDeleted', this.eventOnChildTermDeleted);
this.$termsListBus.$off('editTerm', this.eventOnEditTerm);
this.$termsListBus.$off('termEditionSaved', this.eventOnTermEditionSaved);
this.$termsListBus.$off('termEditionCanceled', this.eventOnTermEditionCanceled);
this.$termsListBus.$off('addNewChildTerm', this.addNewTerm);
this.$termsListBus.$off('deleteBasicTermItem', this.deleteBasicTerm);
}
}

View File

@ -27,19 +27,26 @@
<nav class="breadcrumbs">
<router-link
tag="a"
:to="$routerHelper.getCollectionsPath()">{{ $i18n.get('repository') }}</router-link> >
<span
v-for="(pathItem, index) in arrayRealPath"
:key="index">
:to="$routerHelper.getCollectionsPath()">{{ $i18n.get('repository') }}</router-link>
&nbsp;>&nbsp;
<router-link
v-if="index < arrayRealPath.length - 1"
tag="a"
:to="'/' + arrayRealPath.slice(0, index + 1).join('/')">
{{ arrayViewPath[index] }}
</router-link>
<span v-if="index == arrayRealPath.length - 1">{{ arrayViewPath[index] }}</span>
<span v-if="index != arrayRealPath.length - 1 && arrayViewPath[index]"> > </span>
</span>
:to="$routerHelper.getCollectionsPath()">{{ $i18n.get('collections') }}</router-link>
&nbsp;>&nbsp;
<router-link
tag="a"
:to="{ path: collectionBreadCrumbItem.url, query: { fromBreadcrumb: true }}">{{ collectionBreadCrumbItem.name }}</router-link>
<template v-for="(childBreadCrumbItem, index) of childrenBreadCrumbItems">
<span :key="index">&nbsp;>&nbsp;</span>
<router-link
:key="index"
v-if="childBreadCrumbItem.path != ''"
tag="a"
:to="childBreadCrumbItem.path">{{ childBreadCrumbItem.label }}</router-link>
<span
:key="index"
v-else>{{ childBreadCrumbItem.label }}</span>
</template>
</nav>
</div>
</div>
@ -137,7 +144,7 @@
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
import { mapActions } from 'vuex';
import ActivitiesIcon from '../other/activities-icon.vue';
export default {
@ -146,9 +153,10 @@ export default {
return {
activeRoute: 'ItemsList',
pageTitle: '',
arrayRealPath: [],
arrayViewPath: [],
activeRouteName: '',
collectionNameRequestCancel: undefined,
collectionBreadCrumbItem: {},
childrenBreadCrumbItems: []
}
},
components: {
@ -158,82 +166,20 @@ export default {
id: Number,
},
watch: {
'$route' (to) {
'$route' (to, from) {
if (to.path != from.path) {
this.activeRoute = to.name;
this.pageTitle = this.$route.meta.title;
this.arrayRealPath = to.path.split("/");
this.arrayRealPath = this.arrayRealPath.filter((item) => item.length != 0);
this.generateViewPath();
}
}
},
methods: {
...mapActions('collection', [
'fetchCollectionNameAndURL'
]),
...mapGetters('collection', [
'getCollectionName',
'getCollection'
]),
...mapActions('item', [
'fetchItemTitle'
]),
...mapGetters('item', [
'getItemTitle'
]),
...mapActions('taxonomy', [
'fetchTaxonomyName'
]),
...mapGetters('taxonomy', [
'getTaxonomyName'
]),
...mapActions('event', [
'fetchEventTitle'
]),
generateViewPath() {
for (let i = 0; i < this.arrayRealPath.length; i++) {
this.arrayViewPath.push('');
if (!isNaN(this.arrayRealPath[i]) && i > 0) {
switch(this.arrayRealPath[i-1]) {
case 'collections':
this.fetchCollectionNameAndURL(this.arrayRealPath[i])
.then(collection => this.arrayViewPath.splice(i, 1, collection.name))
.catch((error) => this.$console.error(error));
break;
case 'items':
this.fetchItemTitle(this.arrayRealPath[i])
.then(itemTitle => this.arrayViewPath.splice(i, 1, itemTitle))
.catch((error) => this.$console.error(error));
break;
case 'taxonomies':
this.fetchTaxonomyName(this.arrayRealPath[i])
.then(taxonomyName => this.arrayViewPath.splice(i, 1, taxonomyName))
.catch((error) => this.$console.error(error));
break;
case 'events':
this.fetchEventTitle(this.arrayRealPath[i])
.then(eventName => this.arrayViewPath.splice(i, 1, eventName))
.catch((error) => this.$console.error(error));
break;
}
} else {
if(this.arrayRealPath[i] == 'undefined'){
this.arrayViewPath.splice(i, 1, '');
} else {
this.arrayViewPath.splice(i, 1, this.$i18n.get(this.arrayRealPath[i]));
}
}
}
collectionBreadCrumbUpdate(breadCrumbItems) {
this.childrenBreadCrumbItems = breadCrumbItems;
}
},
created() {
@ -241,10 +187,31 @@ export default {
this.pageTitle = this.$route.meta.title;
this.arrayRealPath = this.$route.path.split("/");
this.arrayRealPath = this.arrayRealPath.filter((item) => item.length != 0);
this.$root.$on('onCollectionBreadCrumbUpdate', this.collectionBreadCrumbUpdate);
},
mounted() {
this.generateViewPath();
// Cancels previous Request
if (this.collectionNameRequestCancel != undefined)
this.collectionNameRequestCancel.cancel('Collection name Canceled.');
this.fetchCollectionNameAndURL(this.id)
.then((resp) => {
resp.request
.then(collection => this.collectionBreadCrumbItem = { url: this.$routerHelper.getCollectionPath(this.id), name: collection.name })
.catch((error) => this.$console.error(error));
this.collectionNameRequestCancel = resp.source;
})
.catch((error) => this.$console.error(error));
},
beforeDestroy() {
// Cancels previous Request
if (this.collectionNameRequestCancel != undefined)
this.collectionNameRequestCancel.cancel('Collection name Canceled.');
this.$root.$on('onCollectionBreadCrumbUpdate', this.collectionBreadCrumbUpdate);
}
}
</script>

View File

@ -142,11 +142,13 @@
},
},
created(){
this.$root.$on('closeAdvancedSearchShortcut', () => {
this.$refs.advancedSearchShortcut.toggle();
});
},
beforeDestroy() {
this.$root.$off('closeAdvancedSearchShortcut');
}
}
</script>

View File

@ -13,128 +13,51 @@
class="breadcrumbs">
<router-link
tag="a"
:to="$routerHelper.getCollectionsPath()">{{ $i18n.get('repository') }}</router-link> >
<span
v-for="(pathItem, index) in arrayRealPath"
:key="index">
:to="$routerHelper.getCollectionsPath()">{{ $i18n.get('repository') }}</router-link>
<template v-for="(breadCrumbItem, index) of breadCrumbItems">
<span :key="index">&nbsp;>&nbsp;</span>
<router-link
:key="index"
v-if="breadCrumbItem.path != ''"
tag="a"
:to="'/' + arrayRealPath.slice(0, index + 1).join('/')">
{{ arrayViewPath[index] }}
</router-link>
<span v-if="index != arrayRealPath.length - 1"> > </span>
</span>
:to="breadCrumbItem.path">{{ breadCrumbItem.label }}</router-link>
<span
:key="index"
v-else>{{ breadCrumbItem.label }}</span>
</template>
</nav>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
export default {
name: 'TainacanTitle',
data(){
return {
isRepositoryLevel: true,
pageTitle: '',
arrayRealPath: [],
arrayViewPath: [],
activeRouteName: '',
entityName: ''
breadCrumbItem: {}
}
},
methods: {
...mapActions('collection', [
'fetchCollectionNameAndURL'
]),
...mapGetters('collection', [
'getCollectionName'
]),
...mapActions('item', [
'fetchItemTitle'
]),
...mapGetters('item', [
'getItemTitle'
]),
...mapActions('taxonomy', [
'fetchTaxonomyName'
]),
...mapGetters('taxonomy', [
'getTaxonomyName'
]),
...mapActions('event', [
'fetchEventTitle'
]),
...mapActions('importer', [
'fetchAvailableImporters'
]),
generateViewPath() {
for (let i = 0; i < this.arrayRealPath.length; i++) {
this.arrayViewPath.push('');
if (!isNaN(this.arrayRealPath[i]) && i > 0) {
switch(this.arrayRealPath[i-1]) {
case 'collections':
this.fetchCollectionNameAndURL(this.arrayRealPath[i])
.then(collection => { this.arrayViewPath.splice(i, 1, collection.name); this.entityName = collection.name; })
.catch((error) => this.$console.error(error));
break;
case 'items':
this.fetchItemTitle(this.arrayRealPath[i])
.then(itemName => { this.arrayViewPath.splice(i, 1, itemName); this.entityName = itemName; })
.catch((error) => this.$console.error(error));
break;
case 'taxonomies':
this.fetchTaxonomyName(this.arrayRealPath[i])
.then(taxonomyName => this.arrayViewPath.splice(i, 1, taxonomyName))
.catch((error) => this.$console.error(error));
break;
case 'events':
this.fetchEventTitle(this.arrayRealPath[i])
.then(eventName => this.arrayViewPath.splice(i, 1, eventName))
.catch((error) => this.$console.error(error));
break;
}
} else if (this.arrayRealPath[i-1] == 'importers' && i > 0){
this.fetchAvailableImporters()
.then(importers => {
this.arrayViewPath.splice(i, 1, importers[this.arrayRealPath[i]].name);
if (i != this.arrayRealPath.length - 1)
this.arrayRealPath.pop();
})
.catch((error) => this.$console.error(error));
} else {
this.arrayViewPath.splice(i, 1, this.$i18n.get(this.arrayRealPath[i]));
}
}
}
props: {
breadCrumbItems: Array
},
watch: {
'$route' (to) {
'$route' (to, from) {
if (to.path != from.path) {
this.isRepositoryLevel = (to.params.collectionId == undefined);
this.activeRoute = to.name;
this.pageTitle = this.$route.meta.title;
this.arrayRealPath = to.path.split("/");
this.arrayRealPath = this.arrayRealPath.filter((item) => item.length != 0);
this.generateViewPath();
}
}
},
created() {
this.isRepositoryLevel = (this.$route.params.collectionId == undefined);
document.title = this.$route.meta.title;
this.pageTitle = document.title;
this.arrayRealPath = this.$route.path.split("/");
this.arrayRealPath = this.arrayRealPath.filter((item) => item.length != 0);
this.generateViewPath();
}
}
</script>
@ -157,7 +80,6 @@ export default {
display: inline-block;
width: 80%;
flex-shrink: 1;
flex-grow: 1;
}
a.back-link{
font-weight: 500;

View File

@ -1,7 +1,8 @@
<template>
<div class="tainacan-modal-content">
<header class="tainacan-modal-title">
<h2>{{ this.$i18n.get('filter') }} <em>{{ filter.name }}</em></h2>
<h2 v-if="isFilter">{{ $i18n.get('filter') }} <em>{{ filter.name }}</em></h2>
<h2 v-else>{{ $i18n.get('metadatum') }} <em>{{ metadatum.name }}</em></h2>
<hr>
</header>
<div class="tainacan-form">
@ -18,6 +19,14 @@
</span>
</div>
<b-tabs
v-if="!isSearching"
size="is-small"
animated
@input="fetchSelectedLabels()"
v-model="activeTab">
<b-tab-item :label="$i18n.get('label_all_terms')">
<div
v-if="!isSearching && !isTaxonomy"
class="modal-card-body tainacan-checkbox-list-container">
@ -76,10 +85,17 @@
:ref="`${key}.${index}-tainacan-li-checkbox-model`"
:key="index">
<b-checkbox
v-if="isCheckbox"
v-model="selected"
:native-value="option.value">
{{ `${option.label}` }}
</b-checkbox>
<b-radio
v-else
v-model="selected"
:native-value="option.value">
{{ `${option.label}` }}
</b-radio>
<a
v-if="option.total_children > 0"
@click="getOptionChildren(option, key, index)">
@ -99,16 +115,61 @@
icon="chevron-down"/>
</div>
</li>
</ul>
<b-loading
:is-full-page="false"
:active.sync="isColumnLoading"/>
</ul>
</div>
<nav
style="margin-top: 10px;"
class="breadcrumb is-small has-succeeds-separator"
aria-label="breadcrumbs">
<ul>
<li
v-for="(pathItem, pi) in hierarchicalPath"
:class="{'is-active': pi === hierarchicalPath.length-1}"
:key="pi">
<a
@click="getOptionChildren(pathItem.option, pathItem.column, pathItem.element)">
{{ pathItem.option.label }}
</a>
</li>
</ul>
</nav>
</b-tab-item>
<b-tab-item
:label="$i18n.get('label_selected_terms')">
<div class="modal-card-body tainacan-tags-container">
<b-field
grouped
group-multiline>
<div
v-for="(term, index) in (selected instanceof Array ? selected : [selected])"
:key="index"
class="control">
<b-tag
v-if="selected instanceof Array ? true : selected != ''"
attached
closable
@close="selected instanceof Array ? selected.splice(index, 1) : selected = ''">
{{ isTaxonomy ? selectedTagsName[term] : term }}
</b-tag>
</div>
</b-field>
<b-loading
:is-full-page="false"
:active.sync="isSelectedTermsLoading"/>
</div>
</b-tab-item>
</b-tabs>
<!--<pre>{{ hierarchicalPath }}</pre>-->
<!--<pre>{{ totalRemaining }}</pre>-->
<!--<pre>{{ selected }}</pre>-->
<!--<pre>{{ options }}</pre>-->
<!--<pre>{{ searchResults }}</pre>-->
<!--<pre>{{ selectedTagsName }}</pre>-->
<div
v-if="isSearching"
@ -119,10 +180,17 @@
v-for="(option, key) in searchResults"
:key="key">
<b-checkbox
v-if="isCheckbox"
v-model="selected"
:native-value="option.id ? option.id : option.value">
{{ `${ option.name ? limitChars(option.name) : limitChars(option.label) }` }}
</b-checkbox>
<b-radio
v-else
v-model="selected"
:native-value="option.id ? option.id : option.value">
{{ `${ option.name ? limitChars(option.name) : limitChars(option.label) }` }}
</b-radio>
</li>
<b-loading
:is-full-page="false"
@ -169,14 +237,19 @@
taxonomy: String,
collection_id: Number,
metadatum_id: Number,
metadatum: Object,
selected: Array,
isTaxonomy: {
type: Boolean,
default: false
default: false,
},
metadatum_type: String,
metadatum_object: Object,
isRepositoryLevel: Boolean,
isCheckbox: {
type: Boolean,
default: true,
},
},
data() {
return {
@ -199,6 +272,9 @@
isSearchingLoading: false,
noMorePage: 0,
maxTextToShow: 47,
activeTab: 0,
selectedTagsName: {},
isSelectedTermsLoading: false,
}
},
updated(){
@ -216,6 +292,37 @@
}
},
methods: {
fetchSelectedLabels() {
this.isSelectedTermsLoading = true;
let selected = this.selected instanceof Array ? this.selected : [this.selected];
if(this.taxonomy_id && selected.length) {
for (const term of selected) {
if(!this.isSelectedTermsLoading){
this.isSelectedTermsLoading = true;
}
axios.get(`/taxonomy/${this.taxonomy_id}/terms/${term}`)
.then((res) => {
this.saveSelectedTagName(res.data.id, res.data.name);
this.isSelectedTermsLoading = false;
})
.catch((error) => {
this.$console.log(error);
this.isSelectedTermsLoading = false;
});
}
} else {
this.isSelectedTermsLoading = false;
}
},
saveSelectedTagName(value, label){
if(!this.selectedTagsName[value]) {
this.$set(this.selectedTagsName, `${value}`, label);
}
},
limitChars(label){
if(label.length > this.maxTextToShow){
return label.slice(0, this.maxTextToShow)+'...';
@ -252,13 +359,17 @@
getOptions(offset){
let promise = '';
// Cancels previous Request
if (this.getOptionsValuesCancel != undefined)
this.getOptionsValuesCancel.cancel('Facet search Canceled.');
if ( this.metadatum_type === 'Tainacan\\Metadata_Types\\Relationship' ) {
let collectionTarget = ( this.metadatum_object && this.metadatum_object.metadata_type_options.collection_id ) ?
this.metadatum_object.metadata_type_options.collection_id : this.collection_id;
promise = this.getValuesRelationship( collectionTarget, this.optionName, [], offset, this.maxNumOptionsCheckboxList, true);
promise
promise.request
.then(() => {
this.isCheckboxListLoading = false;
this.isSearchingLoading = false;
@ -269,7 +380,7 @@
} else {
promise = this.getValuesPlainText( this.metadatum_id, this.optionName, this.isRepositoryLevel, [], offset, this.maxNumOptionsCheckboxList, true);
promise
promise.request
.then(() => {
this.isCheckboxListLoading = false;
this.isSearchingLoading = false;
@ -278,6 +389,9 @@
this.$console.log(error);
})
}
// Search Request Token for cancelling
this.getOptionsValuesCancel = promise.source;
},
autoComplete: _.debounce( function () {
this.isSearching = !!this.optionName.length;
@ -310,7 +424,7 @@
this.getOptions(0);
}
}, 300),
}, 500),
highlightHierarchyPath(){
for(let [index, el] of this.hierarchicalPath.entries()){
let htmlEl = this.$refs[`${el.column}.${el.element}-tainacan-li-checkbox-model`][0].$el;
@ -322,12 +436,13 @@
}
}
},
addToHierarchicalPath(column, element){
addToHierarchicalPath(column, element, option){
let found = undefined;
let toBeAdded = {
column: column,
element: element
element: element,
option: option,
};
for (let f in this.hierarchicalPath) {
@ -398,7 +513,7 @@
let query_items = { 'current_query': this.query };
if(key != undefined) {
this.addToHierarchicalPath(key, index);
this.addToHierarchicalPath(key, index, option);
}
let parent = 0;
@ -480,6 +595,8 @@
collection_id: this.collection_id ? this.collection_id : this.filter.collection_id,
value: this.selected,
});
} else {
this.$emit('input', this.selected)
}
this.$emit('appliedCheckBoxModal');
@ -492,6 +609,10 @@
@import "../../scss/variables.scss";
.breadcrumb {
background-color: white !important;
}
@media screen and (max-width: 768px) {
.tainacan-modal-content {
flex-direction: column;
@ -559,7 +680,7 @@
flex-shrink: 1;
max-width: calc(50% - 8.3333333%);
.b-checkbox {
.b-checkbox, .b-radio {
max-width: 86%;
margin-right: 10px;
}
@ -573,7 +694,7 @@
display: flex;
padding: 0;
.b-checkbox {
.b-checkbox, .b-radio {
max-width: 86%;
margin-left: 0.7rem;
height: 24px;
@ -590,7 +711,7 @@
flex-shrink: 1;
max-width: calc(50% - 8.3333333%);
.b-checkbox {
.b-checkbox, .b-radio {
margin-right: 10px;
}
@ -622,7 +743,9 @@
list-style: none;
margin: 0;
padding: 0rem;
}
ul {
// For Safari
-webkit-margin-after: 0;
-webkit-margin-start: 0;
@ -640,7 +763,7 @@
}
.tainacan-checkbox-search-section {
margin-bottom: 40px;
margin-bottom: 25px;
display: flex;
align-items: center;
position: relative;
@ -703,19 +826,17 @@
min-height: 253px;
}
.tainacan-tags-container {
padding: 0 20px !important;
min-height: 253px;
}
.tainacan-modal-checkbox-search-results-body {
list-style: none;
display: flex;
flex-direction: column;
flex-wrap: wrap;
max-height: 253px;
// For Safari
-webkit-margin-after: 0;
-webkit-margin-start: 0;
-webkit-margin-end: 0;
-webkit-padding-start: 0;
-webkit-margin-before: 0;
}
.tainacan-li-no-children {

View File

@ -0,0 +1,59 @@
<template>
<div class="circular-counter html">
<svg
width="48"
height="48"
xmlns="http://www.w3.org/2000/svg">
<g>
<circle
id="circle"
class="circle-animation"
:style="{ 'animation-duration': time + 's' }"
r="16"
cy="28"
cx="28"
stroke-width="3"
stroke="white"
fill="none"/>
</g>
</svg>
</div>
</template>
<script>
export default {
name: 'CircularCounter',
props: {
time: Number
}
}
</script>
<style lang="scss" scoped>
.circular-counter {
position: relative;
float: left;
}
svg {
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
}
@keyframes loading-counter {
from {
stroke-dashoffset: -100;
}
to {
stroke-dashoffset: 0;
}
}
.circle-animation {
stroke-dasharray: 100;
animation-name: loading-counter;
animation-iteration-count: infinite;
}
</style>

View File

@ -0,0 +1,97 @@
<template>
<form action="">
<div
class="tainacan-modal-content"
style="width: auto">
<header class="tainacan-modal-title">
<h2>{{ this.$i18n.get('collections') }}</h2>
<hr>
</header>
<section class="tainacan-form">
<p>{{ $i18n.get('instruction_select_a_target_collection') }}</p>
<div
v-if="!isLoading"
class="collection-types-container">
<div
class="collection-type"
v-for="(collection, index) in collections"
:key="index"
@click="onSelectCollection(collection)">
<h4>{{ collection.name }}</h4>
<p>{{ collection.length > 200 ? (collection.description.substring(0,197) + '...') : collection.description }}</p>
</div>
</div>
<b-loading
:active.sync="isLoading"
:can-cancel="false"/>
</section>
</div>
</form>
</template>
<script>
import { mapActions } from 'vuex';
export default {
name: 'CollectionsModal',
data(){
return {
collections: [],
isLoading: false
}
},
methods: {
...mapActions('collection', [
'fetchCollections'
]),
onSelectCollection(collection) {
this.$router.push(this.$routerHelper.getNewItemPath(collection.id));
this.$parent.close();
}
},
mounted() {
this.isLoading = true;
this.fetchCollections({
page: 1,
collectionsPerPage: 96,
contextEdit: true
})
.then((res) => {
this.collections = res.collections;
this.isLoading = false;
}).catch((error) => {
this.$console.log(error);
this.isLoading = false;
});
}
}
</script>
<style lang="scss" scoped>
@import "../../scss/_variables.scss";
.collection-types-container {
.collection-type {
border-bottom: 1px solid $gray2;
padding: 15px 8.3333333%;
cursor: pointer;
&:first-child {
margin-top: 15px;
}
&:last-child {
border-bottom: none;
}
&:hover {
background-color: $gray2;
}
}
}
</style>

View File

@ -136,7 +136,8 @@ export default {
showProcessesList: false,
processesCollapses: [],
hasAnyProcessExecuting: false,
dateFormat: ''
dateFormat: '',
intervalID: null,
}
},
watch: {
@ -183,22 +184,6 @@ export default {
pauseProcess(index) {
this.updateProcess({ id: this.bgProcesses[index].ID, status: 'closed' });
},
// resumeProcess(index) {
// this.updateProcess({ id: this.bgProcesses[index].ID, status: 'open' });
// },
getProcessState(){
// Recursively
this.fetchProcesses({
page: 1,
processesPerPage: 12
}).then(() => {
setTimeout(() => {
if (this.getUnfinishedProcesses() > 0) {
this.getProcessState();
}
}, 20000);
});
}
},
created() {
let locale = navigator.language;
@ -208,9 +193,21 @@ export default {
let localeData = moment.localeData();
this.dateFormat = localeData.longDateFormat('lll');
this.getProcessState();
this.intervalID = setInterval(() => {
this.fetchProcesses({
page: 1,
processesPerPage: 12
}).then(() => {
if (this.getUnfinishedProcesses() > 0) {
clearInterval(this.intervalID);
}
});
}, 20000);
this.showProcessesList = false;
},
beforeDestroy() {
clearInterval(this.intervalID);
}
}
</script>

View File

@ -42,7 +42,12 @@
open: false,
},
created(){
this.fetchCollections({page: 1, collectionsPerPage: -1, status: null});
this.fetchCollections({
page: 1,
collectionsPerPage: -1,
status: null,
contextEdit: false
});
},
mounted(){
let routeQueries = this.$route.query;

View File

@ -6,8 +6,10 @@
import Vue from 'vue';
import Buefy from 'buefy';
import VTooltip from 'v-tooltip';
import { VueHammer } from 'vue2-hammer';
// import { VueHammer } from 'vue2-hammer';
import VueMasonry from 'vue-masonry-css';
import draggable from 'vuedraggable';
import VueTheMask from 'vue-the-mask';
// Custom elements
import Text from '../../classes/metadata-types/text/Text.vue';
@ -30,7 +32,6 @@ import FilterTaginput from '../../classes/filter-types/taginput/Taginput.vue';
import FilterTaxonomyCheckbox from '../../classes/filter-types/taxonomy/Checkbox.vue';
import FilterTaxonomyTaginput from '../../classes/filter-types/taxonomy/Taginput.vue';
import FilterTaxonomySelectbox from '../../classes/filter-types/taxonomy/Selectbox.vue';
import TainacanFormItem from '../../classes/metadata-types/tainacan-form-item.vue';
import TainacanFiltersList from '../../classes/filter-types/tainacan-filter-item.vue';
@ -39,18 +40,16 @@ import TainacanFiltersList from '../../classes/filter-types/tainacan-filter-item
import AdminPage from '../admin.vue'
import HelpButton from '../components/other/help-button.vue';
import TainacanTitle from '../components/navigation/tainacan-title.vue';
import draggable from 'vuedraggable'
import store from '../../js/store/store'
import router from './router'
import eventBusSearch from '../../js/event-bus-search';
import termsListBus from './terms-list-bus.js';
import { I18NPlugin, UserPrefsPlugin, RouterHelperPlugin, ConsolePlugin, UserCapabilitiesPlugin } from './utilities';
import VueTheMask from 'vue-the-mask';
// Configure and Register Plugins
Vue.use(Buefy);
Vue.use(VTooltip);
Vue.use(VueHammer);
// Vue.use(VueHammer);
Vue.use(VueMasonry);
Vue.use(I18NPlugin);
Vue.use(UserPrefsPlugin);
@ -82,7 +81,6 @@ Vue.component('tainacan-filter-checkbox', FilterCheckbox);
Vue.component('tainacan-filter-taginput', FilterTaginput);
Vue.component('tainacan-filter-taxonomy-checkbox', FilterTaxonomyCheckbox);
Vue.component('tainacan-filter-taxonomy-taginput', FilterTaxonomyTaginput);
Vue.component('tainacan-filter-taxonomy-selectbox', FilterTaxonomySelectbox);
/* Others */
Vue.component('help-button', HelpButton);
@ -95,6 +93,7 @@ Vue.use(eventBusSearch, { store: store, router: router});
// Changing title of pages
router.beforeEach((to, from, next) => {
document.title = to.meta.title;
if (next() != undefined)
next();
});

View File

@ -53,7 +53,10 @@ const routes = [
{ path: 'settings', component: CollectionEditionForm, name: 'CollectionEditionForm', meta: {title: i18nGet('title_collection_settings'), icon: 'folder-multiple'} },
{ path: 'metadata', component: MetadataList, name: 'MetadataList', meta: {title: i18nGet('title_collection_metadata_edition'), icon: 'folder-multiple'} },
{ path: 'filters', component: FiltersList, name: 'FiltersList', meta: {title: i18nGet('title_collection_filters_edition'), icon: 'folder-multiple'} },
{ path: 'events', component: EventsPage, name: 'CollectionEventsPage', meta: {title: i18nGet('title_collection_events'), icon: 'flash'} }
{ path: 'events', component: EventsPage, name: 'CollectionEventsPage', meta: {title: i18nGet('title_collection_events'), icon: 'flash'} },
{ path: 'events/:eventId', name: 'CollectionEventPage', component: EventPage, meta: {title: i18nGet('title_event_page'), icon: 'flash'} },
{ path: 'sequence/:sequenceId', name: 'SavedSequenceEditionForm', component: ItemEditionForm, meta: {title: i18nGet('title_edit_item'), icon: 'folder-multiple'} },
{ path: 'sequence/:sequenceId/:itemPosition', name: 'SequenceEditionForm', component: ItemEditionForm, meta: {title: i18nGet('title_edit_item'), icon: 'folder-multiple'} },
]
},

View File

@ -2,7 +2,7 @@
import Vue from 'vue';
import Buefy from 'buefy';
import VTooltip from 'v-tooltip';
import { VueHammer } from 'vue2-hammer';
// import { VueHammer } from 'vue2-hammer';
import VueMasonry from 'vue-masonry-css';
// Custom elements
@ -26,7 +26,6 @@ import FilterTaginput from '../../classes/filter-types/taginput/Taginput.vue';
import FilterTaxonomyCheckbox from '../../classes/filter-types/taxonomy/Checkbox.vue';
import FilterTaxonomyTaginput from '../../classes/filter-types/taxonomy/Taginput.vue';
import FilterTaxonomySelectbox from '../../classes/filter-types/taxonomy/Selectbox.vue';
import TaincanFormItem from '../../classes/metadata-types/tainacan-form-item.vue';
import TaincanFiltersList from '../../classes/filter-types/tainacan-filter-item.vue';
@ -36,6 +35,7 @@ import ViewModeTable from '../../theme-helper/view-mode-table.vue';
import ViewModeCards from '../../theme-helper/view-mode-cards.vue';
import ViewModeRecords from '../../theme-helper/view-mode-records.vue';
import ViewModeMasonry from '../../theme-helper/view-mode-masonry.vue';
import ViewModeSlideshow from '../../theme-helper/view-mode-slideshow.vue';
// Remaining imports
import HelpButton from '../components/other/help-button.vue';
@ -48,7 +48,7 @@ import { I18NPlugin, UserPrefsPlugin, RouterHelperPlugin, ConsolePlugin } from '
// Configure and Register Plugins
Vue.use(Buefy);
Vue.use(VTooltip);
Vue.use(VueHammer);
// Vue.use(VueHammer);
Vue.use(VueMasonry);
Vue.use(I18NPlugin);
Vue.use(UserPrefsPlugin);
@ -78,7 +78,6 @@ Vue.component('tainacan-filter-checkbox', FilterCheckbox);
Vue.component('tainacan-filter-taginput', FilterTaginput);
Vue.component('tainacan-filter-taxonomy-checkbox', FilterTaxonomyCheckbox);
Vue.component('tainacan-filter-taxonomy-taginput', FilterTaxonomyTaginput);
Vue.component('tainacan-filter-taxonomy-selectbox', FilterTaxonomySelectbox);
/* Others */
Vue.component('help-button', HelpButton);
@ -91,6 +90,7 @@ Vue.component('view-mode-table', ViewModeTable);
Vue.component('view-mode-cards', ViewModeCards);
Vue.component('view-mode-records', ViewModeRecords);
Vue.component('view-mode-masonry', ViewModeMasonry);
Vue.component('view-mode-slideshow', ViewModeSlideshow);
Vue.use(eventBusSearch, { store: store, router: routerTheme});

View File

@ -134,7 +134,7 @@ UserPrefsPlugin.install = function (Vue, options = {}) {
}
},
get(key) {
return this.tainacanPrefs[key];
return this.tainacanPrefs[key] ? this.tainacanPrefs[key] : undefined;
},
set(key, value) {
this.tainacanPrefs[key] = value;
@ -147,7 +147,7 @@ UserPrefsPlugin.install = function (Vue, options = {}) {
if (prefs[key]) {
resolve( prefs[key] );
} else {
reject('Key ' + key + ' does not exists in user preference.');
this.tainacanPrefs[key] = value;
}
})
.catch(error => {
@ -175,6 +175,9 @@ RouterHelperPlugin.install = function (Vue, options = {}) {
getCollectionItemsPath(collectionId, query) {
return '/collections/'+ collectionId + '/items/?' + qs.stringify(query);
},
getCollectionSequenceEditPath(collectionId, sequenceId, itemPosition) {
return '/collections/'+ collectionId + '/sequence/' + sequenceId + '/' + itemPosition;
},
getCollectionMetadataPath(collectionId) {
return '/collections/'+ collectionId + '/metadata/';
},
@ -187,8 +190,8 @@ RouterHelperPlugin.install = function (Vue, options = {}) {
getItemsPath(query) {
return '/items/?' + qs.stringify(query);
},
getPath(query) {
return '/taxonomies/?' + qs.stringify(query);
getTaxonomiesPath() {
return '/taxonomies/'
},
getTaxonomyTermsPath(taxonomyId, query) {
return '/taxonomyId/' + taxonomyId + '/terms/?' + qs.stringify(query);
@ -203,7 +206,7 @@ RouterHelperPlugin.install = function (Vue, options = {}) {
return '/events/?' + qs.stringify(query);
},
getAvailableImportersPath() {
return '/importers/new';
return '/importers';
},
getProcessesPage(highlightedProcess) {
if (highlightedProcess)
@ -233,6 +236,9 @@ RouterHelperPlugin.install = function (Vue, options = {}) {
getImporterPath(importerType, sessionId) {
return '/importers/' + importerType + '/' + sessionId;
},
getCollectionEventPath(collectionId, eventId) {
return '/collections/' + collectionId + '/events/' + eventId;
},
// New
getNewCollectionPath() {
return '/collections/new';

View File

@ -1,6 +1,7 @@
<template>
<div class="repository-level-page page-container">
<tainacan-title />
<tainacan-title
:bread-crumb-items="[{ path: '', label: $i18n.get('importers') }]" />
<h3>{{ $i18n.get('label_available_importers') }}</h3>
<p>{{ $i18n.get('info_available_importers_helper') }}</p>

View File

@ -1,7 +1,8 @@
<template>
<div class="repository-level-page page-container">
<b-loading :active.sync="isLoadingMetadatumMappers"/>
<tainacan-title />
<tainacan-title
:bread-crumb-items="[{ path: '', label: this.$i18n.get('collections') }]"/>
<div
class="sub-header"
v-if="$userCaps.hasCapability('edit_tainacan-collections')">
@ -205,7 +206,11 @@ export default {
loadCollections() {
this.cleanCollections();
this.isLoading = true;
this.fetchCollections({ 'page': this.page, 'collectionsPerPage': this.collectionsPerPage, 'status': this.status })
this.fetchCollections({
'page': this.page,
'collectionsPerPage': this.collectionsPerPage,
'status': this.status,
'contextEdit': true })
.then((res) => {
this.isLoading = false;
this.totalCollections = res.total;

View File

@ -5,7 +5,8 @@
'repository-level-page': isRepositoryLevel,
'page-container': isRepositoryLevel
}">
<tainacan-title />
<tainacan-title
:bread-crumb-items="[{ path: '', label: this.$i18n.get('events') }]"/>
<div :class="{ 'above-subheader': isRepositoryLevel }">
<div
@ -285,6 +286,9 @@
this.isRepositoryLevel = (this.$route.params.collectionId === undefined);
},
mounted(){
if (!this.isRepositoryLevel)
this.$root.$emit('onCollectionBreadCrumbUpdate', [{ path: '', label: this.$i18n.get('events') }]);
if (this.$route.query.tab == 'processes' && this.isRepositoryLevel)
this.tab = 'processes';

View File

@ -1,6 +1,7 @@
<template>
<div class="repository-level-page page-container">
<tainacan-title />
<tainacan-title
:bread-crumb-items="[{ path: '', label: this.$i18n.get('filters') }]"/>
<filters-list/>
</div>
</template>

View File

@ -1,7 +1,15 @@
<template>
<div
<!-- <div <IF WE USE HAMMERJS>
v-hammer:swipe="onSwipeFiltersMenu"
:class="{'repository-level-page': isRepositoryLevel}">
:class="{
'repository-level-page': isRepositoryLevel,
'is-fullscreen': registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen
}"> -->
<div
:class="{
'repository-level-page': isRepositoryLevel,
'is-fullscreen': registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen
}">
<!-- SEARCH AND FILTERS --------------------- -->
<!-- Filter menu compress button -->
@ -11,7 +19,7 @@
autoHide: false,
placement: 'auto-start'
}"
v-if="!openAdvancedSearch"
v-if="!openAdvancedSearch && !(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)"
class="is-hidden-mobile"
id="filter-menu-compress-button"
:style="{ top: !isOnTheme ? (isRepositoryLevel ? '172px' : '120px') : '76px' }"
@ -20,7 +28,7 @@
</button>
<!-- Filters mobile modal button -->
<button
v-if="!openAdvancedSearch"
v-if="!openAdvancedSearch && !(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)"
class="is-hidden-tablet"
id="filter-menu-compress-button"
:style="{ top: !isOnTheme ? (isRepositoryLevel ? (searchControlHeight + 100) : (searchControlHeight + 70) + 'px') : (searchControlHeight - 25) + 'px' }"
@ -33,7 +41,9 @@
<!-- <transition name="filters-menu"> -->
<aside
:style="{ top: searchControlHeight + 'px' }"
v-if="!isFiltersMenuCompressed && !openAdvancedSearch"
v-if="!isFiltersMenuCompressed &&
!openAdvancedSearch &&
!(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)"
class="filters-menu tainacan-form is-hidden-mobile">
<b-loading
:is-full-page="false"
@ -111,18 +121,20 @@
<div
id="items-list-area"
class="items-list-area"
:class="{ 'spaced-to-right': !isFiltersMenuCompressed && !openAdvancedSearch }">
:class="{ 'spaced-to-right': !isFiltersMenuCompressed && !openAdvancedSearch && !(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)}">
<!-- FILTERS TAG LIST-->
<filters-tags-list
class="filter-tags-list"
:filters="filters"
v-if="hasFiltered && !openAdvancedSearch">Teste</filters-tags-list>
v-if="hasFiltered &&
!openAdvancedSearch &&
!(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)" />
<!-- SEARCH CONTROL ------------------------- -->
<div
ref="search-control"
v-if="!openAdvancedSearch"
v-if="!openAdvancedSearch && !(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)"
class="search-control">
<b-loading
:is-full-page="false"
@ -141,7 +153,7 @@
<b-icon icon="menu-down"/>
</button>
<b-dropdown-item>
<b-dropdown-item v-if="!isRepositoryLevel">
<router-link
id="a-create-item"
tag="div"
@ -149,6 +161,14 @@
{{ $i18n.get('add_one_item') }}
</router-link>
</b-dropdown-item>
<b-dropdown-item v-if="isRepositoryLevel">
<div
id="a-create-item"
tag="div"
@click="onOpenCollectionsModal">
{{ $i18n.get('add_one_item') }}
</div>
</b-dropdown-item>
<b-dropdown-item disabled>
{{ $i18n.get('add_items_bulk') + ' (Not ready)' }}
</b-dropdown-item>
@ -294,7 +314,7 @@
v-for="(viewModeOption, index) of enabledViewModes"
:key="index"
:value="viewModeOption"
v-if="registeredViewModes[viewModeOption] != undefined">
v-if="registeredViewModes[viewModeOption] != undefined && registeredViewModes[viewModeOption].full_screen == false">
<span
class="gray-icon"
v-html="registeredViewModes[viewModeOption].icon"/>
@ -373,6 +393,24 @@
</b-field>
</div>
<!-- Theme Full Screen mode, it's just a special view mode -->
<div
v-if="isOnTheme"
class="search-control-item">
<button
class="button is-white"
@click="onChangeViewMode(viewModeOption)"
v-for="(viewModeOption, index) of enabledViewModes"
:key="index"
:value="viewModeOption"
v-if="registeredViewModes[viewModeOption] != undefined && registeredViewModes[viewModeOption].full_screen == true ">
<span
class="gray-icon"
v-html="registeredViewModes[viewModeOption].icon"/>
<span class="is-hidden-touch">{{ registeredViewModes[viewModeOption].label }}</span>
</button>
</div>
<!-- Text simple search (used on mobile, instead of the one from filter list)-->
<div class="is-hidden-tablet search-control-item">
<div class="search-area">
@ -465,7 +503,8 @@
<div class="above-search-control">
<div
v-show="isLoadingItems"
v-show="isLoadingItems &&
!(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)"
class="loading-container">
<b-loading
:is-full-page="false"
@ -547,9 +586,9 @@
<component
v-else-if="isOnTheme &&
!isLoadingItems &&
registeredViewModes[viewMode] != undefined &&
registeredViewModes[viewMode].type == 'component' &&
(!isLoadingItems || !registeredViewModes[viewMode].show_pagination) &&
!openAdvancedSearch"
:collection-id="collectionId"
:displayed-metadata="displayedMetadata"
@ -661,6 +700,7 @@
import Pagination from '../../components/search/pagination.vue'
import AdvancedSearch from '../../components/advanced-search/advanced-search.vue';
import AvailableImportersModal from '../../components/other/available-importers-modal.vue';
import CollectionsModal from '../../components/other/collections-modal.vue';
import { mapActions, mapGetters } from 'vuex';
export default {
@ -774,6 +814,12 @@
'getAdminViewMode'
]),
onSwipeFiltersMenu($event) {
if (this.registeredViewModes[this.viewMode] == undefined ||
(this.registeredViewModes[this.viewMode] != undefined &&
(this.registeredViewModes[this.viewMode].full_screen == false ||
this.registeredViewModes[this.viewMode].full_screen == undefined)
)
) {
let screenWidth = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth);
if ($event.offsetDirection == 4 && screenWidth <= 768) {
@ -783,6 +829,7 @@
if (this.isFilterModalActive)
this.isFilterModalActive = false;
}
}
},
onOpenImportersModal() {
this.$modal.open({
@ -795,6 +842,13 @@
}
});
},
onOpenCollectionsModal() {
this.$modal.open({
parent: this,
component: CollectionsModal,
hasModalCard: true
});
},
updateSearch() {
this.$eventBusSearch.setSearchQuery(this.futureSearchQuery);
},
@ -812,8 +866,17 @@
this.prepareMetadata();
this.$eventBusSearch.setViewMode(viewMode);
// For view modes such as slides, we force pagination to request only 12 per page
let existingViewModeIndex = Object.keys(this.registeredViewModes).findIndex(aViewMode => aViewMode == viewMode);
if (existingViewModeIndex >= 0) {
if (!this.registeredViewModes[Object.keys(this.registeredViewModes)[existingViewModeIndex]].show_pagination) {
this.$eventBusSearch.setItemsPerPage(12);
}
}
// Updates searchControlHeight before in case we need to adjust filters position on mobile
setTimeout(() => {
if (this.$refs['search-control'] != undefined)
this.searchControlHeight = this.$refs['search-control'].clientHeight;
}, 500);
},
@ -824,6 +887,7 @@
// Updates searchControlHeight before in case we need to adjust filters position on mobile
setTimeout(() => {
if (this.$refs['search-control'] != undefined)
this.searchControlHeight = this.$refs['search-control'].clientHeight;
}, 500);
},
@ -1077,9 +1141,23 @@
},
adjustSearchControlHeight() {
this.$nextTick(() => {
if (this.$refs['search-control'] != undefined)
this.searchControlHeight = this.$refs['search-control'] ? this.$refs['search-control'].clientHeight + this.$refs['search-control'].offsetTop : 0;
this.isFiltersMenuCompressed = jQuery(window).width() <= 768;
});
},
removeEventListeners() {
// Component
this.$off();
// Window
window.removeEventListener('resize', this.adjustSearchControlHeight);
// $root
this.$root.$off('openAdvancedSearch');
// $eventBusSearch
this.$eventBusSearch.$off('isLoadingItems');
this.$eventBusSearch.$off('hasFiltered');
this.$eventBusSearch.$off('advancedSearchResults');
this.$eventBusSearch.$off('hasToPrepareMetadataAndFilters');
}
},
created() {
@ -1093,6 +1171,7 @@
this.$eventBusSearch.$on('isLoadingItems', isLoadingItems => {
this.isLoadingItems = isLoadingItems;
});
this.$eventBusSearch.$on('hasFiltered', hasFiltered => {
@ -1105,11 +1184,11 @@
});
this.$eventBusSearch.$on('hasToPrepareMetadataAndFilters', (to) => {
/* This condition is to prevent a incorrect fetch by filter or metadata when we come from items
/* This condition is to prevent a incorrect fetch by filter or metadata when we coming from items
* at collection level to items page at repository level
*/
if (this.isOnTheme || this.collectionId === to.params.collectionId) {
if (this.isOnTheme || this.collectionId === to.params.collectionId || to.query.fromBreadcrumb) {
this.prepareMetadata();
this.prepareFilters();
}
@ -1130,6 +1209,10 @@
this.prepareMetadata();
this.localDisplayedMetadata = JSON.parse(JSON.stringify(this.displayedMetadata));
// Updates Collection Header Breadcrumb
if (!this.isOnTheme)
this.$root.$emit('onCollectionBreadCrumbUpdate', [{ path: '', label: this.$i18n.get('items') }]);
// Setting initial view mode on Theme
if (this.isOnTheme) {
let prefsViewMode = !this.isRepositoryLevel ? 'view_mode_' + this.collectionId : 'view_mode';
@ -1142,6 +1225,15 @@
else
this.$eventBusSearch.setInitialViewMode(this.defaultViewMode);
}
// For view modes such as slides, we force pagination to request only 12 per page
let existingViewModeIndex = Object.keys(this.registeredViewModes).findIndex(viewMode => viewMode == this.$userPrefs.get(prefsViewMode));
if (existingViewModeIndex >= 0) {
if (!this.registeredViewModes[Object.keys(this.registeredViewModes)[existingViewModeIndex]].show_pagination) {
this.$eventBusSearch.setItemsPerPage(12);
}
}
} else {
let prefsAdminViewMode = !this.isRepositoryLevel ? 'admin_view_mode_' + this.collectionId : 'admin_view_mode';
if (this.$userPrefs.get(prefsAdminViewMode) == undefined)
@ -1164,8 +1256,12 @@
window.addEventListener('resize', this.adjustSearchControlHeight);
},
beforeDestroy() {
this.$off();
window.removeEventListener('resize', this.adjustSearchControlHeight);
this.removeEventListeners();
// Cancels previous Request
if (this.$eventBusSearch.searchCancel != undefined)
this.$eventBusSearch.searchCancel.cancel('Item search Canceled.');
}
}
</script>
@ -1174,6 +1270,31 @@
@import '../../scss/_variables.scss';
@keyframes open-full-screen {
from {
opacity: 0;
transform: scale(0.6);
}
to {
opacity: 1;
transform: scale(1.0);
}
}
.is-fullscreen {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100vw;
height: 100vh;
z-index: 999999999;
background-color: black;
transition: background-color 0.3s ease, width 0.3s ease, height 0.3s ease;
animation: open-full-screen 0.4s ease;
}
.collapse-all {
display: inline-flex;
align-items: center;

View File

@ -1,6 +1,7 @@
<template>
<div class="repository-level-page page-container">
<tainacan-title />
<tainacan-title
:bread-crumb-items="[{ path: '', label: this.$i18n.get('metadata') }]"/>
<metadata-list/>
</div>
</template>

View File

@ -1,7 +1,8 @@
<template>
<div>
<div class="repository-level-page page-container">
<tainacan-title />
<tainacan-title
:bread-crumb-items="[{ path: '', label: this.$i18n.get('taxonomies') }]"/>
<div
class="sub-header"
v-if="$userCaps.hasCapability('edit_tainacan-taxonomies')">

View File

@ -1,7 +1,15 @@
<template>
<div
<!-- <div <IF WE USE HAMMER JS>
v-hammer:swipe="onSwipeFiltersMenu"
:class="{'repository-level-page': isRepositoryLevel}">
:class="{
'repository-level-page': isRepositoryLevel,
'is-fullscreen': registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen
}"> -->
<div
:class="{
'repository-level-page': isRepositoryLevel,
'is-fullscreen': registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen
}">
<!-- SEARCH AND FILTERS --------------------- -->
<!-- Filter menu compress button -->
@ -11,7 +19,7 @@
autoHide: false,
placement: 'auto-start'
}"
v-if="!openAdvancedSearch"
v-if="!openAdvancedSearch && !(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)"
class="is-hidden-mobile"
id="filter-menu-compress-button"
:style="{ top: !isOnTheme ? (isRepositoryLevel ? '172px' : '120px') : '76px' }"
@ -20,7 +28,7 @@
</button>
<!-- Filters mobile modal button -->
<button
v-if="!openAdvancedSearch"
v-if="!openAdvancedSearch && !(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)"
class="is-hidden-tablet"
id="filter-menu-compress-button"
:style="{ top: !isOnTheme ? (isRepositoryLevel ? (searchControlHeight + 100) : (searchControlHeight + 70) + 'px') : (searchControlHeight - 25) + 'px' }"
@ -32,7 +40,9 @@
<!-- Side bar with search and filters -->
<aside
:style="{ top: searchControlHeight + 'px' }"
v-show="!isFiltersMenuCompressed && !openAdvancedSearch"
v-show="!isFiltersMenuCompressed &&
!openAdvancedSearch &&
!(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)"
class="filters-menu tainacan-form is-hidden-mobile">
<b-loading
:is-full-page="false"
@ -110,18 +120,20 @@
<div
id="items-list-area"
class="items-list-area"
:class="{ 'spaced-to-right': !isFiltersMenuCompressed && !openAdvancedSearch }">
:class="{ 'spaced-to-right': !isFiltersMenuCompressed && !openAdvancedSearch && !(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)}">
<!-- FILTERS TAG LIST-->
<filters-tags-list
class="filter-tags-list"
:filters="filters"
v-if="hasFiltered && !openAdvancedSearch">Teste</filters-tags-list>
v-if="hasFiltered &&
!openAdvancedSearch &&
!(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)" />
<!-- SEARCH CONTROL ------------------------- -->
<div
ref="search-control"
v-if="!openAdvancedSearch"
v-if="!openAdvancedSearch && !(registeredViewModes[viewMode] != undefined && registeredViewModes[viewMode].full_screen)"
class="search-control">
<b-loading
:is-full-page="false"
@ -295,7 +307,7 @@
v-for="(viewModeOption, index) of enabledViewModes"
:key="index"
:value="viewModeOption"
v-if="registeredViewModes[viewModeOption] != undefined">
v-if="registeredViewModes[viewModeOption] != undefined && registeredViewModes[viewModeOption].full_screen == false">
<span
class="gray-icon"
v-html="registeredViewModes[viewModeOption].icon"/>
@ -374,6 +386,24 @@
</b-field>
</div>
<!-- Theme Full Screen mode, it's just a special view mode -->
<div
v-if="isOnTheme"
class="search-control-item">
<button
class="button is-white"
@click="onChangeViewMode(viewModeOption)"
v-for="(viewModeOption, index) of enabledViewModes"
:key="index"
:value="viewModeOption"
v-if="registeredViewModes[viewModeOption] != undefined && registeredViewModes[viewModeOption].full_screen == true ">
<span
class="gray-icon"
v-html="registeredViewModes[viewModeOption].icon"/>
<span class="is-hidden-touch">{{ registeredViewModes[viewModeOption].label }}</span>
</button>
</div>
<!-- Text simple search (used on mobile, instead of the one from filter list)-->
<div class="is-hidden-tablet search-control-item">
<div class="search-area">
@ -772,6 +802,12 @@
'getAdminViewMode'
]),
onSwipeFiltersMenu($event) {
if (this.registeredViewModes[this.viewMode] == undefined ||
(this.registeredViewModes[this.viewMode] != undefined &&
(this.registeredViewModes[this.viewMode].full_screen == false ||
this.registeredViewModes[this.viewMode].full_screen == undefined)
)
) {
let screenWidth = (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth);
if ($event.offsetDirection == 4 && screenWidth <= 768) {
@ -781,6 +817,7 @@
if (this.isFilterModalActive)
this.isFilterModalActive = false;
}
}
},
onOpenImportersModal() {
this.$modal.open({
@ -810,6 +847,14 @@
this.prepareMetadata();
this.$eventBusSearch.setViewMode(viewMode);
// For view modes such as slides, we force pagination to request only 12 per page
let existingViewModeIndex = Object.keys(this.registeredViewModes).findIndex(aViewMode => aViewMode == viewMode);
if (existingViewModeIndex >= 0) {
if (!this.registeredViewModes[Object.keys(this.registeredViewModes)[existingViewModeIndex]].show_pagination) {
this.$eventBusSearch.setItemsPerPage(12);
}
}
// Updates searchControlHeight before in case we need to adjust filters position on mobile
setTimeout(() => {
this.searchControlHeight = this.$refs['search-control'].clientHeight;
@ -1078,6 +1123,19 @@
});
}
},
removeEventListeners() {
// Component
this.$off();
// Window
window.removeEventListener('resize', this.adjustSearchControlHeight);
// $root
this.$root.$off('openAdvancedSearch');
// $eventBusSearch
this.$eventBusSearch.$off('isLoadingItems');
this.$eventBusSearch.$off('hasFiltered');
this.$eventBusSearch.$off('advancedSearchResults');
this.$eventBusSearch.$off('hasToPrepareMetadataAndFilters');
},
created() {
this.isOnTheme = (this.$route.name === null);
@ -1139,6 +1197,15 @@
else
this.$eventBusSearch.setInitialViewMode(this.defaultViewMode);
}
// For view modes such as slides, we force pagination to request only 12 per page
let existingViewModeIndex = Object.keys(this.registeredViewModes).findIndex(viewMode => viewMode == this.$userPrefs.get(prefsViewMode));
if (existingViewModeIndex >= 0) {
if (!this.registeredViewModes[Object.keys(this.registeredViewModes)[existingViewModeIndex]].show_pagination) {
this.$eventBusSearch.setItemsPerPage(12);
}
}
} else {
let prefsAdminViewMode = !this.isRepositoryLevel ? 'admin_view_mode_' + this.collectionId : 'admin_view_mode';
if (this.$userPrefs.get(prefsAdminViewMode) == undefined)
@ -1161,8 +1228,11 @@
window.addEventListener('resize', this.adjustSearchControlHeight);
},
beforeDestroy() {
this.$off();
window.removeEventListener('resize', this.adjustSearchControlHeight);
this.removeEventListeners();
// Cancels previous Request
if (this.$eventBusSearch.searchCancel != undefined)
this.$eventBusSearch.searchCancel.cancel('Item search Canceled.');
}
}
</script>
@ -1171,6 +1241,20 @@
@import '../../scss/_variables.scss';
.is-fullscreen {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100vw;
height: 100vh;
z-index: 999999999;
background-color: black;
transition: all 0.3s ease;
}
.collapse-all {
display: inline-flex;
align-items: center;

View File

@ -2,10 +2,12 @@
<div class="columns is-fullheight">
<section class="column is-secondary-content">
<tainacan-collection-subheader :id="collectionId"/>
<router-view
id="collection-page-container"
:collection-id="collectionId"
class="page-container page-container-small"/>
</section>
</div>
</template>

View File

@ -1,8 +1,14 @@
<template>
<div>
<div class="is-fullheight">
<div class="page-container repository-level-page">
<tainacan-title/>
<div
class="page-container"
:class="{ 'repository-level-page': $route.params.collectionId == undefined }">
<tainacan-title
:bread-crumb-items="[
{ path: $routerHelper.getEventsPath(), label: $i18n.get('events') },
{ path: '', label: (event != undefined && event.title != undefined) ? event.title : $i18n.get('event') }
]"/>
<h1 class="event-titles">{{ event.description }}</h1>
<div
class="level"
@ -94,21 +100,20 @@
created() {
this.eventId = parseInt(this.$route.params.eventId);
this.fetchEvent(this.eventId);
this.fetchEvent(this.eventId).then(() => {
if (this.$route.params.collectionId != undefined)
this.$root.$emit('onCollectionBreadCrumbUpdate', [
{ path: this.$routerHelper.getCollectionEventsPath(this.$route.params.collectionId), label: this.$i18n.get('events') },
{ path: '', label: this.event.title}
]);
});
}
}
</script>
<style>
.back-hlight {
background-color: rgb(231, 255, 237);
}
.bottom-space-tainacan {
margin-bottom: 0.2rem;
}
.event-titles {
font-size: 20px;
font-weight: 500;

View File

@ -8,7 +8,15 @@
@click="isMetadataColumnCompressed = !isMetadataColumnCompressed">
<b-icon :icon="isMetadataColumnCompressed ? 'menu-left' : 'menu-right'" />
</button>
<tainacan-title/>
<div class="tainacan-page-title">
<h1>{{ $i18n.get('title_item_page') + ' ' }}<span style="font-weight: 600;">{{ (item != null && item != undefined) ? item.title : '' }}</span></h1>
<a
@click="$router.go(-1)"
class="back-link has-text-secondary">
{{ $i18n.get('back') }}
</a>
<hr>
</div>
<div class="tainacan-form">
<div class="columns">
<div class="column is-5-5">
@ -298,7 +306,7 @@
</template>
<script>
import {mapActions, mapGetters} from 'vuex'
import {mapActions, mapGetters} from 'vuex';
import FileItem from '../../components/other/file-item.vue';
import DocumentItem from '../../components/other/document-item.vue';
import { formHooks } from '../../js/mixins';
@ -313,7 +321,7 @@
isLoading: false,
isLoadingMetadatumMappers: false,
isMetadataColumnCompressed: false,
open: false,
open: true,
collectionName: '',
thumbPlaceholderPath: tainacan_plugin.base_url + '/admin/images/placeholder_square.png',
urls_open: false,
@ -407,7 +415,11 @@
});
// Obtains Item
this.fetchItem(this.itemId).then(() => {
this.fetchItem(this.itemId).then((item) => {
this.$root.$emit('onCollectionBreadCrumbUpdate', [
{ path: this.$routerHelper.getCollectionPath(this.collectionId), label: this.$i18n.get('items') },
{ path: '', label: item.title}
]);
this.loadMetadata();
});
@ -424,7 +436,6 @@
this.collectionAllowComments = collectionAllowComments;
});
}
}
</script>
@ -436,7 +447,7 @@
position: absolute;
z-index: 99;
right: 0;
top: 70px;
top: 148px;
max-width: 36px;
height: 36px;
width: 36px;
@ -462,8 +473,33 @@
}
.tainacan-page-title {
padding-left: $page-side-padding;
padding-right: $page-side-padding;
padding: 0 $page-side-padding;
margin-bottom: 40px;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: space-between;
h1, h2 {
font-size: 20px;
font-weight: 500;
color: $gray5;
display: inline-block;
width: 80%;
flex-shrink: 1;
flex-grow: 1;
}
a.back-link{
font-weight: 500;
float: right;
margin-top: 5px;
}
hr{
margin: 3px 0px 4px 0px;
height: 1px;
background-color: $secondary;
width: 100%;
}
}
.tainacan-form>.columns {

View File

@ -21,6 +21,7 @@
padding: 6px 0px;
border-radius: 0px !important;
.dropdown-item {
display: block;
text-decoration: none;
padding: 0.375rem 1rem;
font-size: 0.8125rem;

View File

@ -69,8 +69,11 @@
color: $secondary;
border: none;
}
.pagination-link:active {
box-shadow: none;
}
.pagination-link.is-current {
color: $gray4;
color: $gray4 !important;
}
.pagination-link::after:not(:last-child) {
content: ',';

View File

@ -155,8 +155,9 @@
font-size: 0.875rem;
margin: 0px;
text-overflow: ellipsis;
overflow-x: hidden;
overflow: hidden;
white-space: nowrap;
// max-height: 1rem;
}
}
img.table-thumb {

View File

@ -400,8 +400,176 @@ $modal-z: 9999999;
animation-duration: 0.2s;
animation-timing-function: ease;
}
.filtes-menu-leave-active {
.filters-menu-leave-active {
animation-name: filters-menu-out;
animation-duration: 0.2s;
animation-timing-function: ease;
}
// Slide
@keyframes slide-left-in {
from {
opacity: 0;
-ms-transform: translate(-5%, 0%) scale(0.95); /* IE 9 */
-webkit-transform: translate(-5%, 0%) scale(0.95); /* Safari */
transform: translate(-5%, 0%) scale(0.95);
}
to {
opacity: 1;
-ms-transform: translate(0, 0) scale(1); /* IE 9 */
-webkit-transform: translate(0, 0) scale(1); /* Safari */
transform: translate(0, 0) scale(1);
}
}
@keyframes slide-left-out {
from {
opacity: 1;
-ms-transform: translate(0, 0) scale(1); /* IE 9 */
-webkit-transform: translate(0, 0) scale(1); /* Safari */
transform: translate(0, 0) scale(1);
}
to {
opacity: 0;
-ms-transform: translate(10%, 0%) scale(0.95); /* IE 9 */
-webkit-transform: translate(10%, 0%) scale(0.95); /* Safari */
transform: translate(10%, 0%) scale(0.95);
}
}
.slide-left-enter-active {
animation-name: slide-left-in;
animation-duration: 0.4s;
animation-timing-function: ease;
}
.slide-left-leave-active {
animation-name: slide-left-out;
animation-duration: 0.4s;
animation-timing-function: ease;
}
@keyframes slide-right-in {
from {
opacity: 0;
-ms-transform: translate(10%, 0%) scale(0.95); /* IE 9 */
-webkit-transform: translate(10%, 0%) scale(0.95); /* Safari */
transform: translate(10%, 0%) scale(0.95);
}
to {
opacity: 1;
-ms-transform: translate(0, 0) scale(1); /* IE 9 */
-webkit-transform: translate(0, 0) scale(1); /* Safari */
transform: translate(0, 0) scale(1);
}
}
@keyframes slide-right-out {
from {
opacity: 1;
-ms-transform: translate(0, 0) scale(1); /* IE 9 */
-webkit-transform: translate(0, 0) scale(1); /* Safari */
transform: translate(0, 0) scale(1);
}
to {
opacity: 0;
-ms-transform: translate(-5%, 0%) scale(0.95); /* IE 9 */
-webkit-transform: translate(-5%, 0%) scale(0.95); /* Safari */
transform: translate(-5%, 0%) scale(0.95);
}
}
.slide-right-enter-active {
animation-name: slide-right-in;
animation-duration: 0.3s;
animation-timing-function: ease;
}
.slide-right-leave-active {
animation-name: slide-right-out;
animation-duration: 0.3s;
animation-timing-function: ease;
}
// Sequence page
// Slide
@keyframes page-left-in {
from {
opacity: 0;
-ms-transform: translate(-5%, 0%); /* IE 9 */
-webkit-transform: translate(-5%, 0%); /* Safari */
transform: translate(-5%, 0%);
}
to {
opacity: 1;
-ms-transform: translate(0, 0); /* IE 9 */
-webkit-transform: translate(0, 0); /* Safari */
transform: translate(0, 0);
}
}
@keyframes page-left-out {
from {
opacity: 1;
-ms-transform: translate(0, 0); /* IE 9 */
-webkit-transform: translate(0, 0); /* Safari */
transform: translate(0, 0);
}
to {
opacity: 0;
-ms-transform: translate(10%, 0%); /* IE 9 */
-webkit-transform: translate(10%, 0%); /* Safari */
transform: translate(10%, 0%);
}
}
.page-left-enter-active {
animation-name: page-left-in;
animation-duration: 0.4s;
animation-timing-function: ease;
}
.page-left-leave-active {
animation-name: page-left-out;
animation-duration: 0.4s;
animation-timing-function: ease;
}
@keyframes page-right-in {
from {
opacity: 0;
-ms-transform: translate(10%, 0%); /* IE 9 */
-webkit-transform: translate(10%, 0%); /* Safari */
transform: translate(10%, 0%);
}
to {
opacity: 1;
-ms-transform: translate(0, 0); /* IE 9 */
-webkit-transform: translate(0, 0); /* Safari */
transform: translate(0, 0);
}
}
@keyframes page-right-out {
from {
opacity: 1;
-ms-transform: translate(0, 0); /* IE 9 */
-webkit-transform: translate(0, 0); /* Safari */
transform: translate(0, 0);
}
to {
opacity: 0;
-ms-transform: translate(-5%, 0%); /* IE 9 */
-webkit-transform: translate(-5%, 0%); /* Safari */
transform: translate(-5%, 0%);
}
}
.page-right-enter-active {
animation-name: page-right-in;
animation-duration: 0.3s;
animation-timing-function: ease;
}
.page-right-leave-active {
animation-name: page-right-out;
animation-duration: 0.3s;
animation-timing-function: ease;
}

View File

@ -1,14 +1,19 @@
.tainacan-cards-container {
min-height: 50vh;
padding: 0;
display: flex;
flex-wrap: wrap;
flex-grow: 1;
flex-shrink: 1;
display: -ms-grid;
display: grid;
grid-template-columns: repeat(auto-fill, 455px);
grid-gap: 0px;
justify-content: space-evenly;
animation-name: item-appear;
animation-duration: 0.5s;
@media screen and (max-width: 480px) {
width: 91.666666667%;
grid-template-columns: repeat(auto-fill, 100%);
}
.selected-card {
background-color: $turquoise1;
.metadata-title {
@ -104,6 +109,8 @@
.media {
width: 100%;
display: flex;
margin: 0 !important;
.list-metadata {
padding: 0.75rem 1.375rem;

View File

@ -1,10 +1,10 @@
.tainacan-grid-container {
min-height: 50vh;
padding: 0;
display: flex;
flex-wrap: wrap;
flex-grow: 1;
flex-shrink: 1;
display: -ms-grid;
display: grid;
grid-template-columns: repeat(auto-fill, 285px);
grid-gap: 0px;
justify-content: space-evenly;
animation-name: item-appear;
animation-duration: 0.5s;
@ -18,7 +18,6 @@
flex-basis: 0;
margin: 15px;
text-align: center;
height: 100%;
&:hover {
background-color: $gray2;

View File

@ -103,6 +103,7 @@
.media {
width: 100%;
display: flex;
.list-metadata {
padding: 25px;

View File

@ -0,0 +1,466 @@
#close-fullscren-button {
border-radius: 50px;
color: white;
background-color: transparent;
border: none;
position: absolute;
top: 0;
right: 0;
padding: 1rem;
cursor: pointer;
z-index: 9999999999;
&:focus, &:active {
outline: none;
}
}
.metadata-menu {
background-color: black;
position: absolute;
z-index: 10;
width: 20.83% !important;
min-width: 180px;
min-height: 100%;
height: 100%;
padding: $page-side-padding 25px $page-side-padding $page-side-padding;
float: left;
overflow-y: auto;
overflow-x: hidden;
visibility: visible;
display: block;
transition: visibility ease 0.5s, display ease 0.5s;
@media screen and (max-width: 768px) {
width: 100% !important;
padding: $page-small-side-padding !important;
h3 {
margin-top: 0 !important;
}
}
@media screen and (min-width: 769px) {
top: 0px !important;
}
.metadata-menu-header {
display: flex;
flex-wrap: wrap;
h2 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: auto;
color: white;
font-size: 1.25rem;
font-weight: bold;
margin-bottom: 0;
}
#close-metadata-button {
border-radius: 50px;
color: white;
background-color: transparent;
border: none;
padding: 0;
cursor: pointer;
z-index: 9999999999;
&:focus, &:active {
outline: none;
}
}
hr {
margin-top: 0;
width: 100%;
background-color: $turquoise5;
}
}
h3 {
font-size: 100%;
margin-top: 0px;
}
.collapse-all {
font-size: 12px;
display: inline-flex;
align-items: center;
margin-bottom: 1rem;
.icon {
vertical-align: bottom;
}
}
// Overrides bootstrap behavior
.collapse:not(.show) {
display: initial;
}
.field {
margin-bottom: 0px !important;
border-bottom: 1px solid $gray5;
padding: 1rem 0px 0.2rem 0px;
.label {
cursor: pointer;
font-size: 14px;
font-weight: 500;
margin-bottom: 0.75rem !important;
display: inline-flex;
align-items: center;
span {
margin-right: 5px;
margin-left: -5px;
}
}
.content {
font-size: 0.75rem;
}
}
.checkbox {
margin-bottom: 5px;
align-items: baseline;
}
}
#metadata-compress-button {
position: absolute;
z-index: 99;
top: 123px;
left: 0;
max-width: 33px;
height: 26px;
width: 33px;
border: none;
background-color: $gray5;
color: white;
padding: 0;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
cursor: pointer;
transition: top 0.3s, left 0.3s, opacity 0.3s, visibility 0.3s;
&:focus, &:active {
outline: none;
}
.icon {
margin-top: 1px;
}
@media screen and (max-width: 768px) {
max-width: 100%;
width: auto;
padding: 3px 6px 3px 0px;
height: 24px;
.icon {
position: relative;
top: -3px;
}
.text {
position: relative;
top: -6px;
}
}
}
.fullscreen-spaced-to-right {
.table-wrapper {
margin-left: 20.83%;
width: calc(100vw - 20.83%) !important;
};
.tainacan-slide-main-view .arrow-left {
left: 20.83% !important;
}
.tainacan-slide-main-view .slide-main-content {
width: calc(100vw - 20.83%) !important;
}
@media screen and (max-width: 768px) {
.table-wrapper {
margin-left: 0;
width: 100vw !important;
};
.tainacan-slide-main-view .arrow-left {
left: 0 !important;
margin-left: 0;
}
.tainacan-slide-main-view .slide-main-content {
width: 100vw !important;
}
}
}
.tainacan-slide-main-view {
display: flex;
justify-content: space-between;
align-items: center;
min-height: calc(100vh - 142px);
transition: height 0.3s, min-height 0.3s;
.slide-main-content {
position: relative;
width: 100vw;
display: flex;
align-items: center;
justify-content: center;
&>div,
&>div audio,
&>div img,
&>div video,
&>div.tainacan-embed-container {
width: 100%;
max-width: 100vh;
text-align: center;
color: white;
max-height: calc(100vh - 115px);
overflow: hidden;
transition: height 0.3s, max-height 0.3s;
}
&>div img {
width: auto;
}
.empty-document {
font-size: 4rem;
font-weight: normal;
color: $gray4;
text-align: center;
position: relative;
max-height: calc(100vh - 115px);
overflow: hidden;
transition: height 0.3s, max-height 0.3s;
margin: auto;
img {
height: 100%;
}
p {
position: absolute;
margin: calc(50% - 4rem) auto;
width: 100%;
}
@media screen and (max-width: 1024px) and (min-width: 768px) {
font-size: 3rem;
p {
margin: calc(50% - 1rem) auto;
}
}
@media screen and (max-width: 768px) {
font-size: 2rem;
p {
margin: calc(50% - 2rem) auto;
}
}
}
}
}
.slide-title-area {
width: 100%;
position: absolute;
bottom: 115px;
// top: -85px;
// margin-bottom: -85px;
background-color: rgba(0,0,0,0.5);
padding: 1rem $page-side-padding;
display: flex;
justify-content: space-between;
align-items: center;
transition: opacity 0.3s, visibility 0.3s, display 0.3s;
h1 {
color: white;
font-size: 2rem;
font-weight: normal;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.play-button {
cursor: pointer;
border: 0;
background: transparent;
position: relative;
.icon {
border-radius: 100px;
background: white;
border: 3px solid $turquoise5;
}
&:focus, &:active {
outline: 0;
border: 0;
}
.circular-counter {
position: absolute;
right: calc(4.16667% + 1px);
top: -3px;
}
}
}
.slide-control-arrow {
cursor: pointer;
background-color: transparent;
border: none !important;
height: 3.5rem;
width: 3.5rem;
text-align: center;
vertical-align: middle;
position: absolute;
z-index: 9;
&:focus, &:active {
border: none;
outline: none;
}
.icon {
height: 3.5rem;
width: 2.5rem;
text-align: center;
.mdi::before {
line-height: 5rem;
font-size: 5rem;
color: $turquoise5;
text-shadow: 0px 0px 2px $gray5;
}
}
&.arrow-left {
left: 0;
margin-left: $page-side-padding;
transition: margin-left 0.3s;
}
&.arrow-right {
right: 0;
margin-right: $page-side-padding;
transition: margin-right 0.3s;
}
&.slide-group-arrow {
top: calc(50% - 33px);
.icon {
height: 2.5rem;
width: 1.5rem;
.mdi::before {
line-height: 3rem;
font-size: 3rem;
color: white;
text-shadow: 0px 0px 2px $gray5;
}
}
}
}
.tainacan-slides-list {
background-color: rgba(0,0,0,0.5);
position: relative;
transition: opacity 0.3s, visibility 0.3s, display 0.3s;
height: 115px;
min-height: 115px;
padding: 0.75rem 0;
.loading-icon {
width: 100%;
top: calc(50% - 33px);
position: absolute;
z-index: 9;
}
#tainacan-slide-container {
padding: 0 $page-side-padding;
display: flex;
flex-wrap: nowrap;
overflow: hidden;
flex-grow: 1;
flex-shrink: 1;
justify-content: space-evenly;
animation-name: item-appear;
animation-duration: 0.5s;
.selected-record {
background-color: $turquoise1;
.metadata-title {
background-color: $turquoise2;
}
.media {
background-color: $turquoise1;
}
}
.tainacan-slide-item {
cursor: pointer;
&.active-item img {
border-bottom: 4px solid $turquoise5;
}
&:hover img{
border-bottom: 4px solid $gray2;
}
img {
color: white;
width: 100%;//85px;
height: auto;
border-radius: 0px;
padding: 0 0 6px 0;
border-bottom: 4px solid transparent;
transition: border-bottom 0.4s;
}
}
}
}
.hide-controls {
// @media screen and (max-width: 768px) {
.slide-control-arrow {
visibility: hidden;
opacity: 0;
}
.arrow-right {
margin-right: 0%;
}
.arrow-left {
margin-left: 0%;
}
#metadata-compress-button {
visibility: hidden;
opacity: 0;
left: -20px;
}
.slide-title-area,
.tainacan-slides-list {
visibility: hidden;
opacity: 0;
}
.tainacan-slide-main-view {
min-height: 100vh;
.slide-main-content {
&>div,
&>div audio,
&>div img,
&>div video,
&>div.tainacan-embed-container {
max-height: 95vh;
}
}
}
.empty-document {
max-height: 95vh;
img {
width: auto;
}
}
@media screen and (max-width: 768px) {
.empty-document img { width: 100% !important; }
}
// }
}

View File

@ -32,7 +32,6 @@ body.tainacan-admin-page #adminmenumain, body.tainacan-admin-page #wpfooter, bod
html {
overflow-y: hidden;
}
#tainacan-admin-app {
background: #ffffff;
position: fixed;

View File

@ -8,3 +8,4 @@
@import "../../../node_modules/bulma/sass/elements/button.sass"
@import "../../../node_modules/bulma/sass/grid/columns.sass"
@import "../../../node_modules/bulma/sass/components/modal.sass"
@import "../../../node_modules/bulma/sass/components/breadcrumb.sass"

View File

@ -31,6 +31,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'mapping' => __( 'Mapping', 'tainacan' ),
'importers' => __( 'Importers', 'tainacan' ),
'processes' => __( 'Processes', 'tainacan' ),
'sequence' => __( 'Sequence', 'tainacan' ),
// Actions
'close' => __( 'Close', 'tainacan' ),
@ -44,6 +45,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'remove_value' => __( 'Remove value', 'tainacan' ),
'save' => __( 'Save', 'tainacan' ),
'next' => __( 'Next', 'tainacan' ),
'previous' => __( 'Previous', 'tainacan' ),
'back' => __( 'Back', 'tainacan' ),
'exit' => __( 'Exit', 'tainacan' ),
'see' => __( 'View', 'tainacan' ),
@ -72,6 +74,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'finish' => __( 'Finish', 'tainacan' ),
'select_to_create' => __( 'select to create', 'tainacan' ),
'new_action' => __( 'New action', 'tainacan' ),
'clear_radio' => __( 'Clear selected radio', 'tainacan'),
// Wordpress Status
'publish' => __( 'Publish', 'tainacan' ),
@ -231,7 +234,8 @@ return apply_filters( 'tainacan-admin-i18n', [
'label_delete_permanently' => __( 'Delete permanently', 'tainacan' ),
'label_send_to_trash' => __( 'Send to trash', 'tainacan' ),
'label_delete_selected_taxonomies' => __( 'Delete selected taxonomies', 'tainacan' ),
'label_edit_selected_items' => __( 'Edit selected items', 'tainacan' ),
'label_bulk_edit_selected_items' => __( 'Bulk edit selected items', 'tainacan' ),
'label_sequence_edit_selected_items' => __( 'Edit selected items in sequence', 'tainacan' ),
'label_edit_selected_taxonomies' => __( 'Edit selected taxonomies', 'tainacan' ),
'label_select_all_collections_page' => __( 'Select all collections on page', 'tainacan' ),
'label_select_all_items_page' => __( 'Select all items on page', 'tainacan' ),
@ -302,7 +306,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'label_show_filters' => __( 'Show filters menu', 'tainacan' ),
'label_select_all_items' => __( 'Select all items', 'tainacan' ),
'label_select_all' => __( 'Select all', 'tainacan' ),
'label_untrash_selected_items' => __( 'Remove from trash the selected items', 'tainacan' ),
'label_untrash_selected_items' => __( 'Recover from trash', 'tainacan' ),
'label_value_not_informed' => __( 'Value not informed.', 'tainacan' ),
'label_description_not_informed' => __( 'Description not informed.', 'tainacan' ),
'label_save_goto_metadata' => __( 'Save and Go to Metadata', 'tainacan' ),
@ -310,6 +314,12 @@ return apply_filters( 'tainacan-admin-i18n', [
'label_view_all_collections' => __( 'View all Collections', 'tainacan' ),
'label_view_on_theme' => __( 'View on Theme', 'tainacan' ),
'label_create_collection' => __( 'Create Collection', 'tainacan' ),
'label_hide_metadata' => __( 'Hide metadata', 'tainacan' ),
'label_show_metadata' => __( 'Show metadata', 'tainacan' ),
'label_all_terms' => __( 'All terms', 'tainacan' ),
'label_selected_terms' => __( 'Selected terms', 'tainacan'),
'label_editing_item_number' => __( 'Editing item n.', 'tainacan'),
'label_sequence_editing_item' => __( 'Sequence editing: Item', 'tainacan'),
// Instructions. More complex sentences to guide user and placeholders
'instruction_delete_selected_collections' => __( 'Delete selected collections', 'tainacan' ),
@ -348,6 +358,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'instruction_type_existing_term' => __( 'Type to add an existing term...', 'tainacan' ),
// Info. Other feedback to user.
'info_error_invalid_date' => __( 'Invalid date', 'tainacan' ),
'info_search_results' => __( 'Search Results', 'tainacan' ),
'info_search_criteria' => __( 'Search Criteria', 'tainacan' ),
'info_name_is_required' => __( 'Name is required.', 'tainacan' ),
@ -403,7 +414,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'info_warning_metadata_not_saved' => __( 'Are you sure? There are metadata not saved, changes will be lost.', 'tainacan' ),
'info_warning_filters_not_saved' => __( 'Are you sure? There are filters not saved, changes will be lost.', 'tainacan' ),
'info_no_description_provided' => __( 'No description provided.', 'tainacan' ),
'info_warning_taxonomy_not_saved' => __( 'Are you sure? The metadata is not saved, changes will be lost.', 'tainacan' ),
'info_warning_taxonomy_not_saved' => __( 'Are you sure? The taxonomy is not saved, changes will be lost.', 'tainacan' ),
'info_warning_terms_not_saved' => __( 'Are you sure? There are terms not saved, changes will be lost.', 'tainacan' ),
'info_warning_orphan_terms' => __( 'Are you sure? This term is parent of other terms. These will be converted to root terms.', 'tainacan' ),
'info_no_events' => __( 'No events', 'tainacan' ),
@ -447,7 +458,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'info_there_are_no_metadata_in_repository_level' => __( 'There are no metadata in repository level', 'tainacan' ),
'info_import_collection' => __( 'Import from external sources.', 'tainacan' ),
'info_import_items' => __( 'Import items from external sources.', 'tainacan' ),
'info_editing_items_in_bulk' => __( 'Editing items in bulk', 'tainacan' ),
'info_editing_items_in_bulk' => __( 'Bulk edit items', 'tainacan' ),
'info_by_inner' => __( 'by', 'tainacan' ),
'info_items_selected' => __( 'items selected', 'tainacan' ),
'info_items_affected' => __( 'items affected', 'tainacan' ),

View File

@ -183,6 +183,7 @@ export default {
#items-list-area {
width: 100%;
overflow-y: hidden;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
margin-left: 0;
&.spaced-to-right {

View File

@ -164,7 +164,7 @@ class REST_Controller extends \WP_REST_Controller {
foreach ( $request_meta_query as $index1 => $a ) {
// handle core metadatum
if( is_array($a) && array_key_exists("key", $a) && !$request['advancedSearch'] ){
if( is_array($a) && array_key_exists("key", $a) && ( !isset($request['advancedSearch']) || !$request['advancedSearch'] ) ){
$metadatum = new \Tainacan\Entities\Metadatum($a['key']);
if( strpos( $metadatum->get_metadata_type(), 'Core_Title') !== false ){
$args[ 'post_title_in' ] = [

View File

@ -36,6 +36,15 @@ class REST_Bulkedit_Controller extends REST_Controller {
'args' => $this->get_create_params()
),
)
);
register_rest_route($this->namespace, '/collection/(?P<collection_id>[\d]+)/' . $this->rest_base . '/(?P<group_id>[0-9a-f]+)',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_item'),
'permission_callback' => array($this, 'bulk_edit_permissions_check'),
),
)
);
register_rest_route($this->namespace, '/collection/(?P<collection_id>[\d]+)/' . $this->rest_base . '/(?P<group_id>[0-9a-f]+)/add',
array(
@ -158,6 +167,15 @@ class REST_Bulkedit_Controller extends REST_Controller {
],
),
)
);
register_rest_route($this->namespace, '/collection/(?P<collection_id>[\d]+)/' . $this->rest_base . '/(?P<group_id>[0-9a-f]+)/sequence/(?P<sequence_index>[\d]+)',
array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_item_in_sequence'),
'permission_callback' => array($this, 'bulk_edit_permissions_check'),
),
)
);
}
@ -181,14 +199,17 @@ class REST_Bulkedit_Controller extends REST_Controller {
if (isset($body['items_ids']) && is_array($body['items_ids']) && !empty($body['items_ids'])) {
$args['items_ids'] = $body['items_ids'];
if (isset($body['options'])) {
$args['options'] = $body['options'];
}
} elseif ( isset($body['use_query']) && $body['use_query'] ) {
unset($request['paged']);
unset($request['offset']);
unset($request['perpage']);
$request['nopaging'] = 1;
unset($body['use_query']['paged']);
unset($body['use_query']['offset']);
unset($body['use_query']['perpage']);
$body['use_query']['nopaging'] = 1;
$query_args = $this->prepare_filters($request);
$query_args = $this->prepare_filters($body['use_query']);
$collection_id = $request['collection_id'];
@ -205,14 +226,10 @@ class REST_Bulkedit_Controller extends REST_Controller {
$bulk = new \Tainacan\Bulk_Edit($args);
$response = [
'id' => $bulk->get_id()
];
$response = $this->prepare_item_for_response($bulk, $request);
$rest_response = new \WP_REST_Response($response, 200);
$rest_response->header('X-WP-Total', $bulk->count_posts());
return $rest_response;
}
@ -265,6 +282,40 @@ class REST_Bulkedit_Controller extends REST_Controller {
}
public function get_item($request) {
$group_id = $request['group_id'];
$args = ['id' => $group_id];
$bulk = new \Tainacan\Bulk_Edit($args);
$return = $this->prepare_item_for_response($bulk, $request);
if (0 === $return['items_count']) {
return new \WP_REST_Response([
'error_message' => __('Group not found', 'tainacan'),
], 404);
}
return new \WP_REST_Response($return, 200);
}
function prepare_item_for_response($bulk_object, $request) {
$count = $bulk_object->count_posts();
$options = $bulk_object->get_options();
$return = [
'id' => $bulk_object->get_id(),
'items_count' => $count,
'options' => $options
];
return $return;
}
public function trash_items($request) {
$group_id = $request['group_id'];
@ -377,6 +428,25 @@ class REST_Bulkedit_Controller extends REST_Controller {
}
}
public function get_item_in_sequence($request) {
$group_id = $request['group_id'];
$index = $request['sequence_index'];
$args = ['id' => $group_id];
$bulk = new \Tainacan\Bulk_Edit($args);
$item_id = $bulk->get_item_id_by_index( (int) $index );
if ( !$item_id ) {
return new \WP_REST_Response([
'error_message' => __('Item not found.', 'tainacan'),
], 404);
} else {
return new \WP_REST_Response($item_id, 200);
}
}
/**

View File

@ -0,0 +1,262 @@
<?php
namespace Tainacan\API\EndPoints;
use \Tainacan\API\REST_Controller;
use Tainacan\Repositories;
use Tainacan\Entities;
use \Tainacan\Exposers\Mappers\Value;
/**
* Represents the Exporters REST Controller
*
* */
class REST_Exporters_Controller extends REST_Controller {
/**
* REST_Exporters_Controller constructor.
* Define the namespace, rest base and instantiate your attributes.
*/
public function __construct() {
$this->rest_base = 'exporters';
if (session_status() == PHP_SESSION_NONE) {
@session_start(); // @ avoids Warnings when running phpunit tests
}
parent::__construct();
}
/**
* Register the collections route and their endpoints
*/
public function register_routes() {
register_rest_route($this->namespace, '/' . $this->rest_base . '/available', array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_registered_exporters'),
'permission_callback' => array($this, 'export_permissions_check'),
),
));
register_rest_route($this->namespace, '/' . $this->rest_base . '/session', array(
array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array($this, 'create_item'),
'permission_callback' => array($this, 'export_permissions_check'),
'args' => [
'importer_slug' => [
'type' => 'string',
'description' => __( 'The slug of the exporter to be initialized', 'tainacan' ),
]
],
),
));
register_rest_route($this->namespace, '/' . $this->rest_base . '/session/(?P<session_id>[0-9a-f]+)', array(
array(
'methods' => \WP_REST_Server::EDITABLE,
'callback' => array($this, 'update_item'),
'permission_callback' => array($this, 'export_permissions_check'),
'args' => [
'send_email' => [
'type' => 'string',
'description' => __( 'The e-mail to be used by the export to send a message when the process ends', 'tainacan' ),
],
'collection' => [
'type' => 'array/object',
'description' => __( 'The array describing the collection as expected by the exporter', 'tainacan' ),
],
'options' => [
'type' => 'array/object',
'description' => __( 'The importer options', 'tainacan' ),
]
],
),
));
register_rest_route($this->namespace, '/' . $this->rest_base . '/session/(?P<session_id>[0-9a-f]+)/run', array(
array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array($this, 'run'),
'permission_callback' => array($this, 'export_permissions_check'),
),
));
}
/**
*
* @param \WP_REST_Request $request
*
* @return bool|\WP_Error
* @throws \Exception
*/
public function export_permissions_check($request) {
return true;
}
public function get_registered_exporters() {
global $Tainacan_Exporter_Handler;
$exporters = $Tainacan_Exporter_Handler->get_registered_exporters();
return new \WP_REST_Response( $exporters, 200 );
}
/**
* Creates a new instance of the desired exporter and returns its ID
*
* @param \WP_REST_Request $request
*
* @return array|\WP_Error|\WP_REST_Response
*/
public function create_item( $request ) {
$body = json_decode($request->get_body(), true);
if(empty($body)) {
return new \WP_REST_Response([
'error_message' => __('Body can not be empty.', 'tainacan'),
], 400);
}
$slug = $body['exporter_slug'];
global $Tainacan_Exporter_Handler;
if ($object = $Tainacan_Exporter_Handler->initialize_exporter($slug)) {
$response = $object->_to_Array();
return new \WP_REST_Response($response, 201);
} else {
return new \WP_REST_Response([
'error_message' => __('Exporter not found', 'tainacan'),
], 400);
}
}
/**
* Update a collection
*
* @param \WP_REST_Request $request
*
* @return string|\WP_Error|\WP_REST_Response
*/
public function update_item( $request ) {
$session_id = $request['session_id'];
$body = json_decode($request->get_body(), true);
if(!empty($body)) {
$attributes = [];
foreach ($body as $att => $value) {
$attributes[$att] = $value;
}
$importer = $_SESSION['tainacan_exporter'][$session_id];
if($importer) {
foreach ($body as $att => $value) {
if ($att == 'collection') {
if (is_array($value) && isset($value['id'])) {
$importer->add_collection($value);
continue;
} else {
return new \WP_REST_Response([
'error_message' => __('Invalid collection', 'tainacan' ),
'session_id' => $session_id
], 400);
}
}
$method = 'set_' . $att;
if (method_exists($importer, $method)) {
$importer->$method($value);
}
}
$response = $importer->_to_Array();
return new \WP_REST_Response( $response, 200 );
}
return new \WP_REST_Response([
'error_message' => __('Importer Session not found', 'tainacan' ),
'session_id' => $session_id
], 400);
}
return new \WP_REST_Response([
'error_message' => __('The body can not be empty', 'tainacan'),
'body' => $body
], 400);
}
/**
* Run a exporter
*
* @param \WP_REST_Request $request
*
* @return string|\WP_Error|\WP_REST_Response
*/
public function run($request) {
$session_id = $request['session_id'];
$exporter = $_SESSION['tainacan_exporter'][$session_id];
if(!$exporter) {
return new \WP_REST_Response([
'error_message' => __('Exporter Session not found', 'tainacan' ),
'session_id' => $session_id
], 400);
}
global $Tainacan_Exporter_Handler;
$process = $Tainacan_Exporter_Handler->add_to_queue($exporter);
if (false === $process) {
return new \WP_REST_Response([
'error_message' => __('Error starting exporter', 'tainacan' ),
'session_id' => $session_id
], 400);
}
$response = [
'bg_process_id' => $process->ID
];
return new \WP_REST_Response( $response, 200 );
}
protected function map($item_arr, $mapper) {
$ret = $item_arr;
if(array_key_exists('metadatum', $item_arr)) { // getting a unique metadatum
$ret = $this->map_metadatum($item_arr, $mapper);
} else { // array of elements
$ret = [];
foreach ($item_arr as $item) {
if(array_key_exists('metadatum', $item)) {
$ret = array_merge($ret, $this->map($item, $mapper) );
} else {
$ret[] = $this->map($item, $mapper);
}
}
}
return $ret;
}
protected function map_metadatum($item_arr, $mapper) {
$ret = $item_arr;
$metadatum_mapping = $item_arr['metadatum']['exposer_mapping'];
if(array_key_exists($mapper->slug, $metadatum_mapping)) {
if(
is_string($metadatum_mapping[$mapper->slug]) && is_array($mapper->metadata) && !array_key_exists( $metadatum_mapping[$mapper->slug], $mapper->metadata) ||
is_array($metadatum_mapping[$mapper->slug]) && $mapper->allow_extra_metadata != true
) {
throw new \Exception('Invalid Mapper Option');
}
$slug = '';
if(is_string($metadatum_mapping[$mapper->slug])) {
$slug = $metadatum_mapping[$mapper->slug];
} else {
$slug = $metadatum_mapping[$mapper->slug]['slug'];
}
$ret = [$mapper->prefix.$slug.$mapper->sufix => $item_arr['value']]; //TODO Validate option
} elseif($mapper->slug == 'value') {
$ret = [$item_arr['metadatum']['name'] => $item_arr['value']];
} else {
$ret = [];
}
return $ret;
}
}
?>

View File

@ -8,6 +8,18 @@ use \Tainacan\API\REST_Controller;
class REST_Facets_Controller extends REST_Controller {
private $total_pages;
private $total_items;
private $collection;
private $collection_repository;
private $metadatum_repository;
private $filter_repository;
private $terms_repository;
private $taxonomy_repository;
private $items_repository;
private $taxonomy;
/**
* REST_Facets_Controller constructor.
*/
@ -38,7 +50,7 @@ class REST_Facets_Controller extends REST_Controller {
register_rest_route($this->namespace, '/collection/(?P<collection_id>[\d]+)/' . $this->rest_base . '/(?P<metadatum_id>[\d]+)', array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_item'),
'callback' => array($this, 'get_items'),
'permission_callback' => array($this, 'get_items_permissions_check')
)
));
@ -46,7 +58,7 @@ class REST_Facets_Controller extends REST_Controller {
register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<metadatum_id>[\d]+)', array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_item'),
'callback' => array($this, 'get_items'),
'permission_callback' => array($this, 'get_items_permissions_check')
)
));
@ -57,7 +69,7 @@ class REST_Facets_Controller extends REST_Controller {
*
* @return \WP_Error|\WP_REST_Response
*/
public function get_item( $request ) {
public function get_items( $request ) {
$metadatum_id = $request['metadatum_id'];
$metadatum = $this->metadatum_repository->fetch($metadatum_id);
@ -83,6 +95,7 @@ class REST_Facets_Controller extends REST_Controller {
*/
public function prepare_item_for_response($metadatum, $request){
$response = [];
$metadatum_type = null;
if( !empty($metadatum) ){
@ -168,7 +181,6 @@ class REST_Facets_Controller extends REST_Controller {
$term_selected = $this->terms_repository->fetch($term_id, $this->taxonomy);
$realResponse[] = $term_selected;
}
foreach( $terms as $index => $term ){
@ -203,8 +215,8 @@ class REST_Facets_Controller extends REST_Controller {
else {
$metadatum_id = $metadatum->get_id();
$offset = '';
$number = '';
$offset = null;
$number = null;
$collection_id = ( isset($request['collection_id']) ) ? $request['collection_id'] : false;
$selected = $this->getTextSelectedValues($request, $metadatum_id);
@ -222,42 +234,40 @@ class REST_Facets_Controller extends REST_Controller {
} else {
if($collection_id) {
$response = $this->metadatum_repository->fetch_all_metadatum_values( $collection_id, $metadatum_id, '', $offset, $number);
$response = $this->metadatum_repository->fetch_all_metadatum_values( $collection_id, $metadatum_id, null, $offset, $number);
} else {
$response = $this->metadatum_repository->fetch_all_metadatum_values( null, $metadatum_id, '', $offset, $number);
$response = $this->metadatum_repository->fetch_all_metadatum_values( null, $metadatum_id, null, $offset, $number);
}
}
$rawResponse = $response;
// retrieve selected items
if( $selected && $request['getSelected'] && $request['getSelected'] === '1'){
if( count($selected) && $request['getSelected'] && $request['getSelected'] === '1'){
$rawValues = $this->get_values( $response );
$realResponse = [];
foreach( $selected as $index => $value ){
$row = ['mvalue' => $value, 'metadatum_id' => $metadatum_id ];
$row = (object) ['mvalue' => $value, 'metadatum_id' => $metadatum_id ];
$realResponse[] = $row;
}
foreach( $rawValues as $index => $row0 ){
if( in_array($row0, $selected) ){
continue;
}
$realResponse[] = ['mvalue' => $row0, 'metadatum_id' => $metadatum_id];
if( !in_array($row0, $selected) ){
$realResponse[] = (object) ['mvalue' => $row0, 'metadatum_id' => $metadatum_id];
if( isset($request['number']) && count($realResponse) >= $request['number']){
break;
}
}
}
$response = $realResponse;
}
$this->set_pagination_properties_text_type( $collection_id, $metadatum_id, ($request['search']) ? $request['search'] : '' , $offset, $number );
$this->set_pagination_properties_text_type( $offset, $number, $rawResponse );
}
}
@ -286,8 +296,7 @@ class REST_Facets_Controller extends REST_Controller {
foreach ( $response as $key => $item ) {
if( $type === 'Tainacan\Metadata_Types\Taxonomy' ){
$row = [
$result[] = [
'label' => $item['name'],
'value' => $item['id'],
'img' => ( isset($item['header_image']) ) ? $item['header_image'] : false ,
@ -297,10 +306,8 @@ class REST_Facets_Controller extends REST_Controller {
'taxonomy_id' => $this->taxonomy->WP_Post->ID,
'taxonomy' => ( isset($item['taxonomy']) ) ? $item['taxonomy'] : false,
];
} else if( $type === 'Tainacan\Metadata_Types\Relationship' ){
$row = [
$result[] = [
'label' => $item['title'],
'value' => $item['id'],
'img' => ( isset($item['thumbnail']['thumb']) ) ? $item['thumbnail']['thumb'] : false,
@ -308,21 +315,16 @@ class REST_Facets_Controller extends REST_Controller {
'total_children' => 0,
'type' => 'Relationship'
];
} else {
$row = [
'label' => $item['mvalue'],
'value' => $item['mvalue'],
$result[] = [
'label' => $item->mvalue,
'value' => $item->mvalue,
'img' => false,
'parent' => false,
'total_children' => 0,
'type' => 'Text'
];
}
$result[] = $row;
}
}
@ -331,15 +333,17 @@ class REST_Facets_Controller extends REST_Controller {
/**
* set attributes for text metadata
*
* @param $offset
* @param $number
* @param $response
*/
private function set_pagination_properties_text_type( $collection_id, $metadatum_id, $search , $offset, $number ){
$response = $this->metadatum_repository->fetch_all_metadatum_values( $collection_id, $metadatum_id, $search);
private function set_pagination_properties_text_type( $offset, $number, $response ){
if( $response && is_array( $response ) ){
if ( $offset !== '' && $number) {
$per_page = (int) $number;
$page = ceil( ( ( (int) $offset ) / $per_page ) + 1 );
//$page = ceil( ( ( (int) $offset ) / $per_page ) + 1 );
$this->total_items = count( $response );
@ -358,12 +362,15 @@ class REST_Facets_Controller extends REST_Controller {
/**
* set attributes for term metadata
*
* @param $args
* @param $response
*/
private function set_pagination_properties_term_type( $args, $response ){
if(isset($args['number'], $args['offset'])){
$number = $args['number'];
$offset = $args['offset'];
//$offset = $args['offset'];
unset( $args['number'], $args['offset'] );
$total_terms = wp_count_terms( $this->taxonomy->get_db_identifier(), $args );
@ -373,7 +380,7 @@ class REST_Facets_Controller extends REST_Controller {
}
$per_page = (int) $number;
$page = ceil( ( ( (int) $offset ) / $per_page ) + 1 );
//$page = ceil( ( ( (int) $offset ) / $per_page ) + 1 );
$this->total_items = (int) $total_terms ;
@ -391,6 +398,8 @@ class REST_Facets_Controller extends REST_Controller {
*
* @param $request
* @param $taxonomy_id
*
* @return array
*/
private function getTaxonomySelectedValues($request, $taxonomy_id){
$selected = [];
@ -415,6 +424,8 @@ class REST_Facets_Controller extends REST_Controller {
*
* @param $request
* @param $metadatum_id
*
* @return array
*/
private function getTextSelectedValues($request, $metadatum_id){
if( isset($request['current_query']['metaquery']) ){
@ -423,7 +434,6 @@ class REST_Facets_Controller extends REST_Controller {
if( $metaquery['key'] == $metadatum_id ){
return $metaquery['value'];
}
}
@ -437,6 +447,8 @@ class REST_Facets_Controller extends REST_Controller {
*
* @param $request
* @param $metadatum_id
*
* @return array
*/
private function getRelationshipSelectedValues($request, $metadatum_id){
$selected = [];
@ -448,7 +460,6 @@ class REST_Facets_Controller extends REST_Controller {
if( $metaquery['key'] == $metadatum_id ){
return $metaquery['value'];
}
}
@ -471,17 +482,84 @@ class REST_Facets_Controller extends REST_Controller {
}
/**
* @param $rows
*
* @return array
*/
private function get_values( $rows ){
$values = [];
foreach( $rows as $row ){
$values[] = $row['mvalue'];
$values[] = $row->mvalue;
}
return $values;
}
/**
* method responsible to return the total of items for the facet value
*
* @param $value
* @param $reference_id
* @param bool $is_taxonomy
* @param $query
* @param $collection_id
*
* @return int total of items found
*/
private function add_items_count( $value, $reference_id, $is_taxonomy = false, $query, $collection_id){
$new_args = $query;
$has_value = false;
if( !$is_taxonomy ){
if( isset( $query['metaquery'] ) ){
foreach( $query['metaquery'] as $index => $metaquery ){
if( $metaquery['key'] == $metadatum_id ){
$has_value = true;
if( is_array($metaquery['value']) )
$new_args['metaquery'][$index]['value'][] = $value;
else
$new_args['metaquery'][$index]['value'] = $value;
}
}
}
if( !$has_value ){
$new_args['metaquery'][] = [
'key' => $reference_id,
'value' => $value
];
}
} else {
if( isset( $query['taxquery'] ) ){
foreach( $query['taxquery'] as $taxquery ){
if( $taxquery['taxonomy'] === 'tnc_tax_' . $reference_id ){
$has_value = true;
$new_args['taxquery'][$index]['terms'][] = $value;
}
}
}
if( !$has_value ){
$new_args['taxquery'][] = [
'taxonomy' => 'tnc_tax_' . $reference_id,
'value' => [$value]
];
}
}
$items = $this->items_repository->fetch($new_args, $collection_id, 'WP_Query');
return $items->found_posts;
}
}
?>

View File

@ -283,7 +283,7 @@ class REST_Importers_Controller extends REST_Controller {
$files = $request->get_file_params();
$headers = $request->get_headers();
if ( $importer->add_file($files['file']) ) {
if ( isset($files['file']) && $importer->add_file($files['file']) ) {
$response = $importer->_to_Array();
return new \WP_REST_Response( $response, 200 );
} else {

View File

@ -14,6 +14,7 @@ $rest_logs_controller = new \Tainacan\API\EndPoints\REST_Logs_Control
$rest_metadata_types_controller = new \Tainacan\API\EndPoints\REST_Metadata_Types_Controller();
$rest_filter_types_controller = new \Tainacan\API\EndPoints\REST_Filter_Types_Controller();
$rest_importers_controller = new \Tainacan\API\EndPoints\REST_Importers_Controller();
$rest_exporters_controller = new \Tainacan\API\EndPoints\REST_Exporters_Controller();
$rest_background_processes_controller = new \Tainacan\API\EndPoints\REST_Background_Processes_Controller();
$rest_bulkedit_controller = new \Tainacan\API\EndPoints\REST_Bulkedit_Controller();
new \Tainacan\API\EndPoints\REST_Export_Controller();

View File

@ -42,6 +42,7 @@ class Bulk_Edit {
* @type int $collection_id The items collection ID. Required if initializing using a query search
* @type array $query The query paramaters used to fetch items that will be part of this bulk edit group
* @type array $items_ids an array containing the IDs of items that will be part of this bulk edit group
* @type array $options an array containing additional options for this bulk edit group (currently used to store sorting information)
* @type string $id The ID of the Bulk edit group.
*
* }
@ -87,7 +88,10 @@ class Bulk_Edit {
$wpdb->query( "INSERT INTO $wpdb->postmeta (post_id, meta_key, meta_value) {$items_query->request}" );
return;
$bulk_params = [
'orderby' => isset($params['query']['orderby']) ? $params['query']['orderby'] : 'post_date',
'order' => isset($params['query']['order']) ? $params['query']['order'] : 'DESC'
];
} elseif (isset($params['items_ids']) && is_array($params['items_ids'])) {
$items_ids = array_filter($params['items_ids'], 'is_integer');
@ -100,10 +104,23 @@ class Bulk_Edit {
$wpdb->query( "INSERT INTO $wpdb->postmeta (post_id, meta_key, meta_value) VALUES $insert_q" );
return;
$bulk_params = [
'orderby' => isset($params['options']['orderby']) ? $params['options']['orderby'] : 'post_date',
'order' => isset($params['options']['order']) ? $params['options']['order'] : 'DESC'
];
}
/**
* This is stored to be used by the get_sequence_item_by_index() method, which is used
* by the sequence edit routine.
*
* For everything else, the order does not matter...
*/
$this->save_options($bulk_params);
return;
}
/**
@ -126,16 +143,65 @@ class Bulk_Edit {
return $this->id;
}
// return the number of items selected in the current bulk group
/**
* return the number of items selected in the current bulk group
* @return int number of items in the group
*/
public function count_posts() {
global $wpdb;
$id = $this->get_id();
if (!empty($id)) {
return $wpdb->get_var( $wpdb->prepare("SELECT COUNT(post_id) FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s", $this->meta_key, $id) );
return (int) $wpdb->get_var( $wpdb->prepare("SELECT COUNT(post_id) FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s", $this->meta_key, $id) );
}
return 0;
}
/**
* Gets the id of the item in a given position inside the group
*
* @param int $index THe position of the index to search for. From 1 to the length of the group
* @return int|bool Returns the ID of the item or false if the index is out of range
*/
public function get_item_id_by_index($index) {
if (!is_int($index)) {
throw new InvalidArgumentException('get_item_id_by_index function only accepts integers. Input was: '.$index);
}
$options = $this->get_options();
$query = [
'meta_query' => [
[
'key' => $this->meta_key,
'value' => $this->get_id()
]
],
'fields' => 'ids',
'post_type' => \Tainacan\Repositories\Repository::get_collections_db_identifiers(),
'posts_per_page' => 1,
'paged' => $index,
'orderby' => $options['orderby'],
'order' => $options['order'],
'post_status' => 'any'
];
$object = new \WP_Query($query);
if ( $object->have_posts() && isset($object->posts) && is_array($object->posts) && isset($object->posts[0]) && is_integer($object->posts[0]) ) {
return $object->posts[0];
}
return false;
}
public function save_options($value) {
update_option('tainacan_bulk_' . $this->get_id(), $value);
}
public function get_options() {
return get_option('tainacan_bulk_' . $this->get_id());
}
private function _build_select($fields) {
global $wpdb;
@ -356,7 +422,9 @@ class Bulk_Edit {
$select_q = $this->_build_select( 'post_id' );
$query_delete = "DELETE FROM $wpdb->posts WHERE ID IN ($select_q)";
$security = " AND post_status = 'trash'";
$query_delete = "DELETE FROM $wpdb->posts WHERE ID IN ($select_q) $security";
return $wpdb->query($query_delete);

View File

@ -633,7 +633,11 @@ class Item extends Entity {
if ( $type == 'url' ) {
global $wp_embed;
$output .= $wp_embed->autoembed($this->get_document());
$_embed = $wp_embed->autoembed($this->get_document());
if ( $_embed == $this->get_document() ) {
$_embed = sprintf('<a href="%s" target="blank">%s</a>', $this->get_document(), $this->get_document());
}
$output .= $_embed;
} elseif ( $type == 'text' ) {
$output .= $this->get_document();
} elseif ( $type == 'attachment' ) {
@ -643,6 +647,9 @@ class Item extends Entity {
$img = wp_get_attachment_image($this->get_document(), $img_size);
$img_full = wp_get_attachment_url($this->get_document());
$image_attributes = wp_get_attachment_image_src( $this->get_document(), $img_size );
$img = "<img style='max-width: 100%;' src='" . $image_attributes[0] . "' />";
$output .= sprintf("<a href='%s' target='blank'>%s</a>", $img_full, $img);
} else {

View File

@ -276,7 +276,7 @@ class Term extends Entity {
}
return $return;
return apply_filters('tainacan-term-to-html', $return, $this);
}
}

View File

@ -59,11 +59,7 @@
this.$console.log(error);
});
this.$eventBusSearch.$on('removeFromFilterTag', (filterTag) => {
if (filterTag.filterId == this.filter.id)
this.cleanSearch();
})
this.$eventBusSearch.$on('removeFromFilterTag', this.cleanSearchFromTags);
},
data(){
return {
@ -98,10 +94,16 @@
});
this.selectedValues();
},
search( query ){
search: _.debounce( function(query) {
if (query != '') {
let promise = null;
this.options = [];
// Cancels previous Request
if (this.getOptionsValuesCancel != undefined)
this.getOptionsValuesCancel.cancel('Facet search Canceled.');
if ( this.type === 'Tainacan\\Metadata_Types\\Relationship' ) {
let collectionTarget = ( this.metadatum_object && this.metadatum_object.metadata_type_options.collection_id ) ?
this.metadatum_object.metadata_type_options.collection_id : this.collection_id;
@ -111,13 +113,17 @@
promise = this.getValuesPlainText( this.metadatum, query, this.isRepositoryLevel );
}
promise.catch( error => {
promise.request.catch( error => {
this.$console.log('error select', error );
});
// Search Request Token for cancelling
this.getOptionsValuesCancel = promise.source;
} else {
this.cleanSearch();
}
},
}, 500),
selectedValues(){
const instance = this;
if ( !this.query || !this.query.metaquery || !Array.isArray( this.query.metaquery ) )
@ -162,6 +168,10 @@
return false;
}
},
cleanSearchFromTags(filterTag) {
if (filterTag.filterId == this.filter.id)
this.cleanSearch();
},
cleanSearch(){
this.results = '';
this.label = '';
@ -173,6 +183,9 @@
value: ''
});
},
},
beforeDestroy() {
this.$eventBusSearch.$off('removeFromFilterTag', this.cleanSearchFromTags);
}
}
</script>

View File

@ -28,10 +28,11 @@
<script>
import { tainacan as axios } from '../../../js/axios/axios';
import { filter_type_mixin } from '../filter-types-mixin';
import CheckboxFilterModal from '../../../admin/components/other/checkbox-filter-modal.vue';
import CheckboxRadioModal from '../../../admin/components/other/checkbox-radio-modal.vue';
export default {
created(){
this.collection = ( this.collection_id ) ? this.collection_id : this.filter.collection_id;
this.metadatum = ( this.metadatum_id ) ? this.metadatum_id : this.filter.metadatum.metadatum_id;
const vm = this;
@ -55,38 +56,7 @@
this.$console.log(error);
});
this.$eventBusSearch.$on('removeFromFilterTag', (filterTag) => {
if (filterTag.filterId == this.filter.id) {
let selectedIndex = this.selected.findIndex(option => option == filterTag.singleValue);
let optionIndex = this.options.findIndex(option => option.label == filterTag.singleValue);
let alternativeIndex;
if (optionIndex >= 0) {
alternativeIndex = this.selected.findIndex(option => this.options[optionIndex].value == option);
}
if (selectedIndex >= 0 || alternativeIndex >= 0) {
selectedIndex >= 0 ? this.selected.splice(selectedIndex, 1) : this.selected.splice(alternativeIndex, 1);
this.$emit('input', {
filter: 'checkbox',
compare: 'IN',
metadatum_id: this.metadatum,
collection_id: ( this.collection_id ) ? this.collection_id : this.filter.collection_id,
value: this.selected
});
this.$eventBusSearch.$emit( 'sendValuesToTags', {
filterId: this.filter.id,
value: this.selected
});
this.selectedValues();
}
}
});
this.$eventBusSearch.$on('removeFromFilterTag', this.cleanSearchFromTags);
},
props: {
isRepositoryLevel: Boolean,
@ -112,46 +82,56 @@
methods: {
loadOptions(){
let promise = null;
this.isLoading = true;
// Cancels previous Request
if (this.getOptionsValuesCancel != undefined)
this.getOptionsValuesCancel.cancel('Facet search Canceled.');
if ( this.type === 'Tainacan\\Metadata_Types\\Relationship' ) {
this.isLoading = true;
let collectionTarget = ( this.metadatum_object && this.metadatum_object.metadata_type_options.collection_id ) ?
this.metadatum_object.metadata_type_options.collection_id : this.collection_id;
promise = this.getValuesRelationship( collectionTarget, null, [], 0, this.filter.max_options, false, '1');
promise
promise.request
.then(() => {
this.isLoading = false;
if(this.options.length > this.filter.max_options){
this.options.splice(this.filter.max_options);
}
this.selectedValues();
}).catch((error) => {
this.$console.error(error);
})
} else {
this.isLoading = true;
promise = this.getValuesPlainText( this.metadatum, null, this.isRepositoryLevel, [], 0, this.filter.max_options, false, '1' );
promise
promise.request
.then(() => {
this.isLoading = false;
if(this.options.length > this.filter.max_options){
this.options.splice(this.filter.max_options);
}
this.selectedValues();
}).catch((error) => {
this.$console.error(error);
})
});
}
promise
.then(() => {
this.isLoading = false;
this.selectedValues()
})
.catch( error => {
this.$console.log('error select', error );
this.isLoading = false;
});
// promise.request
// .then(() => {
// this.isLoading = false;
// })
// .catch( error => {
// this.$console.log('error select', error );
// this.isLoading = false;
// });
// Search Request Token for cancelling
this.getOptionsValuesCancel = promise.source;
},
onSelect(){
this.$emit('input', {
@ -195,7 +175,7 @@
openCheckboxModal() {
this.$modal.open({
parent: this,
component: CheckboxFilterModal,
component: CheckboxRadioModal,
props: {
//parent: parent,
filter: this.filter,
@ -213,7 +193,42 @@
appliedCheckBoxModal: () => this.loadOptions()
}
});
},
cleanSearchFromTags(filterTag) {
if (filterTag.filterId == this.filter.id) {
let selectedIndex = this.selected.findIndex(option => option == filterTag.singleValue);
let optionIndex = this.options.findIndex(option => option.label == filterTag.singleValue);
let alternativeIndex;
if (optionIndex >= 0) {
alternativeIndex = this.selected.findIndex(option => this.options[optionIndex].value == option);
}
if (selectedIndex >= 0 || alternativeIndex >= 0) {
selectedIndex >= 0 ? this.selected.splice(selectedIndex, 1) : this.selected.splice(alternativeIndex, 1);
this.$emit('input', {
filter: 'checkbox',
compare: 'IN',
metadatum_id: this.metadatum,
collection_id: ( this.collection_id ) ? this.collection_id : this.filter.collection_id,
value: this.selected
});
this.$eventBusSearch.$emit( 'sendValuesToTags', {
filterId: this.filter.id,
value: this.selected
});
this.selectedValues();
}
}
}
},
beforeDestroy() {
this.$eventBusSearch.$off('removeFromFilterTag', this.cleanSearchFromTags);
}
}
</script>

View File

@ -69,10 +69,7 @@
this.$console.log(error);
});
this.$eventBusSearch.$on('removeFromFilterTag', (filterTag) => {
if (filterTag.filterId == this.filter.id)
this.clearSearch();
});
this.$eventBusSearch.$on('removeFromFilterTag', this.cleanSearchFromTags);
},
data(){
return {
@ -193,6 +190,10 @@
// return this.value_init + ' - ' +this.value_end;
// }
},
cleanSearchFromTags(filterTag) {
if (filterTag.filterId == this.filter.id)
this.cleanSearch();
},
clearSearch(){
this.clear = true;
@ -281,6 +282,9 @@
});
}
}
},
beforeDestroy() {
this.$eventBusSearch.$off('removeFromFilterTag', this.cleanSearchFromTags);
}
}
</script>

View File

@ -1,10 +1,11 @@
import qs from 'qs';
import { tainacan as axios } from '../../js/axios/axios';
import axios from '../../js/axios/axios';
export const filter_type_mixin = {
data () {
return {
thumbPlaceholderPath: tainacan_plugin.base_url + '/admin/images/placeholder_square.png'
thumbPlaceholderPath: tainacan_plugin.base_url + '/admin/images/placeholder_square.png',
getOptionsValuesCancel: undefined
}
},
props: {
@ -19,7 +20,17 @@ export const filter_type_mixin = {
},
methods: {
getValuesPlainText(metadatumId, search, isRepositoryLevel, valuesToIgnore, offset, number, isInCheckboxModal, getSelected = '0') {
let query_items = { 'current_query': this.query };
const source = axios.CancelToken.source();
let currentQuery = JSON.parse(JSON.stringify(this.query));
if (currentQuery.fetch_only != undefined) {
for (let key of Object.keys(currentQuery.fetch_only)) {
if (currentQuery.fetch_only[key] == null)
delete currentQuery.fetch_only[key];
}
}
let query_items = { 'current_query': currentQuery };
let url = `/collection/${this.collection}/facets/${metadatumId}?getSelected=${getSelected}&`;
@ -36,10 +47,12 @@ export const filter_type_mixin = {
} else if(search){
url += `search=${search}&` + qs.stringify(query_items);
} else {
url += qs.stringify(query_items, { addQueryPrefix: true });
url += qs.stringify(query_items);
}
return axios.get(url)
return new Object ({
request:
axios.tainacan.get(url, { cancelToken: source.token })
.then(res => {
let sResults = [];
let opts = [];
@ -98,12 +111,28 @@ export const filter_type_mixin = {
}
})
.catch(error => {
this.$console.error(error);
.catch((thrown) => {
if (axios.isCancel(thrown)) {
console.log('Request canceled: ', thrown.message);
} else {
reject(thrown);
}
}),
source: source
});
},
getValuesRelationship(collectionTarget, search, valuesToIgnore, offset, number, isInCheckboxModal, getSelected = '0') {
let query_items = { 'current_query': this.query };
const source = axios.CancelToken.source();
let currentQuery = JSON.parse(JSON.stringify(this.query));
if (currentQuery.fetch_only != undefined) {
for (let key of Object.keys(currentQuery.fetch_only)) {
if (currentQuery.fetch_only[key] == null)
delete currentQuery.fetch_only[key];
}
}
let query_items = { 'current_query': currentQuery };
let url = '/collection/' + this.filter.collection_id + '/facets/' + this.filter.metadatum.metadatum_id + `?getSelected=${getSelected}&`;
if(offset != undefined && number != undefined){
@ -116,7 +145,9 @@ export const filter_type_mixin = {
url += `&search=${search}`;
}
return axios.get(url + '&fetch_only[0]=thumbnail&fetch_only[1]=title&fetch_only[2]=id&' + qs.stringify(query_items))
return new Object ({
request:
axios.tainacan.get(url + '&fetch_only[0]=thumbnail&fetch_only[1]=title&fetch_only[2]=id&' + qs.stringify(query_items))
.then(res => {
let sResults = [];
let opts = [];
@ -181,7 +212,15 @@ export const filter_type_mixin = {
})
.catch(error => {
this.$console.error(error);
}),
source: source
});
}
}
},
beforeDestroy() {
// Cancels previous Request
if (this.getOptionsValuesCancel != undefined)
this.getOptionsValuesCancel.cancel('Facet search Canceled.');
},
};

View File

@ -46,10 +46,7 @@
this.$console.error(error);
});
this.$eventBusSearch.$on('removeFromFilterTag', (filterTag) => {
if (filterTag.filterId == this.filter.id)
this.onSelect();
});
this.$eventBusSearch.$on('removeFromFilterTag', this.cleanSearchFromTags);
},
props: {
isRepositoryLevel: Boolean,
@ -81,16 +78,24 @@
loadOptions(){
this.isLoading = true;
// Cancels previous Request
if (this.getOptionsValuesCancel != undefined)
this.getOptionsValuesCancel.cancel('Facet search Canceled.');
let promise = null;
promise = this.getValuesPlainText( this.metadatum, null, this.isRepositoryLevel );
promise.then(() => {
promise.request
.then(() => {
this.isLoading = false;
})
.catch( error => {
this.$console.error('error select', error );
this.isLoading = false;
});
// Search Request Token for cancelling
this.getOptionsValuesCancel = promise.source;
},
onSelect(value){
this.selected = value;
@ -120,7 +125,14 @@
} else {
return false;
}
},
cleanSearchFromTags(filterTag) {
if (filterTag.filterId == this.filter.id)
this.onSelect();
}
},
beforeDestroy() {
this.$eventBusSearch.$off('removeFromFilterTag', this.cleanSearchFromTags);
}
}
</script>

View File

@ -60,37 +60,7 @@
this.$console.log(error);
});
this.$eventBusSearch.$on('removeFromFilterTag', (filterTag) => {
if (filterTag.filterId == this.filter.id) {
let selectedIndex = this.selected.findIndex(option => option.label == filterTag.singleValue);
if (selectedIndex >= 0) {
this.selected.splice(selectedIndex, 1);
let values = [];
let labels = [];
for(let val of this.selected){
values.push( val.value );
labels.push( val.label );
}
this.$emit('input', {
filter: 'taginput',
compare: 'IN',
metadatum_id: this.metadatum,
collection_id: ( this.collection_id ) ? this.collection_id : this.filter.collection_id,
value: values
});
this.$eventBusSearch.$emit( 'sendValuesToTags', {
filterId: this.filter.id,
value: labels
});
}
}
});
this.$eventBusSearch.$on('removeFromFilterTag', this.cleanSearchFromTags);
},
data(){
return {
@ -134,7 +104,7 @@
}
},
methods: {
search( query ){
search: _.debounce( function(query) {
let promise = null;
this.options = [];
let valuesToIgnore = [];
@ -142,6 +112,10 @@
for(let val of this.selected)
valuesToIgnore.push( val.value );
// Cancels previous Request
if (this.getOptionsValuesCancel != undefined)
this.getOptionsValuesCancel.cancel('Facet search Canceled.');
if ( this.type === 'Tainacan\\Metadata_Types\\Relationship' ) {
let collectionTarget = ( this.metadatum_object && this.metadatum_object.metadata_type_options.collection_id ) ?
this.metadatum_object.metadata_type_options.collection_id : this.collection_id;
@ -151,11 +125,15 @@
promise = this.getValuesPlainText( this.metadatum, query, this.isRepositoryLevel, valuesToIgnore );
}
promise
promise.request
.catch( error => {
this.$console.log('error select', error );
});
},
// Search Request Token for cancelling
this.getOptionsValuesCancel = promise.source;
}, 500),
selectedValues(){
const instance = this;
if ( !this.query || !this.query.metaquery || !Array.isArray( this.query.metaquery ) )
@ -188,7 +166,41 @@
} else {
return false;
}
},
cleanSearchFromTags(filterTag) {
if (filterTag.filterId == this.filter.id) {
let selectedIndex = this.selected.findIndex(option => option.label == filterTag.singleValue);
if (selectedIndex >= 0) {
this.selected.splice(selectedIndex, 1);
let values = [];
let labels = [];
for(let val of this.selected){
values.push( val.value );
labels.push( val.label );
}
this.$emit('input', {
filter: 'taginput',
compare: 'IN',
metadatum_id: this.metadatum,
collection_id: ( this.collection_id ) ? this.collection_id : this.filter.collection_id,
value: values
});
this.$eventBusSearch.$emit( 'sendValuesToTags', {
filterId: this.filter.id,
value: labels
});
}
}
}
},
beforeDestroy() {
this.$eventBusSearch.$off('removeFromFilterTag', this.cleanSearchFromTags);
}
}
</script>

View File

@ -28,7 +28,7 @@
<script>
import qs from 'qs';
import { tainacan as axios } from '../../../js/axios/axios';
import CheckboxFilterModal from '../../../admin/components/other/checkbox-filter-modal.vue';
import CheckboxRadioModal from '../../../admin/components/other/checkbox-radio-modal.vue';
export default {
created(){
@ -37,37 +37,7 @@
this.type = ( this.filter_type ) ? this.filter_type : this.filter.metadatum.metadata_type;
this.loadOptions();
this.$eventBusSearch.$on('removeFromFilterTag', (filterTag) => {
if (filterTag.filterId == this.filter.id) {
let selectedOption = this.options.find(option => option.label == filterTag.singleValue);
if(selectedOption) {
let selectedIndex = this.selected.findIndex(option => option == selectedOption.value);
if (selectedIndex >= 0) {
this.selected.splice(selectedIndex, 1);
this.$emit('input', {
filter: 'checkbox',
compare: 'IN',
taxonomy: this.taxonomy,
metadatum_id: this.metadatum,
collection_id: ( this.collection_id ) ? this.collection_id : this.filter.collection_id,
terms: this.selected
});
this.$eventBusSearch.$emit( 'sendValuesToTags', {
filterId: this.filter.id,
value: this.selected
});
this.selectedValues();
}
}
}
});
this.$eventBusSearch.$on('removeFromFilterTag', this.cleanSearchFromTag);
},
data(){
return {
@ -220,7 +190,7 @@
openCheckboxModal(parent) {
this.$modal.open({
parent: this,
component: CheckboxFilterModal,
component: CheckboxRadioModal,
props: {
parent: parent,
filter: this.filter,
@ -237,9 +207,43 @@
},
width: 'calc(100% - 8.333333333%)',
});
},
cleanSearchFromTag(filterTag) {
if (filterTag.filterId == this.filter.id) {
let selectedOption = this.options.find(option => option.label == filterTag.singleValue);
if(selectedOption) {
let selectedIndex = this.selected.findIndex(option => option == selectedOption.value);
if (selectedIndex >= 0) {
this.selected.splice(selectedIndex, 1);
this.$emit('input', {
filter: 'checkbox',
compare: 'IN',
taxonomy: this.taxonomy,
metadatum_id: this.metadatum,
collection_id: ( this.collection_id ) ? this.collection_id : this.filter.collection_id,
terms: this.selected
});
this.$eventBusSearch.$emit( 'sendValuesToTags', {
filterId: this.filter.id,
value: this.selected
});
this.selectedValues();
}
}
}
}
},
beforeDestroy() {
this.$eventBusSearch.$off('removeFromFilterTag', this.cleanSearchFromTags);
}
}
</script>
<style lang="scss" scoped>

View File

@ -1,145 +0,0 @@
<template>
<div class="block">
<b-select
:id="id"
:loading="isLoading"
:value="selected"
@input="onSelect($event)"
size="is-small"
expanded
:placeholder="$i18n.get('label_selectbox_init')">
<option value="">{{ $i18n.get('label_selectbox_init') }}...</option>
<option
v-for=" (option, index) in options"
:key="index"
:label="option.label"
:value="option.value">{{ option.label }}</option>
</b-select>
</div>
</template>
<script>
import qs from 'qs';
import { tainacan as axios } from "../../../js/axios/axios";
export default {
created() {
this.collection = this.collection_id
? this.collection_id
: this.filter.collection_id;
this.metadatum = this.metadatum_id
? this.metadatum_id
: this.filter.metadatum.metadatum_id;
this.type = this.filter_type
? this.filter_type
: this.filter.metadatum.metadata_type;
this.loadOptions();
this.$eventBusSearch.$on("removeFromFilterTag", filterTag => {
if (filterTag.filterId == this.filter.id) {
this.onSelect();
}
});
},
data() {
return {
isLoading: false,
options: [],
collection: "",
metadatum: "",
selected: "",
taxonomy: ""
};
},
props: {
filter: {
type: Object // concentrate all attributes metadatum id and type
},
metadatum_id: [Number], // not required, but overrides the filter metadatum id if is set
collection_id: [Number], // not required, but overrides the filter metadatum id if is set
filter_type: [String], // not required, but overrides the filter metadatum type if is set
id: "",
query: {
type: Object // concentrate all attributes metadatum id and type
}
},
methods: {
loadOptions() {
this.isLoading = true;
let query_items = { 'current_query': this.query };
axios.get('/collection/'+ this.collection +'/facets/' + this.metadatum + `?hideempty=0&order=asc&` + qs.stringify(query_items))
.then( res => {
for (let item of res.data) {
this.taxonomy = item.taxonomy;
this.taxonomy_id = item.taxonomy_id;
this.options.push(item);
}
this.isLoading = false;
this.selectedValues();
})
.catch(error => {
this.$console.log(error);
this.isLoading = false;
});
},
getOptions(parent, level = 0) {
// retrieve only ids
let result = [];
if (this.options) {
for (let term of this.options) {
if (term.parent == parent) {
term["level"] = level;
result.push(term);
const levelTerm = level + 1;
const children = this.getOptions(term.value, levelTerm);
result = result.concat(children);
}
}
}
return result;
},
selectedValues() {
if (
!this.query ||
!this.query.taxquery ||
!Array.isArray(this.query.taxquery)
)
return false;
let index = this.query.taxquery.findIndex(
newMetadatum => newMetadatum.taxonomy === this.taxonomy
);
if (index >= 0) {
let metadata = this.query.taxquery[index];
this.selected = metadata.terms;
} else {
return false;
}
},
onSelect(value) {
this.selected = value;
this.$emit("input", {
filter: "selectbox",
compare: "IN",
taxonomy: this.taxonomy,
metadatum_id: this.metadatum,
collection_id: this.collection,
terms: this.selected
});
let valueIndex = this.options.findIndex(
option => option.value == this.selected
);
if (valueIndex >= 0) {
this.$eventBusSearch.$emit("sendValuesToTags", {
filterId: this.filter.id,
value: this.options[valueIndex].label
});
}
}
}
};
</script>

View File

@ -38,38 +38,7 @@
this.selectedValues( metadatum.metadata_type_options.taxonomy_id );
});
this.$eventBusSearch.$on('removeFromFilterTag', (filterTag) => {
if (filterTag.filterId == this.filter.id) {
let selectedIndex = this.selected.findIndex(option => option.label == filterTag.singleValue);
if (selectedIndex >= 0) {
this.selected.splice(selectedIndex, 1);
let values = [];
let labels = [];
for(let val of this.selected){
values.push( val.value );
labels.push( val.label );
}
this.$emit('input', {
filter: 'taginput',
compare: 'IN',
taxonomy: this.taxonomy,
metadatum_id: ( this.metadatum_id ) ? this.metadatum_id : this.filter.metadatum,
collection_id: ( this.collection_id ) ? this.collection_id : this.filter.collection_id,
terms: values
});
this.$eventBusSearch.$emit( 'sendValuesToTags', {
filterId: this.filter.id,
value: labels
});
}
}
});
this.$eventBusSearch.$on('removeFromFilterTag', this.cleanSearchFromTag);
},
data(){
return {
@ -124,7 +93,7 @@
}
},
methods: {
search( query ){
search: _.debounce( function(query) {
this.isLoading = true;
this.options = [];
@ -161,7 +130,7 @@
this.isLoading = false;
this.$console.log(error);
});
},
}, 500),
selectedValues( taxonomy ){
if ( !this.query || !this.query.taxquery || !Array.isArray( this.query.taxquery ) )
return false;
@ -185,7 +154,42 @@
.catch(error => {
this.$console.log(error);
});
},
cleanSearchFromTag(filterTag) {
if (filterTag.filterId == this.filter.id) {
let selectedIndex = this.selected.findIndex(option => option.label == filterTag.singleValue);
if (selectedIndex >= 0) {
this.selected.splice(selectedIndex, 1);
let values = [];
let labels = [];
for(let val of this.selected){
values.push( val.value );
labels.push( val.label );
}
this.$emit('input', {
filter: 'taginput',
compare: 'IN',
taxonomy: this.taxonomy,
metadatum_id: ( this.metadatum_id ) ? this.metadatum_id : this.filter.metadatum,
collection_id: ( this.collection_id ) ? this.collection_id : this.filter.collection_id,
terms: values
});
this.$eventBusSearch.$emit( 'sendValuesToTags', {
filterId: this.filter.id,
value: labels
});
}
}
}
},
beforeDestroy() {
this.$eventBusSearch.$off('removeFromFilterTag', this.cleanSearchFromTags);
}
}
</script>

View File

@ -22,6 +22,6 @@ class TaxonomyCheckbox extends Filter_Type {
return '<tainacan-filter-taxonomy-checkbox name="'.$filter->get_name().'"
filter_type="'.$filter->get_metadatum()->get_metadata_type().'"
collection_id="'.$filter->get_collection_id().'"
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-checkbox>';
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-taxonomy-checkbox>';
}
}

View File

@ -1,27 +0,0 @@
<?php
namespace Tainacan\Filter_Types;
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
/**
* Class TainacanMetadatumType
*/
class TaxonomySelectbox extends Filter_Type {
function __construct(){
$this->set_supported_types(['term']);
$this->set_component('tainacan-filter-taxonomy-selectbox');
}
/**
* @param $filter
* @return string
*/
public function render( $filter ){
return '<tainacan-filter-taxonomy-selectbox name="'.$filter->get_name().'"
filter_type="'.$filter->get_metadatum()->get_metadata_type().'"
collection_id="'.$filter->get_collection_id().'"
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-selectbox>';
}
}

View File

@ -22,6 +22,6 @@ class TaxonomyTaginput extends Filter_Type {
return '<tainacan-filter-taxonomy-taginput name="'.$filter->get_name().'"
filter_type="'.$filter->get_metadatum()->get_metadata_type().'"
collection_id="'.$filter->get_collection_id().'"
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-taginput>';
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-taxonomy-taginput>';
}
}

View File

@ -10,6 +10,7 @@ defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
* Class TainacanMetadatumType
*/
class Core_Description extends Metadata_Type {
use \Tainacan\Traits\Formatter_Text;
function __construct(){
// call metadatum type constructor
@ -80,4 +81,26 @@ class Core_Description extends Metadata_Type {
}
/**
* Get the value as a HTML string with links and breakline tag.
* @return string
*/
public function get_value_as_html(\Tainacan\Entities\Item_Metadata_Entity $item_metadata) {
$value = $item_metadata->get_value();
$return = '';
if ( $item_metadata->is_multiple() ) {
$total = sizeof($value);
$count = 0;
foreach ( $value as $el ) {
$return .= nl2br($this->make_clickable_links($el));
$count ++;
if ($count <= $total)
$return .= ', ';
}
} else {
$return = nl2br($this->make_clickable_links($value));
}
return $return;
}
}

View File

@ -6,12 +6,16 @@
<input
:disabled="disabled"
class="input"
:class="{'is-danger': isInvalidDate && dateValue}"
type="text"
v-mask="dateMask"
:value="dateValue"
v-model="dateValue"
@blur="onBlur"
@input="onInput"
:placeholder="dateFormat.toLowerCase()">
<p
v-if="isInvalidDate && dateValue"
class="has-text-danger is-italic is-size-7">{{ $i18n.get('info_error_invalid_date') }}</p>
<!--<b-collapse-->
<!--position="is-bottom-right">-->
<!--<b-icon-->
@ -57,7 +61,8 @@
return {
dateValue: '',
dateMask: this.getDateLocaleMask(),
dateFormat: ''
dateFormat: '',
isInvalidDate: false,
}
},
props: {
@ -72,18 +77,25 @@
onBlur() {
this.$emit('blur');
},
onInput($event) {
onInput: _.debounce(function ($event) {
let dateISO = '';
if($event && $event instanceof Date) {
dateISO = moment(this.dateValue, this.dateFormat).toISOString().split('T')[0];
dateISO = moment(this.dateValue, this.dateFormat).toISOString() ? moment(this.dateValue, this.dateFormat).toISOString().split('T')[0] : false;
} else if($event.target.value && $event.target.value.length === this.dateMask.length) {
dateISO = moment($event.target.value, this.dateFormat).toISOString().split('T')[0];
dateISO = moment(this.dateValue, this.dateFormat).toISOString() ? moment($event.target.value, this.dateFormat).toISOString().split('T')[0] : false;
}
if(!dateISO){
this.isInvalidDate = true;
return;
} else {
this.isInvalidDate = false;
}
this.$emit('input', dateISO);
this.$emit('blur');
},
}, 300),
parseDateToNavigatorLanguage(date){
date = new Date(date.replace(/-/g, '/'));

View File

@ -2,6 +2,8 @@
namespace Tainacan\Metadata_Types;
use Tainacan\Entities\Item_Metadata_Entity;
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
use Tainacan\Helpers;
@ -28,4 +30,19 @@ class Date extends Metadata_Type {
value=\''.json_encode( $itemMetadata->get_value() ).'\'
name="'.$itemMetadata->get_metadatum()->get_name().'"></tainacan-date>';
}
public function validate( Item_Metadata_Entity $item_metadata) {
$value = $item_metadata->get_value();
$format = 'Y-m-d';
$d = \DateTime::createFromFormat($format, $value);
return $d && $d->format($format) === $value;
}
}

View File

@ -1,11 +1,11 @@
<template>
<div :class="{ 'is-flex': metadatum.metadatum.multiple != 'yes' }">
<div :class="{ 'is-flex': metadatum.metadatum.multiple != 'yes' || maxtags != undefined }">
<b-taginput
:disabled="disabled"
:id="id"
v-model="selected"
:data="options"
:maxtags="metadatum.metadatum.multiple === 'yes' && allowNew === true ? 100 : 1"
:maxtags="maxtags != undefined ? maxtags : (metadatum.metadatum.multiple == 'yes' || allowNew === true ? 100 : 1)"
autocomplete
attached
:loading="loading"
@ -35,8 +35,9 @@
});
}
if( this.metadatum.metadatum.metadata_type_options
&& this.metadatum.metadatum.metadata_type_options.search.length > 0){
if( this.metadatum.metadatum.metadata_type_options &&
this.metadatum.metadatum.metadata_type_options.search &&
this.metadatum.metadatum.metadata_type_options.search.length > 0){
axios.get('/collection/'+ collectionId +'/metadata?context=edit')
.then( res => {
for (let item of res.data) {
@ -70,6 +71,7 @@
type: Number
},
id: '',
maxtags: undefined,
disabled: false,
allowNew: true,
},
@ -101,10 +103,12 @@
}
if (query !== '') {
let metaquery = this.mountQuery( query );
this.loading = true;
this.options = [];
let metaquery = this.mountQuery( query );
let collectionId = ( this.metadatum && this.metadatum.metadatum.metadata_type_options.collection_id ) ? this.metadatum.metadatum.metadata_type_options.collection_id : this.collection_id;
axios.get('/collection/'+collectionId+'/items?' + qs.stringify( metaquery ))
.then( res => {
this.loading = false;

View File

@ -107,7 +107,6 @@
}
this.single_types['tainacan-taxonomy-radio'] = 'Radio';
this.single_types['tainacan-taxonomy-selectbox'] = 'Selectbox';
this.multiple_types['tainacan-taxonomy-tag-input'] = 'Tag Input';
this.multiple_types['tainacan-taxonomy-checkbox'] = 'Checkbox';

View File

@ -8,25 +8,20 @@
:allow-select-to-create="allowSelectToCreate"
:allow-new="allowNew"
:terms="terms"
:taxonomy-id="taxonomy"
:taxonomy-id="taxonomy_id"
:options="getOptions(0)"/>
<a
class="add-new-term"
v-if="(getComponent == 'tainacan-taxonomy-checkbox' || getComponent == 'tainacan-taxonomy-radio') && terms.length < totalTerms"
@click="getTermsFromTaxonomy()">
{{ $i18n.get('label_view_more') + ' (' + Number(totalTerms - terms.length) + ' ' + $i18n.get('terms') + ')' }}
v-if="(this.getComponent == 'tainacan-taxonomy-checkbox' || this.getComponent == 'tainacan-taxonomy-radio') &&
terms.length < totalTerms"
@click="openCheckboxModal()">
{{ $i18n.get('label_view_all') }}
</a>
<!--<a-->
<!--class="add-new-term"-->
<!--v-if="(getComponent == 'tainacan-taxonomy-checkbox') && terms.length < totalTerms"-->
<!--@click="openCheckboxModal()">-->
<!--{{ $i18n.get('label_view_all') }}-->
<!--</a>-->
<add-new-term
class="add-new-term"
v-if="allowNew"
:component-type="getComponent"
:taxonomy_id="taxonomy"
:taxonomy_id="taxonomy_id"
:metadatum="metadatum"
:item_id="metadatum.item.id"
:value="valueComponent"
@ -39,9 +34,8 @@
import TainacanTaxonomyRadio from './TaxonomyRadio.vue'
import TainacanTaxonomyCheckbox from './TaxonomyCheckbox.vue'
import TainacanTaxonomyTagInput from './TaxonomyTaginput.vue'
import TainacanTaxonomySelectbox from './TaxonomySelectbox.vue'
import AddNewTerm from './AddNewTerm.vue'
import HierarchicalCheckboxModal from '../../../admin/components/other/checkbox-filter-modal.vue'
import CheckboxRadioModal from '../../../admin/components/other/checkbox-radio-modal.vue'
export default {
created(){
@ -68,7 +62,6 @@
TainacanTaxonomyRadio,
TainacanTaxonomyCheckbox,
TainacanTaxonomyTagInput,
TainacanTaxonomySelectbox,
AddNewTerm
},
data(){
@ -82,7 +75,7 @@
totalTerms: 0,
allowNew: false,
offset: 0,
termsNumber: 40
termsNumber: 12
}
},
watch: {
@ -121,17 +114,24 @@
openCheckboxModal(){
this.$modal.open({
parent: this,
component: HierarchicalCheckboxModal,
component: CheckboxRadioModal,
props: {
isFilter: false,
parent: 0,
taxonomy_id: this.taxonomy_id,
selected: this.value,
selected: !this.valueComponent ? [] : this.valueComponent,
metadatum_id: this.metadatum.metadatum.id,
taxonomy: this.taxonomy,
collection_id: this.collectionId,
isTaxonomy: true,
query: '',
metadatum: this.metadatum.metadatum,
isCheckbox: this.getComponent == 'tainacan-taxonomy-checkbox'
},
events: {
input: (selected) => {
this.valueComponent = selected;
}
},
width: 'calc(100% - 8.333333333%)',
});
@ -196,11 +196,12 @@
},
onInput($event) {
this.inputValue = $event;
this.valueComponent = $event;
this.$emit('input', this.inputValue);
this.$emit('blur');
},
reload( $event ) {
if ($event.taxonomyId == this.taxonomy && $event.metadatumId == this.metadatum.metadatum.id) {
if ($event.taxonomyId == this.taxonomy_id && $event.metadatumId == this.metadatum.metadatum.id) {
this.valueComponent = $event.values;
this.terms = [];
this.offset = 0;

View File

@ -1,5 +1,30 @@
<template>
<div>
<p
v-if="value instanceof Array ? value.length > 0 : (value != undefined && value != '')"
class="has-text-gray">
{{ $i18n.get('label_selected_terms') + ' :' }}
</p>
<b-field
v-if="value instanceof Array ? value.length > 0 : (value != undefined && value != '')"
grouped
group-multiline
class="selected-tags">
<div
v-for="(term, index) in (value instanceof Array ? value : [value])"
:key="index">
<b-tag
attached
closable
@close="value.splice(index, 1)">
{{ selectedTagsName[term] }}
</b-tag>
</div>
<div
v-if="isSelectedTermsLoading"
class="control has-icons-right is-loading is-clearfix" />
</b-field>
<div
v-for="(option, index) in options"
:key="index">
@ -20,6 +45,7 @@
</template>
<script>
import { tainacan as axios } from '../../../js/axios/axios';
export default {
created(){
@ -29,11 +55,14 @@
data(){
return {
checked: [],
selectedTagsName: {},
isSelectedTermsLoading: false,
}
},
watch: {
value( val ){
this.checked = val;
this.fetchSelectedLabels();
}
},
props: {
@ -42,16 +71,71 @@
},
value: [ Number, String, Array ],
disabled: false,
taxonomyId: Number
},
methods: {
onChecked() {
this.$emit('blur');
this.onInput(this.checked)
this.onInput(this.checked);
},
onInput($event) {
this.inputValue = $event;
this.$emit('input', this.inputValue);
},
fetchSelectedLabels() {
if (this.value != null && this.value != undefined) {
this.isSelectedTermsLoading = true;
let selected = this.value instanceof Array ? this.value : [this.value];
if (this.taxonomyId && selected.length > 0) {
for (const term of selected) {
if(!this.isSelectedTermsLoading){
this.isSelectedTermsLoading = true;
}
axios.get(`/taxonomy/${this.taxonomyId}/terms/${term}`)
.then((res) => {
this.saveSelectedTagName(res.data.id, res.data.name);
this.isSelectedTermsLoading = false;
})
.catch((error) => {
this.$console.log(error);
this.isSelectedTermsLoading = false;
});
}
} else {
this.isSelectedTermsLoading = false;
}
}
},
saveSelectedTagName(value, label){
if(!this.selectedTagsName[value]) {
this.$set(this.selectedTagsName, `${value}`, label);
}
}
},
mounted() {
this.fetchSelectedLabels();
}
}
</script>
<style>
.selected-tags {
margin-top: 0.75rem;
font-size: 0.75rem;
position: relative;
}
.selected-tags .is-loading {
margin-left: 2rem;
margin-top: -0.4rem;
}
.selected-tags .is-loading::after {
border: 2px solid #898d8f !important;
border-right-color: #dbdbdb !important;
border-top-color: #dbdbdb !important;
}
</style>

View File

@ -1,5 +1,38 @@
<template>
<div>
<p
v-if="value instanceof Array ? value.length > 0 : (value != undefined && value != '')"
class="has-text-gray">
{{ $i18n.get('label_selected_terms') + ' :' }}
</p>
<b-field
v-if="value instanceof Array ? value.length > 0 : (value != undefined && value != '')"
grouped
group-multiline
class="selected-tags">
<div
v-for="(term, index) in (value instanceof Array ? value : [value])"
:key="index">
<b-tag
attached
closable
@close="value = ''">
{{ selectedTagsName[value] }}
</b-tag>
</div>
<div
v-if="isSelectedTermsLoading"
class="control has-icons-right is-loading is-clearfix" />
</b-field>
<b-radio
:disabled="disabled"
:id="id"
v-model="checked"
@input="onChecked()"
:native-value="''"
border>
{{ $i18n.get('clear_radio') }}
</b-radio>
<div
v-for="(option, index) in options"
:key="index">
@ -20,16 +53,20 @@
</template>
<script>
import { tainacan as axios } from '../../../js/axios/axios';
export default {
data(){
return {
checked: ( this.value ) ? this.value : ''
checked: ( this.value ) ? this.value : '',
selectedTagsName: {},
isSelectedTermsLoading: false,
}
},
watch: {
value( val ){
this.checked = val;
this.fetchSelectedLabels();
}
},
props: {
@ -38,6 +75,7 @@
},
value: [ Number, String, Array ],
disabled: false,
taxonomyId: Number
},
methods: {
onChecked() {
@ -47,7 +85,44 @@
onInput($event) {
this.inputValue = $event;
this.$emit('input', this.inputValue);
},
fetchSelectedLabels() {
if (this.value != null && this.value != undefined) {
this.isSelectedTermsLoading = true;
let selected = this.value instanceof Array ? this.value : [this.value];
if (this.taxonomyId && selected.length > 0) {
for (const term of selected) {
if(!this.isSelectedTermsLoading){
this.isSelectedTermsLoading = true;
}
axios.get(`/taxonomy/${this.taxonomyId}/terms/${term}`)
.then((res) => {
this.saveSelectedTagName(res.data.id, res.data.name);
this.isSelectedTermsLoading = false;
})
.catch((error) => {
this.$console.log(error);
this.isSelectedTermsLoading = false;
});
}
} else {
this.isSelectedTermsLoading = false;
}
}
},
saveSelectedTagName(value, label){
if(!this.selectedTagsName[value]) {
this.$set(this.selectedTagsName, `${value}`, label);
}
}
},
mounted() {
this.fetchSelectedLabels();
}
}
</script>

View File

@ -1,62 +0,0 @@
<template>
<div>
<div class="block">
<b-select
:disabled="disabled"
:id="id"
v-model="selected"
@input="emitChange()"
:placeholder="$i18n.get('label_select_taxonomy')"
expanded>
<option
v-for="(option, index) in options"
:key="index"
:value="option.id"
v-html="setSpaces( option.level ) + option.name"/>
</b-select>
</div>
</div>
</template>
<script>
export default {
created(){
if( this.value )
this.selected = this.value;
},
data(){
return {
selected: ''
}
},
watch: {
value( val ){
this.selected = val;
}
},
props: {
id: String,
options: {
type: Array
},
value: [ Number, String, Array ],
disabled: false,
},
methods: {
emitChange() {
this.$emit('input', this.selected);
this.$emit('blur');
},
setSpaces( level ){
let result = '';
let space = '&nbsp;&nbsp;'
for(let i = 0;i < level; i++)
result += space;
return result;
}
}
}
</script>

View File

@ -187,7 +187,7 @@ class Metadata extends Repository {
'type' => __( 'string' ),
'validation' => v::stringType()->in( [ 'yes', 'no', 'never' ] ),
'description' => __( 'Display by default on listing or do not display or never display.', 'tainacan' ),
'default' => 'yes'
'default' => 'no'
],
'semantic_uri' => [
'map' => 'meta',
@ -996,7 +996,7 @@ class Metadata extends Repository {
);
}
$pre_result = $wpdb->get_results( $sql_string, ARRAY_A );
$pre_result = $wpdb->get_results( $sql_string, OBJECT );
if ( ! empty( $pre_result ) ) {
foreach ( $pre_result as $pre ) {
@ -1045,7 +1045,7 @@ class Metadata extends Repository {
);
}
$pre_result = $wpdb->get_results( $sql_string, ARRAY_A );
$pre_result = $wpdb->get_results( $sql_string, OBJECT );
if ( ! empty( $pre_result ) ) {
foreach ( $pre_result as $pre ) {

View File

@ -753,10 +753,11 @@ abstract class Repository {
$key_array = array();
foreach ( $array as $val ) {
if ( ! in_array( $val[ $key ], $key_array ) ) {
$key_array[ $i ] = $val[ $key ];
if ( ! in_array( $val->$key, $key_array ) ) {
$key_array[ $i ] = $val->$key;
$temp_array[ $i ] = $val;
}
$i ++;
}

View File

@ -77,7 +77,7 @@ class Terms extends Repository {
'description' => __( 'The term creator', 'tainacan' ),
'on_error' => __( 'The user is empty or invalid', 'tainacan' ),
'default' => get_current_user_id(),
'validation' => v::numeric(),
//'validation' => v::numeric(),
],
'header_image_id' => [
'map' => 'termmeta',
@ -222,7 +222,6 @@ class Terms extends Repository {
foreach ( $terms as $term ) {
$tainacan_term = new Entities\Term( $term );
$tainacan_term->set_user( get_term_meta( $tainacan_term->get_id(), 'user', true ) );
$return[] = $tainacan_term;
}
@ -230,8 +229,6 @@ class Terms extends Repository {
} elseif ( is_numeric( $args ) && ! empty( $cpt ) && ! is_array( $cpt ) ) { // if an id is passed taxonomy cannot be an array
$wp_term = get_term_by( 'id', $args, $cpt );
$tainacan_term = new Entities\Term( $wp_term );
$tainacan_term->set_user( get_term_meta( $tainacan_term->get_id(), 'user', true ) );
return $tainacan_term;
} else {
return [];

View File

@ -9,6 +9,7 @@ const TAINACAN_VENDOR_DIR = __DIR__ . '/../vendor/';
const TAINACAN_TAPI_DIR = __DIR__ . '/../api/';
const TAINACAN_ENDPOINTS_DIR = __DIR__ . '/../api/endpoints/';
const TAINACAN_IMPORTER_DIR = __DIR__ . '/../importer/';
const TAINACAN_EXPORTER_DIR = __DIR__ . '/../exporter/';
const TAINACAN_EXPOSERS_DIR = __DIR__ . '/../exposers/';
const DIRS = [
@ -21,12 +22,14 @@ const DIRS = [
TAINACAN_TAPI_DIR,
TAINACAN_ENDPOINTS_DIR,
TAINACAN_IMPORTER_DIR,
TAINACAN_EXPORTER_DIR,
TAINACAN_EXPOSERS_DIR
];
require_once('libs/wp-async-request.php');
require_once('libs/wp-background-process.php');
require_once('class-tainacan-background-process.php');
require_once('tainacan-utils.php');
require_once(TAINACAN_IMPORTER_DIR . 'class-tainacan-bg-importer.php');
require_once(TAINACAN_VENDOR_DIR . 'autoload.php');
@ -34,6 +37,8 @@ require_once(TAINACAN_IMPORTER_DIR . 'class-tainacan-importer.php');
require_once(TAINACAN_IMPORTER_DIR . 'class-tainacan-importer-handler.php');
require_once(TAINACAN_EXPOSERS_DIR . 'class-tainacan-exposers.php');
require_once(TAINACAN_EXPORTER_DIR . 'class-tainacan-bg-exporter.php');
require_once(TAINACAN_EXPORTER_DIR . 'class-tainacan-export-handler.php');
spl_autoload_register('tainacan_autoload');
@ -52,9 +57,14 @@ function tainacan_autoload($class_name){
}
elseif ($class_path[0] == 'Tainacan') {
$sliced = array_slice($class_path, 1, count($class_path) -2);
if( isset( $class_path[1] ) && $class_path[1] === 'Importer' ){
if( isset( $class_path[1] ) && $class_path[1] === 'Importer' ) {
$dir = TAINACAN_IMPORTER_DIR;
$dir_import = strtolower(str_replace('_', '-' , $class_name));
if (file_exists("$dir$dir_import/")) {
$dir .= "$dir_import/";
}
} else if( isset( $class_path[1] ) && $class_path[1] === 'Exporter' ) {
$dir = TAINACAN_EXPORTER_DIR;
} else if( isset( $class_path[1] ) && $class_path[1] === 'Exposers' ){
$dir = TAINACAN_EXPOSERS_DIR;
if(count($class_path) > 3) $dir .= strtolower($class_path[2]).DIRECTORY_SEPARATOR;
@ -72,7 +82,7 @@ function tainacan_autoload($class_name){
}
if( in_array('Metadata_Types', $class_path) || in_array('Filter_Types', $class_path) ){
$exceptions = ['taxonomytaginput','taxonomycheckbox','taxonomyselectbox'];
$exceptions = ['taxonomytaginput','taxonomycheckbox'];
if( in_array( strtolower( $class_name ), $exceptions) ){
$dir.= 'taxonomy/';
}else{
@ -114,7 +124,6 @@ $Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Taginput');
$Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Checkbox');
$Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomyTaginput');
$Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomyCheckbox');
$Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomySelectbox');
$Tainacan_Taxonomies = \Tainacan\Repositories\Taxonomies::get_instance();
@ -142,4 +151,6 @@ $Tainacan_Theme_Helper = \Tainacan\Theme_Helper::get_instance();
$Tainacan_Search_Engine = new \Tainacan\Search_Engine();
$Tainacan_Elastic_press = new \Tainacan\Elastic_Press();
$Tainacan_Capabilities = \Tainacan\Capabilities::get_instance();
?>

View File

@ -0,0 +1,15 @@
<?php
/**
* This file gathers functions usefull for theme and plugin developers
*/
/**
* Retrieves raw data sent to an API endpoint reading the php://input stream
* @return Object PHP Raw Postdata
*/
function tainacan_get_api_postdata() {
$postdata = file_get_contents("php://input");
$post = json_decode($postdata);
return $post;
}

View File

@ -0,0 +1,48 @@
<?php
namespace Tainacan;
class Background_Exporter extends Background_Process {
/**
* @var string
*/
protected $action = 'exporter';
public function __construct() {
parent::__construct();
$this->set_name( __('Exporter', 'tainacan') );
}
function task($batch) {
$data = $batch->data;
$key = $batch->key;
$className = $data['class_name'];
if (class_exists($className)) {
$object = new $className($data);
$runned = $object->run();
$this->write_log($key, $object->get_log());
$this->write_error_log($key, $object->get_error_log());
if (true === $object->get_abort()) {
throw new \Exception('Process aborted by Importer');
}
if (false === $runned) {
return false;
}
$batch->progress_label = $object->get_progress_label();
$batch->progress_value = $object->get_progress_value();
$batch->data = $object->_to_Array(true);
return $batch;
}
return false;
}
}
?>

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