From 919e76bdef2ea2190a3873b9678add79b498dccb Mon Sep 17 00:00:00 2001 From: pewgeuges <73141620+pewgeuges@users.noreply.github.com> Date: Fri, 1 Jan 2021 05:52:49 +0000 Subject: [PATCH] development 2.3.1d0 for forum git-svn-id: https://plugins.svn.wordpress.org/footnotes/trunk@2448740 b8457f37-d9ea-0310-8a92-e5e31aec5664 --- class/dashboard/subpage-main.php | 12 +- class/settings.php | 185 +++++++++++--------- class/task.php | 51 +++++- css/public.css | 38 +++- footnotes.php | 4 +- readme.txt | 3 + templates/dashboard/settings-start-end.html | 6 +- 7 files changed, 207 insertions(+), 92 deletions(-) diff --git a/class/dashboard/subpage-main.php b/class/dashboard/subpage-main.php index 13d74c4..de48be7 100644 --- a/class/dashboard/subpage-main.php +++ b/class/dashboard/subpage-main.php @@ -36,8 +36,9 @@ * @since 2.3.0 add settings for hard links, thanks to @psykonevro and @martinneumannat 2020-12-29T1322+0100 * @see * @see + * @since 2.3.1 footnote shortcode syntax validation 2021-01-01T0624+0100 * - * Last modified: 2020-12-31T0801+0100 + * Last modified: 2021-01-01T0639+0100 */ /** @@ -371,6 +372,11 @@ class MCI_Footnotes_Layout_Settings extends MCI_Footnotes_LayoutEngine { // Custom (user-defined) start and end tags bracketing the footnote text inline: "userdefined" => __('custom short code', MCI_Footnotes_Config::C_STR_PLUGIN_NAME) ); + // options for the syntax validation: + $l_arr_Enable = array( + "yes" => __("Yes", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), + "no" => __("No", MCI_Footnotes_Config::C_STR_PLUGIN_NAME) + ); // load template file $l_obj_Template = new MCI_Footnotes_Template(MCI_Footnotes_Template::C_STR_DASHBOARD, "settings-start-end"); @@ -391,6 +397,10 @@ class MCI_Footnotes_Layout_Settings extends MCI_Footnotes_LayoutEngine { "short-code-start-user-id" => MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED, "short-code-end-user-id" => MCI_Footnotes_Settings::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED, + // option to enable syntax validation: + "label-syntax" => $this->addLabel(MCI_Footnotes_Settings::C_BOOL_FOOTNOTE_SHORTCODE_SYNTAX_VALIDATION_ENABLE, __("Check for balanced shortcodes:", MCI_Footnotes_Config::C_STR_PLUGIN_NAME)), + "syntax" => $this->addSelectBox(MCI_Footnotes_Settings::C_BOOL_FOOTNOTE_SHORTCODE_SYNTAX_VALIDATION_ENABLE, $l_arr_Enable), + "notice-syntax" => __("In the presence of an unclosed opening tag shortcode, a warning displays below the post title.", MCI_Footnotes_Config::C_STR_PLUGIN_NAME), ) ); // display template with replaced placeholders diff --git a/class/settings.php b/class/settings.php index 0d405da..9dc7fae 100644 --- a/class/settings.php +++ b/class/settings.php @@ -37,8 +37,9 @@ * @see * @since 2.3.0 swap Custom CSS migration Boolean from 'migration complete' to 'show legacy' 2020-12-27T1243+0100 * @since 2.3.0 referrers, reference container: settings for anchor slugs 2020-12-31T1429+0100 + * @since 2.3.1 footnote shortcode syntax validation 2021-01-01T0624+0100 * - * Last modified: 2020-12-31T1429+0100 + * Last modified: 2021-01-01T0624+0100 */ @@ -565,6 +566,18 @@ class MCI_Footnotes_Settings { const C_STR_FOOTNOTE_FRAGMENT_ID_SLUG = "footnotes_inputfield_footnote_fragment_id_slug"; const C_STR_HARD_LINK_IDS_SEPARATOR = "footnotes_inputfield_hard_link_ids_separator"; + /** + * Settings container key for shortcode syntax validation + * + * @since 2.3.1 + * @var bool + * + * 2021-01-01T0616+0100 + */ + const C_BOOL_FOOTNOTE_SHORTCODE_SYNTAX_VALIDATION_ENABLE = "footnotes_inputfield_shortcode_syntax_validation_enable"; + + + /** * SETTINGS STORAGE */ @@ -613,128 +626,130 @@ class MCI_Footnotes_Settings { "footnotes_storage" => array( - self::C_STR_FOOTNOTES_SHORT_CODE_START => '((', - self::C_STR_FOOTNOTES_SHORT_CODE_END => '))', - self::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED => '', - self::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED => '', + self::C_STR_FOOTNOTES_SHORT_CODE_START => '((', + self::C_STR_FOOTNOTES_SHORT_CODE_END => '))', + self::C_STR_FOOTNOTES_SHORT_CODE_START_USER_DEFINED => '', + self::C_STR_FOOTNOTES_SHORT_CODE_END_USER_DEFINED => '', + + self::C_BOOL_FOOTNOTE_SHORTCODE_SYNTAX_VALIDATION_ENABLE => 'yes', - self::C_STR_FOOTNOTES_COUNTER_STYLE => 'arabic_plain', - self::C_BOOL_COMBINE_IDENTICAL_FOOTNOTES => 'yes', + self::C_STR_FOOTNOTES_COUNTER_STYLE => 'arabic_plain', + self::C_BOOL_COMBINE_IDENTICAL_FOOTNOTES => 'yes', - self::C_BOOL_FOOTNOTES_HARD_LINKS_ENABLE => 'no', - self::C_STR_REFERRER_FRAGMENT_ID_SLUG => 'r', - self::C_STR_FOOTNOTE_FRAGMENT_ID_SLUG => 'f', - self::C_STR_HARD_LINK_IDS_SEPARATOR => '+', - self::C_INT_FOOTNOTES_SCROLL_OFFSET => 20, - self::C_INT_FOOTNOTES_SCROLL_DURATION => 380, + self::C_BOOL_FOOTNOTES_HARD_LINKS_ENABLE => 'no', + self::C_STR_REFERRER_FRAGMENT_ID_SLUG => 'r', + self::C_STR_FOOTNOTE_FRAGMENT_ID_SLUG => 'f', + self::C_STR_HARD_LINK_IDS_SEPARATOR => '+', + self::C_INT_FOOTNOTES_SCROLL_OFFSET => 20, + self::C_INT_FOOTNOTES_SCROLL_DURATION => 380, - self::C_STR_REFERENCE_CONTAINER_NAME => 'References', - self::C_STR_REFERENCE_CONTAINER_LABEL_ELEMENT => 'p', - self::C_BOOL_REFERENCE_CONTAINER_LABEL_BOTTOM_BORDER => 'yes', - self::C_BOOL_REFERENCE_CONTAINER_COLLAPSE => 'no', + self::C_STR_REFERENCE_CONTAINER_NAME => 'References', + self::C_STR_REFERENCE_CONTAINER_LABEL_ELEMENT => 'p', + self::C_BOOL_REFERENCE_CONTAINER_LABEL_BOTTOM_BORDER => 'yes', + self::C_BOOL_REFERENCE_CONTAINER_COLLAPSE => 'no', - self::C_STR_REFERENCE_CONTAINER_POSITION => 'post_end', - self::C_STR_REFERENCE_CONTAINER_POSITION_SHORTCODE => '[[references]]', - self::C_BOOL_REFERENCE_CONTAINER_START_PAGE_ENABLE => 'yes', + self::C_STR_REFERENCE_CONTAINER_POSITION => 'post_end', + self::C_STR_REFERENCE_CONTAINER_POSITION_SHORTCODE => '[[references]]', + self::C_BOOL_REFERENCE_CONTAINER_START_PAGE_ENABLE => 'yes', // whether to enqueue additional style sheet: - self::C_STR_FOOTNOTES_PAGE_LAYOUT_SUPPORT => 'none', + self::C_STR_FOOTNOTES_PAGE_LAYOUT_SUPPORT => 'none', // top and bottom margins: - self::C_INT_REFERENCE_CONTAINER_TOP_MARGIN => 24, - self::C_INT_REFERENCE_CONTAINER_BOTTOM_MARGIN => 0, + self::C_INT_REFERENCE_CONTAINER_TOP_MARGIN => 24, + self::C_INT_REFERENCE_CONTAINER_BOTTOM_MARGIN => 0, // table cell borders: - self::C_BOOL_REFERENCE_CONTAINER_ROW_BORDERS_ENABLE => 'no', + self::C_BOOL_REFERENCE_CONTAINER_ROW_BORDERS_ENABLE => 'no', // backlink symbol: - self::C_BOOL_REFERENCE_CONTAINER_3COLUMN_LAYOUT_ENABLE => 'no', - self::C_BOOL_REFERENCE_CONTAINER_BACKLINK_SYMBOL_ENABLE => 'yes', - self::C_BOOL_REFERENCE_CONTAINER_BACKLINK_SYMBOL_SWITCH => 'no', + self::C_BOOL_REFERENCE_CONTAINER_3COLUMN_LAYOUT_ENABLE => 'no', + self::C_BOOL_REFERENCE_CONTAINER_BACKLINK_SYMBOL_ENABLE => 'yes', + self::C_BOOL_REFERENCE_CONTAINER_BACKLINK_SYMBOL_SWITCH => 'no', // backlink separators and terminators are often not preferred. // but a choice must be provided along with the ability to customize: - self::C_BOOL_BACKLINKS_SEPARATOR_ENABLED => 'yes', - self::C_STR_BACKLINKS_SEPARATOR_OPTION => 'comma', - self::C_STR_BACKLINKS_SEPARATOR_CUSTOM => '', - self::C_BOOL_BACKLINKS_TERMINATOR_ENABLED => 'no', - self::C_STR_BACKLINKS_TERMINATOR_OPTION => 'full_stop', - self::C_STR_BACKLINKS_TERMINATOR_CUSTOM => '', + self::C_BOOL_BACKLINKS_SEPARATOR_ENABLED => 'yes', + self::C_STR_BACKLINKS_SEPARATOR_OPTION => 'comma', + self::C_STR_BACKLINKS_SEPARATOR_CUSTOM => '', + self::C_BOOL_BACKLINKS_TERMINATOR_ENABLED => 'no', + self::C_STR_BACKLINKS_TERMINATOR_OPTION => 'full_stop', + self::C_STR_BACKLINKS_TERMINATOR_CUSTOM => '', // set backlinks column width: - self::C_BOOL_BACKLINKS_COLUMN_WIDTH_ENABLED => 'no', - self::C_INT_BACKLINKS_COLUMN_WIDTH_SCALAR => '50', - self::C_STR_BACKLINKS_COLUMN_WIDTH_UNIT => 'px', + self::C_BOOL_BACKLINKS_COLUMN_WIDTH_ENABLED => 'no', + self::C_INT_BACKLINKS_COLUMN_WIDTH_SCALAR => '50', + self::C_STR_BACKLINKS_COLUMN_WIDTH_UNIT => 'px', // set backlinks column max width: - self::C_BOOL_BACKLINKS_COLUMN_MAX_WIDTH_ENABLED => 'no', - self::C_INT_BACKLINKS_COLUMN_MAX_WIDTH_SCALAR => '140', - self::C_STR_BACKLINKS_COLUMN_MAX_WIDTH_UNIT => 'px', + self::C_BOOL_BACKLINKS_COLUMN_MAX_WIDTH_ENABLED => 'no', + self::C_INT_BACKLINKS_COLUMN_MAX_WIDTH_SCALAR => '140', + self::C_STR_BACKLINKS_COLUMN_MAX_WIDTH_UNIT => 'px', // whether a
tag is inserted: - self::C_BOOL_BACKLINKS_LINE_BREAKS_ENABLED => 'no', + self::C_BOOL_BACKLINKS_LINE_BREAKS_ENABLED => 'no', // whether to enable URL line wrapping: - self::C_BOOL_FOOTNOTE_URL_WRAP_ENABLED => 'yes', + self::C_BOOL_FOOTNOTE_URL_WRAP_ENABLED => 'yes', // whether to use link elements: - self::C_BOOL_LINK_ELEMENT_ENABLED => 'yes', + self::C_BOOL_LINK_ELEMENT_ENABLED => 'yes', // excerpt should be disabled: - self::C_BOOL_FOOTNOTES_IN_EXCERPT => 'no', + self::C_BOOL_FOOTNOTES_IN_EXCERPT => 'no', // since removal of the_post hook, expert mode is no danger zone // not for experts only; raising awareness about relative positioning // changed default to 'yes': - self::C_BOOL_FOOTNOTES_EXPERT_MODE => 'yes', + self::C_BOOL_FOOTNOTES_EXPERT_MODE => 'yes', - self::C_STR_FOOTNOTES_LOVE => 'no', + self::C_STR_FOOTNOTES_LOVE => 'no', ), "footnotes_storage_custom" => array( - self::C_STR_HYPERLINK_ARROW => '↑', - self::C_STR_HYPERLINK_ARROW_USER_DEFINED => '', + self::C_STR_HYPERLINK_ARROW => '↑', + self::C_STR_HYPERLINK_ARROW_USER_DEFINED => '', - self::C_STR_FOOTNOTES_TOOLTIP_READON_LABEL => 'Continue reading', + self::C_STR_FOOTNOTES_TOOLTIP_READON_LABEL => 'Continue reading', - self::C_BOOL_FOOTNOTES_REFERRER_SUPERSCRIPT_TAGS => 'yes', + self::C_BOOL_FOOTNOTES_REFERRER_SUPERSCRIPT_TAGS => 'yes', // The default footnote referrer surroundings should be square brackets: // * with respect to baseline footnote referrers new option; // * as in English or US American typesetting; // * for better UX thanks to a more button-like appearance; // * for stylistic consistency with the expand-collapse button; - self::C_STR_FOOTNOTES_STYLING_BEFORE => '[', - self::C_STR_FOOTNOTES_STYLING_AFTER => ']', + self::C_STR_FOOTNOTES_STYLING_BEFORE => '[', + self::C_STR_FOOTNOTES_STYLING_AFTER => ']', - self::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ENABLED => 'yes', + self::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ENABLED => 'yes', // alternative, low-script tooltips using CSS for transitions // in response to user demand for website with jQuery UI outage - self::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ALTERNATIVE => 'no', + self::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ALTERNATIVE => 'no', // The mouse over content truncation should be enabled by default // to raise awareness of the functionality and to prevent the screen // from being filled at mouse-over, and to allow the Continue reading: - self::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_ENABLED => 'yes', + self::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_ENABLED => 'yes', // The truncation length is raised from 150 to 200 chars: - self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_LENGTH => 200, + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_EXCERPT_LENGTH => 200, // The default position should not be lateral because of the risk // the box gets squeezed between note anchor at line end and window edge, // and top because reading at the bottom of the window is more likely: - self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_POSITION => 'top center', + self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_POSITION => 'top center', - self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_X => 0, + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_X => 0, // The vertical offset must be negative for the box not to cover // the current line of text (web coordinates origin is top left): - self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_Y => -7, + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_OFFSET_Y => -7, // The width should be limited to start with, for the box to have shape: - self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_MAX_WIDTH => 450, + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_MAX_WIDTH => 450, // fixed width is for alternative tooltips, cannot reuse max-width nor offsets: self::C_STR_FOOTNOTES_ALTERNATIVE_MOUSE_OVER_BOX_POSITION => 'top right', @@ -744,33 +759,33 @@ class MCI_Footnotes_Settings { // tooltip display durations: // called mouse over box not tooltip for consistency - self::C_INT_MOUSE_OVER_BOX_FADE_IN_DELAY => 0, - self::C_INT_MOUSE_OVER_BOX_FADE_IN_DURATION => 200, - self::C_INT_MOUSE_OVER_BOX_FADE_OUT_DELAY => 400, - self::C_INT_MOUSE_OVER_BOX_FADE_OUT_DURATION => 200, + self::C_INT_MOUSE_OVER_BOX_FADE_IN_DELAY => 0, + self::C_INT_MOUSE_OVER_BOX_FADE_IN_DURATION => 200, + self::C_INT_MOUSE_OVER_BOX_FADE_OUT_DELAY => 400, + self::C_INT_MOUSE_OVER_BOX_FADE_OUT_DURATION => 200, // tooltip font size reset to legacy by default since 2.1.4; // was set to inherit since 2.1.1 as it overrode custom CSS, // is moved to settings since 2.1.4 2020-12-04T1023+0100 - self::C_BOOL_MOUSE_OVER_BOX_FONT_SIZE_ENABLED => 'yes', - self::C_FLO_MOUSE_OVER_BOX_FONT_SIZE_SCALAR => 13, - self::C_STR_MOUSE_OVER_BOX_FONT_SIZE_UNIT => 'px', + self::C_BOOL_MOUSE_OVER_BOX_FONT_SIZE_ENABLED => 'yes', + self::C_FLO_MOUSE_OVER_BOX_FONT_SIZE_SCALAR => 13, + self::C_STR_MOUSE_OVER_BOX_FONT_SIZE_UNIT => 'px', - self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_COLOR => '', + self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_COLOR => '', // The mouse over box shouldn’t feature a colored background // by default, due to diverging user preferences. White is neutral: - self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BACKGROUND => '#ffffff', + self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BACKGROUND => '#ffffff', - self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_WIDTH => 1, - self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BORDER_COLOR => '#cccc99', + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_WIDTH => 1, + self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_BORDER_COLOR => '#cccc99', // The mouse over box corners mustn’t be rounded as that is outdated: - self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_RADIUS => 0, + self::C_INT_FOOTNOTES_MOUSE_OVER_BOX_BORDER_RADIUS => 0, - self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_SHADOW_COLOR => '#666666', + self::C_STR_FOOTNOTES_MOUSE_OVER_BOX_SHADOW_COLOR => '#666666', // Custom CSS migrates to a dedicated tab: - self::C_STR_CUSTOM_CSS => '', + self::C_STR_CUSTOM_CSS => '', ), @@ -782,45 +797,45 @@ class MCI_Footnotes_Settings { // thinking at first that the feature is broken in post titles. // See // Yet in titles, footnotes are functionally pointless in WordPress. - self::C_BOOL_EXPERT_LOOKUP_THE_TITLE => '', + self::C_BOOL_EXPERT_LOOKUP_THE_TITLE => '', // This is the only useful one: - self::C_BOOL_EXPERT_LOOKUP_THE_CONTENT => 'checked', + self::C_BOOL_EXPERT_LOOKUP_THE_CONTENT => 'checked', // And the_excerpt is disabled by default following @nikelaos in // // - self::C_BOOL_EXPERT_LOOKUP_THE_EXCERPT => '', + self::C_BOOL_EXPERT_LOOKUP_THE_EXCERPT => '', - self::C_BOOL_EXPERT_LOOKUP_WIDGET_TITLE => '', + self::C_BOOL_EXPERT_LOOKUP_WIDGET_TITLE => '', // The widget_text hook must be disabled, because a footnotes container is inserted // at the bottom of each widget, but multiple containers in a page are not disambiguated. // E.g. enabling this causes issues with footnotes in Elementor accordions. - self::C_BOOL_EXPERT_LOOKUP_WIDGET_TEXT => '', + self::C_BOOL_EXPERT_LOOKUP_WIDGET_TEXT => '', // initially hard-coded default // shows "9223372036854780000" instead of 9223372036854775807 in the numbox // empty should be interpreted as PHP_INT_MAX, but a numbox cannot be set to empty: // // interpret -1 as PHP_INT_MAX instead - self::C_INT_EXPERT_LOOKUP_THE_TITLE_PRIORITY_LEVEL => PHP_INT_MAX, + self::C_INT_EXPERT_LOOKUP_THE_TITLE_PRIORITY_LEVEL => PHP_INT_MAX, // Priority level of the_content and of widget_text as the only relevant // hooks must be less than 99 because social buttons may yield scripts // that contain the strings '((' and '))', i.e. the default footnote // start and end short codes, causing issues with fake footnotes. - self::C_INT_EXPERT_LOOKUP_THE_CONTENT_PRIORITY_LEVEL => 98, - self::C_INT_EXPERT_LOOKUP_THE_EXCERPT_PRIORITY_LEVEL => PHP_INT_MAX, - self::C_INT_EXPERT_LOOKUP_WIDGET_TITLE_PRIORITY_LEVEL => PHP_INT_MAX, - self::C_INT_EXPERT_LOOKUP_WIDGET_TEXT_PRIORITY_LEVEL => 98, + self::C_INT_EXPERT_LOOKUP_THE_CONTENT_PRIORITY_LEVEL => 98, + self::C_INT_EXPERT_LOOKUP_THE_EXCERPT_PRIORITY_LEVEL => PHP_INT_MAX, + self::C_INT_EXPERT_LOOKUP_WIDGET_TITLE_PRIORITY_LEVEL => PHP_INT_MAX, + self::C_INT_EXPERT_LOOKUP_WIDGET_TEXT_PRIORITY_LEVEL => 98, ), "footnotes_storage_custom_css" => array( - self::C_BOOL_CUSTOM_CSS_LEGACY_ENABLE => 'yes', - self::C_STR_CUSTOM_CSS_NEW => '', + self::C_BOOL_CUSTOM_CSS_LEGACY_ENABLE => 'yes', + self::C_STR_CUSTOM_CSS_NEW => '', ), diff --git a/class/task.php b/class/task.php index 9b5e541..9fb9d2c 100644 --- a/class/task.php +++ b/class/task.php @@ -64,8 +64,9 @@ * @see * @see * @since 2.3.0 swap Custom CSS migration Boolean from 'migration complete' to 'show legacy' 2020-12-27T1243+0100 + * @since 2.3.1 syntax validation for balanced footnote start and end tags 2021-01-01T0227+0100 * - * Last modified: 2020-12-31T1234+0100 + * Last modified: 2021-01-01T0642+0100 */ // If called directly, abort: @@ -196,6 +197,24 @@ class MCI_Footnotes_Task { public static $l_str_LinkOpenTag = ''; public static $l_str_LinkCloseTag = ''; + /** + * SYNTAX VALIDATION + * + * This part of the algorithm first checks for balanced footnote opening and closing tag + * short codes. The first encountered error triggers the display of a warning below the + * post title and cancellation of further parsing. + * + * Unbalanced short codes have caused significant trouble because they are hard to detect. + * Any compiler or other tool reports syntax errors in the first place. Footnotes’ exception + * is considered a design flaw, and the feature is released as a bug fix after overdue 2.3.0 + * released in urgency to provide AMP compat before 2021. + * + * @since 2.3.1 + * @var bool + */ + public static $l_bool_SyntaxErrorFlag = false; + public static $l_bool_SyntaxErrorShow = true; + /** @@ -753,11 +772,41 @@ class MCI_Footnotes_Task { $l_str_StartingTag = htmlspecialchars($l_str_StartingTag); $l_str_EndingTag = htmlspecialchars($l_str_EndingTag); } + // if footnotes short code is empty, return the content without changes if (empty($l_str_StartingTag) || empty($l_str_EndingTag)) { return $p_str_Content; } + // if footnotes short codes are unbalanced, and syntax validation is not disabled, + // return content with prepended warning: + if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTE_SHORTCODE_SYNTAX_VALIDATION_ENABLE))) { + $l_str_StartTagRegex = preg_replace( '#([\(\)\{\}\[\]\*\.\?\!])#', '\\\\$1', $l_str_StartingTag ); + $l_str_EndTagRegex = preg_replace( '#([\(\)\{\}\[\]\*\.\?\!])#', '\\\\$1', $l_str_EndingTag ); + $l_str_ValidationRegex = '#' . $l_str_StartTagRegex . '(((?!' . $l_str_EndTagRegex . ').)*?)(' . $l_str_StartTagRegex . '|$)#s'; + preg_match( $l_str_ValidationRegex, $p_str_Content, $p_arr_ErrorLocation ); + if ( empty( $p_arr_ErrorLocation ) ) { + self::$l_bool_SyntaxErrorShow = false; + } + + // prevent generating and inserting the warning multiple times: + if ( self::$l_bool_SyntaxErrorShow ) { + $l_str_ErrorSpotString = strip_tags($p_arr_ErrorLocation[1]); + + $l_str_SyntaxErrorWarning = '

'; + $l_str_SyntaxErrorWarning .= 'WARNING: unbalanced footnote start tag short code before:'; + $l_str_SyntaxErrorWarning .= '

“'; + $l_str_SyntaxErrorWarning .= $l_str_ErrorSpotString; + $l_str_SyntaxErrorWarning .= '”

'; + + $p_str_Content = $l_str_SyntaxErrorWarning . $p_str_Content; + self::$l_bool_SyntaxErrorShow = false; + + return $p_str_Content; + } + } + + // load referrer templates if footnotes text not hidden: if (!$p_bool_HideFootnotesText) { // load two template files: if (MCI_Footnotes_Convert::toBool(MCI_Footnotes_Settings::instance()->get(MCI_Footnotes_Settings::C_BOOL_FOOTNOTES_MOUSE_OVER_BOX_ALTERNATIVE))) { diff --git a/css/public.css b/css/public.css index fd80797..7233a76 100755 --- a/css/public.css +++ b/css/public.css @@ -5,7 +5,7 @@ * Created-Time: 16:21 * Since: 1.0 * - * Version: 2.3.0 + * Version: 2.3.1 * * Classes added to public.css may be added to the * list documenting CSS classes for Custom CSS if @@ -20,8 +20,9 @@ * @since 2.1.6 set z-index to maximum 2147483647 to address display issues with overlay content, thanks to @russianicons * @see * @since 2.3.0 offset anchors for optional hard links + * @since 2.3.1 validation error warning box * - * Last modified: 2020-12-31T1211+0100 + * Last modified: 2021-01-01T0642+0100 */ @@ -51,6 +52,39 @@ css/settings.css color: #545f5a; } +/***************************************************** +Validation error warning displayed below post title + +The presence of unbalanced footnote start short codes +significantly alters the post display and may cause an +issue with missing content or footnotes, while it may +be hard to detect in long posts and under deadline. + +A validation check displays a warning box below the +post title, populated with the first instance of a +content snippet preceded by an unbalanced start tag +short code. + +@since 2.3.1 +*/ + +.footnotes_validation_error { + border: 4px solid red; + padding: 20px; + background: #ff000055; +} + +.footnotes_validation_error p:first-child { + font-size: 20px; + font-weight: bold; + text-align: center; +} + +.footnotes_validation_error p:last-child { + font-size: 12px; + text-align: start; +} + /***************************************************** Long URLs in Unicode-non-compliant user agents diff --git a/footnotes.php b/footnotes.php index 9e84d27..026b14e 100755 --- a/footnotes.php +++ b/footnotes.php @@ -4,12 +4,12 @@ Plugin URI: https://wordpress.org/plugins/footnotes/ Description: time to bring footnotes to your website! footnotes are known from offline publishing and everybody takes them for granted when reading a magazine. Author: Mark Cheret - Version: 2.3.0 + Version: 2.3.1d0 Author URI: http://cheret.de/plugins/footnotes-2/ Text Domain: footnotes Domain Path: /languages */ -define( 'FOOTNOTES_VERSION', '2.3.0' ); +define( 'FOOTNOTES_VERSION', '2.3.1d0' ); /* Copyright 2020 Mark Cheret (email: mark@cheret.de) diff --git a/readme.txt b/readme.txt index 56cb6f8..65180e6 100755 --- a/readme.txt +++ b/readme.txt @@ -80,6 +80,9 @@ Visit this swift write-up from a **footnotes** user by the name of **Southwest** == Changelog == += 2.3.1 = +- Bugfix: Shortcodes: syntax validation for balanced footnote start and end tag short codes + = 2.3.0 = - Add: optional hard links in referrers and backlinks for AMP compatibility, thanks to @psykonevro and @martinneumannat - Bugfix: Reference container: convert top padding to margin and make it a setting, thanks to @hamshe diff --git a/templates/dashboard/settings-start-end.html b/templates/dashboard/settings-start-end.html index 6044c0d..2eddf35 100644 --- a/templates/dashboard/settings-start-end.html +++ b/templates/dashboard/settings-start-end.html @@ -1,4 +1,4 @@ - +
@@ -14,6 +14,10 @@ [[short-code-end-user]] + + + +
[[label-short-code-start]]
[[label-syntax]][[syntax]] [[notice-syntax]]