booking
/
includes
/
page-form-builder
/
field-packs
/
custom-shortcode
/
_src
/
custom-shortcode.js
custom-shortcode.js in Booking Calendar 11.8.4, at includes/page-form-builder/field-packs/custom-shortcode/_src/custom-shortcode.js
| 1 | // File: /includes/page-form-builder/field-packs/custom-shortcode/custom-shortcode.js |
| 2 | ( function ( window, document ) { |
| 3 | 'use strict'; |
| 4 | |
| 5 | var Core = window.WPBC_BFB_Core || {}; |
| 6 | var registry = Core.WPBC_BFB_Field_Renderer_Registry; |
| 7 | var Base = Core.WPBC_BFB_Field_Base; |
| 8 | |
| 9 | if ( ! registry || typeof registry.register !== 'function' || ! Base ) { |
| 10 | return; |
| 11 | } |
| 12 | |
| 13 | /** |
| 14 | * Return translated field-pack strings with safe fallbacks. |
| 15 | * |
| 16 | * @returns {{example_shortcode:string, invalid_message:string}} Field-pack strings. |
| 17 | */ |
| 18 | function wpbc_bfb_custom_shortcode_get_boot() { |
| 19 | var boot = window.WPBC_BFB_Custom_Shortcode_Boot || {}; |
| 20 | |
| 21 | return { |
| 22 | example_shortcode : String( boot.example_shortcode || '[field_name_hint]' ), |
| 23 | invalid_message : String( boot.invalid_message || 'Enter one complete shortcode, for example [field_name_hint] or [coupon discount ""].' ) |
| 24 | }; |
| 25 | } |
| 26 | |
| 27 | /** |
| 28 | * Normalize one bracketed Booking Calendar shortcode. |
| 29 | * |
| 30 | * The token may contain space-separated options and balanced single- or |
| 31 | * double-quoted values. Control characters, HTML delimiters, nested brackets, |
| 32 | * multiple tokens, unbalanced quotes, and excessive input are rejected before |
| 33 | * the value can reach the Advanced Booking Form exporter. |
| 34 | * |
| 35 | * @param {*} shortcode_value Candidate value from Builder field data. |
| 36 | * |
| 37 | * @returns {string} Trimmed token when valid, otherwise an empty string. |
| 38 | */ |
| 39 | function wpbc_bfb_custom_shortcode_normalize( shortcode_value ) { |
| 40 | var shortcode = String( shortcode_value == null ? '' : shortcode_value ).trim(); |
| 41 | var shortcode_body; |
| 42 | var shortcode_name_end; |
| 43 | var shortcode_name; |
| 44 | var active_quote = ''; |
| 45 | var character; |
| 46 | var index; |
| 47 | |
| 48 | if ( |
| 49 | shortcode.length < 3 || |
| 50 | shortcode.length > 1000 || |
| 51 | '[' !== shortcode.charAt( 0 ) || |
| 52 | ']' !== shortcode.charAt( shortcode.length - 1 ) |
| 53 | ) { |
| 54 | return ''; |
| 55 | } |
| 56 | |
| 57 | shortcode_body = shortcode.slice( 1, -1 ).trim(); |
| 58 | |
| 59 | if ( ! shortcode_body || /[\u0000-\u001F\u007F<>\[\]]/.test( shortcode_body ) ) { |
| 60 | return ''; |
| 61 | } |
| 62 | |
| 63 | shortcode_name_end = shortcode_body.indexOf( ' ' ); |
| 64 | shortcode_name = -1 === shortcode_name_end |
| 65 | ? shortcode_body |
| 66 | : shortcode_body.slice( 0, shortcode_name_end ); |
| 67 | |
| 68 | if ( ! /^[A-Za-z0-9_.*-]+$/.test( shortcode_name ) ) { |
| 69 | return ''; |
| 70 | } |
| 71 | |
| 72 | for ( index = shortcode_name.length; index < shortcode_body.length; index++ ) { |
| 73 | character = shortcode_body.charAt( index ); |
| 74 | |
| 75 | if ( active_quote ) { |
| 76 | if ( character === active_quote ) { |
| 77 | active_quote = ''; |
| 78 | } |
| 79 | continue; |
| 80 | } |
| 81 | |
| 82 | if ( '"' === character || "'" === character ) { |
| 83 | active_quote = character; |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | return active_quote ? '' : '[' + shortcode_body + ']'; |
| 88 | } |
| 89 | |
| 90 | /** |
| 91 | * Escape preview text when the shared sanitizer is unexpectedly unavailable. |
| 92 | * |
| 93 | * @param {*} raw_value Preview value. |
| 94 | * |
| 95 | * @returns {string} HTML-safe preview value. |
| 96 | */ |
| 97 | function wpbc_bfb_custom_shortcode_escape_html( raw_value ) { |
| 98 | return String( raw_value ) |
| 99 | .replace( /&/g, '&' ) |
| 100 | .replace( /</g, '<' ) |
| 101 | .replace( />/g, '>' ) |
| 102 | .replace( /"/g, '"' ) |
| 103 | .replace( /'/g, ''' ); |
| 104 | } |
| 105 | |
| 106 | /** |
| 107 | * Render and export one validated custom shortcode token. |
| 108 | */ |
| 109 | class WPBC_BFB_Field_Custom_Shortcode extends Base { |
| 110 | |
| 111 | /** |
| 112 | * Return defaults kept in sync with the PHP schema. |
| 113 | * |
| 114 | * @returns {{type:string, shortcode:string, usage_key:string}} Field defaults. |
| 115 | */ |
| 116 | static get_defaults() { |
| 117 | return { |
| 118 | type : 'custom_shortcode', |
| 119 | shortcode : '[field_name_hint]', |
| 120 | usage_key : 'custom_shortcode' |
| 121 | }; |
| 122 | } |
| 123 | |
| 124 | /** |
| 125 | * Render an inert and escaped Builder preview. |
| 126 | * |
| 127 | * The raw draft remains in `data-shortcode` while the preview and exporter |
| 128 | * use only a validated token. This lets the author finish typing without |
| 129 | * silently replacing an incomplete draft with the example value. |
| 130 | * |
| 131 | * @param {HTMLElement} el Builder field element. |
| 132 | * @param {Object} data Field properties. |
| 133 | * @param {Object} ctx Builder context. |
| 134 | * |
| 135 | * @returns {void} |
| 136 | */ |
| 137 | static render( el, data, ctx ) { |
| 138 | var field_data; |
| 139 | var raw_shortcode; |
| 140 | var shortcode; |
| 141 | var boot; |
| 142 | var display_shortcode; |
| 143 | var invalid_html; |
| 144 | var escape_html; |
| 145 | |
| 146 | if ( ! el ) { |
| 147 | return; |
| 148 | } |
| 149 | |
| 150 | field_data = this.normalize_data( data ); |
| 151 | raw_shortcode = String( field_data.shortcode || '' ).trim(); |
| 152 | shortcode = wpbc_bfb_custom_shortcode_normalize( raw_shortcode ); |
| 153 | boot = wpbc_bfb_custom_shortcode_get_boot(); |
| 154 | display_shortcode = raw_shortcode || boot.example_shortcode; |
| 155 | escape_html = Core.WPBC_BFB_Sanitize && Core.WPBC_BFB_Sanitize.escape_html |
| 156 | ? Core.WPBC_BFB_Sanitize.escape_html |
| 157 | : wpbc_bfb_custom_shortcode_escape_html; |
| 158 | invalid_html = shortcode |
| 159 | ? '' |
| 160 | : '<span class="wpbc_bfb__help" role="alert">' + escape_html( boot.invalid_message ) + '</span>'; |
| 161 | |
| 162 | el.dataset.shortcode = raw_shortcode; |
| 163 | el.innerHTML = |
| 164 | '<span class="wpbc_bfb__noaction wpbc_bfb__no-drag-zone" inert="">' + |
| 165 | '<code class="wpbc_bfb__custom-shortcode-preview">' + escape_html( display_shortcode ) + '</code>' + |
| 166 | '</span>' + |
| 167 | invalid_html; |
| 168 | |
| 169 | if ( Core.UI && Core.UI.WPBC_BFB_Overlay && typeof Core.UI.WPBC_BFB_Overlay.ensure === 'function' ) { |
| 170 | Core.UI.WPBC_BFB_Overlay.ensure( ctx && ctx.builder, el ); |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | /** |
| 175 | * Preserve the standard Builder post-drop behavior. |
| 176 | * |
| 177 | * @param {Object} data Field properties. |
| 178 | * @param {HTMLElement} el Builder field element. |
| 179 | * @param {Object} ctx Builder context. |
| 180 | * |
| 181 | * @returns {void} |
| 182 | */ |
| 183 | static on_field_drop( data, el, ctx ) { |
| 184 | if ( typeof super.on_field_drop === 'function' ) { |
| 185 | super.on_field_drop( data, el, ctx ); |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | registry.register( 'custom_shortcode', WPBC_BFB_Field_Custom_Shortcode ); |
| 191 | |
| 192 | /** |
| 193 | * Export one validated token to the Advanced Booking Form. |
| 194 | * |
| 195 | * @param {Object} field Field data from the Builder structure. |
| 196 | * @param {Function} emit Exporter output callback. |
| 197 | * |
| 198 | * @returns {void} |
| 199 | */ |
| 200 | function wpbc_bfb_export_custom_shortcode_to_form( field, emit ) { |
| 201 | var shortcode = wpbc_bfb_custom_shortcode_normalize( field && field.shortcode ); |
| 202 | |
| 203 | if ( shortcode ) { |
| 204 | emit( shortcode ); |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | /** |
| 209 | * Register the Advanced Booking Form exporter. |
| 210 | * |
| 211 | * @returns {void} |
| 212 | */ |
| 213 | function wpbc_bfb_register_custom_shortcode_form_exporter() { |
| 214 | var Exporter = window.WPBC_BFB_Exporter; |
| 215 | |
| 216 | if ( ! Exporter || typeof Exporter.register !== 'function' ) { |
| 217 | return; |
| 218 | } |
| 219 | if ( typeof Exporter.has_exporter === 'function' && Exporter.has_exporter( 'custom_shortcode' ) ) { |
| 220 | return; |
| 221 | } |
| 222 | |
| 223 | Exporter.register( 'custom_shortcode', wpbc_bfb_export_custom_shortcode_to_form ); |
| 224 | } |
| 225 | |
| 226 | if ( window.WPBC_BFB_Exporter && typeof window.WPBC_BFB_Exporter.register === 'function' ) { |
| 227 | wpbc_bfb_register_custom_shortcode_form_exporter(); |
| 228 | } else if ( document && typeof document.addEventListener === 'function' ) { |
| 229 | document.addEventListener( 'wpbc:bfb:exporter-ready', wpbc_bfb_register_custom_shortcode_form_exporter, { once: true } ); |
| 230 | } |
| 231 | |
| 232 | /** |
| 233 | * Omit the custom token from submitted Booking Data output. |
| 234 | * |
| 235 | * @returns {void} |
| 236 | */ |
| 237 | function wpbc_bfb_omit_custom_shortcode_from_content() { |
| 238 | return; |
| 239 | } |
| 240 | |
| 241 | /** |
| 242 | * Register an empty Booking Data exporter. |
| 243 | * |
| 244 | * The field pack modifies only the Advanced Booking Form. It cannot infer the |
| 245 | * correct Booking Data representation for arbitrary display or input tokens. |
| 246 | * |
| 247 | * @returns {void} |
| 248 | */ |
| 249 | function wpbc_bfb_register_custom_shortcode_content_exporter() { |
| 250 | var Exporter = window.WPBC_BFB_ContentExporter; |
| 251 | |
| 252 | if ( ! Exporter || typeof Exporter.register !== 'function' ) { |
| 253 | return; |
| 254 | } |
| 255 | if ( typeof Exporter.has_exporter === 'function' && Exporter.has_exporter( 'custom_shortcode' ) ) { |
| 256 | return; |
| 257 | } |
| 258 | |
| 259 | Exporter.register( 'custom_shortcode', wpbc_bfb_omit_custom_shortcode_from_content ); |
| 260 | } |
| 261 | |
| 262 | if ( window.WPBC_BFB_ContentExporter && typeof window.WPBC_BFB_ContentExporter.register === 'function' ) { |
| 263 | wpbc_bfb_register_custom_shortcode_content_exporter(); |
| 264 | } else if ( document && typeof document.addEventListener === 'function' ) { |
| 265 | document.addEventListener( 'wpbc:bfb:content-exporter-ready', wpbc_bfb_register_custom_shortcode_content_exporter, { once: true } ); |
| 266 | } |
| 267 | } )( window, document ); |
| 268 |