Plugin Directory

Changeset 3335244


Ignore:
Timestamp:
07/28/2025 09:52:22 AM (7 months ago)
Author:
daext
Message:

Committing and tagging 1.22

Location:
ultimate-markdown
Files:
12 edited
1 copied

Legend:

Unmodified
Added
Removed
  • ultimate-markdown/tags/1.22/admin/inc/class-daextulma-front-matter.php

    r3326195 r3335244  
    252252
    253253    /**
    254      * If the date is valid returns it, otherwise returns null.
    255      *
    256      * @param string $date A date in 'Y-m-d h:i:s' format.
     254     * If the date is valid, returns it as a string in 'Y-m-d H:i:s' format. Otherwise returns null.
     255     *
     256     * @param mixed $date
    257257     *
    258258     * @return string|null
     
    264264        }
    265265
    266         if ( !is_numeric( $date ) || (int) $date != $date ) {
     266        /**
     267         * The FrontYAML parser (Mni\FrontYAML\Parser::getYAML()) behaves inconsistently
     268         * when parsing the `date` field:
     269         *
     270         * - If the date is written as an unquoted string like `date: 2025-07-25 10:06:15`,
     271         *   the parser automatically converts it into a UNIX timestamp (integer).
     272         *
     273         * - If the date is written as a quoted string like `date: '2025-07-25 10:06:15'`,
     274         *   the parser preserves it as a plain string.
     275         *
     276         * This inconsistency requires preprocessing to ensure all dates are normalized
     277         * to the 'Y-m-d H:i:s' string format.
     278         */
     279
     280        // If it's a DateTime object (less common, but possible), format it to string.
     281        if ( $date instanceof DateTimeInterface ) {
     282            $date = $date->format( 'Y-m-d H:i:s' );
     283        }
     284
     285        // If it's a numeric UNIX timestamp (due to unquoted YAML date), convert to string format.
     286        elseif ( is_numeric( $date ) && (int) $date == $date ) {
     287            $date = gmdate( 'Y-m-d H:i:s', (int) $date );
     288        }
     289
     290        // At this point, we expect $date to be a string in 'Y-m-d H:i:s' format.
     291        if ( !is_string( $date ) ) {
    267292            throw new Exception( 'invalid_date_format' );
    268293        }
    269294
    270         /**
    271          * Note that the FrontYaml convert the date available in the string in the 'Y-m-d h:i:s' format to a unix date.
    272          * As a consequence, the date here is reconverted to the 'Y-m-d h:i:s' format with the PHP date() function.
    273          */
    274         $date = gmdate( 'Y-m-d h:i:s', $date );
    275 
    276         // Validate the date with a regex.
    277         $date_regex = '/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\s([0-6][0-9]|[0-9]):([0-6][0-9]|[0-9]):([0-6][0-9]|[0-9])$/';
    278         if ( preg_match( $date_regex, $date ) ) {
    279             $date = $date;
    280         } else {
    281             $date = null;
     295        // Validate the final date string format using a strict 24-hour regex.
     296        $date_regex = '/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\s([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$/';
     297
     298        if ( !preg_match( $date_regex, $date ) ) {
     299            return null;
    282300        }
    283301
  • ultimate-markdown/tags/1.22/blocks/build/index.js

    r3326195 r3335244  
    1 !function(){"use strict";var t=window.wp.element;function e(t,e){const{dispatch:a,select:o}=wp.data;wp.data.dispatch("core/block-editor").insertBlocks(t),wp.data.dispatch("core/block-editor").clearSelectedBlock(),wp.data.dispatch("core/edit-post").openGeneralSidebar("edit-post/document"),null!==e.title&&wp.data.dispatch("core/editor").editPost({title:e.title}),null!==e.excerpt&&wp.data.dispatch("core/editor").editPost({excerpt:e.excerpt}),null!==e.categories&&e.categories.forEach((t=>{!function(t){const{dispatch:e,select:a}=wp.data;let o=a("core/editor").getEditedPostAttribute("categories"),r=a("core/edit-post").isEditorPanelOpened("taxonomy-panel-category");o.includes(t)||(o.push(t),e("core/editor").editPost({categories:o}),r&&(e("core/edit-post").toggleEditorPanelOpened("taxonomy-panel-category"),e("core/edit-post").toggleEditorPanelOpened("taxonomy-panel-category")))}(t)})),null!==e.tags&&e.tags.forEach((t=>{!function(t){const{dispatch:e,select:a}=wp.data;let o=a("core/editor").getEditedPostAttribute("tags"),r=a("core/edit-post").isEditorPanelOpened("taxonomy-panel-tags");o.includes(t)||(o.push(t),e("core/editor").editPost({tags:o}),r&&(e("core/edit-post").toggleEditorPanelOpened("taxonomy-panel-tags"),e("core/edit-post").toggleEditorPanelOpened("taxonomy-panel-tags")))}(t)})),null!==e.author&&wp.data.dispatch("core/editor").editPost({author:e.author}),null!==e.date&&wp.data.dispatch("core/editor").editPost({date:e.date}),null!==e.status&&wp.data.dispatch("core/editor").editPost({status:e.status})}const{PluginDocumentSettingPanel:a}=wp.editor,{Component:o}=wp.element,{__:__}=wp.i18n,{FormFileUpload:r}=wp.components,{registerPlugin:n}=wp.plugins;n("daextulma-import-document",{icon:!1,render:class extends o{render(){return(0,t.createElement)(a,{name:"daextulma-import-document",title:__("Import Markdown","ultimate-markdown")},(0,t.createElement)(r,{className:"block-library-gallery-add-item-button",onChange:()=>{const t=event.target.files[0],a=new FormData;a.append("action","daextulma_import_document"),a.append("security",window.DAEXTULMA_PARAMETERS.nonce),a.append("uploaded_file",t),fetch(window.DAEXTULMA_PARAMETERS.ajaxUrl,{method:"POST",body:a}).then((function(t){return t.json()})).then((function(t){const a={invalid_date_format:__("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:__("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},o=a[t.data.error]||a.generic_error;if(t.data.error)return void wp.data.dispatch("core/notices").createErrorNotice(o,{type:"snackbar",isDismissible:!0});let r="";r="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.data.content):t.data.html_content,r=DOMPurify.sanitize(r,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:r}),t.data),wp.data.dispatch("core/notices").createErrorNotice(__("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})}))},accept:".md,.markdown,.mdown,.mkdn,.mkd,.mdwn,.mdtxt,.mdtext,.text,.txt",icon:"insert",__next40pxDefaultSize:!0},__("Upload file and import","ultimate-markdown")))}}});const{dispatch:d,select:i}=wp.data,{PluginDocumentSettingPanel:s}=wp.editor,{Component:c}=wp.element,{__:l}=wp.i18n,{Button:m,SelectControl:p}=wp.components,{registerPlugin:u}=wp.plugins;u("daextulma-load-document",{icon:!1,render:class extends c{constructor(t){super(...arguments),this.state={documentIdSelectorValue:""}}render(){const a=i("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_load_document_selector;return(0,t.createElement)(s,{name:"daextulma-load-document",title:l("Load Markdown","ultimate-markdown"),className:"daextulma-load-document-panel"},(0,t.createElement)(p,{label:l("Markdown document","ultimate-markdown"),help:l("Select a Markdown document, then click the submit document button to generate the corresponding blocks.","ultimate-markdown"),value:a,onChange:t=>{d("core/editor").editPost({meta:{_import_markdown_pro_load_document_selector:t}}),this.setState({documentIdSelectorValue:t})},options:window.DAEXTULMA_PARAMETERS.documents,__nextHasNoMarginBottom:!0,__next40pxDefaultSize:!0}),(0,t.createElement)(m,{variant:"secondary",className:"editor-post-trash is-destructive",onClick:()=>{const t=i("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_load_document_selector;if(0===parseInt(t,10))return;const a=new FormData;a.append("action","daextulma_load_document"),a.append("security",window.DAEXTULMA_PARAMETERS.nonce),a.append("document_id",t),fetch(window.DAEXTULMA_PARAMETERS.ajaxUrl,{method:"POST",body:a}).then((t=>t.json())).then((t=>{const a={invalid_date_format:l("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:l("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},o=a[t.data.error]||a.generic_error;if(t.data.error)return void wp.data.dispatch("core/notices").createErrorNotice(o,{type:"snackbar",isDismissible:!0});let r="";r="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.data.content):t.data.html_content,r=DOMPurify.sanitize(r,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:r}),t.data),d("core/editor").editPost({meta:{_import_markdown_pro_load_document_selector:"0"}}),this.setState({documentIdSelectorValue:"0"}),wp.data.dispatch("core/notices").createErrorNotice(l("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})}))}},l("Submit document","ultimate-markdown")))}}});const{Button:w,TextareaControl:_}=wp.components,{dispatch:k,select:g}=wp.data,{PluginDocumentSettingPanel:h}=wp.editor,{Component:E}=wp.element,{__:P}=wp.i18n,{registerPlugin:b}=wp.plugins;b("submit-text",{icon:!1,render:class extends E{constructor(t){super(...arguments),this.state={textareaValue:""}}render(){const a=g("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_submit_text_textarea;return(0,t.createElement)(h,{name:"submit-text",title:P("Submit Markdown","ultimate-markdown"),className:"daextulma-submit-text-panel"},(0,t.createElement)(_,{label:P("Markdown text","ultimate-markdown"),help:P("Enter the Markdown text, then click the submit text button to generate the corresponding blocks.","ultimate-markdown"),value:a,onChange:t=>{k("core/editor").editPost({meta:{_import_markdown_pro_submit_text_textarea:t}}),this.setState({textareaValue:t})},__nextHasNoMarginBottom:!0}),(0,t.createElement)(w,{variant:"secondary",className:"editor-post-trash is-destructive",onClick:()=>{wp.ajax.post("daextulma_submit_markdown",{security:window.DAEXTULMA_PARAMETERS.nonce,markdowntext:this.state.textareaValue}).done((t=>{let a="";a="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.content):t.html_content,a=DOMPurify.sanitize(a,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:a}),t),k("core/editor").editPost({meta:{_import_markdown_pro_submit_text_textarea:""}}),this.setState({textareaValue:""}),wp.data.dispatch("core/notices").createErrorNotice(P("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})})).fail((t=>{const e={invalid_date_format:P("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:P("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},a=e[t.error]||e.generic_error;wp.data.dispatch("core/notices").createErrorNotice(a,{type:"snackbar",isDismissible:!0})}))}},P("Submit text","ultimate-markdown")))}}})}();
     1!function(){"use strict";var t=window.wp.element;function e(t,e){const{dispatch:a,select:o}=wp.data;wp.data.dispatch("core/block-editor").insertBlocks(t),wp.data.dispatch("core/block-editor").clearSelectedBlock(),wp.data.dispatch("core/edit-post").openGeneralSidebar("edit-post/document"),null!==e.title&&wp.data.dispatch("core/editor").editPost({title:e.title}),null!==e.excerpt&&wp.data.dispatch("core/editor").editPost({excerpt:e.excerpt}),null!==e.categories&&a("core/editor").editPost({categories:e.categories}),null!==e.tags&&a("core/editor").editPost({tags:e.tags}),null!==e.author&&wp.data.dispatch("core/editor").editPost({author:e.author}),null!==e.date&&wp.data.dispatch("core/editor").editPost({date:e.date}),null!==e.status&&wp.data.dispatch("core/editor").editPost({status:e.status})}const{PluginDocumentSettingPanel:a}=wp.editor,{Component:o}=wp.element,{__:__}=wp.i18n,{FormFileUpload:r}=wp.components,{registerPlugin:n}=wp.plugins;n("daextulma-import-document",{icon:!1,render:class extends o{render(){return(0,t.createElement)(a,{name:"daextulma-import-document",title:__("Import Markdown","ultimate-markdown")},(0,t.createElement)(r,{className:"block-library-gallery-add-item-button",onChange:()=>{const t=event.target.files[0],a=new FormData;a.append("action","daextulma_import_document"),a.append("security",window.DAEXTULMA_PARAMETERS.nonce),a.append("uploaded_file",t),fetch(window.DAEXTULMA_PARAMETERS.ajaxUrl,{method:"POST",body:a}).then((function(t){return t.json()})).then((function(t){const a={invalid_date_format:__("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:__("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},o=a[t.data.error]||a.generic_error;if(t.data.error)return void wp.data.dispatch("core/notices").createErrorNotice(o,{type:"snackbar",isDismissible:!0});let r="";r="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.data.content):t.data.html_content,r=DOMPurify.sanitize(r,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:r}),t.data),wp.data.dispatch("core/notices").createErrorNotice(__("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})}))},accept:".md,.markdown,.mdown,.mkdn,.mkd,.mdwn,.mdtxt,.mdtext,.text,.txt",icon:"insert",__next40pxDefaultSize:!0},__("Upload file and import","ultimate-markdown")))}}});const{dispatch:d,select:i}=wp.data,{PluginDocumentSettingPanel:s}=wp.editor,{Component:c}=wp.element,{__:l}=wp.i18n,{Button:m,SelectControl:u}=wp.components,{registerPlugin:p}=wp.plugins;p("daextulma-load-document",{icon:!1,render:class extends c{constructor(t){super(...arguments),this.state={documentIdSelectorValue:""}}render(){const a=i("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_load_document_selector;return(0,t.createElement)(s,{name:"daextulma-load-document",title:l("Load Markdown","ultimate-markdown"),className:"daextulma-load-document-panel"},(0,t.createElement)(u,{label:l("Markdown document","ultimate-markdown"),help:l("Select a Markdown document, then click the submit document button to generate the corresponding blocks.","ultimate-markdown"),value:a,onChange:t=>{d("core/editor").editPost({meta:{_import_markdown_pro_load_document_selector:t}}),this.setState({documentIdSelectorValue:t})},options:window.DAEXTULMA_PARAMETERS.documents,__nextHasNoMarginBottom:!0,__next40pxDefaultSize:!0}),(0,t.createElement)(m,{variant:"secondary",className:"editor-post-trash is-destructive",onClick:()=>{const t=i("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_load_document_selector;if(0===parseInt(t,10))return;const a=new FormData;a.append("action","daextulma_load_document"),a.append("security",window.DAEXTULMA_PARAMETERS.nonce),a.append("document_id",t),fetch(window.DAEXTULMA_PARAMETERS.ajaxUrl,{method:"POST",body:a}).then((t=>t.json())).then((t=>{const a={invalid_date_format:l("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:l("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},o=a[t.data.error]||a.generic_error;if(t.data.error)return void wp.data.dispatch("core/notices").createErrorNotice(o,{type:"snackbar",isDismissible:!0});let r="";r="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.data.content):t.data.html_content,r=DOMPurify.sanitize(r,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:r}),t.data),d("core/editor").editPost({meta:{_import_markdown_pro_load_document_selector:"0"}}),this.setState({documentIdSelectorValue:"0"}),wp.data.dispatch("core/notices").createErrorNotice(l("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})}))}},l("Submit document","ultimate-markdown")))}}});const{Button:w,TextareaControl:_}=wp.components,{dispatch:k,select:h}=wp.data,{PluginDocumentSettingPanel:g}=wp.editor,{Component:b}=wp.element,{__:E}=wp.i18n,{registerPlugin:P}=wp.plugins;P("submit-text",{icon:!1,render:class extends b{constructor(t){super(...arguments),this.state={textareaValue:""}}render(){const a=h("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_submit_text_textarea;return(0,t.createElement)(g,{name:"submit-text",title:E("Submit Markdown","ultimate-markdown"),className:"daextulma-submit-text-panel"},(0,t.createElement)(_,{label:E("Markdown text","ultimate-markdown"),help:E("Enter the Markdown text, then click the submit text button to generate the corresponding blocks.","ultimate-markdown"),value:a,onChange:t=>{k("core/editor").editPost({meta:{_import_markdown_pro_submit_text_textarea:t}}),this.setState({textareaValue:t})},__nextHasNoMarginBottom:!0}),(0,t.createElement)(w,{variant:"secondary",className:"editor-post-trash is-destructive",onClick:()=>{wp.ajax.post("daextulma_submit_markdown",{security:window.DAEXTULMA_PARAMETERS.nonce,markdowntext:this.state.textareaValue}).done((t=>{let a="";a="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.content):t.html_content,a=DOMPurify.sanitize(a,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:a}),t),k("core/editor").editPost({meta:{_import_markdown_pro_submit_text_textarea:""}}),this.setState({textareaValue:""}),wp.data.dispatch("core/notices").createErrorNotice(E("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})})).fail((t=>{const e={invalid_date_format:E("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:E("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},a=e[t.error]||e.generic_error;wp.data.dispatch("core/notices").createErrorNotice(a,{type:"snackbar",isDismissible:!0})}))}},E("Submit text","ultimate-markdown")))}}})}();
  • ultimate-markdown/tags/1.22/blocks/src/utils.js

    r3326195 r3335244  
    44 * @package ultimate-markdown
    55 */
    6 
    7 /**
    8  * Add a category and refresh the panel.
    9  *
    10  * See: https://stackoverflow.com/questions/69983604/changing-a-posts-tag-category-from-a-wordpress-gutenberg-sidebar-plugin/70029499#70029499
    11  *
    12  * @param category
    13  * @constructor
    14  */
    15 export function AddCategory(category) {
    16 
    17     const {dispatch, select} = wp.data;
    18 
    19     // Get Current Selected Categories.
    20     let categories = select('core/editor').getEditedPostAttribute('categories');
    21 
    22     // Get State of Category Panel.
    23     let is_category_panel_open = select('core/edit-post').isEditorPanelOpened('taxonomy-panel-category');
    24 
    25     // Verify new category isn't already selected.
    26     if (!categories.includes(category)) {
    27 
    28         // Add new tag to existing list.
    29         categories.push(category);
    30 
    31         // Update Post with new tags.
    32         dispatch('core/editor').editPost({'categories': categories});
    33 
    34         // Verify if the category panel is open.
    35         if (is_category_panel_open) {
    36 
    37             // Close and re-open the category panel to reload data / refresh the UI.
    38             dispatch('core/edit-post').toggleEditorPanelOpened('taxonomy-panel-category');
    39             dispatch('core/edit-post').toggleEditorPanelOpened('taxonomy-panel-category');
    40         }
    41     }
    42 }
    436
    447/**
     
    11174    // Update the categories.
    11275    if (data['categories'] !== null) {
    113         data['categories'].forEach((category) => {
    114             AddCategory(category);
    115         });
     76        // Replace all categories with the new ones.
     77        dispatch('core/editor').editPost({ categories: data['categories'] });
    11678    }
    11779
    11880    // Update the tags.
    11981    if (data['tags'] !== null) {
    120         data['tags'].forEach((tag) => {
    121             AddTag(tag);
    122         });
     82        // Replace all tags with the new ones.
     83        dispatch('core/editor').editPost({ tags: data['tags'] });
    12384    }
    12485
  • ultimate-markdown/tags/1.22/init.php

    r3326195 r3335244  
    33 * Plugin Name: Ultimate Markdown
    44 * Description: A set of tools that helps you work with the Markdown language.
    5  * Version: 1.21
     5 * Version: 1.22
    66 * Author: DAEXT
    77 * Author URI: https://daext.com
  • ultimate-markdown/tags/1.22/readme.txt

    r3326200 r3335244  
    44Donate link: https://daext.com
    55Requires at least: 5.0
    6 Tested up to: 6.8.1
     6Tested up to: 6.8.2
    77Requires PHP: 5.3
    8 Stable tag: 1.21
     8Stable tag: 1.22
    99License: GPLv3
    1010
     
    107107
    108108== Changelog ==
     109
     110= 1.22 =
     111
     112*July 28, 2025*
     113
     114* Improved normalization of front matter date field during Markdown imports in the block editor.
     115* Bug fix: Categories and tags in the block editor are now correctly updated based on the imported front matter data.
    109116
    110117= 1.21 =
  • ultimate-markdown/tags/1.22/shared/class-daextulma-shared.php

    r3326195 r3335244  
    3333
    3434        $this->data['slug'] = 'daextulma';
    35         $this->data['ver']  = '1.21';
     35        $this->data['ver']  = '1.22';
    3636        $this->data['dir']  = substr( plugin_dir_path( __FILE__ ), 0, - 7 );
    3737        $this->data['url']  = substr( plugin_dir_url( __FILE__ ), 0, - 7 );
  • ultimate-markdown/trunk/admin/inc/class-daextulma-front-matter.php

    r3326195 r3335244  
    252252
    253253    /**
    254      * If the date is valid returns it, otherwise returns null.
    255      *
    256      * @param string $date A date in 'Y-m-d h:i:s' format.
     254     * If the date is valid, returns it as a string in 'Y-m-d H:i:s' format. Otherwise returns null.
     255     *
     256     * @param mixed $date
    257257     *
    258258     * @return string|null
     
    264264        }
    265265
    266         if ( !is_numeric( $date ) || (int) $date != $date ) {
     266        /**
     267         * The FrontYAML parser (Mni\FrontYAML\Parser::getYAML()) behaves inconsistently
     268         * when parsing the `date` field:
     269         *
     270         * - If the date is written as an unquoted string like `date: 2025-07-25 10:06:15`,
     271         *   the parser automatically converts it into a UNIX timestamp (integer).
     272         *
     273         * - If the date is written as a quoted string like `date: '2025-07-25 10:06:15'`,
     274         *   the parser preserves it as a plain string.
     275         *
     276         * This inconsistency requires preprocessing to ensure all dates are normalized
     277         * to the 'Y-m-d H:i:s' string format.
     278         */
     279
     280        // If it's a DateTime object (less common, but possible), format it to string.
     281        if ( $date instanceof DateTimeInterface ) {
     282            $date = $date->format( 'Y-m-d H:i:s' );
     283        }
     284
     285        // If it's a numeric UNIX timestamp (due to unquoted YAML date), convert to string format.
     286        elseif ( is_numeric( $date ) && (int) $date == $date ) {
     287            $date = gmdate( 'Y-m-d H:i:s', (int) $date );
     288        }
     289
     290        // At this point, we expect $date to be a string in 'Y-m-d H:i:s' format.
     291        if ( !is_string( $date ) ) {
    267292            throw new Exception( 'invalid_date_format' );
    268293        }
    269294
    270         /**
    271          * Note that the FrontYaml convert the date available in the string in the 'Y-m-d h:i:s' format to a unix date.
    272          * As a consequence, the date here is reconverted to the 'Y-m-d h:i:s' format with the PHP date() function.
    273          */
    274         $date = gmdate( 'Y-m-d h:i:s', $date );
    275 
    276         // Validate the date with a regex.
    277         $date_regex = '/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\s([0-6][0-9]|[0-9]):([0-6][0-9]|[0-9]):([0-6][0-9]|[0-9])$/';
    278         if ( preg_match( $date_regex, $date ) ) {
    279             $date = $date;
    280         } else {
    281             $date = null;
     295        // Validate the final date string format using a strict 24-hour regex.
     296        $date_regex = '/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\s([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$/';
     297
     298        if ( !preg_match( $date_regex, $date ) ) {
     299            return null;
    282300        }
    283301
  • ultimate-markdown/trunk/blocks/build/index.js

    r3326195 r3335244  
    1 !function(){"use strict";var t=window.wp.element;function e(t,e){const{dispatch:a,select:o}=wp.data;wp.data.dispatch("core/block-editor").insertBlocks(t),wp.data.dispatch("core/block-editor").clearSelectedBlock(),wp.data.dispatch("core/edit-post").openGeneralSidebar("edit-post/document"),null!==e.title&&wp.data.dispatch("core/editor").editPost({title:e.title}),null!==e.excerpt&&wp.data.dispatch("core/editor").editPost({excerpt:e.excerpt}),null!==e.categories&&e.categories.forEach((t=>{!function(t){const{dispatch:e,select:a}=wp.data;let o=a("core/editor").getEditedPostAttribute("categories"),r=a("core/edit-post").isEditorPanelOpened("taxonomy-panel-category");o.includes(t)||(o.push(t),e("core/editor").editPost({categories:o}),r&&(e("core/edit-post").toggleEditorPanelOpened("taxonomy-panel-category"),e("core/edit-post").toggleEditorPanelOpened("taxonomy-panel-category")))}(t)})),null!==e.tags&&e.tags.forEach((t=>{!function(t){const{dispatch:e,select:a}=wp.data;let o=a("core/editor").getEditedPostAttribute("tags"),r=a("core/edit-post").isEditorPanelOpened("taxonomy-panel-tags");o.includes(t)||(o.push(t),e("core/editor").editPost({tags:o}),r&&(e("core/edit-post").toggleEditorPanelOpened("taxonomy-panel-tags"),e("core/edit-post").toggleEditorPanelOpened("taxonomy-panel-tags")))}(t)})),null!==e.author&&wp.data.dispatch("core/editor").editPost({author:e.author}),null!==e.date&&wp.data.dispatch("core/editor").editPost({date:e.date}),null!==e.status&&wp.data.dispatch("core/editor").editPost({status:e.status})}const{PluginDocumentSettingPanel:a}=wp.editor,{Component:o}=wp.element,{__:__}=wp.i18n,{FormFileUpload:r}=wp.components,{registerPlugin:n}=wp.plugins;n("daextulma-import-document",{icon:!1,render:class extends o{render(){return(0,t.createElement)(a,{name:"daextulma-import-document",title:__("Import Markdown","ultimate-markdown")},(0,t.createElement)(r,{className:"block-library-gallery-add-item-button",onChange:()=>{const t=event.target.files[0],a=new FormData;a.append("action","daextulma_import_document"),a.append("security",window.DAEXTULMA_PARAMETERS.nonce),a.append("uploaded_file",t),fetch(window.DAEXTULMA_PARAMETERS.ajaxUrl,{method:"POST",body:a}).then((function(t){return t.json()})).then((function(t){const a={invalid_date_format:__("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:__("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},o=a[t.data.error]||a.generic_error;if(t.data.error)return void wp.data.dispatch("core/notices").createErrorNotice(o,{type:"snackbar",isDismissible:!0});let r="";r="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.data.content):t.data.html_content,r=DOMPurify.sanitize(r,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:r}),t.data),wp.data.dispatch("core/notices").createErrorNotice(__("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})}))},accept:".md,.markdown,.mdown,.mkdn,.mkd,.mdwn,.mdtxt,.mdtext,.text,.txt",icon:"insert",__next40pxDefaultSize:!0},__("Upload file and import","ultimate-markdown")))}}});const{dispatch:d,select:i}=wp.data,{PluginDocumentSettingPanel:s}=wp.editor,{Component:c}=wp.element,{__:l}=wp.i18n,{Button:m,SelectControl:p}=wp.components,{registerPlugin:u}=wp.plugins;u("daextulma-load-document",{icon:!1,render:class extends c{constructor(t){super(...arguments),this.state={documentIdSelectorValue:""}}render(){const a=i("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_load_document_selector;return(0,t.createElement)(s,{name:"daextulma-load-document",title:l("Load Markdown","ultimate-markdown"),className:"daextulma-load-document-panel"},(0,t.createElement)(p,{label:l("Markdown document","ultimate-markdown"),help:l("Select a Markdown document, then click the submit document button to generate the corresponding blocks.","ultimate-markdown"),value:a,onChange:t=>{d("core/editor").editPost({meta:{_import_markdown_pro_load_document_selector:t}}),this.setState({documentIdSelectorValue:t})},options:window.DAEXTULMA_PARAMETERS.documents,__nextHasNoMarginBottom:!0,__next40pxDefaultSize:!0}),(0,t.createElement)(m,{variant:"secondary",className:"editor-post-trash is-destructive",onClick:()=>{const t=i("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_load_document_selector;if(0===parseInt(t,10))return;const a=new FormData;a.append("action","daextulma_load_document"),a.append("security",window.DAEXTULMA_PARAMETERS.nonce),a.append("document_id",t),fetch(window.DAEXTULMA_PARAMETERS.ajaxUrl,{method:"POST",body:a}).then((t=>t.json())).then((t=>{const a={invalid_date_format:l("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:l("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},o=a[t.data.error]||a.generic_error;if(t.data.error)return void wp.data.dispatch("core/notices").createErrorNotice(o,{type:"snackbar",isDismissible:!0});let r="";r="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.data.content):t.data.html_content,r=DOMPurify.sanitize(r,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:r}),t.data),d("core/editor").editPost({meta:{_import_markdown_pro_load_document_selector:"0"}}),this.setState({documentIdSelectorValue:"0"}),wp.data.dispatch("core/notices").createErrorNotice(l("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})}))}},l("Submit document","ultimate-markdown")))}}});const{Button:w,TextareaControl:_}=wp.components,{dispatch:k,select:g}=wp.data,{PluginDocumentSettingPanel:h}=wp.editor,{Component:E}=wp.element,{__:P}=wp.i18n,{registerPlugin:b}=wp.plugins;b("submit-text",{icon:!1,render:class extends E{constructor(t){super(...arguments),this.state={textareaValue:""}}render(){const a=g("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_submit_text_textarea;return(0,t.createElement)(h,{name:"submit-text",title:P("Submit Markdown","ultimate-markdown"),className:"daextulma-submit-text-panel"},(0,t.createElement)(_,{label:P("Markdown text","ultimate-markdown"),help:P("Enter the Markdown text, then click the submit text button to generate the corresponding blocks.","ultimate-markdown"),value:a,onChange:t=>{k("core/editor").editPost({meta:{_import_markdown_pro_submit_text_textarea:t}}),this.setState({textareaValue:t})},__nextHasNoMarginBottom:!0}),(0,t.createElement)(w,{variant:"secondary",className:"editor-post-trash is-destructive",onClick:()=>{wp.ajax.post("daextulma_submit_markdown",{security:window.DAEXTULMA_PARAMETERS.nonce,markdowntext:this.state.textareaValue}).done((t=>{let a="";a="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.content):t.html_content,a=DOMPurify.sanitize(a,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:a}),t),k("core/editor").editPost({meta:{_import_markdown_pro_submit_text_textarea:""}}),this.setState({textareaValue:""}),wp.data.dispatch("core/notices").createErrorNotice(P("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})})).fail((t=>{const e={invalid_date_format:P("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:P("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},a=e[t.error]||e.generic_error;wp.data.dispatch("core/notices").createErrorNotice(a,{type:"snackbar",isDismissible:!0})}))}},P("Submit text","ultimate-markdown")))}}})}();
     1!function(){"use strict";var t=window.wp.element;function e(t,e){const{dispatch:a,select:o}=wp.data;wp.data.dispatch("core/block-editor").insertBlocks(t),wp.data.dispatch("core/block-editor").clearSelectedBlock(),wp.data.dispatch("core/edit-post").openGeneralSidebar("edit-post/document"),null!==e.title&&wp.data.dispatch("core/editor").editPost({title:e.title}),null!==e.excerpt&&wp.data.dispatch("core/editor").editPost({excerpt:e.excerpt}),null!==e.categories&&a("core/editor").editPost({categories:e.categories}),null!==e.tags&&a("core/editor").editPost({tags:e.tags}),null!==e.author&&wp.data.dispatch("core/editor").editPost({author:e.author}),null!==e.date&&wp.data.dispatch("core/editor").editPost({date:e.date}),null!==e.status&&wp.data.dispatch("core/editor").editPost({status:e.status})}const{PluginDocumentSettingPanel:a}=wp.editor,{Component:o}=wp.element,{__:__}=wp.i18n,{FormFileUpload:r}=wp.components,{registerPlugin:n}=wp.plugins;n("daextulma-import-document",{icon:!1,render:class extends o{render(){return(0,t.createElement)(a,{name:"daextulma-import-document",title:__("Import Markdown","ultimate-markdown")},(0,t.createElement)(r,{className:"block-library-gallery-add-item-button",onChange:()=>{const t=event.target.files[0],a=new FormData;a.append("action","daextulma_import_document"),a.append("security",window.DAEXTULMA_PARAMETERS.nonce),a.append("uploaded_file",t),fetch(window.DAEXTULMA_PARAMETERS.ajaxUrl,{method:"POST",body:a}).then((function(t){return t.json()})).then((function(t){const a={invalid_date_format:__("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:__("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},o=a[t.data.error]||a.generic_error;if(t.data.error)return void wp.data.dispatch("core/notices").createErrorNotice(o,{type:"snackbar",isDismissible:!0});let r="";r="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.data.content):t.data.html_content,r=DOMPurify.sanitize(r,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:r}),t.data),wp.data.dispatch("core/notices").createErrorNotice(__("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})}))},accept:".md,.markdown,.mdown,.mkdn,.mkd,.mdwn,.mdtxt,.mdtext,.text,.txt",icon:"insert",__next40pxDefaultSize:!0},__("Upload file and import","ultimate-markdown")))}}});const{dispatch:d,select:i}=wp.data,{PluginDocumentSettingPanel:s}=wp.editor,{Component:c}=wp.element,{__:l}=wp.i18n,{Button:m,SelectControl:u}=wp.components,{registerPlugin:p}=wp.plugins;p("daextulma-load-document",{icon:!1,render:class extends c{constructor(t){super(...arguments),this.state={documentIdSelectorValue:""}}render(){const a=i("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_load_document_selector;return(0,t.createElement)(s,{name:"daextulma-load-document",title:l("Load Markdown","ultimate-markdown"),className:"daextulma-load-document-panel"},(0,t.createElement)(u,{label:l("Markdown document","ultimate-markdown"),help:l("Select a Markdown document, then click the submit document button to generate the corresponding blocks.","ultimate-markdown"),value:a,onChange:t=>{d("core/editor").editPost({meta:{_import_markdown_pro_load_document_selector:t}}),this.setState({documentIdSelectorValue:t})},options:window.DAEXTULMA_PARAMETERS.documents,__nextHasNoMarginBottom:!0,__next40pxDefaultSize:!0}),(0,t.createElement)(m,{variant:"secondary",className:"editor-post-trash is-destructive",onClick:()=>{const t=i("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_load_document_selector;if(0===parseInt(t,10))return;const a=new FormData;a.append("action","daextulma_load_document"),a.append("security",window.DAEXTULMA_PARAMETERS.nonce),a.append("document_id",t),fetch(window.DAEXTULMA_PARAMETERS.ajaxUrl,{method:"POST",body:a}).then((t=>t.json())).then((t=>{const a={invalid_date_format:l("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:l("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},o=a[t.data.error]||a.generic_error;if(t.data.error)return void wp.data.dispatch("core/notices").createErrorNotice(o,{type:"snackbar",isDismissible:!0});let r="";r="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.data.content):t.data.html_content,r=DOMPurify.sanitize(r,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:r}),t.data),d("core/editor").editPost({meta:{_import_markdown_pro_load_document_selector:"0"}}),this.setState({documentIdSelectorValue:"0"}),wp.data.dispatch("core/notices").createErrorNotice(l("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})}))}},l("Submit document","ultimate-markdown")))}}});const{Button:w,TextareaControl:_}=wp.components,{dispatch:k,select:h}=wp.data,{PluginDocumentSettingPanel:g}=wp.editor,{Component:b}=wp.element,{__:E}=wp.i18n,{registerPlugin:P}=wp.plugins;P("submit-text",{icon:!1,render:class extends b{constructor(t){super(...arguments),this.state={textareaValue:""}}render(){const a=h("core/editor").getEditedPostAttribute("meta")._import_markdown_pro_submit_text_textarea;return(0,t.createElement)(g,{name:"submit-text",title:E("Submit Markdown","ultimate-markdown"),className:"daextulma-submit-text-panel"},(0,t.createElement)(_,{label:E("Markdown text","ultimate-markdown"),help:E("Enter the Markdown text, then click the submit text button to generate the corresponding blocks.","ultimate-markdown"),value:a,onChange:t=>{k("core/editor").editPost({meta:{_import_markdown_pro_submit_text_textarea:t}}),this.setState({textareaValue:t})},__nextHasNoMarginBottom:!0}),(0,t.createElement)(w,{variant:"secondary",className:"editor-post-trash is-destructive",onClick:()=>{wp.ajax.post("daextulma_submit_markdown",{security:window.DAEXTULMA_PARAMETERS.nonce,markdowntext:this.state.textareaValue}).done((t=>{let a="";a="marked"===window.DAEXTULMA_PARAMETERS.editorMarkdownParser?marked(t.content):t.html_content,a=DOMPurify.sanitize(a,{USE_PROFILES:{html:!0}}),wp.data.dispatch("core/block-editor").resetBlocks([]),e(wp.blocks.rawHandler({HTML:a}),t),k("core/editor").editPost({meta:{_import_markdown_pro_submit_text_textarea:""}}),this.setState({textareaValue:""}),wp.data.dispatch("core/notices").createErrorNotice(E("Markdown content successfully processed and blocks created.","ultimate-markdown"),{type:"snackbar",isDismissible:!0})})).fail((t=>{const e={invalid_date_format:E("Invalid date format in Front Matter. Please enter a valid date, e.g. 2025-07-16, or a date and time, e.g. 2025-07-16 10:30:42.","ultimate-markdown"),generic_error:E("Please review your document for any formatting issues in the Front Matter or Markdown content, then try again. The content could not be processed. For more details on supported fields and formatting, please refer to the plugin documentation.","ultimate-markdown")},a=e[t.error]||e.generic_error;wp.data.dispatch("core/notices").createErrorNotice(a,{type:"snackbar",isDismissible:!0})}))}},E("Submit text","ultimate-markdown")))}}})}();
  • ultimate-markdown/trunk/blocks/src/utils.js

    r3326195 r3335244  
    44 * @package ultimate-markdown
    55 */
    6 
    7 /**
    8  * Add a category and refresh the panel.
    9  *
    10  * See: https://stackoverflow.com/questions/69983604/changing-a-posts-tag-category-from-a-wordpress-gutenberg-sidebar-plugin/70029499#70029499
    11  *
    12  * @param category
    13  * @constructor
    14  */
    15 export function AddCategory(category) {
    16 
    17     const {dispatch, select} = wp.data;
    18 
    19     // Get Current Selected Categories.
    20     let categories = select('core/editor').getEditedPostAttribute('categories');
    21 
    22     // Get State of Category Panel.
    23     let is_category_panel_open = select('core/edit-post').isEditorPanelOpened('taxonomy-panel-category');
    24 
    25     // Verify new category isn't already selected.
    26     if (!categories.includes(category)) {
    27 
    28         // Add new tag to existing list.
    29         categories.push(category);
    30 
    31         // Update Post with new tags.
    32         dispatch('core/editor').editPost({'categories': categories});
    33 
    34         // Verify if the category panel is open.
    35         if (is_category_panel_open) {
    36 
    37             // Close and re-open the category panel to reload data / refresh the UI.
    38             dispatch('core/edit-post').toggleEditorPanelOpened('taxonomy-panel-category');
    39             dispatch('core/edit-post').toggleEditorPanelOpened('taxonomy-panel-category');
    40         }
    41     }
    42 }
    436
    447/**
     
    11174    // Update the categories.
    11275    if (data['categories'] !== null) {
    113         data['categories'].forEach((category) => {
    114             AddCategory(category);
    115         });
     76        // Replace all categories with the new ones.
     77        dispatch('core/editor').editPost({ categories: data['categories'] });
    11678    }
    11779
    11880    // Update the tags.
    11981    if (data['tags'] !== null) {
    120         data['tags'].forEach((tag) => {
    121             AddTag(tag);
    122         });
     82        // Replace all tags with the new ones.
     83        dispatch('core/editor').editPost({ tags: data['tags'] });
    12384    }
    12485
  • ultimate-markdown/trunk/init.php

    r3326195 r3335244  
    33 * Plugin Name: Ultimate Markdown
    44 * Description: A set of tools that helps you work with the Markdown language.
    5  * Version: 1.21
     5 * Version: 1.22
    66 * Author: DAEXT
    77 * Author URI: https://daext.com
  • ultimate-markdown/trunk/readme.txt

    r3326200 r3335244  
    44Donate link: https://daext.com
    55Requires at least: 5.0
    6 Tested up to: 6.8.1
     6Tested up to: 6.8.2
    77Requires PHP: 5.3
    8 Stable tag: 1.21
     8Stable tag: 1.22
    99License: GPLv3
    1010
     
    107107
    108108== Changelog ==
     109
     110= 1.22 =
     111
     112*July 28, 2025*
     113
     114* Improved normalization of front matter date field during Markdown imports in the block editor.
     115* Bug fix: Categories and tags in the block editor are now correctly updated based on the imported front matter data.
    109116
    110117= 1.21 =
  • ultimate-markdown/trunk/shared/class-daextulma-shared.php

    r3326195 r3335244  
    3333
    3434        $this->data['slug'] = 'daextulma';
    35         $this->data['ver']  = '1.21';
     35        $this->data['ver']  = '1.22';
    3636        $this->data['dir']  = substr( plugin_dir_path( __FILE__ ), 0, - 7 );
    3737        $this->data['url']  = substr( plugin_dir_url( __FILE__ ), 0, - 7 );
Note: See TracChangeset for help on using the changeset viewer.