From eb67549656fb6528fcddd3c17b698589d361895f Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 27 Sep 2018 09:46:46 -0400 Subject: [PATCH 001/107] Initial commit of directories and placeholder blocks. --- client/gutenberg/extensions/map/README.md | 6 ++ client/gutenberg/extensions/map/config.js | 33 +++++++++ client/gutenberg/extensions/map/editor.js | 72 +++++++++++++++++++ client/gutenberg/extensions/map/editor.scss | 1 + .../gutenberg/extensions/map/map-component.js | 32 +++++++++ client/gutenberg/extensions/map/style.scss | 1 + client/gutenberg/extensions/map/view.js | 6 ++ .../gutenberg/extensions/navigation/README.md | 1 + .../gutenberg/extensions/navigation/config.js | 14 ++++ .../gutenberg/extensions/navigation/editor.js | 59 +++++++++++++++ .../extensions/navigation/editor.scss | 4 ++ .../extensions/navigation/navigation.js | 34 +++++++++ .../extensions/navigation/style.scss | 11 +++ .../gutenberg/extensions/navigation/view.js | 6 ++ client/gutenberg/extensions/plugins/README.md | 19 +++++ .../extensions/plugins/atavist/README.md | 1 + .../extensions/plugins/atavist/plugin.php | 49 +++++++++++++ .../extensions/presets/atavist/editor.js | 6 ++ .../extensions/presets/atavist/view.js | 37 ++++++++++ client/gutenberg/extensions/shared/README.md | 1 + .../shared/atavist/frontend-management.js | 68 ++++++++++++++++++ .../subcomponents/AtavistSearch/index.js | 61 ++++++++++++++++ .../subcomponents/AtavistSearch/style.scss | 46 ++++++++++++ 23 files changed, 568 insertions(+) create mode 100644 client/gutenberg/extensions/map/README.md create mode 100644 client/gutenberg/extensions/map/config.js create mode 100644 client/gutenberg/extensions/map/editor.js create mode 100644 client/gutenberg/extensions/map/editor.scss create mode 100644 client/gutenberg/extensions/map/map-component.js create mode 100644 client/gutenberg/extensions/map/style.scss create mode 100644 client/gutenberg/extensions/map/view.js create mode 100644 client/gutenberg/extensions/navigation/README.md create mode 100644 client/gutenberg/extensions/navigation/config.js create mode 100644 client/gutenberg/extensions/navigation/editor.js create mode 100644 client/gutenberg/extensions/navigation/editor.scss create mode 100644 client/gutenberg/extensions/navigation/navigation.js create mode 100644 client/gutenberg/extensions/navigation/style.scss create mode 100644 client/gutenberg/extensions/navigation/view.js create mode 100644 client/gutenberg/extensions/plugins/README.md create mode 100644 client/gutenberg/extensions/plugins/atavist/README.md create mode 100644 client/gutenberg/extensions/plugins/atavist/plugin.php create mode 100644 client/gutenberg/extensions/presets/atavist/editor.js create mode 100644 client/gutenberg/extensions/presets/atavist/view.js create mode 100644 client/gutenberg/extensions/shared/README.md create mode 100644 client/gutenberg/extensions/shared/atavist/frontend-management.js create mode 100644 client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/index.js create mode 100644 client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/style.scss diff --git a/client/gutenberg/extensions/map/README.md b/client/gutenberg/extensions/map/README.md new file mode 100644 index 00000000000000..c313aa798899da --- /dev/null +++ b/client/gutenberg/extensions/map/README.md @@ -0,0 +1,6 @@ +This block will be an adaptation of the Atavist Map block, which renders a map using [Google Maps API](https://cloud.google.com/maps-platform/). Editors will be able to control: + +- Locations on the map, with optional title and description +- Zoom level +- Style (e.g. Terrain, Satellite) +- Marker color diff --git a/client/gutenberg/extensions/map/config.js b/client/gutenberg/extensions/map/config.js new file mode 100644 index 00000000000000..6fa9e2ed19bfba --- /dev/null +++ b/client/gutenberg/extensions/map/config.js @@ -0,0 +1,33 @@ +const config = {} + +config.name = 'atavist/map'; +config.title = 'Map'; +config.icon = ; +config.category = 'common'; +config.keywords = [ 'Map', 'Atavist' ]; +config.attributes = { + map_style: { + type: 'string', + default: 'default' + } +}; +config.baseClasses = [ + 'atavist-block', + 'atavist-simple-map' +]; +config.map_styleOptions = [ + { + value: 'default', + label: 'Basic' + }, + { + value: 'satellite', + label: 'Satellite' + }, + { + value: 'terrain', + label: 'Terrain' + } +]; + +export default config; diff --git a/client/gutenberg/extensions/map/editor.js b/client/gutenberg/extensions/map/editor.js new file mode 100644 index 00000000000000..f7adcc1df0171b --- /dev/null +++ b/client/gutenberg/extensions/map/editor.js @@ -0,0 +1,72 @@ +/** + * Wordpress dependencies + */ + +import { __ } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; +import { SelectControl } from '@wordpress/components'; +import { InspectorControls } from '@wordpress/editor'; +import { Fragment } from '@wordpress/element'; + +/** + * External dependencies + */ + +import classnames from 'classnames'; + + /** + * Internal dependencies + */ + +import './style.scss'; +import './editor.scss'; +import MapComponent from './map-component.js'; +import config from './config.js'; + +const { name, title, icon, category, keywords, attributes, map_styleOptions, baseClasses } = config; +registerBlockType( name, { + title: __( title ), + icon: icon, + category: category, + keywords: keywords.map( keyword => __( keyword ) ), + attributes: attributes, + edit: function( { attributes, setAttributes, className } ) { + const { map_style } = attributes; + const classes = classnames( + baseClasses, + className + ); + const inspectorControls = ( + + { setAttributes( { map_style: value } ) } } + options={ map_styleOptions } + /> + + ); + return ( + + { inspectorControls } +
+ +
+
+ ); + }, + save: function( { attributes, className } ) { + const { map_style } = attributes; + const classes = classnames( + config.baseClasses, + className + ); + return ( +
+ ); + } +} ); diff --git a/client/gutenberg/extensions/map/editor.scss b/client/gutenberg/extensions/map/editor.scss new file mode 100644 index 00000000000000..2046f90522daaf --- /dev/null +++ b/client/gutenberg/extensions/map/editor.scss @@ -0,0 +1 @@ +.wp-block-atavist-map {} diff --git a/client/gutenberg/extensions/map/map-component.js b/client/gutenberg/extensions/map/map-component.js new file mode 100644 index 00000000000000..1c2f14c408a078 --- /dev/null +++ b/client/gutenberg/extensions/map/map-component.js @@ -0,0 +1,32 @@ +/** @format */ + +/** + * Wordpress dependencies + */ + +import { Component } from '@wordpress/element'; + +/** + * External dependencies + */ + +/** + * Internal dependencies + */ + +import config from './config.js'; + +export class MapComponent extends Component { + + render() { + const { map_style } = this.props; + return

Map, with style: { map_style }

; + } + +} + +MapComponent.defaultProps = { + map_style: null +} + +export default MapComponent; diff --git a/client/gutenberg/extensions/map/style.scss b/client/gutenberg/extensions/map/style.scss new file mode 100644 index 00000000000000..2046f90522daaf --- /dev/null +++ b/client/gutenberg/extensions/map/style.scss @@ -0,0 +1 @@ +.wp-block-atavist-map {} diff --git a/client/gutenberg/extensions/map/view.js b/client/gutenberg/extensions/map/view.js new file mode 100644 index 00000000000000..7dd4fedccf05ec --- /dev/null +++ b/client/gutenberg/extensions/map/view.js @@ -0,0 +1,6 @@ +/** @format */ + +/** + * Internal dependencies + */ +import './style.scss'; diff --git a/client/gutenberg/extensions/navigation/README.md b/client/gutenberg/extensions/navigation/README.md new file mode 100644 index 00000000000000..320eb3c99e5ff0 --- /dev/null +++ b/client/gutenberg/extensions/navigation/README.md @@ -0,0 +1 @@ +This block will be an adaptation of an Atavist Navigation Type, which is a wrapper around the contents of an article/story/post/page. Navigation Types are responsible for rendering global elements such as headers, footers, and tables of contents. diff --git a/client/gutenberg/extensions/navigation/config.js b/client/gutenberg/extensions/navigation/config.js new file mode 100644 index 00000000000000..db7f9e0ce65baf --- /dev/null +++ b/client/gutenberg/extensions/navigation/config.js @@ -0,0 +1,14 @@ +const config = {} + +config.name = 'atavist/navigation'; +config.title = 'Navigation'; +config.icon = ; +config.category = 'layout'; +config.keywords = [ 'Navigation', 'Atavist' ]; +config.attributes = {}; +config.baseClasses = [ + 'nav-wrapper', + 'navigation-None' +]; + +export default config; diff --git a/client/gutenberg/extensions/navigation/editor.js b/client/gutenberg/extensions/navigation/editor.js new file mode 100644 index 00000000000000..6bbd0b9b00d54c --- /dev/null +++ b/client/gutenberg/extensions/navigation/editor.js @@ -0,0 +1,59 @@ +/** + * Wordpress dependencies + */ + +import { __ } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; +import { InnerBlocks } from '@wordpress/editor'; + +/** + * External dependencies + */ + +import classnames from 'classnames'; + + /** + * Internal dependencies + */ + +import './style.scss'; +import './editor.scss'; +import Navigation from './navigation.js'; +import config from './config.js'; + +const { name, title, icon, category, keywords, attributes, baseClasses } = config; +registerBlockType( name, { + title: __( title ), + icon: icon, + category: category, + keywords: keywords.map( keyword => __( keyword ) ), + attributes: attributes, + edit: function( { attributes, className } ) { + const classes = classnames( + baseClasses, + className + ); + return ( +
+ +
+ +
+
+
+ ); + }, + save: function( { attributes, className } ) { + const classes = classnames( + config.baseClasses, + className + ); + return ( +
+
+ +
+
+ ); + } +} ); diff --git a/client/gutenberg/extensions/navigation/editor.scss b/client/gutenberg/extensions/navigation/editor.scss new file mode 100644 index 00000000000000..07c1dac151c5eb --- /dev/null +++ b/client/gutenberg/extensions/navigation/editor.scss @@ -0,0 +1,4 @@ +.wp-block-atavist-navigation { + border: 1px solid gray; + padding: 1rem; +} diff --git a/client/gutenberg/extensions/navigation/navigation.js b/client/gutenberg/extensions/navigation/navigation.js new file mode 100644 index 00000000000000..5467ae7d2a686a --- /dev/null +++ b/client/gutenberg/extensions/navigation/navigation.js @@ -0,0 +1,34 @@ +/** @format */ + +/** + * Wordpress dependencies + */ + +import { Component, Fragment } from '@wordpress/element'; + +/** + * External dependencies + */ + +/** + * Internal dependencies + */ + +import config from './config.js'; + +export class Navigation extends Component { + + render() { + const { children } = this.props; + return ( + +
Placeholder Header
+ { children } +
Placeholder Footer
+
+ ); + } + +} + +export default Navigation; diff --git a/client/gutenberg/extensions/navigation/style.scss b/client/gutenberg/extensions/navigation/style.scss new file mode 100644 index 00000000000000..c7ff20f0b2c2b3 --- /dev/null +++ b/client/gutenberg/extensions/navigation/style.scss @@ -0,0 +1,11 @@ +.wp-block-atavist-navigation { + header, footer { + background: black; + color: gray; + padding: 1rem; + text-align: center; + } + article { + padding: 1rem; + } +} diff --git a/client/gutenberg/extensions/navigation/view.js b/client/gutenberg/extensions/navigation/view.js new file mode 100644 index 00000000000000..7dd4fedccf05ec --- /dev/null +++ b/client/gutenberg/extensions/navigation/view.js @@ -0,0 +1,6 @@ +/** @format */ + +/** + * Internal dependencies + */ +import './style.scss'; diff --git a/client/gutenberg/extensions/plugins/README.md b/client/gutenberg/extensions/plugins/README.md new file mode 100644 index 00000000000000..32e0df39ba4cff --- /dev/null +++ b/client/gutenberg/extensions/plugins/README.md @@ -0,0 +1,19 @@ +The plugins directory is for Gutenberg blocks being developed in the `wp-calypso` repo using the Gutenberg SDK. Plugin developers create a directory for each plugin containing the PHP file(s). The SDK should target a `build` directory within the plugin directory. + +Example SDK usage: + +`npm run sdk -- gutenberg client/gutenberg/extensions/presets/my-preset -output-dir=client/gutenberg/extensions/plugins/my-plugin/build -w` + +Example directory structure: + +└───plugins + └───my-plugin + └───plugin.php + └───build + ├───editor.css + ├───editor.js + ├───editor.rtl.css + ├───view.cc + ├───view.js + └───view.rtl.css + diff --git a/client/gutenberg/extensions/plugins/atavist/README.md b/client/gutenberg/extensions/plugins/atavist/README.md new file mode 100644 index 00000000000000..a560af98cb3c0d --- /dev/null +++ b/client/gutenberg/extensions/plugins/atavist/README.md @@ -0,0 +1 @@ +The Atavist plugin is a container for all Gutenberg blocks created from default Atavist blocks, title designs, and navigation types. diff --git a/client/gutenberg/extensions/plugins/atavist/plugin.php b/client/gutenberg/extensions/plugins/atavist/plugin.php new file mode 100644 index 00000000000000..095939f7dbcf00 --- /dev/null +++ b/client/gutenberg/extensions/plugins/atavist/plugin.php @@ -0,0 +1,49 @@ + WP migration. + * Author: rabberson + * Version: 1.0.0 + * License: GPL2+ + * License URI: http://www.gnu.org/licenses/gpl-2.0.txt + * + * @package CGB + */ +// Exit if accessed directly. +if ( ! defined( 'ABSPATH' ) ) { + exit; +} +function atavist_block_assets() { + // Styles. + wp_enqueue_style( + 'atavist_view-css', + plugins_url( 'build/view.css', __FILE__ ), + array( 'wp-blocks' ), + filemtime( plugin_dir_path( __FILE__ ) . 'build/view.css' ) + ); + if ( ! is_admin() ) { + wp_enqueue_script( + 'atavist_view-js', + plugins_url( 'build/view.js', __FILE__ ), + array( 'wp-blocks', 'jquery' ), + filemtime( plugin_dir_path( __FILE__ ) . 'build/view.js' ) + ); + } +} +add_action( 'enqueue_block_assets', 'atavist_block_assets' ); + +function atavist_editor_assets() { + wp_enqueue_script( + 'atavist_editor-js', + plugins_url( 'build/editor.js', __FILE__ ), + array( 'wp-blocks', 'wp-i18n', 'wp-element' ), + filemtime( plugin_dir_path( __FILE__ ) . 'build/editor.js' ) + ); + wp_enqueue_style( + 'atavist_editor-css', // Handle. + plugins_url( 'build/editor.css', __FILE__ ), + array( 'wp-edit-blocks' ), + filemtime( plugin_dir_path( __FILE__ ) . 'build/editor.css' ) + ); +} +add_action( 'enqueue_block_editor_assets', 'atavist_editor_assets' ); diff --git a/client/gutenberg/extensions/presets/atavist/editor.js b/client/gutenberg/extensions/presets/atavist/editor.js new file mode 100644 index 00000000000000..335d098b108acb --- /dev/null +++ b/client/gutenberg/extensions/presets/atavist/editor.js @@ -0,0 +1,6 @@ +/** + * Internal dependencies + */ + +import 'gutenberg/extensions/map/editor'; +import 'gutenberg/extensions/navigation/editor'; diff --git a/client/gutenberg/extensions/presets/atavist/view.js b/client/gutenberg/extensions/presets/atavist/view.js new file mode 100644 index 00000000000000..db3004217d151a --- /dev/null +++ b/client/gutenberg/extensions/presets/atavist/view.js @@ -0,0 +1,37 @@ +/** + * Internal dependencies + */ + +import FrontendManagement from 'gutenberg/extensions/shared/atavist/frontend-management.js'; + +import 'gutenberg/extensions/map/style.scss'; +import MapComponent from 'gutenberg/extensions/map/map-component.js'; +import MapConfig from 'gutenberg/extensions/map/config.js'; + +import 'gutenberg/extensions/navigation/style.scss'; +import Navigation from 'gutenberg/extensions/navigation/navigation.js'; +import NavigationConfig from 'gutenberg/extensions/navigation/config.js'; + +const navigationTypes = [ + { + component: Navigation, + config: NavigationConfig, + options: {} + } +]; +const blocks = [ + { + component: MapComponent, + config: MapConfig, + options: {} + } +]; + +const init = function() { + const frontendManagement = new FrontendManagement(); + document.querySelector('body').classList.add('webcomponentsready'); + frontendManagement.blockIterator( document, navigationTypes ); + frontendManagement.blockIterator( document, blocks ); +}; + +window.addEventListener( 'load', init ); diff --git a/client/gutenberg/extensions/shared/README.md b/client/gutenberg/extensions/shared/README.md new file mode 100644 index 00000000000000..f5547190fc8132 --- /dev/null +++ b/client/gutenberg/extensions/shared/README.md @@ -0,0 +1 @@ +The shared directory is meant to contain components, scripts, and stylesheets that are used in multiple blocks. At present it contains only the FrontendManagement component, which manages the process rendering React components into the wrappers of certain Gutenberg blocks, extracting blcok attributes from the containers data-attributes, and injecting the children. diff --git a/client/gutenberg/extensions/shared/atavist/frontend-management.js b/client/gutenberg/extensions/shared/atavist/frontend-management.js new file mode 100644 index 00000000000000..9ab776a4e416bb --- /dev/null +++ b/client/gutenberg/extensions/shared/atavist/frontend-management.js @@ -0,0 +1,68 @@ +/** + * Wordpress dependencies + */ + +import { createElement, render } from '@wordpress/element'; + +/** + * External dependencies + */ + +/** + * Internal dependencies + */ + + import { toArray } from 'lodash'; + +export class FrontendManagement { + blockIterator( rootNode, blocks ) { + blocks.forEach( block => { + this.initializeFrontendReactBlocks( + block, + rootNode + ) + } ) + } + initializeFrontendReactBlocks( block, rootNode ) { + const { component, config, options } = block; + const { name, attributes } = config; + const { selector } = options; + const blockClass = [ '.wp-block', name.replace('/', '-') ].join( '-' ) + rootNode + .querySelectorAll( blockClass ) + .forEach( node => { + const data = this.extractAttributesFromContainer( node.dataset, attributes ) + let children; + if ( node.childNodes.length > 0 ) { + const innerBlocksContainerAttributes = { + dangerouslySetInnerHTML: { __html: node.innerHTML }, + className: 'inner-blocks-container' + } + children = createElement( 'div', innerBlocksContainerAttributes ); + } + const el = createElement( component, data, children ); + render( el, selector ? node.querySelector( selector ) : node ); + } ) + } + + extractAttributesFromContainer( dataset, attributes ) { + const data = {}; + for ( const name in attributes) { + const attribute = attributes[ name ]; + data[ name ] = dataset[ name ]; + if ( attribute.type === 'array' || attribute.type === 'object' ) { + + try { + data[ name ] = JSON.parse( data[ name ] ); + } catch(e) { + // console.log( 'Error decoding JSON data for field ' + name, e); + data[ name ] = null; + } + + } + } + return data; + } +} + +export default FrontendManagement; diff --git a/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/index.js b/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/index.js new file mode 100644 index 00000000000000..aa7853c3e15ad4 --- /dev/null +++ b/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/index.js @@ -0,0 +1,61 @@ +/** + * Wordpress dependencies + */ + +import { Component, createRef } from '@wordpress/element'; + +/** + * External dependencies + */ + + import classnames from 'classnames'; + +/** + * Internal dependencies + */ + +import './style.scss'; + +export class AtavistSearch extends Component { + constructor() { + super( ...arguments ); + this.searchClicked = this.searchClicked.bind(this); + this.inputRef = createRef(); + this.state = { + isShown: false + }; + } + componentDidMount() { + this.searchClicked = this.searchClicked.bind(this); + // document.addEventListener('mousedown', this._activity_outside.bind(this)); + } + searchClicked(e) { + const { isShown } = this.state; + this.setState( { isShown: ! isShown } ); + this.inputRef.current.focus(); + } + render() { + const { isShown } = this.state; + const { searchClicked, inputRef } = this; + const classes = classnames( 'atavist-search', isShown ? 'show' : 'hide' ); + return ( +
+
+ + + + + + +
+
+ +
+
+ ); + } +} + +export default AtavistSearch; diff --git a/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/style.scss b/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/style.scss new file mode 100644 index 00000000000000..b88c26835c9839 --- /dev/null +++ b/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/style.scss @@ -0,0 +1,46 @@ +.atavist-search { + min-width: 25px; + min-height: 25px; + cursor: pointer; + overflow: hidden; + position: relative; + svg { + width: 100%; + height: 100%; + } + .search-icon { + width: 16px; + height: 16px; + position: absolute; + top: 50%; + left: 0; + margin-top: -8px; + } + input[type=text] { + width: 0px; + -webkit-transition: width 0.3s ease; + -moz-transition: width 0.3s ease; + -o-transition: width 0.3s ease; + transition: width 0.3s ease; + background: none; + border: none; + outline: none; + cursor: pointer; + } + &.show input[type=text], + &.show input[type=text]:focus { + width: 200px; + cursor: initial; + } + &:not(.show) input[type=text] { + border: none !important; + } + input[type=text] { + border-bottom: 1px solid gray; + border-radius: 0; + padding: 0 0 0 25px; + margin: 0; + height: 30px; + font-size: 1em; + } +} From f2a927a9e0196a5d45cbfc93dac37ba21a493a21 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Mon, 8 Oct 2018 02:41:17 -0400 Subject: [PATCH 002/107] Configs rewritten as a single object with comma-separated properties. Refactor of Frontend Management's handling of block children to avoid altering the DOM. Refactor of view.js files with component and config as properties of a single object, for greater uniformity and less code in the preset view file. --- client/gutenberg/extensions/map/config.js | 77 +++++++++++-------- client/gutenberg/extensions/map/editor.js | 18 +++-- client/gutenberg/extensions/map/view.js | 8 ++ .../gutenberg/extensions/navigation/config.js | 43 +++++++---- .../gutenberg/extensions/navigation/editor.js | 11 +-- .../gutenberg/extensions/navigation/view.js | 8 ++ .../extensions/presets/atavist/view.js | 24 +++--- .../shared/atavist/frontend-management.js | 44 +++++++---- 8 files changed, 146 insertions(+), 87 deletions(-) diff --git a/client/gutenberg/extensions/map/config.js b/client/gutenberg/extensions/map/config.js index 6fa9e2ed19bfba..92316e77958ef2 100644 --- a/client/gutenberg/extensions/map/config.js +++ b/client/gutenberg/extensions/map/config.js @@ -1,33 +1,50 @@ -const config = {} +/** + * Wordpress dependencies + */ -config.name = 'atavist/map'; -config.title = 'Map'; -config.icon = ; -config.category = 'common'; -config.keywords = [ 'Map', 'Atavist' ]; -config.attributes = { - map_style: { - type: 'string', - default: 'default' - } -}; -config.baseClasses = [ - 'atavist-block', - 'atavist-simple-map' -]; -config.map_styleOptions = [ - { - value: 'default', - label: 'Basic' - }, - { - value: 'satellite', - label: 'Satellite' +import { __ } from '@wordpress/i18n'; + +/** + * External dependencies + */ + + /** + * Internal dependencies + */ + +export const CONFIG = { + name: 'atavist/map', + title: __( 'Map' ), + icon: , + category: 'common', + keywords: [ + __( 'Map' ), + __( 'Atavist' ) + ], + attributes: { + map_style: { + type: 'string', + default: 'default' + } }, - { - value: 'terrain', - label: 'Terrain' - } -]; + baseClasses: [ + 'atavist-block', + 'atavist-simple-map' + ], + map_styleOptions: [ + { + value: 'default', + label: __( 'Basic' ) + }, + { + value: 'satellite', + label: __( 'Satellite' ) + }, + { + value: 'terrain', + label: __( 'Terrain' ) + } + ] +} -export default config; +export default CONFIG; diff --git a/client/gutenberg/extensions/map/editor.js b/client/gutenberg/extensions/map/editor.js index f7adcc1df0171b..dbbbd60db0b71b 100644 --- a/client/gutenberg/extensions/map/editor.js +++ b/client/gutenberg/extensions/map/editor.js @@ -21,14 +21,15 @@ import classnames from 'classnames'; import './style.scss'; import './editor.scss'; import MapComponent from './map-component.js'; -import config from './config.js'; +import { CONFIG } from './config.js'; + +const { name, title, icon, category, keywords, attributes, map_styleOptions, baseClasses } = CONFIG; -const { name, title, icon, category, keywords, attributes, map_styleOptions, baseClasses } = config; registerBlockType( name, { - title: __( title ), + title: title, icon: icon, category: category, - keywords: keywords.map( keyword => __( keyword ) ), + keywords: keywords, attributes: attributes, edit: function( { attributes, setAttributes, className } ) { const { map_style } = attributes; @@ -49,7 +50,9 @@ registerBlockType( name, { return ( { inspectorControls } -
+
@@ -60,11 +63,12 @@ registerBlockType( name, { save: function( { attributes, className } ) { const { map_style } = attributes; const classes = classnames( - config.baseClasses, + CONFIG.baseClasses, className ); return ( -
); diff --git a/client/gutenberg/extensions/map/view.js b/client/gutenberg/extensions/map/view.js index 7dd4fedccf05ec..407d8a6175f03f 100644 --- a/client/gutenberg/extensions/map/view.js +++ b/client/gutenberg/extensions/map/view.js @@ -3,4 +3,12 @@ /** * Internal dependencies */ + import './style.scss'; +import component from './map-component.js'; +import { CONFIG } from './config.js'; + +export const map = { + component, + CONFIG +} diff --git a/client/gutenberg/extensions/navigation/config.js b/client/gutenberg/extensions/navigation/config.js index db7f9e0ce65baf..9d53764f0c0ba6 100644 --- a/client/gutenberg/extensions/navigation/config.js +++ b/client/gutenberg/extensions/navigation/config.js @@ -1,14 +1,29 @@ -const config = {} - -config.name = 'atavist/navigation'; -config.title = 'Navigation'; -config.icon = ; -config.category = 'layout'; -config.keywords = [ 'Navigation', 'Atavist' ]; -config.attributes = {}; -config.baseClasses = [ - 'nav-wrapper', - 'navigation-None' -]; - -export default config; +/** + * Wordpress dependencies + */ + +import { __ } from '@wordpress/i18n'; + +/** + * External dependencies + */ + + /** + * Internal dependencies + */ + +export const CONFIG = { + name: 'atavist/navigation', + title: __( 'Navigation' ), + icon: , + category: 'layout', + keywords: [ + __( 'Navigation' ), + __( 'Atavist' ) + ], + attributes: {}, + baseClasses: [ + 'nav-wrapper', + 'navigation-None' + ] +} diff --git a/client/gutenberg/extensions/navigation/editor.js b/client/gutenberg/extensions/navigation/editor.js index 6bbd0b9b00d54c..cb595f524062b4 100644 --- a/client/gutenberg/extensions/navigation/editor.js +++ b/client/gutenberg/extensions/navigation/editor.js @@ -19,14 +19,15 @@ import classnames from 'classnames'; import './style.scss'; import './editor.scss'; import Navigation from './navigation.js'; -import config from './config.js'; +import { CONFIG } from './config.js'; + +const { name, title, icon, category, keywords, attributes, baseClasses } = CONFIG; -const { name, title, icon, category, keywords, attributes, baseClasses } = config; registerBlockType( name, { - title: __( title ), + title: title, icon: icon, category: category, - keywords: keywords.map( keyword => __( keyword ) ), + keywords: keywords, attributes: attributes, edit: function( { attributes, className } ) { const classes = classnames( @@ -45,7 +46,7 @@ registerBlockType( name, { }, save: function( { attributes, className } ) { const classes = classnames( - config.baseClasses, + CONFIG.baseClasses, className ); return ( diff --git a/client/gutenberg/extensions/navigation/view.js b/client/gutenberg/extensions/navigation/view.js index 7dd4fedccf05ec..543be1f0053665 100644 --- a/client/gutenberg/extensions/navigation/view.js +++ b/client/gutenberg/extensions/navigation/view.js @@ -3,4 +3,12 @@ /** * Internal dependencies */ + import './style.scss'; +import component from './navigation.js'; +import { CONFIG } from './config.js'; + +export const navigation = { + component, + CONFIG +} diff --git a/client/gutenberg/extensions/presets/atavist/view.js b/client/gutenberg/extensions/presets/atavist/view.js index db3004217d151a..feca5d20ce90ae 100644 --- a/client/gutenberg/extensions/presets/atavist/view.js +++ b/client/gutenberg/extensions/presets/atavist/view.js @@ -3,27 +3,23 @@ */ import FrontendManagement from 'gutenberg/extensions/shared/atavist/frontend-management.js'; - -import 'gutenberg/extensions/map/style.scss'; -import MapComponent from 'gutenberg/extensions/map/map-component.js'; -import MapConfig from 'gutenberg/extensions/map/config.js'; - -import 'gutenberg/extensions/navigation/style.scss'; -import Navigation from 'gutenberg/extensions/navigation/navigation.js'; -import NavigationConfig from 'gutenberg/extensions/navigation/config.js'; +import { map } from 'gutenberg/extensions/map/view'; +import { navigation } from 'gutenberg/extensions/navigation/view'; const navigationTypes = [ { - component: Navigation, - config: NavigationConfig, - options: {} + component: navigation.component, + options: { + config: navigation.CONFIG, + } } ]; const blocks = [ { - component: MapComponent, - config: MapConfig, - options: {} + component: map.component, + options: { + config: map.CONFIG + } } ]; diff --git a/client/gutenberg/extensions/shared/atavist/frontend-management.js b/client/gutenberg/extensions/shared/atavist/frontend-management.js index 9ab776a4e416bb..94a9fcd6854971 100644 --- a/client/gutenberg/extensions/shared/atavist/frontend-management.js +++ b/client/gutenberg/extensions/shared/atavist/frontend-management.js @@ -12,34 +12,27 @@ import { createElement, render } from '@wordpress/element'; * Internal dependencies */ - import { toArray } from 'lodash'; - export class FrontendManagement { + blockIterator( rootNode, blocks ) { blocks.forEach( block => { this.initializeFrontendReactBlocks( - block, + block.component, + block.options, rootNode ) } ) } - initializeFrontendReactBlocks( block, rootNode ) { - const { component, config, options } = block; - const { name, attributes } = config; + + initializeFrontendReactBlocks( component, options = {}, rootNode ) { + const { name, attributes } = options.config; const { selector } = options; - const blockClass = [ '.wp-block', name.replace('/', '-') ].join( '-' ) + const blockClass = [ '.wp-block', name.replace('/', '-') ].join( '-' ); rootNode .querySelectorAll( blockClass ) .forEach( node => { - const data = this.extractAttributesFromContainer( node.dataset, attributes ) - let children; - if ( node.childNodes.length > 0 ) { - const innerBlocksContainerAttributes = { - dangerouslySetInnerHTML: { __html: node.innerHTML }, - className: 'inner-blocks-container' - } - children = createElement( 'div', innerBlocksContainerAttributes ); - } + const data = this.extractAttributesFromContainer( node.dataset, attributes ); + const children = this.extractChildrenFromContainer( node ); const el = createElement( component, data, children ); render( el, selector ? node.querySelector( selector ) : node ); } ) @@ -47,7 +40,7 @@ export class FrontendManagement { extractAttributesFromContainer( dataset, attributes ) { const data = {}; - for ( const name in attributes) { + for ( const name in attributes ) { const attribute = attributes[ name ]; data[ name ] = dataset[ name ]; if ( attribute.type === 'array' || attribute.type === 'object' ) { @@ -63,6 +56,23 @@ export class FrontendManagement { } return data; } + + extractChildrenFromContainer( node ) { + const children = []; + node.childNodes.forEach( childNode => children.push( childNode ) ); + return children.map( child => { + const attr = {}; + for ( const i = 0; i < child.attributes.length; i++ ) { + const attribute = child.attributes[ i ]; + attr[ attribute.nodeName ] = attribute.nodeValue + } + attr.dangerouslySetInnerHTML = { + __html: child.innerHTML + }; + return createElement( child.tagName.toLowerCase(), attr ); + } ); + } + } export default FrontendManagement; From 5d758e5bb5613e0a75b530c12bc73c074c026fca Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Mon, 8 Oct 2018 02:59:48 -0400 Subject: [PATCH 003/107] Replaced incorrect const with let in for loop. --- .../gutenberg/extensions/shared/atavist/frontend-management.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/shared/atavist/frontend-management.js b/client/gutenberg/extensions/shared/atavist/frontend-management.js index 94a9fcd6854971..9e6dc32ef205b0 100644 --- a/client/gutenberg/extensions/shared/atavist/frontend-management.js +++ b/client/gutenberg/extensions/shared/atavist/frontend-management.js @@ -62,7 +62,7 @@ export class FrontendManagement { node.childNodes.forEach( childNode => children.push( childNode ) ); return children.map( child => { const attr = {}; - for ( const i = 0; i < child.attributes.length; i++ ) { + for ( let i = 0; i < child.attributes.length; i++ ) { const attribute = child.attributes[ i ]; attr[ attribute.nodeName ] = attribute.nodeValue } From d4787ce3b8844d99cb31b496bd3db3ca7b925060 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Mon, 8 Oct 2018 09:09:15 -0400 Subject: [PATCH 004/107] Clean branch with temp blocks deleted, as a starting point for others. --- client/gutenberg/extensions/map/README.md | 6 -- client/gutenberg/extensions/map/config.js | 50 ------------ client/gutenberg/extensions/map/editor.js | 76 ------------------- client/gutenberg/extensions/map/editor.scss | 1 - .../gutenberg/extensions/map/map-component.js | 32 -------- client/gutenberg/extensions/map/style.scss | 1 - client/gutenberg/extensions/map/view.js | 14 ---- .../gutenberg/extensions/navigation/README.md | 1 - .../gutenberg/extensions/navigation/config.js | 29 ------- .../gutenberg/extensions/navigation/editor.js | 60 --------------- .../extensions/navigation/editor.scss | 4 - .../extensions/navigation/navigation.js | 34 --------- .../extensions/navigation/style.scss | 11 --- .../gutenberg/extensions/navigation/view.js | 14 ---- .../extensions/presets/atavist/editor.js | 2 - .../extensions/presets/atavist/view.js | 20 +---- 16 files changed, 2 insertions(+), 353 deletions(-) delete mode 100644 client/gutenberg/extensions/map/README.md delete mode 100644 client/gutenberg/extensions/map/config.js delete mode 100644 client/gutenberg/extensions/map/editor.js delete mode 100644 client/gutenberg/extensions/map/editor.scss delete mode 100644 client/gutenberg/extensions/map/map-component.js delete mode 100644 client/gutenberg/extensions/map/style.scss delete mode 100644 client/gutenberg/extensions/map/view.js delete mode 100644 client/gutenberg/extensions/navigation/README.md delete mode 100644 client/gutenberg/extensions/navigation/config.js delete mode 100644 client/gutenberg/extensions/navigation/editor.js delete mode 100644 client/gutenberg/extensions/navigation/editor.scss delete mode 100644 client/gutenberg/extensions/navigation/navigation.js delete mode 100644 client/gutenberg/extensions/navigation/style.scss delete mode 100644 client/gutenberg/extensions/navigation/view.js diff --git a/client/gutenberg/extensions/map/README.md b/client/gutenberg/extensions/map/README.md deleted file mode 100644 index c313aa798899da..00000000000000 --- a/client/gutenberg/extensions/map/README.md +++ /dev/null @@ -1,6 +0,0 @@ -This block will be an adaptation of the Atavist Map block, which renders a map using [Google Maps API](https://cloud.google.com/maps-platform/). Editors will be able to control: - -- Locations on the map, with optional title and description -- Zoom level -- Style (e.g. Terrain, Satellite) -- Marker color diff --git a/client/gutenberg/extensions/map/config.js b/client/gutenberg/extensions/map/config.js deleted file mode 100644 index 92316e77958ef2..00000000000000 --- a/client/gutenberg/extensions/map/config.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Wordpress dependencies - */ - -import { __ } from '@wordpress/i18n'; - -/** - * External dependencies - */ - - /** - * Internal dependencies - */ - -export const CONFIG = { - name: 'atavist/map', - title: __( 'Map' ), - icon: , - category: 'common', - keywords: [ - __( 'Map' ), - __( 'Atavist' ) - ], - attributes: { - map_style: { - type: 'string', - default: 'default' - } - }, - baseClasses: [ - 'atavist-block', - 'atavist-simple-map' - ], - map_styleOptions: [ - { - value: 'default', - label: __( 'Basic' ) - }, - { - value: 'satellite', - label: __( 'Satellite' ) - }, - { - value: 'terrain', - label: __( 'Terrain' ) - } - ] -} - -export default CONFIG; diff --git a/client/gutenberg/extensions/map/editor.js b/client/gutenberg/extensions/map/editor.js deleted file mode 100644 index dbbbd60db0b71b..00000000000000 --- a/client/gutenberg/extensions/map/editor.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Wordpress dependencies - */ - -import { __ } from '@wordpress/i18n'; -import { registerBlockType } from '@wordpress/blocks'; -import { SelectControl } from '@wordpress/components'; -import { InspectorControls } from '@wordpress/editor'; -import { Fragment } from '@wordpress/element'; - -/** - * External dependencies - */ - -import classnames from 'classnames'; - - /** - * Internal dependencies - */ - -import './style.scss'; -import './editor.scss'; -import MapComponent from './map-component.js'; -import { CONFIG } from './config.js'; - -const { name, title, icon, category, keywords, attributes, map_styleOptions, baseClasses } = CONFIG; - -registerBlockType( name, { - title: title, - icon: icon, - category: category, - keywords: keywords, - attributes: attributes, - edit: function( { attributes, setAttributes, className } ) { - const { map_style } = attributes; - const classes = classnames( - baseClasses, - className - ); - const inspectorControls = ( - - { setAttributes( { map_style: value } ) } } - options={ map_styleOptions } - /> - - ); - return ( - - { inspectorControls } -
- -
-
- ); - }, - save: function( { attributes, className } ) { - const { map_style } = attributes; - const classes = classnames( - CONFIG.baseClasses, - className - ); - return ( -
- ); - } -} ); diff --git a/client/gutenberg/extensions/map/editor.scss b/client/gutenberg/extensions/map/editor.scss deleted file mode 100644 index 2046f90522daaf..00000000000000 --- a/client/gutenberg/extensions/map/editor.scss +++ /dev/null @@ -1 +0,0 @@ -.wp-block-atavist-map {} diff --git a/client/gutenberg/extensions/map/map-component.js b/client/gutenberg/extensions/map/map-component.js deleted file mode 100644 index 1c2f14c408a078..00000000000000 --- a/client/gutenberg/extensions/map/map-component.js +++ /dev/null @@ -1,32 +0,0 @@ -/** @format */ - -/** - * Wordpress dependencies - */ - -import { Component } from '@wordpress/element'; - -/** - * External dependencies - */ - -/** - * Internal dependencies - */ - -import config from './config.js'; - -export class MapComponent extends Component { - - render() { - const { map_style } = this.props; - return

Map, with style: { map_style }

; - } - -} - -MapComponent.defaultProps = { - map_style: null -} - -export default MapComponent; diff --git a/client/gutenberg/extensions/map/style.scss b/client/gutenberg/extensions/map/style.scss deleted file mode 100644 index 2046f90522daaf..00000000000000 --- a/client/gutenberg/extensions/map/style.scss +++ /dev/null @@ -1 +0,0 @@ -.wp-block-atavist-map {} diff --git a/client/gutenberg/extensions/map/view.js b/client/gutenberg/extensions/map/view.js deleted file mode 100644 index 407d8a6175f03f..00000000000000 --- a/client/gutenberg/extensions/map/view.js +++ /dev/null @@ -1,14 +0,0 @@ -/** @format */ - -/** - * Internal dependencies - */ - -import './style.scss'; -import component from './map-component.js'; -import { CONFIG } from './config.js'; - -export const map = { - component, - CONFIG -} diff --git a/client/gutenberg/extensions/navigation/README.md b/client/gutenberg/extensions/navigation/README.md deleted file mode 100644 index 320eb3c99e5ff0..00000000000000 --- a/client/gutenberg/extensions/navigation/README.md +++ /dev/null @@ -1 +0,0 @@ -This block will be an adaptation of an Atavist Navigation Type, which is a wrapper around the contents of an article/story/post/page. Navigation Types are responsible for rendering global elements such as headers, footers, and tables of contents. diff --git a/client/gutenberg/extensions/navigation/config.js b/client/gutenberg/extensions/navigation/config.js deleted file mode 100644 index 9d53764f0c0ba6..00000000000000 --- a/client/gutenberg/extensions/navigation/config.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Wordpress dependencies - */ - -import { __ } from '@wordpress/i18n'; - -/** - * External dependencies - */ - - /** - * Internal dependencies - */ - -export const CONFIG = { - name: 'atavist/navigation', - title: __( 'Navigation' ), - icon: , - category: 'layout', - keywords: [ - __( 'Navigation' ), - __( 'Atavist' ) - ], - attributes: {}, - baseClasses: [ - 'nav-wrapper', - 'navigation-None' - ] -} diff --git a/client/gutenberg/extensions/navigation/editor.js b/client/gutenberg/extensions/navigation/editor.js deleted file mode 100644 index cb595f524062b4..00000000000000 --- a/client/gutenberg/extensions/navigation/editor.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Wordpress dependencies - */ - -import { __ } from '@wordpress/i18n'; -import { registerBlockType } from '@wordpress/blocks'; -import { InnerBlocks } from '@wordpress/editor'; - -/** - * External dependencies - */ - -import classnames from 'classnames'; - - /** - * Internal dependencies - */ - -import './style.scss'; -import './editor.scss'; -import Navigation from './navigation.js'; -import { CONFIG } from './config.js'; - -const { name, title, icon, category, keywords, attributes, baseClasses } = CONFIG; - -registerBlockType( name, { - title: title, - icon: icon, - category: category, - keywords: keywords, - attributes: attributes, - edit: function( { attributes, className } ) { - const classes = classnames( - baseClasses, - className - ); - return ( -
- -
- -
-
-
- ); - }, - save: function( { attributes, className } ) { - const classes = classnames( - CONFIG.baseClasses, - className - ); - return ( -
-
- -
-
- ); - } -} ); diff --git a/client/gutenberg/extensions/navigation/editor.scss b/client/gutenberg/extensions/navigation/editor.scss deleted file mode 100644 index 07c1dac151c5eb..00000000000000 --- a/client/gutenberg/extensions/navigation/editor.scss +++ /dev/null @@ -1,4 +0,0 @@ -.wp-block-atavist-navigation { - border: 1px solid gray; - padding: 1rem; -} diff --git a/client/gutenberg/extensions/navigation/navigation.js b/client/gutenberg/extensions/navigation/navigation.js deleted file mode 100644 index 5467ae7d2a686a..00000000000000 --- a/client/gutenberg/extensions/navigation/navigation.js +++ /dev/null @@ -1,34 +0,0 @@ -/** @format */ - -/** - * Wordpress dependencies - */ - -import { Component, Fragment } from '@wordpress/element'; - -/** - * External dependencies - */ - -/** - * Internal dependencies - */ - -import config from './config.js'; - -export class Navigation extends Component { - - render() { - const { children } = this.props; - return ( - -
Placeholder Header
- { children } -
Placeholder Footer
-
- ); - } - -} - -export default Navigation; diff --git a/client/gutenberg/extensions/navigation/style.scss b/client/gutenberg/extensions/navigation/style.scss deleted file mode 100644 index c7ff20f0b2c2b3..00000000000000 --- a/client/gutenberg/extensions/navigation/style.scss +++ /dev/null @@ -1,11 +0,0 @@ -.wp-block-atavist-navigation { - header, footer { - background: black; - color: gray; - padding: 1rem; - text-align: center; - } - article { - padding: 1rem; - } -} diff --git a/client/gutenberg/extensions/navigation/view.js b/client/gutenberg/extensions/navigation/view.js deleted file mode 100644 index 543be1f0053665..00000000000000 --- a/client/gutenberg/extensions/navigation/view.js +++ /dev/null @@ -1,14 +0,0 @@ -/** @format */ - -/** - * Internal dependencies - */ - -import './style.scss'; -import component from './navigation.js'; -import { CONFIG } from './config.js'; - -export const navigation = { - component, - CONFIG -} diff --git a/client/gutenberg/extensions/presets/atavist/editor.js b/client/gutenberg/extensions/presets/atavist/editor.js index 335d098b108acb..2f795a13cc0998 100644 --- a/client/gutenberg/extensions/presets/atavist/editor.js +++ b/client/gutenberg/extensions/presets/atavist/editor.js @@ -2,5 +2,3 @@ * Internal dependencies */ -import 'gutenberg/extensions/map/editor'; -import 'gutenberg/extensions/navigation/editor'; diff --git a/client/gutenberg/extensions/presets/atavist/view.js b/client/gutenberg/extensions/presets/atavist/view.js index feca5d20ce90ae..1914e33772bf16 100644 --- a/client/gutenberg/extensions/presets/atavist/view.js +++ b/client/gutenberg/extensions/presets/atavist/view.js @@ -3,25 +3,9 @@ */ import FrontendManagement from 'gutenberg/extensions/shared/atavist/frontend-management.js'; -import { map } from 'gutenberg/extensions/map/view'; -import { navigation } from 'gutenberg/extensions/navigation/view'; -const navigationTypes = [ - { - component: navigation.component, - options: { - config: navigation.CONFIG, - } - } -]; -const blocks = [ - { - component: map.component, - options: { - config: map.CONFIG - } - } -]; +const navigationTypes = []; +const blocks = []; const init = function() { const frontendManagement = new FrontendManagement(); From b5c756d6c927438fd57ec72ad935334c7f6ad9e9 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Mon, 8 Oct 2018 10:28:30 -0400 Subject: [PATCH 005/107] Map block, initial commit. --- .../gutenberg/extensions/map-block/config.js | 373 ++++++++++++++++++ .../extensions/map-block/editor.scss | 1 + .../gutenberg/extensions/map-block/index.js | 131 ++++++ .../map-block/location-search/index.js | 115 ++++++ .../map-block/location-search/style.scss | 7 + .../extensions/map-block/locations/index.js | 88 +++++ .../extensions/map-block/locations/style.scss | 12 + .../extensions/map-block/map-component.js | 270 +++++++++++++ .../gutenberg/extensions/map-block/style.scss | 8 + client/gutenberg/extensions/map-block/view.js | 14 + .../extensions/presets/atavist/editor.js | 1 + .../extensions/presets/atavist/view.js | 11 +- 12 files changed, 1030 insertions(+), 1 deletion(-) create mode 100644 client/gutenberg/extensions/map-block/config.js create mode 100644 client/gutenberg/extensions/map-block/editor.scss create mode 100644 client/gutenberg/extensions/map-block/index.js create mode 100644 client/gutenberg/extensions/map-block/location-search/index.js create mode 100644 client/gutenberg/extensions/map-block/location-search/style.scss create mode 100644 client/gutenberg/extensions/map-block/locations/index.js create mode 100644 client/gutenberg/extensions/map-block/locations/style.scss create mode 100644 client/gutenberg/extensions/map-block/map-component.js create mode 100644 client/gutenberg/extensions/map-block/style.scss create mode 100644 client/gutenberg/extensions/map-block/view.js diff --git a/client/gutenberg/extensions/map-block/config.js b/client/gutenberg/extensions/map-block/config.js new file mode 100644 index 00000000000000..337dadee07d9a1 --- /dev/null +++ b/client/gutenberg/extensions/map-block/config.js @@ -0,0 +1,373 @@ +/** + * Wordpress dependencies + */ + +import { __ } from '@wordpress/i18n'; + +/** + * External dependencies + */ + + /** + * Internal dependencies + */ + +export const CONFIG = { + name: 'atavist/maps', + title: __( 'Map' ), + icon: , + category: 'common', + keywords: [ + __( 'Map' ), + __( 'Atavist' ) + ], + attributes: { + align: { + type: 'string' + }, + the_caption: { + source: 'text', + selector: '.atavist-caption' + }, + points: { + type: 'array', + default: [] + }, + map_style: { + type: 'string', + default: 'default' + }, + zoom: { + type: 'integer', + default: 13 + }, + map_center: { + type: 'object', + default: { + latitude: 40.7022937, + longitude: -73.9863515 + } + }, + focus_mode: { + type: 'object', + default: { + type: 'fit_markers' + } + }, + marker_color: { + type: 'string', + default: 'red' + }, + api_key: { + type: 'string' + } + }, + styles: { + default: { + map_type: 'ROADMAP', + styles: [ + { + elementType: 'labels', + stylers: [ { + visibility: 'on' + } ] + }, + { + featureType: 'poi', + elementType: 'labels.text', + stylers: [ { + visibility: 'simplified' + } ] + }, + { + featureType: 'poi', + elementType: 'labels.icon', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'transit', + elementType: 'labels.icons', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'transit', + elementType: 'labels.text', + stylers: [ { + visibility: 'off' + } ] + } + ] + }, + satellite: { + map_type: 'SATELLITE', + styles: [ + { + elementType: 'labels', + stylers: [ { + visibility: 'on' + } ] + }, + { + featureType: 'poi', + elementType: 'labels.text', + stylers: [ { + visibility: 'simplified' + } ] + }, + { + featureType: 'poi', + elementType: 'labels.icon', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'transit', + elementType: 'labels.icons', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'transit', + elementType: 'labels.text', + stylers: [ { + visibility: 'off' + } ] + } + ] + }, + satellite_with_features: { + map_type: 'HYBRID', + styles: [ + { + elementType: 'labels', + stylers: [ { + visibility: 'on' + } ] + }, + { + featureType: 'poi', + elementType: 'labels.text', + stylers: [ { + visibility: 'simplified' + } ] + }, + { + featureType: 'poi', + elementType: 'labels.icon', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'transit', + elementType: 'labels.icons', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'transit', + elementType: 'labels.text', + stylers: [ { + visibility: 'off' + } ] + } + ] + }, + terrain: { + map_type: 'TERRAIN', + styles: [ + { + featureType: 'administrative', + stylers: [ { + visibility: 'off' + } ] + }, + { + elementType: 'labels', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'poi', + stylers: [ { + visibility: 'simplified' + } ] + }, + { + featureType: 'poi', + elementType: 'labels', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'road', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'transit', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'water', + elementType: 'labels', + stylers: [ { + visibility: 'off' + } ] + } + ] + }, + terrain_with_features: { + map_type: 'TERRAIN', + styles: [ + { + elementType: 'labels', + stylers: [ { + visibility: 'on' + } ] + }, + { + featureType: 'poi', + elementType: 'labels.text', + stylers: [ { + visibility: 'simplified' + } ] + }, + { + featureType: 'poi', + elementType: 'labels.icon', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'transit', + elementType: 'labels.icons', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'transit', + elementType: 'labels.text', + stylers: [ { + visibility: 'off' + } ] + } + ] + }, + black_and_white: { + map_type: 'ROADMAP', + styles: [ + { + stylers: [ { + saturation: -100 + } ] + }, + { + elementType: 'labels', + stylers: [ { + visibility: 'on' + } ] + }, + { + featureType: 'poi', + elementType: 'labels.text', + stylers: [ { + visibility: 'simplified' + } ] + }, + { + featureType: 'poi', + elementType: 'labels.icon', + stylers: [ { + visibility: 'off' + } ] + }, + { + featureType: 'transit', + elementType: 'labels.text', + stylers: [ { + visibility: 'simplified' + } ] + } + ] + } + }, + map_styleOptions: [ + { + value: 'default', + label: 'Basic' + }, + { + value: 'black_and_white', + label: 'Black and white' + }, + { + value: 'satellite', + label: 'Satellite' + }, + { + value: 'satellite_with_features', + label: 'Satellite (with features)' + }, + { + value: 'terrain', + label: 'Terrain' + }, + { + value: 'terrain_with_features', + label: 'Terrain (with features)' + } + ], + marker_colorOptions: [ + { + value: 'red', + label: 'Red' + }, + { + value: 'blue', + label: 'Blue' + }, + { + value: 'yellow', + label: 'Yellow' + }, + { + value: 'green', + label: 'Green' + }, + { + value: 'purple', + label: 'Purple' + }, + { + value: 'black', + label: 'Black' + } + ], + GOOGLE_MAPS_API_KEY: 'AIzaSyDaj7klnWKpzGx0W5PonA73Dgr68Me8cyg', + baseClasses: [ + 'atavist-block', + 'atavist-simple-map' + ], + validAlignments: [ + 'left', + 'center', + 'right', + 'wide', + 'full' + ] +}; diff --git a/client/gutenberg/extensions/map-block/editor.scss b/client/gutenberg/extensions/map-block/editor.scss new file mode 100644 index 00000000000000..bbe15aed8ca771 --- /dev/null +++ b/client/gutenberg/extensions/map-block/editor.scss @@ -0,0 +1 @@ +.wp-block-atavist-maps {} diff --git a/client/gutenberg/extensions/map-block/index.js b/client/gutenberg/extensions/map-block/index.js new file mode 100644 index 00000000000000..76fb034b993e66 --- /dev/null +++ b/client/gutenberg/extensions/map-block/index.js @@ -0,0 +1,131 @@ +/** + * Wordpress dependencies + */ + +import { __ } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; +import { PanelBody, SelectControl } from '@wordpress/components'; +import { RichText, InspectorControls, BlockControls, BlockAlignmentToolbar } from '@wordpress/editor'; +import { Fragment } from '@wordpress/element'; + +/** + * External dependencies + */ + +import classnames from 'classnames'; + + /** + * Internal dependencies + */ + +import './style.scss'; +import './editor.scss'; +import Map from './map-component.js'; +import Locations from './locations'; +import { CONFIG } from './config.js'; + +registerBlockType( CONFIG.name, { + title: CONFIG.title, + icon: CONFIG.icon, + category: CONFIG.category, + keywords: CONFIG.keywords, + attributes: CONFIG.attributes, + /* TODO: Research why this doesn't work? */ + getEditWrapperProps( attributes ) { + const { align } = attributes; + if ( -1 !== CONFIG.validAlignments.indexOf( align ) ) { + return { 'data-align': align }; + } + }, + edit: function( { attributes, setAttributes, className } ) { + const { the_caption, map_style, points, zoom, map_center, focus_mode, marker_color, align } = attributes; + const updateAlignment = ( value ) => setAttributes( { align: value } ); + const inspectorControls = ( + + + + + + + { setAttributes( { points: value } ) } } + /> + { setAttributes( { map_style: value } ) } } + options={ CONFIG.map_styleOptions } + /> + { setAttributes( { marker_color: value } ) } } + options={ CONFIG.marker_colorOptions } + /> + + + + ); + return ( + + { inspectorControls } +
+ { setAttributes( { zoom: value } ) } } + api_key={ CONFIG.GOOGLE_MAPS_API_KEY } + /> + setAttributes( { the_caption: value } ) } + /> +
+
+ ); + }, + save: function( { attributes, className } ) { + const { the_caption, map_style, points, zoom, map_center, focus_mode, marker_color, align } = attributes; + const atavistAlignClass = ( value ) => { + switch ( value ) { + case 'left': + case 'right': + case 'center': + case 'full': + return 'atavist-block-align-' + value; + default: + return 'atavist-block-align-center'; + } + } + const classes = classnames( + CONFIG.baseClasses, + className, + atavistAlignClass( align ) + ); + return ( +
+
+

{ the_caption }

+
+ ); + } +} ); diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js new file mode 100644 index 00000000000000..64144f37cbba92 --- /dev/null +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -0,0 +1,115 @@ +/** + * Wordpress dependencies + */ + +import { Autocomplete } from '@wordpress/editor'; +import { Component, createRef } from '@wordpress/element'; + +/** + * External dependencies + */ + +import classnames from 'classnames'; + +/** + * Internal dependencies + */ + +import './style.scss'; + +export class LocationSearch extends Component { + + constructor() { + super( ...arguments ) + this.textRef = createRef() + this.testRef = createRef() + this.state = { + isEmpty: true + } + this.autocompleters = [ + { + name: 'placeSearch', + triggerPrefix: '', + options: this.search.bind(this), + isDebounced: true, + getOptionLabel: option => ( + { option.description } + ), + getOptionKeywords: option => [ option.description ], + getOptionCompletion: this.getOptionCompletion.bind(this) + } + ]; + } + + getOptionCompletion( option ) { + const placesService = new window.google.maps.places.PlacesService( this.testRef.current ); + this.textRef.current.innerHTML = ''; + this.textRef.current.focus(); + placesService.getDetails( { placeId: option.place_id }, function( place ) { + const point = { + place_title: option.description, + title: '', + caption: '', + id: option.place_id, + viewport: place.geometry.viewport, + coordinates: { + latitude: place.geometry.location.lat(), + longitude: place.geometry.location.lng() + } + } + this.props.onAddPoint( point ); + this.textRef.current.innerHTML = ''; + }.bind(this)); + return option.description; + } + + search() { + const searchText = this.textRef.current.innerText; + const placeSearch = new window.google.maps.places.AutocompleteService() + if ( searchText.length < 2 ) return + return new Promise( function( resolve, reject ) { + placeSearch.getPlacePredictions( { + input: searchText + }, function ( place, status ) { + if ( status !== window.google.maps.places.PlacesServiceStatus.OK ) { + reject( new Error( status ) ); + } else { + resolve( place ); + } + }); + }); + } + + searchChanged( e ) { + this.setState( { isEmpty: e.target.innerText.length < 1 } ); + } + + render() { + const classes = classnames( + 'input-control', + 'component-location_search__search-field', + this.state.isEmpty ? 'is-empty' : null + ); + return ( +
+ + { ( { isExpanded, listBoxId } ) => ( +
+ ) } + +
+
+ ); + } +} + +export default LocationSearch; diff --git a/client/gutenberg/extensions/map-block/location-search/style.scss b/client/gutenberg/extensions/map-block/location-search/style.scss new file mode 100644 index 00000000000000..90ee8b3a017e6c --- /dev/null +++ b/client/gutenberg/extensions/map-block/location-search/style.scss @@ -0,0 +1,7 @@ +.components-location-search { + margin-bottom: 1em; +} +.component-location_search__search-field.is-empty:after { + content: 'Add a marker...'; + color: lightgray; +} diff --git a/client/gutenberg/extensions/map-block/locations/index.js b/client/gutenberg/extensions/map-block/locations/index.js new file mode 100644 index 00000000000000..554f5ae8a7c73b --- /dev/null +++ b/client/gutenberg/extensions/map-block/locations/index.js @@ -0,0 +1,88 @@ +/** + * Wordpress dependencies + */ + +import { Panel, PanelBody, TextControl } from '@wordpress/components'; +import { Component } from '@wordpress/element'; + +/** + * Internal dependencies + */ + +import './style.scss'; +import LocationSearch from '../location-search'; + +/** + * External dependencies + */ + +import { clone, concat } from 'lodash'; + +export class Locations extends Component { + + constructor() { + super( ...arguments ); + this.onAddPoint = this.onAddPoint.bind(this); + this.onDeletePoint = this.onDeletePoint.bind(this); + this.state = { + selectedCell: null + }; + } + + onAddPoint( point ) { + const { points, onChange } = this.props; + onChange( concat( points, point ) ); + } + + onDeletePoint( e ) { + const index = parseInt( e.target.getAttribute( 'data-id' ) ); + const { points, onChange } = this.props; + let newPoints = clone( points ); + newPoints.splice( index, 1 ); + onChange( newPoints ); + } + + setMarkerField( field, value, index ) { + const { points, onChange } = this.props; + let newPoints = clone( points ); + newPoints[index][field] = value; + onChange( newPoints ); + } + + render() { + const { points } = this.props; + const rows = points.map( ( point, index ) => + + this.setMarkerField( 'title', title, index ) } + /> + this.setMarkerField( 'caption', caption, index ) } + /> + + + ); + return ( +
+ + + { rows } + +
+ ); + } +} + +Locations.defaultProps = { + points: Object.freeze( [] ), + onChange: () => {} +}; + +export default Locations; diff --git a/client/gutenberg/extensions/map-block/locations/style.scss b/client/gutenberg/extensions/map-block/locations/style.scss new file mode 100644 index 00000000000000..58ad8b0262e1cd --- /dev/null +++ b/client/gutenberg/extensions/map-block/locations/style.scss @@ -0,0 +1,12 @@ +.components-locations__panel { + margin-bottom: 1em; + &:empty { + display: none; + } + .components-panel__body, + .components-panel__body:first-child, + .components-panel__body:last-child { + max-width: 100%; + margin: 0; + } +} diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js new file mode 100644 index 00000000000000..56d61fd6b08a2f --- /dev/null +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -0,0 +1,270 @@ +/** @format */ + +/** + * Wordpress dependencies + */ + +import { Component, createRef } from '@wordpress/element'; + +/** + * External dependencies + */ + +/** + * Internal dependencies + */ + +import { CONFIG } from './config.js'; + +const $ = window.jQuery; + +export class Map extends Component { + + constructor() { + super( ...arguments ); + this.mapRef = createRef(); + this.state = { + map: null, + fit_to_bounds: false, + markers: [], + infowindow: null, + }; + this.mapStyles = CONFIG.styles; + this.sizeMap = this.sizeMap.bind( this ); + } + + render() { + return
; + } + + componentDidMount() { + this.loadMapLibraries(); + } + /* Observers */ + + /* This implementation of componentDidUpdate is a reusable way to approximate Polymer observers */ + componentDidUpdate( prevProps ) { + for ( const propName in this.props ) { + const functionName = propName + 'Changed'; + if ( + this.props[ propName ] !== prevProps[ propName ] && + typeof this[ functionName ] === 'function' + ) { + this[ functionName ]( this.props[ propName ] ); + } + } + } + + map_styleChanged() { + const { map } = this.state; + if ( ! map ) { + return; + } + map.setOptions( { + styles: this.getMapStyle(), + mapTypeId: window.google.maps.MapTypeId[ this.getMapType() ], + } ); + } + + marker_colorChanged() { + const { points } = this.props; + this.pointsChanged( points ); + } + + infoWindowFromPoint( point ) { + const els = []; + if ( point.title.replace( ' ', '' ).length > 0 ) { + els.push( '

' + point.title + '

' ); + } + if ( point.caption.replace( ' ', '' ).length > 0 ) { + els.push( '

' + point.caption + '' ); + } + return els.join( '' ); + } + + pointsChanged( points ) { + const markers = []; + const { map } = this.state; + if ( typeof google === 'undefined' || typeof map === 'undefined' ) { + return; + } + this.state.markers.forEach( marker => marker.setMap( null ) ); + const icon = this.getMarkerIcon(); + points.forEach( point => { + const position = new window.google.maps.LatLng( + point.coordinates.latitude, + point.coordinates.longitude + ); + const infowindow = new window.google.maps.InfoWindow( { + content: this.infoWindowFromPoint( point ), + maxWidth: 200, + } ); + const marker = new window.google.maps.Marker( { position, map, icon, infowindow } ); + window.google.maps.event.addListener( + marker, + 'click', + function() { + if ( this.state.infowindow ) { + this.state.infowindow.close(); + } + if ( infowindow.getContent().replace( ' ', '' ).length > 0 ) { + infowindow.open( map, marker ); + this.setState( { infowindow } ); + } + }.bind( this ) + ); + + marker._infowindow = infowindow; + markers.push( marker ); + } ); + + this.setState( { markers }, this.setBoundsByMarkers ); + } + + setBoundsByMarkers() { + const { focus_mode, zoom } = this.props; + const { map, markers } = this.state; + if ( ! map || focus_mode.type !== 'fit_markers' || markers.length === 0 ) { + return; + } + + const bounds = new window.google.maps.LatLngBounds(); + markers.forEach( marker => { + bounds.extend( + new window.google.maps.LatLng( marker.position.lat(), marker.position.lng() ) + ); + } ); + + map.setCenter( bounds.getCenter() ); + map.fitBounds( bounds ); + if ( markers.length > 1 ) { + this.setState( { fit_to_bounds: true } ); + map.setOptions( { zoomControl: false } ); + } else { + map.setZoom( parseInt( zoom, 10 ) ); + this.setState( { fit_to_bounds: false } ); + map.setOptions( { zoomControl: true } ); + } + } + + getMapStyle() { + return this.mapStyles[ this.props.map_style ].styles; + } + + getMapType() { + return this.mapStyles[ this.props.map_style ].map_type; + } + + loadMapLibraries() { + let atavistGoogleMapsLoaded = window.atavistGoogleMapsLoaded; + window.atavistGoogleMapInit = function() { + atavistGoogleMapsLoaded.resolve(); + }; + const scriptsToLoad = []; + if ( ! window.atavistGoogleMapsLoaded ) { + atavistGoogleMapsLoaded = $.Deferred(); + if ( typeof google === 'undefined' ) { + scriptsToLoad.push( + window.jQuery.getScript( + 'https://maps.googleapis.com/maps/api/js?key=' + + this.props.api_key + + '&libraries=places&callback=atavistGoogleMapInit' + ) + ); + } else { + atavistGoogleMapsLoaded.resolve(); + } + } + + atavistGoogleMapsLoaded.done( + function() { + this.init(); + }.bind( this ) + ); + } + + getMarkerIcon() { + const { marker_color } = this.props; + const url = + 'https://atavist-static.s3.amazonaws.com/prototype_assets/map_marker_2x_' + + marker_color + + '.png'; + return new window.google.maps.MarkerImage( + url, + null, + null, + null, + new window.google.maps.Size( 32, 40 ) + ); + } + + sizeMap() { + const blockWidth = $( this.mapRef.current ).width(); + const maxHeight = window.innerHeight * 0.8; + const blockHeight = Math.min( blockWidth * ( 3 / 4 ), maxHeight ); + this.mapRef.current.style.height = blockHeight + 'px'; + } + + init() { + const { points, zoom, map_center } = this.props; + const mapOptions = { + streetViewControl: false, + mapTypeControl: false, + panControl: false, + scrollwheel: false, + zoomControlOptions: { + style: 'SMALL', + }, + styles: this.getMapStyle(), + mapTypeId: window.google.maps.MapTypeId[ this.getMapType() ], + zoom: parseInt( zoom, 10 ), + }; + const map = new window.google.maps.Map( this.mapRef.current, mapOptions ); + map.addListener( + 'zoom_changed', + function() { + this.props.onSetZoom( map.getZoom() ); + }.bind( this ) + ); + this.setState( { map } ); + + setTimeout( + function() { + this.sizeMap(); + this.mapRef.current.addEventListener( 'alignmentChanged', this.sizeMap ); + window.addEventListener( 'resize', this.sizeMap ); + window.google.maps.event.trigger( map, 'resize' ); + map.setCenter( new window.google.maps.LatLng( map_center.latitude, map_center.longitude ) ); + this.pointsChanged( points ); + + // TODO: This won't work as written! + $( this ).on( + 'alignmentChanged afterSectionChange', + function() { + window.google.maps.event.trigger( map, 'resize' ); + this.pointsChanged( points ); + }.bind( this ) + ); + }.bind( this ), + 1000 + ); + } +} + +Map.defaultProps = { + points: [], + map_style: 'default', + zoom: 13, + onSetZoom: () => {}, + map_center: { + latitude: 40.7022937, + longitude: -73.9863515, + }, + focus_mode: { + type: 'fit_markers', + }, + marker_color: 'red', + api_key: null, +}; + +export default Map; diff --git a/client/gutenberg/extensions/map-block/style.scss b/client/gutenberg/extensions/map-block/style.scss new file mode 100644 index 00000000000000..e86638e04112b8 --- /dev/null +++ b/client/gutenberg/extensions/map-block/style.scss @@ -0,0 +1,8 @@ +.wp-block-atavist-maps { + .map__map-container { + width: 100%; + height: 400px; + overflow: hidden; + background: gray; + } +} diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js new file mode 100644 index 00000000000000..46278fe6231333 --- /dev/null +++ b/client/gutenberg/extensions/map-block/view.js @@ -0,0 +1,14 @@ +/** @format */ + +/** + * Internal dependencies + */ + +import './style.scss'; +import component from './map-component.js'; +import { CONFIG } from './config.js'; + +export const map = { + component, + CONFIG, +}; diff --git a/client/gutenberg/extensions/presets/atavist/editor.js b/client/gutenberg/extensions/presets/atavist/editor.js index 2f795a13cc0998..82f09e19184801 100644 --- a/client/gutenberg/extensions/presets/atavist/editor.js +++ b/client/gutenberg/extensions/presets/atavist/editor.js @@ -2,3 +2,4 @@ * Internal dependencies */ +import 'gutenberg/extensions/map-block'; diff --git a/client/gutenberg/extensions/presets/atavist/view.js b/client/gutenberg/extensions/presets/atavist/view.js index 1914e33772bf16..1223c54e002ec3 100644 --- a/client/gutenberg/extensions/presets/atavist/view.js +++ b/client/gutenberg/extensions/presets/atavist/view.js @@ -3,9 +3,18 @@ */ import FrontendManagement from 'gutenberg/extensions/shared/atavist/frontend-management.js'; +import { map } from 'gutenberg/extensions/map-block/view'; const navigationTypes = []; -const blocks = []; +const blocks = [ + { + component: map.component, + options: { + config: map.CONFIG, + selector: '.map__map-container' + } + } +]; const init = function() { const frontendManagement = new FrontendManagement(); From 74af045366ab38c2d310655ee70fc41f76398c6f Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Tue, 9 Oct 2018 07:58:34 -0400 Subject: [PATCH 006/107] On-block approach to adding Map Points. --- .../extensions/map-block/add-point/index.js | 84 +++++++++++++++++++ .../extensions/map-block/add-point/oval.svg | 19 +++++ .../extensions/map-block/add-point/style.scss | 42 ++++++++++ .../gutenberg/extensions/map-block/index.js | 34 ++++++-- .../map-block/location-search/index.js | 10 +-- .../map-block/location-search/style.scss | 6 +- .../extensions/map-block/locations/index.js | 8 -- .../extensions/map-block/map-component.js | 10 ++- 8 files changed, 189 insertions(+), 24 deletions(-) create mode 100644 client/gutenberg/extensions/map-block/add-point/index.js create mode 100644 client/gutenberg/extensions/map-block/add-point/oval.svg create mode 100644 client/gutenberg/extensions/map-block/add-point/style.scss diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js new file mode 100644 index 00000000000000..28f350a00056eb --- /dev/null +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -0,0 +1,84 @@ +/** + * Wordpress dependencies + */ + +import { __ } from '@wordpress/i18n'; +import { Component } from '@wordpress/element'; +import { + Button, + Dashicon, + Popover +} from '@wordpress/components'; + +/** + * External dependencies + */ + +/** + * Internal dependencies + */ + +import LocationSearch from '../location-search'; +import './style.scss'; + +export class AddPoint extends Component { + + constructor() { + super( ...arguments ) + this.state = { + popoverVisible: false + }; + this.onAddPoint = this.onAddPoint.bind( this ); + this.showPopover = this.showPopover.bind( this ); + this.hidePopover = this.hidePopover.bind( this ); + } + + showPopover() { + this.setState( { popoverVisible: true } ); + } + + hidePopover( e ){ + this.setState( { popoverVisible: false } ); + if ( e ) { + e.stopPropagation(); + } + } + + onAddPoint( point ) { + this.props.onAddPoint( point ); + this.hidePopover(); + } + + render() { + const { popoverVisible } = this.state; + const { showPopover, hidePopover, onAddPoint } = this; + return ( + + + + ) } + + ); + } + +} + +AddPoint.defaultProps = { + onAddPoint: () => {} +} + +export default AddPoint; diff --git a/client/gutenberg/extensions/map-block/add-point/oval.svg b/client/gutenberg/extensions/map-block/add-point/oval.svg new file mode 100644 index 00000000000000..cb149ec47cc3d2 --- /dev/null +++ b/client/gutenberg/extensions/map-block/add-point/oval.svg @@ -0,0 +1,19 @@ + + + + Oval Copy + Created with Sketch. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/gutenberg/extensions/map-block/add-point/style.scss b/client/gutenberg/extensions/map-block/add-point/style.scss new file mode 100644 index 00000000000000..462d5b9eb80ff4 --- /dev/null +++ b/client/gutenberg/extensions/map-block/add-point/style.scss @@ -0,0 +1,42 @@ +.map__add_btn { + position: absolute; + left: 50%; + top: 50%; + z-index: 1; + width: 32px; + height: 38px; + margin-top: -19px; + margin-left: -16px; + background-image: url( ./oval.svg ); + background-repeat: no-repeat; + text-indent: -9999px; + box-shadow: none; + background-color: transparent; + &.components-button:not(:disabled):not([aria-disabled=true]):focus { + background-color: transparent; + box-shadow: none; + } + &:focus, &:active { + background-color: transparent; + box-shadow: none; + } +} +.map__popover { + .components-button:not(:disabled):not([aria-disabled=true]):focus { + background-color: transparent; + box-shadow: none; + } + .components-popover__content { + padding: 1rem; + } +} +.map__popover_close { + margin: 0; + padding: 0; + border: none; + box-shadow: none; + float: right; + path { + color: #aaa; + } +} diff --git a/client/gutenberg/extensions/map-block/index.js b/client/gutenberg/extensions/map-block/index.js index 76fb034b993e66..af6650dc7acc24 100644 --- a/client/gutenberg/extensions/map-block/index.js +++ b/client/gutenberg/extensions/map-block/index.js @@ -4,8 +4,19 @@ import { __ } from '@wordpress/i18n'; import { registerBlockType } from '@wordpress/blocks'; -import { PanelBody, SelectControl } from '@wordpress/components'; -import { RichText, InspectorControls, BlockControls, BlockAlignmentToolbar } from '@wordpress/editor'; + +import { + PanelBody, + SelectControl +} from '@wordpress/components'; + +import { + RichText, + InspectorControls, + BlockControls, + BlockAlignmentToolbar +} from '@wordpress/editor'; + import { Fragment } from '@wordpress/element'; /** @@ -13,6 +24,7 @@ import { Fragment } from '@wordpress/element'; */ import classnames from 'classnames'; +import { clone } from 'lodash'; /** * Internal dependencies @@ -20,8 +32,9 @@ import classnames from 'classnames'; import './style.scss'; import './editor.scss'; -import Map from './map-component.js'; +import AddPoint from './add-point'; import Locations from './locations'; +import Map from './map-component.js'; import { CONFIG } from './config.js'; registerBlockType( CONFIG.name, { @@ -40,6 +53,11 @@ registerBlockType( CONFIG.name, { edit: function( { attributes, setAttributes, className } ) { const { the_caption, map_style, points, zoom, map_center, focus_mode, marker_color, align } = attributes; const updateAlignment = ( value ) => setAttributes( { align: value } ); + const addPoint = ( value ) => { + const newPoints = clone( points ); + newPoints.push( value ); + setAttributes( { points: newPoints } ); + } const inspectorControls = ( @@ -63,8 +81,8 @@ registerBlockType( CONFIG.name, { { setAttributes( { marker_color: value } ) } } - options={ CONFIG.marker_colorOptions } + onChange={ ( value ) => { setAttributes( { marker_color: value } ) } } + options={ CONFIG.marker_colorOptions } /> @@ -83,7 +101,11 @@ registerBlockType( CONFIG.name, { marker_color={ marker_color } onSetZoom={ ( value ) => { setAttributes( { zoom: value } ) } } api_key={ CONFIG.GOOGLE_MAPS_API_KEY } - /> + admin={ true } + onSetPoints={ ( value ) => { setAttributes( { points: value } ) } } + > + + + { ( { isExpanded, listBoxId } ) => (

-
+ ); } } diff --git a/client/gutenberg/extensions/map-block/location-search/style.scss b/client/gutenberg/extensions/map-block/location-search/style.scss index 90ee8b3a017e6c..96523b1468b2a9 100644 --- a/client/gutenberg/extensions/map-block/location-search/style.scss +++ b/client/gutenberg/extensions/map-block/location-search/style.scss @@ -1,7 +1,7 @@ -.components-location-search { - margin-bottom: 1em; -} .component-location_search__search-field.is-empty:after { content: 'Add a marker...'; color: lightgray; + label { + margin-bottom: 0.5em; + } } diff --git a/client/gutenberg/extensions/map-block/locations/index.js b/client/gutenberg/extensions/map-block/locations/index.js index 554f5ae8a7c73b..14d0410d10b7ae 100644 --- a/client/gutenberg/extensions/map-block/locations/index.js +++ b/client/gutenberg/extensions/map-block/locations/index.js @@ -10,7 +10,6 @@ import { Component } from '@wordpress/element'; */ import './style.scss'; -import LocationSearch from '../location-search'; /** * External dependencies @@ -22,18 +21,12 @@ export class Locations extends Component { constructor() { super( ...arguments ); - this.onAddPoint = this.onAddPoint.bind(this); this.onDeletePoint = this.onDeletePoint.bind(this); this.state = { selectedCell: null }; } - onAddPoint( point ) { - const { points, onChange } = this.props; - onChange( concat( points, point ) ); - } - onDeletePoint( e ) { const index = parseInt( e.target.getAttribute( 'data-id' ) ); const { points, onChange } = this.props; @@ -71,7 +64,6 @@ export class Locations extends Component { ); return (
- { rows } diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index 56d61fd6b08a2f..edaf7d267e6aab 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -4,7 +4,7 @@ * Wordpress dependencies */ -import { Component, createRef } from '@wordpress/element'; +import { Component, createRef, Fragment } from '@wordpress/element'; /** * External dependencies @@ -34,7 +34,13 @@ export class Map extends Component { } render() { - return
; + const { children } = this.props; + return ( + +
+ { children } + + ); } componentDidMount() { From 65766a9ae30e830a733935859195a9350b092a22 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Tue, 9 Oct 2018 17:37:14 -0400 Subject: [PATCH 007/107] Editable info windows, and many other refinements. --- .../extensions/map-block/add-point/index.js | 10 +- .../gutenberg/extensions/map-block/index.js | 14 +- .../extensions/map-block/info-window/index.js | 56 +++++ .../map-block/location-search/index.js | 2 +- .../extensions/map-block/map-component.js | 193 +++++++++++------- .../extensions/map-block/map-marker/index.js | 75 +++++++ .../gutenberg/extensions/map-block/style.scss | 3 + 7 files changed, 266 insertions(+), 87 deletions(-) create mode 100644 client/gutenberg/extensions/map-block/info-window/index.js create mode 100644 client/gutenberg/extensions/map-block/map-marker/index.js diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index 28f350a00056eb..598ddb2f5e8adc 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -26,7 +26,8 @@ export class AddPoint extends Component { constructor() { super( ...arguments ) this.state = { - popoverVisible: false + popoverVisible: false, + isVisible: true }; this.onAddPoint = this.onAddPoint.bind( this ); this.showPopover = this.showPopover.bind( this ); @@ -51,7 +52,11 @@ export class AddPoint extends Component { render() { const { popoverVisible } = this.state; + const { isVisible } = this.props; const { showPopover, hidePopover, onAddPoint } = this; + if ( ! isVisible ) { + return null; + } return ( + + } + + { activeMarker && ! admin && + +

{ point.title }

+

{ point.caption }

+
+ } + + + ) : null; return ( -
- { children } +
+ { mapMarkers } +
+ { infoWindow } + { admin && + + } ); } @@ -61,6 +164,10 @@ export class Map extends Component { } } + pointsChanged() { + this.setBoundsByMarkers(); + } + map_styleChanged() { const { map } = this.state; if ( ! map ) { @@ -72,78 +179,23 @@ export class Map extends Component { } ); } - marker_colorChanged() { - const { points } = this.props; - this.pointsChanged( points ); - } - - infoWindowFromPoint( point ) { - const els = []; - if ( point.title.replace( ' ', '' ).length > 0 ) { - els.push( '

' + point.title + '

' ); - } - if ( point.caption.replace( ' ', '' ).length > 0 ) { - els.push( '

' + point.caption + '' ); - } - return els.join( '' ); - } - - pointsChanged( points ) { - const markers = []; - const { map } = this.state; - if ( typeof google === 'undefined' || typeof map === 'undefined' ) { - return; - } - this.state.markers.forEach( marker => marker.setMap( null ) ); - const icon = this.getMarkerIcon(); - points.forEach( point => { - const position = new window.google.maps.LatLng( - point.coordinates.latitude, - point.coordinates.longitude - ); - const infowindow = new window.google.maps.InfoWindow( { - content: this.infoWindowFromPoint( point ), - maxWidth: 200, - } ); - const marker = new window.google.maps.Marker( { position, map, icon, infowindow } ); - window.google.maps.event.addListener( - marker, - 'click', - function() { - if ( this.state.infowindow ) { - this.state.infowindow.close(); - } - if ( infowindow.getContent().replace( ' ', '' ).length > 0 ) { - infowindow.open( map, marker ); - this.setState( { infowindow } ); - } - }.bind( this ) - ); - - marker._infowindow = infowindow; - markers.push( marker ); - } ); - - this.setState( { markers }, this.setBoundsByMarkers ); - } - setBoundsByMarkers() { - const { focus_mode, zoom } = this.props; + const { focus_mode, zoom, points } = this.props; const { map, markers } = this.state; - if ( ! map || focus_mode.type !== 'fit_markers' || markers.length === 0 ) { + if ( ! map || focus_mode.type !== 'fit_markers' || points.length === 0 ) { return; } const bounds = new window.google.maps.LatLngBounds(); - markers.forEach( marker => { + points.forEach( point => { bounds.extend( - new window.google.maps.LatLng( marker.position.lat(), marker.position.lng() ) + new window.google.maps.LatLng( point.coordinates.latitude, point.coordinates.longitude ) ); } ); map.setCenter( bounds.getCenter() ); map.fitBounds( bounds ); - if ( markers.length > 1 ) { + if ( points.length > 1 ) { this.setState( { fit_to_bounds: true } ); map.setOptions( { zoomControl: false } ); } else { @@ -185,6 +237,7 @@ export class Map extends Component { atavistGoogleMapsLoaded.done( function() { this.init(); + this.setState( { loaded: true } ); }.bind( this ) ); } @@ -232,6 +285,7 @@ export class Map extends Component { this.props.onSetZoom( map.getZoom() ); }.bind( this ) ); + map.addListener( 'click', this.onMapClick ); this.setState( { map } ); setTimeout( @@ -241,16 +295,7 @@ export class Map extends Component { window.addEventListener( 'resize', this.sizeMap ); window.google.maps.event.trigger( map, 'resize' ); map.setCenter( new window.google.maps.LatLng( map_center.latitude, map_center.longitude ) ); - this.pointsChanged( points ); - - // TODO: This won't work as written! - $( this ).on( - 'alignmentChanged afterSectionChange', - function() { - window.google.maps.event.trigger( map, 'resize' ); - this.pointsChanged( points ); - }.bind( this ) - ); + this.setBoundsByMarkers(); }.bind( this ), 1000 ); diff --git a/client/gutenberg/extensions/map-block/map-marker/index.js b/client/gutenberg/extensions/map-block/map-marker/index.js new file mode 100644 index 00000000000000..f56a6f6393898f --- /dev/null +++ b/client/gutenberg/extensions/map-block/map-marker/index.js @@ -0,0 +1,75 @@ +/** + * Wordpress dependencies + */ + +import { Component } from '@wordpress/element'; + +/** + * External dependencies + */ + +/** + * Internal dependencies + */ + +export class MapMarker extends Component { + + constructor() { + super( ...arguments ); + this.handleClick = this.handleClick.bind( this ); + } + + componentDidMount() { + this.renderMarker(); + } + + componentWillUnmount() { + + if ( this.marker ) { + this.marker.setMap( null ); + } + } + + componentDidUpdate( prevProps ) { + this.renderMarker(); + } + + handleClick( e ) { + const { onClick, point } = this.props; + onClick( this ); + } + + renderMarker() { + + const { map, point, google, icon, onClick } = this.props; + const { handleClick } = this; + + const position = new google.LatLng( + point.coordinates.latitude, + point.coordinates.longitude + ); + + if ( this.marker ) { + this.marker.setPosition( position ); + this.marker.setIcon( icon ); + } else { + this.marker = new google.Marker( { position, map, icon } ); + this.marker.addListener( 'click', handleClick ); + } + + } + + render() { + return null; + } +} + +MapMarker.defaultProps = { + point: {}, + map: null, + icon: null, + google: null, + onClick: () => {} +} + +export default MapMarker; diff --git a/client/gutenberg/extensions/map-block/style.scss b/client/gutenberg/extensions/map-block/style.scss index e86638e04112b8..f103605fb127da 100644 --- a/client/gutenberg/extensions/map-block/style.scss +++ b/client/gutenberg/extensions/map-block/style.scss @@ -5,4 +5,7 @@ overflow: hidden; background: gray; } + .gm-style-iw > div { + padding-right: 1px; + } } From 1d5cc781d1279541c93da913cd97e91edc087ddf Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 08:58:24 -0400 Subject: [PATCH 008/107] SVG for markers instead of raster images. --- .../extensions/map-block/map-component.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index 402e28f39060f3..5e7be11e6666c8 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -244,17 +244,14 @@ export class Map extends Component { getMarkerIcon() { const { marker_color } = this.props; - const url = - 'https://atavist-static.s3.amazonaws.com/prototype_assets/map_marker_2x_' + - marker_color + - '.png'; - return new window.google.maps.MarkerImage( - url, - null, - null, - null, - new window.google.maps.Size( 32, 40 ) - ); + const svgPath = { + path: 'M16,38 C16,38 32,26.692424 32,16 C32,5.307576 24.836556,0 16,0 C7.163444,0 0,5.307576 0,16 C0,26.692424 16,38 16,38 Z', + fillColor: marker_color, + fillOpacity: 0.6, + scale: 1, + strokeWeight: 0 + }; + return svgPath; } sizeMap() { From 7faefab8f3f5747ff61bcc96c6cff9d4458b932d Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 10:53:55 -0400 Subject: [PATCH 009/107] Changes to the UI for hiding/showing the Add Marker button. Dashed icon and popover will always be shown together. The dashed icon is no longer a button for invoking the popover. Add Marker UI will be visible when map is first revealed. Icon in Block Controls shows the Add Marker UI. --- .../extensions/map-block/add-point/index.js | 43 ++++++++----------- .../gutenberg/extensions/map-block/index.js | 17 +++++++- .../extensions/map-block/map-component.js | 14 +++++- 3 files changed, 45 insertions(+), 29 deletions(-) diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index 598ddb2f5e8adc..2e4c6de8a90786 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -26,18 +26,12 @@ export class AddPoint extends Component { constructor() { super( ...arguments ) this.state = { - popoverVisible: false, - isVisible: true + isVisible: false }; this.onAddPoint = this.onAddPoint.bind( this ); - this.showPopover = this.showPopover.bind( this ); this.hidePopover = this.hidePopover.bind( this ); } - showPopover() { - this.setState( { popoverVisible: true } ); - } - hidePopover( e ){ this.setState( { popoverVisible: false } ); if ( e ) { @@ -51,8 +45,7 @@ export class AddPoint extends Component { } render() { - const { popoverVisible } = this.state; - const { isVisible } = this.props; + const { isVisible } = this.state; const { showPopover, hidePopover, onAddPoint } = this; if ( ! isVisible ) { return null; @@ -61,21 +54,20 @@ export class AddPoint extends Component { - - - ) } + > + Add point + + + + ); } @@ -83,8 +75,7 @@ export class AddPoint extends Component { } AddPoint.defaultProps = { - onAddPoint: () => {}, - isVisible: true + onAddPoint: () => {} } export default AddPoint; diff --git a/client/gutenberg/extensions/map-block/index.js b/client/gutenberg/extensions/map-block/index.js index 8f49cc004a265c..687e488f161f5a 100644 --- a/client/gutenberg/extensions/map-block/index.js +++ b/client/gutenberg/extensions/map-block/index.js @@ -6,8 +6,11 @@ import { __ } from '@wordpress/i18n'; import { registerBlockType } from '@wordpress/blocks'; import { + Button, + IconButton, PanelBody, - SelectControl + SelectControl, + Toolbar } from '@wordpress/components'; import { @@ -17,7 +20,7 @@ import { BlockAlignmentToolbar } from '@wordpress/editor'; -import { Fragment } from '@wordpress/element'; +import { Fragment, createRef } from '@wordpress/element'; /** * External dependencies @@ -52,6 +55,8 @@ registerBlockType( CONFIG.name, { edit: function( { attributes, setAttributes, className } ) { const { the_caption, map_style, points, zoom, map_center, focus_mode, marker_color, align } = attributes; const updateAlignment = ( value ) => setAttributes( { align: value } ); + const markerIcon = ; + const mapRef = createRef(); const inspectorControls = ( @@ -59,6 +64,13 @@ registerBlockType( CONFIG.name, { value={ align } onChange={ updateAlignment } /> + + mapRef.current.setAddPointVisibility( true ) } + /> + @@ -87,6 +99,7 @@ registerBlockType( CONFIG.name, { { inspectorControls }

{ infoWindow } { admin && - + } ); @@ -293,6 +304,7 @@ export class Map extends Component { window.google.maps.event.trigger( map, 'resize' ); map.setCenter( new window.google.maps.LatLng( map_center.latitude, map_center.longitude ) ); this.setBoundsByMarkers(); + this.setAddPointVisibility( true ); }.bind( this ), 1000 ); From fb970f39553c5d97254ff439efb952f558bfeeec Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 11:04:23 -0400 Subject: [PATCH 010/107] Bug fix: clear active marker after deletion, to avoid another marker's info window immediately appearing. --- client/gutenberg/extensions/map-block/map-component.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index 730416b3e495c7..0e53b8d2ae4d10 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -72,6 +72,7 @@ export class Map extends Component { const newPoints = clone( points ); newPoints.splice( index, 1 ); this.props.onSetPoints( newPoints ); + this.setState( { activeMarker: null } ); } updateActiveMarker( updates) { From 6c2edebdfcfd21ed7c679c7f7920dbe94cca2880 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 12:54:08 -0400 Subject: [PATCH 011/107] Color and Map Theme pickers. --- .../gutenberg/extensions/map-block/config.js | 30 +++---------- .../gutenberg/extensions/map-block/index.js | 45 ++++++++++++++----- .../extensions/map-block/map-component.js | 2 +- 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/client/gutenberg/extensions/map-block/config.js b/client/gutenberg/extensions/map-block/config.js index 337dadee07d9a1..b43beca50b759c 100644 --- a/client/gutenberg/extensions/map-block/config.js +++ b/client/gutenberg/extensions/map-block/config.js @@ -333,30 +333,12 @@ export const CONFIG = { } ], marker_colorOptions: [ - { - value: 'red', - label: 'Red' - }, - { - value: 'blue', - label: 'Blue' - }, - { - value: 'yellow', - label: 'Yellow' - }, - { - value: 'green', - label: 'Green' - }, - { - value: 'purple', - label: 'Purple' - }, - { - value: 'black', - label: 'Black' - } + { name: 'red', color: 'red' }, + { name: 'blue', color: 'blue' }, + { name: 'yellow', color: 'yellow' }, + { name: 'green', color: 'green' }, + { name: 'purple', color: 'purple' }, + { name: 'black', color: 'black' } ], GOOGLE_MAPS_API_KEY: 'AIzaSyDaj7klnWKpzGx0W5PonA73Dgr68Me8cyg', baseClasses: [ diff --git a/client/gutenberg/extensions/map-block/index.js b/client/gutenberg/extensions/map-block/index.js index 687e488f161f5a..32e016f1fa763a 100644 --- a/client/gutenberg/extensions/map-block/index.js +++ b/client/gutenberg/extensions/map-block/index.js @@ -2,17 +2,27 @@ * Wordpress dependencies */ -import { __ } from '@wordpress/i18n'; -import { registerBlockType } from '@wordpress/blocks'; +import { + __ +} from '@wordpress/i18n'; + +import { + registerBlockType +} from '@wordpress/blocks'; import { Button, + ColorPalette, IconButton, PanelBody, SelectControl, Toolbar } from '@wordpress/components'; +import { + withState +} from '@wordpress/compose'; + import { RichText, InspectorControls, @@ -20,7 +30,10 @@ import { BlockAlignmentToolbar } from '@wordpress/editor'; -import { Fragment, createRef } from '@wordpress/element'; +import { + Fragment, + createRef +} from '@wordpress/element'; /** * External dependencies @@ -37,6 +50,7 @@ import './style.scss'; import './editor.scss'; import Locations from './locations'; import Map from './map-component.js'; +import MapThemePicker from './map-theme-picker'; import { CONFIG } from './config.js'; registerBlockType( CONFIG.name, { @@ -57,6 +71,17 @@ registerBlockType( CONFIG.name, { const updateAlignment = ( value ) => setAttributes( { align: value } ); const markerIcon = ; const mapRef = createRef(); + const MarkerColorPalette = withState( { + color: '#f00', + } )( ( { color, setState } ) => { + return ( + setState( { marker_color } ) } + /> + ) + } ); const inspectorControls = ( @@ -78,18 +103,18 @@ registerBlockType( CONFIG.name, { points={ points } onChange={ ( value ) => { setAttributes( { points: value } ) } } /> - { setAttributes( { map_style: value } ) } } options={ CONFIG.map_styleOptions } /> - { setAttributes( { marker_color: value } ) } } - options={ CONFIG.marker_colorOptions } - /> + + setAttributes( { marker_color } ) } + /> diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index 0e53b8d2ae4d10..8020d4ac0a60aa 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -259,7 +259,7 @@ export class Map extends Component { const svgPath = { path: 'M16,38 C16,38 32,26.692424 32,16 C32,5.307576 24.836556,0 16,0 C7.163444,0 0,5.307576 0,16 C0,26.692424 16,38 16,38 Z', fillColor: marker_color, - fillOpacity: 0.6, + fillOpacity: 0.8, scale: 1, strokeWeight: 0 }; From 99b4af1c5dc42ef1f0f403747f88881ab3297133 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 12:54:55 -0400 Subject: [PATCH 012/107] Missing map theme component. --- .../map-block/map-theme-picker/index.js | 67 +++++++++++++++++++ .../map-block/map-theme-picker/style.scss | 33 +++++++++ 2 files changed, 100 insertions(+) create mode 100644 client/gutenberg/extensions/map-block/map-theme-picker/index.js create mode 100644 client/gutenberg/extensions/map-block/map-theme-picker/style.scss diff --git a/client/gutenberg/extensions/map-block/map-theme-picker/index.js b/client/gutenberg/extensions/map-block/map-theme-picker/index.js new file mode 100644 index 00000000000000..caf9cd79e4f215 --- /dev/null +++ b/client/gutenberg/extensions/map-block/map-theme-picker/index.js @@ -0,0 +1,67 @@ +/** + * Wordpress dependencies + */ + +import { __ } from '@wordpress/i18n'; + +import { + Component, + Fragment +} from '@wordpress/element'; + +import { + Button, + ButtonGroup +} from '@wordpress/components'; + +/** + * External dependencies + */ + + import classnames from 'classnames'; + +/** + * Internal dependencies + */ + +import './style.scss'; + +export class MapThemePicker extends Component { + + render() { + const { options, value, onChange, label } = this.props; + const buttons = options.map( ( option ) => { + const classes = classnames( + 'component_map-theme-picker__button', + option.value, + option.value === value ? 'isSelected' : '' + ); + return ( + + ); + } ); + return ( + + + + { buttons } + + + ); + } + +} + +MapThemePicker.defaultProps = { + label: '', + options: [], + value: null, + onChange: () => {} +} + +export default MapThemePicker; diff --git a/client/gutenberg/extensions/map-block/map-theme-picker/style.scss b/client/gutenberg/extensions/map-block/map-theme-picker/style.scss new file mode 100644 index 00000000000000..31f74363704eec --- /dev/null +++ b/client/gutenberg/extensions/map-block/map-theme-picker/style.scss @@ -0,0 +1,33 @@ +.component_map-theme-picker__button { + border: 1px solid lightgray; + border-radius: 100%; + width: 70px; + height: 70px; + margin: 5px; + text-indent: -9999px; + background-color: red; + background-position: center center; + background-repeat: no-repeat; + background-size: contain; + &.isSelected { + border-color: black; + } + &.default { + background-image: url( 'https://s3.amazonaws.com/atavist-static/map-themes/map-theme-default.jpg' ); + } + &.black_and_white { + background-image: url( 'https://s3.amazonaws.com/atavist-static/map-themes/map-theme-black_and_white.jpg' ); + } + &.satellite { + background-image: url( 'https://s3.amazonaws.com/atavist-static/map-themes/map-theme-satellite.jpg' ); + } + &.satellite_with_features { + background-image: url( 'https://s3.amazonaws.com/atavist-static/map-themes/map-theme-satellite_with_features.jpg' ); + } + &.terrain { + background-image: url( 'https://s3.amazonaws.com/atavist-static/map-themes/map-theme-terrain.jpg' ); + } + &.terrain_with_features { + background-image: url( 'https://s3.amazonaws.com/atavist-static/map-themes/map-theme-terrain_with_features.jpg' ); + } +} From 4431eee60475bbda57a66e561048a9f31345c9a9 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 13:54:19 -0400 Subject: [PATCH 013/107] Close button for location search popover. --- .../gutenberg/extensions/map-block/add-point/index.js | 11 ++++++++--- .../extensions/map-block/add-point/style.scss | 5 ++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index 2e4c6de8a90786..01f8c568d6232b 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -30,6 +30,7 @@ export class AddPoint extends Component { }; this.onAddPoint = this.onAddPoint.bind( this ); this.hidePopover = this.hidePopover.bind( this ); + this.hideSelf = this.hideSelf.bind( this ); } hidePopover( e ){ @@ -39,6 +40,10 @@ export class AddPoint extends Component { } } + hideSelf() { + this.setState( { isVisible: false } ); + } + onAddPoint( point ) { this.props.onAddPoint( point ); this.hidePopover(); @@ -46,7 +51,7 @@ export class AddPoint extends Component { render() { const { isVisible } = this.state; - const { showPopover, hidePopover, onAddPoint } = this; + const { showPopover, hidePopover, onAddPoint, setState, hideSelf } = this; if ( ! isVisible ) { return null; } @@ -59,9 +64,9 @@ export class AddPoint extends Component { Date: Wed, 10 Oct 2018 14:06:06 -0400 Subject: [PATCH 014/107] Hover animation on Map Theme buttons. --- .../extensions/map-block/map-theme-picker/style.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/gutenberg/extensions/map-block/map-theme-picker/style.scss b/client/gutenberg/extensions/map-block/map-theme-picker/style.scss index 31f74363704eec..0a23c062addc8e 100644 --- a/client/gutenberg/extensions/map-block/map-theme-picker/style.scss +++ b/client/gutenberg/extensions/map-block/map-theme-picker/style.scss @@ -9,6 +9,11 @@ background-position: center center; background-repeat: no-repeat; background-size: contain; + transform: scale(1); + transition: transform .2s ease; + &:hover { + transform: scale(1.1); + } &.isSelected { border-color: black; } From 741f7b0fc25657743a0bc975174cf39d2b7bbddf Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 15:36:25 -0400 Subject: [PATCH 015/107] Fix for JS error occurring in frontend. --- client/gutenberg/extensions/map-block/map-component.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index 8020d4ac0a60aa..2abe24fb88d6a9 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -85,7 +85,9 @@ export class Map extends Component { } setAddPointVisibility( visible = true ) { - this.addPointRef.current.setState( { isVisible: visible } ); + if ( this.addPointRef.current ) { + this.addPointRef.current.setState( { isVisible: visible } ); + } if ( visible ) { this.setState( { activeMarker: null } ); } From ad5685f94e7001fcdfef6513eb499352951b3027 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 15:36:46 -0400 Subject: [PATCH 016/107] Removing artificial height constraint in frontend. --- client/gutenberg/extensions/map-block/style.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/style.scss b/client/gutenberg/extensions/map-block/style.scss index f103605fb127da..308610b4264fe0 100644 --- a/client/gutenberg/extensions/map-block/style.scss +++ b/client/gutenberg/extensions/map-block/style.scss @@ -1,7 +1,6 @@ .wp-block-atavist-maps { .map__map-container { width: 100%; - height: 400px; overflow: hidden; background: gray; } From 011f316253f9bafa080ff39b377eb697f8787248 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 15:37:10 -0400 Subject: [PATCH 017/107] Refactoring the frontend initialization, moving code into each block's view.js, to simplify the presets. --- client/gutenberg/extensions/map-block/view.js | 20 ++++++++++++++---- .../extensions/presets/atavist/view.js | 21 +------------------ 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index 46278fe6231333..e6dc85424a9f55 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -7,8 +7,20 @@ import './style.scss'; import component from './map-component.js'; import { CONFIG } from './config.js'; +import FrontendManagement from 'gutenberg/extensions/shared/atavist/frontend-management.js'; -export const map = { - component, - CONFIG, -}; +window.addEventListener( 'load', function() { + const frontendManagement = new FrontendManagement(); + frontendManagement.blockIterator( + document, + [ + { + component: component, + options: { + config: CONFIG, + selector: '.map__map-container' + } + } + ] + ); +} ); diff --git a/client/gutenberg/extensions/presets/atavist/view.js b/client/gutenberg/extensions/presets/atavist/view.js index 1223c54e002ec3..fb9c7d602f6e47 100644 --- a/client/gutenberg/extensions/presets/atavist/view.js +++ b/client/gutenberg/extensions/presets/atavist/view.js @@ -2,25 +2,6 @@ * Internal dependencies */ -import FrontendManagement from 'gutenberg/extensions/shared/atavist/frontend-management.js'; -import { map } from 'gutenberg/extensions/map-block/view'; +import 'gutenberg/extensions/map-block/view'; -const navigationTypes = []; -const blocks = [ - { - component: map.component, - options: { - config: map.CONFIG, - selector: '.map__map-container' - } - } -]; -const init = function() { - const frontendManagement = new FrontendManagement(); - document.querySelector('body').classList.add('webcomponentsready'); - frontendManagement.blockIterator( document, navigationTypes ); - frontendManagement.blockIterator( document, blocks ); -}; - -window.addEventListener( 'load', init ); From 987bd15d2969fec3c36435739742e9ed474ee202 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 16:54:36 -0400 Subject: [PATCH 018/107] Don't recalculate map bounds if the info window is open. The recalculation often caused the infowindow to jump (sometimes off screen) making it difficult or impossible to continue editing. --- client/gutenberg/extensions/map-block/map-component.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index 2abe24fb88d6a9..ec7c380b924e58 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -195,11 +195,15 @@ export class Map extends Component { setBoundsByMarkers() { const { focus_mode, zoom, points } = this.props; - const { map, markers } = this.state; + const { map, markers, activeMarker } = this.state; if ( ! map || focus_mode.type !== 'fit_markers' || points.length === 0 ) { return; } + if ( activeMarker ) { + return; + } + const bounds = new window.google.maps.LatLngBounds(); points.forEach( point => { bounds.extend( From e5197fac0d7435ccca4a512c9396bb48a13e3d26 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 16:56:11 -0400 Subject: [PATCH 019/107] Adding Map block to the Jetpack preset. --- client/gutenberg/extensions/presets/jetpack/editor.js | 1 + client/gutenberg/extensions/presets/jetpack/view.js | 1 + 2 files changed, 2 insertions(+) diff --git a/client/gutenberg/extensions/presets/jetpack/editor.js b/client/gutenberg/extensions/presets/jetpack/editor.js index 89d37615849e16..0d67bfeb706bcc 100644 --- a/client/gutenberg/extensions/presets/jetpack/editor.js +++ b/client/gutenberg/extensions/presets/jetpack/editor.js @@ -8,3 +8,4 @@ import './utils/block-category'; // Register the Jetpack category import 'gutenberg/extensions/markdown/editor'; import 'gutenberg/extensions/related-posts/editor'; import 'gutenberg/extensions/tiled-gallery/editor'; +import 'gutenberg/extensions/map-block'; diff --git a/client/gutenberg/extensions/presets/jetpack/view.js b/client/gutenberg/extensions/presets/jetpack/view.js index f5cc0663e7a3d6..443985e9bbf958 100644 --- a/client/gutenberg/extensions/presets/jetpack/view.js +++ b/client/gutenberg/extensions/presets/jetpack/view.js @@ -5,3 +5,4 @@ */ import './utils/public-path'; import 'gutenberg/extensions/tiled-gallery/view'; +import 'gutenberg/extensions/map-block/view'; From acbedc989b80b92e0adcf766376f3ddef9708961 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 17:27:45 -0400 Subject: [PATCH 020/107] Removing some unused React functions. --- client/gutenberg/extensions/map-block/info-window/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/gutenberg/extensions/map-block/info-window/index.js b/client/gutenberg/extensions/map-block/info-window/index.js index 3943f7ad4d7a81..608c7113f6f859 100644 --- a/client/gutenberg/extensions/map-block/info-window/index.js +++ b/client/gutenberg/extensions/map-block/info-window/index.js @@ -2,8 +2,11 @@ * Wordpress dependencies */ -import { Component, renderToString, render, Fragment, createPortal } from '@wordpress/element'; -import ReactDOM from 'react-dom'; +import { + Component, + Fragment, + createPortal +} from '@wordpress/element'; /** * External dependencies From 5191ef408add00b28e368ba77893995085c7cbfb Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 10 Oct 2018 19:38:47 -0400 Subject: [PATCH 021/107] Key attributes in iterated markup. --- client/gutenberg/extensions/map-block/locations/index.js | 2 +- client/gutenberg/extensions/map-block/map-component.js | 2 ++ .../gutenberg/extensions/map-block/map-theme-picker/index.js | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/client/gutenberg/extensions/map-block/locations/index.js b/client/gutenberg/extensions/map-block/locations/index.js index 14d0410d10b7ae..a3597fa571a3bb 100644 --- a/client/gutenberg/extensions/map-block/locations/index.js +++ b/client/gutenberg/extensions/map-block/locations/index.js @@ -45,7 +45,7 @@ export class Locations extends Component { render() { const { points } = this.props; const rows = points.map( ( point, index ) => - + { + const buttons = options.map( ( option, index ) => { const classes = classnames( 'component_map-theme-picker__button', option.value, @@ -39,6 +39,7 @@ export class MapThemePicker extends Component { return ( + className='wp-block-atavist-maps__delete-btn' + > + Delete Marker + } @@ -249,8 +254,8 @@ export class Map extends Component { } ); map.setCenter( bounds.getCenter() ); - map.fitBounds( bounds ); if ( points.length > 1 ) { + map.fitBounds( bounds ); this.setState( { fit_to_bounds: true } ); map.setOptions( { zoomControl: false } ); } else { diff --git a/client/gutenberg/extensions/map-block/style.scss b/client/gutenberg/extensions/map-block/style.scss index e99225ba2992ee..ecf8e817438e4e 100644 --- a/client/gutenberg/extensions/map-block/style.scss +++ b/client/gutenberg/extensions/map-block/style.scss @@ -8,4 +8,16 @@ .gm-style-iw > div { padding-right: 1px; } + .wp-block-atavist-maps__delete-btn { + margin-top: 1px solid black; + svg { + margin-right: 0.4em; + } + } + .wp-block-atavist-maps__marker-caption input { + height: 70px; + } + .components-base-control__label { + + } } From 30c49d85dc1df7147a2559da0a313c805008cb8c Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 08:56:07 -0400 Subject: [PATCH 029/107] Check to insure initialization occurs only view-side. --- client/gutenberg/extensions/map-block/view.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index e6dc85424a9f55..c80035bd668a42 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -10,6 +10,9 @@ import { CONFIG } from './config.js'; import FrontendManagement from 'gutenberg/extensions/shared/atavist/frontend-management.js'; window.addEventListener( 'load', function() { + if ( document.body.classList.contains( 'gutenberg-editor-page' ) ) { + return; + } const frontendManagement = new FrontendManagement(); frontendManagement.blockIterator( document, From 5449ace7ef03aad554166fcbc01cf1eab0d0ccff Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 12:51:19 -0400 Subject: [PATCH 030/107] Z-index fix for Add Marker popover, to keep it from appearing above various editor chrome. --- client/gutenberg/extensions/map-block/add-point/style.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/gutenberg/extensions/map-block/add-point/style.scss b/client/gutenberg/extensions/map-block/add-point/style.scss index 69176e85a95dd9..08062071ba2ccf 100644 --- a/client/gutenberg/extensions/map-block/add-point/style.scss +++ b/client/gutenberg/extensions/map-block/add-point/style.scss @@ -22,6 +22,11 @@ } } .map__popover { + // Default z-index for components-popover places it above Edit Post Header and Notices + &.components-popover, + &.components-popover:not(.is-mobile).is-bottom { + z-index: 1; + } .components-button:not(:disabled):not([aria-disabled=true]):focus { background-color: transparent; box-shadow: none; From 0efd694e5e7427651168fec6babc6f3f63bd43ee Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 12:52:04 -0400 Subject: [PATCH 031/107] Multi-line object formatting. --- .../gutenberg/extensions/map-block/map-marker/index.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/map-marker/index.js b/client/gutenberg/extensions/map-block/map-marker/index.js index f56a6f6393898f..5c4e165c0cfec9 100644 --- a/client/gutenberg/extensions/map-block/map-marker/index.js +++ b/client/gutenberg/extensions/map-block/map-marker/index.js @@ -41,7 +41,14 @@ export class MapMarker extends Component { renderMarker() { - const { map, point, google, icon, onClick } = this.props; + const { + map, + point, + google, + icon, + onClick + } = this.props; + const { handleClick } = this; const position = new google.LatLng( From c5e2b2d60ce9f7053f1619c464100093fcbbcb0f Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 12:52:34 -0400 Subject: [PATCH 032/107] Less jarring background color. --- .../gutenberg/extensions/map-block/map-theme-picker/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/map-theme-picker/style.scss b/client/gutenberg/extensions/map-block/map-theme-picker/style.scss index 0a23c062addc8e..7d9539d014ecb2 100644 --- a/client/gutenberg/extensions/map-block/map-theme-picker/style.scss +++ b/client/gutenberg/extensions/map-block/map-theme-picker/style.scss @@ -5,7 +5,7 @@ height: 70px; margin: 5px; text-indent: -9999px; - background-color: red; + background-color: lightgray; background-position: center center; background-repeat: no-repeat; background-size: contain; From 51cc707e28144060d16336956866e451ae5b7164 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 12:53:46 -0400 Subject: [PATCH 033/107] Better approach to determining if view.js is loaded in Editor or View environment. --- client/gutenberg/extensions/map-block/view.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index c80035bd668a42..ffaa4fff9dd18e 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -10,7 +10,8 @@ import { CONFIG } from './config.js'; import FrontendManagement from 'gutenberg/extensions/shared/atavist/frontend-management.js'; window.addEventListener( 'load', function() { - if ( document.body.classList.contains( 'gutenberg-editor-page' ) ) { + // Do not initialize in editor. + if ( window.wp.editor ) { return; } const frontendManagement = new FrontendManagement(); From 40a57a8ebf69be1bb7a50fc8d45d981fafa29b4f Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 12:56:27 -0400 Subject: [PATCH 034/107] Removal of all jQuery. Calypso loadScript library used to dynamically load Google Maps library. Will use version found in client/lib after resolution of https://github.com/Automattic/wp-calypso/issues/27821. --- .../map-block/load-script/README.md | 28 +++ .../map-block/load-script/callback-handler.js | 90 +++++++ .../map-block/load-script/dom-operations.js | 28 +++ .../extensions/map-block/load-script/index.js | 65 +++++ .../load-script/test/callback-handler.js | 235 ++++++++++++++++++ .../map-block/load-script/test/index.js | 117 +++++++++ .../extensions/map-block/map-component.js | 79 +++--- 7 files changed, 602 insertions(+), 40 deletions(-) create mode 100644 client/gutenberg/extensions/map-block/load-script/README.md create mode 100644 client/gutenberg/extensions/map-block/load-script/callback-handler.js create mode 100644 client/gutenberg/extensions/map-block/load-script/dom-operations.js create mode 100644 client/gutenberg/extensions/map-block/load-script/index.js create mode 100644 client/gutenberg/extensions/map-block/load-script/test/callback-handler.js create mode 100644 client/gutenberg/extensions/map-block/load-script/test/index.js diff --git a/client/gutenberg/extensions/map-block/load-script/README.md b/client/gutenberg/extensions/map-block/load-script/README.md new file mode 100644 index 00000000000000..1a867c4a92bed0 --- /dev/null +++ b/client/gutenberg/extensions/map-block/load-script/README.md @@ -0,0 +1,28 @@ +Async Script Loader +============== + +This utility function allows us to use a standardized method of loading remote scripts and injecting them into the `` of our document to bring external functionality into the app. + +### Usage +```js +import { loadScript, loadjQueryDependentScript } from 'lib/load-script'; +loadScript( REMOTE_SCRIPT_URL, function( error ) { + if ( error ) { + debug( 'Script ' + error.src + ' failed to load.' ); + return; + } + debug( 'Script loaded!' ); +} ); + +// if we need jQuery, this function will load it (if it's not loaded already) +loadjQueryDependentScript( REMOTE_SCRIPT_URL, function( error ) { + if ( error ) { + debug( 'Script ' + error.src + ' failed to load.' ); + return; + } + debug( 'Script and jQuery are loaded!' ); +} ); +``` + +### Error handling +The callback should expect a single argument, which will be ```null``` on success or an object on failure. The object contains the ```src``` property, which will contain the src url of the script that failed to load. diff --git a/client/gutenberg/extensions/map-block/load-script/callback-handler.js b/client/gutenberg/extensions/map-block/load-script/callback-handler.js new file mode 100644 index 00000000000000..0fb3dd8ff39f9d --- /dev/null +++ b/client/gutenberg/extensions/map-block/load-script/callback-handler.js @@ -0,0 +1,90 @@ +/** @format */ +/** + * External dependencies + */ +import debugFactory from 'debug'; +const debug = debugFactory( 'lib/load-script/callback-handler' ); + +/** + * Module variables + */ +const callbacksForURLsInProgress = new Map(); + +export function getCallbacksMap() { + return callbacksForURLsInProgress; +} + +export function isLoading( url ) { + return getCallbacksMap().has( url ); +} + +export function addScriptCallback( url, callback ) { + const callbacksMap = getCallbacksMap(); + if ( isLoading( url ) ) { + debug( `Adding a callback for an existing script from "${ url }"` ); + callbacksMap.get( url ).add( callback ); + } else { + debug( `Adding a callback for a new script from "${ url }"` ); + callbacksMap.set( url, new Set( [ callback ] ) ); + } +} + +export function removeScriptCallback( url, callback ) { + debug( `Removing a known callback for a script from "${ url }"` ); + + if ( ! isLoading( url ) ) { + return; + } + + const callbacksMap = getCallbacksMap(); + const callbacksAtUrl = callbacksMap.get( url ); + callbacksAtUrl.delete( callback ); + + if ( callbacksAtUrl.size === 0 ) { + callbacksMap.delete( url ); + } +} + +export function removeScriptCallbacks( url ) { + debug( `Removing all callbacks for a script from "${ url }"` ); + getCallbacksMap().delete( url ); +} + +export function removeAllScriptCallbacks() { + debug( 'Removing all callbacks for scripts from all URLs' ); + getCallbacksMap().clear(); +} + +export function executeCallbacks( url, callbackArguments = null ) { + const callbacksMap = getCallbacksMap(); + + if ( callbacksMap.has( url ) ) { + const debugMessage = `Executing callbacks for "${ url }"`; + debug( + callbackArguments === null + ? debugMessage + : debugMessage + ` with args "${ callbackArguments }"` + ); + + [ ...callbacksMap.get( url ) ] + .filter( cb => typeof cb === 'function' ) + .forEach( cb => cb( callbackArguments ) ); + callbacksMap.delete( url ); + } +} + +export function handleRequestSuccess( event ) { + const { target } = event; + const url = target.getAttribute( 'src' ); + debug( `Handling successful request for "${ url }"` ); + executeCallbacks( url ); + this.onload = null; +} + +export function handleRequestError( event ) { + const { target } = event; + const url = target.getAttribute( 'src' ); + debug( `Handling failed request for "${ url }"` ); + executeCallbacks( url, new Error( `Failed to load script "${ url }"` ) ); + this.onerror = null; +} diff --git a/client/gutenberg/extensions/map-block/load-script/dom-operations.js b/client/gutenberg/extensions/map-block/load-script/dom-operations.js new file mode 100644 index 00000000000000..9277ae0e4c38eb --- /dev/null +++ b/client/gutenberg/extensions/map-block/load-script/dom-operations.js @@ -0,0 +1,28 @@ +/** @format */ + +/** + * External dependencies + */ +import debugFactory from 'debug'; +const debug = debugFactory( 'lib/load-script/dom-operations' ); + +/** + * Internal dependencies + */ +import { handleRequestError, handleRequestSuccess } from './callback-handler'; + +export function createScriptElement( url ) { + debug( `Creating script element for "${ url }"` ); + const script = document.createElement( 'script' ); + script.src = url; + script.type = 'text/javascript'; + script.async = true; + script.onload = handleRequestSuccess; + script.onerror = handleRequestError; + return script; +} + +export function attachToHead( element ) { + debug( 'Attaching element to head' ); + document.head.appendChild( element ); +} diff --git a/client/gutenberg/extensions/map-block/load-script/index.js b/client/gutenberg/extensions/map-block/load-script/index.js new file mode 100644 index 00000000000000..ab1a1a748744ad --- /dev/null +++ b/client/gutenberg/extensions/map-block/load-script/index.js @@ -0,0 +1,65 @@ +/** @format */ +/** + * A little module for loading a external script + * + * @format + */ + +/** + * External dependencies + */ +import debugFactory from 'debug'; +const debug = debugFactory( 'lib/load-script' ); + +/** + * Internal dependencies + */ +import { addScriptCallback, isLoading } from './callback-handler'; +import { createScriptElement, attachToHead } from './dom-operations'; + +// NOTE: This exists for compatibility. +export { removeScriptCallback } from './callback-handler'; + +/** + * Module variables + */ +export const JQUERY_URL = 'https://s0.wp.com/wp-includes/js/jquery/jquery.js'; + +// +// loadScript and loadjQueryDependentScript +// + +export function loadScript( url, callback ) { + // If this script is not currently being loaded, create a script element and attach to document head. + const shouldLoadScript = ! isLoading( url ); + + addScriptCallback( url, callback ); + + if ( shouldLoadScript ) { + attachToHead( createScriptElement( url ) ); + } +} + +export function loadjQueryDependentScript( url, callback ) { + debug( `Loading a jQuery dependent script from "${ url }"` ); + + // It is not possible to expose jQuery globally in Electron App: https://github.com/atom/electron/issues/254. + // It needs to be loaded using require and npm package. + // if ( config.isEnabled( 'desktop' ) ) { + debug( `Attaching jQuery from node_modules to window for "${ url }"` ); + window.$ = window.jQuery = require( 'jquery' ); + // } + + if ( window.jQuery ) { + debug( `jQuery found on window, skipping jQuery script loading for "${ url }"` ); + loadScript( url, callback ); + return; + } + + loadScript( JQUERY_URL, function( error ) { + if ( error ) { + callback( error ); + } + loadScript( url, callback ); + } ); +} diff --git a/client/gutenberg/extensions/map-block/load-script/test/callback-handler.js b/client/gutenberg/extensions/map-block/load-script/test/callback-handler.js new file mode 100644 index 00000000000000..2f7cf2e4313e67 --- /dev/null +++ b/client/gutenberg/extensions/map-block/load-script/test/callback-handler.js @@ -0,0 +1,235 @@ +/** + * @format + */ + +/** + * Internal dependencies + */ +import { + addScriptCallback, + executeCallbacks, + getCallbacksMap, + handleRequestError, + handleRequestSuccess, + isLoading, + removeAllScriptCallbacks, + removeScriptCallback, + removeScriptCallbacks, +} from '../callback-handler'; + +describe( 'loadScript/callback-handler', () => { + describe( 'getCallbacksMap()', () => { + test( 'should initially return an empty object', () => { + expect( getCallbacksMap() ).toEqual( new Map() ); + } ); + } ); + + describe( 'addScriptCallback( url, callback )', () => { + // NOTE: This test is tightly coupled with removeAllScriptCallbacks tests + + beforeAll( function() { + removeAllScriptCallbacks(); + } ); + + afterEach( () => { + removeAllScriptCallbacks(); + } ); + + test( 'should create a new array for a callback function to a new URL', () => { + const callbacks = getCallbacksMap(); + + const url = '/'; + const callback = () => {}; + addScriptCallback( url, callback ); + + expect( callbacks.get( url ) ).toEqual( new Set( [ callback ] ) ); + } ); + + test( 'should append to an existing array for a callback function to an old URL', () => { + const callbacks = getCallbacksMap(); + + const url = '/'; + const callback1 = () => {}; + const callback2 = () => {}; + + addScriptCallback( url, callback1 ); + expect( callbacks.get( url ) ).toEqual( new Set( [ callback1 ] ) ); + + addScriptCallback( url, callback2 ); + expect( callbacks.get( url ) ).toEqual( new Set( [ callback1, callback2 ] ) ); + } ); + } ); + + describe( 'removeAllScriptCallbacks()', () => { + // NOTE: This test is tightly coupled with addScriptCallback tests + + test( 'should reset callbacks object to empty', () => { + const callbacks = getCallbacksMap(); + + const url = '/'; + const callback = () => {}; + addScriptCallback( url, callback ); + + expect( callbacks ).toEqual( new Map( [ [ url, new Set( [ callback ] ) ] ] ) ); + + removeAllScriptCallbacks(); + + expect( callbacks ).toEqual( new Map() ); + } ); + } ); + + describe( 'isLoading( url )', () => { + beforeAll( function() { + removeAllScriptCallbacks(); + } ); + + afterEach( () => { + removeAllScriptCallbacks(); + } ); + + test( 'should be false if the URL is new/unrecognized', () => { + const url = '/'; + expect( isLoading( url ) ).toBeFalsy(); + } ); + + test( 'should be true if the URL is old/recognized', () => { + const url = '/'; + const callback = () => {}; + addScriptCallback( url, callback ); + expect( isLoading( url ) ).toBeTruthy(); + } ); + } ); + + describe( 'removeScriptCallback( url, callback )', () => { + beforeAll( function() { + removeAllScriptCallbacks(); + } ); + + afterEach( () => { + removeAllScriptCallbacks(); + } ); + + test( 'should remove the callback from the second parameter', () => { + const callbacks = getCallbacksMap(); + const url = '/'; + const callback1 = () => {}; + const callback2 = () => {}; + const callback3 = () => {}; + + addScriptCallback( url, callback1 ); + addScriptCallback( url, callback2 ); + addScriptCallback( url, callback3 ); + expect( callbacks ).toEqual( + new Map( [ [ url, new Set( [ callback1, callback2, callback3 ] ) ] ] ) + ); + + removeScriptCallback( url, callback2 ); + expect( callbacks ).toEqual( new Map( [ [ url, new Set( [ callback1, callback3 ] ) ] ] ) ); + } ); + } ); + + describe( 'removeScriptCallbacks( url )', () => { + // NOTE: This test is tightly coupled with addScriptCallback tests + beforeAll( function() { + removeAllScriptCallbacks(); + } ); + afterEach( () => { + removeAllScriptCallbacks(); + } ); + + test( 'should remove all callbacks associated with the URL', () => { + const callbacks = getCallbacksMap(); + + const url1 = '/'; + const url2 = '/information'; + const callback = () => {}; + addScriptCallback( url1, callback ); + addScriptCallback( url2, callback ); + + expect( callbacks ).toEqual( + new Map( [ [ url1, new Set( [ callback ] ) ], [ url2, new Set( [ callback ] ) ] ] ) + ); + + removeScriptCallbacks( url1 ); + + expect( callbacks ).toEqual( new Map( [ [ url2, new Set( [ callback ] ) ] ] ) ); + } ); + } ); + + describe( 'executeCallbacks( url, callbackArguments )', () => { + beforeAll( function() { + removeAllScriptCallbacks(); + } ); + + afterEach( () => { + removeAllScriptCallbacks(); + } ); + + test( 'should execute all callbacks associated with the URL', () => { + const url1 = '/'; + const url2 = '/information'; + const callback1a = jest.fn(); + const callback1b = jest.fn(); + const callback2a = jest.fn(); + const callback2b = jest.fn(); + + addScriptCallback( url1, callback1a ); + addScriptCallback( url1, callback1b ); + addScriptCallback( url2, callback2a ); + addScriptCallback( url2, callback2b ); + expect( callback1a ).not.toHaveBeenCalled(); + expect( callback1b ).not.toHaveBeenCalled(); + expect( callback2a ).not.toHaveBeenCalled(); + expect( callback2b ).not.toHaveBeenCalled(); + + const params = { some: 'params' }; + executeCallbacks( url1, params ); + expect( callback1a ).toHaveBeenCalledTimes( 1 ); + expect( callback1b ).toHaveBeenCalledTimes( 1 ); + expect( callback2a ).not.toHaveBeenCalled(); + expect( callback2b ).not.toHaveBeenCalled(); + expect( callback1a ).toHaveBeenCalledWith( params ); + expect( callback1b ).toHaveBeenCalledWith( params ); + } ); + } ); + + describe( 'handleRequestSuccess( event )', () => { + const url = '/'; + const thisObject = {}; + const eventObject = { target: { getAttribute: () => url } }; + const callback = jest.fn(); + + beforeAll( function() { + addScriptCallback( url, callback ); + handleRequestSuccess.bind( thisObject )( eventObject ); + } ); + + test( 'should execute callbacks associated with the url', () => { + expect( callback ).toHaveBeenCalledTimes( 1 ); + expect( callback ).toHaveBeenCalledWith( null ); + } ); + test( 'should set this.onload to null', () => { + expect( thisObject ).toEqual( { onload: null } ); + } ); + } ); + + describe( 'handleRequestError( event )', () => { + const url = '/'; + const thisObject = {}; + const eventObject = { target: { getAttribute: () => url } }; + const callback = jest.fn(); + + beforeAll( function() { + addScriptCallback( url, callback ); + handleRequestError.bind( thisObject )( eventObject ); + } ); + + test( 'should execute callbacks associated with the url with an error', () => { + expect( callback ).toHaveBeenCalledTimes( 1 ); + expect( callback ).toHaveBeenCalledWith( new Error( `Failed to load script "${ url }"` ) ); + } ); + test( 'should set this.onerror to null', () => { + expect( thisObject ).toEqual( { onerror: null } ); + } ); + } ); +} ); diff --git a/client/gutenberg/extensions/map-block/load-script/test/index.js b/client/gutenberg/extensions/map-block/load-script/test/index.js new file mode 100644 index 00000000000000..63c7fdcd3a59bf --- /dev/null +++ b/client/gutenberg/extensions/map-block/load-script/test/index.js @@ -0,0 +1,117 @@ +/** + * @format + * @jest-environment jsdom + */ + +/** + * Internal dependencies + */ +import { JQUERY_URL, loadjQueryDependentScript, loadScript } from '../'; +import { executeCallbacks, getCallbacksMap, removeAllScriptCallbacks } from '../callback-handler'; +import { attachToHead, createScriptElement } from '../dom-operations'; +import config from 'config'; + +jest.mock( '../dom-operations', () => ( { + attachToHead: jest.fn(), + createScriptElement: jest.fn(), +} ) ); + +jest.mock( 'config', () => ( { + isEnabled: jest.fn(), +} ) ); + +describe( 'loadScript', () => { + describe( 'loadScript( url, callback )', () => { + const url = '/'; + const callback = jest.fn(); + + beforeAll( function() { + removeAllScriptCallbacks(); + loadScript( url, callback ); + } ); + + afterEach( () => { + removeAllScriptCallbacks(); + } ); + + afterAll( () => { + attachToHead.mockReset(); + createScriptElement.mockReset(); + } ); + + test( 'should add the callback onto the pending callbacks object', () => { + expect( getCallbacksMap().get( url ) ).toEqual( new Set( [ callback ] ) ); + } ); + + test( 'should call functions attachToHead and createScriptElement', () => { + expect( attachToHead ).toHaveBeenCalled(); + expect( createScriptElement ).toHaveBeenCalledWith( url ); + } ); + } ); + + describe( 'loadjQueryDependentScript( scriptURL, callback )', () => { + const url = '/'; + + beforeAll( function() { + removeAllScriptCallbacks(); + } ); + + afterEach( () => { + removeAllScriptCallbacks(); + attachToHead.mockReset(); + createScriptElement.mockReset(); + } ); + + test( 'should require jQuery on the desktop', () => { + const callback = jest.fn(); + config.isEnabled.mockReturnValueOnce( { isEnabled: input => input === 'desktop' } ); + loadjQueryDependentScript( url, callback ); + + expect( callback ).not.toHaveBeenCalled(); + expect( createScriptElement ).toHaveBeenCalledTimes( 1 ); + expect( createScriptElement ).toHaveBeenLastCalledWith( url ); + + executeCallbacks( url ); + expect( callback ).toHaveBeenCalledTimes( 1 ); + } ); + + test( 'should use window.jQuery if available', () => { + window.jQuery = {}; + + const callback = jest.fn(); + config.isEnabled.mockReturnValueOnce( { isEnabled: () => false } ); + loadjQueryDependentScript( url, callback ); + + expect( createScriptElement ).toHaveBeenCalledTimes( 1 ); + expect( createScriptElement ).toHaveBeenLastCalledWith( url ); + + executeCallbacks( url ); + expect( callback ).toHaveBeenCalledTimes( 1 ); + + delete window.jQuery; + } ); + + test( 'should sequentially load the jQuery script and the script from the URL (in that order)', () => { + // NOTE: jsdom has jQuery attached to the window. We temporarily replace this + // jQuery instance fir this test. + const jQueryBackup = global.window.jQuery; + global.window.jQuery = false; + + const callback = jest.fn(); + loadjQueryDependentScript( url, callback, true ); + + expect( callback ).not.toHaveBeenCalled(); + expect( createScriptElement ).toHaveBeenCalledTimes( 1 ); + expect( createScriptElement ).toHaveBeenLastCalledWith( JQUERY_URL ); + + executeCallbacks( JQUERY_URL ); + expect( createScriptElement ).toHaveBeenCalledTimes( 2 ); + expect( createScriptElement ).toHaveBeenLastCalledWith( url ); + + executeCallbacks( url ); + expect( callback ).toHaveBeenCalledTimes( 1 ); + + global.window.jQuery = jQueryBackup; + } ); + } ); +} ); diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index f26d6c59678750..8efb314dbe9283 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -35,7 +35,8 @@ import MapMarker from './map-marker/'; import InfoWindow from './info-window/'; import AddPoint from './add-point'; -const $ = window.jQuery; +import { loadScript } from './load-script'; +// import { loadScript } from 'lib/load-script'; export class Map extends Component { @@ -54,6 +55,7 @@ export class Map extends Component { this.addPoint = this.addPoint.bind( this ); this.onMapClick = this.onMapClick.bind( this ); this.setBoundsByMarkers = this.setBoundsByMarkers.bind( this ); + this.scriptsLoaded = this.scriptsLoaded.bind( this ); this.addPointRef = React.createRef(); } @@ -120,6 +122,7 @@ export class Map extends Component { updateActiveMarker, addPoint } = this; + const mapMarkers = points.map( ( point, index ) => { if ( window.google ) { return ( @@ -273,49 +276,44 @@ export class Map extends Component { return CONFIG.styles[ this.props.map_style ].map_type; } - loadMapLibraries() { + scriptsLoaded() { const { map_center, points } = this.props; - let atavistGoogleMapsLoaded = window.atavistGoogleMapsLoaded; - window.atavistGoogleMapInit = function() { - atavistGoogleMapsLoaded.resolve(); - }; - const scriptsToLoad = []; - if ( ! window.atavistGoogleMapsLoaded ) { - atavistGoogleMapsLoaded = $.Deferred(); - if ( typeof google === 'undefined' ) { - scriptsToLoad.push( - window.jQuery.getScript( - 'https://maps.googleapis.com/maps/api/js?key=' + - this.props.api_key + - '&libraries=places&callback=atavistGoogleMapInit' - ) - ); - } else { - atavistGoogleMapsLoaded.resolve(); - } + + this.setState({ loaded: true }); + if ( points.length > 0 ) { + this.init( map_center ); + return; } + this.getMapCenter() + .then( ( position ) => { + this.init( { + latitude: position.coords.latitude, + longitude: position.coords.longitude + } ); + }) + .catch( ( err ) => { + this.init( map_center ); + } ); + } - atavistGoogleMapsLoaded.done( - function() { - if ( points.length > 0 ) { - this.init( map_center ); - return; - } - this.getMapCenter() - .then( ( position ) => { - this.init( { - latitude: position.coords.latitude, - longitude: position.coords.longitude - } ); - }) - .catch( ( err ) => { - this.init( map_center ); - } ); - }.bind( this ) - ); + loadMapLibraries() { + const { api_key } = this.props; + + const src = [ + 'https://maps.googleapis.com/maps/api/js?key=', + api_key, + '&libraries=places' ].join( '' ); + + loadScript( src, ( error ) => { + if ( error ) { + console.log( 'Script ' + error.src + ' failed to load.' ); + return; + } + this.scriptsLoaded(); + } ); } getMapCenter = function ( options ) { @@ -337,10 +335,11 @@ export class Map extends Component { } sizeMap() { - const blockWidth = $( this.mapRef.current ).width(); + const mapEl = this.mapRef.current; + const blockWidth = mapEl.offsetWidth; const maxHeight = window.innerHeight * 0.8; const blockHeight = Math.min( blockWidth * ( 3 / 4 ), maxHeight ); - this.mapRef.current.style.height = blockHeight + 'px'; + mapEl.style.height = blockHeight + 'px'; } init( map_center ) { From 325e538790deddf9feaba21a44525b189d2bfdf3 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 13:00:14 -0400 Subject: [PATCH 035/107] Do not render markers until map exists. --- client/gutenberg/extensions/map-block/map-component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index 8efb314dbe9283..bfbbcdbd362f82 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -123,7 +123,7 @@ export class Map extends Component { addPoint } = this; - const mapMarkers = points.map( ( point, index ) => { + const mapMarkers = ( map ) && points.map( ( point, index ) => { if ( window.google ) { return ( Date: Fri, 12 Oct 2018 16:41:42 -0400 Subject: [PATCH 036/107] Comments, readability improvements, clean-up. --- .../extensions/map-block/add-point/index.js | 11 +- .../gutenberg/extensions/map-block/config.js | 9 +- .../gutenberg/extensions/map-block/index.js | 16 +- .../extensions/map-block/info-window/index.js | 11 + .../map-block/location-search/index.js | 18 +- .../extensions/map-block/map-component.js | 277 +++++++++++------- .../extensions/map-block/map-marker/index.js | 10 + .../map-block/map-theme-picker/index.js | 2 + 8 files changed, 228 insertions(+), 126 deletions(-) diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index d0d4b76eec51ff..56d871c560e616 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -27,6 +27,7 @@ import './style.scss'; export class AddPoint extends Component { constructor() { + super( ...arguments ) this.state = { isVisible: false @@ -34,26 +35,33 @@ export class AddPoint extends Component { this.onAddPoint = this.onAddPoint.bind( this ); this.hidePopover = this.hidePopover.bind( this ); this.hideSelf = this.hideSelf.bind( this ); + } hidePopover( e ){ + this.setState( { popoverVisible: false } ); if ( e ) { e.stopPropagation(); } + } hideSelf() { + this.setState( { isVisible: false } ); + } onAddPoint( point ) { + this.props.onAddPoint( point ); this.hidePopover(); + } render() { - const { isVisible } = this.state; + const { showPopover, hidePopover, @@ -61,6 +69,7 @@ export class AddPoint extends Component { setState, hideSelf } = this; + const { isVisible } = this.state; if ( ! isVisible ) { return null; diff --git a/client/gutenberg/extensions/map-block/config.js b/client/gutenberg/extensions/map-block/config.js index c25d27561e6418..815b84d0932686 100644 --- a/client/gutenberg/extensions/map-block/config.js +++ b/client/gutenberg/extensions/map-block/config.js @@ -48,12 +48,6 @@ export const CONFIG = { longitude: -122.41941550000001 } }, - focus_mode: { - type: 'object', - default: { - type: 'fit_markers' - } - }, marker_color: { type: 'string', default: 'red' @@ -351,5 +345,6 @@ export const CONFIG = { 'right', 'wide', 'full' - ] + ], + markerIcon: }; diff --git a/client/gutenberg/extensions/map-block/index.js b/client/gutenberg/extensions/map-block/index.js index a0c90933759709..c6d30a47968c2d 100644 --- a/client/gutenberg/extensions/map-block/index.js +++ b/client/gutenberg/extensions/map-block/index.js @@ -57,9 +57,17 @@ registerBlockType( CONFIG.name, { } }, edit: function( { attributes, setAttributes, className } ) { - const { the_caption, map_style, points, zoom, map_center, focus_mode, marker_color, align } = attributes; + const { + the_caption, + map_style, + points, + zoom, + map_center, + marker_color, + align + } = attributes; const updateAlignment = ( value ) => setAttributes( { align: value } ); - const markerIcon = ; + const markerIcon = CONFIG.markerIcon; const mapRef = createRef(); const inspectorControls = ( @@ -104,7 +112,6 @@ registerBlockType( CONFIG.name, { points={ points } zoom={ zoom } map_center={ map_center } - focus_mode={ focus_mode } marker_color={ marker_color } onSetZoom={ ( value ) => { setAttributes( { zoom: value } ) } } api_key={ CONFIG.GOOGLE_MAPS_API_KEY } @@ -125,7 +132,7 @@ registerBlockType( CONFIG.name, { ); }, save: function( { attributes, className } ) { - const { the_caption, map_style, points, zoom, map_center, focus_mode, marker_color, align } = attributes; + const { the_caption, map_style, points, zoom, map_center, marker_color, align } = attributes; const atavistAlignClass = ( value ) => { switch ( value ) { case 'left': @@ -148,7 +155,6 @@ registerBlockType( CONFIG.name, { data-points={ JSON.stringify( points ) } data-zoom={ zoom } data-map_center={ JSON.stringify( map_center ) } - data-focus_mode={ JSON.stringify( focus_mode ) } data-marker_color={ marker_color } data-api_key={ CONFIG.GOOGLE_MAPS_API_KEY } > diff --git a/client/gutenberg/extensions/map-block/info-window/index.js b/client/gutenberg/extensions/map-block/info-window/index.js index 608c7113f6f859..4efcfd8ae2d0b8 100644 --- a/client/gutenberg/extensions/map-block/info-window/index.js +++ b/client/gutenberg/extensions/map-block/info-window/index.js @@ -19,35 +19,46 @@ import { export class InfoWindow extends Component { componentDidMount() { + this.el = document.createElement( 'DIV' ); this.infowindow = new google.maps.InfoWindow( { content: this.el } ); + } componentDidUpdate( prevProps ) { + if ( this.props.activeMarker !== prevProps.activeMarker ) { this.props.activeMarker ? this.openWindow() : this.closeWindow(); } + } render() { + + // Use React portal to render components directly into the Google Maps info window. return this.el ? createPortal( this.props.children, this.el, ) : null; + } openWindow() { + this.infowindow .open( this.props.map, this.props.activeMarker.marker ); + } closeWindow() { + this.infowindow.close(); + } } diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js index 1bb888c7954413..06379e8357dbe3 100644 --- a/client/gutenberg/extensions/map-block/location-search/index.js +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -26,9 +26,11 @@ import './style.scss'; export class LocationSearch extends Component { constructor() { - super( ...arguments ) - this.textRef = createRef() - this.testRef = createRef() + + super( ...arguments ); + + this.textRef = createRef(); + this.testRef = createRef(); this.state = { isEmpty: true }; @@ -45,11 +47,12 @@ export class LocationSearch extends Component { getOptionCompletion: this.getOptionCompletion.bind(this) } ]; + } getOptionCompletion( option ) { + const placesService = new window.google.maps.places.PlacesService( this.testRef.current ); - this.textRef.current.focus(); placesService.getDetails( { placeId: option.place_id }, function( place ) { const point = { place_title: option.description, @@ -65,9 +68,11 @@ export class LocationSearch extends Component { this.props.onAddPoint( point ); }.bind(this)); return option.description; + } search() { + const searchText = this.textRef.current.innerText; const placeSearch = new window.google.maps.places.AutocompleteService() if ( searchText.length < 2 ) return @@ -82,13 +87,17 @@ export class LocationSearch extends Component { } }); }); + } searchChanged( e ) { + this.setState( { isEmpty: e.target.innerText.length < 1 } ); + } render() { + const { label } = this.props; const classes = classnames( 'input-control', @@ -114,6 +123,7 @@ export class LocationSearch extends Component {
); + } } diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index bfbbcdbd362f82..b25916dca9fc10 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -35,19 +35,24 @@ import MapMarker from './map-marker/'; import InfoWindow from './info-window/'; import AddPoint from './add-point'; +// @TODO: replace with import from lib/load-script after resolution of https://github.com/Automattic/wp-calypso/issues/27821 import { loadScript } from './load-script'; // import { loadScript } from 'lib/load-script'; export class Map extends Component { + // Lifecycle constructor() { + super( ...arguments ); - this.mapRef = createRef(); + this.state = { map: null, fit_to_bounds: false, loaded: false }; + + // Event Handlers as methods this.sizeMap = this.sizeMap.bind( this ); this.onMarkerClick = this.onMarkerClick.bind( this ); this.deleteActiveMarker = this.deleteActiveMarker.bind( this ); @@ -57,52 +62,10 @@ export class Map extends Component { this.setBoundsByMarkers = this.setBoundsByMarkers.bind( this ); this.scriptsLoaded = this.scriptsLoaded.bind( this ); + // Refs + this.mapRef = createRef(); this.addPointRef = React.createRef(); - } - - onMarkerClick( marker ) { - this.setState( { activeMarker: marker } ); - this.setAddPointVisibility( false ); - } - - onMapClick() { - this.setState( { activeMarker: null } ); - } - - addPoint( point ) { - this.setAddPointVisibility( false ); - const { points } = this.props; - const newPoints = clone( points ); - newPoints.push( point ); - this.props.onSetPoints( newPoints ); - } - - deleteActiveMarker() { - const { points } = this.props; - const { activeMarker } = this.state; - const { index } = activeMarker.props; - const newPoints = clone( points ); - newPoints.splice( index, 1 ); - this.props.onSetPoints( newPoints ); - this.setState( { activeMarker: null } ); - } - updateActiveMarker( updates) { - const { points } = this.props; - const { activeMarker } = this.state; - const { index } = activeMarker.props; - const newPoints = clone( points ); - assign( newPoints[ index ], updates ); - this.props.onSetPoints( newPoints ); - } - - setAddPointVisibility( visible = true ) { - if ( this.addPointRef.current ) { - this.addPointRef.current.setState( { isVisible: visible } ); - } - if ( visible ) { - this.setState( { activeMarker: null } ); - } } render() { @@ -123,29 +86,30 @@ export class Map extends Component { addPoint } = this; - const mapMarkers = ( map ) && points.map( ( point, index ) => { - if ( window.google ) { - return ( - - ); - } + const mapMarkers = ( map && window.google ) && points.map( ( point, index ) => { + + return ( + + ); + }); - const point = get( activeMarker, 'props.point' ) || {}; + + const currentPoint = get( activeMarker, 'props.point' ) || {}; const { title, caption - } = point; + } = currentPoint; - const infoWindow = window.google ? + const infoWindow = ( window.google ) && ( - ) : null; + ); + return (
@@ -197,12 +162,14 @@ export class Map extends Component { } componentDidMount() { + this.loadMapLibraries(); + } - /* Observers */ - /* This implementation of componentDidUpdate is a reusable way to approximate Polymer observers */ + // This implementation of componentDidUpdate is a reusable way to approximate Polymer observers componentDidUpdate( prevProps ) { + for ( const propName in this.props ) { const functionName = propName + 'Changed'; if ( @@ -212,24 +179,100 @@ export class Map extends Component { this[ functionName ]( this.props[ propName ] ); } } + } + // Observers pointsChanged() { + this.setBoundsByMarkers(); + } map_styleChanged() { + const { map } = this.state; - if ( ! map ) { - return; - } map.setOptions( { styles: this.getMapStyle(), mapTypeId: window.google.maps.MapTypeId[ this.getMapType() ], } ); + + } + + // Event handling + onMarkerClick( marker ) { + + this.setState( { activeMarker: marker } ); + this.setAddPointVisibility( false ); + + } + + onMapClick() { + + this.setState( { activeMarker: null } ); + + } + + addPoint( point ) { + + const { points } = this.props; + const newPoints = clone( points ); + + newPoints.push( point ); + this.props.onSetPoints( newPoints ); + + this.setAddPointVisibility( false ); + + } + + updateActiveMarker( updates) { + + const { points } = this.props; + const { activeMarker } = this.state; + const { index } = activeMarker.props; + const newPoints = clone( points ); + + assign( newPoints[ index ], updates ); + this.props.onSetPoints( newPoints ); + + } + + deleteActiveMarker() { + + const { points } = this.props; + const { activeMarker } = this.state; + const { index } = activeMarker.props; + const newPoints = clone( points ); + + newPoints.splice( index, 1 ); + this.props.onSetPoints( newPoints ); + this.setState( { activeMarker: null } ); + + } + + setAddPointVisibility( visible = true ) { + + if ( this.addPointRef.current ) { + this.addPointRef.current.setState( { isVisible: visible } ); + } + if ( visible ) { + this.setState( { activeMarker: null } ); + } + + } + + // Various map functions + sizeMap() { + const mapEl = this.mapRef.current; + const blockWidth = mapEl.offsetWidth; + const maxHeight = window.innerHeight * 0.8; + const blockHeight = Math.min( blockWidth * ( 3 / 4 ), maxHeight ); + mapEl.style.height = blockHeight + 'px'; } + // Calculate the appropriate zoom and center point of the map based on defined markers setBoundsByMarkers() { + const { focus_mode, zoom, @@ -241,15 +284,12 @@ export class Map extends Component { activeMarker } = this.state; - if ( ! map || focus_mode.type !== 'fit_markers' || points.length === 0 ) { - return; - } + const bounds = new window.google.maps.LatLngBounds(); - if ( activeMarker ) { + if ( ! map || ! points.length || activeMarker ) { return; } - const bounds = new window.google.maps.LatLngBounds(); points.forEach( point => { bounds.extend( new window.google.maps.LatLng( point.coordinates.latitude, point.coordinates.longitude ) @@ -257,49 +297,89 @@ export class Map extends Component { } ); map.setCenter( bounds.getCenter() ); + + // If there are multiple points, zoom is determined by the area they cover, + // and zoom control is removed. if ( points.length > 1 ) { + map.fitBounds( bounds ); this.setState( { fit_to_bounds: true } ); map.setOptions( { zoomControl: false } ); - } else { - map.setZoom( parseInt( zoom, 10 ) ); - this.setState( { fit_to_bounds: false } ); - map.setOptions( { zoomControl: true } ); + return; + } + + // If there are one (or zero) points, user can set zoom + map.setZoom( parseInt( zoom, 10 ) ); + this.setState( { fit_to_bounds: false } ); + map.setOptions( { zoomControl: true } ); + } getMapStyle() { + return CONFIG.styles[ this.props.map_style ].styles; + } getMapType() { + return CONFIG.styles[ this.props.map_style ].map_type; + } + getMarkerIcon() { + + const { marker_color } = this.props; + const svgPath = { + path: 'M16,38 C16,38 32,26.692424 32,16 C32,5.307576 24.836556,0 16,0 C7.163444,0 0,5.307576 0,16 C0,26.692424 16,38 16,38 Z', + fillColor: marker_color, + fillOpacity: 0.8, + scale: 1, + strokeWeight: 0 + }; + return svgPath; + + } + + // Script loading, browser geolocation scriptsLoaded() { + const { map_center, points } = this.props; this.setState({ loaded: true }); + + // If the map has any points, skip geolocation and use what we have. if ( points.length > 0 ) { - this.init( map_center ); + this.initMap( map_center ); return; } - this.getMapCenter() + + // If there are no points, attempt to use geolocation to center the map on + // the user's current location. + + const getMapCenter = () => { + return new Promise(function (resolve, reject) { + navigator.geolocation.getCurrentPosition(resolve, reject) + }) + } + getMapCenter() .then( ( position ) => { - this.init( { + this.initMap( { latitude: position.coords.latitude, longitude: position.coords.longitude } ); }) .catch( ( err ) => { - this.init( map_center ); + this.initMap( map_center ); } ); } loadMapLibraries() { + const { api_key } = this.props; const src = [ @@ -314,35 +394,12 @@ export class Map extends Component { } this.scriptsLoaded(); } ); - } - getMapCenter = function ( options ) { - return new Promise(function (resolve, reject) { - navigator.geolocation.getCurrentPosition(resolve, reject, options) - }) } - getMarkerIcon() { - const { marker_color } = this.props; - const svgPath = { - path: 'M16,38 C16,38 32,26.692424 32,16 C32,5.307576 24.836556,0 16,0 C7.163444,0 0,5.307576 0,16 C0,26.692424 16,38 16,38 Z', - fillColor: marker_color, - fillOpacity: 0.8, - scale: 1, - strokeWeight: 0 - }; - return svgPath; - } - - sizeMap() { - const mapEl = this.mapRef.current; - const blockWidth = mapEl.offsetWidth; - const maxHeight = window.innerHeight * 0.8; - const blockHeight = Math.min( blockWidth * ( 3 / 4 ), maxHeight ); - mapEl.style.height = blockHeight + 'px'; - } + // Create the map object. + initMap( map_center ) { - init( map_center ) { const { points, zoom @@ -373,7 +430,9 @@ export class Map extends Component { }.bind( this ) ); map.addListener( 'click', this.onMapClick ); + this.setState( { map }, () => { + this.sizeMap(); this.mapRef.current.addEventListener( 'alignmentChanged', this.sizeMap ); window.addEventListener( 'resize', this.sizeMap ); @@ -382,7 +441,9 @@ export class Map extends Component { this.setBoundsByMarkers(); this.setAddPointVisibility( true ); this.setState( { loaded: true } ); + }); + } } @@ -391,13 +452,11 @@ Map.defaultProps = { map_style: 'default', zoom: 13, onSetZoom: () => {}, + // Default center point is San Francisco map_center: { latitude: 37.7749295, longitude: -122.41941550000001 }, - focus_mode: { - type: 'fit_markers', - }, marker_color: 'red', api_key: null, }; diff --git a/client/gutenberg/extensions/map-block/map-marker/index.js b/client/gutenberg/extensions/map-block/map-marker/index.js index 5c4e165c0cfec9..d4e6ca84a72152 100644 --- a/client/gutenberg/extensions/map-block/map-marker/index.js +++ b/client/gutenberg/extensions/map-block/map-marker/index.js @@ -15,12 +15,16 @@ import { Component } from '@wordpress/element'; export class MapMarker extends Component { constructor() { + super( ...arguments ); this.handleClick = this.handleClick.bind( this ); + } componentDidMount() { + this.renderMarker(); + } componentWillUnmount() { @@ -31,12 +35,16 @@ export class MapMarker extends Component { } componentDidUpdate( prevProps ) { + this.renderMarker(); + } handleClick( e ) { + const { onClick, point } = this.props; onClick( this ); + } renderMarker() { @@ -67,7 +75,9 @@ export class MapMarker extends Component { } render() { + return null; + } } diff --git a/client/gutenberg/extensions/map-block/map-theme-picker/index.js b/client/gutenberg/extensions/map-block/map-theme-picker/index.js index 2b7de60a33fdc7..312be46f573ac6 100644 --- a/client/gutenberg/extensions/map-block/map-theme-picker/index.js +++ b/client/gutenberg/extensions/map-block/map-theme-picker/index.js @@ -29,6 +29,7 @@ import './style.scss'; export class MapThemePicker extends Component { render() { + const { options, value, @@ -60,6 +61,7 @@ export class MapThemePicker extends Component { ); + } } From 480696ce67788ac03cee9e1fe3ef70a59c2052d4 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 16:52:01 -0400 Subject: [PATCH 037/107] TextareaControl instead of TextControl for caption field in popover. --- .../gutenberg/extensions/map-block/map-component.js | 13 ++++++++----- client/gutenberg/extensions/map-block/style.scss | 3 --- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index b25916dca9fc10..450e1fb20a6ee1 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -13,6 +13,7 @@ import { import { Button, Dashicon, + TextareaControl, TextControl } from '@wordpress/components'; @@ -120,13 +121,15 @@ export class Map extends Component { updateActiveMarker( { title } ) } /> - updateActiveMarker( { caption } ) } /> + > + Delete Marker + ); return ( From fb7666edaf99852c5580cc7496e7a79f0ea349ce Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 21:27:36 -0400 Subject: [PATCH 039/107] Fixes to two bugs that could break clickable markers. THe first prevents double loading of the Google Maps script in cases where there are multiple Map blocks on a page or where an instance is deleted and reinserted without reload. The second addresses the case where a marker is clicked, the info window is closed by clicking the X and then the marker is clicked a second time. --- .../extensions/map-block/info-window/index.js | 15 ++++++ .../extensions/map-block/map-component.js | 47 ++++++++++++------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/client/gutenberg/extensions/map-block/info-window/index.js b/client/gutenberg/extensions/map-block/info-window/index.js index 4efcfd8ae2d0b8..7160e83021cccf 100644 --- a/client/gutenberg/extensions/map-block/info-window/index.js +++ b/client/gutenberg/extensions/map-block/info-window/index.js @@ -18,12 +18,20 @@ import { export class InfoWindow extends Component { + constructor() { + + super( ...arguments ); + this.closeClick = this.closeClick.bind( this ); + + } + componentDidMount() { this.el = document.createElement( 'DIV' ); this.infowindow = new google.maps.InfoWindow( { content: this.el } ); + google.maps.event.addListener( this.infowindow,'closeclick', this.closeClick ); } @@ -48,6 +56,12 @@ export class InfoWindow extends Component { } + closeClick() { + + this.props.unsetActiveMarker(); + + } + openWindow() { this.infowindow @@ -63,6 +77,7 @@ export class InfoWindow extends Component { } InfoWindow.defaultProps = { + unsetActiveMarker: () => {}, activeMarker: null, map: null } diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index 450e1fb20a6ee1..a08250d12330b8 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -50,7 +50,8 @@ export class Map extends Component { this.state = { map: null, fit_to_bounds: false, - loaded: false + loaded: false, + google: null }; // Event Handlers as methods @@ -77,7 +78,8 @@ export class Map extends Component { const { map, - activeMarker + activeMarker, + google, } = this.state; const { @@ -87,7 +89,7 @@ export class Map extends Component { addPoint } = this; - const mapMarkers = ( map && window.google ) && points.map( ( point, index ) => { + const mapMarkers = ( map && google ) && points.map( ( point, index ) => { return ( @@ -110,12 +112,13 @@ export class Map extends Component { caption } = currentPoint; - const infoWindow = ( window.google ) && + const infoWindow = ( google ) && ( this.setState( { activeMarker: null } ) } > { activeMarker && admin && @@ -194,10 +197,14 @@ export class Map extends Component { map_styleChanged() { - const { map } = this.state; + const { + map, + google + } = this.state; + map.setOptions( { styles: this.getMapStyle(), - mapTypeId: window.google.maps.MapTypeId[ this.getMapType() ], + mapTypeId: google.maps.MapTypeId[ this.getMapType() ], } ); } @@ -284,10 +291,11 @@ export class Map extends Component { const { map, - activeMarker + activeMarker, + google } = this.state; - const bounds = new window.google.maps.LatLngBounds(); + const bounds = new google.maps.LatLngBounds(); if ( ! map || ! points.length || activeMarker ) { return; @@ -295,7 +303,7 @@ export class Map extends Component { points.forEach( point => { bounds.extend( - new window.google.maps.LatLng( point.coordinates.latitude, point.coordinates.longitude ) + new google.maps.LatLng( point.coordinates.latitude, point.coordinates.longitude ) ); } ); @@ -390,12 +398,17 @@ export class Map extends Component { api_key, '&libraries=places' ].join( '' ); + if ( window.google ) { + this.setState( { google: window.google }, this.scriptsLoaded ); + return; + } + loadScript( src, ( error ) => { if ( error ) { console.log( 'Script ' + error.src + ' failed to load.' ); return; } - this.scriptsLoaded(); + this.setState( { google: window.google }, this.scriptsLoaded ); } ); } @@ -403,6 +416,8 @@ export class Map extends Component { // Create the map object. initMap( map_center ) { + const { google } = this.state; + const { points, zoom @@ -417,11 +432,11 @@ export class Map extends Component { style: 'SMALL', }, styles: this.getMapStyle(), - mapTypeId: window.google.maps.MapTypeId[ this.getMapType() ], + mapTypeId: google.maps.MapTypeId[ this.getMapType() ], zoom: parseInt( zoom, 10 ), }; - const map = new window.google.maps.Map( + const map = new google.maps.Map( this.mapRef.current, mapOptions ); @@ -439,8 +454,8 @@ export class Map extends Component { this.sizeMap(); this.mapRef.current.addEventListener( 'alignmentChanged', this.sizeMap ); window.addEventListener( 'resize', this.sizeMap ); - window.google.maps.event.trigger( map, 'resize' ); - map.setCenter( new window.google.maps.LatLng( map_center.latitude, map_center.longitude ) ); + google.maps.event.trigger( map, 'resize' ); + map.setCenter( new google.maps.LatLng( map_center.latitude, map_center.longitude ) ); this.setBoundsByMarkers(); this.setAddPointVisibility( true ); this.setState( { loaded: true } ); From ba0f0653cc41b463543efca4ebfc7f927af4b9ec Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 21:38:44 -0400 Subject: [PATCH 040/107] Right padding to separate the arrow in nested panels from the text. --- client/gutenberg/extensions/map-block/locations/style.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/gutenberg/extensions/map-block/locations/style.scss b/client/gutenberg/extensions/map-block/locations/style.scss index 58ad8b0262e1cd..9512f016d2db18 100644 --- a/client/gutenberg/extensions/map-block/locations/style.scss +++ b/client/gutenberg/extensions/map-block/locations/style.scss @@ -9,4 +9,7 @@ max-width: 100%; margin: 0; } + .components-panel__body button { + padding-right: 40px; + } } From 3181a22966c95baf0cf9499a85bc70c2bcee722b Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 21:42:55 -0400 Subject: [PATCH 041/107] Removing unused subcomponents directory. Will be reinstated in future commits for blocks that make use of them. --- .../subcomponents/AtavistSearch/index.js | 61 ------------------- .../subcomponents/AtavistSearch/style.scss | 46 -------------- 2 files changed, 107 deletions(-) delete mode 100644 client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/index.js delete mode 100644 client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/style.scss diff --git a/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/index.js b/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/index.js deleted file mode 100644 index aa7853c3e15ad4..00000000000000 --- a/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/index.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Wordpress dependencies - */ - -import { Component, createRef } from '@wordpress/element'; - -/** - * External dependencies - */ - - import classnames from 'classnames'; - -/** - * Internal dependencies - */ - -import './style.scss'; - -export class AtavistSearch extends Component { - constructor() { - super( ...arguments ); - this.searchClicked = this.searchClicked.bind(this); - this.inputRef = createRef(); - this.state = { - isShown: false - }; - } - componentDidMount() { - this.searchClicked = this.searchClicked.bind(this); - // document.addEventListener('mousedown', this._activity_outside.bind(this)); - } - searchClicked(e) { - const { isShown } = this.state; - this.setState( { isShown: ! isShown } ); - this.inputRef.current.focus(); - } - render() { - const { isShown } = this.state; - const { searchClicked, inputRef } = this; - const classes = classnames( 'atavist-search', isShown ? 'show' : 'hide' ); - return ( -
-
- - - - - - -
-
- -
-
- ); - } -} - -export default AtavistSearch; diff --git a/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/style.scss b/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/style.scss deleted file mode 100644 index b88c26835c9839..00000000000000 --- a/client/gutenberg/extensions/shared/atavist/subcomponents/AtavistSearch/style.scss +++ /dev/null @@ -1,46 +0,0 @@ -.atavist-search { - min-width: 25px; - min-height: 25px; - cursor: pointer; - overflow: hidden; - position: relative; - svg { - width: 100%; - height: 100%; - } - .search-icon { - width: 16px; - height: 16px; - position: absolute; - top: 50%; - left: 0; - margin-top: -8px; - } - input[type=text] { - width: 0px; - -webkit-transition: width 0.3s ease; - -moz-transition: width 0.3s ease; - -o-transition: width 0.3s ease; - transition: width 0.3s ease; - background: none; - border: none; - outline: none; - cursor: pointer; - } - &.show input[type=text], - &.show input[type=text]:focus { - width: 200px; - cursor: initial; - } - &:not(.show) input[type=text] { - border: none !important; - } - input[type=text] { - border-bottom: 1px solid gray; - border-radius: 0; - padding: 0 0 0 25px; - margin: 0; - height: 30px; - font-size: 1em; - } -} From 3df859c2321895a8231aac0a7148544abd425277 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 21:44:09 -0400 Subject: [PATCH 042/107] Removing console log statement. --- client/gutenberg/extensions/map-block/map-component.js | 1 - 1 file changed, 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index a08250d12330b8..346a428a6c8408 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -405,7 +405,6 @@ export class Map extends Component { loadScript( src, ( error ) => { if ( error ) { - console.log( 'Script ' + error.src + ' failed to load.' ); return; } this.setState( { google: window.google }, this.scriptsLoaded ); From b2b70f7c8b37ecd5c836ff31c504ffbaaa3e653d Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 22:02:32 -0400 Subject: [PATCH 043/107] Circle CI lint & translate issues. --- .../extensions/map-block/add-point/index.js | 8 +------- client/gutenberg/extensions/map-block/index.js | 3 +-- .../extensions/map-block/info-window/index.js | 5 +++-- .../extensions/map-block/locations/index.js | 9 +++------ .../extensions/map-block/map-component.js | 18 ++++++------------ .../extensions/map-block/map-marker/index.js | 9 ++++----- .../map-block/map-theme-picker/index.js | 4 +--- 7 files changed, 19 insertions(+), 37 deletions(-) diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index 56d871c560e616..75b4594ea117b3 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -33,17 +33,13 @@ export class AddPoint extends Component { isVisible: false }; this.onAddPoint = this.onAddPoint.bind( this ); - this.hidePopover = this.hidePopover.bind( this ); this.hideSelf = this.hideSelf.bind( this ); } - hidePopover( e ){ + hidePopover() { this.setState( { popoverVisible: false } ); - if ( e ) { - e.stopPropagation(); - } } @@ -64,9 +60,7 @@ export class AddPoint extends Component { const { showPopover, - hidePopover, onAddPoint, - setState, hideSelf } = this; const { isVisible } = this.state; diff --git a/client/gutenberg/extensions/map-block/index.js b/client/gutenberg/extensions/map-block/index.js index 12a8980f08f6bc..d8ee038e69424c 100644 --- a/client/gutenberg/extensions/map-block/index.js +++ b/client/gutenberg/extensions/map-block/index.js @@ -30,7 +30,6 @@ import { */ import classnames from 'classnames'; -import { clone } from 'lodash'; /** * Internal dependencies @@ -96,7 +95,7 @@ registerBlockType( CONFIG.name, { setAttributes( { marker_color } ) } + onChange={ ( value ) => setAttributes( { marker_color: value } ) } /> diff --git a/client/gutenberg/extensions/map-block/info-window/index.js b/client/gutenberg/extensions/map-block/info-window/index.js index 7160e83021cccf..67090757d8e14a 100644 --- a/client/gutenberg/extensions/map-block/info-window/index.js +++ b/client/gutenberg/extensions/map-block/info-window/index.js @@ -4,7 +4,6 @@ import { Component, - Fragment, createPortal } from '@wordpress/element'; @@ -27,6 +26,7 @@ export class InfoWindow extends Component { componentDidMount() { + const { google } = this.props; this.el = document.createElement( 'DIV' ); this.infowindow = new google.maps.InfoWindow( { content: this.el @@ -79,7 +79,8 @@ export class InfoWindow extends Component { InfoWindow.defaultProps = { unsetActiveMarker: () => {}, activeMarker: null, - map: null + map: null, + google: null } export default InfoWindow; diff --git a/client/gutenberg/extensions/map-block/locations/index.js b/client/gutenberg/extensions/map-block/locations/index.js index 6086d111defdf1..0daa895fd21e49 100644 --- a/client/gutenberg/extensions/map-block/locations/index.js +++ b/client/gutenberg/extensions/map-block/locations/index.js @@ -23,10 +23,7 @@ import './style.scss'; * External dependencies */ -import { - clone, - concat -} from 'lodash'; +import { clone } from 'lodash'; export class Locations extends Component { @@ -45,7 +42,7 @@ export class Locations extends Component { onChange } = this.props; - let newPoints = clone( points ); + const newPoints = clone( points ); newPoints.splice( index, 1 ); onChange( newPoints ); } @@ -56,7 +53,7 @@ export class Locations extends Component { onChange } = this.props; - let newPoints = clone( points ); + const newPoints = clone( points ); newPoints[index][field] = value; onChange( newPoints ); } diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index 346a428a6c8408..326f921cc0104d 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -66,7 +66,7 @@ export class Map extends Component { // Refs this.mapRef = createRef(); - this.addPointRef = React.createRef(); + this.addPointRef = createRef(); } @@ -117,7 +117,7 @@ export class Map extends Component { this.setState( { activeMarker: null } ) } > { activeMarker && admin && @@ -125,7 +125,7 @@ export class Map extends Component { updateActiveMarker( { title } ) } + onChange={ ( value ) => updateActiveMarker( { title: value } ) } /> updateActiveMarker( { caption } ) } + onChange={ ( value ) => updateActiveMarker( { caption: value } ) } /> From 97a30bc227ee13b86044f3a3f2f6ed5840908e53 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 12 Oct 2018 22:06:02 -0400 Subject: [PATCH 044/107] Removed incorrect second key attribute. --- client/gutenberg/extensions/map-block/locations/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/gutenberg/extensions/map-block/locations/index.js b/client/gutenberg/extensions/map-block/locations/index.js index 0daa895fd21e49..fa3e43f1dc8135 100644 --- a/client/gutenberg/extensions/map-block/locations/index.js +++ b/client/gutenberg/extensions/map-block/locations/index.js @@ -53,7 +53,7 @@ export class Locations extends Component { onChange } = this.props; - const newPoints = clone( points ); + let newPoints = clone( points ); newPoints[index][field] = value; onChange( newPoints ); } @@ -61,7 +61,7 @@ export class Locations extends Component { render() { const { points } = this.props; const rows = points.map( ( point, index ) => - + Date: Fri, 12 Oct 2018 22:10:46 -0400 Subject: [PATCH 045/107] Missed one linting fix. --- client/gutenberg/extensions/map-block/locations/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/locations/index.js b/client/gutenberg/extensions/map-block/locations/index.js index fa3e43f1dc8135..df8ae0742f7b09 100644 --- a/client/gutenberg/extensions/map-block/locations/index.js +++ b/client/gutenberg/extensions/map-block/locations/index.js @@ -53,7 +53,7 @@ export class Locations extends Component { onChange } = this.props; - let newPoints = clone( points ); + const newPoints = clone( points ); newPoints[index][field] = value; onChange( newPoints ); } From 68ffb7ab0b7e96ee6f9dd37f2a5b68fe0ff58cbe Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Sat, 13 Oct 2018 00:06:34 -0400 Subject: [PATCH 046/107] Switch to Theme Colors for Marker Color. --- .../gutenberg/extensions/map-block/index.js | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/client/gutenberg/extensions/map-block/index.js b/client/gutenberg/extensions/map-block/index.js index d8ee038e69424c..98a7592a706ef4 100644 --- a/client/gutenberg/extensions/map-block/index.js +++ b/client/gutenberg/extensions/map-block/index.js @@ -7,7 +7,6 @@ import { __ } from '@wordpress/i18n'; import { registerBlockType } from '@wordpress/blocks'; import { - ColorPalette, IconButton, PanelBody, Toolbar @@ -17,7 +16,8 @@ import { RichText, InspectorControls, BlockControls, - BlockAlignmentToolbar + BlockAlignmentToolbar, + PanelColorSettings } from '@wordpress/editor'; import { @@ -91,13 +91,15 @@ registerBlockType( CONFIG.name, { options={ CONFIG.map_styleOptions } /> - - setAttributes( { marker_color: value } ) } - /> - + setAttributes( { marker_color: value } ), + label: 'Marker Color' + } ] } + /> Date: Sat, 13 Oct 2018 13:13:48 -0400 Subject: [PATCH 047/107] Removal of an unused event, fix to the z-index of the Add Point popover. --- client/gutenberg/extensions/map-block/add-point/index.js | 2 -- client/gutenberg/extensions/map-block/add-point/style.scss | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index 75b4594ea117b3..402da779d6d11f 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -59,7 +59,6 @@ export class AddPoint extends Component { render() { const { - showPopover, onAddPoint, hideSelf } = this; @@ -71,7 +70,6 @@ export class AddPoint extends Component { return ( + ) ) } +
+
+ ) } +
+ ); + } +} + +export default compose( [ + withInstanceId, + withFocusOutside, // this MUST be the innermost HOC as it calls handleFocusOutside +] )( Lookup ); From de0ae1cbb3b4a78bacc76792bf2c9a0a8b0ded52 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Tue, 16 Oct 2018 22:06:57 -0400 Subject: [PATCH 052/107] Removing caption. --- client/gutenberg/extensions/map-block/config.js | 4 ---- client/gutenberg/extensions/map-block/index.js | 12 +----------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/client/gutenberg/extensions/map-block/config.js b/client/gutenberg/extensions/map-block/config.js index b271858d7caeef..0592ca2df6ed11 100644 --- a/client/gutenberg/extensions/map-block/config.js +++ b/client/gutenberg/extensions/map-block/config.js @@ -25,10 +25,6 @@ export const CONFIG = { align: { type: 'string' }, - the_caption: { - source: 'text', - selector: '.atavist-caption' - }, points: { type: 'array', default: [] diff --git a/client/gutenberg/extensions/map-block/index.js b/client/gutenberg/extensions/map-block/index.js index 8c2a6c162997b6..d20543fbf8f788 100644 --- a/client/gutenberg/extensions/map-block/index.js +++ b/client/gutenberg/extensions/map-block/index.js @@ -13,7 +13,6 @@ import { } from '@wordpress/components'; import { - RichText, InspectorControls, BlockControls, BlockAlignmentToolbar, @@ -57,7 +56,6 @@ registerBlockType( CONFIG.name, { }, edit: function( { attributes, setAttributes, className } ) { const { - the_caption, map_style, points, zoom, @@ -133,19 +131,12 @@ registerBlockType( CONFIG.name, { setAttributes( { points: value } ) } } /> - setAttributes( { the_caption: value } ) } - />
); }, save: function( { attributes, className } ) { - const { the_caption, map_style, points, zoom, map_center, marker_color, align } = attributes; + const { map_style, points, zoom, map_center, marker_color, align } = attributes; const atavistAlignClass = ( value ) => { switch ( value ) { case 'left': @@ -172,7 +163,6 @@ registerBlockType( CONFIG.name, { data-api_key={ CONFIG.GOOGLE_MAPS_API_KEY } >
-

{ the_caption }

); } From cf870343def07e01608b8e44eba7c18942124a28 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 17 Oct 2018 10:22:21 -0400 Subject: [PATCH 053/107] Removing Geolocation feature - too slow and too invasive without a positive enough outcome. --- .../extensions/map-block/map-component.js | 255 ++++++------------ 1 file changed, 79 insertions(+), 176 deletions(-) diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index 326f921cc0104d..db91b693ce1c61 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -4,28 +4,15 @@ * Wordpress dependencies */ -import { - Component, - createRef, - Fragment -} from '@wordpress/element'; - -import { - Button, - Dashicon, - TextareaControl, - TextControl -} from '@wordpress/components'; +import { Component, createRef, Fragment } from '@wordpress/element'; + +import { Button, Dashicon, TextareaControl, TextControl } from '@wordpress/components'; /** * External dependencies */ -import { - get, - clone, - assign -} from 'lodash'; +import { get, clone, assign } from 'lodash'; /** * Internal dependencies @@ -41,17 +28,15 @@ import { loadScript } from './load-script'; // import { loadScript } from 'lib/load-script'; export class Map extends Component { - // Lifecycle constructor() { - super( ...arguments ); this.state = { map: null, fit_to_bounds: false, loaded: false, - google: null + google: null, }; // Event Handlers as methods @@ -67,92 +52,74 @@ export class Map extends Component { // Refs this.mapRef = createRef(); this.addPointRef = createRef(); - } render() { - const { - points, - admin - } = this.props; - - const { - map, - activeMarker, - google, - } = this.state; - - const { - onMarkerClick, - deleteActiveMarker, - updateActiveMarker, - addPoint - } = this; - - const mapMarkers = ( map && google ) && points.map( ( point, index ) => { - - return ( - - ); - - }); + const { points, admin } = this.props; + + const { map, activeMarker, google } = this.state; + + const { onMarkerClick, deleteActiveMarker, updateActiveMarker, addPoint } = this; + + const mapMarkers = + map && + google && + points.map( ( point, index ) => { + return ( + + ); + } ); const currentPoint = get( activeMarker, 'props.point' ) || {}; - const { - title, - caption - } = currentPoint; - - const infoWindow = ( google ) && - ( - this.setState( { activeMarker: null } ) } - > - { activeMarker && admin && + const { title, caption } = currentPoint; + + const infoWindow = google && ( + this.setState( { activeMarker: null } ) } + > + { activeMarker && + admin && ( updateActiveMarker( { title: value } ) } + onChange={ value => updateActiveMarker( { title: value } ) } /> updateActiveMarker( { caption: value } ) } + rows="3" + tag="textarea" + onChange={ value => updateActiveMarker( { caption: value } ) } /> - - } + ) } - { activeMarker && ! admin && + { activeMarker && + ! admin && (

{ title }

{ caption }

- } - -
- ); + ) } +
+ ); return ( @@ -160,22 +127,23 @@ export class Map extends Component { { mapMarkers }
{ infoWindow } - { admin && - - } + { admin && ( + + ) }
); } componentDidMount() { - this.loadMapLibraries(); - } // This implementation of componentDidUpdate is a reusable way to approximate Polymer observers componentDidUpdate( prevProps ) { - for ( const propName in this.props ) { const functionName = propName + 'Changed'; if ( @@ -185,46 +153,33 @@ export class Map extends Component { this[ functionName ]( this.props[ propName ] ); } } - } // Observers pointsChanged() { - this.setBoundsByMarkers(); - } map_styleChanged() { - - const { - map, - google - } = this.state; + const { map, google } = this.state; map.setOptions( { styles: this.getMapStyle(), mapTypeId: google.maps.MapTypeId[ this.getMapType() ], } ); - } // Event handling onMarkerClick( marker ) { - this.setState( { activeMarker: marker } ); this.setAddPointVisibility( false ); - } onMapClick() { - this.setState( { activeMarker: null } ); - } addPoint( point ) { - const { points } = this.props; const newPoints = clone( points ); @@ -232,11 +187,9 @@ export class Map extends Component { this.props.onSetPoints( newPoints ); this.setAddPointVisibility( false ); - } - updateActiveMarker( updates) { - + updateActiveMarker( updates ) { const { points } = this.props; const { activeMarker } = this.state; const { index } = activeMarker.props; @@ -244,11 +197,9 @@ export class Map extends Component { assign( newPoints[ index ], updates ); this.props.onSetPoints( newPoints ); - } deleteActiveMarker() { - const { points } = this.props; const { activeMarker } = this.state; const { index } = activeMarker.props; @@ -257,18 +208,15 @@ export class Map extends Component { newPoints.splice( index, 1 ); this.props.onSetPoints( newPoints ); this.setState( { activeMarker: null } ); - } setAddPointVisibility( visible = true ) { - if ( this.addPointRef.current ) { this.addPointRef.current.setState( { isVisible: visible } ); } if ( visible ) { this.setState( { activeMarker: null } ); } - } // Various map functions @@ -282,17 +230,9 @@ export class Map extends Component { // Calculate the appropriate zoom and center point of the map based on defined markers setBoundsByMarkers() { + const { zoom, points } = this.props; - const { - zoom, - points - } = this.props; - - const { - map, - activeMarker, - google - } = this.state; + const { map, activeMarker, google } = this.state; const bounds = new google.maps.LatLngBounds(); @@ -311,56 +251,44 @@ export class Map extends Component { // If there are multiple points, zoom is determined by the area they cover, // and zoom control is removed. if ( points.length > 1 ) { - map.fitBounds( bounds ); this.setState( { fit_to_bounds: true } ); map.setOptions( { zoomControl: false } ); return; - } // If there are one (or zero) points, user can set zoom map.setZoom( parseInt( zoom, 10 ) ); this.setState( { fit_to_bounds: false } ); map.setOptions( { zoomControl: true } ); - } getMapStyle() { - return CONFIG.styles[ this.props.map_style ].styles; - } getMapType() { - return CONFIG.styles[ this.props.map_style ].map_type; - } getMarkerIcon() { - const { marker_color } = this.props; const svgPath = { - path: 'M16,38 C16,38 32,26.692424 32,16 C32,5.307576 24.836556,0 16,0 C7.163444,0 0,5.307576 0,16 C0,26.692424 16,38 16,38 Z', - fillColor: marker_color, - fillOpacity: 0.8, - scale: 1, - strokeWeight: 0 - }; - return svgPath; - + path: + 'M16,38 C16,38 32,26.692424 32,16 C32,5.307576 24.836556,0 16,0 C7.163444,0 0,5.307576 0,16 C0,26.692424 16,38 16,38 Z', + fillColor: marker_color, + fillOpacity: 0.8, + scale: 1, + strokeWeight: 0, + }; + return svgPath; } // Script loading, browser geolocation scriptsLoaded() { + const { map_center, points } = this.props; - const { - map_center, - points - } = this.props; - - this.setState({ loaded: true }); + this.setState( { loaded: true } ); // If the map has any points, skip geolocation and use what we have. if ( points.length > 0 ) { @@ -368,52 +296,33 @@ export class Map extends Component { return; } - // If there are no points, attempt to use geolocation to center the map on - // the user's current location. - - const getMapCenter = () => { - return new Promise(function (resolve, reject) { - navigator.geolocation.getCurrentPosition(resolve, reject) - }) - } - getMapCenter() - .then( ( position ) => { - this.initMap( { - latitude: position.coords.latitude, - longitude: position.coords.longitude - } ); - }) - .catch( () => { - this.initMap( map_center ); - } ); + this.initMap( map_center ); } loadMapLibraries() { - const { api_key } = this.props; const src = [ 'https://maps.googleapis.com/maps/api/js?key=', api_key, - '&libraries=places' ].join( '' ); + '&libraries=places', + ].join( '' ); if ( window.google ) { this.setState( { google: window.google }, this.scriptsLoaded ); return; } - loadScript( src, ( error ) => { + loadScript( src, error => { if ( error ) { return; } this.setState( { google: window.google }, this.scriptsLoaded ); } ); - } // Create the map object. initMap( map_center ) { - const { google } = this.state; const { zoom } = this.props; const mapOptions = { @@ -429,10 +338,7 @@ export class Map extends Component { zoom: parseInt( zoom, 10 ), }; - const map = new google.maps.Map( - this.mapRef.current, - mapOptions - ); + const map = new google.maps.Map( this.mapRef.current, mapOptions ); map.addListener( 'zoom_changed', @@ -443,7 +349,6 @@ export class Map extends Component { map.addListener( 'click', this.onMapClick ); this.setState( { map }, () => { - this.sizeMap(); this.mapRef.current.addEventListener( 'alignmentChanged', this.sizeMap ); window.addEventListener( 'resize', this.sizeMap ); @@ -452,9 +357,7 @@ export class Map extends Component { this.setBoundsByMarkers(); this.setAddPointVisibility( true ); this.setState( { loaded: true } ); - - }); - + } ); } } @@ -466,7 +369,7 @@ Map.defaultProps = { // Default center point is San Francisco map_center: { latitude: 37.7749295, - longitude: -122.41941550000001 + longitude: -122.41941550000001, }, marker_color: 'red', api_key: null, From 3009a9c6018ae89b5a075fdc79986ee885807843 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 17 Oct 2018 13:55:15 -0400 Subject: [PATCH 054/107] Lookup key command accessibility to mirror Autocomplete. --- .../map-block/location-search/index.js | 3 +- .../extensions/map-block/lookup/index.js | 75 +++++++++++++++---- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js index fcb2f4d10d2f02..db0fdb7b63d0fb 100644 --- a/client/gutenberg/extensions/map-block/location-search/index.js +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -108,7 +108,7 @@ export class LocationSearch extends Component { return ( - { ( { isExpanded, listBoxId, activeId, onChange } ) => ( + { ( { isExpanded, listBoxId, activeId, onChange, onKeyDown } ) => ( ) } diff --git a/client/gutenberg/extensions/map-block/lookup/index.js b/client/gutenberg/extensions/map-block/lookup/index.js index 45d1c83763c5b9..ec18b52dec1ba9 100644 --- a/client/gutenberg/extensions/map-block/lookup/index.js +++ b/client/gutenberg/extensions/map-block/lookup/index.js @@ -1,15 +1,5 @@ // @TODO: key commands, spoken messages, consider suggesting as a core Gutenberg component -/** - * External dependencies - */ - -import classnames from 'classnames'; -import { - map, - debounce -} from 'lodash'; - /** * WordPress dependencies */ @@ -19,12 +9,31 @@ import { compose } from '@wordpress/compose'; +import { + ENTER, + ESCAPE, + UP, + DOWN, + LEFT, + RIGHT +} from '@wordpress/keycodes'; + import { Button, Popover, withFocusOutside } from '@wordpress/components'; +/** + * External dependencies + */ + +import classnames from 'classnames'; +import { + map, + debounce +} from 'lodash'; + function filterOptions( options = [], maxResults = 10 ) { const filtered = []; for ( let i = 0; i < options.length; i++ ) { @@ -55,6 +64,7 @@ export class Lookup extends Component { selectedIndex: 0, query: undefined, filteredOptions: [], + isOpen: false }; } @@ -69,13 +79,13 @@ export class Lookup extends Component { this.state = this.constructor.getInitialState(); this.onChange = this.onChange.bind( this ); + this.onKeyDown = this.onKeyDown.bind( this ); } componentWillUnmount() { this.debouncedLoadOptions.cancel(); - } select( option ) { @@ -123,6 +133,7 @@ export class Lookup extends Component { [ 'options' ]: keyedOptions, filteredOptions, selectedIndex, + isOpen: filteredOptions.length > 0 } ); } ); @@ -153,9 +164,47 @@ export class Lookup extends Component { } + onKeyDown( event ) { + + const { isOpen, selectedIndex, filteredOptions } = this.state; + if ( ! isOpen ) { + return; + } + let nextSelectedIndex; + switch ( event.keyCode ) { + case UP: + nextSelectedIndex = ( selectedIndex === 0 ? filteredOptions.length : selectedIndex ) - 1; + this.setState( { selectedIndex: nextSelectedIndex } ); + break; + + case DOWN: + nextSelectedIndex = ( selectedIndex + 1 ) % filteredOptions.length; + this.setState( { selectedIndex: nextSelectedIndex } ); + break; + + case ENTER: + this.select( filteredOptions[ selectedIndex ] ); + break; + + case LEFT: + case RIGHT: + case ESCAPE: + this.reset(); + return; + + default: + return; + } + + // Any handled keycode should prevent original behavior. This relies on + // the early return in the default case. + event.preventDefault(); + event.stopPropagation(); + } + render() { - const { onChange } = this; + const { onChange, onKeyDown } = this; const { children, instanceId, completer } = this.props; const { selectedIndex, filteredOptions } = this.state; const { key: selectedKey = '' } = filteredOptions[ selectedIndex ] || {}; @@ -167,7 +216,7 @@ export class Lookup extends Component {
- { children( { isExpanded, listBoxId, activeId, onChange } ) } + { children( { isExpanded, listBoxId, activeId, onChange, onKeyDown } ) } { isExpanded && ( Date: Wed, 17 Oct 2018 13:56:03 -0400 Subject: [PATCH 055/107] Marker caption defaults to address. --- client/gutenberg/extensions/map-block/location-search/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js index db0fdb7b63d0fb..ab4822d710085e 100644 --- a/client/gutenberg/extensions/map-block/location-search/index.js +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -62,7 +62,7 @@ export class LocationSearch extends Component { const point = { place_title: place.name, title: place.name, - caption: '', + caption: place.formatted_address, id: place.place_id, viewport: place.geometry.viewport, coordinates: { From 022ca84c2b7c427fee59677c90fe8111a6713a77 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 17 Oct 2018 14:14:15 -0400 Subject: [PATCH 056/107] Implementation of withSpokenMessages to match Autocomplete. --- .../extensions/map-block/lookup/index.js | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/client/gutenberg/extensions/map-block/lookup/index.js b/client/gutenberg/extensions/map-block/lookup/index.js index ec18b52dec1ba9..6fa30f6e428c4b 100644 --- a/client/gutenberg/extensions/map-block/lookup/index.js +++ b/client/gutenberg/extensions/map-block/lookup/index.js @@ -1,9 +1,12 @@ -// @TODO: key commands, spoken messages, consider suggesting as a core Gutenberg component - /** * WordPress dependencies */ import { Component } from '@wordpress/element'; +import { + __, + _n, + sprintf +} from '@wordpress/i18n'; import { withInstanceId, compose @@ -21,7 +24,8 @@ import { import { Button, Popover, - withFocusOutside + withFocusOutside, + withSpokenMessages } from '@wordpress/components'; /** @@ -135,8 +139,8 @@ export class Lookup extends Component { selectedIndex, isOpen: filteredOptions.length > 0 } ); + this.announce( filteredOptions ); } ); - } onChange( query ) { @@ -201,7 +205,21 @@ export class Lookup extends Component { event.preventDefault(); event.stopPropagation(); } - + announce( filteredOptions ) { + const { debouncedSpeak } = this.props; + if ( ! debouncedSpeak ) { + return; + } + if ( !! filteredOptions.length ) { + debouncedSpeak( sprintf( _n( + '%d result found, use up and down arrow keys to navigate.', + '%d results found, use up and down arrow keys to navigate.', + filteredOptions.length + ), filteredOptions.length ), 'assertive' ); + } else { + debouncedSpeak( __( 'No results.' ), 'assertive' ); + } + } render() { const { onChange, onKeyDown } = this; @@ -254,6 +272,7 @@ export class Lookup extends Component { } export default compose( [ + withSpokenMessages, withInstanceId, withFocusOutside, // this MUST be the innermost HOC as it calls handleFocusOutside ] )( Lookup ); From 762ff13ecfdad98d6f2149d2b8a8a6bd7a6e72ae Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 17 Oct 2018 14:47:28 -0400 Subject: [PATCH 057/107] Set anchor point of map markers so that the point of the graphic is precisely on the location. --- client/gutenberg/extensions/map-block/map-component.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/map-component.js index db91b693ce1c61..b275dacababb2d 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/map-component.js @@ -273,6 +273,8 @@ export class Map extends Component { getMarkerIcon() { const { marker_color } = this.props; + const { google } = this.state; + const svgPath = { path: 'M16,38 C16,38 32,26.692424 32,16 C32,5.307576 24.836556,0 16,0 C7.163444,0 0,5.307576 0,16 C0,26.692424 16,38 16,38 Z', @@ -280,7 +282,9 @@ export class Map extends Component { fillOpacity: 0.8, scale: 1, strokeWeight: 0, + anchor: new google.maps.Point( 16, 38 ), }; + return svgPath; } From 933b877e3ca49cce1acf6413fa75b9dc035a636c Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 17 Oct 2018 19:43:48 -0400 Subject: [PATCH 058/107] Refactor to reduce size of view script and address view script enqueueing problems. --- .../extensions/map-block/add-point/index.js | 38 +---- .../{map-component.js => component.js} | 143 +++++++---------- client/gutenberg/extensions/map-block/edit.js | 146 ++++++++++++++++++ .../extensions/map-block/editor.scss | 6 +- .../gutenberg/extensions/map-block/index.js | 141 +---------------- .../extensions/map-block/lookup/index.js | 1 - client/gutenberg/extensions/map-block/save.js | 55 +++++++ .../gutenberg/extensions/map-block/style.scss | 4 +- client/gutenberg/extensions/map-block/view.js | 22 ++- 9 files changed, 285 insertions(+), 271 deletions(-) rename client/gutenberg/extensions/map-block/{map-component.js => component.js} (84%) create mode 100644 client/gutenberg/extensions/map-block/edit.js create mode 100644 client/gutenberg/extensions/map-block/save.js diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index 402da779d6d11f..20816df0ea2a9a 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -27,46 +27,21 @@ import './style.scss'; export class AddPoint extends Component { constructor() { - - super( ...arguments ) - this.state = { - isVisible: false - }; + super( ...arguments ); this.onAddPoint = this.onAddPoint.bind( this ); - this.hideSelf = this.hideSelf.bind( this ); - - } - - hidePopover() { - - this.setState( { popoverVisible: false } ); - - } - - hideSelf() { - - this.setState( { isVisible: false } ); - } onAddPoint( point ) { this.props.onAddPoint( point ); - this.hidePopover(); } render() { - const { - onAddPoint, - hideSelf - } = this; - const { isVisible } = this.state; - - if ( ! isVisible ) { - return null; - } + onClose, + onAddPoint + } = this.props; return ( @@ -91,7 +66,8 @@ export class AddPoint extends Component { } AddPoint.defaultProps = { - onAddPoint: () => {} + onAddPoint: () => {}, + onClose: () => {} } export default AddPoint; diff --git a/client/gutenberg/extensions/map-block/map-component.js b/client/gutenberg/extensions/map-block/component.js similarity index 84% rename from client/gutenberg/extensions/map-block/map-component.js rename to client/gutenberg/extensions/map-block/component.js index b275dacababb2d..2256db192d2335 100644 --- a/client/gutenberg/extensions/map-block/map-component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -4,15 +4,28 @@ * Wordpress dependencies */ -import { Component, createRef, Fragment } from '@wordpress/element'; - -import { Button, Dashicon, TextareaControl, TextControl } from '@wordpress/components'; +import { + Component, + createRef, + Fragment +} from '@wordpress/element'; + +import { + Button, + Dashicon, + TextareaControl, + TextControl +} from '@wordpress/components'; /** * External dependencies */ -import { get, clone, assign } from 'lodash'; +import { + get, + clone, + assign +} from 'lodash'; /** * Internal dependencies @@ -21,7 +34,6 @@ import { get, clone, assign } from 'lodash'; import { CONFIG } from './config.js'; import MapMarker from './map-marker/'; import InfoWindow from './info-window/'; -import AddPoint from './add-point'; // @TODO: replace with import from lib/load-script after resolution of https://github.com/Automattic/wp-calypso/issues/27821 import { loadScript } from './load-script'; @@ -44,7 +56,6 @@ export class Map extends Component { this.onMarkerClick = this.onMarkerClick.bind( this ); this.deleteActiveMarker = this.deleteActiveMarker.bind( this ); this.updateActiveMarker = this.updateActiveMarker.bind( this ); - this.addPoint = this.addPoint.bind( this ); this.onMapClick = this.onMapClick.bind( this ); this.setBoundsByMarkers = this.setBoundsByMarkers.bind( this ); this.scriptsLoaded = this.scriptsLoaded.bind( this ); @@ -53,14 +64,27 @@ export class Map extends Component { this.mapRef = createRef(); this.addPointRef = createRef(); } - render() { - const { points, admin } = this.props; - - const { map, activeMarker, google } = this.state; - - const { onMarkerClick, deleteActiveMarker, updateActiveMarker, addPoint } = this; - + const { + points, + admin, + children } = this.props; + const { + map, + activeMarker, + google + } = this.state; + const { + onMarkerClick, + deleteActiveMarker, + updateActiveMarker, + addPoint + } = this; + const currentPoint = get( activeMarker, 'props.point' ) || {}; + const { + title, + caption + } = currentPoint; const mapMarkers = map && google && @@ -77,11 +101,6 @@ export class Map extends Component { /> ); } ); - - const currentPoint = get( activeMarker, 'props.point' ) || {}; - - const { title, caption } = currentPoint; - const infoWindow = google && ( ); - return (
{ mapMarkers }
{ infoWindow } - { admin && ( - - ) } + { children }
); } - componentDidMount() { this.loadMapLibraries(); } - - // This implementation of componentDidUpdate is a reusable way to approximate Polymer observers componentDidUpdate( prevProps ) { + // If the user has just clicked to show the Add Point component, hide info window. + // AddPoint is the only possible child. + if ( this.props.children !== prevProps.children + && this.props.children !== false) { + this.setState( { activeMarker: null } ); + } + // This implementation of componentDidUpdate is a reusable way to approximate Polymer observers for ( const propName in this.props ) { const functionName = propName + 'Changed'; if ( @@ -154,12 +170,10 @@ export class Map extends Component { } } } - // Observers pointsChanged() { this.setBoundsByMarkers(); } - map_styleChanged() { const { map, google } = this.state; @@ -168,27 +182,15 @@ export class Map extends Component { mapTypeId: google.maps.MapTypeId[ this.getMapType() ], } ); } - // Event handling onMarkerClick( marker ) { + const { onMarkerClick } = this.props; this.setState( { activeMarker: marker } ); - this.setAddPointVisibility( false ); + onMarkerClick(); } - onMapClick() { this.setState( { activeMarker: null } ); } - - addPoint( point ) { - const { points } = this.props; - const newPoints = clone( points ); - - newPoints.push( point ); - this.props.onSetPoints( newPoints ); - - this.setAddPointVisibility( false ); - } - updateActiveMarker( updates ) { const { points } = this.props; const { activeMarker } = this.state; @@ -198,7 +200,6 @@ export class Map extends Component { assign( newPoints[ index ], updates ); this.props.onSetPoints( newPoints ); } - deleteActiveMarker() { const { points } = this.props; const { activeMarker } = this.state; @@ -209,16 +210,6 @@ export class Map extends Component { this.props.onSetPoints( newPoints ); this.setState( { activeMarker: null } ); } - - setAddPointVisibility( visible = true ) { - if ( this.addPointRef.current ) { - this.addPointRef.current.setState( { isVisible: visible } ); - } - if ( visible ) { - this.setState( { activeMarker: null } ); - } - } - // Various map functions sizeMap() { const mapEl = this.mapRef.current; @@ -227,25 +218,19 @@ export class Map extends Component { const blockHeight = Math.min( blockWidth * ( 3 / 4 ), maxHeight ); mapEl.style.height = blockHeight + 'px'; } - // Calculate the appropriate zoom and center point of the map based on defined markers setBoundsByMarkers() { const { zoom, points } = this.props; - const { map, activeMarker, google } = this.state; - const bounds = new google.maps.LatLngBounds(); - if ( ! map || ! points.length || activeMarker ) { return; } - points.forEach( point => { bounds.extend( new google.maps.LatLng( point.coordinates.latitude, point.coordinates.longitude ) ); } ); - map.setCenter( bounds.getCenter() ); // If there are multiple points, zoom is determined by the area they cover, @@ -262,20 +247,16 @@ export class Map extends Component { this.setState( { fit_to_bounds: false } ); map.setOptions( { zoomControl: true } ); } - getMapStyle() { return CONFIG.styles[ this.props.map_style ].styles; } - getMapType() { return CONFIG.styles[ this.props.map_style ].map_type; } - getMarkerIcon() { const { marker_color } = this.props; const { google } = this.state; - - const svgPath = { + return { path: 'M16,38 C16,38 32,26.692424 32,16 C32,5.307576 24.836556,0 16,0 C7.163444,0 0,5.307576 0,16 C0,26.692424 16,38 16,38 Z', fillColor: marker_color, @@ -284,14 +265,13 @@ export class Map extends Component { strokeWeight: 0, anchor: new google.maps.Point( 16, 38 ), }; - - return svgPath; } - // Script loading, browser geolocation scriptsLoaded() { - const { map_center, points } = this.props; - + const { + map_center, + points + } = this.props; this.setState( { loaded: true } ); // If the map has any points, skip geolocation and use what we have. @@ -299,24 +279,19 @@ export class Map extends Component { this.initMap( map_center ); return; } - this.initMap( map_center ); } - loadMapLibraries() { const { api_key } = this.props; - const src = [ 'https://maps.googleapis.com/maps/api/js?key=', api_key, '&libraries=places', ].join( '' ); - if ( window.google ) { this.setState( { google: window.google }, this.scriptsLoaded ); return; } - loadScript( src, error => { if ( error ) { return; @@ -324,11 +299,10 @@ export class Map extends Component { this.setState( { google: window.google }, this.scriptsLoaded ); } ); } - // Create the map object. initMap( map_center ) { const { google } = this.state; - const { zoom } = this.props; + const { zoom, onMapLoaded } = this.props; const mapOptions = { streetViewControl: false, mapTypeControl: false, @@ -341,9 +315,7 @@ export class Map extends Component { mapTypeId: google.maps.MapTypeId[ this.getMapType() ], zoom: parseInt( zoom, 10 ), }; - const map = new google.maps.Map( this.mapRef.current, mapOptions ); - map.addListener( 'zoom_changed', function() { @@ -351,7 +323,6 @@ export class Map extends Component { }.bind( this ) ); map.addListener( 'click', this.onMapClick ); - this.setState( { map }, () => { this.sizeMap(); this.mapRef.current.addEventListener( 'alignmentChanged', this.sizeMap ); @@ -359,7 +330,7 @@ export class Map extends Component { google.maps.event.trigger( map, 'resize' ); map.setCenter( new google.maps.LatLng( map_center.latitude, map_center.longitude ) ); this.setBoundsByMarkers(); - this.setAddPointVisibility( true ); + onMapLoaded(); this.setState( { loaded: true } ); } ); } @@ -370,13 +341,15 @@ Map.defaultProps = { map_style: 'default', zoom: 13, onSetZoom: () => {}, + onMapLoaded: () => {}, + onMarkerClick: () => {}, + marker_color: 'red', + api_key: null, // Default center point is San Francisco map_center: { latitude: 37.7749295, longitude: -122.41941550000001, }, - marker_color: 'red', - api_key: null, }; export default Map; diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js new file mode 100644 index 00000000000000..7bcb1d6eb35494 --- /dev/null +++ b/client/gutenberg/extensions/map-block/edit.js @@ -0,0 +1,146 @@ +/** @format */ + +/** + * Wordpress dependencies + */ + +import { __ } from '@wordpress/i18n'; + +import { Component, createRef, Fragment } from '@wordpress/element'; + +import { IconButton, PanelBody, Toolbar } from '@wordpress/components'; + +import { + InspectorControls, + BlockControls, + BlockAlignmentToolbar, + PanelColorSettings, +} from '@wordpress/editor'; + +/** + * External dependencies + */ + +import { clone } from 'lodash'; + +/** + * Internal dependencies + */ + +import { CONFIG } from './config.js'; +import AddPoint from './add-point'; +import Locations from './locations'; +import Map from './component.js'; +import MapThemePicker from './map-theme-picker'; + +/** + * Module variables + */ + +class MapEdit extends Component { + constructor() { + super( ...arguments ); + this.state = { + addPointVisibility: false, + }; + this.mapRef = createRef(); + this.addPoint = this.addPoint.bind( this ); + this.updateAlignment = this.updateAlignment.bind( this ); + } + addPoint( point ) { + const { attributes, setAttributes } = this.props; + const { points } = attributes; + const newPoints = clone( points ); + newPoints.push( point ); + setAttributes( { points: newPoints } ); + this.setState( { addPointVisibility: false } ); + } + updateAlignment( value ) { + this.props.setAttributes( { align: value } ); + // Allow one cycle for alignment change to take effect + setTimeout( this.mapRef.current.sizeMap, 0 ); + } + render() { + const { className, setAttributes, attributes } = this.props; + const { map_style, points, zoom, map_center, marker_color, align } = attributes; + const { addPointVisibility } = this.state; + const inspectorControls = ( + + + + + this.setState( { addPointVisibility: true } ) } + /> + + + + + { + setAttributes( { map_style: value } ); + } } + options={ CONFIG.map_styleOptions } + /> + + setAttributes( { marker_color: value } ), + label: 'Marker Color', + }, + ] } + /> + { points.length ? ( + + { + setAttributes( { points: value } ); + } } + /> + + ) : null } + + + ); + return ( + + { inspectorControls } +
+ { + setAttributes( { zoom: value } ); + } } + api_key={ CONFIG.GOOGLE_MAPS_API_KEY } + admin={ true } + onSetPoints={ value => setAttributes( { points: value } ) } + onMapLoaded={ () => this.setState( { addPointVisibility: true } ) } + onMarkerClick={ () => this.setState( { addPointVisibility: false } ) } + > + { addPointVisibility && ( + this.setState( { addPointVisibility: false } ) } + /> + ) } + +
+
+ ); + } +} + +export default MapEdit; diff --git a/client/gutenberg/extensions/map-block/editor.scss b/client/gutenberg/extensions/map-block/editor.scss index bbe15aed8ca771..5bb34fbbdc6192 100644 --- a/client/gutenberg/extensions/map-block/editor.scss +++ b/client/gutenberg/extensions/map-block/editor.scss @@ -1 +1,5 @@ -.wp-block-atavist-maps {} +.wp-block-atavist-maps { + .wp-block-atavist-maps__delete-btn { + padding: 0; + } +} diff --git a/client/gutenberg/extensions/map-block/index.js b/client/gutenberg/extensions/map-block/index.js index d20543fbf8f788..f061abccec26c3 100644 --- a/client/gutenberg/extensions/map-block/index.js +++ b/client/gutenberg/extensions/map-block/index.js @@ -2,42 +2,19 @@ * Wordpress dependencies */ -import { __ } from '@wordpress/i18n'; - import { registerBlockType } from '@wordpress/blocks'; -import { - IconButton, - PanelBody, - Toolbar -} from '@wordpress/components'; - -import { - InspectorControls, - BlockControls, - BlockAlignmentToolbar, - PanelColorSettings -} from '@wordpress/editor'; - -import { - Fragment, - createRef -} from '@wordpress/element'; - /** * External dependencies */ -import classnames from 'classnames'; - /** * Internal dependencies */ import { CONFIG } from './config.js'; -import Locations from './locations'; -import Map from './map-component.js'; -import MapThemePicker from './map-theme-picker'; +import edit from './edit'; +import save from './save'; import './style.scss'; import './editor.scss'; @@ -54,116 +31,6 @@ registerBlockType( CONFIG.name, { return { 'data-align': align }; } }, - edit: function( { attributes, setAttributes, className } ) { - const { - map_style, - points, - zoom, - map_center, - marker_color, - align - } = attributes; - const mapRef = createRef(); - const updateAlignment = ( value ) => { - setAttributes( { align: value } ) - // Allow one cycle for alignment change to take effect - setTimeout( mapRef.current.sizeMap, 0); - }; - const markerIcon = CONFIG.markerIcon; - const inspectorControls = ( - - - - - mapRef.current.setAddPointVisibility( true ) } - /> - - - - - { setAttributes( { map_style: value } ) } } - options={ CONFIG.map_styleOptions } - /> - - setAttributes( { marker_color: value } ), - label: 'Marker Color' - } ] } - /> - { points.length ? - - { setAttributes( { points: value } ) } } - /> - - : null} - - - ); - return ( - - { inspectorControls } -
- { setAttributes( { zoom: value } ) } } - api_key={ CONFIG.GOOGLE_MAPS_API_KEY } - admin={ true } - onSetPoints={ ( value ) => { - setAttributes( { points: value } ) - } } - /> -
-
- ); - }, - save: function( { attributes, className } ) { - const { map_style, points, zoom, map_center, marker_color, align } = attributes; - const atavistAlignClass = ( value ) => { - switch ( value ) { - case 'left': - case 'right': - case 'center': - case 'full': - return 'atavist-block-align-' + value; - default: - return 'atavist-block-align-center'; - } - } - const classes = classnames( - CONFIG.baseClasses, - className, - atavistAlignClass( align ) - ); - return ( -
-
-
- ); - } + edit, + save } ); diff --git a/client/gutenberg/extensions/map-block/lookup/index.js b/client/gutenberg/extensions/map-block/lookup/index.js index 6fa30f6e428c4b..9f4667810b039c 100644 --- a/client/gutenberg/extensions/map-block/lookup/index.js +++ b/client/gutenberg/extensions/map-block/lookup/index.js @@ -270,7 +270,6 @@ export class Lookup extends Component { ); } } - export default compose( [ withSpokenMessages, withInstanceId, diff --git a/client/gutenberg/extensions/map-block/save.js b/client/gutenberg/extensions/map-block/save.js new file mode 100644 index 00000000000000..fb6057fea09841 --- /dev/null +++ b/client/gutenberg/extensions/map-block/save.js @@ -0,0 +1,55 @@ +/** @format */ + +/** + * Wordpress dependencies + */ + +import { Component } from '@wordpress/element'; + +/** + * External dependencies + */ + +import classnames from 'classnames'; + +/** + * Internal dependencies + */ + +import { CONFIG } from './config.js'; + +/** + * Module variables + */ + +class MapSave extends Component { + render() { + const { className, attributes } = this.props; + const { map_style, points, zoom, map_center, marker_color, align } = attributes; + const atavistAlignClass = value => { + switch ( value ) { + case 'left': + case 'right': + case 'center': + case 'full': + return 'atavist-block-align-' + value; + default: + return 'atavist-block-align-center'; + } + }; + const classes = classnames( CONFIG.baseClasses, className, atavistAlignClass( align ) ); + return ( +
+ ); + } +} + +export default MapSave; diff --git a/client/gutenberg/extensions/map-block/style.scss b/client/gutenberg/extensions/map-block/style.scss index 3c8f8878eb76bc..c0cf2c8095eea8 100644 --- a/client/gutenberg/extensions/map-block/style.scss +++ b/client/gutenberg/extensions/map-block/style.scss @@ -4,6 +4,7 @@ overflow: hidden; background: lightgray; min-height: 400px; + text-align: left; } .gm-style-iw > div { padding-right: 1px; @@ -14,7 +15,4 @@ margin-right: 0.4em; } } - .components-base-control__label { - - } } diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index ffaa4fff9dd18e..ae986100353288 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -5,7 +5,7 @@ */ import './style.scss'; -import component from './map-component.js'; +import component from './component.js'; import { CONFIG } from './config.js'; import FrontendManagement from 'gutenberg/extensions/shared/atavist/frontend-management.js'; @@ -15,16 +15,12 @@ window.addEventListener( 'load', function() { return; } const frontendManagement = new FrontendManagement(); - frontendManagement.blockIterator( - document, - [ - { - component: component, - options: { - config: CONFIG, - selector: '.map__map-container' - } - } - ] - ); + frontendManagement.blockIterator( document, [ + { + component: component, + options: { + config: CONFIG, + }, + }, + ] ); } ); From 072f5098398c2a8ba53a9c2a682a96bc5353a1a0 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 18 Oct 2018 17:36:36 -0400 Subject: [PATCH 059/107] Replacing lodash clone() with Array.slice(0) to remove dependency. A couple of linting fixes. --- .../extensions/map-block/component.js | 60 +++++-------------- client/gutenberg/extensions/map-block/edit.js | 4 +- .../extensions/map-block/locations/index.js | 6 +- .../map-block/map-theme-picker/index.js | 2 +- 4 files changed, 19 insertions(+), 53 deletions(-) diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index 2256db192d2335..ce573ef059bb2d 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -4,28 +4,15 @@ * Wordpress dependencies */ -import { - Component, - createRef, - Fragment -} from '@wordpress/element'; +import { Component, createRef, Fragment } from '@wordpress/element'; -import { - Button, - Dashicon, - TextareaControl, - TextControl -} from '@wordpress/components'; +import { Button, Dashicon, TextareaControl, TextControl } from '@wordpress/components'; /** * External dependencies */ -import { - get, - clone, - assign -} from 'lodash'; +import { get, assign } from 'lodash'; /** * Internal dependencies @@ -62,29 +49,13 @@ export class Map extends Component { // Refs this.mapRef = createRef(); - this.addPointRef = createRef(); } render() { - const { - points, - admin, - children } = this.props; - const { - map, - activeMarker, - google - } = this.state; - const { - onMarkerClick, - deleteActiveMarker, - updateActiveMarker, - addPoint - } = this; + const { points, admin, children } = this.props; + const { map, activeMarker, google } = this.state; + const { onMarkerClick, deleteActiveMarker, updateActiveMarker } = this; const currentPoint = get( activeMarker, 'props.point' ) || {}; - const { - title, - caption - } = currentPoint; + const { title, caption } = currentPoint; const mapMarkers = map && google && @@ -155,9 +126,8 @@ export class Map extends Component { componentDidUpdate( prevProps ) { // If the user has just clicked to show the Add Point component, hide info window. // AddPoint is the only possible child. - if ( this.props.children !== prevProps.children - && this.props.children !== false) { - this.setState( { activeMarker: null } ); + if ( this.props.children !== prevProps.children && this.props.children !== false ) { + this.clearCurrentMarker(); } // This implementation of componentDidUpdate is a reusable way to approximate Polymer observers for ( const propName in this.props ) { @@ -191,11 +161,14 @@ export class Map extends Component { onMapClick() { this.setState( { activeMarker: null } ); } + clearCurrentMarker() { + this.setState( { activeMarker: null } ); + } updateActiveMarker( updates ) { const { points } = this.props; const { activeMarker } = this.state; const { index } = activeMarker.props; - const newPoints = clone( points ); + const newPoints = points.slice( 0 ); assign( newPoints[ index ], updates ); this.props.onSetPoints( newPoints ); @@ -204,7 +177,7 @@ export class Map extends Component { const { points } = this.props; const { activeMarker } = this.state; const { index } = activeMarker.props; - const newPoints = clone( points ); + const newPoints = points.slice( 0 ); newPoints.splice( index, 1 ); this.props.onSetPoints( newPoints ); @@ -268,10 +241,7 @@ export class Map extends Component { } // Script loading, browser geolocation scriptsLoaded() { - const { - map_center, - points - } = this.props; + const { map_center, points } = this.props; this.setState( { loaded: true } ); // If the map has any points, skip geolocation and use what we have. diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index 7bcb1d6eb35494..d16fcc32ae0501 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -21,8 +21,6 @@ import { * External dependencies */ -import { clone } from 'lodash'; - /** * Internal dependencies */ @@ -50,7 +48,7 @@ class MapEdit extends Component { addPoint( point ) { const { attributes, setAttributes } = this.props; const { points } = attributes; - const newPoints = clone( points ); + const newPoints = points.slice( 0 ); newPoints.push( point ); setAttributes( { points: newPoints } ); this.setState( { addPointVisibility: false } ); diff --git a/client/gutenberg/extensions/map-block/locations/index.js b/client/gutenberg/extensions/map-block/locations/index.js index df8ae0742f7b09..05f9aec8a4b1d1 100644 --- a/client/gutenberg/extensions/map-block/locations/index.js +++ b/client/gutenberg/extensions/map-block/locations/index.js @@ -23,8 +23,6 @@ import './style.scss'; * External dependencies */ -import { clone } from 'lodash'; - export class Locations extends Component { constructor() { @@ -42,7 +40,7 @@ export class Locations extends Component { onChange } = this.props; - const newPoints = clone( points ); + const newPoints = points.slice( 0 ); newPoints.splice( index, 1 ); onChange( newPoints ); } @@ -53,7 +51,7 @@ export class Locations extends Component { onChange } = this.props; - const newPoints = clone( points ); + const newPoints = points.slice( 0 ); newPoints[index][field] = value; onChange( newPoints ); } diff --git a/client/gutenberg/extensions/map-block/map-theme-picker/index.js b/client/gutenberg/extensions/map-block/map-theme-picker/index.js index e90cc6bff761ae..1630eb9c71ffc8 100644 --- a/client/gutenberg/extensions/map-block/map-theme-picker/index.js +++ b/client/gutenberg/extensions/map-block/map-theme-picker/index.js @@ -16,7 +16,7 @@ import { * External dependencies */ - import classnames from 'classnames'; +import classnames from 'classnames'; /** * Internal dependencies From 132678949ef94a4f85746232629a2a452cd10003 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 19 Oct 2018 09:37:25 -0400 Subject: [PATCH 060/107] Moved all WordPress dependencies into External dependencies block. Removed all spaces between imports within a comment block. --- .../extensions/map-block/add-point/index.js | 10 +------ .../extensions/map-block/component.js | 27 ++++++++++--------- .../gutenberg/extensions/map-block/config.js | 6 +---- client/gutenberg/extensions/map-block/edit.js | 15 +---------- .../gutenberg/extensions/map-block/index.js | 9 ++----- .../extensions/map-block/info-window/index.js | 6 +---- .../map-block/location-search/index.js | 8 +----- .../extensions/map-block/locations/index.js | 7 +---- .../extensions/map-block/lookup/index.js | 10 ++----- .../extensions/map-block/map-marker/index.js | 5 +--- .../map-block/map-theme-picker/index.js | 8 +----- client/gutenberg/extensions/map-block/save.js | 13 +-------- client/gutenberg/extensions/map-block/view.js | 2 -- 13 files changed, 28 insertions(+), 98 deletions(-) diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index 20816df0ea2a9a..94e96f5dd2a961 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -1,29 +1,21 @@ /** - * Wordpress dependencies + * External dependencies */ import { __ } from '@wordpress/i18n'; - import { Component } from '@wordpress/element'; - import { Button, Dashicon, Popover } from '@wordpress/components'; -/** - * External dependencies - */ - /** * Internal dependencies */ import LocationSearch from '../location-search'; - import './style.scss'; - export class AddPoint extends Component { constructor() { diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index ce573ef059bb2d..92e98eb3190127 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -1,18 +1,22 @@ -/** @format */ - -/** - * Wordpress dependencies - */ - -import { Component, createRef, Fragment } from '@wordpress/element'; - -import { Button, Dashicon, TextareaControl, TextControl } from '@wordpress/components'; - /** * External dependencies */ -import { get, assign } from 'lodash'; +import { + Component, + createRef, + Fragment +} from '@wordpress/element'; +import { + Button, + Dashicon, + TextareaControl, + TextControl +} from '@wordpress/components'; +import { + get, + assign +} from 'lodash'; /** * Internal dependencies @@ -21,7 +25,6 @@ import { get, assign } from 'lodash'; import { CONFIG } from './config.js'; import MapMarker from './map-marker/'; import InfoWindow from './info-window/'; - // @TODO: replace with import from lib/load-script after resolution of https://github.com/Automattic/wp-calypso/issues/27821 import { loadScript } from './load-script'; // import { loadScript } from 'lib/load-script'; diff --git a/client/gutenberg/extensions/map-block/config.js b/client/gutenberg/extensions/map-block/config.js index 0592ca2df6ed11..caad4643a381b9 100644 --- a/client/gutenberg/extensions/map-block/config.js +++ b/client/gutenberg/extensions/map-block/config.js @@ -1,13 +1,9 @@ /** - * Wordpress dependencies + * External dependencies */ import { __ } from '@wordpress/i18n'; -/** - * External dependencies - */ - /** * Internal dependencies */ diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index d16fcc32ae0501..c2d148b38cb764 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -1,15 +1,10 @@ -/** @format */ - /** - * Wordpress dependencies + * External dependencies */ import { __ } from '@wordpress/i18n'; - import { Component, createRef, Fragment } from '@wordpress/element'; - import { IconButton, PanelBody, Toolbar } from '@wordpress/components'; - import { InspectorControls, BlockControls, @@ -17,10 +12,6 @@ import { PanelColorSettings, } from '@wordpress/editor'; -/** - * External dependencies - */ - /** * Internal dependencies */ @@ -31,10 +22,6 @@ import Locations from './locations'; import Map from './component.js'; import MapThemePicker from './map-theme-picker'; -/** - * Module variables - */ - class MapEdit extends Component { constructor() { super( ...arguments ); diff --git a/client/gutenberg/extensions/map-block/index.js b/client/gutenberg/extensions/map-block/index.js index f061abccec26c3..6d89bb6525041b 100644 --- a/client/gutenberg/extensions/map-block/index.js +++ b/client/gutenberg/extensions/map-block/index.js @@ -1,13 +1,9 @@ -/** - * Wordpress dependencies - */ - -import { registerBlockType } from '@wordpress/blocks'; - /** * External dependencies */ + import { registerBlockType } from '@wordpress/blocks'; + /** * Internal dependencies */ @@ -15,7 +11,6 @@ import { registerBlockType } from '@wordpress/blocks'; import { CONFIG } from './config.js'; import edit from './edit'; import save from './save'; - import './style.scss'; import './editor.scss'; diff --git a/client/gutenberg/extensions/map-block/info-window/index.js b/client/gutenberg/extensions/map-block/info-window/index.js index 67090757d8e14a..391ef3b6cdf891 100644 --- a/client/gutenberg/extensions/map-block/info-window/index.js +++ b/client/gutenberg/extensions/map-block/info-window/index.js @@ -1,5 +1,5 @@ /** - * Wordpress dependencies + * External dependencies */ import { @@ -7,10 +7,6 @@ import { createPortal } from '@wordpress/element'; -/** - * External dependencies - */ - /** * Internal dependencies */ diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js index ab4822d710085e..7b5cb043d58157 100644 --- a/client/gutenberg/extensions/map-block/location-search/index.js +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -1,23 +1,17 @@ /** - * Wordpress dependencies + * External dependencies */ import { __ } from '@wordpress/i18n'; - import { Component, createRef } from '@wordpress/element'; - import { BaseControl, TextControl } from '@wordpress/components'; -/** - * External dependencies - */ - /** * Internal dependencies */ diff --git a/client/gutenberg/extensions/map-block/locations/index.js b/client/gutenberg/extensions/map-block/locations/index.js index 05f9aec8a4b1d1..e42413050ba83a 100644 --- a/client/gutenberg/extensions/map-block/locations/index.js +++ b/client/gutenberg/extensions/map-block/locations/index.js @@ -1,5 +1,5 @@ /** - * Wordpress dependencies + * External dependencies */ import { @@ -10,7 +10,6 @@ import { TextareaControl, TextControl } from '@wordpress/components'; - import { Component } from '@wordpress/element'; /** @@ -19,10 +18,6 @@ import { Component } from '@wordpress/element'; import './style.scss'; -/** - * External dependencies - */ - export class Locations extends Component { constructor() { diff --git a/client/gutenberg/extensions/map-block/lookup/index.js b/client/gutenberg/extensions/map-block/lookup/index.js index 9f4667810b039c..e7b613bcef9bec 100644 --- a/client/gutenberg/extensions/map-block/lookup/index.js +++ b/client/gutenberg/extensions/map-block/lookup/index.js @@ -1,6 +1,7 @@ /** - * WordPress dependencies + * External dependencies */ + import { Component } from '@wordpress/element'; import { __, @@ -11,7 +12,6 @@ import { withInstanceId, compose } from '@wordpress/compose'; - import { ENTER, ESCAPE, @@ -20,18 +20,12 @@ import { LEFT, RIGHT } from '@wordpress/keycodes'; - import { Button, Popover, withFocusOutside, withSpokenMessages } from '@wordpress/components'; - -/** - * External dependencies - */ - import classnames from 'classnames'; import { map, diff --git a/client/gutenberg/extensions/map-block/map-marker/index.js b/client/gutenberg/extensions/map-block/map-marker/index.js index 22e8a7621af5d7..628f241c944d5e 100644 --- a/client/gutenberg/extensions/map-block/map-marker/index.js +++ b/client/gutenberg/extensions/map-block/map-marker/index.js @@ -1,12 +1,9 @@ /** - * Wordpress dependencies + * External dependencies */ import { Component } from '@wordpress/element'; -/** - * External dependencies - */ /** * Internal dependencies diff --git a/client/gutenberg/extensions/map-block/map-theme-picker/index.js b/client/gutenberg/extensions/map-block/map-theme-picker/index.js index 1630eb9c71ffc8..b25ca2ac2343b2 100644 --- a/client/gutenberg/extensions/map-block/map-theme-picker/index.js +++ b/client/gutenberg/extensions/map-block/map-theme-picker/index.js @@ -1,21 +1,15 @@ /** - * Wordpress dependencies + * External dependencies */ import { Component, Fragment } from '@wordpress/element'; - import { Button, ButtonGroup } from '@wordpress/components'; - -/** - * External dependencies - */ - import classnames from 'classnames'; /** diff --git a/client/gutenberg/extensions/map-block/save.js b/client/gutenberg/extensions/map-block/save.js index fb6057fea09841..53d45c1e7cbbdf 100644 --- a/client/gutenberg/extensions/map-block/save.js +++ b/client/gutenberg/extensions/map-block/save.js @@ -1,15 +1,8 @@ -/** @format */ - -/** - * Wordpress dependencies - */ - -import { Component } from '@wordpress/element'; - /** * External dependencies */ +import { Component } from '@wordpress/element'; import classnames from 'classnames'; /** @@ -18,10 +11,6 @@ import classnames from 'classnames'; import { CONFIG } from './config.js'; -/** - * Module variables - */ - class MapSave extends Component { render() { const { className, attributes } = this.props; diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index ae986100353288..955a77ee4c268c 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -1,5 +1,3 @@ -/** @format */ - /** * Internal dependencies */ From 7f06bd632c59398201692f5b29a0bcd7e90d1570 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 19 Oct 2018 10:32:51 -0400 Subject: [PATCH 061/107] Replacing all bound event handlers with arrow functions. Removing unnecessary blank lines. --- .../extensions/map-block/add-point/index.js | 13 ---------- client/gutenberg/extensions/map-block/edit.js | 6 ++--- .../extensions/map-block/info-window/index.js | 26 +------------------ .../map-block/location-search/index.js | 12 +-------- .../extensions/map-block/locations/index.js | 3 +-- .../extensions/map-block/lookup/index.js | 19 +++----------- .../extensions/map-block/map-marker/index.js | 26 +------------------ .../shared/atavist/frontend-management.js | 4 +-- 8 files changed, 11 insertions(+), 98 deletions(-) diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index 94e96f5dd2a961..6ca7b18dc44736 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -17,18 +17,6 @@ import { import LocationSearch from '../location-search'; import './style.scss'; export class AddPoint extends Component { - - constructor() { - super( ...arguments ); - this.onAddPoint = this.onAddPoint.bind( this ); - } - - onAddPoint( point ) { - - this.props.onAddPoint( point ); - - } - render() { const { onClose, @@ -54,7 +42,6 @@ export class AddPoint extends Component { ); } - } AddPoint.defaultProps = { diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index c2d148b38cb764..ec033e61b1d096 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -29,10 +29,8 @@ class MapEdit extends Component { addPointVisibility: false, }; this.mapRef = createRef(); - this.addPoint = this.addPoint.bind( this ); - this.updateAlignment = this.updateAlignment.bind( this ); } - addPoint( point ) { + addPoint = ( point ) => { const { attributes, setAttributes } = this.props; const { points } = attributes; const newPoints = points.slice( 0 ); @@ -40,7 +38,7 @@ class MapEdit extends Component { setAttributes( { points: newPoints } ); this.setState( { addPointVisibility: false } ); } - updateAlignment( value ) { + updateAlignment = ( value ) => { this.props.setAttributes( { align: value } ); // Allow one cycle for alignment change to take effect setTimeout( this.mapRef.current.sizeMap, 0 ); diff --git a/client/gutenberg/extensions/map-block/info-window/index.js b/client/gutenberg/extensions/map-block/info-window/index.js index 391ef3b6cdf891..124b53d20c19c0 100644 --- a/client/gutenberg/extensions/map-block/info-window/index.js +++ b/client/gutenberg/extensions/map-block/info-window/index.js @@ -12,37 +12,22 @@ import { */ export class InfoWindow extends Component { - - constructor() { - - super( ...arguments ); - this.closeClick = this.closeClick.bind( this ); - - } - componentDidMount() { - const { google } = this.props; this.el = document.createElement( 'DIV' ); this.infowindow = new google.maps.InfoWindow( { content: this.el } ); google.maps.event.addListener( this.infowindow,'closeclick', this.closeClick ); - } - componentDidUpdate( prevProps ) { - if ( this.props.activeMarker !== prevProps.activeMarker ) { this.props.activeMarker ? this.openWindow() : this.closeWindow(); } - } - render() { - // Use React portal to render components directly into the Google Maps info window. return this.el ? createPortal( @@ -51,24 +36,15 @@ export class InfoWindow extends Component { ) : null; } - - closeClick() { - + closeClick = () => { this.props.unsetActiveMarker(); - } - openWindow() { - this.infowindow .open( this.props.map, this.props.activeMarker.marker ); - } - closeWindow() { - this.infowindow.close(); - } } diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js index 7b5cb043d58157..0858af4fdf2408 100644 --- a/client/gutenberg/extensions/map-block/location-search/index.js +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -32,8 +32,6 @@ export class LocationSearch extends Component { this.state = { isEmpty: true }; - this.searchChanged = this.searchChanged.bind( this ); - this.onReset = this.onReset.bind( this ); this.autocompleter = { name: 'placeSearch', @@ -85,17 +83,9 @@ export class LocationSearch extends Component { }); } - - searchChanged( value ) { - - this.setState( { isEmpty: value.length < 1 } ); - - } - - onReset() { + onReset = () => { this.textRef.current.value = null; } - render() { const { label } = this.props; diff --git a/client/gutenberg/extensions/map-block/locations/index.js b/client/gutenberg/extensions/map-block/locations/index.js index e42413050ba83a..4e089743581aa1 100644 --- a/client/gutenberg/extensions/map-block/locations/index.js +++ b/client/gutenberg/extensions/map-block/locations/index.js @@ -22,13 +22,12 @@ export class Locations extends Component { constructor() { super( ...arguments ); - this.onDeletePoint = this.onDeletePoint.bind(this); this.state = { selectedCell: null }; } - onDeletePoint( e ) { + onDeletePoint = ( e ) => { const index = parseInt( e.target.getAttribute( 'data-id' ) ); const { points, diff --git a/client/gutenberg/extensions/map-block/lookup/index.js b/client/gutenberg/extensions/map-block/lookup/index.js index e7b613bcef9bec..f8c8fc798f956a 100644 --- a/client/gutenberg/extensions/map-block/lookup/index.js +++ b/client/gutenberg/extensions/map-block/lookup/index.js @@ -68,17 +68,9 @@ export class Lookup extends Component { } constructor() { - super( ...arguments ); - - this.select = this.select.bind( this ); - this.reset = this.reset.bind( this ); this.debouncedLoadOptions = debounce( this.loadOptions, 250 ); - this.state = this.constructor.getInitialState(); - this.onChange = this.onChange.bind( this ); - this.onKeyDown = this.onKeyDown.bind( this ); - } componentWillUnmount() { @@ -86,7 +78,7 @@ export class Lookup extends Component { this.debouncedLoadOptions.cancel(); } - select( option ) { + select = ( option ) => { const { completer } = this.props; const getOptionCompletion = completer.getOptionCompletion || {}; @@ -95,7 +87,7 @@ export class Lookup extends Component { } - reset() { + reset = () => { this.setState( this.constructor.getInitialState() ); @@ -137,8 +129,7 @@ export class Lookup extends Component { } ); } - onChange( query ) { - + onChange = ( query ) => { const { completer } = this.props; const { options } = this.state; @@ -159,11 +150,9 @@ export class Lookup extends Component { if ( completer ) { this.setState( { selectedIndex: 0, filteredOptions, query } ); } - } - onKeyDown( event ) { - + onKeyDown = ( event ) => { const { isOpen, selectedIndex, filteredOptions } = this.state; if ( ! isOpen ) { return; diff --git a/client/gutenberg/extensions/map-block/map-marker/index.js b/client/gutenberg/extensions/map-block/map-marker/index.js index 628f241c944d5e..cc96aad89d38c9 100644 --- a/client/gutenberg/extensions/map-block/map-marker/index.js +++ b/client/gutenberg/extensions/map-block/map-marker/index.js @@ -10,42 +10,22 @@ import { Component } from '@wordpress/element'; */ export class MapMarker extends Component { - - constructor() { - - super( ...arguments ); - this.handleClick = this.handleClick.bind( this ); - - } - componentDidMount() { - this.renderMarker(); - } - componentWillUnmount() { - if ( this.marker ) { this.marker.setMap( null ); } } - componentDidUpdate() { - this.renderMarker(); - } - - handleClick() { - + handleClick = () => { const { onClick } = this.props; onClick( this ); - } - renderMarker() { - const { map, point, @@ -67,13 +47,9 @@ export class MapMarker extends Component { this.marker = new google.Marker( { position, map, icon } ); this.marker.addListener( 'click', handleClick ); } - } - render() { - return null; - } } diff --git a/client/gutenberg/extensions/shared/atavist/frontend-management.js b/client/gutenberg/extensions/shared/atavist/frontend-management.js index 9e6dc32ef205b0..86bd2436dfaae7 100644 --- a/client/gutenberg/extensions/shared/atavist/frontend-management.js +++ b/client/gutenberg/extensions/shared/atavist/frontend-management.js @@ -13,7 +13,6 @@ import { createElement, render } from '@wordpress/element'; */ export class FrontendManagement { - blockIterator( rootNode, blocks ) { blocks.forEach( block => { this.initializeFrontendReactBlocks( @@ -22,8 +21,7 @@ export class FrontendManagement { rootNode ) } ) - } - + }; initializeFrontendReactBlocks( component, options = {}, rootNode ) { const { name, attributes } = options.config; const { selector } = options; From 2a2c3f934fbd0d289151a8d86491c448ed25013e Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 19 Oct 2018 10:44:07 -0400 Subject: [PATCH 062/107] Missed localization. --- client/gutenberg/extensions/map-block/add-point/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index 6ca7b18dc44736..f27e6a2974045e 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -26,7 +26,7 @@ export class AddPoint extends Component { ); return ( -
- +
+ { rows }
diff --git a/client/gutenberg/extensions/map-block/locations/style.scss b/client/gutenberg/extensions/map-block/locations/style.scss index 9512f016d2db18..8d78a2cab704c6 100644 --- a/client/gutenberg/extensions/map-block/locations/style.scss +++ b/client/gutenberg/extensions/map-block/locations/style.scss @@ -1,4 +1,4 @@ -.components-locations__panel { +.component__locations__panel { margin-bottom: 1em; &:empty { display: none; @@ -13,3 +13,9 @@ padding-right: 40px; } } +.component__locations__delete-btn { + padding: 0; + svg { + margin-right: 0.4em; + } +} diff --git a/client/gutenberg/extensions/map-block/map-theme-picker/index.js b/client/gutenberg/extensions/map-block/map-theme-picker/index.js index b25ca2ac2343b2..74a272b3456227 100644 --- a/client/gutenberg/extensions/map-block/map-theme-picker/index.js +++ b/client/gutenberg/extensions/map-block/map-theme-picker/index.js @@ -31,9 +31,9 @@ export class MapThemePicker extends Component { const buttons = options.map( ( option, index ) => { const classes = classnames( - 'component_map-theme-picker__button', - option.value, - option.value === value ? 'isSelected' : '' + 'component__map-theme-picker__button', + 'is-theme-' + option.value, + option.value === value ? 'is-selected' : '' ); return ( diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index b55f79266dd034..b20c45d2264600 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -2,6 +2,7 @@ * External dependencies */ +import { __ } from '@wordpress/i18n'; import { Component, createRef, @@ -86,20 +87,20 @@ export class Map extends Component { admin && ( updateActiveMarker( { title: value } ) } /> updateActiveMarker( { caption: value } ) } /> ) } diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index 633b4e11f85b1a..83536b8b9494d7 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -60,7 +60,7 @@ class MapEdit extends Component { - + { @@ -70,7 +70,7 @@ class MapEdit extends Component { /> { points.length ? ( - + { diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js index 8445175208af04..bcaedb416aa0b3 100644 --- a/client/gutenberg/extensions/map-block/location-search/index.js +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -18,7 +18,7 @@ import { import Lookup from '../lookup'; -const placeholderText = __( 'Add a marker...' ); +const placeholderText = __( 'Add a marker...', 'jetpack' ); export class LocationSearch extends Component { diff --git a/client/gutenberg/extensions/map-block/lookup/index.js b/client/gutenberg/extensions/map-block/lookup/index.js index f8c8fc798f956a..13ecfe7fd2b91c 100644 --- a/client/gutenberg/extensions/map-block/lookup/index.js +++ b/client/gutenberg/extensions/map-block/lookup/index.js @@ -200,7 +200,7 @@ export class Lookup extends Component { filteredOptions.length ), filteredOptions.length ), 'assertive' ); } else { - debouncedSpeak( __( 'No results.' ), 'assertive' ); + debouncedSpeak( __( 'No results.', 'jetpack' ), 'assertive' ); } } render() { diff --git a/client/gutenberg/extensions/map-block/settings.js b/client/gutenberg/extensions/map-block/settings.js index 82feb9e8f32be5..f74be055e71070 100644 --- a/client/gutenberg/extensions/map-block/settings.js +++ b/client/gutenberg/extensions/map-block/settings.js @@ -10,13 +10,13 @@ import { __ } from '@wordpress/i18n'; export const settings = { name: 'atavist/maps', - title: __( 'Map' ), + title: __( 'Map', 'jetpack' ), icon: , category: 'common', keywords: [ - __( 'map' ), - __( 'jetpack' ), - __( 'atavist' ) + __( 'map', 'jetpack' ), + __( 'jetpack', 'jetpack' ), + __( 'atavist', 'jetpack' ) ], attributes: { align: { @@ -296,27 +296,27 @@ export const settings = { map_styleOptions: [ { value: 'default', - label: 'Basic' + label: __( 'Basic', 'jetpack' ) }, { value: 'black_and_white', - label: 'Black and white' + label: __( 'Black and white', 'jetpack' ) }, { value: 'satellite', - label: 'Satellite' + label: __( 'Satellite', 'jetpack' ) }, { value: 'satellite_with_features', - label: 'Satellite (with features)' + label: __( 'Satellite (with features)', 'jetpack' ) }, { value: 'terrain', - label: 'Terrain' + label: __( 'Terrain', 'jetpack' ) }, { value: 'terrain_with_features', - label: 'Terrain (with features)' + label: __( 'Terrain (with features)', 'jetpack' ) } ], GOOGLE_MAPS_API_KEY: 'AIzaSyDaj7klnWKpzGx0W5PonA73Dgr68Me8cyg', From fd8a77b2f1a525b451f1fb04041cd8eaff5dc820 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Mon, 22 Oct 2018 11:07:50 -0400 Subject: [PATCH 069/107] Sytax updates with Prettier. --- .../extensions/map-block/add-point/index.js | 33 +- .../extensions/map-block/add-point/style.scss | 11 +- .../extensions/map-block/component.js | 26 +- client/gutenberg/extensions/map-block/edit.js | 10 +- .../extensions/map-block/editor.scss | 5 +- .../gutenberg/extensions/map-block/index.js | 8 +- .../extensions/map-block/info-window/index.js | 31 +- .../map-block/location-search/index.js | 101 +++-- .../extensions/map-block/locations/index.js | 43 +-- .../extensions/map-block/locations/style.scss | 2 + .../extensions/map-block/lookup/index.js | 105 ++--- .../extensions/map-block/map-marker/index.js | 23 +- .../map-block/map-theme-picker/index.js | 39 +- .../map-block/map-theme-picker/style.scss | 8 +- client/gutenberg/extensions/map-block/save.js | 2 + .../extensions/map-block/settings.js | 360 +++++++++++------- .../gutenberg/extensions/map-block/style.scss | 2 + client/gutenberg/extensions/map-block/view.js | 2 + .../shared/atavist/frontend-management.js | 36 +- 19 files changed, 415 insertions(+), 432 deletions(-) diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index 2050153c6dd907..a1908850c9dc13 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -1,14 +1,12 @@ +/** @format */ + /** * External dependencies */ import { __ } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; -import { - Button, - Dashicon, - Popover -} from '@wordpress/components'; +import { Button, Dashicon, Popover } from '@wordpress/components'; /** * Internal dependencies @@ -18,26 +16,15 @@ import LocationSearch from '../location-search'; import './style.scss'; export class AddPoint extends Component { render() { - const { - onClose, - onAddPoint - } = this.props; + const { onClose, onAddPoint } = this.props; return ( - - + ); @@ -46,7 +33,7 @@ export class AddPoint extends Component { AddPoint.defaultProps = { onAddPoint: () => {}, - onClose: () => {} -} + onClose: () => {}, +}; export default AddPoint; diff --git a/client/gutenberg/extensions/map-block/add-point/style.scss b/client/gutenberg/extensions/map-block/add-point/style.scss index 21b11cd59e583b..0347f9476ebdcb 100644 --- a/client/gutenberg/extensions/map-block/add-point/style.scss +++ b/client/gutenberg/extensions/map-block/add-point/style.scss @@ -1,3 +1,5 @@ +/** @format */ + .component__add-point { position: absolute; left: 50%; @@ -12,11 +14,12 @@ text-indent: -9999px; box-shadow: none; background-color: transparent; - &.components-button:not(:disabled):not([aria-disabled=true]):focus { + &.components-button:not( :disabled ):not( [aria-disabled='true'] ):focus { background-color: transparent; box-shadow: none; } - &:focus, &:active { + &:focus, + &:active { background-color: transparent; box-shadow: none; } @@ -24,10 +27,10 @@ .component__add-point__popover { // Default z-index for components-popover places it above Edit Post Header and Notices &.components-popover, - &.components-popover:not(.is-mobile).is-bottom { + &.components-popover:not( .is-mobile ).is-bottom { z-index: 20; } - .components-button:not(:disabled):not([aria-disabled=true]):focus { + .components-button:not( :disabled ):not( [aria-disabled='true'] ):focus { background-color: transparent; box-shadow: none; } diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index b20c45d2264600..68a28d6fd11c32 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -1,23 +1,13 @@ +/** @format */ + /** * External dependencies */ import { __ } from '@wordpress/i18n'; -import { - Component, - createRef, - Fragment -} from '@wordpress/element'; -import { - Button, - Dashicon, - TextareaControl, - TextControl -} from '@wordpress/components'; -import { - get, - assign -} from 'lodash'; +import { Component, createRef, Fragment } from '@wordpress/element'; +import { Button, Dashicon, TextareaControl, TextControl } from '@wordpress/components'; +import { get, assign } from 'lodash'; /** * Internal dependencies @@ -87,20 +77,20 @@ export class Map extends Component { admin && ( updateActiveMarker( { title: value } ) } /> updateActiveMarker( { caption: value } ) } /> ) } diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index 83536b8b9494d7..554b36c471598a 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -1,3 +1,5 @@ +/** @format */ + /** * External dependencies */ @@ -30,19 +32,19 @@ class MapEdit extends Component { }; this.mapRef = createRef(); } - addPoint = ( point ) => { + addPoint = point => { const { attributes, setAttributes } = this.props; const { points } = attributes; const newPoints = points.slice( 0 ); newPoints.push( point ); setAttributes( { points: newPoints } ); this.setState( { addPointVisibility: false } ); - } - updateAlignment = ( value ) => { + }; + updateAlignment = value => { this.props.setAttributes( { align: value } ); // Allow one cycle for alignment change to take effect setTimeout( this.mapRef.current.sizeMap, 0 ); - } + }; render() { const { className, setAttributes, attributes } = this.props; const { map_style, points, zoom, map_center, marker_color, align } = attributes; diff --git a/client/gutenberg/extensions/map-block/editor.scss b/client/gutenberg/extensions/map-block/editor.scss index c482f42e2c8500..6c38238bea2335 100644 --- a/client/gutenberg/extensions/map-block/editor.scss +++ b/client/gutenberg/extensions/map-block/editor.scss @@ -1,4 +1,7 @@ -.wp-block-atavist-maps {} +/** @format */ + +.wp-block-atavist-maps { +} .wp-block-atavist-maps__delete-btn { padding: 0; diff --git a/client/gutenberg/extensions/map-block/index.js b/client/gutenberg/extensions/map-block/index.js index b3669fb4a8b041..73d56e13df88be 100644 --- a/client/gutenberg/extensions/map-block/index.js +++ b/client/gutenberg/extensions/map-block/index.js @@ -1,10 +1,12 @@ +/** @format */ + /** * External dependencies */ - import { registerBlockType } from '@wordpress/blocks'; +import { registerBlockType } from '@wordpress/blocks'; - /** +/** * Internal dependencies */ @@ -27,5 +29,5 @@ registerBlockType( settings.name, { } }, edit, - save + save, } ); diff --git a/client/gutenberg/extensions/map-block/info-window/index.js b/client/gutenberg/extensions/map-block/info-window/index.js index ee1fc4b0a7420b..b9e1f157e71a78 100644 --- a/client/gutenberg/extensions/map-block/info-window/index.js +++ b/client/gutenberg/extensions/map-block/info-window/index.js @@ -1,11 +1,10 @@ +/** @format */ + /** * External dependencies */ -import { - Component, - createPortal -} from '@wordpress/element'; +import { Component, createPortal } from '@wordpress/element'; /** * Internal dependencies @@ -16,32 +15,24 @@ export class InfoWindow extends Component { const { google } = this.props; this.el = document.createElement( 'DIV' ); this.infowindow = new google.maps.InfoWindow( { - content: this.el + content: this.el, } ); - google.maps.event.addListener( this.infowindow,'closeclick', this.closeClick ); + google.maps.event.addListener( this.infowindow, 'closeclick', this.closeClick ); } componentDidUpdate( prevProps ) { if ( this.props.activeMarker !== prevProps.activeMarker ) { - this.props.activeMarker ? - this.openWindow() : - this.closeWindow(); + this.props.activeMarker ? this.openWindow() : this.closeWindow(); } } render() { // Use React portal to render components directly into the Google Maps info window. - return this.el ? - createPortal( - this.props.children, - this.el, - ) : null; - + return this.el ? createPortal( this.props.children, this.el ) : null; } closeClick = () => { this.props.unsetActiveMarker(); - } + }; openWindow() { - this.infowindow - .open( this.props.map, this.props.activeMarker.marker ); + this.infowindow.open( this.props.map, this.props.activeMarker.marker ); } closeWindow() { this.infowindow.close(); @@ -52,7 +43,7 @@ InfoWindow.defaultProps = { unsetActiveMarker: () => {}, activeMarker: null, map: null, - google: null -} + google: null, +}; export default InfoWindow; diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js index bcaedb416aa0b3..031e1ee267f4ec 100644 --- a/client/gutenberg/extensions/map-block/location-search/index.js +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -1,16 +1,12 @@ +/** @format */ + /** * External dependencies */ import { __ } from '@wordpress/i18n'; -import { - Component, - createRef -} from '@wordpress/element'; -import { - BaseControl, - TextControl -} from '@wordpress/components'; +import { Component, createRef } from '@wordpress/element'; +import { BaseControl, TextControl } from '@wordpress/components'; /** * Internal dependencies @@ -21,92 +17,87 @@ import Lookup from '../lookup'; const placeholderText = __( 'Add a marker...', 'jetpack' ); export class LocationSearch extends Component { - constructor() { - super( ...arguments ); this.textRef = createRef(); this.testRef = createRef(); this.state = { - isEmpty: true + isEmpty: true, }; this.autocompleter = { - name: 'placeSearch', - options: this.search.bind(this), + options: this.search.bind( this ), isDebounced: true, - getOptionLabel: option => ( - { option.description } - ), + getOptionLabel: option => { option.description }, getOptionKeywords: option => [ option.description ], - getOptionCompletion: this.getOptionCompletion.bind(this) - + getOptionCompletion: this.getOptionCompletion.bind( this ), }; - } getOptionCompletion( option ) { const { value } = option; const placesService = new window.google.maps.places.PlacesService( this.testRef.current ); - placesService.getDetails( { placeId: value.place_id }, function( place ) { - const point = { - place_title: place.name, - title: place.name, - caption: place.formatted_address, - id: place.place_id, - viewport: place.geometry.viewport, - coordinates: { - latitude: place.geometry.location.lat(), - longitude: place.geometry.location.lng() - } - } - this.props.onAddPoint( point ); - }.bind(this)); + placesService.getDetails( + { placeId: value.place_id }, + function( place ) { + const point = { + place_title: place.name, + title: place.name, + caption: place.formatted_address, + id: place.place_id, + viewport: place.geometry.viewport, + coordinates: { + latitude: place.geometry.location.lat(), + longitude: place.geometry.location.lng(), + }, + }; + this.props.onAddPoint( point ); + }.bind( this ) + ); return option.description; - } search( value ) { const placeSearch = new window.google.maps.places.AutocompleteService(); return new Promise( function( resolve, reject ) { - placeSearch.getPlacePredictions( { - input: value - }, function ( place, status ) { - if ( status !== window.google.maps.places.PlacesServiceStatus.OK ) { - reject( new Error( status ) ); - } else { - resolve( place ); + placeSearch.getPlacePredictions( + { + input: value, + }, + function( place, status ) { + if ( status !== window.google.maps.places.PlacesServiceStatus.OK ) { + reject( new Error( status ) ); + } else { + resolve( place ); + } } - }); - }); - + ); + } ); } onReset = () => { this.textRef.current.value = null; - } + }; render() { - const { label } = this.props; return ( - + { ( { isExpanded, listBoxId, activeId, onChange, onKeyDown } ) => ( + onChange={ onChange } + aria-expanded={ isExpanded } + aria-owns={ listBoxId } + aria-activedescendant={ activeId } + onKeyDown={ onKeyDown } + /> ) } -
+
); - } } diff --git a/client/gutenberg/extensions/map-block/locations/index.js b/client/gutenberg/extensions/map-block/locations/index.js index a8cf45b2ce0b3e..17db009b334cea 100644 --- a/client/gutenberg/extensions/map-block/locations/index.js +++ b/client/gutenberg/extensions/map-block/locations/index.js @@ -1,3 +1,5 @@ +/** @format */ + /** * External dependencies */ @@ -8,7 +10,7 @@ import { Panel, PanelBody, TextareaControl, - TextControl + TextControl, } from '@wordpress/components'; import { Component } from '@wordpress/element'; @@ -19,66 +21,57 @@ import { Component } from '@wordpress/element'; import './style.scss'; export class Locations extends Component { - constructor() { super( ...arguments ); this.state = { - selectedCell: null + selectedCell: null, }; } - onDeletePoint = ( e ) => { + onDeletePoint = e => { const index = parseInt( e.target.getAttribute( 'data-id' ) ); - const { - points, - onChange - } = this.props; + const { points, onChange } = this.props; const newPoints = points.slice( 0 ); newPoints.splice( index, 1 ); onChange( newPoints ); - } + }; setMarkerField( field, value, index ) { - const { - points, - onChange - } = this.props; + const { points, onChange } = this.props; const newPoints = points.slice( 0 ); - newPoints[index][field] = value; + newPoints[ index ][ field ] = value; onChange( newPoints ); } render() { const { points } = this.props; - const rows = points.map( ( point, index ) => + const rows = points.map( ( point, index ) => ( this.setMarkerField( 'title', title, index ) } + onChange={ title => this.setMarkerField( 'title', title, index ) } /> this.setMarkerField( 'caption', caption, index ) } + rows="3" + onChange={ caption => this.setMarkerField( 'caption', caption, index ) } /> - ); + ) ); return ( -
- - { rows } - +
+ { rows }
); } @@ -86,7 +79,7 @@ export class Locations extends Component { Locations.defaultProps = { points: Object.freeze( [] ), - onChange: () => {} + onChange: () => {}, }; export default Locations; diff --git a/client/gutenberg/extensions/map-block/locations/style.scss b/client/gutenberg/extensions/map-block/locations/style.scss index 8d78a2cab704c6..041b0d36cf9822 100644 --- a/client/gutenberg/extensions/map-block/locations/style.scss +++ b/client/gutenberg/extensions/map-block/locations/style.scss @@ -1,3 +1,5 @@ +/** @format */ + .component__locations__panel { margin-bottom: 1em; &:empty { diff --git a/client/gutenberg/extensions/map-block/lookup/index.js b/client/gutenberg/extensions/map-block/lookup/index.js index 13ecfe7fd2b91c..c80a4918a785df 100644 --- a/client/gutenberg/extensions/map-block/lookup/index.js +++ b/client/gutenberg/extensions/map-block/lookup/index.js @@ -1,36 +1,16 @@ +/** @format */ + /** * External dependencies */ import { Component } from '@wordpress/element'; -import { - __, - _n, - sprintf -} from '@wordpress/i18n'; -import { - withInstanceId, - compose -} from '@wordpress/compose'; -import { - ENTER, - ESCAPE, - UP, - DOWN, - LEFT, - RIGHT -} from '@wordpress/keycodes'; -import { - Button, - Popover, - withFocusOutside, - withSpokenMessages -} from '@wordpress/components'; +import { __, _n, sprintf } from '@wordpress/i18n'; +import { withInstanceId, compose } from '@wordpress/compose'; +import { ENTER, ESCAPE, UP, DOWN, LEFT, RIGHT } from '@wordpress/keycodes'; +import { Button, Popover, withFocusOutside, withSpokenMessages } from '@wordpress/components'; import classnames from 'classnames'; -import { - map, - debounce -} from 'lodash'; +import { map, debounce } from 'lodash'; function filterOptions( options = [], maxResults = 10 ) { const filtered = []; @@ -55,16 +35,13 @@ function filterOptions( options = [], maxResults = 10 ) { } export class Lookup extends Component { - static getInitialState() { - return { selectedIndex: 0, query: undefined, filteredOptions: [], - isOpen: false + isOpen: false, }; - } constructor() { @@ -74,37 +51,29 @@ export class Lookup extends Component { } componentWillUnmount() { - this.debouncedLoadOptions.cancel(); } - select = ( option ) => { - + select = option => { const { completer } = this.props; const getOptionCompletion = completer.getOptionCompletion || {}; getOptionCompletion( option ); this.reset(); - - } + }; reset = () => { - this.setState( this.constructor.getInitialState() ); - - } + }; handleFocusOutside() { - this.reset(); - } loadOptions( completer, query ) { - const { options } = completer; - const promise = this.activePromise = Promise.resolve( + const promise = ( this.activePromise = Promise.resolve( typeof options === 'function' ? options( query ) : options - ).then( ( optionsData ) => { + ).then( optionsData => { if ( promise !== this.activePromise ) { // Another promise has become active since this one was asked to resolve, so do nothing, // or else we might end triggering a race condition updating the state. @@ -114,22 +83,23 @@ export class Lookup extends Component { key: `${ optionIndex }`, value: optionData, label: completer.getOptionLabel( optionData ), - keywords: completer.getOptionKeywords ? completer.getOptionKeywords( optionData ) : [] + keywords: completer.getOptionKeywords ? completer.getOptionKeywords( optionData ) : [], } ) ); const filteredOptions = filterOptions( keyedOptions ); - const selectedIndex = filteredOptions.length === this.state.filteredOptions.length ? this.state.selectedIndex : 0; + const selectedIndex = + filteredOptions.length === this.state.filteredOptions.length ? this.state.selectedIndex : 0; this.setState( { [ 'options' ]: keyedOptions, filteredOptions, selectedIndex, - isOpen: filteredOptions.length > 0 + isOpen: filteredOptions.length > 0, } ); this.announce( filteredOptions ); - } ); + } ) ); } - onChange = ( query ) => { + onChange = query => { const { completer } = this.props; const { options } = this.state; @@ -150,9 +120,9 @@ export class Lookup extends Component { if ( completer ) { this.setState( { selectedIndex: 0, filteredOptions, query } ); } - } + }; - onKeyDown = ( event ) => { + onKeyDown = event => { const { isOpen, selectedIndex, filteredOptions } = this.state; if ( ! isOpen ) { return; @@ -187,24 +157,29 @@ export class Lookup extends Component { // the early return in the default case. event.preventDefault(); event.stopPropagation(); - } + }; announce( filteredOptions ) { const { debouncedSpeak } = this.props; if ( ! debouncedSpeak ) { return; } if ( !! filteredOptions.length ) { - debouncedSpeak( sprintf( _n( - '%d result found, use up and down arrow keys to navigate.', - '%d results found, use up and down arrow keys to navigate.', - filteredOptions.length - ), filteredOptions.length ), 'assertive' ); + debouncedSpeak( + sprintf( + _n( + '%d result found, use up and down arrow keys to navigate.', + '%d results found, use up and down arrow keys to navigate.', + filteredOptions.length + ), + filteredOptions.length + ), + 'assertive' + ); } else { debouncedSpeak( __( 'No results.', 'jetpack' ), 'assertive' ); } } render() { - const { onChange, onKeyDown } = this; const { children, instanceId, completer } = this.props; const { selectedIndex, filteredOptions } = this.state; @@ -212,11 +187,11 @@ export class Lookup extends Component { const { className } = completer; const isExpanded = filteredOptions.length > 0; const listBoxId = isExpanded ? `components-autocomplete-listbox-${ instanceId }` : null; - const activeId = isExpanded ? `components-autocomplete-item-${ instanceId }-${ selectedKey }` : null; + const activeId = isExpanded + ? `components-autocomplete-item-${ instanceId }-${ selectedKey }` + : null; return ( -
+
{ children( { isExpanded, listBoxId, activeId, onChange, onKeyDown } ) } { isExpanded && ( -
+
{ map( filteredOptions, ( option, index ) => ( ); } ); return ( - - - { buttons } - + + { buttons } ); - } - } MapThemePicker.defaultProps = { label: '', options: [], value: null, - onChange: () => {} -} + onChange: () => {}, +}; export default MapThemePicker; diff --git a/client/gutenberg/extensions/map-block/map-theme-picker/style.scss b/client/gutenberg/extensions/map-block/map-theme-picker/style.scss index 902dbcc34e50d7..9158a30bad7d1c 100644 --- a/client/gutenberg/extensions/map-block/map-theme-picker/style.scss +++ b/client/gutenberg/extensions/map-block/map-theme-picker/style.scss @@ -1,3 +1,5 @@ +/** @format */ + .component__map-theme-picker__button { border: 1px solid lightgray; border-radius: 100%; @@ -9,10 +11,10 @@ background-position: center center; background-repeat: no-repeat; background-size: contain; - transform: scale(1); - transition: transform .2s ease; + transform: scale( 1 ); + transition: transform 0.2s ease; &:hover { - transform: scale(1.1); + transform: scale( 1.1 ); } &.is-selected { border-color: black; diff --git a/client/gutenberg/extensions/map-block/save.js b/client/gutenberg/extensions/map-block/save.js index 4306c0f1c93433..885cff4e673e5d 100644 --- a/client/gutenberg/extensions/map-block/save.js +++ b/client/gutenberg/extensions/map-block/save.js @@ -1,3 +1,5 @@ +/** @format */ + /** * External dependencies */ diff --git a/client/gutenberg/extensions/map-block/settings.js b/client/gutenberg/extensions/map-block/settings.js index f74be055e71070..3f77e01f5a3bdf 100644 --- a/client/gutenberg/extensions/map-block/settings.js +++ b/client/gutenberg/extensions/map-block/settings.js @@ -1,53 +1,56 @@ +/** @format */ + /** * External dependencies */ import { __ } from '@wordpress/i18n'; - /** +/** * Internal dependencies */ export const settings = { name: 'atavist/maps', title: __( 'Map', 'jetpack' ), - icon: , + icon: ( + + + + + ), category: 'common', - keywords: [ - __( 'map', 'jetpack' ), - __( 'jetpack', 'jetpack' ), - __( 'atavist', 'jetpack' ) - ], + keywords: [ __( 'map', 'jetpack' ), __( 'jetpack', 'jetpack' ), __( 'atavist', 'jetpack' ) ], attributes: { align: { - type: 'string' + type: 'string', }, points: { type: 'array', - default: [] + default: [], }, map_style: { type: 'string', - default: 'default' + default: 'default', }, zoom: { type: 'integer', - default: 13 + default: 13, }, map_center: { type: 'object', default: { latitude: 37.7749295, - longitude: -122.41941550000001 - } + longitude: -122.41941550000001, + }, }, marker_color: { type: 'string', - default: 'red' + default: 'red', }, api_key: { - type: 'string' - } + type: 'string', + }, }, styles: { default: { @@ -55,281 +58,350 @@ export const settings = { styles: [ { elementType: 'labels', - stylers: [ { - visibility: 'on' - } ] + stylers: [ + { + visibility: 'on', + }, + ], }, { featureType: 'poi', elementType: 'labels.text', - stylers: [ { - visibility: 'simplified' - } ] + stylers: [ + { + visibility: 'simplified', + }, + ], }, { featureType: 'poi', elementType: 'labels.icon', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'transit', elementType: 'labels.icons', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'transit', elementType: 'labels.text', - stylers: [ { - visibility: 'off' - } ] - } - ] + stylers: [ + { + visibility: 'off', + }, + ], + }, + ], }, satellite: { map_type: 'SATELLITE', styles: [ { elementType: 'labels', - stylers: [ { - visibility: 'on' - } ] + stylers: [ + { + visibility: 'on', + }, + ], }, { featureType: 'poi', elementType: 'labels.text', - stylers: [ { - visibility: 'simplified' - } ] + stylers: [ + { + visibility: 'simplified', + }, + ], }, { featureType: 'poi', elementType: 'labels.icon', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'transit', elementType: 'labels.icons', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'transit', elementType: 'labels.text', - stylers: [ { - visibility: 'off' - } ] - } - ] + stylers: [ + { + visibility: 'off', + }, + ], + }, + ], }, satellite_with_features: { map_type: 'HYBRID', styles: [ { elementType: 'labels', - stylers: [ { - visibility: 'on' - } ] + stylers: [ + { + visibility: 'on', + }, + ], }, { featureType: 'poi', elementType: 'labels.text', - stylers: [ { - visibility: 'simplified' - } ] + stylers: [ + { + visibility: 'simplified', + }, + ], }, { featureType: 'poi', elementType: 'labels.icon', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'transit', elementType: 'labels.icons', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'transit', elementType: 'labels.text', - stylers: [ { - visibility: 'off' - } ] - } - ] + stylers: [ + { + visibility: 'off', + }, + ], + }, + ], }, terrain: { map_type: 'TERRAIN', styles: [ { featureType: 'administrative', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { elementType: 'labels', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'poi', - stylers: [ { - visibility: 'simplified' - } ] + stylers: [ + { + visibility: 'simplified', + }, + ], }, { featureType: 'poi', elementType: 'labels', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'road', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'transit', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'water', elementType: 'labels', - stylers: [ { - visibility: 'off' - } ] - } - ] + stylers: [ + { + visibility: 'off', + }, + ], + }, + ], }, terrain_with_features: { map_type: 'TERRAIN', styles: [ { elementType: 'labels', - stylers: [ { - visibility: 'on' - } ] + stylers: [ + { + visibility: 'on', + }, + ], }, { featureType: 'poi', elementType: 'labels.text', - stylers: [ { - visibility: 'simplified' - } ] + stylers: [ + { + visibility: 'simplified', + }, + ], }, { featureType: 'poi', elementType: 'labels.icon', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'transit', elementType: 'labels.icons', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'transit', elementType: 'labels.text', - stylers: [ { - visibility: 'off' - } ] - } - ] + stylers: [ + { + visibility: 'off', + }, + ], + }, + ], }, black_and_white: { map_type: 'ROADMAP', styles: [ { - stylers: [ { - saturation: -100 - } ] + stylers: [ + { + saturation: -100, + }, + ], }, { elementType: 'labels', - stylers: [ { - visibility: 'on' - } ] + stylers: [ + { + visibility: 'on', + }, + ], }, { featureType: 'poi', elementType: 'labels.text', - stylers: [ { - visibility: 'simplified' - } ] + stylers: [ + { + visibility: 'simplified', + }, + ], }, { featureType: 'poi', elementType: 'labels.icon', - stylers: [ { - visibility: 'off' - } ] + stylers: [ + { + visibility: 'off', + }, + ], }, { featureType: 'transit', elementType: 'labels.text', - stylers: [ { - visibility: 'simplified' - } ] - } - ] - } + stylers: [ + { + visibility: 'simplified', + }, + ], + }, + ], + }, }, map_styleOptions: [ { value: 'default', - label: __( 'Basic', 'jetpack' ) + label: __( 'Basic', 'jetpack' ), }, { value: 'black_and_white', - label: __( 'Black and white', 'jetpack' ) + label: __( 'Black and white', 'jetpack' ), }, { value: 'satellite', - label: __( 'Satellite', 'jetpack' ) + label: __( 'Satellite', 'jetpack' ), }, { value: 'satellite_with_features', - label: __( 'Satellite (with features)', 'jetpack' ) + label: __( 'Satellite (with features)', 'jetpack' ), }, { value: 'terrain', - label: __( 'Terrain', 'jetpack' ) + label: __( 'Terrain', 'jetpack' ), }, { value: 'terrain_with_features', - label: __( 'Terrain (with features)', 'jetpack' ) - } + label: __( 'Terrain (with features)', 'jetpack' ), + }, ], GOOGLE_MAPS_API_KEY: 'AIzaSyDaj7klnWKpzGx0W5PonA73Dgr68Me8cyg', - baseClasses: [ - 'atavist-block', - 'atavist-simple-map' - ], - validAlignments: [ - 'left', - 'center', - 'right', - 'wide', - 'full' - ], - markerIcon: + baseClasses: [ 'atavist-block', 'atavist-simple-map' ], + validAlignments: [ 'left', 'center', 'right', 'wide', 'full' ], + markerIcon: ( + + + + + + + + + ), }; diff --git a/client/gutenberg/extensions/map-block/style.scss b/client/gutenberg/extensions/map-block/style.scss index 1be7cf056b16d8..7e0658736a285d 100644 --- a/client/gutenberg/extensions/map-block/style.scss +++ b/client/gutenberg/extensions/map-block/style.scss @@ -1,3 +1,5 @@ +/** @format */ + .wp-block-atavist-maps { .wp-block-atavist-maps__gm-container { width: 100%; diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index 282d8d2824f13e..c8bdf87fb2ec93 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -1,3 +1,5 @@ +/** @format */ + /** * Internal dependencies */ diff --git a/client/gutenberg/extensions/shared/atavist/frontend-management.js b/client/gutenberg/extensions/shared/atavist/frontend-management.js index 14db067a030113..79b78a558e556a 100644 --- a/client/gutenberg/extensions/shared/atavist/frontend-management.js +++ b/client/gutenberg/extensions/shared/atavist/frontend-management.js @@ -1,5 +1,7 @@ /** * Wordpress dependencies + * + * @format */ import { createElement, render } from '@wordpress/element'; @@ -15,25 +17,19 @@ import { createElement, render } from '@wordpress/element'; export class FrontendManagement { blockIterator( rootNode, blocks ) { blocks.forEach( block => { - this.initializeFrontendReactBlocks( - block.component, - block.options, - rootNode - ) - } ) - }; + this.initializeFrontendReactBlocks( block.component, block.options, rootNode ); + } ); + } initializeFrontendReactBlocks( component, options = {}, rootNode ) { const { name, attributes } = options.settings; const { selector } = options; - const blockClass = [ '.wp-block', name.replace('/', '-') ].join( '-' ); - rootNode - .querySelectorAll( blockClass ) - .forEach( node => { - const data = this.extractAttributesFromContainer( node.dataset, attributes ); - const children = this.extractChildrenFromContainer( node ); - const el = createElement( component, data, children ); - render( el, selector ? node.querySelector( selector ) : node ); - } ) + const blockClass = [ '.wp-block', name.replace( '/', '-' ) ].join( '-' ); + rootNode.querySelectorAll( blockClass ).forEach( node => { + const data = this.extractAttributesFromContainer( node.dataset, attributes ); + const children = this.extractChildrenFromContainer( node ); + const el = createElement( component, data, children ); + render( el, selector ? node.querySelector( selector ) : node ); + } ); } extractAttributesFromContainer( dataset, attributes ) { const data = {}; @@ -41,14 +37,12 @@ export class FrontendManagement { const attribute = attributes[ name ]; data[ name ] = dataset[ name ]; if ( attribute.type === 'array' || attribute.type === 'object' ) { - try { data[ name ] = JSON.parse( data[ name ] ); - } catch(e) { + } catch ( e ) { // console.log( 'Error decoding JSON data for field ' + name, e); data[ name ] = null; } - } } return data; @@ -60,10 +54,10 @@ export class FrontendManagement { const attr = {}; for ( let i = 0; i < child.attributes.length; i++ ) { const attribute = child.attributes[ i ]; - attr[ attribute.nodeName ] = attribute.nodeValue + attr[ attribute.nodeName ] = attribute.nodeValue; } attr.dangerouslySetInnerHTML = { - __html: child.innerHTML + __html: child.innerHTML, }; return createElement( child.tagName.toLowerCase(), attr ); } ); From 68771da1a118307f4f868c938c48d3a04a95ad8d Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Mon, 22 Oct 2018 20:32:23 -0400 Subject: [PATCH 070/107] Removing 'atavist' from block registration name. --- client/gutenberg/extensions/map-block/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/settings.js b/client/gutenberg/extensions/map-block/settings.js index 3f77e01f5a3bdf..0dbef1506fa538 100644 --- a/client/gutenberg/extensions/map-block/settings.js +++ b/client/gutenberg/extensions/map-block/settings.js @@ -11,7 +11,7 @@ import { __ } from '@wordpress/i18n'; */ export const settings = { - name: 'atavist/maps', + name: 'a8c/maps', title: __( 'Map', 'jetpack' ), icon: ( From 5f0c938fc05dca79776d1cf2148d2587fb21e0e3 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Mon, 22 Oct 2018 20:59:46 -0400 Subject: [PATCH 071/107] Removing all atavist references, and styles. --- .../gutenberg/extensions/map-block/component.js | 6 +++--- .../gutenberg/extensions/map-block/editor.scss | 5 +---- client/gutenberg/extensions/map-block/save.js | 17 ++--------------- .../gutenberg/extensions/map-block/settings.js | 3 +-- .../gutenberg/extensions/map-block/style.scss | 4 ++-- client/gutenberg/extensions/map-block/view.js | 2 +- .../shared/{atavist => }/frontend-management.js | 0 7 files changed, 10 insertions(+), 27 deletions(-) rename client/gutenberg/extensions/shared/{atavist => }/frontend-management.js (100%) diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index 68a28d6fd11c32..5633fbd654ea6a 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -82,14 +82,14 @@ export class Map extends Component { onChange={ value => updateActiveMarker( { title: value } ) } /> updateActiveMarker( { caption: value } ) } /> -
+
{ mapMarkers }
{ infoWindow } diff --git a/client/gutenberg/extensions/map-block/editor.scss b/client/gutenberg/extensions/map-block/editor.scss index 6c38238bea2335..c5c51a91efd0d1 100644 --- a/client/gutenberg/extensions/map-block/editor.scss +++ b/client/gutenberg/extensions/map-block/editor.scss @@ -1,9 +1,6 @@ /** @format */ -.wp-block-atavist-maps { -} - -.wp-block-atavist-maps__delete-btn { +.wp-block-a8c-maps__delete-btn { padding: 0; svg { margin-right: 0.4em; diff --git a/client/gutenberg/extensions/map-block/save.js b/client/gutenberg/extensions/map-block/save.js index 885cff4e673e5d..cc377db37acfa0 100644 --- a/client/gutenberg/extensions/map-block/save.js +++ b/client/gutenberg/extensions/map-block/save.js @@ -5,7 +5,6 @@ */ import { Component } from '@wordpress/element'; -import classnames from 'classnames'; /** * Internal dependencies @@ -16,22 +15,10 @@ import { settings } from './settings.js'; class MapSave extends Component { render() { const { className, attributes } = this.props; - const { map_style, points, zoom, map_center, marker_color, align } = attributes; - const atavistAlignClass = value => { - switch ( value ) { - case 'left': - case 'right': - case 'center': - case 'full': - return 'atavist-block-align-' + value; - default: - return 'atavist-block-align-center'; - } - }; - const classes = classnames( settings.baseClasses, className, atavistAlignClass( align ) ); + const { map_style, points, zoom, map_center, marker_color } = attributes; return (
), category: 'common', - keywords: [ __( 'map', 'jetpack' ), __( 'jetpack', 'jetpack' ), __( 'atavist', 'jetpack' ) ], + keywords: [ __( 'map', 'jetpack' ), __( 'jetpack', 'jetpack' ), __( 'jetpack' ) ], attributes: { align: { type: 'string', @@ -387,7 +387,6 @@ export const settings = { }, ], GOOGLE_MAPS_API_KEY: 'AIzaSyDaj7klnWKpzGx0W5PonA73Dgr68Me8cyg', - baseClasses: [ 'atavist-block', 'atavist-simple-map' ], validAlignments: [ 'left', 'center', 'right', 'wide', 'full' ], markerIcon: ( diff --git a/client/gutenberg/extensions/map-block/style.scss b/client/gutenberg/extensions/map-block/style.scss index 7e0658736a285d..5486dec45f6fc3 100644 --- a/client/gutenberg/extensions/map-block/style.scss +++ b/client/gutenberg/extensions/map-block/style.scss @@ -1,7 +1,7 @@ /** @format */ -.wp-block-atavist-maps { - .wp-block-atavist-maps__gm-container { +.wp-block-a8c-maps { + .wp-block-a8c-maps__gm-container { width: 100%; overflow: hidden; background: lightgray; diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index c8bdf87fb2ec93..230f4417564bff 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -7,7 +7,7 @@ import './style.scss'; import component from './component.js'; import { settings } from './settings.js'; -import FrontendManagement from 'gutenberg/extensions/shared/atavist/frontend-management.js'; +import FrontendManagement from 'gutenberg/extensions/shared/frontend-management.js'; window.addEventListener( 'load', function() { // Do not initialize in editor. diff --git a/client/gutenberg/extensions/shared/atavist/frontend-management.js b/client/gutenberg/extensions/shared/frontend-management.js similarity index 100% rename from client/gutenberg/extensions/shared/atavist/frontend-management.js rename to client/gutenberg/extensions/shared/frontend-management.js From bf7f6a08e4fe3e5f4314c556bf6458c62eaa6a1e Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Tue, 23 Oct 2018 09:36:03 -0400 Subject: [PATCH 072/107] One missing localization text domain, some JsPrettier formatting. --- client/gutenberg/extensions/map-block/lookup/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/lookup/index.js b/client/gutenberg/extensions/map-block/lookup/index.js index c80a4918a785df..23da1ffa6a3a90 100644 --- a/client/gutenberg/extensions/map-block/lookup/index.js +++ b/client/gutenberg/extensions/map-block/lookup/index.js @@ -169,7 +169,8 @@ export class Lookup extends Component { _n( '%d result found, use up and down arrow keys to navigate.', '%d results found, use up and down arrow keys to navigate.', - filteredOptions.length + filteredOptions.length, + 'jetpack' ), filteredOptions.length ), From d2d5f5141cafcf8d53e53501e54f18889e4cc81b Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Tue, 23 Oct 2018 14:16:01 -0400 Subject: [PATCH 073/107] Changing block name prefix from a8c to jetpack. --- client/gutenberg/extensions/map-block/component.js | 6 +++--- client/gutenberg/extensions/map-block/editor.scss | 2 +- client/gutenberg/extensions/map-block/settings.js | 2 +- client/gutenberg/extensions/map-block/style.scss | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index 5633fbd654ea6a..0f4a68aa406020 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -82,14 +82,14 @@ export class Map extends Component { onChange={ value => updateActiveMarker( { title: value } ) } /> updateActiveMarker( { caption: value } ) } /> -
+
{ mapMarkers }
{ infoWindow } diff --git a/client/gutenberg/extensions/map-block/editor.scss b/client/gutenberg/extensions/map-block/editor.scss index c5c51a91efd0d1..7c00f3ad7f3372 100644 --- a/client/gutenberg/extensions/map-block/editor.scss +++ b/client/gutenberg/extensions/map-block/editor.scss @@ -1,6 +1,6 @@ /** @format */ -.wp-block-a8c-maps__delete-btn { +.wp-block-jetpack-maps__delete-btn { padding: 0; svg { margin-right: 0.4em; diff --git a/client/gutenberg/extensions/map-block/settings.js b/client/gutenberg/extensions/map-block/settings.js index 1af7e2dd152aa3..8db1375bb150d8 100644 --- a/client/gutenberg/extensions/map-block/settings.js +++ b/client/gutenberg/extensions/map-block/settings.js @@ -11,7 +11,7 @@ import { __ } from '@wordpress/i18n'; */ export const settings = { - name: 'a8c/maps', + name: 'jetpack/maps', title: __( 'Map', 'jetpack' ), icon: ( diff --git a/client/gutenberg/extensions/map-block/style.scss b/client/gutenberg/extensions/map-block/style.scss index 5486dec45f6fc3..18f4aeda31fa74 100644 --- a/client/gutenberg/extensions/map-block/style.scss +++ b/client/gutenberg/extensions/map-block/style.scss @@ -1,7 +1,7 @@ /** @format */ -.wp-block-a8c-maps { - .wp-block-a8c-maps__gm-container { +.wp-block-jetpack-maps { + .wp-block-jetpack-maps__gm-container { width: 100%; overflow: hidden; background: lightgray; From e45afaed53c81436fcb2f5abce7645281e74dc26 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Tue, 23 Oct 2018 19:42:24 -0400 Subject: [PATCH 074/107] Use Jetpack REST API for Google Maps API Key. --- .../extensions/map-block/component.js | 11 ++++--- client/gutenberg/extensions/map-block/edit.js | 33 +++++++++++++++++-- client/gutenberg/extensions/map-block/save.js | 3 -- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index 0f4a68aa406020..488b1dda1c37b6 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -16,6 +16,7 @@ import { get, assign } from 'lodash'; import { settings } from './settings.js'; import MapMarker from './map-marker/'; import InfoWindow from './info-window/'; + // @TODO: replace with import from lib/load-script after resolution of https://github.com/Automattic/wp-calypso/issues/27821 import { loadScript } from './load-script'; // import { loadScript } from 'lib/load-script'; @@ -114,13 +115,15 @@ export class Map extends Component { ); } - componentDidMount() { - this.loadMapLibraries(); - } componentDidUpdate( prevProps ) { + const { api_key, children } = this.props; + if ( api_key && api_key.length > 0 && api_key !== prevProps.api_key ) { + window.google = null; + this.loadMapLibraries(); + } // If the user has just clicked to show the Add Point component, hide info window. // AddPoint is the only possible child. - if ( this.props.children !== prevProps.children && this.props.children !== false ) { + if ( children !== prevProps.children && children !== false ) { this.clearCurrentMarker(); } // This implementation of componentDidUpdate is a reusable way to approximate Polymer observers diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index 554b36c471598a..9f1312c59cc8ba 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -6,13 +6,14 @@ import { __ } from '@wordpress/i18n'; import { Component, createRef, Fragment } from '@wordpress/element'; -import { IconButton, PanelBody, Toolbar } from '@wordpress/components'; +import { Button, IconButton, PanelBody, Toolbar, TextControl } from '@wordpress/components'; import { InspectorControls, BlockControls, BlockAlignmentToolbar, PanelColorSettings, } from '@wordpress/editor'; +import apiFetch from '@wordpress/api-fetch'; /** * Internal dependencies @@ -45,10 +46,28 @@ class MapEdit extends Component { // Allow one cycle for alignment change to take effect setTimeout( this.mapRef.current.sizeMap, 0 ); }; + updateAPIKey = () => { + const { apiKeyControl } = this.state; + this.apiCall( apiKeyControl ); + }; + apiCall( api_key = null ) { + const method = api_key ? 'POST' : 'GET'; + const url = '/wp-json/jetpack/v4/api-key/googlemaps'; + const fetch = api_key ? { url, method, data: { api_key } } : { url, method }; + apiFetch( fetch ).then( result => { + this.setState( { + api_key: result.api_key, + apiKeyControl: result.api_key, + } ); + } ); + } + componentDidMount() { + this.apiCall(); + } render() { const { className, setAttributes, attributes } = this.props; const { map_style, points, zoom, map_center, marker_color, align } = attributes; - const { addPointVisibility } = this.state; + const { addPointVisibility, api_key, apiKeyControl } = this.state; const inspectorControls = ( @@ -92,6 +111,14 @@ class MapEdit extends Component { /> ) : null } + this.setState( { apiKeyControl: value } ) } + /> + ); @@ -109,8 +136,8 @@ class MapEdit extends Component { onSetZoom={ value => { setAttributes( { zoom: value } ); } } - api_key={ settings.GOOGLE_MAPS_API_KEY } admin={ true } + api_key={ api_key } onSetPoints={ value => setAttributes( { points: value } ) } onMapLoaded={ () => this.setState( { addPointVisibility: true } ) } onMarkerClick={ () => this.setState( { addPointVisibility: false } ) } diff --git a/client/gutenberg/extensions/map-block/save.js b/client/gutenberg/extensions/map-block/save.js index cc377db37acfa0..13b9ee07436fbc 100644 --- a/client/gutenberg/extensions/map-block/save.js +++ b/client/gutenberg/extensions/map-block/save.js @@ -10,8 +10,6 @@ import { Component } from '@wordpress/element'; * Internal dependencies */ -import { settings } from './settings.js'; - class MapSave extends Component { render() { const { className, attributes } = this.props; @@ -24,7 +22,6 @@ class MapSave extends Component { data-zoom={ zoom } data-map_center={ JSON.stringify( map_center ) } data-marker_color={ marker_color } - data-api_key={ settings.GOOGLE_MAPS_API_KEY } /> ); } From 1920bb149f2f1ef5bdf97de26db2a3a2ea03cb9a Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Tue, 23 Oct 2018 20:36:05 -0400 Subject: [PATCH 075/107] Google Maps API key retrieval by API in view. --- .../extensions/map-block/component.js | 6 ++++++ client/gutenberg/extensions/map-block/view.js | 19 +++++++++++++------ .../extensions/shared/frontend-management.js | 9 ++++----- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index 488b1dda1c37b6..ee1dff2667d3bb 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -115,6 +115,12 @@ export class Map extends Component { ); } + componentDidMount() { + const { api_key } = this.props; + if ( api_key ) { + this.loadMapLibraries(); + } + } componentDidUpdate( prevProps ) { const { api_key, children } = this.props; if ( api_key && api_key.length > 0 && api_key !== prevProps.api_key ) { diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index 230f4417564bff..8fffe6bcffacc6 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -8,6 +8,7 @@ import './style.scss'; import component from './component.js'; import { settings } from './settings.js'; import FrontendManagement from 'gutenberg/extensions/shared/frontend-management.js'; +import apiFetch from '@wordpress/api-fetch'; window.addEventListener( 'load', function() { // Do not initialize in editor. @@ -15,10 +16,16 @@ window.addEventListener( 'load', function() { return; } const frontendManagement = new FrontendManagement(); - frontendManagement.blockIterator( document, [ - { - component: component, - options: { settings }, - }, - ] ); + const url = '/wp-json/jetpack/v4/api-key/googlemaps'; + apiFetch( { url, method: 'GET' } ).then( result => { + frontendManagement.blockIterator( document, [ + { + component: component, + options: { + settings, + props: { api_key: result.api_key }, + }, + }, + ] ); + } ); } ); diff --git a/client/gutenberg/extensions/shared/frontend-management.js b/client/gutenberg/extensions/shared/frontend-management.js index 79b78a558e556a..47efa7ba6f94de 100644 --- a/client/gutenberg/extensions/shared/frontend-management.js +++ b/client/gutenberg/extensions/shared/frontend-management.js @@ -1,19 +1,17 @@ /** - * Wordpress dependencies + * External dependencies * * @format */ import { createElement, render } from '@wordpress/element'; -/** - * External dependencies - */ - /** * Internal dependencies */ +import { assign } from 'lodash'; + export class FrontendManagement { blockIterator( rootNode, blocks ) { blocks.forEach( block => { @@ -26,6 +24,7 @@ export class FrontendManagement { const blockClass = [ '.wp-block', name.replace( '/', '-' ) ].join( '-' ); rootNode.querySelectorAll( blockClass ).forEach( node => { const data = this.extractAttributesFromContainer( node.dataset, attributes ); + assign( data, options.props ); const children = this.extractChildrenFromContainer( node ); const el = createElement( component, data, children ); render( el, selector ? node.querySelector( selector ) : node ); From 4bbe2489913d4fd7d07b39016601331614f5f5e2 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 24 Oct 2018 12:46:19 -0400 Subject: [PATCH 076/107] API key deletion. Notices on API update error. --- client/gutenberg/extensions/map-block/edit.js | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index 9f1312c59cc8ba..2ad01893b80095 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -6,7 +6,14 @@ import { __ } from '@wordpress/i18n'; import { Component, createRef, Fragment } from '@wordpress/element'; -import { Button, IconButton, PanelBody, Toolbar, TextControl } from '@wordpress/components'; +import { + Button, + IconButton, + PanelBody, + Toolbar, + TextControl, + withNotices, +} from '@wordpress/components'; import { InspectorControls, BlockControls, @@ -48,24 +55,33 @@ class MapEdit extends Component { }; updateAPIKey = () => { const { apiKeyControl } = this.state; - this.apiCall( apiKeyControl ); + this.apiCall( apiKeyControl, 'POST' ); + }; + removeAPIKey = () => { + this.apiCall( null, 'DELETE' ); }; - apiCall( api_key = null ) { - const method = api_key ? 'POST' : 'GET'; + apiCall( api_key = null, method = 'GET' ) { + const { noticeOperations } = this.props; const url = '/wp-json/jetpack/v4/api-key/googlemaps'; const fetch = api_key ? { url, method, data: { api_key } } : { url, method }; - apiFetch( fetch ).then( result => { - this.setState( { - api_key: result.api_key, - apiKeyControl: result.api_key, + apiFetch( fetch ) + .then( result => { + noticeOperations.removeAllNotices(); + this.setState( { + api_key: result.api_key, + apiKeyControl: result.api_key, + } ); + } ) + .catch( result => { + noticeOperations.removeAllNotices(); + noticeOperations.createErrorNotice( result.message ); } ); - } ); } componentDidMount() { this.apiCall(); } render() { - const { className, setAttributes, attributes } = this.props; + const { className, setAttributes, attributes, noticeUI } = this.props; const { map_style, points, zoom, map_center, marker_color, align } = attributes; const { addPointVisibility, api_key, apiKeyControl } = this.state; const inspectorControls = ( @@ -119,11 +135,15 @@ class MapEdit extends Component { + ); return ( + { noticeUI } { inspectorControls }
Date: Wed, 24 Oct 2018 17:14:29 -0400 Subject: [PATCH 077/107] Placeholder with API key field for first-time users who have not yet set the key. Initial loading screen before first API call to retrieve the key. --- client/gutenberg/extensions/map-block/edit.js | 80 ++++++++++++++++--- 1 file changed, 67 insertions(+), 13 deletions(-) diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index 2ad01893b80095..c31dbc9e670869 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -4,12 +4,15 @@ * External dependencies */ -import { __ } from '@wordpress/i18n'; -import { Component, createRef, Fragment } from '@wordpress/element'; +import { __, sprintf } from '@wordpress/i18n'; +import { Component, createRef, Fragment, RawHTML } from '@wordpress/element'; import { Button, + ButtonGroup, IconButton, PanelBody, + Placeholder, + Spinner, Toolbar, TextControl, withNotices, @@ -21,6 +24,7 @@ import { PanelColorSettings, } from '@wordpress/editor'; import apiFetch from '@wordpress/api-fetch'; +import { debounce } from 'lodash'; /** * Internal dependencies @@ -32,13 +36,22 @@ import Locations from './locations'; import Map from './component.js'; import MapThemePicker from './map-theme-picker'; +const API_STATE_LOADING = 0; +const API_STATE_FAILURE = 1; +const API_STATE_SUCCESS = 2; + class MapEdit extends Component { constructor() { super( ...arguments ); this.state = { addPointVisibility: false, + apiState: API_STATE_LOADING, }; this.mapRef = createRef(); + this.debouncedUpdateAPIKey = debounce( this.updateAPIKey, 800 ); + } + componentWillUnmount() { + this.debouncedAPIKey.cancel(); } addPoint = point => { const { attributes, setAttributes } = this.props; @@ -53,9 +66,14 @@ class MapEdit extends Component { // Allow one cycle for alignment change to take effect setTimeout( this.mapRef.current.sizeMap, 0 ); }; + updateAPIKeyControl = value => { + this.setState( { apiKeyControl: value }, this.debouncedUpdateAPIKey ); + }; updateAPIKey = () => { + const { noticeOperations } = this.props; const { apiKeyControl } = this.state; - this.apiCall( apiKeyControl, 'POST' ); + noticeOperations.removeAllNotices(); + apiKeyControl && this.apiCall( apiKeyControl, 'POST' ); }; removeAPIKey = () => { this.apiCall( null, 'DELETE' ); @@ -68,6 +86,7 @@ class MapEdit extends Component { .then( result => { noticeOperations.removeAllNotices(); this.setState( { + apiState: result.api_key ? API_STATE_SUCCESS : API_STATE_FAILURE, api_key: result.api_key, apiKeyControl: result.api_key, } ); @@ -75,15 +94,18 @@ class MapEdit extends Component { .catch( result => { noticeOperations.removeAllNotices(); noticeOperations.createErrorNotice( result.message ); + this.setState( { + apiState: API_STATE_FAILURE, + } ); } ); } componentDidMount() { this.apiCall(); } render() { - const { className, setAttributes, attributes, noticeUI } = this.props; + const { className, setAttributes, attributes, noticeUI, notices } = this.props; const { map_style, points, zoom, map_center, marker_color, align } = attributes; - const { addPointVisibility, api_key, apiKeyControl } = this.state; + const { addPointVisibility, api_key, apiKeyControl, apiState } = this.state; const inspectorControls = ( @@ -132,18 +154,42 @@ class MapEdit extends Component { value={ apiKeyControl } onChange={ value => this.setState( { apiKeyControl: value } ) } /> - - + + + + ); - return ( + const placholderAPIStateLoading = ( + + + + ); + const getAPIInstructions = sprintf( + "This is your first map block. You need to get a Google Maps API key. Here's how to do it.", + 'https://developers.google.com/maps/documentation/javascript/get-api-key' + ); + const placeholderAPIStateFailure = ( + + +
+ { getAPIInstructions } +
+ +
+
+ ); + const placeholderAPIStateSuccess = ( - { noticeUI } { inspectorControls }
); + return ( + + { noticeUI } + { apiState === API_STATE_LOADING && placholderAPIStateLoading } + { apiState === API_STATE_FAILURE && placeholderAPIStateFailure } + { apiState === API_STATE_SUCCESS && placeholderAPIStateSuccess } + + ); } } From df8605054a1636ebc867f230fd3c0351de266314 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 24 Oct 2018 18:52:40 -0400 Subject: [PATCH 078/107] Google Maps API Key form field in its own PanelGroup. Markers & Google Maps API Key areas begin collapsed. --- client/gutenberg/extensions/map-block/edit.js | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index c31dbc9e670869..b91a55ae4005fd 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -140,7 +140,7 @@ class MapEdit extends Component { ] } /> { points.length ? ( - + { @@ -149,19 +149,20 @@ class MapEdit extends Component { /> ) : null } - this.setState( { apiKeyControl: value } ) } - /> - - - - + + this.setState( { apiKeyControl: value } ) } + /> + + + + + ); From 6d851442225017e1287124a9077431cec508d543 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Wed, 24 Oct 2018 19:20:05 -0400 Subject: [PATCH 079/107] Some tweaks to the Google Maps API form element area. --- client/gutenberg/extensions/map-block/edit.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index b91a55ae4005fd..dedf9138f32087 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -151,14 +151,15 @@ class MapEdit extends Component { ) : null } this.setState( { apiKeyControl: value } ) } /> - - From 925707c2ca21923e8ad7185eefd6e92b44e57c2f Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 25 Oct 2018 09:52:45 -0400 Subject: [PATCH 080/107] Change to Service API Keys endpoint. --- client/gutenberg/extensions/map-block/edit.js | 2 +- client/gutenberg/extensions/map-block/view.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index dedf9138f32087..56bf91c56be111 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -80,7 +80,7 @@ class MapEdit extends Component { }; apiCall( api_key = null, method = 'GET' ) { const { noticeOperations } = this.props; - const url = '/wp-json/jetpack/v4/api-key/googlemaps'; + const url = '/wp-json/jetpack/v4/api-keys/googlemaps'; const fetch = api_key ? { url, method, data: { api_key } } : { url, method }; apiFetch( fetch ) .then( result => { diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index 8fffe6bcffacc6..58fefc57781b8c 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -16,7 +16,7 @@ window.addEventListener( 'load', function() { return; } const frontendManagement = new FrontendManagement(); - const url = '/wp-json/jetpack/v4/api-key/googlemaps'; + const url = '/wp-json/jetpack/v4/api-keys/googlemaps'; apiFetch( { url, method: 'GET' } ).then( result => { frontendManagement.blockIterator( document, [ { From 9608c88d613e5f13ac2944009f2d4a9d07214dbb Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 25 Oct 2018 09:56:07 -0400 Subject: [PATCH 081/107] A better change to the Service API Keys endpoint. --- client/gutenberg/extensions/map-block/edit.js | 2 +- client/gutenberg/extensions/map-block/view.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index 56bf91c56be111..6caf9eb899a535 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -80,7 +80,7 @@ class MapEdit extends Component { }; apiCall( api_key = null, method = 'GET' ) { const { noticeOperations } = this.props; - const url = '/wp-json/jetpack/v4/api-keys/googlemaps'; + const url = '/wp-json/jetpack/v4/service-api-keys/googlemaps'; const fetch = api_key ? { url, method, data: { api_key } } : { url, method }; apiFetch( fetch ) .then( result => { diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index 58fefc57781b8c..e8f04dafe53650 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -16,7 +16,7 @@ window.addEventListener( 'load', function() { return; } const frontendManagement = new FrontendManagement(); - const url = '/wp-json/jetpack/v4/api-keys/googlemaps'; + const url = '/wp-json/jetpack/v4/service-api-keys/googlemaps'; apiFetch( { url, method: 'GET' } ).then( result => { frontendManagement.blockIterator( document, [ { From 28808a5452569cbbba49b8a2466d4589e2db7652 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 25 Oct 2018 11:41:28 -0400 Subject: [PATCH 082/107] Changes to the /service-api-keys/ parameters. --- client/gutenberg/extensions/map-block/edit.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index 6caf9eb899a535..cad656988aaf81 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -78,17 +78,17 @@ class MapEdit extends Component { removeAPIKey = () => { this.apiCall( null, 'DELETE' ); }; - apiCall( api_key = null, method = 'GET' ) { + apiCall( service_api_key = null, method = 'GET' ) { const { noticeOperations } = this.props; const url = '/wp-json/jetpack/v4/service-api-keys/googlemaps'; - const fetch = api_key ? { url, method, data: { api_key } } : { url, method }; + const fetch = service_api_key ? { url, method, data: { service_api_key } } : { url, method }; apiFetch( fetch ) .then( result => { noticeOperations.removeAllNotices(); this.setState( { - apiState: result.api_key ? API_STATE_SUCCESS : API_STATE_FAILURE, - api_key: result.api_key, - apiKeyControl: result.api_key, + apiState: result.service_api_key ? API_STATE_SUCCESS : API_STATE_FAILURE, + api_key: result.service_api_key, + apiKeyControl: result.service_api_key, } ); } ) .catch( result => { From dadf5f82317b02e8707f7d43021a775a7e9e9ce3 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 25 Oct 2018 16:10:55 -0400 Subject: [PATCH 083/107] Better apiFetch promise, using second param of .then() as the catch. --- client/gutenberg/extensions/map-block/edit.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index cad656988aaf81..26a0ee00f2640f 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -82,22 +82,23 @@ class MapEdit extends Component { const { noticeOperations } = this.props; const url = '/wp-json/jetpack/v4/service-api-keys/googlemaps'; const fetch = service_api_key ? { url, method, data: { service_api_key } } : { url, method }; - apiFetch( fetch ) - .then( result => { + apiFetch( fetch ).then( + result => { noticeOperations.removeAllNotices(); this.setState( { apiState: result.service_api_key ? API_STATE_SUCCESS : API_STATE_FAILURE, api_key: result.service_api_key, apiKeyControl: result.service_api_key, } ); - } ) - .catch( result => { + }, + result => { noticeOperations.removeAllNotices(); noticeOperations.createErrorNotice( result.message ); this.setState( { apiState: API_STATE_FAILURE, } ); - } ); + } + ); } componentDidMount() { this.apiCall(); From 10ccbdf8d1c6353df431f3dfcba1e4d139a3113f Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 25 Oct 2018 22:52:16 -0400 Subject: [PATCH 084/107] Additional keyword, removed translation for "jetpack" as it is a brand name. --- client/gutenberg/extensions/map-block/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/settings.js b/client/gutenberg/extensions/map-block/settings.js index 8db1375bb150d8..c43407bafdd865 100644 --- a/client/gutenberg/extensions/map-block/settings.js +++ b/client/gutenberg/extensions/map-block/settings.js @@ -20,7 +20,7 @@ export const settings = { ), category: 'common', - keywords: [ __( 'map', 'jetpack' ), __( 'jetpack', 'jetpack' ), __( 'jetpack' ) ], + keywords: [ __( 'map', 'jetpack' ), __( 'location', 'jetpack' ), 'jetpack' ], attributes: { align: { type: 'string', From 7ce9855bfd071e1d9f64cc93314c6ca707f2ad99 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 25 Oct 2018 22:52:59 -0400 Subject: [PATCH 085/107] Bug fix: frontend Google Maps API retrieval was out of date with recent changes to the API. --- client/gutenberg/extensions/map-block/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index e8f04dafe53650..6d39cdeefefcc5 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -23,7 +23,7 @@ window.addEventListener( 'load', function() { component: component, options: { settings, - props: { api_key: result.api_key }, + props: { api_key: result.service_api_key }, }, }, ] ); From 1c47ada219ec25ac2883a602da748e2181be60c9 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 25 Oct 2018 23:06:22 -0400 Subject: [PATCH 086/107] Removing left/right alignment options. --- client/gutenberg/extensions/map-block/edit.js | 6 +++++- client/gutenberg/extensions/map-block/settings.js | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index 26a0ee00f2640f..dae29b67e60f59 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -110,7 +110,11 @@ class MapEdit extends Component { const inspectorControls = ( - + From 8ac2e2a0c90d47e6d16f4680827001cbba9e624c Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Fri, 26 Oct 2018 11:38:50 -0400 Subject: [PATCH 087/107] New approach to map styles, with four options available (Roadmap, Terrain, Satellite, Black & White) and toggle to control details. --- .../extensions/map-block/component.js | 25 +- client/gutenberg/extensions/map-block/edit.js | 15 +- .../map-block/google-map-formatter/index.js | 41 +++ .../map-block/map-theme-picker/index.js | 8 +- .../map-block/map-theme-picker/style.scss | 12 +- client/gutenberg/extensions/map-block/save.js | 3 +- .../extensions/map-block/settings.js | 320 +----------------- .../extensions/shared/frontend-management.js | 3 + 8 files changed, 90 insertions(+), 337 deletions(-) create mode 100644 client/gutenberg/extensions/map-block/google-map-formatter/index.js diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index ee1dff2667d3bb..69231e5d26d5cb 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -13,9 +13,9 @@ import { get, assign } from 'lodash'; * Internal dependencies */ -import { settings } from './settings.js'; import MapMarker from './map-marker/'; import InfoWindow from './info-window/'; +import { googleMapFormatter } from './google-map-formatter/'; // @TODO: replace with import from lib/load-script after resolution of https://github.com/Automattic/wp-calypso/issues/27821 import { loadScript } from './load-script'; @@ -147,14 +147,19 @@ export class Map extends Component { pointsChanged() { this.setBoundsByMarkers(); } - map_styleChanged() { + mapStyleAndDetailsChanged() { const { map, google } = this.state; - map.setOptions( { styles: this.getMapStyle(), mapTypeId: google.maps.MapTypeId[ this.getMapType() ], } ); } + map_styleChanged() { + this.mapStyleAndDetailsChanged(); + } + map_detailsChanged() { + this.mapStyleAndDetailsChanged(); + } // Event handling onMarkerClick( marker ) { const { onMarkerClick } = this.props; @@ -224,10 +229,20 @@ export class Map extends Component { map.setOptions( { zoomControl: true } ); } getMapStyle() { - return settings.styles[ this.props.map_style ].styles; + const { map_style, map_details } = this.props; + return googleMapFormatter( map_style, map_details ); } getMapType() { - return settings.styles[ this.props.map_style ].map_type; + const { map_style } = this.props; + switch ( map_style ) { + case 'satellite': + return 'HYBRID'; + case 'terrain': + return 'TERRAIN'; + case 'black_and_white': + default: + return 'ROADMAP'; + } } getMarkerIcon() { const { marker_color } = this.props; diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index dae29b67e60f59..3be2077f3a350c 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -13,6 +13,7 @@ import { PanelBody, Placeholder, Spinner, + ToggleControl, Toolbar, TextControl, withNotices, @@ -105,7 +106,7 @@ class MapEdit extends Component { } render() { const { className, setAttributes, attributes, noticeUI, notices } = this.props; - const { map_style, points, zoom, map_center, marker_color, align } = attributes; + const { map_style, map_details, points, zoom, map_center, marker_color, align } = attributes; const { addPointVisibility, api_key, apiKeyControl, apiState } = this.state; const inspectorControls = ( @@ -127,12 +128,17 @@ class MapEdit extends Component { { - setAttributes( { map_style: value } ); - } } + onChange={ value => setAttributes( { map_style: value } ) } options={ settings.map_styleOptions } /> + + setAttributes( { map_details: value } ) } + /> + { const classes = classnames( 'component__map-theme-picker__button', @@ -25,7 +24,12 @@ export class MapThemePicker extends Component { option.value === value ? 'is-selected' : '' ); return ( - ); diff --git a/client/gutenberg/extensions/map-block/map-theme-picker/style.scss b/client/gutenberg/extensions/map-block/map-theme-picker/style.scss index 9158a30bad7d1c..f07f7be9a08e85 100644 --- a/client/gutenberg/extensions/map-block/map-theme-picker/style.scss +++ b/client/gutenberg/extensions/map-block/map-theme-picker/style.scss @@ -3,9 +3,9 @@ .component__map-theme-picker__button { border: 1px solid lightgray; border-radius: 100%; - width: 70px; - height: 70px; - margin: 5px; + width: 56px; + height: 56px; + margin: 2px; text-indent: -9999px; background-color: lightgray; background-position: center center; @@ -26,15 +26,9 @@ background-image: url( 'https://s3.amazonaws.com/atavist-static/map-themes/map-theme-black_and_white.jpg' ); } &.is-theme-satellite { - background-image: url( 'https://s3.amazonaws.com/atavist-static/map-themes/map-theme-satellite.jpg' ); - } - &.is-theme-satellite_with_features { background-image: url( 'https://s3.amazonaws.com/atavist-static/map-themes/map-theme-satellite_with_features.jpg' ); } &.is-theme-terrain { - background-image: url( 'https://s3.amazonaws.com/atavist-static/map-themes/map-theme-terrain.jpg' ); - } - &.is-theme-terrain_with_features { background-image: url( 'https://s3.amazonaws.com/atavist-static/map-themes/map-theme-terrain_with_features.jpg' ); } } diff --git a/client/gutenberg/extensions/map-block/save.js b/client/gutenberg/extensions/map-block/save.js index 13b9ee07436fbc..59c914f6a48bce 100644 --- a/client/gutenberg/extensions/map-block/save.js +++ b/client/gutenberg/extensions/map-block/save.js @@ -13,11 +13,12 @@ import { Component } from '@wordpress/element'; class MapSave extends Component { render() { const { className, attributes } = this.props; - const { map_style, points, zoom, map_center, marker_color } = attributes; + const { map_style, map_details, points, zoom, map_center, marker_color } = attributes; return (
Date: Wed, 31 Oct 2018 16:57:18 -0400 Subject: [PATCH 088/107] Switch to Mapbox from Google Maps. --- .../extensions/map-block/add-point/index.js | 8 +- .../extensions/map-block/component.js | 192 +++--- client/gutenberg/extensions/map-block/edit.js | 11 +- .../extensions/map-block/info-window/index.js | 20 +- .../map-block/location-search/index.js | 76 ++- .../extensions/map-block/map-marker/index.js | 36 +- .../map-block/map-marker/style.scss | 6 + .../map-block/mapbox-map-formatter/index.js | 25 + .../extensions/map-block/mapbox.scss | 593 ++++++++++++++++++ .../extensions/map-block/settings.js | 8 +- .../gutenberg/extensions/map-block/style.scss | 4 - client/gutenberg/extensions/map-block/view.js | 4 +- 12 files changed, 803 insertions(+), 180 deletions(-) create mode 100644 client/gutenberg/extensions/map-block/map-marker/style.scss create mode 100644 client/gutenberg/extensions/map-block/mapbox-map-formatter/index.js create mode 100644 client/gutenberg/extensions/map-block/mapbox.scss diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index a1908850c9dc13..41a6c12c056824 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -16,7 +16,7 @@ import LocationSearch from '../location-search'; import './style.scss'; export class AddPoint extends Component { render() { - const { onClose, onAddPoint } = this.props; + const { onClose, onAddPoint, api_key } = this.props; return ( - + ); diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index 69231e5d26d5cb..56e606e962296d 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -15,7 +15,7 @@ import { get, assign } from 'lodash'; import MapMarker from './map-marker/'; import InfoWindow from './info-window/'; -import { googleMapFormatter } from './google-map-formatter/'; +import { mapboxMapFormatter } from './mapbox-map-formatter/'; // @TODO: replace with import from lib/load-script after resolution of https://github.com/Automattic/wp-calypso/issues/27821 import { loadScript } from './load-script'; @@ -30,30 +30,21 @@ export class Map extends Component { map: null, fit_to_bounds: false, loaded: false, - google: null, + mapboxgl: null, }; - // Event Handlers as methods - this.sizeMap = this.sizeMap.bind( this ); - this.onMarkerClick = this.onMarkerClick.bind( this ); - this.deleteActiveMarker = this.deleteActiveMarker.bind( this ); - this.updateActiveMarker = this.updateActiveMarker.bind( this ); - this.onMapClick = this.onMapClick.bind( this ); - this.setBoundsByMarkers = this.setBoundsByMarkers.bind( this ); - this.scriptsLoaded = this.scriptsLoaded.bind( this ); - // Refs this.mapRef = createRef(); } render() { - const { points, admin, children } = this.props; - const { map, activeMarker, google } = this.state; + const { points, admin, children, marker_color } = this.props; + const { map, activeMarker, mapboxgl } = this.state; const { onMarkerClick, deleteActiveMarker, updateActiveMarker } = this; const currentPoint = get( activeMarker, 'props.point' ) || {}; const { title, caption } = currentPoint; const mapMarkers = map && - google && + mapboxgl && points.map( ( point, index ) => { return ( ); } ); - const infoWindow = google && ( + const infoWindow = mapboxgl && ( this.setState( { activeMarker: null } ) } > { activeMarker && @@ -124,7 +115,7 @@ export class Map extends Component { componentDidUpdate( prevProps ) { const { api_key, children } = this.props; if ( api_key && api_key.length > 0 && api_key !== prevProps.api_key ) { - window.google = null; + window.mapboxgl = null; this.loadMapLibraries(); } // If the user has just clicked to show the Add Point component, hide info window. @@ -148,11 +139,8 @@ export class Map extends Component { this.setBoundsByMarkers(); } mapStyleAndDetailsChanged() { - const { map, google } = this.state; - map.setOptions( { - styles: this.getMapStyle(), - mapTypeId: google.maps.MapTypeId[ this.getMapType() ], - } ); + const { map } = this.state; + map.setStyle( this.getMapStyle() ); } map_styleChanged() { this.mapStyleAndDetailsChanged(); @@ -160,19 +148,19 @@ export class Map extends Component { map_detailsChanged() { this.mapStyleAndDetailsChanged(); } - // Event handling - onMarkerClick( marker ) { + /* Event handling */ + onMarkerClick = marker => { const { onMarkerClick } = this.props; this.setState( { activeMarker: marker } ); onMarkerClick(); - } - onMapClick() { + }; + onMapClick = () => { this.setState( { activeMarker: null } ); - } - clearCurrentMarker() { + }; + clearCurrentMarker = () => { this.setState( { activeMarker: null } ); - } - updateActiveMarker( updates ) { + }; + updateActiveMarker = updates => { const { points } = this.props; const { activeMarker } = this.state; const { index } = activeMarker.props; @@ -180,8 +168,8 @@ export class Map extends Component { assign( newPoints[ index ], updates ); this.props.onSetPoints( newPoints ); - } - deleteActiveMarker() { + }; + deleteActiveMarker = () => { const { points } = this.props; const { activeMarker } = this.state; const { index } = activeMarker.props; @@ -190,47 +178,55 @@ export class Map extends Component { newPoints.splice( index, 1 ); this.props.onSetPoints( newPoints ); this.setState( { activeMarker: null } ); - } + }; // Various map functions - sizeMap() { + sizeMap = () => { + const { map } = this.state; const mapEl = this.mapRef.current; const blockWidth = mapEl.offsetWidth; const maxHeight = window.innerHeight * 0.8; const blockHeight = Math.min( blockWidth * ( 3 / 4 ), maxHeight ); mapEl.style.height = blockHeight + 'px'; - } - // Calculate the appropriate zoom and center point of the map based on defined markers - setBoundsByMarkers() { + map.resize(); + this.setBoundsByMarkers(); + }; + setBoundsByMarkers = () => { const { zoom, points } = this.props; - const { map, activeMarker, google } = this.state; - const bounds = new google.maps.LatLngBounds(); + const { map, activeMarker, mapboxgl, zoomControl } = this.state; + + const bounds = new mapboxgl.LngLatBounds(); if ( ! map || ! points.length || activeMarker ) { return; } points.forEach( point => { - bounds.extend( - new google.maps.LatLng( point.coordinates.latitude, point.coordinates.longitude ) - ); + bounds.extend( [ point.coordinates.latitude, point.coordinates.longitude ] ); } ); map.setCenter( bounds.getCenter() ); // If there are multiple points, zoom is determined by the area they cover, // and zoom control is removed. if ( points.length > 1 ) { - map.fitBounds( bounds ); + map.fitBounds( bounds, { + padding: { + top: 40, + bottom: 40, + left: 20, + right: 20, + }, + } ); this.setState( { fit_to_bounds: true } ); - map.setOptions( { zoomControl: false } ); + map.removeControl( zoomControl ); return; } // If there are one (or zero) points, user can set zoom map.setZoom( parseInt( zoom, 10 ) ); this.setState( { fit_to_bounds: false } ); - map.setOptions( { zoomControl: true } ); - } + map.addControl( zoomControl ); + }; getMapStyle() { const { map_style, map_details } = this.props; - return googleMapFormatter( map_style, map_details ); + return mapboxMapFormatter( map_style, map_details ); } getMapType() { const { map_style } = this.props; @@ -244,21 +240,8 @@ export class Map extends Component { return 'ROADMAP'; } } - getMarkerIcon() { - const { marker_color } = this.props; - const { google } = this.state; - return { - path: - 'M16,38 C16,38 32,26.692424 32,16 C32,5.307576 24.836556,0 16,0 C7.163444,0 0,5.307576 0,16 C0,26.692424 16,38 16,38 Z', - fillColor: marker_color, - fillOpacity: 0.8, - scale: 1, - strokeWeight: 0, - anchor: new google.maps.Point( 16, 38 ), - }; - } // Script loading, browser geolocation - scriptsLoaded() { + scriptsLoaded = () => { const { map_center, points } = this.props; this.setState( { loaded: true } ); @@ -268,60 +251,65 @@ export class Map extends Component { return; } this.initMap( map_center ); - } + }; loadMapLibraries() { const { api_key } = this.props; - const src = [ - 'https://maps.googleapis.com/maps/api/js?key=', - api_key, - '&libraries=places', - ].join( '' ); - if ( window.google ) { - this.setState( { google: window.google }, this.scriptsLoaded ); + const src = 'https://api.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.js'; + if ( window.mapboxgl ) { + this.setState( { mapboxgl: window.mapboxgl }, this.scriptsLoaded ); return; } loadScript( src, error => { if ( error ) { return; } - this.setState( { google: window.google }, this.scriptsLoaded ); + window.mapboxgl.accessToken = api_key; + this.setState( { mapboxgl: window.mapboxgl }, this.scriptsLoaded ); } ); } - // Create the map object. initMap( map_center ) { - const { google } = this.state; - const { zoom, onMapLoaded } = this.props; - const mapOptions = { - streetViewControl: false, - mapTypeControl: false, - panControl: false, - scrollwheel: false, - zoomControlOptions: { - style: 'SMALL', - }, - styles: this.getMapStyle(), - mapTypeId: google.maps.MapTypeId[ this.getMapType() ], + const { mapboxgl } = this.state; + const { zoom, onMapLoaded, admin } = this.props; + const map = new mapboxgl.Map( { + container: this.mapRef.current, + style: 'mapbox://styles/mapbox/streets-v9', + center: this.googlePoint2Mapbox( map_center ), zoom: parseInt( zoom, 10 ), - }; - const map = new google.maps.Map( this.mapRef.current, mapOptions ); - map.addListener( - 'zoom_changed', - function() { - this.props.onSetZoom( map.getZoom() ); - }.bind( this ) - ); - map.addListener( 'click', this.onMapClick ); - this.setState( { map }, () => { + pitchWithRotate: false, + attributionControl: false, + dragRotate: false, + } ); + const zoomControl = new mapboxgl.NavigationControl( { + showCompass: false, + showZoom: true, + } ); + map.on( 'zoomend', () => { + this.props.onSetZoom( map.getZoom() ); + } ); + + /* Listen for clicks on the Map background, which hides the current popup. */ + map.getCanvas().addEventListener( 'click', this.onMapClick ); + this.setState( { map, zoomControl }, () => { this.sizeMap(); + map.addControl( zoomControl ); + if ( ! admin ) { + map.addControl( new mapboxgl.FullscreenControl() ); + } this.mapRef.current.addEventListener( 'alignmentChanged', this.sizeMap ); - window.addEventListener( 'resize', this.sizeMap ); - google.maps.event.trigger( map, 'resize' ); - map.setCenter( new google.maps.LatLng( map_center.latitude, map_center.longitude ) ); - this.setBoundsByMarkers(); + map.resize(); onMapLoaded(); this.setState( { loaded: true } ); + map.setStyle( this.getMapStyle() ); + window.addEventListener( 'resize', this.sizeMap ); } ); } + googlePoint2Mapbox( google_point ) { + const map_center = [ + google_point.latitude ? google_point.latitude : 0, + google_point.longitude ? google_point.longitude : 0, + ]; + return map_center; + } } Map.defaultProps = { @@ -333,11 +321,7 @@ Map.defaultProps = { onMarkerClick: () => {}, marker_color: 'red', api_key: null, - // Default center point is San Francisco - map_center: { - latitude: 37.7749295, - longitude: -122.41941550000001, - }, + map_center: {}, }; export default Map; diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index 3be2077f3a350c..b074ead62e1d2b 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -81,7 +81,7 @@ class MapEdit extends Component { }; apiCall( service_api_key = null, method = 'GET' ) { const { noticeOperations } = this.props; - const url = '/wp-json/jetpack/v4/service-api-keys/googlemaps'; + const url = '/wp-json/jetpack/v4/service-api-keys/mapbox'; const fetch = service_api_key ? { url, method, data: { service_api_key } } : { url, method }; apiFetch( fetch ).then( result => { @@ -160,9 +160,9 @@ class MapEdit extends Component { /> ) : null } - + this.setState( { apiKeyControl: value } ) } /> @@ -184,8 +184,8 @@ class MapEdit extends Component { ); const getAPIInstructions = sprintf( - "This is your first map block. You need to get a Google Maps API key. Here's how to do it.", - 'https://developers.google.com/maps/documentation/javascript/get-api-key' + "This is your first map block. You need to get a Mapbox Access Token. Here's how to do it.", + 'https://www.mapbox.com/help/how-access-tokens-work/' ); const placeholderAPIStateFailure = ( @@ -226,6 +226,7 @@ class MapEdit extends Component { this.setState( { addPointVisibility: false } ) } + api_key={ api_key } /> ) } diff --git a/client/gutenberg/extensions/map-block/info-window/index.js b/client/gutenberg/extensions/map-block/info-window/index.js index b9e1f157e71a78..41b8fc153fb706 100644 --- a/client/gutenberg/extensions/map-block/info-window/index.js +++ b/client/gutenberg/extensions/map-block/info-window/index.js @@ -12,12 +12,15 @@ import { Component, createPortal } from '@wordpress/element'; export class InfoWindow extends Component { componentDidMount() { - const { google } = this.props; + const { mapboxgl } = this.props; this.el = document.createElement( 'DIV' ); - this.infowindow = new google.maps.InfoWindow( { - content: this.el, + this.infowindow = new mapboxgl.Popup( { + closeButton: true, + closeOnClick: false, + offset: 25, } ); - google.maps.event.addListener( this.infowindow, 'closeclick', this.closeClick ); + this.infowindow.setDOMContent( this.el ); + this.infowindow.on( 'close', this.closeClick ); } componentDidUpdate( prevProps ) { if ( this.props.activeMarker !== prevProps.activeMarker ) { @@ -25,17 +28,18 @@ export class InfoWindow extends Component { } } render() { - // Use React portal to render components directly into the Google Maps info window. + // Use React portal to render components directly into the Mapbox info window. return this.el ? createPortal( this.props.children, this.el ) : null; } closeClick = () => { this.props.unsetActiveMarker(); }; openWindow() { - this.infowindow.open( this.props.map, this.props.activeMarker.marker ); + const { map, activeMarker } = this.props; + this.infowindow.setLngLat( activeMarker.getPoint() ).addTo( map ); } closeWindow() { - this.infowindow.close(); + this.infowindow.remove(); } } @@ -43,7 +47,7 @@ InfoWindow.defaultProps = { unsetActiveMarker: () => {}, activeMarker: null, map: null, - google: null, + mapboxgl: null, }; export default InfoWindow; diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js index 031e1ee267f4ec..83daa932610418 100644 --- a/client/gutenberg/extensions/map-block/location-search/index.js +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -27,54 +27,48 @@ export class LocationSearch extends Component { }; this.autocompleter = { name: 'placeSearch', - options: this.search.bind( this ), + options: this.search, isDebounced: true, - getOptionLabel: option => { option.description }, - getOptionKeywords: option => [ option.description ], - getOptionCompletion: this.getOptionCompletion.bind( this ), + getOptionLabel: option => { option.place_name }, + getOptionKeywords: option => [ option.place_name ], + getOptionCompletion: this.getOptionCompletion, }; } - - getOptionCompletion( option ) { + getOptionCompletion = option => { const { value } = option; - const placesService = new window.google.maps.places.PlacesService( this.testRef.current ); - placesService.getDetails( - { placeId: value.place_id }, - function( place ) { - const point = { - place_title: place.name, - title: place.name, - caption: place.formatted_address, - id: place.place_id, - viewport: place.geometry.viewport, - coordinates: { - latitude: place.geometry.location.lat(), - longitude: place.geometry.location.lng(), - }, - }; - this.props.onAddPoint( point ); - }.bind( this ) - ); - return option.description; - } + const point = { + place_title: value.text, + title: value.text, + caption: value.place_name, + id: value.id, + coordinates: { + latitude: value.geometry.coordinates[ 0 ], + longitude: value.geometry.coordinates[ 1 ], + }, + }; + this.props.onAddPoint( point ); + return value.text; + }; - search( value ) { - const placeSearch = new window.google.maps.places.AutocompleteService(); + search = value => { + const { api_key } = this.props; + const url = + 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + + encodeURI( value ) + + '.json?access_token=' + + api_key; return new Promise( function( resolve, reject ) { - placeSearch.getPlacePredictions( - { - input: value, - }, - function( place, status ) { - if ( status !== window.google.maps.places.PlacesServiceStatus.OK ) { - reject( new Error( status ) ); - } else { - resolve( place ); - } - } - ); + /* TODO: Replace with pure JS */ + window.jQuery + .ajax( url ) + .done( function( data ) { + resolve( data.features ); + } ) + .fail( function() { + reject( new Error( 'Mapbox Places Error' ) ); + } ); } ); - } + }; onReset = () => { this.textRef.current.value = null; }; diff --git a/client/gutenberg/extensions/map-block/map-marker/index.js b/client/gutenberg/extensions/map-block/map-marker/index.js index 4aaa4725c505f1..7907c3857953f4 100644 --- a/client/gutenberg/extensions/map-block/map-marker/index.js +++ b/client/gutenberg/extensions/map-block/map-marker/index.js @@ -10,13 +10,15 @@ import { Component } from '@wordpress/element'; * Internal dependencies */ +import './style.scss'; + export class MapMarker extends Component { componentDidMount() { this.renderMarker(); } componentWillUnmount() { if ( this.marker ) { - this.marker.setMap( null ); + this.marker.remove(); } } componentDidUpdate() { @@ -26,20 +28,30 @@ export class MapMarker extends Component { const { onClick } = this.props; onClick( this ); }; + getPoint = () => { + const { point } = this.props; + return [ point.coordinates.latitude, point.coordinates.longitude ]; + }; renderMarker() { - const { map, point, google, icon } = this.props; - + const { map, point, mapboxgl, marker_color } = this.props; const { handleClick } = this; - - const position = new google.LatLng( point.coordinates.latitude, point.coordinates.longitude ); - + const mapboxPoint = [ point.coordinates.latitude, point.coordinates.longitude ]; + const el = this.marker ? this.marker.getElement() : document.createElement( 'div' ); if ( this.marker ) { - this.marker.setPosition( position ); - this.marker.setIcon( icon ); + this.marker.setLngLat( mapboxPoint ); } else { - this.marker = new google.Marker( { position, map, icon } ); - this.marker.addListener( 'click', handleClick ); + el.className = 'wp-block-jetpack-maps-marker'; + this.marker = new mapboxgl.Marker( el ) + .setLngLat( mapboxPoint ) + .setOffset( [ 0, -19 ] ) + .addTo( map ); + + this.marker.getElement().addEventListener( 'click', handleClick ); } + el.innerHTML = + ''; } render() { return null; @@ -49,8 +61,8 @@ export class MapMarker extends Component { MapMarker.defaultProps = { point: {}, map: null, - icon: null, - google: null, + marker_color: '#000000', + mapboxgl: null, onClick: () => {}, }; diff --git a/client/gutenberg/extensions/map-block/map-marker/style.scss b/client/gutenberg/extensions/map-block/map-marker/style.scss new file mode 100644 index 00000000000000..0c41a3ec9eac91 --- /dev/null +++ b/client/gutenberg/extensions/map-block/map-marker/style.scss @@ -0,0 +1,6 @@ +/** @format */ + +.wp-block-jetpack-maps-marker { + width: 32px; + height: 38px; +} diff --git a/client/gutenberg/extensions/map-block/mapbox-map-formatter/index.js b/client/gutenberg/extensions/map-block/mapbox-map-formatter/index.js new file mode 100644 index 00000000000000..f6a837968cce16 --- /dev/null +++ b/client/gutenberg/extensions/map-block/mapbox-map-formatter/index.js @@ -0,0 +1,25 @@ +/** @format */ + +/* TODO: Replace with styles created in A8C-owned account */ +export function mapboxMapFormatter( map_style, map_details ) { + const style_urls = { + default: { + details: 'mapbox://styles/rabberson/cjnxjme2m054v2rs2gf3nggx6', + no_details: 'mapbox://styles/rabberson/cjnxl6xqp55kt2sk55ivay8r0', + }, + black_and_white: { + details: 'mapbox://styles/rabberson/cjnxjofik08ax2rmx47rfzhji', + no_details: 'mapbox://styles/rabberson/cjnxjvlk108kq2slmjnd9beni', + }, + satellite: { + details: 'mapbox://styles/mapbox/satellite-streets-v10', + no_details: 'mapbox://styles/mapbox/satellite-v9', + }, + terrain: { + details: 'mapbox://styles/rabberson/cjnxl0upd52ik2srtr0zh216f', + no_details: 'mapbox://styles/rabberson/cjnxl28cc54rl2roaamgb621y', + }, + }; + const style_url = style_urls[ map_style ][ map_details ? 'details' : 'no_details' ]; + return style_url; +} diff --git a/client/gutenberg/extensions/map-block/mapbox.scss b/client/gutenberg/extensions/map-block/mapbox.scss new file mode 100644 index 00000000000000..6de03b77c09d4c --- /dev/null +++ b/client/gutenberg/extensions/map-block/mapbox.scss @@ -0,0 +1,593 @@ +/** @format */ + +.mapboxgl-map { + font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif; + overflow: hidden; + position: relative; + -webkit-tap-highlight-color: rgba( 0, 0, 0, 0 ); +} + +.mapboxgl-map:-webkit-full-screen { + width: 100%; + height: 100%; +} + +.mapboxgl-canary { + background-color: salmon; +} + +.mapboxgl-canvas-container.mapboxgl-interactive, +.mapboxgl-ctrl-group > button.mapboxgl-ctrl-compass { + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.mapboxgl-canvas-container.mapboxgl-interactive:active, +.mapboxgl-ctrl-group > button.mapboxgl-ctrl-compass:active { + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing; +} + +.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate, +.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate .mapboxgl-canvas { + touch-action: pan-x pan-y; +} + +.mapboxgl-canvas-container.mapboxgl-touch-drag-pan, +.mapboxgl-canvas-container.mapboxgl-touch-drag-pan .mapboxgl-canvas { + touch-action: pinch-zoom; +} + +.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate.mapboxgl-touch-drag-pan, +.mapboxgl-canvas-container.mapboxgl-touch-zoom-rotate.mapboxgl-touch-drag-pan .mapboxgl-canvas { + touch-action: none; +} + +.mapboxgl-ctrl-top-left, +.mapboxgl-ctrl-top-right, +.mapboxgl-ctrl-bottom-left, +.mapboxgl-ctrl-bottom-right { + position: absolute; + pointer-events: none; + z-index: 2; +} +.mapboxgl-ctrl-top-left { + top: 0; + left: 0; +} +.mapboxgl-ctrl-top-right { + top: 0; + right: 0; +} +.mapboxgl-ctrl-bottom-left { + bottom: 0; + left: 0; +} +.mapboxgl-ctrl-bottom-right { + right: 0; + bottom: 0; +} + +.mapboxgl-ctrl { + clear: both; + pointer-events: auto; +} +.mapboxgl-ctrl-top-left .mapboxgl-ctrl { + margin: 10px 0 0 10px; + float: left; +} +.mapboxgl-ctrl-top-right .mapboxgl-ctrl { + margin: 10px 10px 0 0; + float: right; +} +.mapboxgl-ctrl-bottom-left .mapboxgl-ctrl { + margin: 0 0 10px 10px; + float: left; +} +.mapboxgl-ctrl-bottom-right .mapboxgl-ctrl { + margin: 0 10px 10px 0; + float: right; +} + +.mapboxgl-ctrl-group { + border-radius: 4px; + overflow: hidden; + background: #fff; +} + +.mapboxgl-ctrl-group:not( :empty ) { + -moz-box-shadow: 0 0 2px rgba( 0, 0, 0, 0.1 ); + -webkit-box-shadow: 0 0 2px rgba( 0, 0, 0, 0.1 ); + box-shadow: 0 0 0 2px rgba( 0, 0, 0, 0.1 ); +} + +.mapboxgl-ctrl-group > button { + width: 30px; + height: 30px; + display: block; + padding: 0; + outline: none; + border: 0; + box-sizing: border-box; + background-color: transparent; + cursor: pointer; +} + +.mapboxgl-ctrl-group > button + button { + border-top: 1px solid #ddd; +} + +/* https://bugzilla.mozilla.org/show_bug.cgi?id=140562 */ +.mapboxgl-ctrl > button::-moz-focus-inner { + border: 0; + padding: 0; +} + +.mapboxgl-ctrl > button:hover { + background-color: rgba( 0, 0, 0, 0.05 ); +} + +.mapboxgl-ctrl-icon, +.mapboxgl-ctrl-icon > .mapboxgl-ctrl-compass-arrow { + speak: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.mapboxgl-ctrl-icon { + padding: 5px; +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-zoom-out { + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath style='fill:%23333333;' d='m 7,9 c -0.554,0 -1,0.446 -1,1 0,0.554 0.446,1 1,1 l 6,0 c 0.554,0 1,-0.446 1,-1 0,-0.554 -0.446,-1 -1,-1 z'/%3E %3C/svg%3E" ); +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-zoom-in { + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath style='fill:%23333333;' d='M 10 6 C 9.446 6 9 6.4459904 9 7 L 9 9 L 7 9 C 6.446 9 6 9.446 6 10 C 6 10.554 6.446 11 7 11 L 9 11 L 9 13 C 9 13.55401 9.446 14 10 14 C 10.554 14 11 13.55401 11 13 L 11 11 L 13 11 C 13.554 11 14 10.554 14 10 C 14 9.446 13.554 9 13 9 L 11 9 L 11 7 C 11 6.4459904 10.554 6 10 6 z'/%3E %3C/svg%3E" ); +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-geolocate { + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23333'%3E %3Cpath d='M10 4C9 4 9 5 9 5L9 5.1A5 5 0 0 0 5.1 9L5 9C5 9 4 9 4 10 4 11 5 11 5 11L5.1 11A5 5 0 0 0 9 14.9L9 15C9 15 9 16 10 16 11 16 11 15 11 15L11 14.9A5 5 0 0 0 14.9 11L15 11C15 11 16 11 16 10 16 9 15 9 15 9L14.9 9A5 5 0 0 0 11 5.1L11 5C11 5 11 4 10 4zM10 6.5A3.5 3.5 0 0 1 13.5 10 3.5 3.5 0 0 1 10 13.5 3.5 3.5 0 0 1 6.5 10 3.5 3.5 0 0 1 10 6.5zM10 8.3A1.8 1.8 0 0 0 8.3 10 1.8 1.8 0 0 0 10 11.8 1.8 1.8 0 0 0 11.8 10 1.8 1.8 0 0 0 10 8.3z'/%3E %3C/svg%3E" ); +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-geolocate:disabled { + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23aaa'%3E %3Cpath d='M10 4C9 4 9 5 9 5L9 5.1A5 5 0 0 0 5.1 9L5 9C5 9 4 9 4 10 4 11 5 11 5 11L5.1 11A5 5 0 0 0 9 14.9L9 15C9 15 9 16 10 16 11 16 11 15 11 15L11 14.9A5 5 0 0 0 14.9 11L15 11C15 11 16 11 16 10 16 9 15 9 15 9L14.9 9A5 5 0 0 0 11 5.1L11 5C11 5 11 4 10 4zM10 6.5A3.5 3.5 0 0 1 13.5 10 3.5 3.5 0 0 1 10 13.5 3.5 3.5 0 0 1 6.5 10 3.5 3.5 0 0 1 10 6.5zM10 8.3A1.8 1.8 0 0 0 8.3 10 1.8 1.8 0 0 0 10 11.8 1.8 1.8 0 0 0 11.8 10 1.8 1.8 0 0 0 10 8.3z'/%3E %3C/svg%3E" ); +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-active { + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%2333b5e5'%3E %3Cpath d='M10 4C9 4 9 5 9 5L9 5.1A5 5 0 0 0 5.1 9L5 9C5 9 4 9 4 10 4 11 5 11 5 11L5.1 11A5 5 0 0 0 9 14.9L9 15C9 15 9 16 10 16 11 16 11 15 11 15L11 14.9A5 5 0 0 0 14.9 11L15 11C15 11 16 11 16 10 16 9 15 9 15 9L14.9 9A5 5 0 0 0 11 5.1L11 5C11 5 11 4 10 4zM10 6.5A3.5 3.5 0 0 1 13.5 10 3.5 3.5 0 0 1 10 13.5 3.5 3.5 0 0 1 6.5 10 3.5 3.5 0 0 1 10 6.5zM10 8.3A1.8 1.8 0 0 0 8.3 10 1.8 1.8 0 0 0 10 11.8 1.8 1.8 0 0 0 11.8 10 1.8 1.8 0 0 0 10 8.3z'/%3E %3C/svg%3E" ); +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-active-error { + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23e58978'%3E %3Cpath d='M10 4C9 4 9 5 9 5L9 5.1A5 5 0 0 0 5.1 9L5 9C5 9 4 9 4 10 4 11 5 11 5 11L5.1 11A5 5 0 0 0 9 14.9L9 15C9 15 9 16 10 16 11 16 11 15 11 15L11 14.9A5 5 0 0 0 14.9 11L15 11C15 11 16 11 16 10 16 9 15 9 15 9L14.9 9A5 5 0 0 0 11 5.1L11 5C11 5 11 4 10 4zM10 6.5A3.5 3.5 0 0 1 13.5 10 3.5 3.5 0 0 1 10 13.5 3.5 3.5 0 0 1 6.5 10 3.5 3.5 0 0 1 10 6.5zM10 8.3A1.8 1.8 0 0 0 8.3 10 1.8 1.8 0 0 0 10 11.8 1.8 1.8 0 0 0 11.8 10 1.8 1.8 0 0 0 10 8.3z'/%3E %3C/svg%3E" ); +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-background { + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%2333b5e5'%3E %3Cpath d='M 10,4 C 9,4 9,5 9,5 L 9,5.1 C 7.0357113,5.5006048 5.5006048,7.0357113 5.1,9 L 5,9 c 0,0 -1,0 -1,1 0,1 1,1 1,1 l 0.1,0 c 0.4006048,1.964289 1.9357113,3.499395 3.9,3.9 L 9,15 c 0,0 0,1 1,1 1,0 1,-1 1,-1 l 0,-0.1 c 1.964289,-0.400605 3.499395,-1.935711 3.9,-3.9 l 0.1,0 c 0,0 1,0 1,-1 C 16,9 15,9 15,9 L 14.9,9 C 14.499395,7.0357113 12.964289,5.5006048 11,5.1 L 11,5 c 0,0 0,-1 -1,-1 z m 0,2.5 c 1.932997,0 3.5,1.5670034 3.5,3.5 0,1.932997 -1.567003,3.5 -3.5,3.5 C 8.0670034,13.5 6.5,11.932997 6.5,10 6.5,8.0670034 8.0670034,6.5 10,6.5 Z'/%3E %3C/svg%3E" ); +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-background-error { + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill='%23e54e33'%3E %3Cpath d='M 10,4 C 9,4 9,5 9,5 L 9,5.1 C 7.0357113,5.5006048 5.5006048,7.0357113 5.1,9 L 5,9 c 0,0 -1,0 -1,1 0,1 1,1 1,1 l 0.1,0 c 0.4006048,1.964289 1.9357113,3.499395 3.9,3.9 L 9,15 c 0,0 0,1 1,1 1,0 1,-1 1,-1 l 0,-0.1 c 1.964289,-0.400605 3.499395,-1.935711 3.9,-3.9 l 0.1,0 c 0,0 1,0 1,-1 C 16,9 15,9 15,9 L 14.9,9 C 14.499395,7.0357113 12.964289,5.5006048 11,5.1 L 11,5 c 0,0 0,-1 -1,-1 z m 0,2.5 c 1.932997,0 3.5,1.5670034 3.5,3.5 0,1.932997 -1.567003,3.5 -3.5,3.5 C 8.0670034,13.5 6.5,11.932997 6.5,10 6.5,8.0670034 8.0670034,6.5 10,6.5 Z'/%3E %3C/svg%3E" ); +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-geolocate.mapboxgl-ctrl-geolocate-waiting { + -webkit-animation: mapboxgl-spin 2s infinite linear; + -moz-animation: mapboxgl-spin 2s infinite linear; + -o-animation: mapboxgl-spin 2s infinite linear; + -ms-animation: mapboxgl-spin 2s infinite linear; + animation: mapboxgl-spin 2s infinite linear; +} + +@-webkit-keyframes mapboxgl-spin { + 0% { + -webkit-transform: rotate( 0deg ); + } + 100% { + -webkit-transform: rotate( 360deg ); + } +} + +@-moz-keyframes mapboxgl-spin { + 0% { + -moz-transform: rotate( 0deg ); + } + 100% { + -moz-transform: rotate( 360deg ); + } +} + +@-o-keyframes mapboxgl-spin { + 0% { + -o-transform: rotate( 0deg ); + } + 100% { + -o-transform: rotate( 360deg ); + } +} + +@-ms-keyframes mapboxgl-spin { + 0% { + -ms-transform: rotate( 0deg ); + } + 100% { + -ms-transform: rotate( 360deg ); + } +} + +@keyframes mapboxgl-spin { + 0% { + transform: rotate( 0deg ); + } + 100% { + transform: rotate( 360deg ); + } +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-fullscreen { + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath d='M 5 4 C 4.5 4 4 4.5 4 5 L 4 6 L 4 9 L 4.5 9 L 5.7773438 7.296875 C 6.7771319 8.0602131 7.835765 8.9565728 8.890625 10 C 7.8257121 11.0633 6.7761791 11.951675 5.78125 12.707031 L 4.5 11 L 4 11 L 4 15 C 4 15.5 4.5 16 5 16 L 9 16 L 9 15.5 L 7.2734375 14.205078 C 8.0428931 13.187886 8.9395441 12.133481 9.9609375 11.068359 C 11.042371 12.14699 11.942093 13.2112 12.707031 14.21875 L 11 15.5 L 11 16 L 14 16 L 15 16 C 15.5 16 16 15.5 16 15 L 16 14 L 16 11 L 15.5 11 L 14.205078 12.726562 C 13.177985 11.949617 12.112718 11.043577 11.037109 10.009766 C 12.151856 8.981061 13.224345 8.0798624 14.228516 7.3046875 L 15.5 9 L 16 9 L 16 5 C 16 4.5 15.5 4 15 4 L 11 4 L 11 4.5 L 12.703125 5.7773438 C 11.932647 6.7864834 11.026693 7.8554712 9.9707031 8.9199219 C 8.9584739 7.8204943 8.0698767 6.7627188 7.3046875 5.7714844 L 9 4.5 L 9 4 L 6 4 L 5 4 z '/%3E %3C/svg%3E" ); +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-shrink { + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath style='fill:%23000000;' d='M 4.2421875 3.4921875 A 0.750075 0.750075 0 0 0 3.71875 4.78125 L 5.9648438 7.0273438 L 4 8.5 L 4 9 L 8 9 C 8.500001 8.9999988 9 8.4999992 9 8 L 9 4 L 8.5 4 L 7.0175781 5.9550781 L 4.78125 3.71875 A 0.750075 0.750075 0 0 0 4.2421875 3.4921875 z M 15.734375 3.4921875 A 0.750075 0.750075 0 0 0 15.21875 3.71875 L 12.984375 5.953125 L 11.5 4 L 11 4 L 11 8 C 11 8.4999992 11.499999 8.9999988 12 9 L 16 9 L 16 8.5 L 14.035156 7.0273438 L 16.28125 4.78125 A 0.750075 0.750075 0 0 0 15.734375 3.4921875 z M 4 11 L 4 11.5 L 5.9648438 12.972656 L 3.71875 15.21875 A 0.75130096 0.75130096 0 1 0 4.78125 16.28125 L 7.0273438 14.035156 L 8.5 16 L 9 16 L 9 12 C 9 11.500001 8.500001 11.000001 8 11 L 4 11 z M 12 11 C 11.499999 11.000001 11 11.500001 11 12 L 11 16 L 11.5 16 L 12.972656 14.035156 L 15.21875 16.28125 A 0.75130096 0.75130096 0 1 0 16.28125 15.21875 L 14.035156 12.972656 L 16 11.5 L 16 11 L 12 11 z '/%3E %3C/svg%3E" ); +} + +.mapboxgl-ctrl-icon.mapboxgl-ctrl-compass > .mapboxgl-ctrl-compass-arrow { + width: 20px; + height: 20px; + margin: 5px; + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E %3Cpolygon fill='%23333333' points='6,9 10,1 14,9'/%3E %3Cpolygon fill='%23CCCCCC' points='6,11 10,19 14,11 '/%3E %3C/svg%3E" ); + background-repeat: no-repeat; + display: inline-block; +} + +a.mapboxgl-ctrl-logo { + width: 85px; + height: 21px; + margin: 0 0 -3px -3px; + display: block; + background-repeat: no-repeat; + cursor: pointer; + background-image: url( "data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 84.49 21' style='enable-background:new 0 0 84.49 21;' xml:space='preserve'%3E%3Cg%3E %3Cpath class='st0' style='opacity:0.9; fill: %23FFFFFF; enable-background: new;' d='M83.25,14.26c0,0.12-0.09,0.21-0.21,0.21h-1.61c-0.13,0-0.24-0.06-0.3-0.17l-1.44-2.39l-1.44,2.39 c-0.06,0.11-0.18,0.17-0.3,0.17h-1.61c-0.04,0-0.08-0.01-0.12-0.03c-0.09-0.06-0.13-0.19-0.06-0.28l0,0l2.43-3.68L76.2,6.84 c-0.02-0.03-0.03-0.07-0.03-0.12c0-0.12,0.09-0.21,0.21-0.21h1.61c0.13,0,0.24,0.06,0.3,0.17l1.41,2.36l1.4-2.35 c0.06-0.11,0.18-0.17,0.3-0.17H83c0.04,0,0.08,0.01,0.12,0.03c0.09,0.06,0.13,0.19,0.06,0.28l0,0l-2.37,3.63l2.43,3.67 C83.24,14.18,83.25,14.22,83.25,14.26z'/%3E %3Cpath class='st0' style='opacity:0.9; fill: %23FFFFFF; enable-background: new;' d='M66.24,9.59c-0.39-1.88-1.96-3.28-3.84-3.28c-1.03,0-2.03,0.42-2.73,1.18V3.51c0-0.13-0.1-0.23-0.23-0.23h-1.4 c-0.13,0-0.23,0.11-0.23,0.23v10.72c0,0.13,0.1,0.23,0.23,0.23h1.4c0.13,0,0.23-0.11,0.23-0.23V13.5c0.71,0.75,1.7,1.18,2.73,1.18 c1.88,0,3.45-1.41,3.84-3.29C66.37,10.79,66.37,10.18,66.24,9.59L66.24,9.59z M62.08,13c-1.32,0-2.39-1.11-2.41-2.48v-0.06 c0.02-1.38,1.09-2.48,2.41-2.48s2.42,1.12,2.42,2.51S63.41,13,62.08,13z'/%3E %3Cpath class='st0' style='opacity:0.9; fill: %23FFFFFF; enable-background: new;' d='M71.67,6.32c-1.98-0.01-3.72,1.35-4.16,3.29c-0.13,0.59-0.13,1.19,0,1.77c0.44,1.94,2.17,3.32,4.17,3.3 c2.35,0,4.26-1.87,4.26-4.19S74.04,6.32,71.67,6.32z M71.65,13.01c-1.33,0-2.42-1.12-2.42-2.51s1.08-2.52,2.42-2.52 c1.33,0,2.42,1.12,2.42,2.51S72.99,13,71.65,13.01L71.65,13.01z'/%3E %3Cpath class='st1' style='opacity:0.35; enable-background:new;' d='M62.08,7.98c-1.32,0-2.39,1.11-2.41,2.48v0.06C59.68,11.9,60.75,13,62.08,13s2.42-1.12,2.42-2.51 S63.41,7.98,62.08,7.98z M62.08,11.76c-0.63,0-1.14-0.56-1.17-1.25v-0.04c0.01-0.69,0.54-1.25,1.17-1.25 c0.63,0,1.17,0.57,1.17,1.27C63.24,11.2,62.73,11.76,62.08,11.76z'/%3E %3Cpath class='st1' style='opacity:0.35; enable-background:new;' d='M71.65,7.98c-1.33,0-2.42,1.12-2.42,2.51S70.32,13,71.65,13s2.42-1.12,2.42-2.51S72.99,7.98,71.65,7.98z M71.65,11.76c-0.64,0-1.17-0.57-1.17-1.27c0-0.7,0.53-1.26,1.17-1.26s1.17,0.57,1.17,1.27C72.82,11.21,72.29,11.76,71.65,11.76z'/%3E %3Cpath class='st0' style='opacity:0.9; fill: %23FFFFFF; enable-background: new;' d='M45.74,6.53h-1.4c-0.13,0-0.23,0.11-0.23,0.23v0.73c-0.71-0.75-1.7-1.18-2.73-1.18 c-2.17,0-3.94,1.87-3.94,4.19s1.77,4.19,3.94,4.19c1.04,0,2.03-0.43,2.73-1.19v0.73c0,0.13,0.1,0.23,0.23,0.23h1.4 c0.13,0,0.23-0.11,0.23-0.23V6.74c0-0.12-0.09-0.22-0.22-0.22C45.75,6.53,45.75,6.53,45.74,6.53z M44.12,10.53 C44.11,11.9,43.03,13,41.71,13s-2.42-1.12-2.42-2.51s1.08-2.52,2.4-2.52c1.33,0,2.39,1.11,2.41,2.48L44.12,10.53z'/%3E %3Cpath class='st1' style='opacity:0.35; enable-background:new;' d='M41.71,7.98c-1.33,0-2.42,1.12-2.42,2.51S40.37,13,41.71,13s2.39-1.11,2.41-2.48v-0.06 C44.1,9.09,43.03,7.98,41.71,7.98z M40.55,10.49c0-0.7,0.52-1.27,1.17-1.27c0.64,0,1.14,0.56,1.17,1.25v0.04 c-0.01,0.68-0.53,1.24-1.17,1.24C41.08,11.75,40.55,11.19,40.55,10.49z'/%3E %3Cpath class='st0' style='opacity:0.9; fill: %23FFFFFF; enable-background: new;' d='M52.41,6.32c-1.03,0-2.03,0.42-2.73,1.18V6.75c0-0.13-0.1-0.23-0.23-0.23h-1.4c-0.13,0-0.23,0.11-0.23,0.23 v10.72c0,0.13,0.1,0.23,0.23,0.23h1.4c0.13,0,0.23-0.1,0.23-0.23V13.5c0.71,0.75,1.7,1.18,2.74,1.18c2.17,0,3.94-1.87,3.94-4.19 S54.58,6.32,52.41,6.32z M52.08,13.01c-1.32,0-2.39-1.11-2.42-2.48v-0.07c0.02-1.38,1.09-2.49,2.4-2.49c1.32,0,2.41,1.12,2.41,2.51 S53.4,13,52.08,13.01L52.08,13.01z'/%3E %3Cpath class='st1' style='opacity:0.35; enable-background:new;' d='M52.08,7.98c-1.32,0-2.39,1.11-2.42,2.48v0.06c0.03,1.38,1.1,2.48,2.42,2.48s2.41-1.12,2.41-2.51 S53.4,7.98,52.08,7.98z M52.08,11.76c-0.63,0-1.14-0.56-1.17-1.25v-0.04c0.01-0.69,0.54-1.25,1.17-1.25c0.63,0,1.17,0.58,1.17,1.27 S52.72,11.76,52.08,11.76z'/%3E %3Cpath class='st0' style='opacity:0.9; fill: %23FFFFFF; enable-background: new;' d='M36.08,14.24c0,0.13-0.1,0.23-0.23,0.23h-1.41c-0.13,0-0.23-0.11-0.23-0.23V9.68c0-0.98-0.74-1.71-1.62-1.71 c-0.8,0-1.46,0.7-1.59,1.62l0.01,4.66c0,0.13-0.11,0.23-0.23,0.23h-1.41c-0.13,0-0.23-0.11-0.23-0.23V9.68 c0-0.98-0.74-1.71-1.62-1.71c-0.85,0-1.54,0.79-1.6,1.8v4.48c0,0.13-0.1,0.23-0.23,0.23h-1.4c-0.13,0-0.23-0.11-0.23-0.23V6.74 c0.01-0.13,0.1-0.22,0.23-0.22h1.4c0.13,0,0.22,0.11,0.23,0.22V7.4c0.5-0.68,1.3-1.09,2.16-1.1h0.03c1.09,0,2.09,0.6,2.6,1.55 c0.45-0.95,1.4-1.55,2.44-1.56c1.62,0,2.93,1.25,2.9,2.78L36.08,14.24z'/%3E %3Cpath class='st1' style='opacity:0.35; enable-background:new;' d='M84.34,13.59l-0.07-0.13l-1.96-2.99l1.94-2.95c0.44-0.67,0.26-1.56-0.41-2.02c-0.02,0-0.03,0-0.04-0.01 c-0.23-0.15-0.5-0.22-0.78-0.22h-1.61c-0.56,0-1.08,0.29-1.37,0.78L79.72,6.6l-0.34-0.56C79.09,5.56,78.57,5.27,78,5.27h-1.6 c-0.6,0-1.13,0.37-1.35,0.92c-2.19-1.66-5.28-1.47-7.26,0.45c-0.35,0.34-0.65,0.72-0.89,1.14c-0.9-1.62-2.58-2.72-4.5-2.72 c-0.5,0-1.01,0.07-1.48,0.23V3.51c0-0.82-0.66-1.48-1.47-1.48h-1.4c-0.81,0-1.47,0.66-1.47,1.47v3.75 c-0.95-1.36-2.5-2.18-4.17-2.19c-0.74,0-1.46,0.16-2.12,0.47c-0.24-0.17-0.54-0.26-0.84-0.26h-1.4c-0.45,0-0.87,0.21-1.15,0.56 c-0.02-0.03-0.04-0.05-0.07-0.08c-0.28-0.3-0.68-0.47-1.09-0.47h-1.39c-0.3,0-0.6,0.09-0.84,0.26c-0.67-0.3-1.39-0.46-2.12-0.46 c-1.83,0-3.43,1-4.37,2.5c-0.2-0.46-0.48-0.89-0.83-1.25c-0.8-0.81-1.89-1.25-3.02-1.25h-0.01c-0.89,0.01-1.75,0.33-2.46,0.88 c-0.74-0.57-1.64-0.88-2.57-0.88H28.1c-0.29,0-0.58,0.03-0.86,0.11c-0.28,0.06-0.56,0.16-0.82,0.28c-0.21-0.12-0.45-0.18-0.7-0.18 h-1.4c-0.82,0-1.47,0.66-1.47,1.47v7.5c0,0.82,0.66,1.47,1.47,1.47h1.4c0.82,0,1.48-0.66,1.48-1.48l0,0V9.79 c0.03-0.36,0.23-0.59,0.36-0.59c0.18,0,0.38,0.18,0.38,0.47v4.57c0,0.82,0.66,1.47,1.47,1.47h1.41c0.82,0,1.47-0.66,1.47-1.47 l-0.01-4.57c0.06-0.32,0.25-0.47,0.35-0.47c0.18,0,0.38,0.18,0.38,0.47v4.57c0,0.82,0.66,1.47,1.47,1.47h1.41 c0.82,0,1.47-0.66,1.47-1.47v-0.38c0.96,1.29,2.46,2.06,4.06,2.06c0.74,0,1.46-0.16,2.12-0.47c0.24,0.17,0.54,0.26,0.84,0.26h1.39 c0.3,0,0.6-0.09,0.84-0.26v2.01c0,0.82,0.66,1.47,1.47,1.47h1.4c0.82,0,1.47-0.66,1.47-1.47v-1.77c0.48,0.15,0.99,0.23,1.49,0.22 c1.7,0,3.22-0.87,4.17-2.2v0.52c0,0.82,0.66,1.47,1.47,1.47h1.4c0.3,0,0.6-0.09,0.84-0.26c0.66,0.31,1.39,0.47,2.12,0.47 c1.92,0,3.6-1.1,4.49-2.73c1.54,2.65,4.95,3.53,7.58,1.98c0.18-0.11,0.36-0.22,0.53-0.36c0.22,0.55,0.76,0.91,1.35,0.9H78 c0.56,0,1.08-0.29,1.37-0.78l0.37-0.61l0.37,0.61c0.29,0.48,0.81,0.78,1.38,0.78h1.6c0.81,0,1.46-0.66,1.45-1.46 C84.49,14.02,84.44,13.8,84.34,13.59L84.34,13.59z M35.86,14.47h-1.41c-0.13,0-0.23-0.11-0.23-0.23V9.68 c0-0.98-0.74-1.71-1.62-1.71c-0.8,0-1.46,0.7-1.59,1.62l0.01,4.66c0,0.13-0.1,0.23-0.23,0.23h-1.41c-0.13,0-0.23-0.11-0.23-0.23 V9.68c0-0.98-0.74-1.71-1.62-1.71c-0.85,0-1.54,0.79-1.6,1.8v4.48c0,0.13-0.1,0.23-0.23,0.23h-1.4c-0.13,0-0.23-0.11-0.23-0.23 V6.74c0.01-0.13,0.11-0.22,0.23-0.22h1.4c0.13,0,0.22,0.11,0.23,0.22V7.4c0.5-0.68,1.3-1.09,2.16-1.1h0.03 c1.09,0,2.09,0.6,2.6,1.55c0.45-0.95,1.4-1.55,2.44-1.56c1.62,0,2.93,1.25,2.9,2.78l0.01,5.16C36.09,14.36,35.98,14.46,35.86,14.47 L35.86,14.47z M45.97,14.24c0,0.13-0.1,0.23-0.23,0.23h-1.4c-0.13,0-0.23-0.11-0.23-0.23V13.5c-0.7,0.76-1.69,1.18-2.72,1.18 c-2.17,0-3.94-1.87-3.94-4.19s1.77-4.19,3.94-4.19c1.03,0,2.02,0.43,2.73,1.18V6.74c0-0.13,0.1-0.23,0.23-0.23h1.4 c0.12-0.01,0.22,0.08,0.23,0.21c0,0.01,0,0.01,0,0.02v7.51h-0.01V14.24z M52.41,14.67c-1.03,0-2.02-0.43-2.73-1.18v3.97 c0,0.13-0.1,0.23-0.23,0.23h-1.4c-0.13,0-0.23-0.1-0.23-0.23V6.75c0-0.13,0.1-0.22,0.23-0.22h1.4c0.13,0,0.23,0.11,0.23,0.23v0.73 c0.71-0.76,1.7-1.18,2.73-1.18c2.17,0,3.94,1.86,3.94,4.18S54.58,14.67,52.41,14.67z M66.24,11.39c-0.39,1.87-1.96,3.29-3.84,3.29 c-1.03,0-2.02-0.43-2.73-1.18v0.73c0,0.13-0.1,0.23-0.23,0.23h-1.4c-0.13,0-0.23-0.11-0.23-0.23V3.51c0-0.13,0.1-0.23,0.23-0.23 h1.4c0.13,0,0.23,0.11,0.23,0.23v3.97c0.71-0.75,1.7-1.18,2.73-1.17c1.88,0,3.45,1.4,3.84,3.28C66.37,10.19,66.37,10.8,66.24,11.39 L66.24,11.39L66.24,11.39z M71.67,14.68c-2,0.01-3.73-1.35-4.17-3.3c-0.13-0.59-0.13-1.19,0-1.77c0.44-1.94,2.17-3.31,4.17-3.3 c2.36,0,4.26,1.87,4.26,4.19S74.03,14.68,71.67,14.68L71.67,14.68z M83.04,14.47h-1.61c-0.13,0-0.24-0.06-0.3-0.17l-1.44-2.39 l-1.44,2.39c-0.06,0.11-0.18,0.17-0.3,0.17h-1.61c-0.04,0-0.08-0.01-0.12-0.03c-0.09-0.06-0.13-0.19-0.06-0.28l0,0l2.43-3.68 L76.2,6.84c-0.02-0.03-0.03-0.07-0.03-0.12c0-0.12,0.09-0.21,0.21-0.21h1.61c0.13,0,0.24,0.06,0.3,0.17l1.41,2.36l1.41-2.36 c0.06-0.11,0.18-0.17,0.3-0.17h1.61c0.04,0,0.08,0.01,0.12,0.03c0.09,0.06,0.13,0.19,0.06,0.28l0,0l-2.38,3.64l2.43,3.67 c0.02,0.03,0.03,0.07,0.03,0.12C83.25,14.38,83.16,14.47,83.04,14.47L83.04,14.47L83.04,14.47z'/%3E %3Cpath class='st0' style='opacity:0.9; fill: %23FFFFFF; enable-background: new;' d='M10.5,1.24c-5.11,0-9.25,4.15-9.25,9.25s4.15,9.25,9.25,9.25s9.25-4.15,9.25-9.25 C19.75,5.38,15.61,1.24,10.5,1.24z M14.89,12.77c-1.93,1.93-4.78,2.31-6.7,2.31c-0.7,0-1.41-0.05-2.1-0.16c0,0-1.02-5.64,2.14-8.81 c0.83-0.83,1.95-1.28,3.13-1.28c1.27,0,2.49,0.51,3.39,1.42C16.59,8.09,16.64,11,14.89,12.77z'/%3E %3Cpath class='st1' style='opacity:0.35; enable-background:new;' d='M10.5-0.01C4.7-0.01,0,4.7,0,10.49s4.7,10.5,10.5,10.5S21,16.29,21,10.49C20.99,4.7,16.3-0.01,10.5-0.01z M10.5,19.74c-5.11,0-9.25-4.15-9.25-9.25s4.14-9.26,9.25-9.26s9.25,4.15,9.25,9.25C19.75,15.61,15.61,19.74,10.5,19.74z'/%3E %3Cpath class='st1' style='opacity:0.35; enable-background:new;' d='M14.74,6.25C12.9,4.41,9.98,4.35,8.23,6.1c-3.16,3.17-2.14,8.81-2.14,8.81s5.64,1.02,8.81-2.14 C16.64,11,16.59,8.09,14.74,6.25z M12.47,10.34l-0.91,1.87l-0.9-1.87L8.8,9.43l1.86-0.9l0.9-1.87l0.91,1.87l1.86,0.9L12.47,10.34z'/%3E %3Cpolygon class='st0' style='opacity:0.9; fill: %23FFFFFF; enable-background: new;' points='14.33,9.43 12.47,10.34 11.56,12.21 10.66,10.34 8.8,9.43 10.66,8.53 11.56,6.66 12.47,8.53 '/%3E%3C/g%3E%3C/svg%3E" ); +} + +a.mapboxgl-ctrl-logo.mapboxgl-compact { + width: 21px; + height: 21px; + background-image: url( "data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 21 21' style='enable-background:new 0 0 21 21;' xml:space='preserve'%3E%3Cg transform='translate(0,0.01)'%3E%3Cpath d='m 10.5,1.24 c -5.11,0 -9.25,4.15 -9.25,9.25 0,5.1 4.15,9.25 9.25,9.25 5.1,0 9.25,-4.15 9.25,-9.25 0,-5.11 -4.14,-9.25 -9.25,-9.25 z m 4.39,11.53 c -1.93,1.93 -4.78,2.31 -6.7,2.31 -0.7,0 -1.41,-0.05 -2.1,-0.16 0,0 -1.02,-5.64 2.14,-8.81 0.83,-0.83 1.95,-1.28 3.13,-1.28 1.27,0 2.49,0.51 3.39,1.42 1.84,1.84 1.89,4.75 0.14,6.52 z' style='opacity:0.9;fill:%23ffffff;enable-background:new' class='st0'/%3E%3Cpath d='M 10.5,-0.01 C 4.7,-0.01 0,4.7 0,10.49 c 0,5.79 4.7,10.5 10.5,10.5 5.8,0 10.5,-4.7 10.5,-10.5 C 20.99,4.7 16.3,-0.01 10.5,-0.01 Z m 0,19.75 c -5.11,0 -9.25,-4.15 -9.25,-9.25 0,-5.1 4.14,-9.26 9.25,-9.26 5.11,0 9.25,4.15 9.25,9.25 0,5.13 -4.14,9.26 -9.25,9.26 z' style='opacity:0.35;enable-background:new' class='st1'/%3E%3Cpath d='M 14.74,6.25 C 12.9,4.41 9.98,4.35 8.23,6.1 5.07,9.27 6.09,14.91 6.09,14.91 c 0,0 5.64,1.02 8.81,-2.14 C 16.64,11 16.59,8.09 14.74,6.25 Z m -2.27,4.09 -0.91,1.87 -0.9,-1.87 -1.86,-0.91 1.86,-0.9 0.9,-1.87 0.91,1.87 1.86,0.9 z' style='opacity:0.35;enable-background:new' class='st1'/%3E%3Cpolygon points='11.56,12.21 10.66,10.34 8.8,9.43 10.66,8.53 11.56,6.66 12.47,8.53 14.33,9.43 12.47,10.34 ' style='opacity:0.9;fill:%23ffffff;enable-background:new' class='st0'/%3E%3C/g%3E%3C/svg%3E" ); +} + +.mapboxgl-ctrl.mapboxgl-ctrl-attrib { + padding: 0 5px; + background-color: rgba( 255, 255, 255, 0.5 ); + margin: 0; +} + +@media screen { + .mapboxgl-ctrl-attrib.mapboxgl-compact { + margin: 0 10px 10px; + position: relative; + background-color: #fff; + border-radius: 3px 12px 12px 3px; + } + + .mapboxgl-ctrl-attrib.mapboxgl-compact:hover { + padding: 2px 24px 2px 4px; + visibility: visible; + } + + .mapboxgl-ctrl-attrib.mapboxgl-compact > a { + display: none; + } + + .mapboxgl-ctrl-attrib.mapboxgl-compact:hover > a { + display: inline; + } + + .mapboxgl-ctrl-attrib.mapboxgl-compact::after { + content: ''; + cursor: pointer; + position: absolute; + bottom: 0; + right: 0; + background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath fill='%23333333' fill-rule='evenodd' d='M4,10a6,6 0 1,0 12,0a6,6 0 1,0 -12,0 M9,7a1,1 0 1,0 2,0a1,1 0 1,0 -2,0 M9,10a1,1 0 1,1 2,0l0,3a1,1 0 1,1 -2,0'/%3E %3C/svg%3E" ); + background-color: rgba( 255, 255, 255, 0.5 ); + width: 24px; + height: 24px; + box-sizing: border-box; + border-radius: 12px; + } +} + +.mapboxgl-ctrl-attrib a { + color: rgba( 0, 0, 0, 0.75 ); + text-decoration: none; +} + +.mapboxgl-ctrl-attrib a:hover { + color: inherit; + text-decoration: underline; +} + +/* stylelint-disable-next-line selector-class-pattern */ +.mapboxgl-ctrl-attrib .mapbox-improve-map { + font-weight: bold; + margin-left: 2px; +} + +.mapboxgl-attrib-empty { + display: none; +} + +.mapboxgl-ctrl-scale { + background-color: rgba( 255, 255, 255, 0.75 ); + font-size: 10px; + border-width: medium 2px 2px; + border-style: none solid solid; + border-color: #333; + padding: 0 5px; + color: #333; + box-sizing: border-box; +} + +.mapboxgl-popup { + position: absolute; + top: 0; + left: 0; + display: -webkit-flex; + display: flex; + will-change: transform; + pointer-events: none; +} + +.mapboxgl-popup-anchor-top, +.mapboxgl-popup-anchor-top-left, +.mapboxgl-popup-anchor-top-right { + -webkit-flex-direction: column; + flex-direction: column; +} + +.mapboxgl-popup-anchor-bottom, +.mapboxgl-popup-anchor-bottom-left, +.mapboxgl-popup-anchor-bottom-right { + -webkit-flex-direction: column-reverse; + flex-direction: column-reverse; +} + +.mapboxgl-popup-anchor-left { + -webkit-flex-direction: row; + flex-direction: row; +} + +.mapboxgl-popup-anchor-right { + -webkit-flex-direction: row-reverse; + flex-direction: row-reverse; +} + +.mapboxgl-popup-tip { + width: 0; + height: 0; + border: 10px solid transparent; + z-index: 1; +} + +.mapboxgl-popup-anchor-top .mapboxgl-popup-tip { + -webkit-align-self: center; + align-self: center; + border-top: none; + border-bottom-color: #fff; +} + +.mapboxgl-popup-anchor-top-left .mapboxgl-popup-tip { + -webkit-align-self: flex-start; + align-self: flex-start; + border-top: none; + border-left: none; + border-bottom-color: #fff; +} + +.mapboxgl-popup-anchor-top-right .mapboxgl-popup-tip { + -webkit-align-self: flex-end; + align-self: flex-end; + border-top: none; + border-right: none; + border-bottom-color: #fff; +} + +.mapboxgl-popup-anchor-bottom .mapboxgl-popup-tip { + -webkit-align-self: center; + align-self: center; + border-bottom: none; + border-top-color: #fff; +} + +.mapboxgl-popup-anchor-bottom-left .mapboxgl-popup-tip { + -webkit-align-self: flex-start; + align-self: flex-start; + border-bottom: none; + border-left: none; + border-top-color: #fff; +} + +.mapboxgl-popup-anchor-bottom-right .mapboxgl-popup-tip { + -webkit-align-self: flex-end; + align-self: flex-end; + border-bottom: none; + border-right: none; + border-top-color: #fff; +} + +.mapboxgl-popup-anchor-left .mapboxgl-popup-tip { + -webkit-align-self: center; + align-self: center; + border-left: none; + border-right-color: #fff; +} + +.mapboxgl-popup-anchor-right .mapboxgl-popup-tip { + -webkit-align-self: center; + align-self: center; + border-right: none; + border-left-color: #fff; +} + +.mapboxgl-popup-close-button { + position: absolute; + right: 0; + top: 0; + border: 0; + border-radius: 0 3px 0 0; + cursor: pointer; + background-color: transparent; +} + +.mapboxgl-popup-close-button:hover { + background-color: rgba( 0, 0, 0, 0.05 ); +} + +.mapboxgl-popup-content { + position: relative; + background: #fff; + border-radius: 3px; + box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.1 ); + padding: 10px 10px 15px; + pointer-events: auto; +} + +.mapboxgl-popup-anchor-top-left .mapboxgl-popup-content { + border-top-left-radius: 0; +} + +.mapboxgl-popup-anchor-top-right .mapboxgl-popup-content { + border-top-right-radius: 0; +} + +.mapboxgl-popup-anchor-bottom-left .mapboxgl-popup-content { + border-bottom-left-radius: 0; +} + +.mapboxgl-popup-anchor-bottom-right .mapboxgl-popup-content { + border-bottom-right-radius: 0; +} + +.mapboxgl-marker { + position: absolute; + top: 0; + left: 0; + will-change: transform; +} + +.mapboxgl-user-location-dot { + background-color: #1da1f2; + width: 15px; + height: 15px; + border-radius: 50%; + box-shadow: 0 0 2px rgba( 0, 0, 0, 0.25 ); +} + +.mapboxgl-user-location-dot::before { + background-color: #1da1f2; + content: ''; + width: 15px; + height: 15px; + border-radius: 50%; + position: absolute; + -webkit-animation: mapboxgl-user-location-dot-pulse 2s infinite; + -moz-animation: mapboxgl-user-location-dot-pulse 2s infinite; + -ms-animation: mapboxgl-user-location-dot-pulse 2s infinite; + animation: mapboxgl-user-location-dot-pulse 2s infinite; +} + +.mapboxgl-user-location-dot::after { + border-radius: 50%; + border: 2px solid #fff; + content: ''; + height: 19px; + left: -2px; + position: absolute; + top: -2px; + width: 19px; + box-sizing: border-box; +} + +@-webkit-keyframes mapboxgl-user-location-dot-pulse { + 0% { + -webkit-transform: scale( 1 ); + opacity: 1; + } + 70% { + -webkit-transform: scale( 3 ); + opacity: 0; + } + 100% { + -webkit-transform: scale( 1 ); + opacity: 0; + } +} + +@-ms-keyframes mapboxgl-user-location-dot-pulse { + 0% { + -ms-transform: scale( 1 ); + opacity: 1; + } + 70% { + -ms-transform: scale( 3 ); + opacity: 0; + } + 100% { + -ms-transform: scale( 1 ); + opacity: 0; + } +} + +@keyframes mapboxgl-user-location-dot-pulse { + 0% { + transform: scale( 1 ); + opacity: 1; + } + 70% { + transform: scale( 3 ); + opacity: 0; + } + 100% { + transform: scale( 1 ); + opacity: 0; + } +} + +.mapboxgl-user-location-dot-stale { + background-color: #aaa; +} + +.mapboxgl-user-location-dot-stale::after { + display: none; +} + +.mapboxgl-crosshair, +.mapboxgl-crosshair .mapboxgl-interactive, +.mapboxgl-crosshair .mapboxgl-interactive:active { + cursor: crosshair; +} + +.mapboxgl-boxzoom { + position: absolute; + top: 0; + left: 0; + width: 0; + height: 0; + background: #fff; + border: 2px dotted #202020; + opacity: 0.5; +} + +@media print { + /* stylelint-disable-next-line selector-class-pattern */ + .mapbox-improve-map { + display: none; + } +} diff --git a/client/gutenberg/extensions/map-block/settings.js b/client/gutenberg/extensions/map-block/settings.js index b7e5460407895a..8e1f7407b70e66 100644 --- a/client/gutenberg/extensions/map-block/settings.js +++ b/client/gutenberg/extensions/map-block/settings.js @@ -44,8 +44,8 @@ export const settings = { map_center: { type: 'object', default: { - latitude: 37.7749295, - longitude: -122.41941550000001, + latitude: -122.41941550000001, + longitude: 37.7749295, }, }, marker_color: { @@ -55,6 +55,9 @@ export const settings = { api_key: { type: 'string', }, + mapbox_key: { + type: 'string', + }, }, map_styleOptions: [ { @@ -74,7 +77,6 @@ export const settings = { label: __( 'Terrain', 'jetpack' ), }, ], - GOOGLE_MAPS_API_KEY: 'AIzaSyDaj7klnWKpzGx0W5PonA73Dgr68Me8cyg', validAlignments: [ 'center', 'wide', 'full' ], markerIcon: ( diff --git a/client/gutenberg/extensions/map-block/style.scss b/client/gutenberg/extensions/map-block/style.scss index 18f4aeda31fa74..2167e2d2380316 100644 --- a/client/gutenberg/extensions/map-block/style.scss +++ b/client/gutenberg/extensions/map-block/style.scss @@ -8,8 +8,4 @@ min-height: 400px; text-align: left; } - // Ensure that right edge of Title/Caption inputs aren't cut off - .gm-style-iw > div { - padding-right: 1px; - } } diff --git a/client/gutenberg/extensions/map-block/view.js b/client/gutenberg/extensions/map-block/view.js index 6d39cdeefefcc5..f4e29d948262db 100644 --- a/client/gutenberg/extensions/map-block/view.js +++ b/client/gutenberg/extensions/map-block/view.js @@ -5,6 +5,8 @@ */ import './style.scss'; +/* TODO: Load Mapbox stylesheet dynamically, from CDN */ +import './mapbox.scss'; import component from './component.js'; import { settings } from './settings.js'; import FrontendManagement from 'gutenberg/extensions/shared/frontend-management.js'; @@ -16,7 +18,7 @@ window.addEventListener( 'load', function() { return; } const frontendManagement = new FrontendManagement(); - const url = '/wp-json/jetpack/v4/service-api-keys/googlemaps'; + const url = '/wp-json/jetpack/v4/service-api-keys/mapbox'; apiFetch( { url, method: 'GET' } ).then( result => { frontendManagement.blockIterator( document, [ { From d8f438b0e33e1680d1d03fe23ef58741d1084a87 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 1 Nov 2018 12:03:29 -0400 Subject: [PATCH 089/107] Mapbox error management. --- .../gutenberg/extensions/map-block/add-point/index.js | 4 +++- client/gutenberg/extensions/map-block/component.js | 6 +++++- client/gutenberg/extensions/map-block/edit.js | 10 ++++++++-- .../extensions/map-block/location-search/index.js | 9 +++++++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/client/gutenberg/extensions/map-block/add-point/index.js b/client/gutenberg/extensions/map-block/add-point/index.js index 41a6c12c056824..d26f6f87fdc1b4 100644 --- a/client/gutenberg/extensions/map-block/add-point/index.js +++ b/client/gutenberg/extensions/map-block/add-point/index.js @@ -16,7 +16,7 @@ import LocationSearch from '../location-search'; import './style.scss'; export class AddPoint extends Component { render() { - const { onClose, onAddPoint, api_key } = this.props; + const { onClose, onAddPoint, onError, api_key } = this.props; return ( @@ -38,6 +39,7 @@ export class AddPoint extends Component { AddPoint.defaultProps = { onAddPoint: () => {}, onClose: () => {}, + onError: () => {}, }; export default AddPoint; diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index 56e606e962296d..e08b47b7ff2cd2 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -269,7 +269,7 @@ export class Map extends Component { } initMap( map_center ) { const { mapboxgl } = this.state; - const { zoom, onMapLoaded, admin } = this.props; + const { zoom, onMapLoaded, onError, admin } = this.props; const map = new mapboxgl.Map( { container: this.mapRef.current, style: 'mapbox://styles/mapbox/streets-v9', @@ -279,6 +279,9 @@ export class Map extends Component { attributionControl: false, dragRotate: false, } ); + map.on( 'error', e => { + onError( 'mapbox_error', e.error.message ); + } ); const zoomControl = new mapboxgl.NavigationControl( { showCompass: false, showZoom: true, @@ -319,6 +322,7 @@ Map.defaultProps = { onSetZoom: () => {}, onMapLoaded: () => {}, onMarkerClick: () => {}, + onError: () => {}, marker_color: 'red', api_key: null, map_center: {}, diff --git a/client/gutenberg/extensions/map-block/edit.js b/client/gutenberg/extensions/map-block/edit.js index b074ead62e1d2b..acecead0da742c 100644 --- a/client/gutenberg/extensions/map-block/edit.js +++ b/client/gutenberg/extensions/map-block/edit.js @@ -93,8 +93,7 @@ class MapEdit extends Component { } ); }, result => { - noticeOperations.removeAllNotices(); - noticeOperations.createErrorNotice( result.message ); + this.onError( null, result.message ); this.setState( { apiState: API_STATE_FAILURE, } ); @@ -104,6 +103,11 @@ class MapEdit extends Component { componentDidMount() { this.apiCall(); } + onError = ( code, message ) => { + const { noticeOperations } = this.props; + noticeOperations.removeAllNotices(); + noticeOperations.createErrorNotice( message ); + }; render() { const { className, setAttributes, attributes, noticeUI, notices } = this.props; const { map_style, map_details, points, zoom, map_center, marker_color, align } = attributes; @@ -221,12 +225,14 @@ class MapEdit extends Component { onSetPoints={ value => setAttributes( { points: value } ) } onMapLoaded={ () => this.setState( { addPointVisibility: true } ) } onMarkerClick={ () => this.setState( { addPointVisibility: false } ) } + onError={ this.onError } > { addPointVisibility && ( this.setState( { addPointVisibility: false } ) } api_key={ api_key } + onError={ this.onError } /> ) } diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js index 83daa932610418..9570eea6722af2 100644 --- a/client/gutenberg/extensions/map-block/location-search/index.js +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -51,7 +51,7 @@ export class LocationSearch extends Component { }; search = value => { - const { api_key } = this.props; + const { api_key, onError } = this.props; const url = 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + encodeURI( value ) + @@ -64,7 +64,8 @@ export class LocationSearch extends Component { .done( function( data ) { resolve( data.features ); } ) - .fail( function() { + .fail( function( data ) { + onError( data.statusText, data.responseJSON.message ); reject( new Error( 'Mapbox Places Error' ) ); } ); } ); @@ -95,4 +96,8 @@ export class LocationSearch extends Component { } } +LocationSearch.defaultProps = { + onError: () => {}, +}; + export default LocationSearch; From 6b34ca147f72f1484286c2f96adf619d0f9b5602 Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 1 Nov 2018 12:31:39 -0400 Subject: [PATCH 090/107] Replace jQuery ajax() with pure Javascript. --- .../map-block/location-search/index.js | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js index 9570eea6722af2..59c93997877aa8 100644 --- a/client/gutenberg/extensions/map-block/location-search/index.js +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -58,16 +58,19 @@ export class LocationSearch extends Component { '.json?access_token=' + api_key; return new Promise( function( resolve, reject ) { - /* TODO: Replace with pure JS */ - window.jQuery - .ajax( url ) - .done( function( data ) { - resolve( data.features ); - } ) - .fail( function( data ) { - onError( data.statusText, data.responseJSON.message ); + const xhr = new XMLHttpRequest(); + xhr.open( 'GET', url ); + xhr.onload = function() { + if ( xhr.status === 200 ) { + const res = JSON.parse( xhr.responseText ); + resolve( res.features ); + } else { + const res = JSON.parse( xhr.responseText ); + onError( res.statusText, res.responseJSON.message ); reject( new Error( 'Mapbox Places Error' ) ); - } ); + } + }; + xhr.send(); } ); }; onReset = () => { From e6e946cd5f5296b6ab9ad7220f95cbb63a37dc5f Mon Sep 17 00:00:00 2001 From: Jefferson Rabb Date: Thu, 1 Nov 2018 14:40:33 -0400 Subject: [PATCH 091/107] Fallback to Open Street Map embed, which will be visible if block is unavailable or fails to render. --- .../extensions/map-block/component.js | 14 ++++++++++---- .../map-block/location-search/index.js | 4 ++-- .../extensions/map-block/map-marker/index.js | 4 ++-- client/gutenberg/extensions/map-block/save.js | 18 +++++++++++++++++- .../gutenberg/extensions/map-block/settings.js | 4 ++-- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/client/gutenberg/extensions/map-block/component.js b/client/gutenberg/extensions/map-block/component.js index e08b47b7ff2cd2..4af748899970c9 100644 --- a/client/gutenberg/extensions/map-block/component.js +++ b/client/gutenberg/extensions/map-block/component.js @@ -5,7 +5,7 @@ */ import { __ } from '@wordpress/i18n'; -import { Component, createRef, Fragment } from '@wordpress/element'; +import { Component, createRef, Fragment, Children } from '@wordpress/element'; import { Button, Dashicon, TextareaControl, TextControl } from '@wordpress/components'; import { get, assign } from 'lodash'; @@ -42,6 +42,12 @@ export class Map extends Component { const { onMarkerClick, deleteActiveMarker, updateActiveMarker } = this; const currentPoint = get( activeMarker, 'props.point' ) || {}; const { title, caption } = currentPoint; + let addPoint = null; + Children.map( children, element => { + if ( element && 'AddPoint' === element.type.name ) { + addPoint = element; + } + } ); const mapMarkers = map && mapboxgl && @@ -102,7 +108,7 @@ export class Map extends Component { { mapMarkers }
{ infoWindow } - { children } + { addPoint }
); } @@ -199,7 +205,7 @@ export class Map extends Component { return; } points.forEach( point => { - bounds.extend( [ point.coordinates.latitude, point.coordinates.longitude ] ); + bounds.extend( [ point.coordinates.longitude, point.coordinates.latitude ] ); } ); map.setCenter( bounds.getCenter() ); @@ -308,8 +314,8 @@ export class Map extends Component { } googlePoint2Mapbox( google_point ) { const map_center = [ - google_point.latitude ? google_point.latitude : 0, google_point.longitude ? google_point.longitude : 0, + google_point.latitude ? google_point.latitude : 0, ]; return map_center; } diff --git a/client/gutenberg/extensions/map-block/location-search/index.js b/client/gutenberg/extensions/map-block/location-search/index.js index 59c93997877aa8..0256897cc7ee98 100644 --- a/client/gutenberg/extensions/map-block/location-search/index.js +++ b/client/gutenberg/extensions/map-block/location-search/index.js @@ -42,8 +42,8 @@ export class LocationSearch extends Component { caption: value.place_name, id: value.id, coordinates: { - latitude: value.geometry.coordinates[ 0 ], - longitude: value.geometry.coordinates[ 1 ], + longitude: value.geometry.coordinates[ 0 ], + latitude: value.geometry.coordinates[ 1 ], }, }; this.props.onAddPoint( point ); diff --git a/client/gutenberg/extensions/map-block/map-marker/index.js b/client/gutenberg/extensions/map-block/map-marker/index.js index 7907c3857953f4..0534ed6962b5e9 100644 --- a/client/gutenberg/extensions/map-block/map-marker/index.js +++ b/client/gutenberg/extensions/map-block/map-marker/index.js @@ -30,12 +30,12 @@ export class MapMarker extends Component { }; getPoint = () => { const { point } = this.props; - return [ point.coordinates.latitude, point.coordinates.longitude ]; + return [ point.coordinates.longitude, point.coordinates.latitude ]; }; renderMarker() { const { map, point, mapboxgl, marker_color } = this.props; const { handleClick } = this; - const mapboxPoint = [ point.coordinates.latitude, point.coordinates.longitude ]; + const mapboxPoint = [ point.coordinates.longitude, point.coordinates.latitude ]; const el = this.marker ? this.marker.getElement() : document.createElement( 'div' ); if ( this.marker ) { this.marker.setLngLat( mapboxPoint ); diff --git a/client/gutenberg/extensions/map-block/save.js b/client/gutenberg/extensions/map-block/save.js index 59c914f6a48bce..8c875defdce8af 100644 --- a/client/gutenberg/extensions/map-block/save.js +++ b/client/gutenberg/extensions/map-block/save.js @@ -23,7 +23,23 @@ class MapSave extends Component { data-zoom={ zoom } data-map_center={ JSON.stringify( map_center ) } data-marker_color={ marker_color } - /> + > +