<?php // https://divibooster.com/change-the-divi-gallery-module-image-count-separator/

namespace DiviBooster\GalleryBooster\ImageCountSeparator;

// === Constants ===
const DIVI4_MODULE_SLUG = 'et_pb_gallery';
const DIVI5_MODULE_SLUG = 'divi/gallery';
const DIVI4_SETTING_SLUG = 'dbdb_image_count_separator';
const DIVI5_SETTING_SLUG = 'diviboosterImageCountSeparator';

// === Hooks Registration ===
if (function_exists('add_filter')) {
    // Divi 4: Register field
    \add_filter('et_pb_all_fields_unprocessed_' . DIVI4_MODULE_SLUG, __NAMESPACE__ . '\\d4_add_field');

    // Divi 4: Output processing
    \add_filter('et_module_shortcode_output', __NAMESPACE__ . '\\d4_output', 10, 3);

    // Divi 5: Output processing
    \add_filter('render_block_' . DIVI5_MODULE_SLUG, __NAMESPACE__ . '\\d5_output', 10, 3);

    // Divi 5: PHP attribute registration
    \add_filter('divi_module_library_register_module_attrs', __NAMESPACE__ . '\\d5_register_attribute', 10, 2);

    // Divi 5: PHP conversion outline registration
    \add_filter('divi.moduleLibrary.conversion.moduleConversionOutline', __NAMESPACE__ . '\\d5_register_conversion_outline', 10, 2);
}

if (function_exists('add_action')) {
    // Define a safe global stub early to avoid ReferenceError if other scripts call it before our footer JS runs
    \add_action('wp_head', __NAMESPACE__ . '\\output_global_stub_once');

    // Divi 5: Enqueue VB-only JS for attribute + conversion + visibility
    \add_action('divi_visual_builder_assets_before_enqueue_scripts', __NAMESPACE__ . '\\enqueue_divi5_js');

    // Front-end JS to apply separators in lightbox and slider counter (when present)
    // Use a late priority so jQuery and other scripts are already printed
    \add_action('wp_footer', __NAMESPACE__ . '\\output_frontend_script_once', 99);

    // Divi 4 Builder/Admin UI helper to hide field when neither lightbox nor slider enabled
    // Run after core/admin scripts to ensure jQuery is available
    \add_action('wp_footer', __NAMESPACE__ . '\\output_d4_ui_visibility_js_once', 99);
    \add_action('admin_footer', __NAMESPACE__ . '\\output_d4_ui_visibility_js_once', 99);
}

// === Early global stub to prevent ReferenceError when called before footer ===
function output_global_stub_once() {
    static $done = false; if ($done) return; $done = true;
?>
<style>
    /* Hide all slide counters immediately to avoid flash of default separator */
    .dbdb-slide-counter{visibility:hidden;}
    .dbdb-slide-counter.dbdb-counter-ready{visibility:visible;}
</style>
<script>window.applySliderCounterSeparator = window.applySliderCounterSeparator || function(){ /* stub until plugin JS loads */ };</script>
<?php
}

// === Divi 4: Field Registration ===
function d4_add_field($fields) {
    if (!is_array($fields)) {
        return $fields;
    }
    $fields[DIVI4_SETTING_SLUG] = array(
        'label'            => esc_html__('Image Count Separator', 'divi-booster'),
        'type'             => 'text',
        'option_category'  => 'configuration',
        'default'          => esc_html__(' of ', 'divi-booster'),
        'tab_slug'         => 'general',
        'toggle_slug'      => 'elements',
        'description'      => esc_html__('Customize the text between the current image number and total images.', 'divi-booster'),
        // Note: Divi 4 show_if cannot express OR. We manage visibility via builder JS below.
    );
    return $fields;
}

// === Divi 4: Output ===
function d4_output($output, $render_slug, $module) {
    if (!is_string($output) || $render_slug !== DIVI4_MODULE_SLUG || !isset($module->props) || !is_array($module->props)) {
        return $output;
    }
    $props = $module->props;
    $sep   = resolve_separator_from_props($props);
    if ($sep === null) {
        return $output;
    }
    return inject_separator_attr_into_gallery_items($output, $sep);
}

// === Divi 5: Attribute Registration (PHP) ===
function d5_register_attribute($module_attrs, $filter_args) {
    if (($filter_args['name'] ?? '') !== DIVI5_MODULE_SLUG) {
        return $module_attrs;
    }
    $module_attrs[DIVI5_SETTING_SLUG] = get_divi5_attribute_definition();
    return $module_attrs;
}

// === Divi 5: PHP conversion outline registration ===
function d5_register_conversion_outline($conversion_outline, $module_name) {
    if (DIVI5_MODULE_SLUG !== $module_name) {
        return $conversion_outline;
    }
    if (!isset($conversion_outline['module']) || !is_array($conversion_outline['module'])) {
        $conversion_outline['module'] = array();
    }
    $conversion_outline['module'][DIVI4_SETTING_SLUG] = DIVI5_SETTING_SLUG . '.*';
    return $conversion_outline;
}

// === Divi 5: Output ===
function d5_output($block_content, $parsed_block, $block) {
    $attrs = $parsed_block['attrs'] ?? array();
    $sep   = resolve_separator_from_props($attrs);
    if ($sep === null || !is_string($block_content) || $block_content === '') {
        return $block_content;
    }
    return inject_separator_attr_into_gallery_items($block_content, $sep);
}

// === Divi 5: VB JS Attribute & Conversion + Visibility ===
function enqueue_divi5_js() {
    if ((!function_exists('et_builder_d5_enabled') || !\et_builder_d5_enabled()) ||
        (!function_exists('et_core_is_fb_enabled') || !\et_core_is_fb_enabled())) {
        return;
    }
    $handle = sanitize_title('divi-booster-' . DIVI5_MODULE_SLUG . '-' . DIVI5_SETTING_SLUG);
    wp_register_script($handle, '', ['lodash', 'divi-vendor-wp-hooks'], null, true);
    wp_enqueue_script($handle);
    wp_add_inline_script($handle, get_divi5_inline_js());
}

function get_divi5_inline_js() {
    $attr  = wp_json_encode(get_divi5_attribute_definition());
    $d4slug = wp_json_encode(DIVI4_MODULE_SLUG);
    $d5key  = wp_json_encode(DIVI5_SETTING_SLUG);
    $d4key  = wp_json_encode(DIVI4_SETTING_SLUG);
    return <<<JS
// Adds the custom attribute to the Gallery module and sets up OR-visibility.
(function(){
  const hooks = window.vendor?.wp?.hooks; if (!hooks) return; const { addFilter } = hooks;
  addFilter('divi.moduleLibrary.moduleAttributes.divi.gallery', 'divi', (attributes) => {
    attributes[{$d5key}] = {$attr};
    // Add visible callback to separator field (OR logic: slider OR lightbox enabled)
    var item = attributes[{$d5key}]?.settings?.innerContent?.items?.imageCountSeparator;
        if (item) {
            item.visible = function({ attrs }) {
                try {
                    // Slider layout and slider image count enabled
                    const fullwidth = attrs?.module?.advanced?.fullwidth?.desktop?.value === 'on';
                    const sliderCount = (attrs?.diviboosterImageCount?.desktop?.value ?? attrs?.diviboosterImageCount?.value ?? 'off') === 'on';
                    // Lightbox enabled and show lightbox image count enabled
                    const lightbox = (attrs?.diviboosterShowInLightbox?.desktop?.value ?? 'on') === 'on';
                    const lightboxCount = (attrs?.diviboosterShowLightboxImageCount?.desktop?.value ?? attrs?.diviboosterShowLightboxImageCount?.value ?? 'on') === 'on';
                    return (fullwidth && sliderCount) || (lightbox && lightboxCount);
                } catch(e) { return true; }
            };
        }
    return attributes;
  });
  // Conversion mapping (Divi 4 -> Divi 5)
  addFilter('divi.moduleLibrary.conversion.moduleConversionOutline', 'divi', (outline, name) => {
    if (name !== {$d4slug}) return outline;
    if (!outline.module) outline.module = {};
    outline.module[{$d4key}] = {$d5key} + '.*';
    return outline;
  });
})();
JS;
}

// === Divi 5: Attribute Definition ===
function get_divi5_attribute_definition() {
    return [
        'type'     => 'object',
        'settings' => [
            'innerContent' => [
                'groupType' => 'group-items',
                'items'     => [
                    'imageCountSeparator' => [
                        'groupSlug'   => 'contentElements',
                        'attrName'    => DIVI5_SETTING_SLUG,
                        'label'       => __('Image Count Separator', 'divi-booster'),
                        'description' => __('Customize the text between the current image number and total images.', 'divi-booster'),
                        'features'    => [ 'hover' => false, 'sticky' => false, 'responsive' => false, 'preset' => 'elements' ],
                        'render'      => true,
                        'priority'    => 99,
                        'component'   => [ 'type' => 'field', 'name' => 'divi/text' ],
                        'defaultAttr' => [ 'desktop' => [ 'value' => __(' of ', 'divi-booster') ] ],
                    ],
                ],
            ],
        ],
    ];
}

// === Front-end JS (Once) ===
function output_frontend_script_once() {
    static $done = false; if ($done) return; $done = true;
?>
<script>
(function($){
    if(!$) return;
  function getSepFromGallery($gallery){
    var sep = ($gallery.find('.et_pb_gallery_items').attr('data-dbdb-image-count-separator'));
    if (typeof sep === 'undefined' || sep === null) sep = ' of ';
    return sep;
  }
  function applySliderCounterSeparator($gallery){
    var $counter = $gallery.find('.dbdb-slide-counter').first();
    if (!$counter.length) return;
    var $active = $counter.find('.dbdb-slide-counter-active').first();
    var $total  = $counter.find('.dbdb-slide-counter-total').first();
    if (!$active.length || !$total.length) return;
        var outer = function($el){
            var node = ($el && $el[0]) ? $el[0] : null;
            if (node && typeof node.outerHTML === 'string') return node.outerHTML;
            return $el ? $el.text() : '';
        };
    var s = getSepFromGallery($gallery);
        $counter.html(outer($active) + s + outer($total));
    $counter.addClass('dbdb-counter-ready');
  }
  $(function(){
            $('.et_pb_gallery').each(function(){
                var $g = $(this);
            applySliderCounterSeparator($g);
            // One follow-up pass after dynamic slider activation / lazy content
            setTimeout(function(){ applySliderCounterSeparator($g); }, 80);
    // Ensure lightbox counter template is updated before first open
    ensureLightboxTemplate($g);
        });

        // Helper: set lightbox template if magnificPopup instance available
        function setLightboxTemplate($gallery){
            var $items = $gallery.find('.et_pb_gallery_items');
            if (!$items.length) return false;
            var mp = $items.data('magnificPopup');
            if (mp && mp.gallery){
                mp.gallery.tCounter = '%curr%' + getSepFromGallery($gallery) + '%total%';
                return true;
            }
            return false;
        }
        // Ensure template applied with limited retries (covers delayed MP init)
        function ensureLightboxTemplate($gallery){
            var attempts = 0, maxAttempts = 12; // ~ < 1s at 60ms
            (function trySet(){
                if (setLightboxTemplate($gallery)) return;
                if (attempts++ < maxAttempts) setTimeout(trySet, 60);
            })();
        }
        // On click attempt immediate + post-init pass (Divi may init on demand)
        $(document).on('click', '.et_pb_gallery .et_pb_gallery_image a', function(){
            var $gallery = $(this).closest('.et_pb_gallery');
            // Try now (in case already initialized)
            if (!setLightboxTemplate($gallery)) {
                // Fallback shortly after (after Divi's own handler runs)
                setTimeout(function(){ setLightboxTemplate($gallery) || ensureLightboxTemplate($gallery); }, 0);
            }
        });

    // Re-apply separator after custom slide change events (from related features)
    $(document).on('divi-booster:gallery-slide-changed', '.et_pb_gallery', function(){ applySliderCounterSeparator($(this)); });
  });
    window.applySliderCounterSeparator = applySliderCounterSeparator;
})(window.jQuery);
</script>
<?php
}

// === Divi 4 Builder/Admin UI visibility helper ===
function output_d4_ui_visibility_js_once() {
    static $done = false; if ($done) return; $done = true;
?>
<script>
(function($){
    if(!$) return;
  function findFieldRow(){
    // VB modal field
    var $inp = $('input[name="<?php echo esc_js(DIVI4_SETTING_SLUG); ?>"], textarea[name="<?php echo esc_js(DIVI4_SETTING_SLUG); ?>"]');
    if (!$inp.length) return $();
    var $row = $inp.closest('.et-fb-form__group');
    if ($row.length) return $row;
    // Back-end settings
    return $inp.closest('.et_pb_option');
  }
  function getVal(name){ var $f = $('[name="'+name+'"]').first(); return $f.length ? $f.val() : null; }
  function updateVisibility(){
    var $row = findFieldRow(); if (!$row.length) return;
    var fullwidth = getVal('fullwidth') || 'off';
    var lightbox  = getVal('dbdb_show_in_lightbox');
    if (lightbox === null || typeof lightbox === 'undefined') lightbox = 'on'; // assume enabled if control absent
    var show = (fullwidth === 'on') || (lightbox !== 'off');
    $row.toggle(!!show);
  }
    var iv=null; $(document).on('et_fb_loaded et_fb_setting:change', function(){ updateVisibility(); });
  $(function(){ updateVisibility(); if (!iv) { iv = setInterval(updateVisibility, 500); } });
})(window.jQuery);
</script>
<?php
}

// === Common Helpers ===
function resolve_separator_from_props($props) {
    // Divi 4 flat
    if (isset($props[DIVI4_SETTING_SLUG]) && is_string($props[DIVI4_SETTING_SLUG])) {
        return $props[DIVI4_SETTING_SLUG];
    }
    // Divi 5 structured
    if (isset($props[DIVI5_SETTING_SLUG]['desktop']['value']) && is_string($props[DIVI5_SETTING_SLUG]['desktop']['value'])) {
        return $props[DIVI5_SETTING_SLUG]['desktop']['value'];
    }
    if (isset($props[DIVI5_SETTING_SLUG]['value']) && is_string($props[DIVI5_SETTING_SLUG]['value'])) {
        return $props[DIVI5_SETTING_SLUG]['value'];
    }
    // Default
    return __(' of ', 'divi-booster');
}

function inject_separator_attr_into_gallery_items($content, $separator) {
    if (!is_string($content) || $content === '') return $content;
    $attr_name  = 'data-dbdb-image-count-separator';
    $attr_value = esc_attr($separator);
    // Append or replace the data attribute on the first element with class et_pb_gallery_items
    $out = preg_replace_callback(
        '/<([a-z0-9\-]+)([^>]*)class="([^"]*\bet_pb_gallery_items\b[^"]*)"/i',
        function($m) use ($attr_name, $attr_value) {
            $tag = $m[1]; $before = $m[2]; $classes = $m[3];
            if (stripos($before, $attr_name.'=') === false) {
                $before .= ' ' . $attr_name . '="' . $attr_value . '"';
            } else {
                $before = preg_replace('/' . preg_quote($attr_name, '/') . '\\s*=\\s*"[^"]*"/i', $attr_name . '="' . $attr_value . '"', $before);
            }
            return '<' . $tag . $before . 'class="' . $classes . '"';
        },
        $content,
        1
    );
    return $out ?: $content;
}

// Created at 1757562275.
