/**
 * Greyd.Blocks Editor Script for Query Blocks.
 * 
 * This file is loaded in block editor pages and modifies the editor experience.
 */
( function( wp ) {

	const {
		createElement: el,
		useState
	} = wp.element;

	const { __, _x, sprintf } = wp.i18n;
	const _ = lodash;

	/**
	 * Register custom attributes to core blocks.
	 * - core/query
	 * - core/post-template
	 * 
	 * @hook blocks.registerBlockType
	 */
	var registerBlockTypeHook = function(settings, name) {

		if (name == 'core/query') {
			// console.log("register query");
			settings.attributes.animation = { type: 'object' };
			// dirty fix to keep displayLayout extensions
			// todo: also move to post-template
			settings.attributes.displayLayout = { type: 'object' };
			settings.deprecated = [];
			settings.attributes.advancedFilter = { type: 'array', default: [] };
			// post table
			settings.variations.unshift( {
				name: "table",
				title: __("Post Table", 'greyd_hub'),
				description: __("Display posts as table", 'greyd_hub'),
				icon: greyd.tools.getBlockIcon('table'),
				category: 'greyd-blocks',
				keywords: [ 'post', 'table', 'query', 'loop' ],
				attributes: {
					query: { perPage: 10, pages: 0, offset: 0, postType: "post", order: "desc", orderBy: "date", author: "", search: "", exclude: [], sticky: "", inherit: false },
					displayLayout: { type: 'list' }
				},
				innerBlocks: [ [ "greyd/post-table" ] ],
				scope: [ "inserter", "block" ]
			} );
			// post overview
			settings.variations.unshift( {
				name: "template",
				title: __("Post Overview", 'greyd_hub'),
				description: __("Display posts with Dynamic Templates as sliders, grid, etc.", 'greyd_hub'),
				icon: greyd.tools.getBlockIcon('query'),
				category: 'greyd-blocks',
				keywords: [ 'post', 'overview', 'query', 'loop' ],
				attributes: {
					query: { perPage: 3, pages: 0, offset: 0, postType: "post", order: "desc", orderBy: "date", author: "", search: "", exclude: [], sticky: "", inherit: false },
					displayLayout: { type: 'flex', columns: 3 }
				},
				innerBlocks: [ [ "core/post-template", {}, [ [ "greyd/dynamic" ] ] ] ],
				scope: [ "inserter", "block" ]
			} );
			// console.log(settings);
		}

		if (name == 'core/post-template') {
			// console.log("register post-template");
			// dirty fix to keep displayLayout extensions
			// todo: also move here
			delete settings.attributes.layout;
			// settings.attributes.perPage = { type: 'object' };
			settings.attributes.filter = { type: 'object' };
			settings.attributes.pagination = { type: 'object' };
			settings.attributes.arrows = { type: 'object' };
			settings.attributes.sorting = { type: 'object' };
			settings.attributes.animation = { type: 'object' };
			settings.attributes.loader = { type: 'object' };
			// console.log(settings);
		}

		return settings;
	};

	wp.hooks.addFilter(
		'blocks.registerBlockType',
		'greyd/hook/query',
		registerBlockTypeHook
	);


	/**
	 * Manipulate attributes before edit.
	 * 
	 * @hook editor.BlockListBlock
	 */
	var editBlockListHook = wp.compose.createHigherOrderComponent( function ( BlockListBlock ) {
		return function ( props ) {
			// console.log(BlockListBlock);
			// console.log(props);

			// 
			// query extensions
			if (props.name == "core/query") {
				// console.log(props);
				// console.log("listing query");

				if (_.has(props.attributes.query, 'inherit') && props.attributes.query.inherit === true) {
					var query = {
						inherit: true, postType: "post", orderBy: "date", order: "desc", sticky: "", author: "", search: "", exclude: [],
						perPage: null, offset: 0, pages: 0,
					};
					if (greyd.data.post_type == "dynamic_template") {

						var isSingle = greyd.data.template_type == "single";
						var isArchive = greyd.data.template_type == "archives";
						var isSearch = greyd.data.template_type == "search";
						var postType = greyd.data.post_name.indexOf('-') > -1 ? greyd.data.post_name.split(/-(.*)/s)[1] : null;

						if ( greyd.data.template_type == "woo" ) {
							if ( greyd.data.post_name == "woo-product" ) {
								isSingle = true;
							} 
							else if ( greyd.data.post_name.indexOf("woo-product-") == 0 ) {
								isArchive = true;
							}
						}

						if ( isSingle || isArchive || isSearch ) {
							query['perPage'] = parseInt(greyd.data.posts_per_page);
							if ( postType ) {

								/**
								 * Get the postType slug in archive, single & search templates
								 * based on the curretn template slug.
								 * 
								 * @example
								 * * search-myposttype       -> myposttype
								 * * search-myposttype-news  -> myposttype
								 * * search-my-posttype      -> my-posttype
								 * * search-my-posttype-news -> my-posttype
								 */
								if ( postType.indexOf('-') > -1 ) {
									var postTypeExists = false
									for (const pt of greyd.data.post_types) {
										if (pt.slug == postType) {
											postTypeExists = true;
											break;
										}
									}
									if ( !postTypeExists ) {
										postType = postType.slice( 0, postType.lastIndexOf('-') )
									}
								}

								/**
								 * In FSE templates, the archive template used for categories and tags
								 * is called "archives-category(-general)".
								 */
								if ( postType == 'category' || postType == 'tag' ) {
									postType = 'post';
								}
								// console.log( "dynamic post type:", postType );

								query['postType'] = postType;
							}
						}
						if ( isSingle ) {
							// from vc_post_tp
							query['perPage'] = 1;
						}
						// todo: taxQuery
						if ( !_.isEqual(props.attributes.query, query) ) {
							props.attributes.query = query;
						}
					}
					// console.log("inherit query", query);
				}
			}

			return el( BlockListBlock, props );
		};
	}, 'editBlockListHook' );

	wp.hooks.addFilter( 
		'editor.BlockListBlock', 
		'greyd/hook/query/list', 
		editBlockListHook 
	);
	

	/**
	 * Add custom edit controls to core blocks.
	 * - core/query
	 * - core/post-template
	 * 
	 * @hook editor.BlockEdit
	 */
	var editBlockHook = wp.compose.createHigherOrderComponent( function( BlockEdit ) {
		
		return function( props ) {	
			
			/**
			 * =================================================================
			 *                          Query extensions
			 * =================================================================
			 */
			
			/**
			 * Extend query block.
			 */
			if (props.name == "core/query") {
				// console.log(props.attributes);
				// console.log("extending query");

				/**
				 * Convert own deprecated taxonomy filters into the core taxQuery
				 * 
				 * @since WordPress 5.9
				 */
				if ( has(props.attributes, 'query') && ( !has(props.attributes.query, 'taxQuery') || greyd.tools.isEmptyObject(props.attributes.query.taxQuery) ) ) {

					const oldQuery = { ...props.attributes.query };
					const newQuery = { ...props.attributes.query, taxQuery: {} };
					var update = false;
					
					var posttype = get(props.attributes, 'query.postType', 'post');
					for (var i=0; i<greyd.data.post_types.length; i++) {
						if (greyd.data.post_types[i].slug == posttype) {
							var pt = greyd.data.post_types[i];
							if (has(pt, "taxes") && pt.taxes.length > 0) {
								// get categories, tags and customtax
								for (var j=0; j<pt.taxes.length; j++) {

									const taxSlug = pt.taxes[j].slug;
									if ( has( oldQuery, taxSlug+'Ids' ) ) {
										newQuery.taxQuery[taxSlug] = get( oldQuery, taxSlug+'Ids' );
										delete newQuery[taxSlug+'Ids'];
										update = true;
									}
	
								}
							}
							break;
						}
					}
					if ( update ) {
						props.setAttributes( { query: newQuery } );
					}
				}

				const layout = get(props.attributes, 'displayLayout.type', '');
				const isInherit = has(props.attributes, 'query') && has(props.attributes.query, 'inherit') && props.attributes.query.inherit;

				// early escape with original block
				if ( layout !== 'flex' && isInherit ) {
					return el( BlockEdit, props );
				}

				// sync items per page attributes
				if ( layout === 'flex' && has(props.attributes, 'displayLayout') ) {

					const itemsPerPage = get(props.attributes.displayLayout, 'items');
					const queryPerPage = get(props.attributes.query, 'perPage');

					if ( itemsPerPage && itemsPerPage != queryPerPage ) {
						props.setAttributes({ query: { ...props.attributes.query, perPage: parseInt( itemsPerPage ) } });
					}
				}

				const makeDisplayLayout = function() {

					// check if gutenberg is active - don't add buttons in version < 16.0.0
					if ( 
						_.has(greyd.data, 'versions') && 
						_.has(greyd.data.versions, "gutenberg") && 
						_.has(greyd.tools, 'versionCompare') &&
						greyd.tools.versionCompare(greyd.data.versions["gutenberg"], "16.0.0", "<")
					) {
						// console.log("not adding layout buttons");
						return;
					}

					return el( wp.blockEditor.BlockControls, { group: 'inline' }, [
						el( wp.components.ToolbarButton, {
							icon: greyd.tools.getCoreIcon('layoutList'),
							label: __( "List view", 'greyd_hub' ),
							isPressed: !_.has(props.attributes, 'displayLayout.type') || (_.has(props.attributes, 'displayLayout.type') && props.attributes.displayLayout.type == 'list'),
							onClick: function() {
								// console.log("set list");
								var layout = _.has(props.attributes, 'displayLayout') ? props.attributes.displayLayout : {};
								props.setAttributes( { displayLayout: { ...layout, type: 'list' } } );
							},
						} ),
						el( wp.components.ToolbarButton, {
							icon: greyd.tools.getCoreIcon('layoutFlex'),
							label: __( "Grid view", 'greyd_hub' ),
							isPressed: _.has(props.attributes, 'displayLayout.type') && props.attributes.displayLayout.type == 'flex',
							onClick: function() {
								// console.log("set flex");
								var layout = _.has(props.attributes, 'displayLayout') ? props.attributes.displayLayout : {};
								if (!_.has(layout, 'columns')) layout.columns = 2;
								props.setAttributes( { displayLayout: { ...layout, type: 'flex' } } );
							},
						} ),
					] );
				}

				// render responsive columns media styles
				const makeResponsivePreviewStyles = function() {
					if ( layout !== 'flex' || !has(props.attributes, 'displayLayout') || !has(props.attributes.displayLayout, 'responsive') ) return null;

					var style = "";
					var selector = '#block-'+props.clientId+' .wp-block-post-template.is-flex-container > li';

					// make responsive styles
					[ 'lg', 'md', 'sm' ].forEach(function(size) {

						let css = "";

						if ( has(props.attributes.displayLayout.responsive, size+'.columns') ) {
							css += selector + " { width: calc(100% / "+ get(props.attributes.displayLayout.responsive, size+'.columns', "1") +"); } ";
						}
						else if (size == 'sm') {
							css += selector + " { width: 100%; } ";
						}

						/** responsive items per page preview */
						if ( has(props.attributes.displayLayout.responsive, size+'.items') ) {
							css += selector + ":nth-child( n + "+ ( parseInt(get( props.attributes.displayLayout.responsive, size+'.items' )) + 1 ) +" ) { display: none !important; } ";
						}

						if ( css != "" ) {
							style += "@media (max-width: "+( get(greyd.data.grid, size) - 0.02 )+"px) { "+css+" } ";
						}
					});

					// console.log( props.attributes.displayLayout, style )

					// render styles
					if ( style != "" ) {
						return el( 'style', { className: 'greyd_styles' }, style );
					}
					return null;
				};

				// 
				var makeFilter = function() {

					// set advancedFilter attributes
					var setFilter = function(param, value, target) {
						var values = props.attributes.advancedFilter;
						var index = target;
						if (typeof target !== 'number') {
							index = parseInt(target.closest('.components-greyd-controlgroup__item').dataset.index);
						}
						if (!_.has(values, index)) {
							console.warn("advancedFilter index "+index+" not available");
							return;
						}
						// console.log("change advancedFilter "+index+": "+param+": "+value);
						values[index][param] = value;
						if (param == 'name') {
							values[index] = { name: value };
						}
						props.setAttributes( { advancedFilter: [ ...values ] } );
					};

					// controls
					var optionsControl = function(atts) {
						var index = atts.index;
						var advancedFilter = props.attributes.advancedFilter[index];
						var value = !_.isEmpty(advancedFilter[atts.param]) ? advancedFilter[atts.param] : '';
						return el( greyd.components.OptionsControl, {
							label: _.has(atts, 'label') ? atts.label : '',
							help: _.has(atts, 'help') ? atts.help : '',
							value: value,
							onChange: function(value) { 
								setFilter( atts.param, value, index );
							},
							options: atts.options
						} );
					};
					var toggleControl = function(atts) {
						var index = atts.index;
						var advancedFilter = props.attributes.advancedFilter[index];
						var value = _.has(advancedFilter, atts.param) ? advancedFilter[atts.param] : false;
						return el( wp.components.ToggleControl, {
							label: _.has(atts, 'label') ? atts.label : '',
							help: _.has(atts, 'help') ? atts.help : '',
							checked: value,
							onChange: function(value) { 
								setFilter( atts.param, value, index );
							},
						} )
					};
					var radioControl = function(atts) {
						var index = atts.index;
						var advancedFilter = props.attributes.advancedFilter[index];
						var value = !_.isEmpty(advancedFilter[atts.param]) ? advancedFilter[atts.param] : '';
						return el( wp.components.RadioControl, {
							label: _.has(atts, 'label') ? atts.label : '',
							help: _.has(atts, 'help') ? atts.help : '',
							selected: value,
							onChange: function(value) { 
								setFilter( atts.param, value, index );
							},
							options: atts.options
						} );
					};
					var tokenField = function(atts) {
						var index = atts.index;
						var advancedFilter = props.attributes.advancedFilter[index];
						var value = !_.isEmpty(advancedFilter[atts.param]) ? advancedFilter[atts.param] : [];
						var suggestions = atts.suggestions.map(function(item) { return item.label } );
						var ids = atts.suggestions.map(function(item) { return item.value } );
						value = value.map(function(item) { 
							if (ids.indexOf(item) == -1) return item;
							return suggestions[ids.indexOf(item)];
						});
						return el( wp.components.FormTokenField, {
							__experimentalExpandOnFocus: true,
							__experimentalShowHowTo: _.has(atts, 'help') && atts.help,
							value: value,
							suggestions: suggestions,
							onChange: function(value) {
								value = value.map(function(item) { 
									if (suggestions.indexOf(item) == -1) return item;
									return ids[suggestions.indexOf(item)];
								});
								setFilter( atts.param, value, index );
							},
							tokenizeOnBlur: true
						} );
					};
					var help = function(name, not=false) {
						if (name == 'taxonomy') {
							if (not) return __("Exclude posts with assigned terms from a taxonomy", 'greyd_hub');
							else return __("Show only posts with assigned terms of a taxonomy", 'greyd_hub');
						}
						if (name == 'author') {
							if (not) return __("Exclude posts from specific authors", 'greyd_hub');
							else return __("Show only posts from specific authors", 'greyd_hub');
						}
						if (name == 'include') {
							if (not) return __("Exclude individual posts", 'greyd_hub');
							else return __("Select individual posts to be shown", 'greyd_hub');
						}
						if (name == 'meta') {
							if (not) return __("Exclude posts with meta field property", 'greyd_hub');
							else return __("Show only posts with meta field property", 'greyd_hub');
						}
						if (name == 'order') {
							if (not) return __("Choose the order in which the posts should be sorted in descending order", 'greyd_hub');
							else return __("Choose the order in which the posts should be sorted in ascending order", 'greyd_hub');
						}
						return "";
					};
				
					// selected posttype
					var posttype = 'post';
					if ( _.has(props.attributes, 'query') && _.has(props.attributes.query, 'postType') ) {
						posttype = props.attributes.query.postType;
					}

					// get posts of posttype
					var getPosts = function() {
						var posts = {};
						var advancedFilter = [];
						if ( _.has(greyd.data.all_posts, posttype) ) {
							for (var i=0; i<greyd.data.all_posts[posttype].length; i++) {
								var post = greyd.data.all_posts[posttype][i];
								var title = post['id']+": "+post['title'];
								var language = "default";
								if ( _.has(post, 'lang') && typeof post.lang === 'object' && post.lang && post.lang.language_code != "" ) {
									// console.log(value.lang);
									language = post.lang.language_code;
									title += " ("+language+")";
									if ( language != greyd.data.language.post.language_code && language != greyd.data.language.default ) {
										advancedFilter.push(post['id']);
									}
									else if ( _.has(post.lang, 'original_id' )) {
										advancedFilter.push(post.lang['original_id']);
									}
								}
								if ( !_.has(posts, language) ) posts[language] = [];
								posts[language].push( { value: post['id'], label: title } );
							}
						}
						var final = [];
						for (var [lang, options] of Object.entries(posts)) {
							var advancedFiltered = [];
							if (advancedFilter.length == 0) advancedFiltered = options;
							else {
								for (var i=0; i<options.length; i++) {
									// console.log(options[i]);
									if (advancedFilter.indexOf(options[i].value) == -1)
										advancedFiltered.push(options[i]);
									// else console.log("skipped: "+options[i].value);
								}
							}
							if (advancedFiltered.length > 0) {
								if (lang == 'default') {
									final = [ ...advancedFiltered, ...final ];
								}
								else {
									final = [ ...final, ...advancedFiltered ];
								}
							}
						}
						return final;
					};
					// is posttype hierarchical
					var isHierarchical = function() {
						if ( posttype == 'post' ) return false;
						else if ( posttype == 'page' ) return true;
						else {
							for (var i=0; i<greyd.data.post_types.length; i++) {
								if ( greyd.data.post_types[i]['slug'] == posttype ) {
									if ( _.has(greyd.data.post_types[i]['arguments'], 'hierarchical') ) return true;
									break;
								}
							}
							return false;
						}
					};

					// get taxonomies of posttype
					var getTaxonomies = function() {
						var final = [];
						if ( _.has(greyd.data.all_taxes, posttype) ) {
							for (var i=0; i<greyd.data.all_taxes[posttype].length; i++) {
								var tax = greyd.data.all_taxes[posttype][i];
								if (tax['public']) {
									final.push( { value: tax['slug'], label: tax['title'] } );
								}
							}
						}
						if (final.length == 0) {
							final.push( { value: '', label: sprintf( __("\"%s\" has no taxonomies", 'greyd_hub'), posttype), disabled: true } );
						}
						else {
							final.unshift( { value: '', label: __("Select taxonomy", 'greyd_hub') } );
						}
						return final;
					};
					// is taxonomy hierarchical
					var isHierarchicalTax = function(tax) {
						if ( _.has(greyd.data.all_taxes, posttype ) ) {
							for (var i=0; i<greyd.data.all_taxes[posttype].length; i++) {
								if ( greyd.data.all_taxes[posttype][i]['slug'] == tax ) {
									if (greyd.data.all_taxes[posttype][i]['hierarchical']) return true;
								}
							}
						}
						return false;
					};
					// get terms of taxonomy
					var getTerms = function(tax) {
						var final = [];
						if ( _.has(greyd.data.all_taxes, posttype ) ) {
							for (var i=0; i<greyd.data.all_taxes[posttype].length; i++) {
								if ( greyd.data.all_taxes[posttype][i]['slug'] == tax ) {
									for (var j=0; j<greyd.data.all_taxes[posttype][i]['values'].length; j++) {
										var term = greyd.data.all_taxes[posttype][i]['values'][j];
										var title = term['title']+" ("+term['count']+")";
										final.push( { value: term['id'], label: title } );
									}
									break;
								}
							}
						}
						return final;
					};

					// get all meta fields of posttye
					var getFields = function() {
						var final = [];
						for (var i=0; i<greyd.data.post_types.length; i++) {
							if ( greyd.data.post_types[i]['slug'] == posttype && _.has(greyd.data.post_types[i], 'fields') ) {
								for (var j=0; j<greyd.data.post_types[i]['fields'].length; j++) {
									var field = greyd.data.post_types[i]['fields'][j];
									if (
										!_.has(field, "type") ||
										field["type"] === 'hr' ||
										field["type"] === 'space' ||
										field["type"] === 'headline' ||
										field["type"] === 'descr'
									) continue;
									final.push( { value: field['name'], label: field['label'] } );
								}
								break;
							}
						}
						if (final.length == 0) {
							final.push( { value: '', label: sprintf( __("\"%s\" has no meta fields", 'greyd_hub'), posttype), disabled: true } );
						}
						else {
							final.unshift( { value: '', label: __("Select meta field", 'greyd_hub') } );
						}
						return final;
					};

					// get all authors/users
					var getAuthors = function() {
						var final = [];
						for (var i=0; i<greyd.data.users.length; i++) {
							final.push( { value: greyd.data.users[i]['id'], label: greyd.data.users[i]['display_name'] } );
						}
						return final;
					};
					// has posttype author support
					var hasAuthors = function() {
						if ( posttype == 'post' || posttype == 'page' ) return true;
						else {
							for (var i=0; i<greyd.data.post_types.length; i++) {
								if ( greyd.data.post_types[i]['slug'] == posttype ) {
									if ( _.has(greyd.data.post_types[i]['supports'], 'author') ) return true;
									break;
								}
							}
							return false;
						}
					}

					// is setting postviews_counter enabled
					var postviewsEnabled = function() {
						return _.has(greyd.data.settings, 'advanced_search') && greyd.data.settings.advanced_search.postviews_counter == "true";
					}

					// make controls
					var controls = [];
					if (!_.isEmpty(props.attributes.advancedFilter)) {
						var orderOnce = false;
						for (var i=0; i<props.attributes.advancedFilter.length; i++) {
							var advancedFilter = props.attributes.advancedFilter[i];
							if (advancedFilter.name == 'order') orderOnce = true;
							controls.push(
								el( 'div', {
									className: 'components-greyd-controlgroup__item',
									'data-index': i,
								}, [
									// remove
									el( wp.components.Button, { 
										className: "components-greyd-controlgroup__remove",
										onClick: (event) => {
											var index = parseInt(event.target.closest('.components-greyd-controlgroup__item').dataset.index);
											// console.log("remove advancedFilter "+index);
											var values = props.attributes.advancedFilter;
											values.splice(index, 1);
											props.setAttributes( { advancedFilter: [ ...values ] } ); 
										},
										title: __("Remove filter", 'greyd_hub')
									}, el( wp.components.Icon, { icon: 'no-alt' } ) ),

									// advancedFilter
									optionsControl( {
										index: i,
										label: __('Filter', 'greyd_hub'),
										param: 'name',
										options: [
											{ value: '', label: __("Select filter", 'greyd_hub') },
											{ value: 'taxonomy', label: __("filter by taxonomy", 'greyd_hub') },
											{ value: 'meta', label: __("filter by meta field", 'greyd_hub') },
											hasAuthors() && { value: 'author', label: __('filter by authors', 'greyd_hub') },
											{ value: 'include', label: __("select individual posts", 'greyd_hub') },
											{ value: 'order', label: __("Sort results", 'greyd_hub'), ...orderOnce ? { disabled: true } : {} },
										]
									} ),

									// taxonomy
									advancedFilter.name == 'taxonomy' && [
										optionsControl( {
											index: i,
											label: __("Taxonomy", 'greyd_hub'),
											param: 'taxonomy',
											options: getTaxonomies(),
										} ),
										!_.isEmpty(advancedFilter.taxonomy) && [
											tokenField( {
												index: i,
												param: 'terms',
												suggestions: [
													{ 
														value: 'current_terms', 
														label: advancedFilter.not == true ? 
															__("Exclude terms of the current post", 'greyd_hub') : 
															__("Terms of the current post", 'greyd_hub') 
													},
													{
														value: 'any_terms',
														label: advancedFilter.not == true ? 
															__("Exclude posts with terms", 'greyd_hub') : 
															__("Posts with terms", 'greyd_hub') 
													},
													...getTerms(advancedFilter.taxonomy),
												]
											} ),
											isHierarchicalTax(advancedFilter.taxonomy) && toggleControl( {
												index: i,
												param: 'children',
												label: advancedFilter.not == true ? 
													__("do not exclude subordinate terms", 'greyd_hub') : 
													__("exclude subordinate terms", 'greyd_hub')
											} ),
										]
									],

									// meta
									advancedFilter.name == 'meta' && [
										optionsControl( {
											index: i,
											param: 'meta',
											options: getFields(),
										} ),
										!_.isEmpty(advancedFilter.meta) && [
											radioControl( {
												index: i,
												param: 'operator',
												options: advancedFilter.not ? [
													{ value: '', label: _x( "is not set", 'small', 'greyd_hub' ) },
													{ value: 'is', label: _x( "has not the value:", 'small', 'greyd_hub' ) },
													{ value: 'has', label: _x( "does not contain the value:", 'small', 'greyd_hub' ) },
												] : [
													{ value: '', label: _x( "is set", 'small', 'greyd_hub' ) },
													{ value: 'is', label: _x( "has the value:", 'small', 'greyd_hub' ) },
													{ value: 'has', label: _x( "contains the value:", 'small', 'greyd_hub' ) },
												]
											} ),
											!_.isEmpty(advancedFilter.operator) && [
												tokenField( {
													index: i,
													param: 'search',
													suggestions: [
														{ 
															value: 'current_meta', 
															label: advancedFilter.not == true ? 
																__("Exclude field value of the current post", 'greyd_hub') : 
																__("Field value of the current post", 'greyd_hub') 
														}
													],
													help: true
												} )
											]
										]
									],

									// author
									advancedFilter.name == 'author' && [
										tokenField( {
											index: i,
											param: 'author',
											suggestions: [
												{ 
													value: 'current_author', 
													label: advancedFilter.not == true ? 
														__("Exclude author of the current post", 'greyd_hub') : 
														__("Author of the current post", 'greyd_hub') 
												},
												{
													value: 'any_author',
													label: advancedFilter.not == true ? 
														__("Exclude posts with author", 'greyd_hub') : 
														__("Posts with author", 'greyd_hub') 
												},
												...getAuthors(),
											]
										} ),
									],

									// include
									advancedFilter.name == 'include' && [
										tokenField( {
											index: i,
											param: 'include',
											suggestions: [
												{ 
													value: 'current_post', 
													label: advancedFilter.not == true ? 
														__("Exclude current post", 'greyd_hub') : 
														__("Current post", 'greyd_hub') 
												},
												...getPosts(),
											]
										} ),
										isHierarchical() && toggleControl( {
											index: i,
											param: 'children',
											label: __("only subordinate posts", 'greyd_hub'),
										} ),
									],

									// order
									advancedFilter.name == 'order' && [
										optionsControl( {
											index: i,
											label: __("Order", 'greyd_hub'),
											param: 'order',
											options: advancedFilter.not ? [
												// absteigend
												{ value: '', label: __("Select sorting", 'greyd_hub') },
												{ value: 'date', label: __("Old to new", 'greyd_hub') },
												{ value: 'title', label: __('Z → A', 'greyd_hub') },
												{ value: 'meta', label: __("Meta descending", 'greyd_hub') },
												isHierarchical() && { value: 'menu_order', label: __("Order descending", 'greyd_hub') },
												postviewsEnabled() && { value: 'views', label: __("Least read", 'greyd_hub') },
												{ value: 'random', label: __("Random", 'greyd_hub') },
											] : [
												// aufsteigend
												{ value: '', label: __("Select sorting", 'greyd_hub') },
												{ value: 'date', label: __("New to old", 'greyd_hub') },
												{ value: 'title', label: __('A → Z', 'greyd_hub') },
												{ value: 'meta', label: __("Meta ascending", 'greyd_hub') },
												isHierarchical() && { value: 'menu_order', label: __("Order ascending", 'greyd_hub') },
												postviewsEnabled() && { value: 'views', label: __("Most read", 'greyd_hub') },
												{ value: 'random', label: __("Random", 'greyd_hub') },
											]
										} ),
										advancedFilter.order == 'meta' && [
											optionsControl( {
												index: i,
												param: 'meta',
												options: getFields(),
											} ),
											!_.isEmpty(advancedFilter.meta) && [
												radioControl( {
													index: i,
													param: 'operator',
													options: [
														{ value: '', label: _x( "auto", 'small', 'greyd_hub' ) },
														{ value: 'alphabetical', label: _x( "alphabetical", 'small', 'greyd_hub' ) },
														{ value: 'chronological', label: _x( "chronological", 'small', 'greyd_hub' ) },
														{ value: 'numeric', label: _x( "numerical", 'small', 'greyd_hub' ) }
													]
												} ),

											]
										]
									],

									// negate
									advancedFilter.name != '' && [
										toggleControl( {
											index: i,
											param: 'not',
											label: /*advancedFilter.name != 'order' ? __('ausschließen', 'greyd_hub') :*/ __("reverse / exclude", 'greyd_hub'),
										} ),
										el( 'p', { className: "greyd-inspector-help" }, help(advancedFilter.name, advancedFilter.not) )
									],
								] )
							);
						}
					}
					return controls;
				}

				return el( wp.element.Fragment, { }, [
					// toolbar
					makeDisplayLayout(),
					// responsive columns style
					makeResponsivePreviewStyles(),
					// original block
					el( BlockEdit, props ),
					// sidebar
					el( wp.blockEditor.InspectorControls, { }, [
						// advancedFilter
						el( greyd.components.AdvancedPanelBody, { 
							title: __("Advanced filters", 'greyd_hub'),
							// isBeta: true,
							initialOpen: !_.isEmpty(props.attributes.advancedFilter),
							holdsChange: !_.isEmpty(props.attributes.advancedFilter)
						}, [
							el( 'div', { className: 'components-greyd-controlgroup'}, [
								makeFilter(),
								el( wp.components.Button, {
									className: 'components-greyd-controlgroup__add'+( _.isEmpty(props.attributes.advancedFilter) ? ' group_is_empty': '' ),
									onClick: function() {
										// console.log('adding parameter');
										var values = !_.isEmpty(props.attributes.advancedFilter) ? props.attributes.advancedFilter : [];
										values.push( { name: '' } );
										props.setAttributes( { advancedFilter: [ ...values ] } ); 
									},
									title: __("Add filter", 'greyd_hub')
								}, [
									el( wp.components.Icon, { icon: 'plus-alt2' } ),
									_.isEmpty(props.attributes.advancedFilter) ? el( 'span', {}, __("Add filter", 'greyd_hub') ) : null
								] )
							] )
						] ),
						// responsive columns
						el( greyd.components.StylingControlPanel, {
							title: __("Grid Settings", 'greyd_hub'),
							initialOpen: true,
							supportsResponsive: true,
							parentAttr: "displayLayout",
							blockProps: props,
							controls: [
								...isInherit ? [] : [ {
									label: __("elements per page", 'greyd_hub'),
									attribute: "items",
									control: wp.components.__experimentalNumberControl,
									min: 1,
									// control: wp.components.RangeControl,
									// min: 1, max: 12,
								} ],
								...layout !== 'flex' ? [] : [ {
									label: __("Colums", 'greyd_hub'),
									attribute: "columns",
									control: wp.components.RangeControl,
									min: 1, max: 12,
								} ]
							]
						} ),
					] ), 
				] );

			}

			/**
			 * Extend post template block (direct child of core/query)
			 */
			if (props.name == "core/post-template") {
				// console.log(props);
				// console.log("extending post-template");
				
				// get parent query
				const getParent = () => {
					var parent = greyd.tools.isChildOf(props.clientId, 'core/query');
					if ( !parent && props.context?.previewPostType ) {
						// fix previews (e.g. pattern)
						parent = { attributes: props.context };
					}
					return parent;
				}
				var parent = getParent();
				// console.log(parent);

				// sorting dropdown
				const sortingLabels = {
					date_DESC: __("chronological (newest first)", 'greyd_hub'),
					date_ASC: __("chronological (oldest first)", 'greyd_hub'),
					title_ASC: __("alphabetical (ascending)", 'greyd_hub'),
					title_DESC: __("alphabetical (descending)", 'greyd_hub'),
					...( greyd.data.settings?.advanced_search?.postviews_counter == "true" ? {
						views_DESC: __("Post views", 'greyd_hub')
					} : {} ),
					...( greyd.data.settings?.advanced_search?.relevance == "true" ? {
						relevance_DESC: __("Relevance", 'greyd_hub')
					} : {} ),
				}


				/**
				 * (1) VALUES
				 */
				// defaults for sorting, pagination and arrows
				const defaults = {
					filter: { 
						enable: false, 
						position: 'top', 
						align: 'end',

						inputStyle: '',
						custom: false,
						customStyles: {},
						empty: '',
						showTaxTitle: false,

						greydClass: getGreydClass(props, 'filter.greydClass'), // generateGreydClass(),
						greydStyles: {
							width: '',
							margin: {},
						},
					},
					sorting: { 
						enable: false, 
						position: 'top', 
						align: 'end',

						inputStyle: '',
						custom: false,
						customStyles: {},
						options: {
							date_DESC: '',
							date_ASC: '',
							title_DESC: '',
							title_ASC: '',
							views_DESC: '',
							relevance_DESC: '',
						},

						greydClass: getGreydClass(props, 'sorting.greydClass'), // generateGreydClass(),
						greydStyles: {
							width: '',
							margin: {},
						},
					},
					pagination: { 
						enable: true, 
						position: 'bottom', 
						// align: 'center',
						overlap: false, 
						
						type: 'icon', 
						text_type: '',
						icon_type: 'icon',
						icon_normal: 'icon_circle-empty',
						icon_active: 'icon_circle-slelected',
						img_normal: -1, 
						img_active: -1,

						arrows_type: 'icon',
						icon_previous: 'arrow_left', 
						icon_next: 'arrow_right',
						img_previous: -1, 
						img_next: -1,

						greydClass: getGreydClass(props, 'pagination.greydClass'), // generateGreydClass(),
						greydStyles: {
							justifyContent: 'center',
							color: '',
							opacity: '',
							fontSize: '',
							padding: { top: '', right: '', bottom: '', left: '' },
							gutter: ''
						},
					 },
					arrows: { 
						enable: false,
						overlap: false, 

						type: 'icon', 
						icon_previous: 'arrow_left', 
						icon_next: 'arrow_right',
						img_previous: -1, 
						img_next: -1,

						greydClass: getGreydClass(props, 'arrows.greydClass'), // generateGreydClass(),
						greydStyles: {
							alignItems: 'center',
							color: '',
							opacity: '',
							fontSize: '',
							padding: { top: '', right: '', bottom: '', left: '' }
						},
					},
					animation: {
						anim: '',
						loop: false,
						autoplay: false,
						interval: 5,
						height: '',
						height_custom: '500px',
						scroll_top: false
					},
					loader: {
						style: '',
						size: '',
						greydClass: getGreydClass(props, 'loader.greydClass'), // generateGreydClass(),
						greydStyles: {},
					}
				};

				var values = {
					filter: greyd.tools.getBackgroundvalues(defaults.filter, props.attributes.filter),
					sorting: greyd.tools.getBackgroundvalues(defaults.sorting, props.attributes.sorting),
					pagination: greyd.tools.getBackgroundvalues(defaults.pagination, props.attributes.pagination),
					arrows: greyd.tools.getBackgroundvalues(defaults.arrows, props.attributes.arrows)
				};

				/**
				 * Live Search support
				 * @since 1.2.0
				 */
				const liveSearchEnabled = (
					greyd.data.settings?.advanced_search?.live_search === "true" &&
					greyd.data?.template_type === 'search' &&
					parent?.attributes?.query?.inherit
				);
				if ( liveSearchEnabled ) {
					values.loader = greyd.tools.getBackgroundvalues( defaults.loader, props.attributes.loader);
				}

				// remove deprecated atts
				if (_.isEmpty(values.pagination.greydStyles, 'justifyContent')) {
					values.pagination.greydStyles.justifyContent = defaults.pagination.greydStyles.justifyContent;
				}
				if (_.isEmpty(values.arrows.greydStyles, 'alignItems')) {
					values.arrows.greydStyles.alignItems = defaults.arrows.greydStyles.alignItems;
				}

				var filterProps = {
					attributes: values.filter,
					setAttributes: function(value) {
						// console.log(value);
						setValues('filter', value);
					}
				};
				var sortingProps = {
					attributes: values.sorting,
					setAttributes: function(value) {
						// console.log(value);
						setValues('sorting', value);
					}
				};
				var paginationProps = {
					attributes: values.pagination,
					setAttributes: function(value) {
						setValues('pagination', value);
					}
				};
				var arrowProps = {
					attributes: values.arrows,
					setAttributes: function(value) {
						// console.log(value);
						setValues('arrows', value);
					}
				};
				const loaderProps = {
					attributes: values.loader,
					setAttributes: (value) => {
						props.setAttributes( { loader: { ...values.loader, ...value } } )
					}
				};
				var setValues = function(slug, value) {
					if (typeof value !== 'undefined') {
						var new_values = false;
						if (has(value, 'greydStyles')) {
							// console.log(value.greydStyles);
							// console.log(values.arrows.greydStyles);
							new_values = { ...values[slug], greydStyles: value.greydStyles };
						}
						if (has(value, 'customStyles')) {
							new_values = { ...values[slug], customStyles: value.customStyles };
						}
						else if (has(value, slug)) {
							// console.log(value);
							new_values = greyd.tools.makeBackgroundvalues(defaults[slug], { ...values[slug], ...value[slug] });
						}
						if (new_values) props.setAttributes( { [slug]: new_values } );
					}

				}
				var setAnimation = function(values) {
					var new_values = greyd.tools.makeBackgroundvalues(defaults.animation, values.animation);
					props.setAttributes( { animation: new_values } );
				}
				if (has(parent.attributes, 'animation')) {
					// move animation atts
					// console.log(parent);
					setAnimation(parent.attributes);
					delete parent.attributes.animation;
				}


				var getImageUrl = function(id) {
					if(_.has(greyd.data.media_urls, id)) {
						return greyd.data.media_urls[id].src
					} else {
						return "";
					}
				};

				var [mode, setMode ] = wp.element.useState("");
				// console.log('mode: '+mode);

				if (!props.isSelected && mode != "") setMode("");


				/**
				 * (2) CONTROLS
				 */
				const makeInspectorControls = function() {
					return el( wp.blockEditor.InspectorControls, { }, [

						// general
						...(
							mode == ""
							? [
								// pagination features
								el( greyd.components.AdvancedPanelBody, { 
									title: __("Slider elements", 'greyd_hub'), 
									initialOpen: true, 
								}, [
									// filter
									parent?.attributes?.query?.inherit
									? null
									: el( 'div', { className: 'is-flex-space-between' },
										el( wp.components.ToggleControl, {
											label: __('Filter', 'greyd_hub'),
											checked: values.filter.enable,
											onChange: function(value) { 
												filterProps.setAttributes( { filter: { ...values.filter, enable: value } } );
											},
										} ),
										(values.filter.enable) ? el( wp.components.Button, {
											icon: 'admin-tools',
											style: { height: '20px' },
											onClick: function() { setMode("filter") }
										}) : el( 'div' ),
									),
									// sorting
									el( 'div', { className: 'is-flex-space-between' },
										el( wp.components.ToggleControl, {
											label: __("Order", 'greyd_hub'),
											checked: values.sorting.enable,
											onChange: function(value) { 
												sortingProps.setAttributes( { sorting: { ...values.sorting, enable: value } } );
											},
										} ),
										(values.sorting.enable) ? el( wp.components.Button, {
											icon: 'admin-tools',
											style: { height: '20px' },
											onClick: function() { setMode("sorting") }
										}) : el( 'div' ),
									),
									// arrows
									liveSearchEnabled ? null : el( 'div', { className: 'is-flex-space-between' },
										el( wp.components.ToggleControl, {
											label: __("Side arrows", 'greyd_hub'),
											checked: values.arrows.enable,
											onChange: function(value) { 
												arrowProps.setAttributes( { arrows: { ...values.arrows, enable: value } } ); 
											},
										} ),
										(values.arrows.enable) ? el( wp.components.Button, {
											icon: 'admin-tools',
											style: { height: '20px' },
											onClick: function() { setMode("arrows") }
										}) : el( 'div' ),
									),
									// pagination
									liveSearchEnabled ? null : el( 'div', { className: 'is-flex-space-between' },
										el( wp.components.ToggleControl, {
											label: __("classic pagination", 'greyd_hub'),
											checked: values.pagination.enable,
											onChange: function(value) { 
												paginationProps.setAttributes( { pagination: { ...values.pagination, enable: value } } ); 
											},
										} ),
										(values.pagination.enable) ? el( wp.components.Button, {
											icon: 'admin-tools',
											style: { height: '20px' },
											onClick: function() { setMode("numbers") }
										}) : el( 'div' ),
									),
									// load more
									liveSearchEnabled ? el( 'div', {
										className: 'is-flex-space-between',
										onClick: function() { setMode("loader") }
									}, [
										el( 'span', {}, __("\"Load more\" button", 'greyd_hub') ),
										el( wp.components.Button, {
											icon: 'admin-tools',
											style: { height: '20px' }
										})
									] ) : null,
								] ),

								// animation
								el( greyd.components.AdvancedPanelBody, { 
									className: (get(parent.attributes, 'query.inherit', false) == false) ? '' : 'hidden',
									title: __('Animation', 'greyd_hub'), 
									initialOpen: true, 
								}, [
									// posts_animation
									el( greyd.components.ButtonGroupControl, {
										label: __( "Animation type", 'greyd_hub' ),
										value: get(props.attributes, 'animation.anim', defaults.animation.anim),
										options: [
											{ label: __('Slide', 'greyd_hub'), value: '' },
											{ label: __('Fade', 'greyd_hub'), value: 'fade' },
											{ label: __('Cover-Flow', 'greyd_hub'), value: 'cover' },
											{ label: __('✕', 'greyd_hub'), value: 'none' },
										],
										onChange: function(value) {
											// console.log(value);
											setAnimation( { animation: { ...props.attributes.animation, anim: value } } );
										},
									} ),
									// posts_loop
									el( wp.components.ToggleControl, {
										label: __('Loop', 'greyd_hub'),
										help: __("after the last slide, the first one is displayed again.", 'greyd_hub'),
										checked: get(props.attributes, 'animation.loop', defaults.animation.loop),
										onChange: function(value) { 
											// console.log(value);
											setAnimation( { animation: { ...props.attributes.animation, loop: value } } );
										},
									} ),
									// posts_autoplay
									el( wp.components.ToggleControl, {
										label: __('Autoplay', 'greyd_hub'),
										help: __("slides are played automatically.", 'greyd_hub'),
										checked: get(props.attributes, 'animation.autoplay', defaults.animation.autoplay),
										onChange: function(value) { 
											// console.log(value);
											setAnimation( { animation: { ...props.attributes.animation, autoplay: value } } );
										},
									} ),
									// posts_interval
									(get(props.attributes, 'animation.autoplay', defaults.animation.autoplay) == true) ? 
										el( wp.components.RangeControl, {
											label: __("Interval in s", 'greyd_hub'),
											value: get(props.attributes, 'animation.interval', defaults.animation.interval),
											step: 0.1, min: 0, max: 30,
											onChange: function(value) { 
												// console.log(value);
												setAnimation( { animation: { ...props.attributes.animation, interval: value } } );
											},
										} ) : '',
									// posts_height
									el( wp.components.SelectControl, {
										label: __( "Height of the slider", 'greyd_hub' ),
										value: get(props.attributes, 'animation.height', defaults.animation.height),
										options: [
											{ label: __("adjust automatically", 'greyd_hub'), value: '' },
											{ label: __("as high as highest slide", 'greyd_hub'), value: 'auto' },
											{ label: __("enter height", 'greyd_hub'), value: 'custom' },
										],
										onChange: function(value) { 
											// console.log(value);
											setAnimation( { animation: { ...props.attributes.animation, height: value } } );
										},
									} ),
									// posts_height_custom
									(get(props.attributes, 'animation.height', defaults.animation.height) == 'custom') ? 
										el( greyd.components.RangeUnitControl, {
											value: get(props.attributes, 'animation.height_custom', defaults.animation.height_custom),
											// units: [ '%', 'em' ],
											min: 10, max: 1000,
											onChange: function(value) { 
												// console.log(value);
												setAnimation( { animation: { ...props.attributes.animation, height_custom: value } } );
											},
										} ) : '',
									// posts_scroll_top
									el( wp.components.ToggleControl, {
										label: __("scroll up", 'greyd_hub'),
										help: __("When the slide is changed, it automatically scrolls up to the beginning of the slider.", 'greyd_hub'),
										checked: get(props.attributes, 'animation.scroll_top', defaults.animation.scroll_top),
										onChange: function(value) { 
											// console.log(value);
											setAnimation( { animation: { ...props.attributes.animation, scroll_top: value } } );
										},
									} ),
								] ),
							]
							: [
								el( wp.components.Button, {
									icon: 'arrow-left-alt',
									// style: { height: '20px' },
									onClick: function() { setMode("") }
								}, __("general settings", 'greyd_hub') )
							]
						),

						// filter
						...(
							mode == "filter" && values.filter.enable && !parent?.attributes?.query?.inherit
							? [
								// basics
								el( greyd.components.AdvancedPanelBody, { 
									title: __('Filter', 'greyd_hub'), 
									initialOpen: true, 
									// holdsChange: parts.background.type != "" 
								}, [
									// position
									el( 'span', {}, __('Position', 'greyd_hub') ),
									el( greyd.components.ButtonGroupControl, {
										value: values.filter.position,
										options: [
											{ label: __("top", 'greyd_hub'), value: 'top' },
											{ label: __("bottom", 'greyd_hub'), value: 'bottom' },
										],
										onChange: function(value) { 
											filterProps.setAttributes( { filter: { ...values.filter, position: value } } ); 
										},
									} ),
									// align
									el( 'span', {}, __("Alignment", 'greyd_hub') ),
									el( greyd.components.ButtonGroupControl, {
										value: values.filter.align,
										options: [
											{ label: __("left", 'greyd_hub'), value: 'start' },
											{ label: __("center", 'greyd_hub'), value: 'center' },
											{ label: __("right", 'greyd_hub'), value: 'end' },
										],
										onChange: function(value) { 
											filterProps.setAttributes( { filter: { ...values.filter, align: value } } ); 
										},
									} ),
								] ),
								// design
								el( greyd.components.AdvancedPanelBody, { 
									title: __("Appearance", 'greyd_hub'), 
									initialOpen: false, 
								}, [
									// types
									el( greyd.components.ButtonGroupControl, {
										value: values.filter.inputStyle,
										options: [
											{ label: __('Primary', 'greyd_hub'), value: '' },
											{ label: __('Secondary', 'greyd_hub'), value: 'sec' },
										],
										onChange: function(value) { 
											filterProps.setAttributes( { filter: { ...values.filter, inputStyle: value } } ); 
										},
									} ),
									el( wp.components.ToggleControl, {
										label: __( "Overwrite design individually", 'greyd_hub' ),
										checked: values.filter.custom,
										onChange: function(value) { 
											filterProps.setAttributes( { filter: { ...values.filter, custom: value } } ); 
											// props.setAttributes( { styles: { ...props.attributes.styles, custom: value } } ); 
										},
									} ),
								] ),
								(values.filter.custom) ? el( greyd.components.CustomButtonStyles, {
									blockProps: filterProps,
									parentAttr: 'customStyles'
								} ) : '',
								// styles
								// greydStyles + responsive
								el( greyd.components.StylingControlPanel, {
									title: __("Size", 'greyd_hub'),
									initialOpen: false,
									supportsResponsive: true,
									blockProps: filterProps,
									controls: [ {
										label: __("Width", 'greyd_hub'),
										attribute: "width",
										control: greyd.components.RangeUnitControl,
										max: 1000
									} ]
								} ),
								el( greyd.components.StylingControlPanel, {
									title: __("Spaces", 'greyd_hub'),
									initialOpen: false,
									supportsResponsive: true,
									blockProps: filterProps,
									controls: [ {
										label: __("Outside", 'greyd_hub'),
										attribute: "margin",
										control: greyd.components.DimensionControl,
									} ]
								} ),
								// labels
								el( greyd.components.AdvancedPanelBody, { 
									title: __("Designations", 'greyd_hub'), 
									initialOpen: false, 
								}, [
									el( wp.components.TextControl, {
										label: __("Select filter", 'greyd_hub'),
										value: values.filter.empty,
										onChange: function(value) { 
											filterProps.setAttributes( { filter: { ...values.filter, empty: value } } ); 
										},
									} ), 
									el( wp.components.ToggleControl, {
										label: __( "Show filter title", 'greyd_hub' ),
										checked: values.filter.showTaxTitle,
										onChange: function(value) { 
											filterProps.setAttributes( { filter: { ...values.filter, showTaxTitle: value } } ); 
										},
									} ),
								] ),
							]
							: []
						),

						// sorting
						...( 
							mode == "sorting" && values.sorting.enable
							? [
								// basics
								el( greyd.components.AdvancedPanelBody, { 
									title: __("Order", 'greyd_hub'), 
									initialOpen: true, 
									// holdsChange: parts.background.type != "" 
								}, [
									// position
									el( 'span', {}, __('Position', 'greyd_hub') ),
									el( greyd.components.ButtonGroupControl, {
										value: values.sorting.position,
										options: [
											{ label: __("top", 'greyd_hub'), value: 'top' },
											{ label: __("bottom", 'greyd_hub'), value: 'bottom' },
										],
										onChange: function(value) { 
											sortingProps.setAttributes( { sorting: { ...values.sorting, position: value } } ); 
										},
									} ),
									// align
									el( 'span', {}, __("Alignment", 'greyd_hub') ),
									el( greyd.components.ButtonGroupControl, {
										value: values.sorting.align,
										options: [
											{ label: __("left", 'greyd_hub'), value: 'start' },
											{ label: __("center", 'greyd_hub'), value: 'center' },
											{ label: __("right", 'greyd_hub'), value: 'end' },
										],
										onChange: function(value) { 
											sortingProps.setAttributes( { sorting: { ...values.sorting, align: value } } ); 
										},
									} ),
								] ),
								// design
								el( greyd.components.AdvancedPanelBody, { 
									title: __("Appearance", 'greyd_hub'), 
									initialOpen: false, 
								}, [
									// types
									el( greyd.components.ButtonGroupControl, {
										value: values.sorting.inputStyle,
										options: [
											{ label: __('Primary', 'greyd_hub'), value: '' },
											{ label: __('Secondary', 'greyd_hub'), value: 'sec' },
										],
										onChange: function(value) { 
											sortingProps.setAttributes( { sorting: { ...values.sorting, inputStyle: value } } ); 
										},
									} ),
									el( wp.components.ToggleControl, {
										label: __( "Overwrite design individually", 'greyd_hub' ),
										checked: values.sorting.custom,
										onChange: function(value) { 
											sortingProps.setAttributes( { sorting: { ...values.sorting, custom: value } } ); 
											// props.setAttributes( { styles: { ...props.attributes.styles, custom: value } } ); 
										},
									} ),
								] ),
								values.sorting.custom && el( greyd.components.CustomButtonStyles, {
									blockProps: sortingProps,
									parentAttr: 'customStyles'
								} ),
								// styles
								// greydStyles + responsive
								el( greyd.components.StylingControlPanel, {
									title: __("Size", 'greyd_hub'),
									initialOpen: false,
									supportsResponsive: true,
									blockProps: sortingProps,
									controls: [ {
										label: __("Width", 'greyd_hub'),
										attribute: "width",
										control: greyd.components.RangeUnitControl,
										max: 1000
									} ]
								} ),
								el( greyd.components.StylingControlPanel, {
									title: __("Spaces", 'greyd_hub'),
									initialOpen: false,
									supportsResponsive: true,
									blockProps: sortingProps,
									controls: [ {
										label: __("Outside", 'greyd_hub'),
										attribute: "margin",
										control: greyd.components.DimensionControl,
									} ]
								} ),
								// options labels
								el( greyd.components.AdvancedPanelBody, { 
									title: __("Designations", 'greyd_hub'), 
									initialOpen: false, 
								}, Object.keys(sortingLabels).map((key) => {
									// console.log(key);
									return el( wp.components.TextControl, {
										label: sortingLabels[key],
										value: _.has(values.sorting.options, key) ? values.sorting.options[key] : '',
										onChange: (value) => sortingProps.setAttributes({
											sorting: {
												...values.sorting,
												options: {
													...values.sorting.options,
													[key]: value
												}
											}
										} ),
									} );
								}) ),
							]
							: []
						),

						// numbers
						...(
							mode == "numbers" && values.pagination.enable && !liveSearchEnabled
							? [
								// basics
								el( greyd.components.AdvancedPanelBody, { 
									title: __("classic pagination", 'greyd_hub'), 
									initialOpen: true, 
									// holdsChange: parts.background.type != "" 
								}, [
									// position
									el( 'span', {}, __('Position', 'greyd_hub') ),
									el( greyd.components.ButtonGroupControl, {
										value: values.pagination.position,
										options: [
											{ label: __("top", 'greyd_hub'), value: 'top' },
											{ label: __("bottom", 'greyd_hub'), value: 'bottom' },
										],
										onChange: function(value) { 
											paginationProps.setAttributes( { pagination: { ...values.pagination, position: value } } ); 
										},
									} ),
									// align
									el( 'span', {}, __("Alignment", 'greyd_hub') ),
									el( greyd.components.ButtonGroupControl, {
										value: values.pagination.greydStyles.justifyContent,
										options: [
											{ label: __("left", 'greyd_hub'), value: 'start' },
											{ label: __("center", 'greyd_hub'), value: 'center' },
											{ label: __("right", 'greyd_hub'), value: 'end' },
											{ label: __("spreaded", 'greyd_hub'), value: 'space-between' },
										],
										onChange: function(value) { 
											paginationProps.setAttributes( { pagination: {
												...values.pagination,
												greydStyles: {
													...values.pagination.greydStyles,
													justifyContent: value
												}
											} } ); 
										},
									} ),
									// overlap
									el( wp.components.ToggleControl, {
										label: __("Overlap content", 'greyd_hub'),
										checked: values.pagination.overlap,
										onChange: function(value) { 
											paginationProps.setAttributes( { pagination: { ...values.pagination, overlap: value } } ); 
										},
									} ),
								] ),
								// design numbers
								el( greyd.components.AdvancedPanelBody, { 
									title: __("Page numbers", 'greyd_hub'), 
									initialOpen: true, 
								}, [
									// type
									el( 'span', {}, __("Appearance", 'greyd_hub') ),
									el( greyd.components.ButtonGroupControl, {
										value: values.pagination.type,
										options: [
											{ label: __('✕', 'greyd_hub'), value: '' },
											{ label: __("Digits", 'greyd_hub'), value: 'text' },
											{ label: __('Icon', 'greyd_hub'), value: 'icon' },
											{ label: __("Upload image", 'greyd_hub'), value: 'image' },
										],
										onChange: function(value) { 
											paginationProps.setAttributes( { pagination: { ...values.pagination, type: value } } ); 
										},
									} ),
									(values.pagination.type == 'text') ? [
										// text
										el( wp.components.SelectControl, {
											value: values.pagination.text_type,
											options: [
												{ label: __('1 2 3 ...', 'greyd_hub'), value: '' },
												{ label: __('1. 2. 3. ...', 'greyd_hub'), value: '1.' },
												{ label: __('01 02 03 ...', 'greyd_hub'), value: '01' },
												{ label: __('01. 02. 03. ...', 'greyd_hub'), value: '01.' },
												{ label: __('A B C ...', 'greyd_hub'), value: 'A' },
												{ label: __('a b c ...', 'greyd_hub'), value: 'a' },
											],
											onChange: function(value) { 
												paginationProps.setAttributes( { pagination: { ...values.pagination, text_type: value } } ); 
											},
										} )
									] : '',
									(values.pagination.type == 'icon') ? [
										// icon
										el( wp.components.SelectControl, {
											value: values.pagination.icon_type,
											options: [
												{ label: __('Icons', 'greyd_hub'), value: 'icon' },
												{ label: __("Circles", 'greyd_hub'), value: 'dots' },
												{ label: __('Quadrate', 'greyd_hub'), value: 'blocks' },
											],
											onChange: function(value) { 
												paginationProps.setAttributes( { pagination: { ...values.pagination, icon_type: value } } ); 
											},
										} ),
										(values.pagination.icon_type == 'icon') ? [
											el( greyd.components.IconPicker, {
												label: __("Normal pagination", 'greyd_hub'),
												value: values.pagination.icon_normal,
												icons: greyd.data.icons,
												onChange: function(value) { 
													paginationProps.setAttributes( { pagination: { ...values.pagination, icon_normal: value } } ); 
												},
											} ),
											el( greyd.components.IconPicker, {
												label: __("Pagination active", 'greyd_hub'),
												value: values.pagination.icon_active,
												icons: greyd.data.icons,
												onChange: function(value) { 
													paginationProps.setAttributes( { pagination: { ...values.pagination, icon_active: value } } ); 
												},
											} ),
										] : '',
									] : '',
									(values.pagination.type == 'image') ? [
										// image
										el( wp.components.BaseControl, { }, [
											el( wp.blockEditor.MediaUploadCheck, { fallback: el( 'p', { className: "greyd-inspector-help" }, __("To edit the background image, you need permission to upload media.", 'greyd_hub') ) }, [
												// normal image
												el( 'div', {}, __("Image normal", 'greyd_hub') ),
												el( wp.blockEditor.MediaUpload, {
													allowedTypes: 'image/*',
													value: values.pagination.img_normal,
													onSelect: function(value) { paginationProps.setAttributes( { pagination: { ...values.pagination, img_normal: value.id } } ); },
													render: function(obj) {
														return el( wp.components.Button, { 
															className: values.pagination.img_normal == -1 ? 'editor-post-featured-image__toggle' : 'editor-post-featured-image__preview',
															onClick: obj.open 
														}, values.pagination.img_normal == -1 ? 
															__( "Select image", 'greyd_hub' ) : 
															el( 'img', { src: getImageUrl(values.pagination.img_normal) } ) 
														)
													},
												} ),
												values.pagination.img_normal !== -1 ? el( wp.components.Button, { 
													className: "is-link is-destructive",
													onClick: function() { paginationProps.setAttributes( { pagination: { ...values.pagination, img_normal: -1 } } ) },
												}, __( "Remove image", 'greyd_hub' ) ) : "",
												// active image
												el( 'div', { style: { marginTop: '8px' } }, __("Image active", 'greyd_hub') ),
												el( wp.blockEditor.MediaUpload, {
													allowedTypes: 'image/*',
													value: values.pagination.img_active,
													onSelect: function(value) { paginationProps.setAttributes( { pagination: { ...values.pagination, img_active: value.id } } ); },
													render: function(obj) {
														return el( wp.components.Button, { 
															className: values.pagination.img_active == -1 ? 'editor-post-featured-image__toggle' : 'editor-post-featured-image__preview',
															onClick: obj.open 
														}, values.pagination.img_active == -1 ? 
															__( "Select image", 'greyd_hub' ) :
															el( 'img', { src: getImageUrl(values.pagination.img_active) } ) 
														)
													},
												} ),
												values.pagination.img_active !== -1 ? el( wp.components.Button, { 
													className: "is-link is-destructive",
													onClick: function() { paginationProps.setAttributes( { pagination: { ...values.pagination, img_active: -1 } } ) },
												}, __( "Remove image", 'greyd_hub' ) ) : "",
											] ),
										] ),
									] : '',
								] ),
								// design arrows
								el( greyd.components.AdvancedPanelBody, { 
									title: __("Arrows", 'greyd_hub'), 
									initialOpen: true, 
								}, [
									// type
									el( 'span', {}, __("Type", 'greyd_hub') ),
									el( greyd.components.ButtonGroupControl, {
										value: values.pagination.arrows_type,
										options: [
											{ label: __('✕', 'greyd_hub'), value: '' },
											{ label: __('Icon', 'greyd_hub'), value: 'icon' },
											{ label: __("Upload image", 'greyd_hub'), value: 'image' },
										],
										onChange: function(value) { 
											paginationProps.setAttributes( { pagination: { ...values.pagination, arrows_type: value } } ); 
										},
									} ),
									(values.pagination.arrows_type == 'icon') ? [
										// icon
										el( greyd.components.IconPicker, {
											label: __("Previous-Icon", 'greyd_hub'),
											value: values.pagination.icon_previous,
											icons: greyd.data.icons,
											onChange: function(value) { 
												paginationProps.setAttributes( { pagination: { ...values.pagination, icon_previous: value } } ); 
											},
										} ),
										el( greyd.components.IconPicker, {
											label: __("Next-Icon", 'greyd_hub'),
											value: values.pagination.icon_next,
											icons: greyd.data.icons,
											onChange: function(value) { 
												paginationProps.setAttributes( { pagination: { ...values.pagination, icon_next: value } } ); 
											},
										} ),
									] : '',
									(values.pagination.arrows_type == 'image') ? [
										// image
										el( wp.components.BaseControl, { }, [
											el( wp.blockEditor.MediaUploadCheck, { fallback: el( 'p', { className: "greyd-inspector-help" }, __("To edit the background image, you need permission to upload media.", 'greyd_hub') ) }, [
												// previous image
												el( 'div', {}, __("Previous-Image", 'greyd_hub') ),
												el( wp.blockEditor.MediaUpload, {
													allowedTypes: 'image/*',
													value: values.pagination.img_previous,
													onSelect: function(value) { paginationProps.setAttributes( { pagination: { ...values.pagination, img_previous: value.id } } ); },
													render: function(obj) {
														return el( wp.components.Button, { 
															className: values.pagination.img_previous == -1 ? 'editor-post-featured-image__toggle' : 'editor-post-featured-image__preview',
															onClick: obj.open 
														}, values.pagination.img_previous == -1 ? 
															__( "Select image", 'greyd_hub' ) : 
															el( 'img', { src: getImageUrl(values.pagination.img_previous) } ) 
														)
													},
												} ),
												values.pagination.img_previous !== -1 ? el( wp.components.Button, { 
													className: "is-link is-destructive",
													onClick: function() { paginationProps.setAttributes( { pagination: { ...values.pagination, img_previous: -1 } } ) },
												}, __( "Remove image", 'greyd_hub' ) ) : "",
												// next image
												el( 'div', { style: { marginTop: '8px' } }, __("Next-Image", 'greyd_hub') ),
												el( wp.blockEditor.MediaUpload, {
													allowedTypes: 'image/*',
													value: values.pagination.img_next,
													onSelect: function(value) { paginationProps.setAttributes( { pagination: { ...values.pagination, img_next: value.id } } ); },
													render: function(obj) {
														return el( wp.components.Button, { 
															className: values.pagination.img_next == -1 ? 'editor-post-featured-image__toggle' : 'editor-post-featured-image__preview',
															onClick: obj.open 
														}, values.pagination.img_next == -1 ? 
															__( "Select image", 'greyd_hub' ) :
															el( 'img', { src: getImageUrl(values.pagination.img_next) } ) 
														)
													},
												} ),
												values.pagination.img_next !== -1 ? el( wp.components.Button, { 
													className: "is-link is-destructive",
													onClick: function() { paginationProps.setAttributes( { pagination: { ...values.pagination, img_next: -1 } } ) },
												}, __( "Remove image", 'greyd_hub' ) ) : "",
											] ),
										] ),
									] : '',
								] ),
								// styles
								// color + hover + active
								el( greyd.components.StylingControlPanel, {
									// className: ((values.pagination.type != '' && values.pagination.type != 'image') || values.pagination.arrows_type == 'icon') ? '' : 'hidden',
									title: __("Colors", 'greyd_hub'),
									initialOpen: false,
									supportsHover: true,
									supportsActive: true,
									holdsColors: [
										{ 
											color: (has(paginationProps.attributes, 'greydStyles.color')) ? paginationProps.attributes.greydStyles.color : '', 
											title: __("Symbol color", 'greyd_hub') 
										}
									],
									blockProps: paginationProps,
									controls: [ {
										className: 'single'+((values.pagination.type != '' && values.pagination.type != 'image') || values.pagination.arrows_type == 'icon' ? '' : ' hidden'),
										label: __("Symbol color", 'greyd_hub'),
										attribute: "color",
										control: greyd.components.ColorGradientPopupControl,
										mode: 'color'
									}, {
										label: __("Opacity", 'greyd_hub'),
										attribute: "opacity",
										control: greyd.components.RangeUnitControl,
										units: ['%'],
									} ]
								} ),
								// greydStyles + responsive
								el( greyd.components.StylingControlPanel, {
									title: __("Size", 'greyd_hub'),
									initialOpen: false,
									supportsResponsive: true,
									blockProps: paginationProps,
									controls: [ {
										label: __("Symbol size", 'greyd_hub'),
										attribute: "fontSize",
										control: greyd.components.RangeUnitControl,
										units: [ 'px', 'em' ],
										max: {
											px: 60,
											em: 3
										}
									} ]
								} ),
								el( greyd.components.StylingControlPanel, {
									title: __("Spaces", 'greyd_hub'),
									initialOpen: false,
									supportsResponsive: true,
									blockProps: paginationProps,
									controls: [ {
										label: __("Inside", 'greyd_hub'),
										attribute: "padding",
										control: greyd.components.DimensionControl,
										units: [ 'px', 'em' ],
									}, {
										label: __("in between", 'greyd_hub'),
										attribute: "gutter",
										control: greyd.components.RangeUnitControl,
										units: [ 'px', 'em' ],
										max: {
											px: 60,
											em: 3
										}
									} ]
								} ),
							]
							: []
						),

						// arrows
						...(
							mode == "arrows" && values.arrows.enable && !liveSearchEnabled
							? [
								// basics
								el( greyd.components.AdvancedPanelBody, { 
									title: __("Side arrows", 'greyd_hub'), 
									initialOpen: true, 
								}, [
									// position
									el( greyd.components.AdvancedLabel, { label: __("Alignment", 'greyd_hub') } ),
									el( greyd.components.ButtonGroupControl, {
										value: values.arrows.greydStyles.alignItems,
										options: [
											{ label: __("top", 'greyd_hub'), value: 'start' },
											{ label: __("center", 'greyd_hub'), value: 'center' },
											{ label: __("bottom", 'greyd_hub'), value: 'end' },
										],
										onChange: function(value) { 
											arrowProps.setAttributes( { arrows: {
												...values.arrows,
												greydStyles: {
													...values.arrows.greydStyles,
													alignItems: value
												}
											} } ); 
										},
									} ),
									// overlap
									el( wp.components.ToggleControl, {
										label: __("Overlap content", 'greyd_hub'),
										checked: values.arrows.overlap,
										onChange: function(value) { 
											arrowProps.setAttributes( { arrows: { ...values.arrows, overlap: value } } ); 
										},
									} ),
								] ),
								// design
								el( greyd.components.AdvancedPanelBody, { 
									title: __("Appearance", 'greyd_hub'), 
									initialOpen: true, 
								}, [
									// type
									el( greyd.components.AdvancedLabel, { label: __("Appearance", 'greyd_hub') } ),
									el( greyd.components.ButtonGroupControl, {
										value: values.arrows.type,
										options: [
											{ label: __('Icon', 'greyd_hub'), value: 'icon' },
											{ label: __("Upload image", 'greyd_hub'), value: 'image' },
										],
										onChange: function(value) { 
											console.log(value);
											arrowProps.setAttributes( { arrows: { ...values.arrows, type: value } } ); 
										},
									} ),
									(values.arrows.type == 'icon') ? [
										// icon
										el( greyd.components.IconPicker, {
											label: __("Previous-Icon", 'greyd_hub'),
											value: values.arrows.icon_previous,
											icons: greyd.data.icons,
											onChange: function(value) { 
												arrowProps.setAttributes( { arrows: { ...values.arrows, icon_previous: value } } ); 
											},
										} ),
										el( greyd.components.IconPicker, {
											label: __("Next-Icon", 'greyd_hub'),
											value: values.arrows.icon_next,
											icons: greyd.data.icons,
											onChange: function(value) { 
												arrowProps.setAttributes( { arrows: { ...values.arrows, icon_next: value } } ); 
											},
										} ),
									] : '',
									(values.arrows.type == 'image') ? [
										// image
										el( wp.components.BaseControl, { }, [
											el( wp.blockEditor.MediaUploadCheck, { fallback: el( 'p', { className: "greyd-inspector-help" }, __("To edit the background image, you need permission to upload media.", 'greyd_hub') ) }, [
												// previous image
												el( greyd.components.AdvancedLabel, { label: __("Previous-Image", 'greyd_hub') } ),
												el( wp.blockEditor.MediaUpload, {
													allowedTypes: 'image/*',
													value: values.arrows.img_previous,
													onSelect: function(value) { arrowProps.setAttributes( { arrows: { ...values.arrows, img_previous: value.id } } ); },
													render: function(obj) {
														return el( wp.components.Button, { 
															className: values.arrows.img_previous == -1 ? 'editor-post-featured-image__toggle' : 'editor-post-featured-image__preview',
															onClick: obj.open 
														}, values.arrows.img_previous == -1 ? 
															__( "Select image", 'greyd_hub' ) : 
															el( 'img', { src: getImageUrl(values.arrows.img_previous) } ) 
														)
													},
												} ),
												values.arrows.img_previous !== -1 ? el( wp.components.Button, { 
													className: "is-link is-destructive",
													onClick: function() { arrowProps.setAttributes( { arrows: { ...values.arrows, img_previous: -1 } } ) },
												}, __( "Remove image", 'greyd_hub' ) ) : "",
												// next image
												el( 'div', { style: { marginTop: '8px' } }, __("Next-Image", 'greyd_hub') ),
												el( wp.blockEditor.MediaUpload, {
													allowedTypes: 'image/*',
													value: values.arrows.img_next,
													onSelect: function(value) { arrowProps.setAttributes( { arrows: { ...values.arrows, img_next: value.id } } ); },
													render: function(obj) {
														return el( wp.components.Button, { 
															className: values.arrows.img_next == -1 ? 'editor-post-featured-image__toggle' : 'editor-post-featured-image__preview',
															onClick: obj.open 
														}, values.arrows.img_next == -1 ? 
															__( "Select image", 'greyd_hub' ) :
															el( 'img', { src: getImageUrl(values.arrows.img_next) } ) 
														)
													},
												} ),
												values.arrows.img_next !== -1 ? el( wp.components.Button, { 
													className: "is-link is-destructive",
													onClick: function() { arrowProps.setAttributes( { arrows: { ...values.arrows, img_next: -1 } } ) },
												}, __( "Remove image", 'greyd_hub' ) ) : "",
											] ),
										] ),
									] : '',
								] ),
								// styles
								// color + hover
								el( greyd.components.StylingControlPanel, {
									// className: (values.arrows.type != 'icon') ? 'hidden' : '',
									title: __("Colors", 'greyd_hub'),
									initialOpen: false,
									supportsHover: true,
									holdsColors: [
										{ 
											color: (has(arrowProps.attributes, 'greydStyles.color')) ? arrowProps.attributes.greydStyles.color : '', 
											title: __("Icon color", 'greyd_hub') 
										}
									],
									blockProps: arrowProps,
									controls: [ {
										className: 'single'+(values.arrows.type != 'icon' ? ' hidden' : ''),
										label: __("Icon color", 'greyd_hub'),
										attribute: "color",
										control: greyd.components.ColorGradientPopupControl,
										mode: 'color'
									}, {
										label: __("Background", 'greyd_hub'),
										attribute: "backgroundColor",
										control: greyd.components.ColorGradientPopupControl,
										mode: 'color'
									}, {
										label: __("Opacity", 'greyd_hub'),
										attribute: "opacity",
										control: greyd.components.RangeUnitControl,
										units: ['%'],
									} ]
								} ),
								// greydStyles + responsive
								el( greyd.components.StylingControlPanel, {
									title: __("Size", 'greyd_hub'),
									initialOpen: false,
									supportsResponsive: true,
									blockProps: arrowProps,
									controls: [ {
										label: __("Width", 'greyd_hub'),
										attribute: "fontSize",
										control: greyd.components.RangeUnitControl,
										units: [ 'px', 'em' ],
										max: {
											px: 100,
											em: 5
										}
									} ]
								} ),
								el( greyd.components.StylingControlPanel, {
									title: __("Spaces", 'greyd_hub'),
									initialOpen: false,
									supportsResponsive: true,
									blockProps: arrowProps,
									controls: [ {
										label: __("Inside", 'greyd_hub'),
										attribute: "padding",
										control: greyd.components.DimensionControl,
									} ]
								} ),
							]
							: []
						),

						// load more button
						...(
							mode == "loader"
							? [
								// basics
								el( greyd.components.AdvancedPanelBody, { 
									title: __("\"Load more\" button", 'greyd_hub'), 
									initialOpen: true,
								}, [
									el( wp.components.SelectControl, {
										label: __('Design', 'greyd_hub'),
										value: values.loader.style,
										onChange: (value) => loaderProps.setAttributes( { style: value } ),
										options: [
											{ value: '', label: __("primary button", 'greyd_hub') },
											{ value: 'button sec', label: __("secondary button", 'greyd_hub') },
											{ value: 'button trd', label: __("alternate button", 'greyd_hub') },
											{ value: 'link', label: __("primary link", 'greyd_hub') },
											{ value: 'link sec', label: __("secondary link", 'greyd_hub') },
										],
									} ),
									values.loader.style.indexOf('link') == -1 ? el( greyd.components.ButtonGroupControl, {
										label: __("Size", 'greyd_hub'),
										value: values.loader.size,
										onChange: (value) => loaderProps.setAttributes( { size: value } ),
										options: [
											{ label: __("small", 'greyd_hub'), value: 'small' },
											{ label: __("default", 'greyd_hub'), value: '' },
											{ label: __("big", 'greyd_hub'), value: 'big' },
										],
									} ) : null
								] ),
								el( greyd.components.StylingControlPanel, {
									title: __("Sizes & spaces", 'greyd_hub'),
									initialOpen: true,
									supportsResponsive: true,
									blockProps: loaderProps,
									controls: [
										{
											label: __("Alignment", 'greyd_hub'),
											attribute: "--align",
											control: greyd.components.ButtonGroupControl,
											options: [
												{ icon: greyd.tools.getCoreIcon('alignLeft'), value: 'left' },
												{ icon: greyd.tools.getCoreIcon('alignCenter'), value: '' },
												{ icon: greyd.tools.getCoreIcon('alignRight'), value: 'right' },
											],
										},
										{
											label: __("Space", 'greyd_hub'),
											attribute: "margin",
											control: greyd.components.DimensionControl,
											min: -300,
											max: 300,
										},
									]
								} ),
							]
							: []
						),
					] );
				};

			
				/**
				 * (2) PREVIEW
				 */

				// render filter preview
				const filterPreview = function(position) {
					if ( !values.filter.enable || values.filter.position !== position || parent?.attributes?.query?.inherit ) return null;

					var option = values.filter.empty != '' ? values.filter.empty : __("Select filter", 'greyd_hub');
					if (_.has(parent, 'attributes.query.taxQuery') && !_.isEmpty(parent.attributes.query.taxQuery)) {
						// get first selected filter as dummy option to display
						// console.log(parent.attributes.query);
						var pt = parent.attributes.query.postType;
						var taxes = Object.keys(parent.attributes.query.taxQuery);
						var terms = parent.attributes.query.taxQuery[taxes[0]];
						greyd.data.all_taxes[pt].forEach(function(tax) {
							if (tax.slug == taxes[0]) {
								tax.values.forEach(function(term) {
									if (term.id == terms[0]) {
										if (values.filter.showTaxTitle) option = tax.title+': '+term.title;
										else option = term.title;
									}
								})
							}
						});
					}

					return el( 'div', {
						className: values.filter.greydClass+' '+values.filter.position+' filter'+(mode == "filter" ? ' active' : ''), 
						style: { display: "flex", width: "100%", justifyContent: values.filter.align },
						onClick: () => {
							// console.log("select filter");
							setMode("filter");
							wp.data.dispatch('core/block-editor').selectBlock(props.clientId);
						}
					}, [
						el( greyd.components.RenderPreviewStyles, {
							selector: values.filter.greydClass,
							styles: {
								"": values.filter.greydStyles
							}
						} ),
						el( greyd.components.RenderPreviewStyles, {
							selector: values.filter.greydClass+" select",
							styles: {
								"": values.filter.greydStyles,
								" ": (values.filter.custom) ? values.filter.customStyles : {}
							},
							important: true
						} ),
						el( 'select', {
							className: values.filter.inputStyle == 'sec' ? 'is-style-sec' : '',
							style: { 
								// paddingRight: "30px", 
								width: values.filter.width, 
								margin: values.filter.margin 
							}
						}, [
							el( 'option', { value: '' }, option ),
						] )
					] );
				}
				// render sorting preview
				const sortingPreview = function(position) {
					if ( !values.sorting.enable || values.sorting.position !== position ) return null;

					return el( 'div', {
						className: values.sorting.greydClass+' '+values.sorting.position+' sorting'+(mode == "sorting" ? ' active' : ''), 
						style: { display: "flex", width: "100%", justifyContent: values.sorting.align },
						onClick: () => {
							// console.log("select sorting");
							setMode("sorting");
							wp.data.dispatch('core/block-editor').selectBlock(props.clientId);
						}
					}, [
						el( greyd.components.RenderPreviewStyles, {
							selector: values.sorting.greydClass,
							styles: {
								"": values.sorting.greydStyles
							}
						} ),
						el( greyd.components.RenderPreviewStyles, {
							selector: values.sorting.greydClass+" select",
							styles: {
								"": values.sorting.greydStyles,
								" ": (values.sorting.custom) ? values.sorting.customStyles : {}
							},
							important: true
						} ),
						el( 'select', {
							className: values.sorting.inputStyle == 'sec' ? 'is-style-sec' : '',
							style: { 
								// paddingRight: "30px", 
								width: values.sorting.width, 
								margin: values.sorting.margin 
							}
						}, [
							Object.keys(sortingLabels).map( key => {
								// console.log(key);
								// console.log(_.some(values.sorting.options[key], _.isEmpty));
								return el( 'option', { value: key }, _.some(values.sorting.options[key], _.isEmpty) ? values.sorting.options[key] : sortingLabels[key] );
							} )
						] )
					] );
				}
				// render pagination preview
				const paginationPreview = function(position) {

					if ( liveSearchEnabled || !values.pagination.enable || values.pagination.position !== position ) return null;

					const makeArrow = (direction) => {
						if ( values.pagination.arrows_type === 'icon' ) {
							return el( 'a', { className: values.pagination['icon_'+direction] } );
						}
						else if ( values.pagination.arrows_type === 'image' ) {
							return el( 'a', {}, el( 'img', {
								src: getImageUrl(values.pagination['img_'+direction])
							} ) );
						}
						return null;
					}

					const makeNumbers = () => {

						if (values.pagination.type == '') return null;

						// get number of pages
						var pages = 3;
						if (has(parent, 'attributes.query')) {
							// console.log(parent.attributes.query);
							if (block_posts && posts_max > 0) {
								// pages = Math.ceil(posts_max/block_posts.length);
								// console.log( pages, posts_max, block_posts.length )
								if (parent.attributes.query.pages != 0) {
									pages = parseInt(parent.attributes.query.pages);
								}
							}
						}

						var numbers = [];
						if (values.pagination.type == 'text') {
							const makeNumberStyle = function(number, numbers_style) {
								if (numbers_style === 'A' || numbers_style === 'a') {
									var result = '';
									while (number > 0) {
										var t = (number - 1) % 26;
										result = String.fromCharCode(65 + t) + result;
										number = (number - t)/26 | 0;
									}
									if (numbers_style == 'a') result = result.toLowerCase();
								}
								else {
									var result = number.toString();
									if ((numbers_style === '01' || numbers_style === '01.') && result < 10) result = '0'+result;
									if (numbers_style === '1.' || numbers_style === '01.') result += '.';
								}
								return result;
							}
							for (var i=1; i<=pages; i++) {
								numbers[i] = el( "a", { className: (i==1 ? 'active' : undefined) }, makeNumberStyle(i, values.pagination.text_type) );
							}
						}
						else if (values.pagination.type == 'icon') {
							var number = "";
							if (values.pagination.icon_type == 'dots') number = "●"; 
							else if (values.pagination.icon_type == 'blocks') number = "■"; 
							for (var i=1; i<=pages; i++) {
								var classes = i==1 ? 'active' : '';
								if (values.pagination.icon_type == 'icon') {
									classes += ' '+(i==1 ? values.pagination.icon_active : values.pagination.icon_normal);
								}
								numbers[i] = el( "a", { className: classes }, number );
							}
						}
						else if (values.pagination.type == 'image') {
							const img = { active: getImageUrl(values.pagination.img_active), normal: getImageUrl(values.pagination.img_normal) }
							for (var i=1; i<=pages; i++) {
								numbers[i] = el( "a", { className: (i==1 ? 'active' : undefined) }, el( 'img', { src: i==1 ? img.active : img.normal } ) );
							}
						}

						return el( 'span', {}, numbers );
					}

					return el( 'div', {
						className: values.pagination.greydClass+' '+'pgn numbers '+position+(mode == "numbers" ? ' active' : '')+(values.pagination.overlap ? ' overlap' : ''),
						onClick: function() {
							// console.log("select numbers");
							setMode("numbers");
							wp.data.dispatch('core/block-editor').selectBlock(props.clientId);
						}
					}, [
						// styles
						el( greyd.components.RenderPreviewStyles, {
							selector: values.pagination.greydClass+".pgn.numbers",
							styles: { 
								"": {
									...omit(values.pagination.greydStyles, 'color', 'opacity', 'active', 'hover', 'gutter'),
									'--pgn-numbers-gutter': _.get(values.pagination.greydStyles, 'gutter')
								},
							}
						} ),
						el( greyd.components.RenderPreviewStyles, {
							selector: values.pagination.greydClass+".pgn.numbers a",
							styles: { 
								"": pick(values.pagination.greydStyles, 'color', 'opacity'),
								".active": pick(values.pagination.greydStyles.active, 'color', 'opacity'),
								":hover, ._hover": pick(values.pagination.greydStyles, 'hover')
							}
						} ),
						makeArrow('previous'),
						makeNumbers(),
						makeArrow('next')
					] );
				};
				// render arrow preview
				const arrowPreview = function(position) {

					if ( liveSearchEnabled || !values.arrows.enable ) return null;

					const direction = position === 'left' ? 'previous' : 'next';
					var linkStyles = {};
					var greydStyles = { ...values.arrows.greydStyles };

					/**
					 * Fix color inhertiation of custom pagination arrow colors.
					 * 
					 * @since 1.3.3
					 */
					if ( has(greydStyles, 'color') ) {
						linkStyles.color = greydStyles.color;
						greydStyles.color = null;
					}
					if ( has(greydStyles, 'backgroundColor') ) {
						linkStyles.backgroundColor = greydStyles.backgroundColor;
						greydStyles.backgroundColor = null;
					}
					if ( has(greydStyles, 'hover') ) {
						linkStyles.hover = greydStyles.hover;
						greydStyles.hover = null;
					}

					return el( 'div', { 
						className: values.arrows.greydClass+' pgn arrows '+position+(mode == "arrows" ? ' active' : '')+(values.arrows.overlap ? ' overlap' : ''),
						onClick: () => {
							// console.log("select arrows");
							setMode("arrows");
							wp.data.dispatch('core/block-editor').selectBlock(props.clientId);
						}
					}, [
						el( greyd.components.RenderPreviewStyles, {
							selector: values.arrows.greydClass+".pgn.arrows",
							styles: { "": greydStyles }
						} ),
						el( greyd.components.RenderPreviewStyles, {
							selector: values.arrows.greydClass+".pgn.arrows > a",
							styles: { "": linkStyles }
						} ),
						(
							values.arrows.type == 'icon' ? 
							el( "a", { className: values.arrows[ 'icon_'+direction ] } ) :
							el( 'img', { src: getImageUrl(values.arrows[ 'img_'+direction ] ) } )
						)
					] );
				}
				// live search load more button preview
				const loaderPreview = () => {
					if ( ! liveSearchEnabled ) return null;

					var buttonClass = 'button';
					if ( !_.isEmpty(values.loader.style) ) {
						buttonClass = values.loader.style;
					}
					if ( !_.isEmpty(values.loader.size) ) {
						buttonClass += ' ' + values.loader.size;
					}
					buttonClass = 'load_more ' + buttonClass;

					return el( 'div', {
						className: 'load_more_wrapper ' + values.loader.greydClass,
						onClick: () => {
							setMode("loader");
							wp.data.dispatch('core/block-editor').selectBlock(props.clientId);
						}
					}, [
						el( greyd.components.RenderPreviewStyles, {
							selector: values.loader.greydClass,
							styles: { "": values.loader.greydStyles }
						} ),
						el( 'div', {
							className: buttonClass
						}, __("load more", "greyd_hub") )
					] );
				};

				// get posts for modified preview
				var [ activeBlockContext, setActiveBlockContext ] = wp.element.useState();
				// get all posts first
				var { posts, blocks } = wp.data.useSelect(select => {
					// get current parent state
					parent = getParent();
					if (!has(parent, 'attributes.query')) return false;
					// console.log(parent.attributes.query);
					// console.log(props);
					
					// original query vars
					var parentQuery = parent.attributes.query;
					var postType = (parentQuery.postType) ? parentQuery.postType : 'post';
					var query = {
						offset: parentQuery.offset,
						order: parentQuery.order,
						orderby: parentQuery.orderBy,
					};
					if (parentQuery.taxQuery?.length) query.taxQuery = parentQuery.taxQuery; 
					if (parentQuery.perPage) query.per_page = -1; // get all posts
					if (parentQuery.author) query.author = parentQuery.author; 
					if (parentQuery.search) query.search = parentQuery.search; 
					if (parentQuery.exclude?.length) query.exclude = parentQuery.exclude; 
					if (parentQuery.parents?.length) query.parent = parentQuery.parents; 
					if (parentQuery.sticky) query.sticky = parentQuery.sticky === 'only';
					// console.log("fetch posts");
					
					return {
						posts: select("core").getEntityRecords('postType', postType, query),
						blocks: select("core/block-editor").getBlocks(props.clientId)
					}
				}, [ props, parent ]);
				// then filter
				var { block_posts, posts_max } = wp.element.useMemo(() => {
					var parentQuery = parent?.attributes?.query;
					var postType = (parentQuery?.postType) ? parentQuery.postType : 'post';
					/**
					 * @deprecated WordPress 5.9
					 */
					// extended query vars
					// console.log(posts);
					// if (posts && !parentQuery.taxQuery) {
					// 	for (var i=0; i<greyd.data.post_types.length; i++) {
					// 		// console.log(greyd.data.post_types[i]);
					// 		if (greyd.data.post_types[i].slug == postType) {
					// 			var pt = greyd.data.post_types[i];
					// 			if (has(pt, "taxes") && pt.taxes.length > 0) {
					// 				// get categories, tags and customtax
					// 				for (var j=0; j<pt.taxes.length; j++) {
					// 					var slug = pt.taxes[j].slug;
					// 					if (parentQuery[slug+'Ids']?.length) {
					// 						var terms = parentQuery[slug+'Ids'];
					// 						var new_posts = [];
					// 						for (var k=0; k<terms.length; k++) {
					// 							for (var p=0; p<posts.length; p++) {
					// 								if (has(posts[p], slug) && posts[p][slug].indexOf(terms[k]) > -1) {
					// 									new_posts.push(posts[p]);
					// 								}
					// 							}
					// 						}
					// 						// console.log(new_posts);
					// 						posts = clone(new_posts);
					// 					}
					// 				}
					// 			}
					// 			break;
					// 		}
					// 	}
					// }
					// don't set fixed value for post-per-page - needs to be variable for responsive preview
					var perpage = parentQuery && parentQuery.perPage ? parseInt(parentQuery.perPage) : (posts ? posts.length : false);
					return {
						block_posts: posts?.map( ( post ) => ( {
							postType: post.type,
							postId: post.id,
						} ) ).slice(0, perpage*2),
						posts_max: posts ? posts.length : 0
					};
				}, [ posts, parent ]);
				// console.log(block_posts, posts_max);

				// 
				// subscriptions
				var [subscribe, setSubscribe ] = wp.element.useState( { parent: false, viewport: false } );
				// subscribe to viewport change
				var viewport = greyd.tools.getDeviceType();
				if ( !subscribe.viewport ) {
					setSubscribe( { ...subscribe, viewport: {
						unsubscribe: wp.data.subscribe(() => {
							// compare values
							var newViewport = greyd.tools.getDeviceType();
							if (viewport !== newViewport) {
								// console.log("viewport changed to "+newViewport);
								// set new viewport
								viewport = newViewport;
								// reset subscription
								if (subscribe.viewport) subscribe.viewport.unsubscribe();
								setSubscribe( { ...subscribe, viewport: false } );
							}
						})
					} } );
				}
				// subscribe to parent change
				if ( parent && !subscribe.parent ) {
					setSubscribe( { ...subscribe, parent: {
						unsubscribe: wp.data.subscribe(() => {
							// compare values
							var newParent = getParent();
							if (!newParent || JSON.stringify(parent.attributes) !== JSON.stringify(newParent.attributes)) {
								// console.log("parent atts changed");
								// set new parent
								parent = newParent;
								// reset subscription (and trigger redraw with new parent atts)
								if (subscribe.parent) subscribe.parent.unsubscribe();
								setSubscribe( { ...subscribe, parent: false } );
							}
						})
					} } );
				}

				// props
				// console.log(props);
				var classNames = "";
				if ( parent ) {
					// console.log(parent.attributes);
					var layoutType = parent?.attributes?.displayLayout?.type;
					var columns = parent?.attributes?.displayLayout?.columns;
					if ( layoutType && layoutType === 'flex' && columns && columns > 0 ) {
						classNames = 'is-flex-container columns-'+columns;
					}
				}
				const blockProps = wp.blockEditor.useBlockProps( { className: classNames } );
				const innerBlocksProps = wp.blockEditor.useInnerBlocksProps( { className: 'wp-block-post' } );
				const blockPreviewProps = wp.blockEditor.__experimentalUseBlockPreview( { blocks, props: { className: 'wp-block-post' } } );

				// render post preview
				const makePreview = function(post) {
					// console.log("make preview");
					return el( 'li', { 
						...blockPreviewProps,
						tabIndex: 0,
						role: 'button',
						onClick: function() {
							setActiveBlockContext( post.postId );
						},
						onKeyPress: function() {
							setActiveBlockContext( post.postId );
						},
						style: { display: post.postId === (activeBlockContext || block_posts[0].postId) ? 'none' : undefined }
					} );
				};

				// render modified posts preview
				const makePosts = function() {
					if (parent && typeof block_posts !== 'undefined' && block_posts ) {
						// console.log(posts);
						// console.log(block_posts);
						// console.log('re-render new');
						
						// get value for responsive posts-per-page preview
						const getPerPage = () => {
							if ( posts && parent ) {
								// get from parent query
								const parentQuery = parent.attributes.query;
								let items = _.has(parentQuery, 'perPage') ? parseInt(parentQuery.perPage) : (block_posts ? block_posts.length : 0);
								// console.log(viewport);
								// console.log(values.perPage.customStyles);
								
								if (viewport == "Tablet" && _.has(parent.attributes, "displayLayout.responsive.md.items")) {
									items = parseInt(parent.attributes.displayLayout.responsive.md.items);
								}
								else if (viewport == "Mobile" && _.has(parent.attributes, "displayLayout.responsive.sm.items")) {
									items = parseInt(parent.attributes.displayLayout.responsive.sm.items);
								}
								return items;
							}
							return 0;
						}

						// set the responsive posts-per-page value to slice the block_posts array
						const perPage = getPerPage();
						// console.log(perPage);

						if (
							!block_posts.length
							|| block_posts.length == 0
							|| perPage == 0
						) {
							return el( 'p', { ...blockProps }, __( "No posts found.", 'greyd_hub' ) );
						}
						return el( 'ul', { ...blockProps },
							block_posts
							.slice( 0, perPage )
							.map( (post) => ( 
								el( wp.blockEditor.BlockContextProvider, {
									value: post.postId,
									children:  [
										( post.postId === (activeBlockContext || block_posts[0].postId) ) ? 
										el( 'li', { ...innerBlocksProps } ) : null, 
										makePreview( post )
									] 
								} ) 
							) )
						);
					}
					// console.log('re-render original');
					// return el( BlockEdit, props );
					return el( wp.components.Spinner, { ...blockProps } );
				}

				// render block with advanced featues
				return el( wp.element.Fragment, { }, [
					// render new preview
					el( 'div', { 
						className: "greyd-posts-slider"+(props.isSelected ? " hover" : ''),
					}, [
						// perPagePreview( 'top' ),
						filterPreview( 'top' ),
						sortingPreview( 'top' ),
						paginationPreview('top'),
						arrowPreview( 'left' ),
						makePosts(),
						arrowPreview( 'right' ),
						paginationPreview('bottom'),
						sortingPreview( 'bottom' ),
						filterPreview( 'bottom' ),
						// perPagePreview( 'bottom' ),
						loaderPreview(),
					] ),
					// sidebar
					makeInspectorControls(),
				] );
			}

			// return original block
			return el( BlockEdit, props );
		};

	}, 'editBlockHook' );

	wp.hooks.addFilter( 
		'editor.BlockEdit', 
		'greyd/hook/query/edit', 
		editBlockHook 
	);


} )( 
	window.wp
);