From 30f0377b45b9aa9a8b1de7e1517ec6f2f217abba Mon Sep 17 00:00:00 2001 From: Justin Foell <630830+jrfoell@users.noreply.github.com> Date: Fri, 30 Apr 2021 14:59:10 -0500 Subject: [PATCH] Added segment block with test --- readme.txt | 4 +- src/WPStrava.php | 11 +++ src/WPStrava/Blocks/Segment.php | 98 +++++++++++++++++++++++ src/WPStrava/SOM.php | 11 +++ src/WPStrava/SegmentsRenderer.php | 27 ++++--- src/blocks/segment/block.json | 30 +++++++ src/blocks/segment/edit.js | 125 ++++++++++++++++++++++++++++++ src/blocks/segment/index.js | 9 +++ src/index.js | 1 + tests/WPStrava/SOMEnglishTest.php | 11 +++ 10 files changed, 314 insertions(+), 13 deletions(-) create mode 100644 src/WPStrava/Blocks/Segment.php create mode 100644 src/blocks/segment/block.json create mode 100644 src/blocks/segment/edit.js create mode 100644 src/blocks/segment/index.js diff --git a/readme.txt b/readme.txt index 5cca9ec..d581463 100755 --- a/readme.txt +++ b/readme.txt @@ -121,13 +121,11 @@ On the WP-Strava settings page you cannot currently remove and add another athle == Changelog == = 2.9.0 = +Added Segment Block https://wordpress.org/support/topic/show-segments-feature/ / https://wordpress.org/support/topic/embed-segments-feature/ Switched Activities List to display moving time instead of elapsed time https://wordpress.org/support/topic/moving-time-instead-of-elapsed-time/ Added calories burned (when available) to Activity and Activities List https://wordpress.org/support/topic/calorie/ -= Unreleased = -Add Segment Block - = 2.8.0 = Revised `block.json` based on feedback from https://wordpress.org/plugins/developers/block-plugin-validator/ Add PHPCompatibility checks to coding standards (and fixes from recommendations) diff --git a/src/WPStrava.php b/src/WPStrava.php index d5d61eb..27ce19d 100644 --- a/src/WPStrava.php +++ b/src/WPStrava.php @@ -41,6 +41,12 @@ class WPStrava { */ private $routes = null; + /** + * Segment object to get segments. + * @var WPStrava_Segments + */ + private $segments = null; + /** * Private constructor (singleton). */ @@ -115,6 +121,10 @@ class WPStrava { return $this->get_routes(); } + if ( 'segments' === $name ) { + return $this->get_segments(); + } + if ( isset( $this->{$name} ) ) { return $this->{$name}; } @@ -216,6 +226,7 @@ class WPStrava { 'WPStrava_Blocks_Activity', 'WPStrava_Blocks_Route', 'WPStrava_Blocks_ActivitiesList', + 'WPStrava_Blocks_Segment', ); // automatically load dependencies and version diff --git a/src/WPStrava/Blocks/Segment.php b/src/WPStrava/Blocks/Segment.php new file mode 100644 index 0000000..89bcb62 --- /dev/null +++ b/src/WPStrava/Blocks/Segment.php @@ -0,0 +1,98 @@ + + * @since 2.9.0 + */ + private $add_script = false; + + /** + * Register the wp-strava/segment block. + * + * @author Justin Foell + * @since 2.9.0 + */ + public function register_block() { + register_block_type( + 'wp-strava/segment', + array( + 'style' => 'wp-strava-block', + 'editor_style' => 'wp-strava-block-editor', + 'editor_script' => 'wp-strava-block', + 'render_callback' => array( $this, 'render_block' ), + 'attributes' => array( + 'url' => array( + 'type' => 'string', + 'default' => '', + ), + 'imageOnly' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'displayMarkers' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'som' => array( + 'type' => 'string', + 'default' => null, + ), + ), + ) + ); + add_action( 'wp_footer', array( $this, 'print_scripts' ) ); + } + + /** + * Render for this block. + * + * @param array $attributes JSON attributes saved in the HTML comment for this block. + * @param string $content The content from JS save() for this block. + * @return string HTML for this block. + * @author Justin Foell + * @since 2.9.0 + */ + public function render_block( $attributes, $content ) { + if ( empty( $attributes['url'] ) ) { + return $content; + } + + $this->add_script = true; + + $matches = array(); + preg_match( '/\/segments\/([0-9].*)$/', $attributes['url'], $matches ); + if ( $matches[1] ) { + // Transform from block attributes to shortcode standard. + $atts = array( + 'id' => $matches[1], + 'image_only' => isset( $attributes['imageOnly'] ) ? $attributes['imageOnly'] : false, + 'markers' => isset( $attributes['displayMarkers'] ) ? $attributes['displayMarkers'] : true, + 'som' => ! empty( $attributes['som'] ) ? $attributes['som'] : null, + ); + + $renderer = new WPStrava_SegmentsRenderer(); + return $renderer->get_html( $atts ); + } + return $content; + } + + /** + * Enqueue style if block is being used. + * + * @author Justin Foell + * @since 2.9.0 + */ + public function print_scripts() { + if ( $this->add_script ) { + wp_enqueue_style( 'wp-strava-style' ); + } + } +} diff --git a/src/WPStrava/SOM.php b/src/WPStrava/SOM.php index 907d27b..deaf7d0 100644 --- a/src/WPStrava/SOM.php +++ b/src/WPStrava/SOM.php @@ -99,4 +99,15 @@ abstract class WPStrava_SOM { public function get_calories_label() { return __( 'kcal', 'wp-strava' ); } + + /** + * Get percent with % symbol. + * + * @param mixed $pct + * @author Justin Foell + * @since 2.9.0 + */ + public function percent( $pct ) { + return number_format_i18n( $pct, 1 ) . '%'; + } } diff --git a/src/WPStrava/SegmentsRenderer.php b/src/WPStrava/SegmentsRenderer.php index 645bf2b..d50055f 100644 --- a/src/WPStrava/SegmentsRenderer.php +++ b/src/WPStrava/SegmentsRenderer.php @@ -18,7 +18,7 @@ class WPStrava_SegmentsRenderer { * @param array $atts * @return string HTML for an segment. * @author Justin Foell - * @since 2.2.0 + * @since 2.9.0 */ public function get_html( $atts ) { $defaults = array( @@ -27,7 +27,7 @@ class WPStrava_SegmentsRenderer { 'map_width' => '480', 'map_height' => '320', 'client_id' => WPStrava::get_instance()->settings->get_default_id(), - 'markers' => false, + 'markers' => true, 'image_only' => false, ); @@ -43,7 +43,7 @@ class WPStrava_SegmentsRenderer { $segment_details = null; try { - $segment_details = $segments->get_segments( $atts['client_id'], $atts['id'] ); + $segment_details = $segments->get_segment( $atts['client_id'], $atts['id'] ); } catch ( WPStrava_Exception $e ) { return $e->to_html(); } @@ -91,31 +91,38 @@ class WPStrava_SegmentsRenderer { $strava_som = WPStrava_SOM::get_som( $som ); $elevation_title = '' . __( 'Elevation Gain', 'wp-strava' ) . ''; $elevation = ' -
' . $strava_som->elevation( $segment_details->total_elevation_gain ) . '
-
' . $strava_som->get_elevation_label() . '
+
' . $strava_som->elevation( $segment_details->total_elevation_gain ) . '
+
' . $strava_som->get_elevation_label() . '
+ '; + $grade_title = '' . __( 'Avg. Grade', 'wp-strava' ) . ''; + $grade = ' +
' . $strava_som->percent( $segment_details->average_grade ) . '
+
 
'; if ( WPStrava::get_instance()->settings->hide_elevation ) { $elevation_title = ''; $elevation = ''; + $grade_title = ''; + $grade_title = ''; } return ' - +
- - + ' . $grade_title . ' ' . $elevation_title . ' + ' . $grade . ' ' . $elevation . ' diff --git a/src/blocks/segment/block.json b/src/blocks/segment/block.json new file mode 100644 index 0000000..354d783 --- /dev/null +++ b/src/blocks/segment/block.json @@ -0,0 +1,30 @@ +{ + "name": "wp-strava/segment", + "title": "Strava Segment", + "category": "embed", + "icon": "location-alt", + "description": "Embed a Strava Segment", + "keywords": [ "segment", "map" ], + "textdomain": "wp-strava", + "attributes": { + "url": { + "type": "string", + "default": "" + }, + "imageOnly": { + "type": "boolean", + "default": false + }, + "displayMarkers": { + "type": "boolean", + "default": true + }, + "som": { + "type": "string", + "default": null + } + }, + "editorScript": "file:../../../build/index.js", + "editorStyle": "file:../../../build/editor.css", + "style": "file:../../../build/style.css" +} diff --git a/src/blocks/segment/edit.js b/src/blocks/segment/edit.js new file mode 100644 index 0000000..2ce5416 --- /dev/null +++ b/src/blocks/segment/edit.js @@ -0,0 +1,125 @@ +/* global wp, wpStrava */ +import EmbedPlaceholder from '../components/embed-placeholder'; +import EmbedControls from '../components/embed-controls'; +import SOMOverride from '../components/som-override'; + +const { __ } = wp.i18n; +const { Component } = wp.element; +const { InspectorControls } = wp.editor; +const { PanelBody, ToggleControl, ServerSideRender } = wp.components; +const { isEmpty } = lodash; + +class Edit extends Component { + + constructor() { + super( ...arguments ); + this.setUrl = this.setUrl.bind( this ); + this.switchBackToURLInput = this.switchBackToURLInput.bind( this ); + this.toggleImageOnly = this.toggleImageOnly.bind( this ); + this.toggleDisplayMarkers = this.toggleDisplayMarkers.bind( this ); + this.overrideSOM = this.overrideSOM.bind( this ); + + this.state = { + url: this.props.attributes.url, + imageOnly: this.props.attributes.imageOnly, + displayMarkers: this.props.attributes.displayMarkers, + som: this.props.attributes.som, + editingURL: isEmpty( this.props.attributes.url ) ? true : false, + }; + } + + setUrl( event ) { + if ( event ) { + event.preventDefault(); + } + this.setState( { editingURL: false } ); + this.props.setAttributes( { url: this.state.url } ); + } + + switchBackToURLInput() { + this.setState( { editingURL: true } ); + } + + toggleImageOnly( checked ) { + this.setState( { imageOnly: checked } ); + this.props.setAttributes( { imageOnly: checked } ); + } + + toggleDisplayMarkers( checked ) { + this.setState( { displayMarkers: checked } ); + this.props.setAttributes( { displayMarkers: checked } ); + } + + overrideSOM( newSOM ) { + this.setState( { som: newSOM } ); + this.props.setAttributes( { som: newSOM } ); + } + + render() { + const { + url, + editingURL, + imageOnly, + displayMarkers, + som + } = this.state; + + // Newly inserted block or we've clicked the edit button. + if ( editingURL ) { + return ( + + this.setState( { url: event.target.value } ) + } + /> + ); + } + + return ( + <> + + + + + this.toggleImageOnly( checked ) } + /> + this.toggleDisplayMarkers( checked ) } + /> + + + + + ); + } +} + +export default Edit; diff --git a/src/blocks/segment/index.js b/src/blocks/segment/index.js new file mode 100644 index 0000000..70a50a1 --- /dev/null +++ b/src/blocks/segment/index.js @@ -0,0 +1,9 @@ +/* global wp, wpStrava */ +import { registerBlockType } from '@wordpress/blocks'; +import edit from './edit'; +import metadata from './block.json'; + +metadata.edit = edit; +metadata.save = () => null; + +registerBlockType( metadata.name, metadata ); diff --git a/src/index.js b/src/index.js index 056e447..0fdc131 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,4 @@ import './blocks/activity'; import './blocks/route'; import './blocks/activitieslist'; +import './blocks/segment'; diff --git a/tests/WPStrava/SOMEnglishTest.php b/tests/WPStrava/SOMEnglishTest.php index 26e3d63..c6e5a5f 100644 --- a/tests/WPStrava/SOMEnglishTest.php +++ b/tests/WPStrava/SOMEnglishTest.php @@ -107,4 +107,15 @@ class WPStrava_SOMEnglishTest extends TestCase { $this->assertEquals( '1,304', $this->som->calories( 1304 ) ); } + /** + * Test that 5.7 grade is 5.7% using both string and int inputs. + * + * @author Justin Foell + * @since 2.9.0 + */ + public function test_percent() { + $this->assertEquals( '5.7%', $this->som->percent( '5.7' ) ); + $this->assertEquals( '5.7%', $this->som->percent( 5.7 ) ); + } + }
' . __( 'Elapsed Time', 'wp-strava' ) . '' . __( 'Moving Time', 'wp-strava' ) . ' ' . __( 'Distance', 'wp-strava' ) . '
-
' . $strava_som->distance( $segment_details->distance ) . '
-
' . $strava_som->get_distance_label() . '
+
' . $strava_som->distance( $segment_details->distance ) . '
+
' . $strava_som->get_distance_label() . '