*/ public function get_categories() { return array( 'dadan' ); } /** * @return array */ public function get_keywords() { return array( 'dadan', 'record', 'camera', 'screen', 'sdk' ); } /** * Output depends on the visitor (access gate) — disable Elementor element cache (DADAN-37). * * @return bool */ public function is_dynamic_content(): bool { return true; } /** * Elementor switcher → bool. * * @param mixed $value Control value. * @return bool */ private function switch_on( $value ) { return in_array( (string) $value, array( 'yes', '1', 'true' ), true ); } /** * Resolve a COLOR control value, including Elementor Global Colors (__globals__). * * @param array $settings Widget settings from get_settings_for_display(). * @param string $key Control id. * @param string $fallback Fallback color. * @return string */ private function resolve_color( array $settings, $key, $fallback = '' ) { $direct = isset( $settings[ $key ] ) ? trim( (string) $settings[ $key ] ) : ''; if ( '' !== $direct && 0 !== strpos( $direct, 'globals/' ) ) { return $direct; } $global_ref = ''; if ( ! empty( $settings['__globals__'][ $key ] ) ) { $global_ref = (string) $settings['__globals__'][ $key ]; } elseif ( 0 === strpos( $direct, 'globals/' ) ) { $global_ref = $direct; } if ( '' === $global_ref ) { return $fallback; } $color_id = ''; if ( preg_match( '/(?:globals\/colors\?id=|e-global-color-)([a-z0-9_-]+)/i', $global_ref, $m ) ) { $color_id = $m[1]; } if ( '' === $color_id ) { return $fallback; } $resolved = $this->kit_color_by_id( $color_id ); return '' !== $resolved ? $resolved : $fallback; } /** * Look up a global color hex/rgb from the active Elementor kit. * * @param string $color_id Kit color _id (primary, secondary, text, accent, or custom). * @return string */ private function kit_color_by_id( $color_id ) { if ( ! class_exists( '\Elementor\Plugin' ) ) { return ''; } $kits = \Elementor\Plugin::$instance->kits_manager; if ( ! $kits || ! method_exists( $kits, 'get_active_kit_for_frontend' ) ) { return ''; } $kit = $kits->get_active_kit_for_frontend(); if ( ! $kit || ! method_exists( $kit, 'get_settings_for_display' ) ) { return ''; } foreach ( array( 'system_colors', 'custom_colors' ) as $group ) { $colors = $kit->get_settings_for_display( $group ); if ( ! is_array( $colors ) ) { continue; } foreach ( $colors as $row ) { if ( ! is_array( $row ) || empty( $row['_id'] ) ) { continue; } if ( (string) $row['_id'] === (string) $color_id && ! empty( $row['color'] ) ) { return trim( (string) $row['color'] ); } } } return ''; } /** * Shared args so COLOR controls get a working Global Colors globe + picker refresh. * * @param string $css_var Custom property name (without --). * @param array $extra Extra control args. * @return array */ private function color_control_args( $css_var, array $extra = array() ) { $args = array( 'type' => \Elementor\Controls_Manager::COLOR, // Prefer opaque hex — Record studio CSS vars are solid colors. 'alpha' => false, 'global' => array( 'active' => true, ), // selectors required so Global Colors apply/refresh in the editor. 'selectors' => array( '{{WRAPPER}}' => '--dadan-' . $css_var . ': {{VALUE}};', ), ); return array_merge( $args, $extra ); } /** * Map widget controls → settings array (pre-sanitize). * * @param array $settings Elementor settings. * @return array */ private function settings_from_controls( array $settings ) { $modes = isset( $settings['feature_modes'] ) ? $settings['feature_modes'] : array(); if ( ! is_array( $modes ) ) { $modes = array_filter( array_map( 'trim', explode( ',', (string) $modes ) ) ); } $surfaces = isset( $settings['screen_surfaces'] ) ? $settings['screen_surfaces'] : array(); if ( ! is_array( $surfaces ) ) { $surfaces = array_filter( array_map( 'trim', explode( ',', (string) $surfaces ) ) ); } $image_id = 0; if ( ! empty( $settings['cta_image']['id'] ) ) { $image_id = absint( $settings['cta_image']['id'] ); } elseif ( ! empty( $settings['cta_image_id'] ) ) { $image_id = absint( $settings['cta_image_id'] ); } $bg = Dadan_Settings::DADAN_BG; $fg = Dadan_Settings::DADAN_FG; return array( 'public_app_id' => isset( $settings['public_app_id'] ) ? $settings['public_app_id'] : '', 'video_title' => isset( $settings['video_title'] ) ? $settings['video_title'] : 'Website recording', 'recording_quality' => isset( $settings['recording_quality'] ) ? $settings['recording_quality'] : '1080p', 'default_mode' => isset( $settings['default_mode'] ) ? $settings['default_mode'] : 'both', 'folder_id' => isset( $settings['folder_id'] ) ? $settings['folder_id'] : '', 'team_id' => isset( $settings['team_id'] ) ? $settings['team_id'] : '', 'mount' => isset( $settings['mount'] ) ? $settings['mount'] : 'shadow', 'locale' => isset( $settings['locale'] ) ? $settings['locale'] : 'en', 'countdown_seconds' => isset( $settings['countdown_seconds'] ) ? $settings['countdown_seconds'] : 3, 'insert_button_text' => isset( $settings['insert_button_text'] ) ? $settings['insert_button_text'] : 'Done', 'feature_modes' => $modes, 'feature_mode_picker' => $this->switch_on( isset( $settings['feature_mode_picker'] ) ? $settings['feature_mode_picker'] : 'yes' ), 'feature_camera_picker' => $this->switch_on( isset( $settings['feature_camera_picker'] ) ? $settings['feature_camera_picker'] : 'yes' ), 'feature_mic_picker' => $this->switch_on( isset( $settings['feature_mic_picker'] ) ? $settings['feature_mic_picker'] : 'yes' ), 'feature_system_audio' => $this->switch_on( isset( $settings['feature_system_audio'] ) ? $settings['feature_system_audio'] : 'yes' ), 'feature_backdrop' => $this->switch_on( isset( $settings['feature_backdrop'] ) ? $settings['feature_backdrop'] : 'yes' ), 'feature_deck_grip' => $this->switch_on( isset( $settings['feature_deck_grip'] ) ? $settings['feature_deck_grip'] : 'yes' ), 'feature_close_button' => $this->switch_on( isset( $settings['feature_close_button'] ) ? $settings['feature_close_button'] : 'yes' ), 'feature_restore_pending' => $this->switch_on( isset( $settings['feature_restore_pending'] ) ? $settings['feature_restore_pending'] : 'yes' ), 'theme_primary' => $this->resolve_color( $settings, 'theme_primary', $bg ), 'theme_appearance' => isset( $settings['theme_appearance'] ) ? $settings['theme_appearance'] : 'light', 'theme_font_family' => isset( $settings['theme_font_family'] ) ? $settings['theme_font_family'] : '', 'theme_border_radius' => isset( $settings['theme_border_radius'] ) ? $settings['theme_border_radius'] : '', 'theme_logo_url' => isset( $settings['theme_logo_url'] ) ? $settings['theme_logo_url'] : '', 'theme_surface' => $this->resolve_color( $settings, 'theme_surface', '' ), 'theme_surface_muted' => $this->resolve_color( $settings, 'theme_surface_muted', '' ), 'theme_ink' => $this->resolve_color( $settings, 'theme_ink', '' ), 'theme_ink_soft' => $this->resolve_color( $settings, 'theme_ink_soft', '' ), 'theme_ink_muted' => $this->resolve_color( $settings, 'theme_ink_muted', '' ), 'theme_border' => $this->resolve_color( $settings, 'theme_border', '' ), 'theme_border_strong' => $this->resolve_color( $settings, 'theme_border_strong', '' ), 'theme_danger' => $this->resolve_color( $settings, 'theme_danger', '' ), 'theme_success' => $this->resolve_color( $settings, 'theme_success', '' ), 'theme_shadow' => isset( $settings['theme_shadow'] ) ? $settings['theme_shadow'] : '', 'screen_surfaces_set' => 1, 'screen_surfaces' => $surfaces, 'screen_prefer_current_tab' => $this->switch_on( isset( $settings['screen_prefer_current_tab'] ) ? $settings['screen_prefer_current_tab'] : '' ), 'screen_self_browser' => isset( $settings['screen_self_browser'] ) ? $settings['screen_self_browser'] : '', 'screen_surface_switching' => isset( $settings['screen_surface_switching'] ) ? $settings['screen_surface_switching'] : '', 'screen_monitor_type' => isset( $settings['screen_monitor_type'] ) ? $settings['screen_monitor_type'] : '', 'dispatch_browser_events' => $this->switch_on( isset( $settings['dispatch_browser_events'] ) ? $settings['dispatch_browser_events'] : 'yes' ), 'front_record_access' => isset( $settings['front_record_access'] ) ? $settings['front_record_access'] : '', 'cta_preset' => isset( $settings['cta_preset'] ) ? $settings['cta_preset'] : 'dadan', 'cta_variant' => isset( $settings['cta_variant'] ) ? $settings['cta_variant'] : 'icon', 'cta_label' => isset( $settings['cta_label'] ) ? $settings['cta_label'] : '', 'cta_bg' => $this->resolve_color( $settings, 'cta_bg', $bg ), 'cta_fg' => $this->resolve_color( $settings, 'cta_fg', $fg ), 'cta_shape' => isset( $settings['cta_shape'] ) ? $settings['cta_shape'] : 'rounded', 'cta_size' => isset( $settings['cta_size'] ) ? $settings['cta_size'] : 'md', 'cta_image_id' => $image_id, 'cta_hide_on_phones' => $this->switch_on( isset( $settings['cta_hide_on_phones'] ) ? $settings['cta_hide_on_phones'] : 'yes' ), 'cta_custom_class' => isset( $settings['cta_custom_class'] ) ? $settings['cta_custom_class'] : '', 'cta_custom_id' => isset( $settings['cta_custom_id'] ) ? $settings['cta_custom_id'] : '', ); } /** * Elementor panel notice (info / warning / success styling). * * @param string $id Control id. * @param string $html Trusted, already-escaped HTML. * @param string $kind info|warning|success. */ private function add_notice( $id, $html, $kind = 'info' ) { $this->add_control( $id, array( 'type' => \Elementor\Controls_Manager::RAW_HTML, 'raw' => $html, 'content_classes' => 'elementor-panel-alert elementor-panel-alert-' . $kind . ' dadan-el-notice', ) ); } /** * Register all Record settings as Elementor controls. * * Control ids, defaults and value sets are unchanged from 2.1.x so saved pages * keep their settings; only grouping, order, labels and control types changed. */ protected function register_controls() { $d = Dadan_Settings::defaults(); $is_admin = current_user_can( 'manage_options' ); $default_id = class_exists( 'Dadan_Instance' ) ? Dadan_Instance::default_id() : 0; $def_app = ''; if ( $default_id ) { $def_settings = Dadan_Instance::get_settings( $default_id ); $def_app = isset( $def_settings['public_app_id'] ) ? (string) $def_settings['public_app_id'] : ''; } $def_ok = Dadan_Settings::is_valid_public_app_id( $def_app ); $inst_url = admin_url( 'edit.php?post_type=' . Dadan_Instance::POST_TYPE ); /* ================= Content ================= */ /* —— Record button —— */ $this->start_controls_section( 'section_cta', array( 'label' => __( 'Record button', 'dadan' ), 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, ) ); $this->add_control( 'cta_preset', array( 'label' => __( 'Button', 'dadan' ), 'type' => \Elementor\Controls_Manager::CHOOSE, 'default' => $d['cta_preset'], 'toggle' => false, 'options' => array( 'dadan' => array( 'title' => __( 'Dadan button', 'dadan' ), 'icon' => 'eicon-video-camera', ), 'custom' => array( 'title' => __( 'Custom', 'dadan' ), 'icon' => 'eicon-paint-brush', ), ), 'description' => __( 'Dadan button is the recommended default. Choose Custom to match your site.', 'dadan' ), ) ); $this->add_control( 'cta_variant', array( 'label' => __( 'Type', 'dadan' ), 'type' => \Elementor\Controls_Manager::CHOOSE, 'default' => $d['cta_variant'], 'toggle' => false, 'options' => array( 'icon' => array( 'title' => __( 'Icon', 'dadan' ), 'icon' => 'eicon-video-camera', ), 'button' => array( 'title' => __( 'Text button', 'dadan' ), 'icon' => 'eicon-t-letter', ), 'image' => array( 'title' => __( 'Image', 'dadan' ), 'icon' => 'eicon-image-bold', ), ), 'condition' => array( 'cta_preset' => 'custom' ), ) ); $this->add_control( 'cta_label', array( 'label' => __( 'Label', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', 'placeholder' => __( 'Open recorder', 'dadan' ), 'label_block' => true, 'description' => __( 'Button text, and the name screen readers announce for icon buttons.', 'dadan' ), ) ); $this->add_control( 'cta_image', array( 'label' => __( 'Image', 'dadan' ), 'type' => \Elementor\Controls_Manager::MEDIA, 'default' => array( 'url' => '', 'id' => '', ), 'description' => __( 'Square PNG or SVG. Empty uses the Dadan mark.', 'dadan' ), 'condition' => array( 'cta_preset' => 'custom', 'cta_variant' => array( 'icon', 'image' ), ), ) ); $this->add_control( 'cta_hide_on_phones', array( 'label' => __( 'Hide on phones', 'dadan' ), 'type' => \Elementor\Controls_Manager::SWITCHER, 'label_on' => __( 'Yes', 'dadan' ), 'label_off' => __( 'No', 'dadan' ), 'return_value' => 'yes', 'default' => 'yes', 'separator' => 'before', 'description' => __( 'Screen recording is unreliable on mobile browsers.', 'dadan' ), ) ); $this->end_controls_section(); /* —— Recording —— */ $this->start_controls_section( 'section_studio', array( 'label' => __( 'Recording', 'dadan' ), 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, ) ); $mode_options = array( 'both' => __( 'Screen + camera', 'dadan' ), 'camera' => __( 'Camera only', 'dadan' ), 'screen' => __( 'Screen only', 'dadan' ), ); $this->add_control( 'feature_modes', array( 'label' => __( 'Allowed modes', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT2, 'multiple' => true, 'label_block' => true, 'default' => $d['feature_modes'], 'options' => $mode_options, ) ); $this->add_control( 'default_mode', array( 'label' => __( 'Starts in', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => $d['default_mode'], 'options' => $mode_options, 'description' => __( 'Must be one of the allowed modes.', 'dadan' ), ) ); $this->add_control( 'recording_quality', array( 'label' => __( 'Quality', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => $d['recording_quality'], 'options' => array( '720p' => '720p', '1080p' => '1080p', '2k' => '2K', ), ) ); $this->add_control( 'countdown_seconds', array( 'label' => __( 'Countdown (sec)', 'dadan' ), 'type' => \Elementor\Controls_Manager::NUMBER, 'min' => 0, 'max' => 10, 'step' => 1, 'default' => (int) $d['countdown_seconds'], 'description' => __( '0 starts recording immediately.', 'dadan' ), ) ); $this->add_control( 'insert_button_text', array( 'label' => __( 'Finish button text', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => $d['insert_button_text'], ) ); $this->add_control( 'studio_controls_heading', array( 'label' => __( 'Studio controls', 'dadan' ), 'type' => \Elementor\Controls_Manager::HEADING, 'separator' => 'before', ) ); foreach ( array( 'feature_mode_picker' => __( 'Mode picker', 'dadan' ), 'feature_camera_picker' => __( 'Camera picker', 'dadan' ), 'feature_mic_picker' => __( 'Microphone picker', 'dadan' ), 'feature_system_audio' => __( 'System / tab audio', 'dadan' ), 'feature_backdrop' => __( 'Backdrop picker', 'dadan' ), 'feature_deck_grip' => __( 'Drag handle', 'dadan' ), 'feature_close_button' => __( 'Close button', 'dadan' ), 'feature_restore_pending' => __( 'Recover unsent takes', 'dadan' ), ) as $key => $label ) { $this->add_control( $key, array( 'label' => $label, 'type' => \Elementor\Controls_Manager::SWITCHER, 'label_on' => __( 'On', 'dadan' ), 'label_off' => __( 'Off', 'dadan' ), 'return_value' => 'yes', 'default' => ! empty( $d[ $key ] ) ? 'yes' : '', ) ); } $this->end_controls_section(); /* —— Connection —— */ $this->start_controls_section( 'section_general', array( 'label' => __( 'Connection', 'dadan' ), 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, ) ); if ( $def_ok ) { $this->add_notice( 'settings_notice', '' . esc_html__( 'Connected', 'dadan' ) . ' ' . esc_html__( 'This widget uses the App ID from your Default instance. Override it below only if this button should upload to a different Dadan app.', 'dadan' ), 'success' ); } else { $this->add_notice( 'settings_notice', '' . esc_html__( 'Not connected yet', 'dadan' ) . ' ' . sprintf( /* translators: %s: link to Dadan Instances admin screen */ esc_html__( 'Add a public App ID below, or once for the whole site in %s.', 'dadan' ), '' . esc_html__( 'Dadan → Instances', 'dadan' ) . '' ), 'warning' ); } if ( $is_admin ) { $this->add_control( 'public_app_id', array( 'label' => __( 'Public App ID', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', 'placeholder' => $def_ok ? $def_app : 'app_…', 'label_block' => true, 'description' => __( 'Optional override. Starts with app_; never a secret API key. Allow this site\'s origin in Dadan.', 'dadan' ), ) ); } else { $this->add_notice( 'public_app_id_notice', esc_html__( 'Only administrators can change the App ID. This widget uses the Default instance.', 'dadan' ) ); } $this->add_control( 'video_title', array( 'label' => __( 'Default video title', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => $d['video_title'], 'label_block' => true, ) ); if ( $is_admin ) { $this->add_control( 'folder_id', array( 'label' => __( 'Folder ID', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', 'label_block' => true, 'placeholder' => __( 'Optional', 'dadan' ), 'description' => __( 'Upload destination. Takes priority over Team ID.', 'dadan' ), ) ); $this->add_control( 'team_id', array( 'label' => __( 'Team ID', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', 'label_block' => true, 'placeholder' => __( 'Optional', 'dadan' ), 'description' => __( 'Ignored when a Folder ID is set.', 'dadan' ), ) ); } $this->end_controls_section(); /* —— Access & screen sharing —— */ $this->start_controls_section( 'section_advanced_dadan', array( 'label' => __( 'Access & screen sharing', 'dadan' ), 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, ) ); if ( $is_admin ) { $this->add_control( 'front_record_access', array( 'label' => __( 'Who can record', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => '', 'label_block' => true, 'options' => array( '' => __( 'Same as Default instance', 'dadan' ), 'anyone' => __( 'Anyone', 'dadan' ), 'logged_in' => __( 'Logged-in users', 'dadan' ), 'edit_posts' => __( 'Editors and above', 'dadan' ), ), 'description' => __( 'Others don\'t see the button.', 'dadan' ), ) ); } $this->add_control( 'screen_surfaces', array( 'label' => __( 'Screen share offers', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT2, 'multiple' => true, 'label_block' => true, 'default' => $d['screen_surfaces'], 'options' => array( 'monitor' => __( 'Entire screen', 'dadan' ), 'window' => __( 'Window', 'dadan' ), 'browser' => __( 'Browser tab', 'dadan' ), ), 'separator' => $is_admin ? 'before' : 'none', 'description' => __( 'The first is suggested first. Pick only Browser tab for tab-only capture.', 'dadan' ), ) ); $this->add_control( 'screen_prefer_current_tab', array( 'label' => __( 'Prefer current tab', 'dadan' ), 'type' => \Elementor\Controls_Manager::SWITCHER, 'return_value' => 'yes', 'default' => '', ) ); $include_opts = array( '' => __( 'Browser default', 'dadan' ), 'include' => __( 'Include', 'dadan' ), 'exclude' => __( 'Exclude', 'dadan' ), ); $this->add_control( 'screen_dialog_heading', array( 'label' => __( 'Share dialog', 'dadan' ), 'type' => \Elementor\Controls_Manager::HEADING, 'separator' => 'before', ) ); $this->add_control( 'screen_self_browser', array( 'label' => __( 'This tab in the list', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => '', 'options' => $include_opts, ) ); $this->add_control( 'screen_surface_switching', array( 'label' => __( 'Switch while sharing', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => '', 'options' => $include_opts, ) ); $this->add_control( 'screen_monitor_type', array( 'label' => __( 'Whole screens', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => '', 'options' => $include_opts, ) ); $this->add_control( 'developer_heading', array( 'label' => __( 'Developer', 'dadan' ), 'type' => \Elementor\Controls_Manager::HEADING, 'separator' => 'before', ) ); $locale_opts = array(); foreach ( Dadan_Settings::supported_locales() as $code => $label ) { $locale_opts[ $code ] = $label . ' (' . $code . ')'; } $this->add_control( 'locale', array( 'label' => __( 'Studio language', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => $d['locale'], 'options' => $locale_opts, ) ); $this->add_control( 'mount', array( 'label' => __( 'Style isolation', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => $d['mount'], 'options' => array( 'light' => __( 'Inherit theme CSS', 'dadan' ), 'shadow' => __( 'Isolated', 'dadan' ), ), ) ); $this->add_control( 'dispatch_browser_events', array( 'label' => __( 'Browser events', 'dadan' ), 'type' => \Elementor\Controls_Manager::SWITCHER, 'return_value' => 'yes', 'default' => 'yes', 'description' => __( 'Fires window events like dadan:recording.completed.', 'dadan' ), ) ); $this->add_control( 'cta_custom_class', array( 'label' => __( 'Button CSS classes', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', 'label_block' => true, ) ); $this->add_control( 'cta_custom_id', array( 'label' => __( 'Button element ID', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', 'label_block' => true, ) ); $this->end_controls_section(); /* ================= Style ================= */ /* —— Button style —— */ $this->start_controls_section( 'section_cta_style', array( 'label' => __( 'Record button', 'dadan' ), 'tab' => \Elementor\Controls_Manager::TAB_STYLE, 'condition' => array( 'cta_preset' => 'custom' ), ) ); $this->add_control( 'cta_shape', array( 'label' => __( 'Shape', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => $d['cta_shape'], 'options' => array( 'rounded' => __( 'Rounded', 'dadan' ), 'pill' => __( 'Pill', 'dadan' ), 'square' => __( 'Square', 'dadan' ), ), ) ); $this->add_control( 'cta_size', array( 'label' => __( 'Size', 'dadan' ), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => $d['cta_size'], 'options' => array( 'sm' => __( 'Small', 'dadan' ), 'md' => __( 'Medium', 'dadan' ), 'lg' => __( 'Large', 'dadan' ), ), ) ); $this->add_control( 'cta_bg', $this->color_control_args( 'cta-bg', array( 'label' => __( 'Background', 'dadan' ), 'default' => $d['cta_bg'], 'separator' => 'before', 'condition' => array( 'cta_variant' => 'button' ), ) ) ); $this->add_control( 'cta_fg', $this->color_control_args( 'cta-fg', array( 'label' => __( 'Text', 'dadan' ), 'default' => $d['cta_fg'], 'condition' => array( 'cta_variant' => 'button' ), ) ) ); $this->end_controls_section(); /* —— Studio theme —— */ $this->start_controls_section( 'section_theme', array( 'label' => __( 'Studio theme', 'dadan' ), 'tab' => \Elementor\Controls_Manager::TAB_STYLE, ) ); $this->add_notice( 'theme_notice', esc_html__( 'Styles the recording studio that opens after a click. Preview it on the live page.', 'dadan' ) ); $this->add_control( 'theme_primary', $this->color_control_args( 'theme-primary', array( 'label' => __( 'Accent', 'dadan' ), 'default' => $d['theme_primary'], ) ) ); $this->add_control( 'theme_appearance', array( 'label' => __( 'Appearance', 'dadan' ), 'type' => \Elementor\Controls_Manager::CHOOSE, 'default' => $d['theme_appearance'], 'toggle' => false, 'options' => array( 'light' => array( 'title' => __( 'Light', 'dadan' ), 'icon' => 'eicon-light-mode', ), 'dark' => array( 'title' => __( 'Dark', 'dadan' ), 'icon' => 'eicon-dark-mode', ), ), ) ); $this->add_control( 'theme_font_family', array( 'label' => __( 'Font family', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', 'label_block' => true, 'placeholder' => '"Inter", system-ui', ) ); $this->add_control( 'theme_border_radius', array( 'label' => __( 'Corner radius', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', 'placeholder' => '12px', ) ); $this->add_control( 'theme_logo_url', array( 'label' => __( 'Logo URL', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', 'label_block' => true, 'placeholder' => 'https://', 'description' => __( 'Saved now; shown once the studio supports logos.', 'dadan' ), ) ); $this->add_control( 'theme_extended_heading', array( 'label' => __( 'Fine-tune colors', 'dadan' ), 'type' => \Elementor\Controls_Manager::HEADING, 'separator' => 'before', ) ); $this->add_notice( 'theme_extended_notice', esc_html__( 'Optional. Empty uses the studio defaults; Dark fills these in automatically.', 'dadan' ) ); foreach ( array( 'theme_surface' => __( 'Surface', 'dadan' ), 'theme_surface_muted' => __( 'Surface muted', 'dadan' ), 'theme_ink' => __( 'Text', 'dadan' ), 'theme_ink_soft' => __( 'Text soft', 'dadan' ), 'theme_ink_muted' => __( 'Text muted', 'dadan' ), 'theme_border' => __( 'Border', 'dadan' ), 'theme_border_strong' => __( 'Border strong', 'dadan' ), 'theme_danger' => __( 'Danger', 'dadan' ), 'theme_success' => __( 'Success', 'dadan' ), ) as $key => $label ) { $this->add_control( $key, $this->color_control_args( str_replace( '_', '-', $key ), array( 'label' => $label, 'default' => '', ) ) ); } $this->add_control( 'theme_shadow', array( 'label' => __( 'Deck shadow', 'dadan' ), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => '', 'label_block' => true, 'placeholder' => '0 12px 32px rgba(0,0,0,.14)', ) ); $this->end_controls_section(); } /** * Front-end / preview render — settings come only from this widget. */ protected function render() { $settings = $this->get_settings_for_display(); $raw = $this->settings_from_controls( $settings ); $is_edit = \Elementor\Plugin::$instance->editor->is_edit_mode(); /* * DADAN-03 residual / NEW-1: trust stored App ID / folder / team / access only when * the Elementor document author is an admin. Clears pre-fix attacker values on * non-admin-authored pages; keeps admin-authored widget overrides for visitors. */ $doc_id = 0; $doc = \Elementor\Plugin::$instance->documents->get_current(); if ( $doc ) { $doc_id = (int) $doc->get_main_id(); } if ( ! $doc_id ) { $doc_id = (int) get_the_ID(); } $trust_creds = Dadan_Settings::placement_author_can_set_credentials( $doc_id ); if ( ! $trust_creds || ( $is_edit && ! current_user_can( 'manage_options' ) ) ) { $raw['public_app_id'] = ''; $raw['folder_id'] = ''; $raw['team_id'] = ''; $raw['front_record_access'] = ''; } // Empty / invalid per-widget App ID → Default Instance. if ( ! Dadan_Settings::is_valid_public_app_id( isset( $raw['public_app_id'] ) ? $raw['public_app_id'] : '' ) ) { $default_id = class_exists( 'Dadan_Instance' ) ? Dadan_Instance::default_id() : 0; if ( $default_id ) { $inst = Dadan_Instance::get_settings( $default_id ); $raw = array_merge( $inst, array_filter( $raw, static function ( $v ) { return ! ( '' === $v || null === $v || array() === $v ); } ) ); $raw['screen_surfaces_set'] = 1; if ( empty( $raw['public_app_id'] ) && ! empty( $inst['public_app_id'] ) ) { $raw['public_app_id'] = $inst['public_app_id']; } } } if ( '' === trim( (string) ( isset( $raw['front_record_access'] ) ? $raw['front_record_access'] : '' ) ) ) { $default_id = class_exists( 'Dadan_Instance' ) ? Dadan_Instance::default_id() : 0; if ( $default_id ) { $def = Dadan_Instance::get_settings( $default_id ); if ( ! empty( $def['front_record_access'] ) ) { $raw['front_record_access'] = $def['front_record_access']; } } } $forced = Dadan_Settings::sanitize_array( $raw ); $config = Dadan_Settings::with_forced_settings( $forced, static function () { return Dadan_Settings::recorder_config( 0 ); } ); $app_id = isset( $config['publicAppId'] ) ? trim( (string) $config['publicAppId'] ) : ''; if ( ! Dadan_Settings::is_valid_public_app_id( $app_id ) ) { if ( $is_edit || current_user_can( 'edit_posts' ) ) { echo '
'; echo esc_html__( 'Set a valid Public App ID (app_…) on this widget or the Default Instance.', 'dadan' ); echo '
'; } return; } $allowed = Dadan_Settings::with_forced_settings( $forced, static function () { return Dadan_Settings::visitor_can_record( 0 ); } ); if ( ! $allowed ) { if ( $is_edit || current_user_can( 'edit_posts' ) ) { echo '
'; echo esc_html__( 'Recording is restricted for visitors on this placement.', 'dadan' ); echo '
'; } return; } // Shared recorder bundle (same as Gutenberg / shortcodes). if ( ! $is_edit ) { if ( ! Dadan_Recorder::bundle_ready() ) { if ( current_user_can( 'edit_posts' ) ) { echo '
'; echo esc_html__( 'Recorder unavailable. Reinstall the Dadan plugin or contact the site admin.', 'dadan' ); echo '
'; } return; } Dadan_Record_Shortcode::request_assets( 0 ); } $uid = 'dadan-el-' . $this->get_id(); if ( ! $is_edit ) { Dadan_Record_Shortcode::register_placement( $uid, $config ); // DADAN-21: prefer the shared shortcode enqueue (one localize). // DADAN-25: only enqueue here when wp_footer already ran (late Elementor). if ( did_action( 'wp_footer' ) ) { Dadan_Record_Shortcode::enqueue_now(); } } $btn = Dadan_Settings::with_forced_settings( $forced, static function () use ( $uid ) { return Dadan_Settings::render_trigger_button( array( 'id' => $uid . '-btn', 'class' => 'dadan-el-record-btn dadan-record-trigger', 'label' => '', 'instance_id' => 0, ) ); } ); $wrap = 'dadan-el-record dadan-public-record'; if ( ! empty( $forced['cta_hide_on_phones'] ) ) { $wrap .= ' dadan-hide-on-phone'; } // Credentials live in localized placements (DADAN-02), not data-dadan-config. echo '
'; echo wp_kses( $btn, Dadan_Settings::kses_trigger_button() ); echo '

'; echo '
'; } }