🏨 Hotel Booking Enhancements: - Implemented Eagle Booking Advanced Pricing add-on - Added Booking.com-style rate management system - Created professional calendar interface for pricing - Integrated deals and discounts functionality 💰 Advanced Pricing Features: - Dynamic pricing models (per room, per person, per adult) - Base rates, adult rates, and child rates management - Length of stay discounts and early bird deals - Mobile rates and secret deals implementation - Seasonal promotions and flash sales 📅 Availability Management: - Real-time availability tracking - Stop sell and restriction controls - Closed to arrival/departure functionality - Minimum/maximum stay requirements - Automatic sold-out management 💳 Payment Integration: - Maintained Redsys payment gateway integration - Seamless integration with existing Eagle Booking - No modifications to core Eagle Booking plugin 🛠️ Technical Implementation: - Custom database tables for advanced pricing - WordPress hooks and filters integration - AJAX-powered admin interface - Data migration from existing Eagle Booking - Professional calendar view for revenue management 📊 Admin Interface: - Booking.com-style management dashboard - Visual rate and availability calendar - Bulk operations for date ranges - Statistics and analytics dashboard - Modal dialogs for quick editing 🔧 Code Quality: - WordPress coding standards compliance - Secure database operations with prepared statements - Proper input validation and sanitization - Error handling and logging - Responsive admin interface 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
250 lines
6.6 KiB
JavaScript
250 lines
6.6 KiB
JavaScript
/**
|
|
* @output wp-includes/js/wp-embed-template.js
|
|
*/
|
|
(function ( window, document ) {
|
|
'use strict';
|
|
|
|
var supportedBrowser = ( document.querySelector && window.addEventListener ),
|
|
loaded = false,
|
|
secret,
|
|
secretTimeout,
|
|
resizing;
|
|
|
|
function sendEmbedMessage( message, value ) {
|
|
window.parent.postMessage( {
|
|
message: message,
|
|
value: value,
|
|
secret: secret
|
|
}, '*' );
|
|
}
|
|
|
|
/**
|
|
* Send the height message to the parent window.
|
|
*/
|
|
function sendHeightMessage() {
|
|
sendEmbedMessage( 'height', Math.ceil( document.body.getBoundingClientRect().height ) );
|
|
}
|
|
|
|
function onLoad() {
|
|
if ( loaded ) {
|
|
return;
|
|
}
|
|
loaded = true;
|
|
|
|
var share_dialog = document.querySelector( '.wp-embed-share-dialog' ),
|
|
share_dialog_open = document.querySelector( '.wp-embed-share-dialog-open' ),
|
|
share_dialog_close = document.querySelector( '.wp-embed-share-dialog-close' ),
|
|
share_input = document.querySelectorAll( '.wp-embed-share-input' ),
|
|
share_dialog_tabs = document.querySelectorAll( '.wp-embed-share-tab-button button' ),
|
|
featured_image = document.querySelector( '.wp-embed-featured-image img' ),
|
|
i;
|
|
|
|
if ( share_input ) {
|
|
for ( i = 0; i < share_input.length; i++ ) {
|
|
share_input[ i ].addEventListener( 'click', function ( e ) {
|
|
e.target.select();
|
|
} );
|
|
}
|
|
}
|
|
|
|
function openSharingDialog() {
|
|
share_dialog.className = share_dialog.className.replace( 'hidden', '' );
|
|
// Initial focus should go on the currently selected tab in the dialog.
|
|
document.querySelector( '.wp-embed-share-tab-button [aria-selected="true"]' ).focus();
|
|
}
|
|
|
|
function closeSharingDialog() {
|
|
share_dialog.className += ' hidden';
|
|
document.querySelector( '.wp-embed-share-dialog-open' ).focus();
|
|
}
|
|
|
|
if ( share_dialog_open ) {
|
|
share_dialog_open.addEventListener( 'click', function () {
|
|
openSharingDialog();
|
|
} );
|
|
}
|
|
|
|
if ( share_dialog_close ) {
|
|
share_dialog_close.addEventListener( 'click', function () {
|
|
closeSharingDialog();
|
|
} );
|
|
}
|
|
|
|
function shareClickHandler( e ) {
|
|
var currentTab = document.querySelector( '.wp-embed-share-tab-button [aria-selected="true"]' );
|
|
currentTab.setAttribute( 'aria-selected', 'false' );
|
|
document.querySelector( '#' + currentTab.getAttribute( 'aria-controls' ) ).setAttribute( 'aria-hidden', 'true' );
|
|
|
|
e.target.setAttribute( 'aria-selected', 'true' );
|
|
document.querySelector( '#' + e.target.getAttribute( 'aria-controls' ) ).setAttribute( 'aria-hidden', 'false' );
|
|
}
|
|
|
|
function shareKeyHandler( e ) {
|
|
var target = e.target,
|
|
previousSibling = target.parentElement.previousElementSibling,
|
|
nextSibling = target.parentElement.nextElementSibling,
|
|
newTab, newTabChild;
|
|
|
|
if ( 37 === e.keyCode ) {
|
|
newTab = previousSibling;
|
|
} else if ( 39 === e.keyCode ) {
|
|
newTab = nextSibling;
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
if ( 'rtl' === document.documentElement.getAttribute( 'dir' ) ) {
|
|
newTab = ( newTab === previousSibling ) ? nextSibling : previousSibling;
|
|
}
|
|
|
|
if ( newTab ) {
|
|
newTabChild = newTab.firstElementChild;
|
|
|
|
target.setAttribute( 'tabindex', '-1' );
|
|
target.setAttribute( 'aria-selected', false );
|
|
document.querySelector( '#' + target.getAttribute( 'aria-controls' ) ).setAttribute( 'aria-hidden', 'true' );
|
|
|
|
newTabChild.setAttribute( 'tabindex', '0' );
|
|
newTabChild.setAttribute( 'aria-selected', 'true' );
|
|
newTabChild.focus();
|
|
document.querySelector( '#' + newTabChild.getAttribute( 'aria-controls' ) ).setAttribute( 'aria-hidden', 'false' );
|
|
}
|
|
}
|
|
|
|
if ( share_dialog_tabs ) {
|
|
for ( i = 0; i < share_dialog_tabs.length; i++ ) {
|
|
share_dialog_tabs[ i ].addEventListener( 'click', shareClickHandler );
|
|
|
|
share_dialog_tabs[ i ].addEventListener( 'keydown', shareKeyHandler );
|
|
}
|
|
}
|
|
|
|
document.addEventListener( 'keydown', function ( e ) {
|
|
if ( 27 === e.keyCode && -1 === share_dialog.className.indexOf( 'hidden' ) ) {
|
|
closeSharingDialog();
|
|
} else if ( 9 === e.keyCode ) {
|
|
constrainTabbing( e );
|
|
}
|
|
}, false );
|
|
|
|
function constrainTabbing( e ) {
|
|
// Need to re-get the selected tab each time.
|
|
var firstFocusable = document.querySelector( '.wp-embed-share-tab-button [aria-selected="true"]' );
|
|
|
|
if ( share_dialog_close === e.target && ! e.shiftKey ) {
|
|
firstFocusable.focus();
|
|
e.preventDefault();
|
|
} else if ( firstFocusable === e.target && e.shiftKey ) {
|
|
share_dialog_close.focus();
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
|
|
if ( window.self === window.top ) {
|
|
return;
|
|
}
|
|
|
|
// Send this document's height to the parent (embedding) site.
|
|
sendHeightMessage();
|
|
|
|
// Send the document's height again after the featured image has been loaded.
|
|
if ( featured_image ) {
|
|
featured_image.addEventListener( 'load', sendHeightMessage );
|
|
}
|
|
|
|
/**
|
|
* Detect clicks to external (_top) links.
|
|
*/
|
|
function linkClickHandler( e ) {
|
|
var target = e.target,
|
|
href;
|
|
if ( target.hasAttribute( 'href' ) ) {
|
|
href = target.getAttribute( 'href' );
|
|
} else {
|
|
href = target.parentElement.getAttribute( 'href' );
|
|
}
|
|
|
|
// Only catch clicks from the primary mouse button, without any modifiers.
|
|
if ( event.altKey || event.ctrlKey || event.metaKey || event.shiftKey ) {
|
|
return;
|
|
}
|
|
|
|
// Send link target to the parent (embedding) site.
|
|
if ( href ) {
|
|
sendEmbedMessage( 'link', href );
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
|
|
document.addEventListener( 'click', linkClickHandler );
|
|
}
|
|
|
|
/**
|
|
* Iframe resize handler.
|
|
*/
|
|
function onResize() {
|
|
if ( window.self === window.top ) {
|
|
return;
|
|
}
|
|
|
|
clearTimeout( resizing );
|
|
|
|
resizing = setTimeout( sendHeightMessage, 100 );
|
|
}
|
|
|
|
/**
|
|
* Message handler.
|
|
*
|
|
* @param {MessageEvent} event
|
|
*/
|
|
function onMessage( event ) {
|
|
var data = event.data;
|
|
|
|
if ( ! data ) {
|
|
return;
|
|
}
|
|
|
|
if ( event.source !== window.parent ) {
|
|
return;
|
|
}
|
|
|
|
if ( ! ( data.secret || data.message ) ) {
|
|
return;
|
|
}
|
|
|
|
if ( data.secret !== secret ) {
|
|
return;
|
|
}
|
|
|
|
if ( 'ready' === data.message ) {
|
|
sendHeightMessage();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Re-get the secret when it was added later on.
|
|
*/
|
|
function getSecret() {
|
|
if ( window.self === window.top || !!secret ) {
|
|
return;
|
|
}
|
|
|
|
secret = window.location.hash.replace( /.*secret=([\d\w]{10}).*/, '$1' );
|
|
|
|
clearTimeout( secretTimeout );
|
|
|
|
secretTimeout = setTimeout( function () {
|
|
getSecret();
|
|
}, 100 );
|
|
}
|
|
|
|
if ( supportedBrowser ) {
|
|
getSecret();
|
|
document.documentElement.className = document.documentElement.className.replace( /\bno-js\b/, '' ) + ' js';
|
|
document.addEventListener( 'DOMContentLoaded', onLoad, false );
|
|
window.addEventListener( 'load', onLoad, false );
|
|
window.addEventListener( 'resize', onResize, false );
|
|
window.addEventListener( 'message', onMessage, false );
|
|
}
|
|
})( window, document );
|