Plugin Directory

Changeset 3429507


Ignore:
Timestamp:
12/30/2025 09:13:50 AM (2 months ago)
Author:
unitecms
Message:

updated to 2.0.2 version.

Location:
unlimited-elements-for-elementor/trunk
Files:
40 edited

Legend:

Unmodified
Added
Removed
  • unlimited-elements-for-elementor/trunk/assets_libraries/filters/ue_filters.js

    r3379552 r3429507  
    99    var t = this;
    1010
    11     var g_showDebug = false;
     11    var g_showDebug = true;
    1212    var g_debugInitMode = false;
    1313   
     
    462462        if(!isInitAfter)
    463463            isInitAfter = isSpecialFilterInitAfter(objFilter, objGrid);
    464                
     464       
    465465        if(g_showDebug){
    466466            trace("init after: "+isInitAfter);
     
    22752275        operateAjax_setHtmlSyngGrids(response, objGrid, isLoadMore);
    22762276       
    2277         objGrid.trigger(g_vars.EVENT_AJAX_REFRESHED);
     2277        objGrid.trigger(g_vars.EVENT_AJAX_REFRESHED,[{isLoadMore:isLoadMore}]);
    22782278        g_objBody.trigger(g_vars.EVENT_AJAX_REFRESHED_BODY, [objGrid]);
    2279 
     2279       
    22802280        //trigger body as well
    22812281
     
    37633763     */
    37643764    function isSpecialFilterInitAfter(objFilter, objGrid){
    3765 
     3765       
    37663766        var type = getFilterType(objFilter);
    3767 
    3768         if(type != g_types.PAGINATION)
     3767               
     3768        if(type != g_types.PAGINATION && type != g_types.LOADMORE)
    37693769            return(false);
    37703770
     
    37753775
    37763776            if(g_showDebug == true)
    3777                 trace("Set pagination to ajax init");
     3777                trace("Set "+type+" to ajax init");
    37783778
    37793779            return(true);
  • unlimited-elements-for-elementor/trunk/changelog.txt

    r3403331 r3429507  
    11
    22== Changelog ==
     3
     4
     5version 2.0.2 2025-12-30 =
     6
     7Plugin Changes:
     8
     9* Feature: add google reviews from serp api feature
     10* Fix - fixed double tax pricing in woocommerce variation
     11* Fix - fixed the entrance animation together with load more issue
     12* Fix - some blocks related bug fixes
     13* Fix - fixed default items not loading js issues
     14* Fix - fixed some small security issue
     15
     16Widgets Changes:
     17
     18* Feature: Unlimited Grid (Pro) - Added Title HTML Tag option for better SEO and accessibility.
     19* Feature: Content Carousel (Free) - Enhanced custom SVG icon support for navigation arrows, and added title and description text shadow options.
     20* Feature: Content Slider (Free) - Added title HTML tag option, improved links by adding link attributes, and introduced Slide Border, Overlay Hover, and Overlay Hover Transition Duration options.
     21* Feature: Video on Hover (Free) - Added a "Schema" option to enable schema markup support for better SEO and AI understand your content for increased visibility in AI powered search features.
     22* Feature: Text Field (Free) - Introduced a dynamic URL Autopopulate feature, allowing fields to automatically retrieve and fill values from custom query string parameters upon page load
     23* Feature: Off Canvas (Pro) - Added Background Color Hover and Text Color Hover options, allowing finer visual control over hover states and enabling consistent styling of the Trigger Button element.
     24* Feature: Side Menu (Free) - Added support for the Conditions widget, enabling seamless control over the Side Menu by allowing it to be opened, closed, or toggled dynamically based on defined conditions
     25* Feature: Conditions (Free) - Added three new actions — UE Open Side Menu, UE Close Side Menu, and UE Toggle Side Menu — allowing full programmatic control over the Side Menu widget behavior
     26* Feature: Snow Background (Free) - Added Speed Mobile option, allowing precise control over animation and interaction speed specifically for mobile devices, ensuring smoother performance, better usability on smaller screens
     27* Feature: Swipe Carousel (Pro) - Added Title Tag option, allowing users to define the HTML tag for the title element to better match the page structure, improve semantic markup, and enhance SEO and accessibility control.
     28* Feature: Grid Gallery (Pro) - Added Enable Link On Main Image option, allowing the main image within each item to function as a clickable link.
     29* Feature: Post Grid (Free) - Made the Title Spacing option fully responsive, allowing different spacing values to be applied across desktop, tablet, and mobile for more precise control of layout and typography.
     30* Feature: Expanding Content Cards (Free) - Added Sub Title option, enabling users to include an additional descriptive text line beneath the main title.
     31* Feature: Vertical Curved Timeline (Free) - Added "Content Vertical Position" option when the image option is enabled, also introduced "Alternate Image Alignment" option for improved design and customization.
     32* Feature: Icon Accordion (Free) - Added multi-source support along with pagination and filtering features, and improved the item color options for easier styling.
     33* Feature: Dynamic Post Popup (Pro) - Added Arrows Type option, introducing support for choosing between icon-based arrows and text-based arrows.
     34* Feature: Portfolio Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked.
     35* Feature: Overlay Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     36* Feature: Material Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked.
     37* Feature: Icon Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     38* Feature: Unlimited Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked.
     39* Feature: Logo Carousel (Free) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     40* Feature: Woo Product Carousel (Free) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked.
     41* Feature: Post Carousel (Free) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     42* Feature: Repeater Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     43* Feature: Flip Box Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     44* Feature: Loop Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     45* Feature: Notification (Free) - The widget's accessibility was improved by replacing the close div with a semantic <button> element, adding the essential aria-label="Close Notification" for screen reader clarity, applying role="status" to the main container for conveying passive informative content.
     46* Feature: Contact Form 7 (Free) - Improved accessibility of the widget by enabling proper keyboard navigation within form elements.
     47* Feature: Fullscreen Menu (Free) - Added Expand Collapse Icon Spacing option, allowing users to precisely control the distance between the expand/collapse icon and the text.
     48* Feature: Gradient Underline Text Effect (Free) - Made the Text Align option responsive, allowing different alignment settings for desktop, tablet, and mobile.
     49* Feature: Post Accordion (Free) - Added Icon Spacing option — introduced a new control that allows adjusting the distance between the icon and its adjacent elements.
     50* Feature: Team Member Carousel (Free) - Added Icon One, Icon Two, Icon Three, Icon Four and Link One, Link Two, Link Three, Link Four options to the Source options
     51* Feature: Unlimited Google Maps (Free) - Added Scroll To Active Navigation Item option, ensuring that navigation automatically scrolls to keep the active item visible.
     52* Feature: 360 Panorama Virtual Tour (Pro) - Enhanced the widget's accessibility by applying ARIA attributes (role, aria-label) and tabindex="0" to interactive controls, allowing keyboard-only users to activate them by simulating a click using the Enter or Space key.
     53* Fix: Repeater Table (Pro) - Accessibility for the widget was improved by implementing the scope="col" attribute on all header cells to explicitly link data to headings
     54* Fix: Restaurant Menu (Free) - Accessibility for the widget was improved by adding role="list" and role="listitem" for better navigation structure, converting the "See More" toggle into a keyboard-accessible button with aria-expanded states.
     55* Fix: Loop Grid (Pro) - Fixed an issue where the “Empty Message Type: Template” was displayed even when the Loop Widget had successfully rendered items, causing the empty state template to appear incorrectly alongside actual content
     56* Fix: Border Hero (Free) - The button field was incorrectly configured as a text field and has now been changed to a proper link field. A security vulnerability was also fixed to improve overall safety and stability.
     57* Fix: Content Grid (Free) - Removed empty links to prevent rendering unnecessary anchor elements and to avoid potential accessibility and SEO issues when link fields are left blank
     58* Fix: Comparison List (Pro) - Fixed an issue where column widths were not working correctly on mobile devices, and resolved RTL layout issues.
     59* Fix: Horizontal Timeline (Free) - Removed empty links to prevent rendering unnecessary anchor elements and to avoid potential accessibility and SEO issues when link fields are left blank.
     60* Fix: Price Range Filter (Pro) - Fixed an issue where slider thumbnail elements were displayed incorrectly on RTL (right-to-left) websites, ensuring proper alignment, order, and interaction consistency across all supported directions
     61* Fix: Random Content (Free) - Accessibility for the Random Content widget was improved by converting the shuffle trigger into a semantic <button>, marking the shuffle icon as aria-hidden="true" to avoid redundant noise, and applying aria-live="polite" to the content container
     62* Fix: Stacking Cards (Free) - Fixed an issue where the Alternate Page Position option was not functioning correctly on the live site and was only applied inside the Elementor editor
     63* Fix: Protected Content (Free) - Accessibility for the Protected Content widget was improved by correcting the form structure to properly link the <label> (title) to the password <input> using the "for" and "id" attributes, adding aria-required="true" to the input
     64* Fix: Cookie Consent (Free) - Accessibility for the Cookie Consent widget was improved by switching interactive <div> elements to semantic <button> tags, and ensuring the main container dynamically uses role="dialog" and aria-modal="true" only when the banner is visible, thereby guiding keyboard and screen reader focus correctly.
     65* Fix: Age Verification (Free) - The Age Verification widget's accessibility was improved by adding role="dialog", aria-modal="true", and descriptive aria-label attributes to all input fields and buttons for better screen reader and keyboard navigation
     66* Fix: Content Tabs (Free) - Fixed an issue where theme-defined padding styles for ul elements were being unintentionally overridden by the widget’s CSS, ensuring better compatibility with various themes and preserving the original list spacing and layout as defined by the active theme
     67* Fix: Image Tooltip (Free) - Added aria-describedby attribute to the main widget wrapper to improve accessibility, and included additional HTML attributes—such as alt for the image—to ensure better semantic structure, screen-reader support, and overall accessibility compliance
     68* Fix: Event Box (Free) - Added ARIA attributes to interactive elements and link labels for improved screen reader compatibility.
     69* Fix: Calendar (Pro) - Increased the CSS priority of the Event Title element, ensuring its styling reliably overrides conflicting theme rules and displays consistently across different layouts and environments.
     70* Fix: Masonry & Justified Gallery (Free) - Fixed an issue where the Tile Text Panel styling options were not appearing in the widget settings panel, ensuring all relevant controls are now properly displayed and accessible for customization.
     71* Fix: Submit Button (Free) - Fixed issue where attempting to proceed to the next step of Multi Source widget from the first page without filling mandatory fields caused unwanted spacing to be repeatedly added to the form
     72* Fix: Vertical Curved Timeline (Free) - Fixed an issue where "Button Spacing" option was not working.
     73* Fix: Vertical Curved Timeline (Free) - Fixed issue where, when the image element was disabled and the content inside an item had a width below 100%, items with an even item count were not aligning correctly to the side, ensuring proper layout consistency across all configurations.
     74* Fix: Justified Image Carousel (Pro) - Fixed an issue on touch devices where opening the lightbox required two taps instead of one, ensuring the lightbox now opens correctly on a single tap for a smoother and more responsive user experience.
     75* Fix: QR Code (Pro) - Accessibility of the QR Code widget was improved by applying role="img" to the SVG container to define it as a graphic and using aria-label to provide the visible title as the accessible name, ensuring screen readers can announce the image's content.
     76* Fix: Animated Mouse Scroll Icon (Free) - The accessibility of the widget was improved by adding aria-label="Scroll Down" and role="button" to the link wrapper and using aria-hidden="true" on the decorative animation elements
     77* Fix: Vertical Curved Timeline (Free) - Fixed issue when button wasn't clickable for all items except last one.
     78* Fix: Repeater Tabs (Free) - Fixed issue when Repeater Tabs couldn't display all content with JSON / CSV Repeater Source.
     79* Fix: Social Share Buttons (Free) - Fixed an issue where the Telegram share option was redirecting to Xing instead of Telegram.
     80* Release: Person Schema (Pro) - Person Schema adds structured data that defines an individual for search engines. Improve SEO by clearly connecting a person to content, roles, and social profiles.
     81
    382
    483version 2.0.1 2025-11-26 =
  • unlimited-elements-for-elementor/trunk/inc_php/framework/google/client.class.php

    r3379552 r3429507  
    6262     */
    6363    protected function get($endpoint, $params = array()){
    64 
     64       
    6565        return $this->request(UEHttpRequest::METHOD_GET, $endpoint, $params);
    6666    }
     
    108108        $url = $this->getBaseUrl() . $endpoint;
    109109        $query = ($method === UEHttpRequest::METHOD_GET) ? $params : array();
    110         $body = ($method !== UEHttpRequest::METHOD_GET) ? $params : array();
     110            $body = ($method !== UEHttpRequest::METHOD_GET) ? $params : array();
    111111
    112112        if(empty($params[self::PARAM_QUERY]) === false){
     
    151151        });
    152152       
     153       
    153154        $response = $request->request($method, $url);
    154155        $data = $response->json();
  • unlimited-elements-for-elementor/trunk/inc_php/framework/google/places/place.class.php

    r2969618 r3429507  
    99     */
    1010    public function getReviews(){
    11 
     11       
    1212        $reviews = $this->getAttribute("reviews", array());
    1313        $reviews = UEGoogleAPIPlaceReview::transformAll($reviews);
    14 
     14       
    1515        return $reviews;
    1616    }
    17 
     17   
     18    /**
     19     * get place info if available
     20     */
     21    public function getPlaceInfo(){
     22       
     23        $arrInfo = $this->getAttribute("place_info");
     24       
     25        return($arrInfo);
     26    }
     27   
     28    /**
     29     * get place info if available
     30     */
     31    public function getSearchParams(){
     32       
     33        $arrParams = $this->getAttribute("search_parameters");
     34       
     35        return($arrParams);
     36    }
     37   
     38    /**
     39     * get search meta data
     40     */
     41    public function getMetaData(){
     42       
     43        $arrParams = $this->getAttribute("search_metadata");
     44       
     45        return($arrParams);
     46    }
     47   
     48   
     49   
    1850}
  • unlimited-elements-for-elementor/trunk/inc_php/framework/google/places/place_review.class.php

    r3329756 r3429507  
    33class UEGoogleAPIPlaceReview extends UEGoogleAPIModel{
    44
     5    private $isSerp = false;
     6   
     7    /**
     8     * set that the review is from serp source
     9     */
     10    public function setSerpSource(){
     11       
     12        $this->isSerp = true;
     13    }
     14   
     15   
    516    /**
    617     * Get the identifier.
     
    2334     */
    2435    public function getText($asHtml = false){
    25 
    26         $text = $this->getAttribute("text");
    27 
     36       
     37        $name = "text";
     38        if($this->isSerp == true)
     39            $name = "snippet";
     40       
     41        $text = $this->getAttribute($name);
     42       
    2843        if($asHtml === true)
    2944            $text = nl2br($text);
     
    3853     */
    3954    public function getRating(){
    40 
     55       
    4156        $rating = $this->getAttribute("rating");
    4257
     
    5469
    5570        $time = $this->getTime();
     71               
    5672        $date = uelm_date($format, $time);
    5773
     
    6682    public function getAuthorName(){
    6783
     84       
     85        if($this->isSerp == true){
     86           
     87            $user = $this->getAttribute("user");
     88            $name = UniteFunctionsUC::getVal($user, "name");
     89           
     90            return($name);
     91        }
     92       
     93       
    6894        $name = $this->getAttribute("author_name");
    6995
     
    77103     */
    78104    public function getAuthorPhotoUrl(){
    79 
     105       
     106        if($this->isSerp == true){
     107            $user = $this->getAttribute("user");
     108            $url = UniteFunctionsUC::getVal($user, "thumbnail");
     109           
     110            return($url);
     111        }
     112       
    80113        $url = $this->getAttribute("profile_photo_url");
    81114
     
    89122     */
    90123    private function getTime(){
    91 
     124       
     125        if($this->isSerp == true){
     126           
     127            $dateString = $this->getAttribute("iso_date");
     128           
     129            $timestamp = strtotime($dateString);
     130           
     131            return($timestamp);
     132        }
     133       
    92134        $time = $this->getAttribute("time");
    93 
     135       
    94136        return $time;
     137    }
     138   
     139    /**
     140     * get time ago text
     141     */
     142    public function getTimeAgoText(){
     143       
     144        $name = "relative_time_description";
     145       
     146        if($this->isSerp == true)
     147            $name = "date";
     148       
     149        $timeAgo = $this->getAttribute($name);
     150       
     151        return($timeAgo);
    95152    }
    96153
  • unlimited-elements-for-elementor/trunk/inc_php/framework/google/places/places_services.class.php

    r3379552 r3429507  
    55 */
    66class UEGoogleAPIPlacesService extends UEGoogleAPIClient{
    7 
     7   
     8    private $isSerp = false;
     9   
    810    /**
    911     * Get the place details.
     
    1416     * @return UEGoogleAPIPlace
    1517     */
    16     public function getDetails($placeId, $params = array()){
     18    public function getDetails($placeId, $params = array(),$showDebug = false){
     19       
     20        $this->isSerp = false;
    1721       
    1822        $params["place_id"] = $placeId;
     
    2428        else
    2529            $params["reviews_no_translations"] = true;
    26        
     30                   
    2731        $response = $this->get("/details/json", $params);
    28        
     32
     33        //debug
     34        if($showDebug == true){
     35           
     36            HelperHtmlUC::putHtmlDataDebugBox_start();
     37                       
     38            dmp("Official API Request Debug");
     39           
     40            $paramsForDebug = $params;
     41           
     42            dmp("Send Params");
     43            dmp($paramsForDebug);
     44           
     45            $dataShow = UniteFunctionsUC::modifyDataArrayForShow($response);
     46           
     47            dmp("Response Data");
     48            dmp($dataShow);
     49           
     50            HelperHtmlUC::putHtmlDataDebugBox_end();
     51        }
    2952       
    3053        $response = UEGoogleAPIPlace::transform($response["result"]);
    3154       
     55       
    3256        return $response;
    3357    }
     58   
     59    /**
     60     * get details using serp function
     61     */
     62    public function getDetailsSerp($placeID, $apiKey, $params = array(),$showDebug = false){
    3463
     64        if(empty($apiKey))
     65            UniteFunctionsUC::throwError("No serp api key");
     66       
     67        $this->isSerp = true;
     68       
     69        $cacheTime = 1440;  //day in minutes
     70       
     71        $params["place_id"] = $placeID;
     72        $params["api_key"] = $apiKey;
     73       
     74        $headers = array();
     75       
     76        $request = UEHttp::make();
     77               
     78        if(!empty($headers))
     79            $request->withHeaders($headers);
     80               
     81        $request->asJson();
     82        $request->acceptJson();
     83       
     84        $request->cacheTime($cacheTime);
     85        $request->withQuery($params);
     86       
     87        $url = "https://serpapi.com/search?engine=google_maps_reviews";
     88       
     89        //first call
     90       
     91        $response = $request->request(UEHttpRequest::METHOD_GET, $url);
     92       
     93        $data = $response->json();
     94       
     95        if($showDebug == true){
     96           
     97            HelperHtmlUC::putHtmlDataDebugBox_start();
     98                       
     99            dmp("Serp API Request Debug");
     100           
     101            $paramsForDebug = $params;
     102           
     103            $apiKey = UniteFunctionsUC::getVal($paramsForDebug, "api_key");
     104           
     105            $paramsForDebug["api_key"] = substr($apiKey, 0, 10) . '********';
     106           
     107            dmp("Send Params");
     108            dmp($paramsForDebug);
     109           
     110            $dataShow = UniteFunctionsUC::modifyDataArrayForShow($data);
     111           
     112            dmp("Response Data");
     113            dmp($dataShow);
     114           
     115        }
     116       
     117        $error = UniteFunctionsUC::getVal($data, "error");
     118        if(!empty($error)){
     119            dmp($data);
     120            UniteFunctionsUC::throwError($error);
     121        }
     122       
     123        $pagination = UniteFunctionsUC::getVal($data, "serpapi_pagination");
     124        $nextPageToken = UniteFunctionsUC::getVal($pagination, "next_page_token");
     125       
     126        //second call:
     127       
     128        if(!empty($nextPageToken)){
     129           
     130            $params["next_page_token"] = $nextPageToken;
     131            $params["num"] = 20;
     132           
     133            $request->withQuery($params);
     134           
     135            $response = $request->request(UEHttpRequest::METHOD_GET, $url);
     136            $data2 = $response->json();
     137
     138            if($showDebug == true){
     139               
     140                dmp("Second Request - Send Params2");
     141                dmp($params);
     142               
     143                $dataShow2 = UniteFunctionsUC::modifyDataArrayForShow($data);
     144               
     145                dmp("Second Request - Response Data");
     146                dmp($dataShow2);
     147               
     148            }
     149           
     150            $arrReviews2 = UniteFunctionsUC::getVal($data2, "reviews");
     151           
     152            if(!empty($arrReviews2))
     153                $data["reviews"] += $arrReviews2;
     154           
     155        }
     156       
     157        if($showDebug == true)
     158            HelperHtmlUC::putHtmlDataDebugBox_end();
     159       
     160       
     161        $place = UEGoogleAPIPlace::transform($data);       
     162       
     163        return($place);
     164    }
     165   
     166   
    35167    /**
    36168     * Get the base URL for the API.
     
    39171     */
    40172    protected function getBaseUrl(){
    41 
    42         return "https://maps.googleapis.com/maps/api/place";
     173       
     174        if($this->isSerp == true)
     175            return("https://serpapi.com/search?engine=google_maps_reviews");
     176        else       
     177            return "https://maps.googleapis.com/maps/api/place";
     178       
    43179    }
    44180
  • unlimited-elements-for-elementor/trunk/inc_php/framework/settings_output.class.php

    r3397365 r3429507  
    10671067                        data-value="<?php echo esc_attr($itemValue); ?>"
    10681068                        class="unite-setting-tabs-item-label"
    1069                         for="<?php echo esc_attr($itemId); ?>" onclick="console.log('Set Tab: <?= $itemValue ?>')"
     1069                        for="<?php echo esc_attr($itemId); ?>")"
    10701070                    >                   
    10711071                        <input
     
    21342134        $strTemplateOptions = '';
    21352135        if (!empty($options)) {
    2136             $strTemplateOptions = '<template id="' . esc_attr($this->wrapperID) . '-options">'
     2136            $strTemplateOptions = '<template id="' . esc_attr($this->wrapperID) . '-options" class="tpl-options">'
    21372137                        . wp_json_encode($options, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
    21382138                        . '</template>';
     
    21432143        $controlsTemplateHTML = '';
    21442144        if (!empty($controls)) {
    2145             $controlsTemplateHTML = '<template id="' . esc_attr($this->wrapperID) . '-controls">'
     2145            $controlsTemplateHTML = '<template id="' . esc_attr($this->wrapperID) . '-controls" class="tpl-controls">'
    21462146                        . wp_json_encode($controls, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
    21472147                        . '</template>';
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_actions.class.php

    r3329756 r3429507  
    373373
    374374                    $addons->saveAddonDefaultsFromData($data);
    375 
     375                   
    376376                    HelperUC::ajaxResponseSuccess(esc_html__("Saved", "unlimited-elements-for-elementor"));
    377377                break;
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_addon.class.php

    r3397365 r3429507  
    22002200            $objSettings->addGutenbergEditorBackgroundSection();
    22012201       
    2202        
     2202                   
    22032203        //choose if add items chooser
    22042204       
     
    22232223            $objSettings->initByCreatorParams($arrParams, $this->paramsCats);
    22242224        }
    2225 
     2225       
    22262226       
    22272227        //add items repeater
     
    35033503     */
    35043504    public function getTestData($num){
    3505 
     3505       
    35063506        $arrData = array();
    35073507
     
    35103510        $fieldName = "test_slot" . $num;
    35113511        $jsonData = UniteFunctionsUC::getVal($this->data, $fieldName);
    3512 
    35133512
    35143513        if(empty($jsonData))
     
    35203519                $arrData = array();
    35213520        }
    3522 
     3521       
    35233522        return ($arrData);
    35243523    }
     
    35303529
    35313530        $arrData = $this->getTestData(2);
    3532 
     3531               
    35333532        return ($arrData);
    35343533    }
     
    35383537     */
    35393538    public function getAllTestData($isJson = false){
    3540 
     3539       
    35413540        $arrData = array();
    35423541
     
    36483647
    36493648        $data = $this->modifyAddonDataConvertToUrlAssets($data);
    3650 
     3649               
    36513650        $dataJson = json_encode($data);
    36523651
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_addons.class.php

    r3397365 r3429507  
    14571457     */
    14581458    public function getTestAddonData($data){
    1459 
     1459               
    14601460        $objAddon = $this->initAddonByData($data);
    14611461
     
    14641464        $isCombine = UniteFunctionsUC::strToBool($isCombine);
    14651465
    1466 
    14671466        $data = $objAddon->getTestData($slotNum);
    1468 
    1469 
    14701467
    14711468        if($isCombine === true){
     
    14801477            return $output;
    14811478        }
    1482 
     1479       
     1480       
    14831481        return $data;
    14841482    }
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_api_integrations.class.php

    r3379552 r3429507  
    5555    const GOOGLE_REVIEWS_FIELD_EMPTY_API_KEY = "google_reviews_empty_api_key";
    5656    const GOOGLE_REVIEWS_FIELD_PLACE_ID = "google_reviews_place_id";
     57    const GOOGLE_REVIEWS_FIELD_API_TEXT = "google_reviews_api_text";
    5758    const GOOGLE_REVIEWS_FIELD_CACHE_TIME = "google_reviews_cache_time";
    5859    const GOOGLE_REVIEWS_FIELD_LANG = "google_reviews_lang";
     60    const GOOGLE_REVIEWS_FIELD_SHOW_DEBUG = "google_reviews_show_debug";
     61    const GOOGLE_REVIEWS_SORT_BY = "google_reviews_sort_by";   
    5962    const GOOGLE_REVIEWS_DEFAULT_CACHE_TIME = 10;
     63   
    6064
    6165    const GOOGLE_SHEETS_FIELD_EMPTY_CREDENTIALS = "google_sheets_empty_credentials";
     
    96100
    97101    private static $instance = null;
    98 
     102   
     103    private $googleReviewsShowDebug = false;
     104   
    99105    private $params = array();
    100106   
     
    185191            break;
    186192            default:
     193               
     194                if(UniteFunctionsUC::isMaxDebug()){
     195                    UniteFunctionsUC::showTrace();
     196                }
     197               
    187198                UniteFunctionsUC::throwError(__FUNCTION__ . " Error: API type \"$type\" is not implemented");
     199            break;
    188200        }
    189201
     
    195207     */
    196208    public function getDataForMultisource($type, $params){
    197 
     209       
    198210        $data = $this->getData($type, $params);
    199 
     211       
    200212        switch($type){
    201213            case self::TYPE_CURRENCY_EXCHANGE:
     
    205217                $data = UniteFunctionsUC::getVal($data, "daily");
    206218            break;
     219            case self::TYPE_GOOGLE_REVIEWS:
     220                $data = UniteFunctionsUC::getVal($data, "reviews");
     221            break;
    207222        }
    208223
     
    215230     * @return array
    216231     */
    217     public function addDataToParams($data, $name){
     232    public function addDataToParams($data, $name, $paramType = null){
    218233
    219234        $params = UniteFunctionsUC::getVal($data, $name, array());
    220235        $params = UniteFunctionsUC::clearKeysFirstUnderscore($params);
    221 
     236               
    222237        try{
     238           
    223239            $apiType = UniteFunctionsUC::getVal($params, "api_type");
     240           
     241           
     242            //some small fix - get api type by special param type
     243           
     244            if(empty($apiType)){
     245                switch($paramType){
     246                    case "reviews":
     247                        $apiType = "google_reviews";
     248                    break;
     249                }
     250            }
     251           
    224252            $apiData = $this->getData($apiType, $params);
    225 
     253                       
    226254            $params["success"] = true;
    227255            $params = array_merge($params, $apiData);
     
    241269     * @return array
    242270     */
    243     public function getSettingsFields(){
    244 
     271    public function getSettingsFields($isSingle = false){
     272       
    245273        $fields = array();
    246 
     274       
    247275        if(GlobalsUnlimitedElements::$enableGoogleAPI === true){
    248276            $fields[self::TYPE_GOOGLE_EVENTS] = $this->getGoogleEventsSettingsFields();
    249             $fields[self::TYPE_GOOGLE_REVIEWS] = $this->getGoogleReviewsSettingsFields();
     277            $fields[self::TYPE_GOOGLE_REVIEWS] = $this->getGoogleReviewsSettingsFields($isSingle);
    250278            $fields[self::TYPE_GOOGLE_SHEETS] = $this->getGoogleSheetsSettingsFields();
    251279            $fields[self::TYPE_YOUTUBE_PLAYLIST] = $this->getYoutubePlaylistSettingsFields();
    252280        }
    253 
     281       
    254282        if(GlobalsUnlimitedElements::$enableCurrencyAPI === true)
    255283            $fields[self::TYPE_CURRENCY_EXCHANGE] = $this->getCurrencyExchangeSettingsFields();
     
    269297    public function addServiceSettingsFields($settingsManager, $type, $name, $condition = null){
    270298
    271         $fields = $this->getSettingsFields();
     299        $fields = $this->getSettingsFields(true);
    272300        $fields = UniteFunctionsUC::getVal($fields, $type);
    273 
     301       
    274302        if(empty($fields))
    275303            return;
    276 
     304       
    277305        // add api type
    278306        $params = array();
     
    280308
    281309        $settingsManager->addHiddenInput($name . "_api_type", $type, "API Type", $params);
    282 
     310       
    283311        // add the fields
    284         HelperProviderUC::addSettingsFields($settingsManager, $fields, $name, $condition);
    285     }
    286        
     312        HelperProviderUC::addSettingsFields($settingsManager, $fields, $name, $condition, true);
     313    }
     314       
     315   
    287316    /**
    288317     * init the api integrations
     
    365394            $key = $name."_".$key;
    366395       
    367         $value = empty($this->params[$key]) ? $fallback : $this->params[$key];
    368 
    369         return $value;
     396        $paramValue = UniteFunctionsUC::getVal($this->params, $key);
     397
     398        if(empty($paramValue))
     399            $paramValue = $fallback;
     400       
     401        return $paramValue;
    370402    }
    371403
     
    464496     */
    465497    private function getExchangeRateApiKey(){
    466 
     498       
    467499        $key = $this->getRequiredParam(self::SETTINGS_EXCHANGE_RATE_API_KEY, "Exchange Rate API key");
    468500
     
    480512
    481513        $fields = $this->addEmptyApiKeyField($fields, $key, self::CURRENCY_EXCHANGE_FIELD_EMPTY_API_KEY, "Exchange Rate API");
    482 
     514       
    483515        $fields = array_merge($fields, array(
    484516            array(
     
    584616    }
    585617
    586     /**
    587      * get google reviews settings fields
    588      */
    589     private function getGoogleReviewsSettingsFields(){
    590 
    591         $fields = array();
    592 
    593         $fields = $this->addGoogleEmptyApiKeyField($fields, self::GOOGLE_REVIEWS_FIELD_EMPTY_API_KEY);
    594 
    595         $fields = array_merge($fields, array(
    596             array(
    597                 "id" => self::GOOGLE_REVIEWS_FIELD_PLACE_ID,
    598                 "type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
    599                 "text" => __("Place ID", "unlimited-elements-for-elementor"),
    600                 // translators: %s is page url
    601                 "desc" => sprintf(__("You can find the place ID by using <a href='%s' target='_blank'>Place ID Finder</a>.", "unlimited-elements-for-elementor"), "https://developers.google.com/maps/documentation/javascript/examples/places-placeid-finder"),
    602             ),
    603             array(
    604                 "id" => self::GOOGLE_REVIEWS_FIELD_CACHE_TIME,
    605                 "type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
    606                 "text" => __("Cache Time", "unlimited-elements-for-elementor"),
    607                 // translators: %d is a number
    608                 "desc" => sprintf(__("Optional. You can specify the cache time of results in minutes. The default value is %d minutes.", "unlimited-elements-for-elementor"), self::GOOGLE_REVIEWS_DEFAULT_CACHE_TIME),
    609                 "default" => self::GOOGLE_REVIEWS_DEFAULT_CACHE_TIME,
    610             ),
    611             array(
    612                 "id" => self::GOOGLE_REVIEWS_FIELD_LANG,
    613                 "type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
    614                 "text" => __("Language Code", "unlimited-elements-for-elementor"),
    615                 "desc" => sprintf(__("Optional. Specify a language code. Example: de and google will translate the review.", "unlimited-elements-for-elementor"), self::GOOGLE_REVIEWS_DEFAULT_CACHE_TIME),
    616                 "default" => "",
    617             )
    618         ));
    619 
    620         return $fields;
    621     }
     618   
    622619
    623620
     
    868865    }
    869866
    870     /**
    871      * get google reviews data
    872      */
    873     private function getGoogleReviewsData(){
    874 
    875         $data = array();
    876 
     867   
     868    private function _________GOOGLE_REVIEWS_________(){}
     869   
     870    /**
     871     * get serp api key
     872     */
     873    private function getSerpAPIKey(){
     874       
     875        if(GlobalsUnlimitedElements::$enableSerpAPI == false)
     876            return(null);
     877       
     878        $serpKey = HelperProviderCoreUC_EL::getGeneralSetting("serpapi_key");
     879        $serpKey = trim($serpKey);
     880       
     881        return($serpKey);
     882    }
     883   
     884    /**
     885     * is serp api enabled
     886     */
     887    private function isGoogleReviewsSerpEnabled(){
     888                       
     889        $apiKey = $this->getSerpAPIKey();
     890       
     891        if(!empty($apiKey))
     892            return(true);
     893           
     894        return(false);     
     895    }
     896   
     897    /**
     898     * get official google reviews
     899     */
     900    private function getGoogleReviewsData_official($placeId){
     901       
    877902        $this->validateGoogleApiKey();
    878 
    879         $placeId = $this->getRequiredParam(self::GOOGLE_REVIEWS_FIELD_PLACE_ID, "Place ID");
     903       
    880904        $cacheTime = $this->getCacheTimeParam(self::GOOGLE_REVIEWS_FIELD_CACHE_TIME, self::GOOGLE_REVIEWS_DEFAULT_CACHE_TIME);
    881 
     905       
    882906        $placesService = new UEGoogleAPIPlacesService();
    883907        $placesService->setCacheTime($cacheTime);
     
    893917        );
    894918       
    895         $place = $placesService->getDetails($placeId, $placeParams);
    896 
    897         foreach($place->getReviews() as $review){
    898            
    899             $data[] = array(
    900                 "id" => $review->getId(),
    901                 "date" => $review->getDate(self::FORMAT_DATETIME),
    902                 "text" => $review->getText(true),
    903                 "rating" => $review->getRating(),
    904                 "author_name" => $review->getAuthorName(),
    905                 "author_photo" => $review->getAuthorPhotoUrl(),
     919        $place = $placesService->getDetails($placeId, $placeParams, $this->googleReviewsShowDebug);
     920       
     921        return($place);
     922    }
     923   
     924    /**
     925     * get google reviews from serp service
     926     */
     927    private function getGoogleReviewsData_serp($placeId){
     928       
     929        $placesService = new UEGoogleAPIPlacesService();
     930
     931        $placeParams = array();
     932               
     933        $apiKey = $this->getSerpAPIKey();
     934       
     935        $reviewsLanguage = $this->getParam(self::GOOGLE_REVIEWS_FIELD_LANG);
     936        $placeParams["hl"] = $reviewsLanguage;
     937       
     938        $reviewsSortBy = $this->getParam(self::GOOGLE_REVIEWS_SORT_BY);
     939        $placeParams["sort_by"] = $reviewsSortBy;
     940       
     941        $place = $placesService->getDetailsSerp($placeId, $apiKey, $placeParams, $this->googleReviewsShowDebug);
     942       
     943        return($place);
     944    }
     945   
     946   
     947    /**
     948     * get google reviews data
     949     */
     950    private function getGoogleReviewsData(){
     951       
     952        $data = array();
     953       
     954        $showDebug = $this->getParam(self::GOOGLE_REVIEWS_FIELD_SHOW_DEBUG);
     955       
     956        if($showDebug == true)
     957            $this->googleReviewsShowDebug = true;
     958       
     959        try{
     960                   
     961            $serpAPIKey = $this->getSerpAPIKey();
     962           
     963            $isSerp = !empty($serpAPIKey);
     964           
     965            if($this->googleReviewsShowDebug == true){
     966               
     967                $message = "Reviews API Debug";
     968               
     969                if($isSerp == true)
     970                    $message .= "<br> Output google reviews data using serp.com API";
     971                else
     972                    $message .= "<br> Output google reviews data using Official Google API";
     973               
     974                echo HelperHtmlUC::getDebugWarningMessageHtml($message);
     975            }
     976       
     977            $placeId = $this->getRequiredParam(self::GOOGLE_REVIEWS_FIELD_PLACE_ID, "Place ID");
     978       
     979       
     980            if($isSerp == false)
     981                $place = $this->getGoogleReviewsData_official($placeId);
     982            else
     983                $place = $this->getGoogleReviewsData_serp($placeId);
     984       
     985       
     986        //add api source
     987           
     988            $apiSourceText = ($isSerp == true)?"serp":"official";
     989           
     990            $data["reviews_api_type"] = $apiSourceText;
     991           
     992            //add place info
     993           
     994            $arrInfo = $place->getPlaceInfo();
     995           
     996            if(!empty($arrInfo))
     997                $data["place_info"] = $arrInfo;
     998           
     999            //add search link
     1000           
     1001            if($isSerp == true){
     1002               
     1003                $arrMetaData = $place->getMetaData();
     1004               
     1005                $data["api_search_link_for_debug"] = UniteFunctionsUC::getVal($arrMetaData, "json_endpoint");
     1006                $data["api_search_html_link_for_debug"] = UniteFunctionsUC::getVal($arrMetaData, "prettify_html_file");
     1007               
     1008            }
     1009       
     1010       
     1011            //add reviews
     1012               
     1013            $arrReviews = $place->getReviews();
     1014           
     1015            $arrReviewsOutput = array();
     1016           
     1017            foreach($arrReviews as $review){
     1018               
     1019                if($isSerp == true)
     1020                    $review->setSerpSource();
     1021               
     1022                $arrReviewsOutput[] = array(
     1023                    "id" => $review->getId(),
     1024                    "date" => $review->getDate(self::FORMAT_DATETIME),
     1025                    "time_ago" => $review->getTimeAgoText(),
     1026                    "text" => $review->getText(true),
     1027                    "rating" => $review->getRating(),
     1028                    "author_name" => $review->getAuthorName(),
     1029                    "author_photo" => $review->getAuthorPhotoUrl(),
     1030                );
     1031               
     1032            }
     1033           
     1034            $data["reviews"] = $arrReviewsOutput;
     1035       
     1036        }catch(Exception $e){
     1037           
     1038            if($this->googleReviewsShowDebug == true){
     1039               
     1040                $message = $e->getMessage();
     1041               
     1042                echo HelperHtmlUC::getErrorMessageHtml($message,"",true);
     1043            }
     1044           
     1045            throw $e;
     1046        }
     1047       
     1048        return $data;
     1049    }
     1050   
     1051   
     1052    /**
     1053     * get google reviews settings fields
     1054     */
     1055    private function getGoogleReviewsSettingsFields($isSingle = false){
     1056       
     1057        $fields = array();
     1058
     1059        $fields = $this->addGoogleEmptyApiKeyField($fields, self::GOOGLE_REVIEWS_FIELD_EMPTY_API_KEY);
     1060       
     1061        $fields[] = array(
     1062                "id" => self::GOOGLE_REVIEWS_FIELD_PLACE_ID,
     1063                "type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
     1064                "text" => __("Place ID", "unlimited-elements-for-elementor"),
     1065                // translators: %s is page url
     1066                "desc" => sprintf(__("You can find the place ID by using <a href='%s' target='_blank'>Place ID Finder</a>.", "unlimited-elements-for-elementor"), "https://developers.google.com/maps/documentation/javascript/examples/places-placeid-finder"),
     1067                "default"=>"ChIJmeeg4mbcQUcRIOHu3gDTJDs"
     1068        );
     1069       
     1070        $isSerpEnabled = $this->isGoogleReviewsSerpEnabled();
     1071       
     1072        if($isSerpEnabled == false)
     1073            $text = sprintf(__("To get more then 5 reviews, enter %s key in general settings", "unlimited-elements-for-elementor"), "<a href='https://serpapi.com' target='_blank'>serpapi.com</a>");
     1074        else
     1075            $text = sprintf(__("Fetching google reviews using %s service. The cache time is 1 day.", "unlimited-elements-for-elementor"), "<a href='https://serpapi.com' target='_blank'>serpapi.com</a>");
     1076       
     1077        //if there is no option - no need for text
     1078        if(GlobalsUnlimitedElements::$enableSerpAPI == true){
     1079           
     1080            $fields[] = array(
     1081                    "id" => self::GOOGLE_REVIEWS_FIELD_API_TEXT,
     1082                    "type" => UniteCreatorDialogParam::PARAM_STATIC_TEXT,
     1083                    "text" => $text,
    9061084            );
    9071085        }
    908 
    909         return $data;
    910     }
    911 
     1086       
     1087        //for serp api the cache is 1 day
     1088               
     1089        if($isSerpEnabled == false){
     1090           
     1091            $fields[] = array(
     1092                    "id" => self::GOOGLE_REVIEWS_FIELD_CACHE_TIME,
     1093                    "type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
     1094                    "text" => __("Cache Time", "unlimited-elements-for-elementor"),
     1095                    // translators: %d is a number
     1096                    "desc" => sprintf(__("Optional. You can specify the cache time of results in minutes. The default value is %d minutes.", "unlimited-elements-for-elementor"), self::GOOGLE_REVIEWS_DEFAULT_CACHE_TIME),
     1097                    "default" => self::GOOGLE_REVIEWS_DEFAULT_CACHE_TIME,
     1098                );
     1099        }
     1100       
     1101       
     1102        $fields[] = array(
     1103                "id" => self::GOOGLE_REVIEWS_FIELD_LANG,
     1104                "type" => UniteCreatorDialogParam::PARAM_TEXTFIELD,
     1105                "text" => __("Language Code", "unlimited-elements-for-elementor"),
     1106                "desc" => __("Optional. Specify a language code. Example: de and google will translate the review.", "unlimited-elements-for-elementor"),
     1107                "default" => "",
     1108            );
     1109       
     1110        if($isSerpEnabled == true){
     1111           
     1112            $fields[] = array(
     1113                "id" => self::GOOGLE_REVIEWS_SORT_BY,
     1114                "type" => UniteCreatorDialogParam::PARAM_DROPDOWN,
     1115                "text" => __("Sort By", "unlimited-elements-for-elementor"),
     1116                "options" => array(
     1117                    "qualityScore"=>"Most Relevant",
     1118                    "newestFirst"=>"Newest",
     1119                    "ratingHigh"=>"Highest Rating",
     1120                    "ratingLow"=>"Lowest Rating",
     1121                ),
     1122                "default" => "qualityScore"
     1123            );
     1124           
     1125        }
     1126       
     1127       
     1128        //add fields for single mode
     1129       
     1130        if($isSingle == true){
     1131           
     1132            $fields[] = array(
     1133                "id" => "google_reviews_hr_beore_debug",
     1134                "type" => UniteCreatorDialogParam::PARAM_HR,
     1135            );
     1136           
     1137            $fields[] = array(
     1138                "id" => self::GOOGLE_REVIEWS_FIELD_SHOW_DEBUG,
     1139                "type" => UniteCreatorDialogParam::PARAM_RADIOBOOLEAN,
     1140                "text" => __("Show Debug", "unlimited-elements-for-elementor"),
     1141            );
     1142           
     1143        }
     1144           
     1145
     1146        return $fields;
     1147    }
     1148   
     1149   
    9121150    private function _________GOOGLE_SHEETS_________(){}
     1151   
    9131152   
    9141153    /**
     
    10721311        return $key;
    10731312    }
    1074 
     1313   
     1314   
    10751315    /**
    10761316     * get weather forecast settings fields
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_entrance_animations.class.php

    r3251080 r3429507  
    454454        var step = 100;
    455455
    456     var objItems = objElement.find("."+classItem);
     456    var objItems = objElement.find("."+classItem).not(".uc-entrance-animate");
    457457
    458458    var numItems = objItems.length;
     
    464464
    465465    objItems.each(function(index, item){
    466 
     466     
    467467      var timeoutTime = time;
    468468      if(order == "up")
     
    576576            ueCheckEntranceAnimation(objElement, <?php echo esc_attr($animationStep)?>, "<?php echo esc_attr($classItem)?>", "<?php echo esc_attr($order)?>")
    577577        });
    578 
    579         objElement.on("uc_ajax_refreshed", function(){
    580 
    581             objElement.removeData("ue_entrance_animation_started");
    582 
     578       
     579        objElement.on("uc_ajax_refreshed", function(event, params){
     580                       
     581            objElement.removeData("ue_entrance_animation_started");
     582           
     583            if(params.isLoadMore && params.isLoadMore === true){
     584               
     585                ueStartEntranceAnimation(objElement, <?php echo esc_attr($animationStep)?>, "<?php echo esc_attr($classItem)?>", "<?php echo esc_attr($order)?>");
     586               
     587                return(true);
     588            }
     589                       
    583590            ueCheckEntranceAnimation(objElement, <?php echo esc_attr($animationStep)?>, "<?php echo esc_attr($classItem)?>", "<?php echo esc_attr($order)?>")
    584591        });
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_helperhtml.class.php

    r3401883 r3429507  
    488488            return($html);
    489489        }
    490 
    491         protected function z_________PUTTERS_______(){}
    492490       
     491        protected function z_________DEBUG_______(){}
     492       
    493493        /**
    494494         * put debug box
    495495         */
    496496        public static function putHtmlDataDebugBox($data){
    497                        
     497           
    498498            self::putHtmlDataDebugBox_start();
    499499           
     
    503503            if(is_string($data))
    504504                $data = htmlspecialchars($data);
    505                            
     505           
    506506            dmp($data);
    507507           
     
    556556            return($html);
    557557        }
     558       
     559       
     560        protected function z_________PUTTERS_______(){}
     561       
    558562       
    559563       
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_import_changelog.class.php

    r3329756 r3429507  
    146146
    147147        $wpdb->query("TRUNCATE TABLE {$changelogTable}");
    148 
    149         $adminUserID = $this->getAdminID();
    150 
     148       
     149        $adminUserID = get_current_user_id();
     150       
    151151        foreach ($data as $item) {
    152152
     
    172172    }
    173173
    174     /**
    175      * get admin user id
    176      */
    177     private function getAdminID() {
    178 
    179         $arrUsers = UniteFunctionsWPUC::getAdminUsers();
    180 
    181         if(empty($arrUsers))
    182             return(null);
    183 
    184         $firstUser = $arrUsers[0];
    185 
    186         $userID = $firstUser->ID;
    187 
    188         return($userID);
    189     }
    190174
    191175    /**
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_output.class.php

    r3401883 r3429507  
    989989     * prepare css selector dimentions css
    990990     */
    991     private function prepareCSSSelectorDimentionsCSS($selectorValue, $value){
    992 
    993         $top = UniteFunctionsUC::getVal($value, "top");
    994         $right = UniteFunctionsUC::getVal($value, "right");
    995         $bottom = UniteFunctionsUC::getVal($value, "bottom");
    996         $left = UniteFunctionsUC::getVal($value, "left");
    997         $unit = UniteFunctionsUC::getVal($value, "unit", "px");
    998 
    999         $css = $this->processCSSSelectorReplaces($selectorValue, array(
    1000             "{{top}}" => $top . $unit,
    1001             "{{right}}" => $right . $unit,
    1002             "{{bottom}}" => $bottom . $unit,
    1003             "{{left}}" => $left . $unit,
    1004         ));
    1005 
    1006         return $css;
    1007     }
     991    function prepareCSSSelectorDimentionsCSS($selectorValue, $value){
     992
     993        $top    = UniteFunctionsUC::getVal($value, "top");
     994        $right  = UniteFunctionsUC::getVal($value, "right");
     995        $bottom = UniteFunctionsUC::getVal($value, "bottom");
     996        $left   = UniteFunctionsUC::getVal($value, "left");
     997        $unit   = UniteFunctionsUC::getVal($value, "unit", "px");
     998
     999        $rawSides = array($top, $right, $bottom, $left);
     1000        $hasValue = false;
     1001
     1002        foreach ($rawSides as $sideValue) {
     1003            if ($sideValue !== '' && $sideValue !== null && $sideValue !== false) {
     1004                $sideValue = trim((string)$sideValue);
     1005                if ($sideValue !== '') {
     1006                    $hasValue = true;
     1007                    break;
     1008                }
     1009            }
     1010        }
     1011
     1012        if ($hasValue === false) return "";
     1013
     1014        $prepareSide = function($v) use ($unit) {
     1015            if ($v === '' || $v === null || $v === false)
     1016                return '';
     1017
     1018            $v = trim((string)$v);
     1019            if ($v === '')
     1020                return '';
     1021
     1022            return $v . $unit;
     1023        };
     1024
     1025        $css = $this->processCSSSelectorReplaces($selectorValue, array(
     1026            "{{top}}"    => $prepareSide($top),
     1027            "{{right}}"  => $prepareSide($right),
     1028            "{{bottom}}" => $prepareSide($bottom),
     1029            "{{left}}"   => $prepareSide($left),
     1030        ));
     1031
     1032        return $css;
     1033    }
    10081034
    10091035    /**
     
    11641190
    11651191        foreach($selectors as $index => $selector){
    1166             $selectors[$index] = "#" . $wrapperId . " " . trim($selector);
     1192            $selectors[$index] = "." . $wrapperId . " " . trim($selector);
    11671193        }
    11681194
     
    12671293        $padding = UniteFunctionsUC::getVal($paramsTmp, 'advanced_padding');
    12681294        if (is_array($padding)) {
     1295
     1296            $unit = !empty($padding['unit']) ? $padding['unit'] : 'px';
     1297
    12691298            if(!empty($padding['is_linked']) && $padding['is_linked'] && $padding['top'] !== '' && $padding['top'] !== null) {
    12701299                $val = (string)$padding['top'];
    1271                 if($val !== '' && $val !== null) {
    1272                     $advanced_styles .= 'padding: ' . $val . $padding['unit'] . '; ';
     1300                if ($val !== '' && $val !== null && $val !== false) {
     1301                    $val = trim((string)$val);
     1302                    if ($val !== '') {
     1303                        $advanced_styles .= 'padding: ' . $val . $unit . '; ';
     1304                    }
    12731305                }
    12741306            } else {
    12751307                foreach($sides as $side) {
    12761308                    $val = UniteFunctionsUC::getVal($padding, $side);
    1277                     if($val !== '' && $val !== null && $val !== false) {
    1278                         $advanced_styles .= 'padding-' . $side . ': ' . (string)$val . $padding['unit'] . '; ';
     1309
     1310                    if ($val === '' || $val === null || $val === false) {
     1311                        continue;
    12791312                    }
     1313
     1314                    $val = trim((string)$val);
     1315                    if ($val === '') {
     1316                        continue;
     1317                    }
     1318
     1319                    $advanced_styles .= 'padding-' . $side . ': ' . $val . $unit . '; ';
    12801320                }
    12811321            }
     
    14831523
    14841524        if($advanced_styles != '') {
    1485             $styles .= "\n#" . $wrapperId . " {" . $advanced_styles . "}";
     1525            $styles .= "\n." . $wrapperId . " {" . $advanced_styles . "}";
    14861526        }
    14871527
     
    15141554            }
    15151555        }
     1556
     1557        $styles .= ' /* debug 2 */';
    15161558
    15171559        return $styles;
     
    15871629        $styles .= $this->processItemsSelectors();
    15881630
     1631        $styles .= ' /* debug 3 */';
     1632
    15891633        if(empty($styles) === true)
    15901634            return null;
    15911635
    1592         UniteProviderFunctionsUC::printCustomStyle($styles);
     1636        // UniteProviderFunctionsUC::printCustomStyle($styles);
    15931637
    15941638        return $styles;
     
    16231667
    16241668            $styles .= $itemStyles;
     1669
     1670            $styles .= ' /* debug 4 */';
    16251671        }
    16261672
     
    16321678     */
    16331679    public function getSelectorsCss(){
    1634                
     1680
    16351681        $style = $this->processPreviewParamsSelectors();
    16361682
     
    16621708
    16631709        //process selectors only for preview (elementor output uses its own processing)
     1710
    16641711        $this->processPreviewParamsSelectors();
    16651712
     
    19211968        return($html);
    19221969    }
    1923    
     1970
    19241971    /**
    19251972     * modify debug array - output for debug, fordebug
     
    20002047     */
    20012048    private function putDebugDataHtml_posts($arrItemData){
    2002        
     2049
    20032050        $numPosts = count($arrItemData);
    20042051
     
    20092056        if(empty($arrItemData))
    20102057            return($html);
    2011        
     2058
    20122059        $isShowMeta = ($this->debugDataType == "post_meta");
    20132060
    20142061        foreach($arrItemData as $index => $item){
    2015                        
     2062
    20162063            $isPost = false;
    20172064            if($item instanceof WP_Post)
     
    20362083               
    20372084                $item = UniteFunctionsUC::getVal($item, "item");
    2038                                
     2085
    20392086                $postData = UniteFunctionsUC::getArrFirstValue($item);
    2040                                    
     2087
    20412088                $title = UniteFunctionsUC::getVal($postData, "title");
    20422089                $alias = UniteFunctionsUC::getVal($postData, "alias");
     
    21322179     */
    21332180    private function putDebugDataHtml($arrData, $arrItemData){
    2134        
     2181
    21352182        $html = "<div class='uc-debug-output' style='font-size:16px;color:black;text-decoration:none;background-color:white;padding:3px;'>";
    2136        
     2183
    21372184        $html .= dmpGet("<b>Widget Debug Data</b> (turned on by setting in widget advanced section)<br>",true);
    21382185
     
    21412188       
    21422189        if(!empty($paramListing) && $this->itemsType == "template"){
    2143            
     2190
    21442191            $arrItemData = $this->putDebugDataHtml_getItemsFromListing($paramListing, $arrData);
    21452192        }
    2146        
    2147        
     2193
    21482194        switch($this->debugDataType){
    21492195            case "post_titles":
     
    22042250        if($isInsideEditor == true){
    22052251           
    2206             $css = "#{$ucID}-root .uc-background-editor-placeholder{
     2252            $css = ".{$ucID}-root .uc-background-editor-placeholder{
    22072253                font-size:12px;
    22082254                padding:20px;
     
    22102256            }
    22112257           
    2212             #{$ucID}-root{
     2258            .{$ucID}-root{
    22132259                position:relative;
    22142260                border:1px solid gray;
     
    22322278        $css = "
    22332279/* background wrapper */
    2234 #{$ucID}-root.uc-background-active{
     2280.{$ucID}-root.uc-background-active{
    22352281    position: absolute;
    22362282    top:0px;
     
    25432589                $advancedAddClasses = UniteFunctionsUC::getVal($params, "advanced_css_classes");
    25442590
    2545                 $output .= "\n<div id=\"" . esc_attr($id) . "\" class=\"ue-widget-root " . esc_attr($advancedAddClasses) . "\" data-id=\"" . esc_attr($rootId) . "\">";
     2591                $output .= "\n<div id=\"" . esc_attr($id) . "\" class=\"ue-widget-root " . esc_attr($advancedAddClasses) . " " . esc_attr($id) . "\" data-id=\"" . esc_attr($rootId) . "\">";
    25462592            }
    25472593           
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_params_processor.class.php

    r3397365 r3429507  
    10141014        if(!empty($imageUrl))
    10151015            $imageUrl = UniteFunctionsUC::sanitize($imageUrl, UniteFunctionsUC::SANITIZE_URL);
    1016                    
     1016       
    10171017        $data[$name] = $imageUrl;
    10181018
     
    18261826            case "currency_api":
    18271827            case "weather_api":
    1828                 $data = UniteCreatorAPIIntegrations::getInstance()->addDataToParams($data, $name);
     1828            case "reviews":
     1829                $data = UniteCreatorAPIIntegrations::getInstance()->addDataToParams($data, $name, $type);
    18291830            break;
    18301831            case "rss_feed":
     
    18581859               
    18591860            break;
     1861           
    18601862        }
    18611863        return($data);
     
    18631865
    18641866    private function z__________VALUES_OUTPUT__________(){}
    1865 
    1866 
     1867   
     1868   
    18671869    /**
    18681870     * get processe param data, function with override
     
    18701872    protected function getProcessedParamData($data, $value, $param, $processType){
    18711873
    1872        
    18731874        $type = UniteFunctionsUC::getVal($param, "type");
    18741875        $name = UniteFunctionsUC::getVal($param, "name");
    18751876
    18761877        $isOutputProcessType = $this->isOutputProcessType($processType);
    1877 
     1878       
    18781879        //special params - all types
    18791880        switch($type){
     1881            case UniteCreatorDialogParam::PARAM_TEXTFIELD:
     1882                $data = $this->maybeSanitizeLink($data, $name, $value);
     1883            break;
    18801884            case UniteCreatorDialogParam::PARAM_DROPDOWN:
    18811885            case UniteCreatorDialogParam::PARAM_NUMBER:
     
    19361940    }
    19371941
     1942    /**
     1943     * maybe sanitize link in text field
     1944     */
     1945    protected function maybeSanitizeLink($data, $name, $value){
     1946       
     1947        if(strpos($name,"link_") === false && strpos($name,"_link") === false)
     1948            return($data);
     1949        $valueLow = strtolower($value);
     1950        if(strpos($valueLow,"javascript") === false)
     1951            return($data);
     1952       
     1953        //if it's a link
     1954        $value = UniteFunctionsUC::sanitize($value, UniteFunctionsUC::SANITIZE_URL);
     1955       
     1956        $data[$name] = $value;
     1957       
     1958        return($data);
     1959    }
     1960   
    19381961
    19391962    /**
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_rss.class.php

    r3329756 r3429507  
    320320       
    321321        $hasImageKey = $this->hasImageKey($firstRssElement);
    322        
    323         if($hasImageKey == false)
     322               
     323        if($hasImageKey == true)
    324324            return($arrRss);
     325                 
     326        $isAddedImage = true;
    325327           
    326328        foreach ($arrRss as $rssKey => $rssItem) {
    327329           
    328330             $imageLink = $this->getFirstImageLinkFromContent($rssItem);
    329 
    330              if(!empty($imageLink))
     331       
     332             if(!empty($imageLink)){
     333                 
     334                  $isAddedImage = true;
     335                 
    331336                  $arrRss[$rssKey]['image_url'] = $imageLink;
    332              
    333         }
    334 
     337             }
     338             
     339        }
     340       
     341        //add image key to others
     342        if($isAddedImage == true){
     343            foreach ($arrRss as $rssKey => $rssItem) {
     344                if(array_key_exists("image_url", $arrRss[$rssKey]) == false)
     345                    $arrRss[$rssKey]["image_url"] = "";
     346            }
     347        }
     348       
     349       
    335350        return($arrRss);
    336351    }
     
    475490       
    476491        $rssKeyArr = $this->filterByTypeAndCatId($params, UniteCreatorDialogParam::PARAM_TEXTFIELD, $catValue[GlobalsUC::ATTR_CATID]);
    477        
    478492       
    479493        $isAutoDetect = UniteFunctionsUC::getVal($data, "auto_detect_keys");
     
    487501        }
    488502
     503       
    489504        foreach ($rssKeyArr as $keyValue) {
    490505           
     
    503518                               
    504519            } else {
    505                                
     520                       
    506521                $autoKey = $this->autoDetectKeys($keyName, $firstRssElement);
    507                
     522
    508523                if (!empty($autoKey)) {
    509524                                       
     
    515530                   
    516531                    $searchImageKey = $this->searchForImageKey($firstRssElement);
    517 
    518                     if (!empty($searchImageKey))
     532                   
     533                    if (!empty($searchImageKey)){
    519534                        $keys[$keyName] = $searchImageKey;
    520                        
     535                                               
     536                    }
    521537                }
    522538            }
     
    529545                $autoText = $isAutoKey?" <span style='color:grey;'>[auto detect]</span>":"";
    530546               
    531                 if(!array_key_exists($keyName, $keys))
     547                if(!array_key_exists($keyName, $keys)){
    532548                    dmp("{$title}: <span style='color:darkred;'>not detected, please select a custom one</span>");
     549                }
    533550                 else if (array_key_exists($keys[$keyName], $firstRssElement))
    534551                    dmp("{$title}: <b>$key</b> {$autoText}");
     
    556573        else
    557574            $keys["date_key_original"] = "publish_date";
    558        
     575               
    559576       
    560577        return $keys;
     
    570587           
    571588            $autoDetectKey = $this->rssAutoDetectKeys[$keyName];
    572                
     589           
    573590            $arrKeys = explode('|', $autoDetectKey);
    574 
    575             foreach ($arrKeys as $arrKey) {
    576                
    577                 $foundValue = UniteFunctionsUC::getVal($rssElement, $arrKey);
    578 
    579                 if (!empty($foundValue)) {
    580                     return $arrKey;
    581                 }
     591           
     592            foreach ($arrKeys as $key) {
     593                               
     594                if(array_key_exists($key, $rssElement))
     595                    return($key);               
    582596            }
    583597           
     
    648662        $descKeys = explode('|', $possibleDescKeys);
    649663        $rssKeys = array_merge($contentKeys, $descKeys);
    650 
    651         $pattern = '/<img[^>]+src=["\']([^"\']+)["\']/i';
    652 
     664       
     665        //$pattern = '/<img[^>]+src=["\']([^"\']+)["\']/i';
     666        $pattern = '/<img\b[^>]*\bsrc\s*=\s*["\']([^"\']+)["\'][^>]*>/i';
     667       
    653668        foreach ($rssKeys as $rssKey) {
     669           
    654670            if(array_key_exists($rssKey, $rssItem)) {
     671               
    655672                if (!is_array($rssItem[$rssKey])) {
    656                     if (preg_match($pattern, $rssItem[$rssKey], $matches)) {
     673                   
     674                    $content = $rssItem[$rssKey];
     675                                       
     676                    if (preg_match($pattern, $content, $matches)) {
     677                                               
    657678                        if (!empty($matches[1])) {
    658679                            return $matches[1];
    659680                        }
    660681                    }
     682                   
    661683                } else {
    662684                    $firstImage = $this->getFirstImageLinkFromContent($rssItem[$rssKey]);
    663 
     685                   
    664686                    if (!empty($firstImage)) {
    665687                        return $firstImage;
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_schema.class.php

    r3401896 r3429507  
    369369            break;
    370370            case self::ROLE_IMAGE:
     371                if($value == GlobalsUC::$url_no_image_placeholder)
     372                    $value = "";
    371373            case self::ROLE_LINK:
    372374                $value = UniteFunctionsUC::sanitize($value, UniteFunctionsUC::SANITIZE_URL);
    373375            break;
    374376        }
    375        
     377           
    376378        return($value);
    377379    }
  • unlimited-elements-for-elementor/trunk/inc_php/unitecreator_settings.class.php

    r3397365 r3429507  
    3131    private $currentTabs;
    3232    private static $addEditWidgetHTML = null;
     33    private $currentCategoryID;
    3334   
    3435   
     
    395396
    396397        $params["label_block"] = true;
    397 
     398       
    398399        $this->add($name, $defaultValue, $text, self::TYPE_GALLERY, $params);
    399400    }
     
    435436        $objManager = new UniteCreatorManagerInline();
    436437        $objManager->setStartAddon($addon);
    437 
     438       
    438439        $arrParams["items_manager"] = $objManager;
    439440        $this->add("uc_items_editor", "", self::PARAM_NOTEXT, self::TYPE_ITEMS, $arrParams);
     
    521522        if(empty($name) === true){
    522523            $this->currentTabs = null;
    523 
    524524            return null;
    525525        }
     
    537537        // add/update the tab
    538538        $value = UniteFunctionsUC::getVal($tabs["items"], $name);
    539 
    540539        if(empty($value) === true){
     540
    541541            $value = "tab_" . UniteFunctionsUC::getRandomString(5);
    542542
     
    544544
    545545            try{
    546                 $this->updateSettingItems($tabs["name"], $tabs["items"]);
     546                $this->updateSettingItems($tabs["name"] . '-' . $this->currentCategoryID, $tabs["items"]);
    547547            }catch(Exception $exception){
    548                 $this->addTabs($tabs["name"], $tabs["items"], $value);
     548                $this->addTabs($tabs["name"] . '-' . $this->currentCategoryID, $tabs["items"], $value);
    549549            }
    550550        }
     
    553553
    554554        return array(
    555             "name" => $tabs["name"],
     555            "name" => $tabs["name"] . '-' . $this->currentCategoryID,
    556556            "value" => $value,
    557557        );
     
    820820            break;
    821821            case "base_widget": //operate base widget addon object
     822            break;
     823            case "reviews":
     824               
     825                UniteCreatorAPIIntegrations::getInstance()->addServiceSettingsFields($this, UniteCreatorAPIIntegrations::TYPE_GOOGLE_REVIEWS, $name, $condition);
     826               
    822827            break;
    823828            default:
     
    18041809               
    18051810        foreach($arrParamsWithCats as $catID => $arrCat){
    1806            
     1811
     1812            $this->currentCategoryID = $catID;
     1813
     1814            // reset tabs to create for new cat
     1815            $this->currentTabs = null;
     1816
    18071817            $title = UniteFunctionsUC::getVal($arrCat, "title");
    18081818            $tab = UniteFunctionsUC::getVal($arrCat, "tab");
     
    18591869                    $this->addByCreatorParam($param);
    18601870               
    1861             }//foreach params
     1871            }
    18621872           
    18631873            if($isGeneralCategory == true && GlobalsUC::$isProVersion == false){
    1864                
    18651874                $this->addFreeVersionInsideNotification();
    18661875            }
  • unlimited-elements-for-elementor/trunk/includes.php

    r3403331 r3429507  
    1313
    1414if(!defined("UNLIMITED_ELEMENTS_VERSION"))
    15     define("UNLIMITED_ELEMENTS_VERSION", "2.0.1");
     15    define("UNLIMITED_ELEMENTS_VERSION", "2.0.2");
    1616
    1717//disable elementor support for debugging purposes. keep it commented
    1818//define("UE_DISABLE_ELEMENTOR_SUPPORT", true);
    1919
    20    
     20
    2121$currentFile = __FILE__;
    2222$currentFolder = dirname($currentFile);
  • unlimited-elements-for-elementor/trunk/js/manager/unitecreator_manager_actions_addons.js

    r2938098 r3429507  
    688688                var numItems = jQuery("#uc_list_items li").length;
    689689                if(numItems == 0){
    690                     jQuery("#no_items_text").hide();
     690                   
     691                    jQuery("#no_items_text").show();
     692                   
    691693                    g_emptyAddonsWrapper.show();
    692694                    g_manager.updateGlobalHeight(null, 390);
  • unlimited-elements-for-elementor/trunk/js/manager/unitecreator_manager_actions_inline.js

    r2762592 r3429507  
    135135        if(typeof arrItems != "object")
    136136            return(false);
    137        
     137               
    138138        jQuery.each(arrItems, function(index, itemData){
    139139            appendItem(itemData, true);
     
    378378     */
    379379    function appendItem(objValues, noUpdate){
     380               
    380381        var htmlItem = generateItemHtml(objValues);
     382       
    381383        var objItem = g_objItems.appendItem(htmlItem, noUpdate);
    382384        objItem.data("params", objValues);
     385               
    383386    }
    384387   
     
    526529        //init from data
    527530        var arrInitItems = g_objWrapper.data("init-items");
    528        
    529         if(arrInitItems && typeof arrInitItems == "object")
     531               
     532        if(arrInitItems && typeof arrInitItems == "object"){           
    530533            t.setItemsFromData(arrInitItems);
     534        }
    531535       
    532536    };
  • unlimited-elements-for-elementor/trunk/js/manager/unitecreator_manager_items.js

    r3023498 r3429507  
    15111511    this.appendItem = function(htmlItem, noUpdate){
    15121512       
    1513         jQuery("#uc_list_items").show();
     1513        var objListItems = jQuery("#uc_list_items");
     1514        objListItems.show();
     1515               
    15141516        t.hideNoAddonsText();
    1515        
     1517               
    15161518        var objItem = jQuery(htmlItem);
    15171519       
    1518         jQuery("#uc_list_items").append(objItem);
     1520        objListItems.append(objItem);
    15191521       
    15201522        if(noUpdate !== true)
     
    17521754        if(jQuery("#uc_list_items li").length == 0){
    17531755            jQuery("#uc_list_items").hide();
    1754             jQuery("#no_items_text").show();
     1756           
     1757            showNoItemsText(true);
     1758           
    17551759        }else{
    17561760            t.hideNoAddonsText();
     
    17671771       
    17681772        jQuery("#uc_list_items").html("").hide();
    1769         jQuery("#no_items_text").show();
    1770        
     1773       
     1774        showNoItemsText(true);
     1775               
    17711776        if(noUpdate !== true)
    17721777            t.checkSelectRelatedItems();
     
    18791884       
    18801885        if(numItems == 0){
    1881             jQuery("#no_items_text").show();
     1886           
     1887            //show
     1888            showNoItemsText(true);
     1889           
    18821890            jQuery("#uc_list_items").hide();
    18831891        }else{
     
    18861894            jQuery("#uc_list_items").show();
    18871895            t.hideNoAddonsText();
     1896           
    18881897        }
    18891898       
     
    18911900    }
    18921901   
     1902    /**
     1903     * hide or show actually no items text
     1904     */
     1905    function showNoItemsText(isShow){
     1906       
     1907        var objNoItems = jQuery("#no_items_text");
     1908               
     1909        if(isShow == true)
     1910            objNoItems.show();
     1911        else
     1912            objNoItems.hide();
     1913       
     1914    }
    18931915   
    18941916    /**
     
    18961918     */
    18971919    this.hideNoAddonsText = function(){
    1898         jQuery("#no_items_text").hide();
    1899        
     1920       
     1921        //hide
     1922        showNoItemsText(false);
     1923                       
    19001924        g_manager.triggerEvent(g_manager.events.ITEM_HIDE_EMPTY_TEXT);
    19011925    }
     
    19862010     */
    19872011    this.initItems = function(objManager){
     2012               
    19882013        initItems(objManager);
    19892014    };
  • unlimited-elements-for-elementor/trunk/js/settings.js

    r3397365 r3429507  
    1515   
    1616    var g_debug = false;
     17   
     18    var g_debug_selectors = null;
     19    //var g_debug_selectors = "item_border_width";  //enter input name
    1720   
    1821    var g_vars = {
     
    320323
    321324    function isInputFullyInited($input){
    322         return _initedInputsOnce && _initedInputsOnce.has($input[0]);
     325        return _initedInputsOnce.has($input[0]);
    323326    }
    324327
     
    488491     */
    489492    this.getSettingsValues = function (controlsOnly, isChangedOnly) {
     493       
    490494        validateInited();
    491495
     
    497501        jQuery.each(objInputs, function () {
    498502            const objInput = jQuery(this);
    499 
    500             if (objInput.closest(".unite-setting-row").hasClass("unite-setting-hidden") === true)
    501                 return;
    502 
     503           
    503504            const name = getInputName(objInput);
     505           
    504506            if (!name) return;
    505507
     
    509511
    510512            if (isInputFullyInited(objInput)) {
     513               
     514                if (objInput.closest(".unite-setting-row").hasClass("unite-setting-hidden") === true) {
     515                    //console.log('hidden: ' + name);   
     516                    return;
     517                }
     518
    511519                value = getSettingInputValue(objInput);
    512520                if (value === g_vars.NOT_UPDATE_OPTION) return;
     
    578586     */
    579587    function clearInput(objInput, dataname, checkboxDataName, skipControl){
    580 
     588       
    581589        var name = getInputName(objInput);
    582590        var type = getInputType(objInput);
     
    681689            case "checkbox":
    682690            case "radio":
    683                 defaultValue = objInput.data(checkboxDataName);
    684                 defaultValue = g_ucAdmin.strToBool(defaultValue);
    685 
    686                 objInput.prop("checked", defaultValue);
     691                defaultValue = objInput.data(checkboxDataName);
     692
     693                defaultValue = g_ucAdmin.strToBool(defaultValue);
     694                objInput.prop("checked", defaultValue === true);
    687695            break;
    688696            case "editor_tinymce":
     
    10661074    }
    10671075
    1068 
    1069 
    1070 
    1071 
    1072 
    1073 
    1074 
    1075 
    1076 
    1077 
    1078 
    1079 
    1080 
    1081 
    1082 
    1083     // =[2]
    1084 
    10851076    function _______EVENTS_____(){}
    10861077
     
    11441135            return;
    11451136       
    1146         var value = getSettingInputValue(objInput);
     1137        var value   = getSettingInputValue(objInput);
     1138        var name    = getInputName(objInput);
    11471139
    11481140        switch (type) {
     
    11631155            break;
    11641156        }
     1157
     1158        // update cache
     1159        if (!g_temp.cacheValues || typeof g_temp.cacheValues !== "object") {
     1160            g_temp.cacheValues = {};
     1161        }
     1162        if (name && value !== g_vars.NOT_UPDATE_OPTION) {
     1163            g_temp.cacheValues[name] = value;
     1164        }
    11651165
    11661166        //process control change
     
    11791179                eventName = t.events.CHANGE;
    11801180        }
    1181        
    1182         var name = getInputName(objInput);
    11831181         
    11841182        checkUpdateResponsivePlaceholders(objInput);
     
    12181216     */
    12191217    function initControls() {
     1218
    12201219        if (!g_objWrapper)
    12211220            return;
    12221221
    1223         var template = jQuery("#" + g_objWrapper.attr("id") + "-controls");
     1222        // var template = jQuery("#" + g_objWrapper.attr("id") + "-controls");
     1223        var template = g_objWrapper.find('.tpl-controls');
    12241224        var objControls = null;
    12251225
     
    12361236
    12371237        g_arrControls = objControls.parents;
     1238
    12381239        g_arrChildrenControls = objControls.children;
    12391240    }
     
    12941295    }
    12951296
     1297    /*
     1298    * init input once
     1299    */
    12961300    function initInputOnce(objInput, funcChange){
     1301       
    12971302        if (_initedInputsOnce.has(objInput[0])) return;
    12981303       
    12991304        if (!funcChange)
    13001305            funcChange = t.onSettingChange;
    1301 
     1306       
    13021307        var type = getInputType(objInput);
     1308               
    13031309        var basicType = getInputBasicType(objInput);       
    13041310       
     
    13081314            trace(objInput);
    13091315        }
     1316               
     1317        //no need to init items panel from here
     1318        if(type == "items"){
     1319            _initedInputsOnce.add(objInput[0]);
     1320            return(false);
     1321        }
     1322       
    13101323       
    13111324        // init by type
     
    14021415            break;
    14031416        }
     1417       
    14041418
    14051419        t.disableTriggerChange();
     1420
    14061421        try {
    1407             clearInput(objInput, "initval", "initchecked", true);
    1408 
    1409             if (g_temp && g_temp.cacheValues && typeof g_temp.cacheValues === "object") {
    1410                 const name = getInputName(objInput);
    1411 
    1412                 if (name && Object.prototype.hasOwnProperty.call(g_temp.cacheValues, name)) {
    1413 
    1414                     setInputValue(objInput, g_temp.cacheValues[name], g_temp.cacheValues);
     1422            const name = getInputName(objInput);
     1423
     1424            if (!g_temp.cacheValues || typeof g_temp.cacheValues !== 'object') {
     1425                g_temp.cacheValues = {};
     1426            }
     1427
     1428            if (name && !Object.prototype.hasOwnProperty.call(g_temp.cacheValues, name)) {
     1429                const plannedValue = getPlannedInitValue(objInput);
     1430
     1431                if (plannedValue !== g_vars.NOT_UPDATE_OPTION) {
     1432                    g_temp.cacheValues[name] = plannedValue;
    14151433                }
    14161434            }
    14171435
    1418         } catch(e){
     1436            clearInput(objInput, "initval", "initchecked", true);
     1437
     1438            if (name && Object.prototype.hasOwnProperty.call(g_temp.cacheValues, name)) {
     1439                setInputValue(objInput, g_temp.cacheValues[name], g_temp.cacheValues);
     1440            }
     1441
     1442        } catch (e) {
    14191443            console.error("Init-once error:", objInput, e);
    14201444        } finally {
     
    14291453     */
    14301454    function initSettings() {
     1455
    14311456        const $inputs = getObjInputs();
    14321457
     
    14461471
    14471472                    let type = getInputType($input);
     1473                                       
    14481474                    if(type == 'repeater') {
    14491475                        initInputOnce($input, t.onSettingChange);
     
    14591485            else if (g_debug === true) console.log("All inputs scheduled for init-once");
    14601486        })();
     1487
    14611488    }
    14621489
     
    14761503        if (!g_options) g_options = {};
    14771504
    1478         var template = jQuery("#" + g_objWrapper.attr("id") + "-options");
    14791505        var objOptions = {};
    14801506
     1507        var template = g_objWrapper.find(".tpl-options").first();
     1508
     1509        if (!template.length) {
     1510            var wrapperId = g_objWrapper.attr("id");
     1511            if (wrapperId) {
     1512                template = jQuery("#" + wrapperId + "-options");
     1513            }
     1514        }
     1515
    14811516        if (template.length) {
    1482             var raw = (template[0].content?.textContent ?? template.html() ?? "").trim();
     1517            var raw = "";
     1518
     1519            if (
     1520                template[0].tagName &&
     1521                template[0].tagName.toLowerCase() === "template" &&
     1522                template[0].content &&
     1523                typeof template[0].content.textContent === "string"
     1524            ) {
     1525                raw = template[0].content.textContent;
     1526            } else {
     1527                raw = template.html() || "";
     1528            }
     1529
     1530            raw = jQuery.trim(raw);
     1531
    14831532            if (raw) {
    14841533                try {
    14851534                    var parsed = JSON.parse(raw);
    1486                     if (parsed && typeof parsed === "object") objOptions = parsed; // игнорируем null
     1535                    if (parsed && typeof parsed === "object") {
     1536                        objOptions = parsed;
     1537                    }
    14871538                } catch (e) {
    14881539                    console.warn("Options JSON parse error:", e);
     
    14951546        jQuery.each(arrOptions, function (index, optionKey) {
    14961547            g_options[optionKey] = g_ucAdmin.getVal(objOptions, optionKey, g_options[optionKey]);
     1548
    14971549            if (Object.keys(objOptions).length) {
    14981550                objOptions[optionKey] = true;
     
    15051557        }
    15061558
    1507         if (g_options["id_prefix"]) g_IDPrefix = "#" + g_options["id_prefix"];
     1559        if (g_options["id_prefix"]) {
     1560            g_IDPrefix = "#" + g_options["id_prefix"];
     1561        }
    15081562    }
    15091563
     
    15281582
    15291583    };
    1530 
    15311584
    15321585
     
    17721825    };
    17731826
    1774     // =[2]
    1775 
    1776 
    1777 
    1778 
    1779 
    1780 
    1781 
    1782 
    1783 
    1784 
    1785     // =[1]
    17861827
    17871828    function _________CUSTOM_SETTING_TYPES__________(){}
     
    17911832     */
    17921833    const customSettingTypeCache = {};
     1834   
    17931835    function getCustomSettingType(settingName) {
    17941836        if (!settingName) {
     
    34363478     */
    34373479    function initTabs(objWrapper) {
     3480
    34383481        objWrapper.find(".unite-setting-tabs-item-label").on("click", function () {
    34393482            var objInput = jQuery(this);
     
    34503493        });       
    34513494
    3452         /*
    3453         objWrapper.find(".unite-setting-tabs-item-input").on("change", function () {
    3454             var objInput = jQuery(this);
    3455             var id = objInput.attr("name");
    3456             var value = objInput.val();
    3457 
    3458             objInput.closest(".unite-list-settings")
    3459                 .find(".unite-setting-row[data-tabs-id=\"" + id + "\"]")
    3460                 .addClass("unite-tabs-hidden")
    3461                 .filter("[data-tabs-value=\"" + value + "\"]")
    3462                 .removeClass("unite-tabs-hidden");
    3463         });
    3464         */
    34653495        objWrapper.find(".unite-setting-tabs-item-input").first().trigger('click');
    34663496    }
     
    40334063     */
    40344064    function initItemsPanel(){
    4035 
     4065               
    40364066        var objItemsWrapper = g_objParent.find(".uc-setting-items-panel");
    40374067        if(objItemsWrapper.length == 0)
     
    41274157     */
    41284158    function initSubSettingsDialog(objWrapper) {
     4159       
    41294160        var objDialog = getSubSettingsDialog(objWrapper);
    41304161
     
    42594290
    42604291    /**
     4292     * init repeater
     4293     */
     4294/**
    42614295     * init repeater
    42624296     */
     
    43104344            addRepeaterItem(null, objWrapper, itemValues, $item);
    43114345        });
     4346
     4347        var name = getInputName(objWrapper);
     4348        var cachedValue = null;
     4349
     4350        if (g_temp.cacheValues && g_temp.cacheValues.hasOwnProperty(name)) {
     4351            cachedValue = g_temp.cacheValues[name];
     4352        }
     4353
     4354        if (cachedValue && Array.isArray(cachedValue) && cachedValue.length > 0) {
     4355            setRepeaterValues(objWrapper, cachedValue);
     4356        } else {
     4357            var defaultItems = objWrapper.data("itemvalues");
     4358            if (defaultItems && objWrapper.find(".unite-repeater-item").length === 0) {
     4359                setRepeaterValues(objWrapper, null, true);
     4360            }
     4361        }
    43124362    }
    43134363
     
    43154365     * add repeater item
    43164366     */
    4317     function addRepeaterItem(event, objWrapper, itemValues, objItemInsertAfter) {
    4318         if (!objWrapper)
    4319             objWrapper = jQuery(this).closest(".unite-setting-repeater");
    4320 
    4321         var objSettingsTemplate = objWrapper.find(".unite-repeater-template");
    4322         var objItemsWrapper = objWrapper.find(".unite-repeater-items");
    4323         var objEmpty = objWrapper.find(".unite-repeater-empty");
    4324 
    4325         g_ucAdmin.validateDomElement(objItemsWrapper, "items wrapper");
    4326         g_ucAdmin.validateDomElement(objSettingsTemplate, "settings template");
    4327 
    4328         objEmpty.hide();
    4329 
    4330         // prepare item values
    4331         if (!itemValues) {
    4332             var itemNumber = objWrapper.find(".unite-repeater-item").length + 1;
    4333             var itemTitle = objWrapper.data("item-title") + " " + itemNumber;
    4334 
    4335             itemValues = {
    4336                 title: itemTitle,
    4337             };
    4338         }
    4339 
    4340         if (!itemValues._generated_id)
    4341             itemValues._generated_id = g_ucAdmin.getRandomString(5);
    4342 
    4343         // get item html
    4344         var textDelete = objWrapper.data("text-delete");
    4345         var textDuplicate = objWrapper.data("text-duplicate");
    4346 
    4347         var html = "<div class='unite-repeater-item'>";
    4348         html += " <div class='unite-repeater-item-header'>";
    4349 
    4350         if(itemValues.title == '') {
    4351             html += "    <div class='unite-repeater-item-title unite-repeater-item-title-placeholder'>Item Title</div>";
     4367    function addRepeaterItem(event, objWrapper, itemValues, objItemInsertAfter) {
     4368        if (!objWrapper)
     4369            objWrapper = jQuery(this).closest(".unite-setting-repeater");
     4370
     4371        var objSettingsTemplate = objWrapper.find(".unite-repeater-template");
     4372        var objItemsWrapper    = objWrapper.find(".unite-repeater-items");
     4373        var objEmpty            = objWrapper.find(".unite-repeater-empty");
     4374
     4375        g_ucAdmin.validateDomElement(objItemsWrapper, "items wrapper");
     4376        g_ucAdmin.validateDomElement(objSettingsTemplate, "settings template");
     4377
     4378        objEmpty.hide();
     4379
     4380        // prepare item values
     4381        if (!itemValues) {
     4382            var itemNumber = objWrapper.find(".unite-repeater-item").length + 1;
     4383            var itemTitle = objWrapper.data("item-title") + " " + itemNumber;
     4384
     4385            itemValues = {
     4386                title: itemTitle
     4387            };
     4388        }
     4389
     4390        if (!itemValues._generated_id)
     4391            itemValues._generated_id = g_ucAdmin.getRandomString(5);
     4392
     4393        // get item html
     4394        var textDelete    = objWrapper.data("text-delete");
     4395        var textDuplicate = objWrapper.data("text-duplicate");
     4396
     4397        var html = "<div class='unite-repeater-item'>";
     4398        html    += " <div class='unite-repeater-item-header'>";
     4399
     4400        if (itemValues.title == "") {
     4401            html += "  <div class='unite-repeater-item-title unite-repeater-item-title-placeholder'>Item Title</div>";
    43524402        } else {
    4353             html += "    <div class='unite-repeater-item-title'>" + itemValues.title + "</div>";
     4403            html += "  <div class='unite-repeater-item-title'>" + itemValues.title + "</div>";
    43544404        }
    43554405
    4356         html += "    <div class='unite-repeater-item-actions'>";
    4357         html += "     <button class='unite-repeater-item-action unite-repeater-item-duplicate uc-tip' title='" + textDuplicate + "'><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M8.625.375H.375v8.25h8.25V.375Z' /><path d='M10.125 3.375h1.5v8.25h-8.25v-1.5' /></svg></button>";
    4358         html += "       <button class='unite-repeater-item-action unite-repeater-item-delete uc-tip' title='" + textDelete + "'><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='m1.5 1.5 9 9M10.5 1.5l-9 9' /></svg></button>";
    4359         html += "    </div>";
    4360         html += "   </div>";
    4361         html += "   <div class='unite-repeater-item-content'>";
    4362         html += objSettingsTemplate.html();
    4363         html += "   </div>";
    4364         html += "</div>";
    4365 
    4366         // change item settings IDs
    4367         var objItem = jQuery(html);
    4368         var objItemSettingsWrapper = objItem.find(".unite_settings_wrapper");
    4369 
    4370         g_ucAdmin.validateDomElement(objItemSettingsWrapper, "item settings wrapper");
    4371 
    4372         var template = jQuery("#" + g_objWrapper.attr("id") + "-options");
    4373         var options = null;
     4406        html += "     <div class='unite-repeater-item-actions'>";
     4407        html += "       <button class='unite-repeater-item-action unite-repeater-item-duplicate uc-tip' title='" + textDuplicate + "'><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M8.625.375H.375v8.25h8.25V.375Z' /><path d='M10.125 3.375h1.5v8.25h-8.25v-1.5' /></svg></button>";
     4408        html += "       <button class='unite-repeater-item-action unite-repeater-item-delete uc-tip' title='" + textDelete + "'><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='m1.5 1.5 9 9M10.5 1.5l-9 9' /></svg></button>";
     4409        html += "     </div>";
     4410        html += "   </div>";
     4411        html += "   <div class='unite-repeater-item-content'>";
     4412        html +=         objSettingsTemplate.html();
     4413        html += "   </div>";
     4414        html += "</div>";
     4415
     4416        // change item settings IDs
     4417        var objItem               = jQuery(html);
     4418        var objItemSettingsWrapper = objItem.find(".unite_settings_wrapper");
     4419
     4420        g_ucAdmin.validateDomElement(objItemSettingsWrapper, "item settings wrapper");
     4421
     4422        var template = objSettingsTemplate.find(".tpl-options").first();
     4423        var options  = null;
     4424
    43744425        if (template.length) {
    43754426            try {
    4376                 options = JSON.parse(template.html().trim());
     4427                var raw;
     4428
     4429                if (template[0].content && template[0].content.textContent) {
     4430                    raw = template[0].content.textContent.trim();
     4431                } else {
     4432                    raw = (template.html() || "").trim();
     4433                }
     4434
     4435                if (raw) {
     4436                    options = JSON.parse(raw);
     4437                }
    43774438            } catch (e) {
    43784439                console.warn("Options JSON parse error:", e);
     
    43804441        }
    43814442
    4382         var idPrefix = options?.id_prefix;
    4383         var newID = idPrefix + "item_" + itemValues._generated_id + "_";
    4384 
    4385         html = g_ucAdmin.replaceAll(html, idPrefix, newID);
    4386 
    4387         // change item settings wrapper ID
    4388         objItem = jQuery(html);
    4389         objItemSettingsWrapper = objItem.find(".unite_settings_wrapper");
    4390         objItemSettingsWrapper.attr("id", "unite_settings_repeater_" + newID);
    4391 
    4392         if (objItemInsertAfter)
    4393             objItemInsertAfter.after(objItem);
    4394         else
    4395             objItemsWrapper.append(objItem);
    4396 
    4397         // init item settings
    4398         var objSettings = new UniteSettingsUC();
    4399 
     4443        var idPrefix = options && options.id_prefix ? options.id_prefix : null;
     4444
     4445        if (!idPrefix) {
     4446            idPrefix = (g_IDPrefix || "#unite_setting_").replace(/^#/, "");
     4447        }
     4448
     4449        var newID = idPrefix + "item_" + itemValues._generated_id + "_";
     4450
     4451        html = g_ucAdmin.replaceAll(html, idPrefix, newID);
     4452
     4453        objItem               = jQuery(html);
     4454        objItemSettingsWrapper = objItem.find(".unite_settings_wrapper");
     4455
     4456        objItemSettingsWrapper.attr("id", "unite_settings_repeater_" + newID);
     4457
     4458        if (objItemInsertAfter)
     4459            objItemInsertAfter.after(objItem);
     4460        else
     4461            objItemsWrapper.append(objItem);
     4462
     4463        // init item settings
     4464        var objSettings = new UniteSettingsUC();
    44004465        objSettings.init(objItemSettingsWrapper, { cacheValues: itemValues });
    4401         objSettings?.setValues(itemValues);
    4402 
    4403         objItem.data("objsettings", objSettings);
    4404 
    4405         // init item title change
    4406         var objTitleInput = objSettings.getInputByName("title");
    4407         var objItemTitle = objItem.find(".unite-repeater-item-title");
    4408 
    4409         objTitleInput?.on("input", function () {
    4410             var value = objTitleInput.val();
    4411 
    4412             objItemTitle.text(value);
    4413         });           
    4414 
    4415         t.onSettingChange(null, objWrapper);
    4416     }
     4466        objSettings.setValues && objSettings.setValues(itemValues);
     4467
     4468        objItem.data("objsettings", objSettings);
     4469
     4470        // init item title change
     4471        var objTitleInput = objSettings.getInputByName("title");
     4472        var objItemTitle  = objItem.find(".unite-repeater-item-title");
     4473
     4474        if (objTitleInput && objTitleInput.length) {
     4475            objTitleInput.on("input", function () {
     4476                var value = objTitleInput.val();
     4477
     4478                if (value === "") {
     4479                    objItemTitle
     4480                        .addClass("unite-repeater-item-title-placeholder")
     4481                        .text("Item Title");
     4482                } else {
     4483                    objItemTitle
     4484                        .removeClass("unite-repeater-item-title-placeholder")
     4485                        .text(value);
     4486                }
     4487            });
     4488        }
     4489
     4490        t.onSettingChange(null, objWrapper);
     4491    }
    44174492
    44184493    /**
     
    44494524     */
    44504525    function getRepeaterValues(objWrapper) {
     4526       
    44514527        var values = [];
    44524528
     
    44704546
    44714547            if (obj && typeof obj.getSettingsValues === "function") {
    4472             values.push(obj.getSettingsValues());
     4548                values.push(obj.getSettingsValues());
    44734549            }
    44744550        });
     
    46464722            return;
    46474723
    4648         if (!g_arrControls[controlID])
    4649             return;
     4724        if (!g_arrControls[controlID]) 
     4725            return;
    46504726
    46514727        var controlValue = getSettingInputValue(objInput);
     
    46584734
    46594735        jQuery.each(arrChildControls, function (childName, objControl) {
     4736
    46604737            var isSap = g_ucAdmin.getVal(objControl, "forsap");
    46614738            var rowID;
     
    46654742                rowID = g_IDPrefix + "ucsap_" + childName;
    46664743            } else { //setting
    4667                 rowID = g_IDPrefix + childName + "_row";
    4668                 objChildInput = jQuery(g_IDPrefix + childName);
     4744                // rowID = g_IDPrefix + childName + "_row";
     4745                // objChildInput = jQuery(g_IDPrefix + childName);
     4746
     4747                rowID = '#' + g_objWrapper.attr('id') + ' [data-name=' + childName + ']' ;
    46694748            }
    46704749
     
    49164995            var objPicker = jQuery(this);
    49174996           
    4918             objPicker.html('<option value="px" data-content="<div class=\'unite-units-picker-item\'>px</div>">px</option><option value="vh" data-content="<div class=\'unite-units-picker-item\'>vh</div>">vh</option><option value="%" data-content="<div class=\'unite-units-picker-item\'>%</div>">%</option><option value="em" data-content="<div class=\'unite-units-picker-item\'>em</div>">em</option><option value="rem" data-content="<div class=\'unite-units-picker-item\'>rem</div>">rem</option>').val(objPicker.data('value'));
     4997            objPicker.html('<option value="px" data-content="<div class=\'unite-units-picker-item\'>px</div>">px</option><option value="vh" data-content="<div class=\'unite-units-picker-item\'>vh</div>">vh</option><option value="%" data-content="<div class=\'unite-units-picker-item\'>%</div>">%</option><option value="em" data-content="<div class=\'unite-units-picker-item\'>em</div>">em</option><option value="rem" data-content="<div class=\'unite-units-picker-item\'>rem</div>">rem</option><option value="deg" data-content="<div class=\'unite-units-picker-item\'>deg</div>">deg</option>').val(objPicker.data('value'));
    49194998
    49204999            initSelect2(objPicker, {
     
    49925071     */
    49935072    this.getSelectorsCss = function () {
     5073       
    49945074        var objInputs = getObjInputs();
     5075       
    49955076        var css = "";
    49965077
    49975078        jQuery.each(objInputs, function () {
     5079                       
    49985080            var objInput = jQuery(this);
    4999 
     5081           
    50005082            // skip hidden/disabled setting
    50015083            if (objInput.closest(".unite-setting-row").hasClass("unite-setting-hidden") === true)
     
    50045086            var type = getInputType(objInput);
    50055087            var style;
    5006 
     5088           
    50075089            switch (type) {
    50085090                case "repeater":
     
    50135095                break;
    50145096            }
    5015 
     5097           
     5098           
     5099            //-- debug selector css
     5100           
     5101            if(isDebugSelector(objInput) == true){
     5102                trace("process input selectors: "+name);
     5103                var name = getInputName(objInput);
     5104                trace(objInput);
     5105                trace(style);
     5106            }
     5107                           
     5108           
    50165109            if (style)
    50175110                css += style;
     
    50305123                selector = selector.trim();
    50315124
    5032                 if (g_selectorWrapperID)
    5033                     selector = "#" + g_selectorWrapperID + " " + selector;
     5125                if (g_selectorWrapperID) {
     5126                    let selectorId = jQuery('#' + g_selectorWrapperID + ' .ue-widget-root').attr('id');
     5127                    selector = "." + selectorId + " " + selector;
     5128                }
     5129                   
    50345130
    50355131                return selector;
     
    50785174     * get dimentions selector replaces
    50795175     */
    5080     function getDimentionsSelectorReplaces(value) {
    5081         return {
    5082             "{{top}}": value.top + value.unit,
    5083             "{{right}}": value.right + value.unit,
    5084             "{{bottom}}": value.bottom + value.unit,
    5085             "{{left}}": value.left + value.unit
    5086         };
    5087     }
     5176    function getDimentionsSelectorReplaces(value, isDebug){
     5177               
     5178        if(isDebug === true){
     5179            trace("get dimentions replaces");
     5180            trace(value);
     5181        }
     5182       
     5183        if (!value || typeof value !== "object")
     5184            return;
     5185
     5186        var unit = value.unit || "px";
     5187
     5188        function normSide(side) {
     5189            if (side === "" || side == null)
     5190                return "";
     5191
     5192            return side + unit;
     5193        }
     5194
     5195        var top    = normSide(value.top);
     5196        var right  = normSide(value.right);
     5197        var bottom = normSide(value.bottom);
     5198        var left   = normSide(value.left);
     5199
     5200        if (!top && !right && !bottom && !left)
     5201            return;
     5202
     5203        if (!top)    top    = "0" + unit;
     5204        if (!right)  right  = "0" + unit;
     5205        if (!bottom) bottom = "0" + unit;
     5206        if (!left)   left   = "0" + unit;
     5207
     5208        return {
     5209            "{{top}}": top,
     5210            "{{right}}": right,
     5211            "{{bottom}}": bottom,
     5212            "{{left}}": left
     5213        };
     5214    }
    50885215
    50895216    /**
     
    51165243     * get input selector replaces
    51175244     */
    5118     function getInputSelectorReplaces(objInput) {
    5119 
    5120         if (!objInput || objInput.length === 0) return;
     5245    function getInputSelectorReplaces(objInput, isDebug) {
     5246
     5247        if (!objInput || objInput.length === 0)
     5248            return;
     5249       
    51215250        var value = getSettingInputValue(objInput);
    5122 
     5251       
     5252        if(isDebug == true){
     5253            trace("run function: getInputSelectorReplaces");
     5254            trace(value);
     5255        }
     5256       
    51235257        if (!value)
    51245258            return;
    5125 
     5259       
    51265260        var type = getInputType(objInput);
    5127 
     5261       
     5262        if (value === g_vars.NOT_UPDATE_OPTION)
     5263            return;
     5264
     5265        if (value === "" || value == null)
     5266            return;
     5267       
     5268        // if (typeof value != "object") return;
     5269       
    51285270        switch (type) {
    51295271            case "dimentions":
    5130                 return getDimentionsSelectorReplaces(value);
     5272                var replaces = getDimentionsSelectorReplaces(value);
     5273                return replaces;
     5274            break;
    51315275            case "image":
    5132                 return getImageSelectorReplaces(value);
     5276                var replaces = getImageSelectorReplaces(value);
     5277                return replaces;
     5278            break;
    51335279            case "range":
    5134                 return getRangeSliderSelectorReplaces(value);
    5135         }
    5136 
     5280                var replaces = getRangeSliderSelectorReplaces(value);
     5281                return replaces;
     5282            break;
     5283        }
     5284       
    51375285        return { "{{value}}": value };
    51385286    }
     5287
     5288   
    51395289
    51405290    /**
     
    51875337     */
    51885338    function processInputSelectors(objInput) {
     5339       
    51895340        var groupSelector = objInput.data("group-selector");
    51905341
     
    51995350        var type = getInputType(objInput);
    52005351        var style;
    5201 
     5352       
    52025353        switch (type) {
    52035354            case "group_selector":
     
    52155366            break;
    52165367        }
    5217 
     5368       
    52185369        if (!style)
    52195370            return;
    5220 
     5371       
    52215372        var device = getResponsivePickerValue(objInput);
    5222 
     5373       
    52235374        switch (device) {
    52245375            case "tablet":
     
    52365387     * process repeater selectors
    52375388     */
    5238     function processRepeaterSelectors(objWrapper) {
     5389    function processRepeaterSelectors(objWrapper) {
    52395390        var style = "";
    52405391
    52415392        objWrapper.find(".unite-repeater-item").each(function () {
    5242             var objSettings = jQuery(this).data("objsettings");
    5243 
    5244             objSettings?.setSelectorWrapperID(g_selectorWrapperID);
    5245 
    5246             var value = objSettings?.getSettingsValues();
    5247             var css = objSettings?.getSelectorsCss();
    5248 
    5249             css = processSelectorReplaces(css, { "{{current_item}}": ".elementor-repeater-item-" + value?._generated_id });
    5250 
    5251             style += css;
     5393            var objItem = jQuery(this);
     5394            var objSettings = objItem.data("objsettings");
     5395
     5396            if (!objSettings) {
     5397                var $inner = objItem.find(".unite_settings_wrapper");
     5398                if ($inner.length) {
     5399                    try {
     5400                        objSettings = new UniteSettingsUC();
     5401                        objSettings.init($inner, {});           
     5402                        objItem.data("objsettings", objSettings);
     5403                    } catch (e) {
     5404                        objSettings = null;
     5405                    }
     5406                }
     5407            }
     5408
     5409            if (objSettings) {
     5410
     5411                objSettings.setSelectorWrapperID(g_selectorWrapperID);
     5412
     5413                var value = objSettings.getSettingsValues();
     5414                var css = objSettings.getSelectorsCss();
     5415
     5416                css = processSelectorReplaces(css, { "{{current_item}}": ".elementor-repeater-item-" + value?._generated_id });
     5417
     5418                style += css;
     5419            }
    52525420        });
    52535421
     
    52965464     */
    52975465    function getInputSelectorsStyle(objInput, selectors) {
    5298         var replaces = getInputSelectorReplaces(objInput);
     5466       
     5467        //debug
     5468        var isDebug = isDebugSelector(objInput);
     5469       
     5470        if(isDebug){
     5471            trace("Run function: getInputSelectorsStyle");
     5472            trace("get selector style: "+g_debug_selectors);
     5473        }
     5474       
     5475        var replaces = getInputSelectorReplaces(objInput, isDebug);
     5476       
     5477        if(isDebug){
     5478            trace("replacers");
     5479            trace(replaces);
     5480        }
    52995481
    53005482        if (!replaces)
    53015483            return;
    5302 
    5303         return getSelectorsStyle(selectors, replaces);
     5484       
     5485        var style = getSelectorsStyle(selectors, replaces);
     5486
     5487        if(isDebug){
     5488            trace("style");
     5489            trace(style);
     5490        }
     5491       
     5492        return style;
     5493    }
     5494   
     5495    /**
     5496     * check if debug selector
     5497     */
     5498    function isDebugSelector(objInput){
     5499       
     5500        if(!g_debug_selectors)
     5501            return(g_debug_selectors);
     5502       
     5503        var name = getInputName(objInput);
     5504        if(name == g_debug_selectors)
     5505            return(true);
     5506       
     5507        return(false);
    53045508    }
    53055509
  • unlimited-elements-for-elementor/trunk/js/unitecreator_addon_config.js

    r2535588 r3429507  
    661661    this.init = function(objWrapper, isPreviewMode){
    662662       
     663       
    663664        if(g_objWrapper)
    664665            throw new Error("the config is alrady inited, can't init it twice");
     
    687688        parseInputOptions(objOptions);
    688689       
    689        
    690690        //set settings events
     691       
    691692        g_objSettings.init(g_objSettingsContainer);
    692                                
     693                   
    693694        initEvens();
    694695               
  • unlimited-elements-for-elementor/trunk/js/unitecreator_addondefaults_admin.js

    r2386165 r3429507  
    170170     */
    171171    this.init = function(){
    172        
     172               
    173173        g_objWrapper = jQuery("#uc_addondefaults_wrapper");
    174174        g_options = g_objWrapper.data("options");
  • unlimited-elements-for-elementor/trunk/provider/assets/provider_admin.js

    r3329756 r3429507  
    642642     * get first editor options
    643643     */
    644     function initEditor_tinyMCE_GetOptions(objEditorsOptions) {
    645         if (jQuery.isEmptyObject(objEditorsOptions))
    646             return {};
    647 
    648         for (var key in objEditorsOptions) {
    649             var options = objEditorsOptions[key];
    650 
    651             if (options !== null)
    652                 return options;
    653         }
    654 
    655         return {};
    656     }
     644
     645    function initEditor_tinyMCE_GetOptions(objEditorsOptions) {
     646        if (!objEditorsOptions || jQuery.isEmptyObject(objEditorsOptions))
     647            return {};
     648
     649        for (var key in objEditorsOptions) {
     650            if (!objEditorsOptions.hasOwnProperty(key)) continue;
     651            var options = objEditorsOptions[key];
     652
     653            if (options != null)
     654                return options;
     655        }
     656
     657        return {};
     658    }
    657659
    658660    /**
    659661     * trigger change on editor, pass back
    660662     */
    661     function onEditorChange(editor, objSettings){
    662 
    663         var objInput = editor.getElement();
    664         objInput = jQuery(objInput);
    665         objSettings.triggerKeyupEvent(objInput);
    666     }
     663    var uelm_ucEditorChangeTimers = uelm_ucEditorChangeTimers || {};
     664
     665    function onEditorChange(editor, objSettings) {
     666
     667        var DEBOUNCE_DELAY = 600;
     668
     669        var editorId = editor && (editor.id || (editor.getElement && editor.getElement().id));
     670        if (!editorId)
     671            return;
     672
     673        if (uelm_ucEditorChangeTimers[editorId]) {
     674            clearTimeout(uelm_ucEditorChangeTimers[editorId]);
     675        }
     676
     677        uelm_ucEditorChangeTimers[editorId] = setTimeout(function () {
     678
     679            if (!editor || !editor.getElement) {
     680                return;
     681            }
     682
     683            var el = editor.getElement();
     684            if (!el)
     685                return;
     686
     687            editor.save();
     688
     689            var $el = jQuery(el);
     690
     691            $el.trigger("keyup");
     692            $el.trigger("change");
     693
     694            delete uelm_ucEditorChangeTimers[editorId];
     695
     696        }, DEBOUNCE_DELAY);
     697    }
    667698
    668699    /**
     
    714745     */
    715746    function initEditors_afterTimeout(objSettings, arrEditorNames, isForce) {
     747
    716748        if (typeof window.tinyMCEPreInit === "undefined" && arrEditorNames.length)
    717749            throw new Error("Init " + arrEditorNames[0] + " editor error. no other editors found on page");
     
    725757            if (isForce === true
    726758                || window.tinyMCEPreInit.mceInit.hasOwnProperty(inputID) === false
    727                 || window.tinyMCEPreInit.mceInit[inputID] === null)
    728                 initEditor_tinyMCE(inputID, objSettings);
     759                || window.tinyMCEPreInit.mceInit[inputID] === null) {
     760                    initEditor_tinyMCE(inputID, objSettings);
     761            }
     762               
    729763        });
    730764    }
     
    929963                }
    930964
    931                 window.tinyMCEPreInit.mceInit[editorID] = null;
    932                 window.tinyMCEPreInit.qtInit[editorID] = null;
     965                // window.tinyMCEPreInit.mceInit[editorID] = null;
     966                // window.tinyMCEPreInit.qtInit[editorID] = null;
     967
     968                if (window.tinyMCEPreInit && window.tinyMCEPreInit.mceInit) {
     969                    delete window.tinyMCEPreInit.mceInit[editorID];
     970                }
     971
     972                if (window.tinyMCEPreInit && window.tinyMCEPreInit.qtInit) {
     973                    delete window.tinyMCEPreInit.qtInit[editorID];
     974                }
    933975            }
    934976        });
  • unlimited-elements-for-elementor/trunk/provider/core/unlimited_elements/dialog_param_elementor.class.php

    r3329756 r3429507  
    944944        $arrTypes["rss_feed"] = __("Rss Feed Fields","unlimited-elements-for-elementor");
    945945        $arrTypes["repeater"] = __("Repeater","unlimited-elements-for-elementor");
     946        $arrTypes["reviews"] = __("Google Reviews","unlimited-elements-for-elementor");
    946947       
    947948        $optionsClass = "uc-special-attribute-options";
  • unlimited-elements-for-elementor/trunk/provider/core/unlimited_elements/gutenberg/assets/gutenberg_integrate.js

    r3397365 r3429507  
    33
    44(function (wp) {
    5     var g_debug = true;
     5   
     6    var g_debug = true;
     7   
    68    function trace(str){ console.log(str); }
    79    function debug(){ if(!g_debug) return; console.log.apply(console, arguments); }
    8 
    9     // ping editor to activate Save btn
    10     function pingSaveButton(){
    11         try{
    12             const d = wp?.data?.dispatch('core/editor');
    13             if (d?.editPost) { d.editPost({}); return; }
    14         }catch(e){}
    15         try{
    16             const d = wp?.data?.dispatch('core/edit-site');
    17             if (d?.setIsDirty) { d.setIsDirty(true); return; }
    18         }catch(e){}
    19         try{
    20             const d = wp?.data?.dispatch('core/edit-widgets');
    21             if (d?.setHasEdits) { d.setHasEdits(true); return; }
    22         }catch(e){}
    23     }
    24 
     10   
    2511    var wbe = wp.blockEditor;
    2612    var wc  = wp.components;
     
    4531            return el("img", { src: previewUrl, style: { width: "100%", height: "auto" } });
    4632
    47         var blockProps             = wbe.useBlockProps();
    48         var widgetContentState     = we.useState(null);
    49         var settingsVisibleState   = we.useState(false);
    50         var settingsContentState   = we.useState(null);
    51         var isLoadingSettingsState = we.useState(false);
    52 
    53         var widgetRef              = we.useRef(null);
    54         var widgetLoaderRef        = we.useRef(null);
    55         var widgetRequestRef       = we.useRef(null);
    56 
    57         var ucSettingsRef          = we.useRef(new UniteSettingsUC());
    58         var ucHelperRef            = we.useRef(new UniteCreatorHelper());
    59 
    60         var settingsInitedRef            = we.useRef(false);
    61         var initedSettingsElementRef     = we.useRef(null);
    62         var lastSentDataRef              = we.useRef(null);
    63         var settingsObserverRef          = we.useRef(null);
    64         var settingsWatchdogTimerRef     = we.useRef(null);
    65 
    66         var ucSettings = ucSettingsRef.current;
    67         var ucHelper   = ucHelperRef.current;
     33        const blockProps = wbe.useBlockProps();
     34
     35        // block options cache key
     36        const cacheKeyBase = props.clientId || props.attributes._id;
     37
     38        // state
     39        const [widgetContent,     setWidgetContent]     = we.useState(null);
     40        const [settingsVisible,   setSettingsVisible]   = we.useState(false);
     41        const [settingsContent,   setSettingsContent]   = we.useState(null);
     42        const [isLoadingSettings, setIsLoadingSettings] = we.useState(false);
     43
     44        // refs
     45        const widgetRef         = we.useRef(null);
     46        const widgetLoaderRef   = we.useRef(null);
     47        const widgetRequestRef  = we.useRef(null);
     48
     49        const ucSettingsRef     = we.useRef(new UniteSettingsUC());
     50        const ucHelperRef       = we.useRef(new UniteCreatorHelper());
     51
     52        const settingsInitedRef        = we.useRef(false);
     53        const initedSettingsElementRef = we.useRef(null);
     54        const lastSentDataRef          = we.useRef(null);
     55        const settingsObserverRef      = we.useRef(null);
     56
     57        const ucSettings = ucSettingsRef.current;
     58        const ucHelper   = ucHelperRef.current;
    6859
    6960        // orchestrator refs
    70         const didFirstPreviewRef    = we.useRef(false); 
    71         const firstPreviewReadyRef  = we.useRef(false);   
    72         const lastPreviewPayloadRef = we.useRef(null);   
    73         const firstPreviewTimerRef  = we.useRef(null); 
     61        const didFirstPreviewRef    = we.useRef(false);
     62        const firstPreviewReadyRef  = we.useRef(false);
     63        const lastPreviewPayloadRef = we.useRef(null);
     64        const firstPreviewTimerRef  = we.useRef(null);
    7465
    7566        function isSettingsReady() {
     
    8071        }
    8172
    82         // root block's element
    8373        function getWidgetRootEl(){
    8474            const $root = jQuery(widgetRef.current);
    85             // пробуем найти «внутренний» корень, если он помечен
     75
    8676            const $inner = $root.find('[data-uc-root]').first();
    8777            return ($inner.length ? $inner : $root);
    8878        }
    8979
    90         function ensureStyleTag($root){
    91             if ($root.find("[name=uc_selectors_css]").length === 0) {
    92                 $root.prepend('<style name="uc_selectors_css"></style>');
    93             }
    94             return $root.find("[name=uc_selectors_css]");
    95         }
    96 
    9780        function applyStylePreviewOnce(maxTries = 30, delay = 50){
     81
     82            if (!props.isSelected) {
     83                return;
     84            }
     85
    9886            let tries = 0;
    9987            (function tick(){
     
    10290
    10391                if ($root.length && ready) {
    104                     ensureStyleTag($root);
    105                     const css = (ucSettings.getSelectorsCss && ucSettings.getSelectorsCss()) || '';
    106                     if (css && css !== lastSelectorsCssRef.current) {
    107                         $root.find("[name=uc_selectors_css]").text(css);
    108                         lastSelectorsCssRef.current = css;
    109                     }
    110 
    111                     const selIncludes = ucSettings.getSelectorsIncludes && ucSettings.getSelectorsIncludes();
    112                     const selHash = stableStringify(selIncludes || {});
    113                     if (selIncludes && selHash !== lastIncludesHashRef.current) {
    114                         ucHelper.putIncludes(getPreviewWindowElement(), selIncludes);
    115                         lastIncludesHashRef.current = selHash;
    116                     }
    117                     // одновременно прокинем box-model, если есть
    118                     applyLiveBoxModelInline();
     92                    updateSelectorsPreview();
    11993                    return;
    12094                }
     
    12498
    12599        // --- delay for color/range/dimensions ---
    126         const DELAY_MS = 800;
    127100        const saveDelayTimerRef = we.useRef(null);
    128         const pendingSaveRef       = we.useRef(false);
    129101        const lastChangeTypeRef    = we.useRef(null);
    130102        const suppressNextReloadRef= we.useRef(false);
    131         const pendingSuppressByDomRef = we.useRef(false);
    132 
    133         const styleOnlyDirtyRef    = we.useRef(false);
    134103
    135104        const lastSelectorsCssRef  = we.useRef('');
     
    137106
    138107        function applyLiveBoxModelInline(){
     108           
    139109            try{
    140110                if (!isSettingsReady()) return;
     
    169139        }
    170140
    171         // общая функция обновления css + includes + live box-model
     141        // update oldCss with props from newCss
     142        function mergeCss(oldCss, newCss) {
     143            function createEmptyMap() {
     144                return {
     145                    scopesOrder: [],         
     146                    selectorsOrder: {},       
     147                    rules: {}               
     148                };
     149            }
     150
     151            function ensureScope(map, scope) {
     152                if (!map.rules[scope]) {
     153                    map.rules[scope] = {};
     154                    map.selectorsOrder[scope] = [];
     155                    map.scopesOrder.push(scope);
     156                }
     157            }
     158
     159            function addRuleToMap(map, scope, selector, body) {
     160                selector = selector && selector.trim();
     161                if (!selector) return;
     162
     163                var decls = {};
     164                var parts = body.split(';');
     165                for (var i = 0; i < parts.length; i++) {
     166                    var part = parts[i].trim();
     167                    if (!part) continue;
     168                    var colonPos = part.indexOf(':');
     169                    if (colonPos === -1) continue;
     170                    var prop = part.slice(0, colonPos).trim();
     171                    var val  = part.slice(colonPos + 1).trim();
     172                    if (!prop || !val) continue;
     173                    decls[prop] = val;
     174                }
     175
     176                if (!Object.keys(decls).length) return;
     177
     178                ensureScope(map, scope);
     179                if (!map.rules[scope][selector]) {
     180                    map.rules[scope][selector] = {};
     181                    map.selectorsOrder[scope].push(selector);
     182                }
     183
     184                var target = map.rules[scope][selector];
     185                for (var p in decls) {
     186                    target[p] = decls[p];
     187                }
     188            }
     189
     190            function parseSimpleRulesInto(map, scope, css) {
     191                var len = css.length;
     192                var i = 0;
     193                while (i < len) {
     194
     195                    while (i < len && /\s|;/.test(css[i])) i++;
     196                    if (i >= len) break;
     197
     198                    if (css[i] === '}') {
     199                        i++;
     200                        continue;
     201                    }
     202
     203                    var selStart = i;
     204                    while (i < len && css[i] !== '{' && css[i] !== '}') i++;
     205                    if (i >= len || css[i] === '}') {
     206                        i++;
     207                        continue;
     208                    }
     209                    var selector = css.slice(selStart, i).trim();
     210                    i++;
     211
     212                    var bodyStart = i;
     213                    var depth = 1;
     214                    while (i < len && depth > 0) {
     215                        if (css[i] === '{') depth++;
     216                        else if (css[i] === '}') depth--;
     217                        i++;
     218                    }
     219                    var body = css.slice(bodyStart, i - 1);
     220
     221                    addRuleToMap(map, scope, selector, body);
     222                }
     223            }
     224
     225            function parseCssToMap(css) {
     226                var map = createEmptyMap();
     227                if (!css) return map;
     228
     229                var len = css.length;
     230                var i = 0;
     231
     232                while (i < len) {
     233
     234                    while (i < len && /\s|;/.test(css[i])) i++;
     235                    if (i >= len) break;
     236
     237                    if (css[i] === '@') {
     238                        var atStart = i;
     239                        while (i < len && css[i] !== '{') i++;
     240                        if (i >= len) break;
     241                        var prelude = css.slice(atStart, i).trim();
     242                        i++; // '{'
     243
     244                        var bodyStart = i;
     245                        var depth = 1;
     246                        while (i < len && depth > 0) {
     247                            if (css[i] === '{') depth++;
     248                            else if (css[i] === '}') depth--;
     249                            i++;
     250                        }
     251                        var body = css.slice(bodyStart, i - 1);
     252
     253                        parseSimpleRulesInto(map, prelude, body);
     254                    } else if (css[i] === '}') {
     255                        i++;
     256                        continue;
     257                    } else {
     258
     259                        var selStart = i;
     260                        while (i < len && css[i] !== '{' && css[i] !== '}') i++;
     261                        if (i >= len || css[i] === '}') {
     262                            i++;
     263                            continue;
     264                        }
     265                        var selector = css.slice(selStart, i).trim();
     266                        i++;
     267
     268                        var bodyStart2 = i;
     269                        var depth2 = 1;
     270                        while (i < len && depth2 > 0) {
     271                            if (css[i] === '{') depth2++;
     272                            else if (css[i] === '}') depth2--;
     273                            i++;
     274                        }
     275                        var body2 = css.slice(bodyStart2, i - 1);
     276
     277                        addRuleToMap(map, '', selector, body2);
     278                    }
     279                }
     280
     281                return map;
     282            }
     283
     284            function mapToCss(map) {
     285                var out = '';
     286
     287                for (var s = 0; s < map.scopesOrder.length; s++) {
     288                    var scope = map.scopesOrder[s];
     289                    var selectors = map.selectorsOrder[scope];
     290                    if (!selectors || !selectors.length) continue;
     291
     292                    if (scope === '') {
     293
     294                        for (var i = 0; i < selectors.length; i++) {
     295                            var sel = selectors[i];
     296                            var props = map.rules[scope][sel];
     297                            var keys = Object.keys(props);
     298                            if (!keys.length) continue;
     299                            out += sel + '{';
     300                            for (var k = 0; k < keys.length; k++) {
     301                                var prop = keys[k];
     302                                out += prop + ':' + props[prop] + ';';
     303                            }
     304                            out += '}';
     305                        }
     306                    } else {
     307
     308                        var inner = '';
     309                        for (var j = 0; j < selectors.length; j++) {
     310                            var sel2 = selectors[j];
     311                            var props2 = map.rules[scope][sel2];
     312                            var keys2 = Object.keys(props2);
     313                            if (!keys2.length) continue;
     314                            inner += sel2 + '{';
     315                            for (var k2 = 0; k2 < keys2.length; k2++) {
     316                                var prop2 = keys2[k2];
     317                                inner += prop2 + ':' + props2[prop2] + ';';
     318                            }
     319                            inner += '}';
     320                        }
     321                        if (inner) {
     322                            out += scope + '{' + inner + '}';
     323                        }
     324                    }
     325                }
     326
     327                return out;
     328            }
     329
     330            var oldMap = parseCssToMap(oldCss || '');
     331            var newMap = parseCssToMap(newCss || '');
     332
     333            for (var s = 0; s < newMap.scopesOrder.length; s++) {
     334                var scope = newMap.scopesOrder[s];
     335                var newSelectors = newMap.selectorsOrder[scope];
     336                if (!newSelectors || !newSelectors.length) continue;
     337
     338                ensureScope(oldMap, scope);
     339
     340                for (var i = 0; i < newSelectors.length; i++) {
     341                    var sel = newSelectors[i];
     342                    var newProps = newMap.rules[scope][sel];
     343
     344                    if (!oldMap.rules[scope][sel]) {
     345                        oldMap.rules[scope][sel] = {};
     346                        oldMap.selectorsOrder[scope].push(sel);
     347                    }
     348
     349                    var target = oldMap.rules[scope][sel];
     350                    for (var p in newProps) {
     351                        target[p] = newProps[p];
     352                    }
     353                }
     354            }
     355
     356            return mapToCss(oldMap);
     357        }
     358
     359       /**
     360        * update selectors preview
     361        */
    172362        function updateSelectorsPreview() {
    173             if (!isSettingsReady()) return;
     363           
     364            var isDetailedDebug = false;
     365           
     366            debug("run func: updateSelectorsPreview");
     367                                   
     368            if (!props.isSelected) {
     369               
     370                if(isDetailedDebug == true)
     371                    trace("not selected, exit");
     372               
     373                return;
     374            }
     375
     376            if (!isSettingsReady()) {
     377               
     378                if(isDetailedDebug == true)
     379                    trace("not ready, exit");
     380               
     381                return;
     382            }
    174383            const $root = jQuery(widgetRef.current);
    175             if ($root.length === 0) return;
    176 
    177             ensureStyleTag($root);
    178 
     384            if ($root.length === 0) {
     385               
     386                if(isDetailedDebug == true)
     387                    trace("not root, exit");
     388               
     389                return;
     390            }
     391                       
    179392            const css = (ucSettings.getSelectorsCss && ucSettings.getSelectorsCss()) || '';
     393           
    180394            if (css && css !== lastSelectorsCssRef.current) {
    181                 $root.find('[name=uc_selectors_css]').text(css);
    182                 lastSelectorsCssRef.current = css;
     395
     396                if ($root.find("[name=uc_selectors_css]").length === 0) {
     397                    $root.prepend('<style name="uc_selectors_css"></style>');
     398                }
     399                const $style = $root.find('[name=uc_selectors_css]');
     400                const prevCss = $style.text() || '';
     401
     402                const mergedCss = mergeCss(prevCss, css);
     403               
     404                $style.text(mergedCss);
     405                lastSelectorsCssRef.current = mergedCss;
     406               
     407                if(isDetailedDebug == true)
     408                    trace("merge css!");
     409               
     410            }else{
     411               
     412                if(isDetailedDebug == true)
     413                    trace("not root, exit");
     414               
    183415            }
    184416
     
    190422            }
    191423
    192             // и сразу инлайн-бокс-модель
    193424            applyLiveBoxModelInline();
    194         }
    195 
     425
     426        }
     427       
     428        /**
     429         * flush save new
     430         * @param typeOverride
     431         */
    196432        function flushSaveNow(typeOverride) {
    197433            if (!isSettingsReady()) return;
     
    212448
    213449                try {
    214                     delete uelm_WidgetSettingsCache[props.attributes._id];
    215                     uelm_WidgetSettingsCacheFlags[props.attributes._id] = false;
     450                    delete uelm_WidgetSettingsCache[cacheKeyBase];
     451                    delete uelm_WidgetSettingsCache[cacheKeyBase + '_settings'];
     452
     453                    uelm_WidgetSettingsCacheFlags[cacheKeyBase] = false;
     454                    uelm_WidgetSettingsCacheFlags[cacheKeyBase + '_settings'] = false;
    216455                } catch(e){}
    217456
     
    223462
    224463                props.setAttributes({ data: mergedStr });
    225                 styleOnlyDirtyRef.current = false;
    226             } finally {
    227                 pendingSaveRef.current = false;
    228             }
     464
     465            } finally { }
    229466        }
    230467
     
    243480        var settingsId    = "ue-gutenberg-settings-" + props.clientId;
    244481        var settingsErrorId = settingsId + "-error";
    245         var settingsVisible = settingsVisibleState[0];
    246         var setSettingsVisible = settingsVisibleState[1];
    247 
    248         var settingsContent = settingsContentState[0];
    249         var setSettingsContent = settingsContentState[1];
    250 
    251         var widgetContent = widgetContentState[0];
    252         var setWidgetContent = widgetContentState[1];
    253 
    254         var isLoadingSettings = isLoadingSettingsState[0];
    255         var setIsLoadingSettings = isLoadingSettingsState[1];
    256482
    257483        function stableStringify(obj){
    258484            try { return JSON.stringify(obj, Object.keys(obj).sort()); }
    259485            catch(e){ return ""; }
    260         }
    261         function deepEqual(a, b){
    262             if (a === b) return true;
    263             return stableStringify(a) === stableStringify(b);
    264486        }
    265487
     
    275497        };
    276498
    277         var saveSettingsIfChanged = function (explicitPatch, suppressReload) {
    278             const currentObj = (function(){
    279                 try { return props.attributes.data ? JSON.parse(props.attributes.data) : {}; }
    280                 catch(e){ return {}; }
    281             })();
    282 
    283             const patch     = explicitPatch || ucSettings.getSettingsValues();
    284             const mergedObj = { ...currentObj, ...patch };
    285 
    286             if (deepEqual(currentObj, mergedObj)) {
    287                 updateSelectorsPreview();
    288                 return;
    289             }
    290 
    291             const mergedStr = JSON.stringify(mergedObj);
    292 
    293             const isStyleOnly = !!suppressReload || !!pendingSuppressByDomRef.current;
    294             if (isStyleOnly) {
    295                 pendingSuppressByDomRef.current = false;
    296                 styleOnlyDirtyRef.current = true;
    297 
    298                 updateSelectorsPreview();
    299                 pingSaveButton();
    300                 return;
    301             }
    302 
    303             if (lastSentDataRef.current === mergedStr) {
    304                 updateSelectorsPreview();
    305                 return;
    306             }
    307 
    308             try {
    309                 delete uelm_WidgetSettingsCache[props.attributes._id];
    310                 uelm_WidgetSettingsCacheFlags[props.attributes._id] = false;
    311             } catch(e){}
    312 
    313             lastSentDataRef.current = mergedStr;
    314 
    315             props.setAttributes({
    316                 _rootId: ucHelper.getRandomString(5),
    317                 data: mergedStr,
    318             });
    319         };
    320 
    321499        var initSettings = function () {
     500           
     501            debug("init settings!");
     502           
    322503            var $settingsElement = getSettingsElement();
    323504            if (!$settingsElement || $settingsElement.length === 0) return;
     
    340521
    341522            function handleSettingsEvent(evt, payload) {
     523
     524                const name = (payload?.name ?? '').toString();
     525
    342526                const type = (payload?.type ?? '').toString().toLowerCase().trim();
    343527                const STYLE_ONLY_TYPES = ['color','range','dimensions'];
     
    347531                    // style only fields
    348532                    lastChangeTypeRef.current = 'styles';
    349 
    350                     styleOnlyDirtyRef.current = true;
    351533
    352534                    if (saveDelayTimerRef.current) {
     
    355537                    }
    356538                    saveDelayTimerRef.current = setTimeout(() => {
    357                         flushSaveNow(type);
     539                        flushSaveNow('styles');
    358540                    }, 180);
    359541                } else {
     
    367549                    flushSaveNow(type);
    368550                }
    369 
    370             }
    371 
     551            }
     552           
    372553            ucSettings.setEventOnChange(handleSettingsEvent);
    373554            if (typeof ucSettings.onEvent === 'function') {
     
    376557
    377558            ucSettings.setEventOnSelectorsChange(function () {
    378                 if (!isSettingsReady()) return;
     559               
     560                if (!isSettingsReady())
     561                    return;
     562
    379563                updateSelectorsPreview();
     564
     565                lastChangeTypeRef.current = 'styles';
     566
     567                flushSaveNow('styles');
    380568            });
    381569
    382570            ucSettings.setEventOnResponsiveTypeChange(function (event, type) {
    383                 uelm_WidgetSettingsCacheFlags[props.attributes._id] = true;
    384                 uelm_WidgetSettingsCacheFlags[props.attributes._id + '_settings'] = true;
     571                uelm_WidgetSettingsCacheFlags[cacheKeyBase] = true;
     572                uelm_WidgetSettingsCacheFlags[cacheKeyBase + '_settings'] = true;
    385573
    386574                var deviceType = type.charAt(0).toUpperCase() + type.substring(1);
     
    403591        };
    404592
     593        // init settings when panel visible + settings HTML ready + real DOM exists
    405594        function maybeInitSettings(){
    406             if (!settingsVisible) return;
    407             if (!settingsContent) return;
    408 
     595           
     596            if (!settingsVisible)
     597                return;
     598           
     599            if (!settingsContent)
     600                return;
     601           
    409602            var $settingsElement = getSettingsElement();
    410603            if (!$settingsElement || $settingsElement.length === 0) return;
     
    432625        }
    433626
    434         function startSettingsWatchdog(){
    435             stopSettingsWatchdog();
    436             settingsWatchdogTimerRef.current = setInterval(function(){
    437                 if (!settingsVisible || !settingsContent) return;
    438 
    439                 var $settingsElement = getSettingsElement();
    440                 var elem = $settingsElement && $settingsElement[0];
    441 
    442                 if (!elem) return;
    443 
    444                 if (!ucSettings.isInited() || initedSettingsElementRef.current !== elem) {
    445                     initSettings();
    446                 }
    447             }, 2000);
    448         }
    449         function stopSettingsWatchdog(){
    450             if (settingsWatchdogTimerRef.current) {
    451                 clearInterval(settingsWatchdogTimerRef.current);
    452                 settingsWatchdogTimerRef.current = null;
    453             }
    454         }
    455 
    456627        // AJAX: load settings HTML
    457628        var loadSettingsContent = function () {
    458             var widgetCacheKey = props.attributes._id + '_settings';
     629            var widgetCacheKey = cacheKeyBase + '_settings';
    459630
    460631            setIsLoadingSettings(true);
     
    480651            if (isTestFreeVersion) requestData.testfreeversion = true;
    481652
    482             debug('Load get_addon_settings_html');
    483653            g_ucAdmin.ajaxRequest("get_addon_settings_html", requestData, function (response) {
    484654
     
    497667        // AJAX: load widget HTML
    498668        var loadWidgetContent = function (overrideSettings) {
    499             var widgetCacheKey = props.attributes._id;
     669            var widgetCacheKey = cacheKeyBase;
    500670
    501671            if ( uelm_WidgetSettingsCache[widgetCacheKey] && uelm_WidgetSettingsCacheFlags[widgetCacheKey] ) {
     
    507677
    508678            if (!widgetContent) {
    509                 // load existing widgets from the page
    510                 for (var index in g_gutenbergParsedBlocks) {
    511                     var block = g_gutenbergParsedBlocks[index];
    512                     if (block.name === props.name) {
     679
     680                if (typeof window.uelm_setBlocks === 'undefined') {
     681                    window.uelm_setBlocks = new Set();
     682                }
     683               
     684                var blockKey = props.name + '_' + props.clientId;
     685
     686                if (window.uelm_setBlocks.has(blockKey)) {
     687                    // Block already processed, skipping
     688                    return;
     689                }
     690               
     691                for (var i = 0; i < g_gutenbergParsedBlocks.length; i++) {
     692                    var block = g_gutenbergParsedBlocks[i];
     693
     694                    if (block && block.name === props.name && block.html) {
     695                       
    513696                        setWidgetContent(block.html);
    514                         delete g_gutenbergParsedBlocks[index];
    515                         debug('loadWidgetContent loaded from page content');
     697
     698                        try {
     699                            if (isSettingsReady()) {
     700                                var values = getSettings();
     701                                if (values !== null) {
     702                                    ucSettings.setCacheValues(values);
     703                                }
     704                            }
     705                        } catch (e) {
     706                            console.warn('Failed to sync ucSettings from data after load-from-page', e);
     707                        }
     708
     709                        uelm_WidgetSettingsCache[widgetCacheKey] = {
     710                            html: block.html,
     711                            includes: {}   
     712                        };
     713                        uelm_WidgetSettingsCacheFlags[widgetCacheKey] = true;
     714                       
     715                        delete g_gutenbergParsedBlocks[i];
     716                       
     717                        window.uelm_setBlocks.add(blockKey);
     718                       
     719                        debug('loadWidgetContent loaded from page');
    516720                        return;
    517721                    }
    518722                }
     723               
     724                console.warn('No content found for block:', blockKey);
    519725            }
    520726
     
    527733            loaderElement.show();
    528734
    529             debug('loadWidgetContent load from server, uc_items length: ' + (settings?.uc_items?.length ?? 0));
     735            debug('loadWidgetContent load from server');
    530736
    531737            widgetRequestRef.current = g_ucAdmin.ajaxRequest("get_addon_output_data", {
     
    543749                loaderElement.hide();
    544750            });
     751
    545752        };
    546753
     
    569776
    570777            attachSettingsObserver();
    571             startSettingsWatchdog();
     778            // startSettingsWatchdog();
    572779
    573780            loadWidgetContent();
     
    610817        // mark color/range/dimensions to suppress reload
    611818        we.useEffect(function () {
     819
    612820            debug('[effect 3]');
    613             function markIfColorOrRange(e){
     821
     822            function checkEventType(e){
     823
    614824                const t = e.target;
    615825                if (!t) return;
     826
    616827                const settingsRoot = document.getElementById(settingsId);
    617828                if (!settingsRoot || !settingsRoot.contains(t)) return;
    618829
    619                 const type = (t.type || '').toLowerCase();
    620                 const hasColorClass = t.classList && t.classList.contains('unite-color-picker');
    621                 const isRange = type === 'range' || (t.classList && t.classList.contains('unite-range-slider'));
    622                 const isDimensions = !!(t.closest && t.closest('.unite-dimensions'));
    623 
    624                 if (hasColorClass) {
     830                const type         = (t.type || '').toLowerCase();
     831                const hasColor     = t.classList?.contains('unite-color-picker');
     832                const isRange      = type === 'range' || t.classList?.contains('unite-range-slider');
     833                const isDimensions = !!t.closest?.('.unite-dimensions');
     834
     835                if (hasColor) {
    625836                    lastChangeTypeRef.current = 'color';
    626                     pendingSuppressByDomRef.current = true;
    627                     pingSaveButton();
    628837                } else if (isRange || isDimensions) {
    629838                    lastChangeTypeRef.current = isDimensions ? 'dimensions' : 'range';
    630                     pendingSuppressByDomRef.current = true;
    631                     pingSaveButton();
    632                 }
    633             }
    634             document.addEventListener('input',  markIfColorOrRange, true);
    635             document.addEventListener('change', markIfColorOrRange, true);
     839                }
     840            }
     841
     842            document.addEventListener('input',  checkEventType, true);
     843            document.addEventListener('change', checkEventType, true);
     844
    636845            return () => {
    637                 document.removeEventListener('input',  markIfColorOrRange, true);
    638                 document.removeEventListener('change', markIfColorOrRange, true);
     846                document.removeEventListener('input',  checkEventType, true);
     847                document.removeEventListener('change', checkEventType, true);
    639848            };
    640849        }, [settingsId]);
     
    643852        we.useEffect(function () {
    644853            debug('[effect 4]');
     854
    645855            if (!widgetContent) return;
    646856            jQuery(widgetRef.current).html(widgetContent);
     857
    647858        }, [widgetContent]);
    648859
     
    670881
    671882        we.useEffect(function () {
    672             debug('[effect 7]');
     883           
     884            debug('[effect 7]');
     885           
    673886            maybeInitSettings();
    674         }, [settingsVisible, settingsContent]);
     887                       
     888        }, [settingsVisible, settingsContent, previewDeviceType, props.attributes.data]);
    675889
    676890        we.useEffect(function () {
     891           
    677892            debug('[effect 8]');
    678             maybeInitSettings();
    679         }, [previewDeviceType, props.attributes.data]);
     893           
     894            if (!settingsContent) return;
     895                runFirstPreviewOnce();
     896           
     897        }, [settingsContent]);
    680898
    681899        we.useEffect(function () {
    682             debug('[effect 9]');
    683             if (!settingsContent) return;
    684             runFirstPreviewOnce();
    685         }, [settingsContent]);
    686 
    687         we.useEffect(function () {
    688             debug('[effect 10]');
    689 
     900           
     901            debug('[effect 9]');
     902           
    690903            if (!firstPreviewReadyRef.current) {
    691904                if (widgetContent) {
     
    695908                }
    696909            }
     910           
     911            debug("check the settings");
     912           
    697913            if (suppressNextReloadRef.current) {
    698914
    699915                suppressNextReloadRef.current = false;
    700916
     917                debug("effect 9 - supress next reload");
     918               
    701919                updateSelectorsPreview();
     920                               
    702921                return;
    703922            }
     
    710929                }
    711930            })();
     931           
     932            trace("the settings");
     933            trace(settings);
     934           
    712935            const payloadStr = JSON.stringify(settings || {});
    713936            if (payloadStr === lastPreviewPayloadRef.current) {
    714                 debug('[effect 10] [5]');
     937               
     938                debug("Update Selectors Preview");
     939               
    715940                updateSelectorsPreview();
    716941                return;
     
    719944
    720945            loadWidgetContent(settings);
     946
    721947        }, [props.attributes.data]);
    722948
    723         // fix changes on lost focus
     949        // set focus and mouse events
    724950        we.useEffect(function () {
    725             debug('[effect 11]');
     951           
     952            debug('[effect 10]');
    726953
    727954            function onBlur(e){
     
    733960                }
    734961            }
    735             document.addEventListener('blur', onBlur, true);
    736             window.addEventListener('beforeunload', function(){ if (isSettingsReady()) flushSaveNow(); });
    737             return () => {
    738                 document.removeEventListener('blur', onBlur, true);
    739             };
    740         }, []);
    741 
    742         we.useEffect(function () {
    743             debug('[effect 12]');
     962
     963            function onBeforeUnload() {
     964                if (isSettingsReady()) flushSaveNow();
     965            }
     966
    744967            function onPointerUpOrTouchEnd() {
    745968                const t = (lastChangeTypeRef.current || '').toLowerCase();
     
    748971                }
    749972            }
     973
     974            document.addEventListener('blur', onBlur, true);
     975            window.addEventListener('beforeunload', onBeforeUnload);
    750976            window.addEventListener('pointerup', onPointerUpOrTouchEnd, { passive: true });
    751977            window.addEventListener('touchend',  onPointerUpOrTouchEnd, { passive: true });
     978
    752979            return () => {
    753980                window.removeEventListener('pointerup', onPointerUpOrTouchEnd);
    754981                window.removeEventListener('touchend',  onPointerUpOrTouchEnd);
     982                window.removeEventListener('beforeunload', onBeforeUnload);
     983                document.removeEventListener('blur', onBlur, true);
    755984            };
    756985        }, []);
    757 
    758         // init settings when panel visible + settings HTML ready + real DOM exists
    759         function maybeInitSettings(){
    760             if (!settingsVisible) return;
    761             if (!settingsContent) return;
    762 
    763             var $settingsElement = getSettingsElement();
    764             if (!$settingsElement || $settingsElement.length === 0) return;
    765 
    766             var elem = $settingsElement[0];
    767             if (!ucSettings.isInited() || initedSettingsElementRef.current !== elem) {
    768                 initSettings();
    769             }
    770         }
    771986
    772987        function runFirstPreviewOnce(maxTries = 30, delay = 50) {
     
    8141029
    8151030                lastPreviewPayloadRef.current = mergedStr;
     1031               
    8161032                loadWidgetContent(merged);
    8171033
  • unlimited-elements-for-elementor/trunk/provider/core/unlimited_elements/settings/general_settings_el.xml

    r3317018 r3429507  
    239239    </field>
    240240
     241    <field name="serpapi_heading"
     242      type="statictext"
     243      label="&lt;b&gt;Serp API&lt;/b&gt;">
     244    </field>
     245
     246    <field name="serpapi_key"
     247      type="text"
     248      label="Serp API Key"
     249      description="Used for google reviews. Get your API key here: &lt;a href='https://serpapi.com/' target='_blank'&gt;serpapi.com&lt;/a&gt;."
     250      default="">
     251    </field>
     252
    241253    <field name="wpml_heading"
    242254      type="statictext"
  • unlimited-elements-for-elementor/trunk/provider/functions_wordpress.class.php

    r3403331 r3429507  
    38973897    }
    38983898
    3899     /**
    3900      * get all admin users
    3901      */
    3902     public static function getAdminUsers(){
    3903        
    3904         $arrAdminUsers = get_users( array( 'role' => 'Administrator' ) );
    3905        
    3906         return($arrAdminUsers);
    3907     }
    39083899   
    39093900    /**
  • unlimited-elements-for-elementor/trunk/provider/provider_browser.class.php

    r3251080 r3429507  
    2626   
    2727}
     28
  • unlimited-elements-for-elementor/trunk/provider/provider_helper.class.php

    r3397365 r3429507  
    12611261           
    12621262            switch($field["type"]){
     1263                case UniteCreatorDialogParam::PARAM_HR:
     1264                   
     1265                    $settingsManager->addHr($paramName, $params);
     1266                   
     1267                break;
    12631268                case UniteCreatorDialogParam::PARAM_STATIC_TEXT:
    12641269                    $settingsManager->addStaticText($field["text"], $paramName, $params);
  • unlimited-elements-for-elementor/trunk/provider/provider_params_processor_multisource.class.php

    r3379552 r3429507  
    294294        $type = UniteFunctionsUC::getVal($params, "type");
    295295        $data = UniteCreatorAPIIntegrations::getInstance()->getDataForMultisource($type, $params);
    296 
     296       
     297       
    297298        return $data;
    298299    }
  • unlimited-elements-for-elementor/trunk/provider/provider_settings.class.php

    r3397365 r3429507  
    23002300        $params["is_multiple"] = true;
    23012301        $params["elementor_condition"] = $arrConditionIncludeAuthor;
    2302 
     2302       
    23032303        $this->addMultiSelect($name . "_excludeby_authors", $arrAuthors, __("Exclude By Author", "unlimited-elements-for-elementor"), "", $params);
    23042304
     
    36303630                    'responsive_id'   => 'advanced_margin',
    36313631                    'units'           => ['px','vh','%','em','rem'],
    3632                     'selector'        => '.ue-widget-root',
     3632                    'selector'        => '',
    36333633                    'selector_value'  => 'margin-top:{{top}}!important;margin-right:{{right}}!important;margin-bottom:{{bottom}}!important;margin-left:{{left}}!important;',
    36343634                ]
     
    36533653                    'responsive_id'   => 'advanced_padding',
    36543654                    'units'           => ['px','vh','%','em','rem'],
    3655                     'selector'        => '.ue-widget-root',
     3655                    'selector'        => '',
    36563656                    'selector_value' => 'padding-top:{{top}}!important;padding-right:{{right}}!important;padding-bottom:{{bottom}}!important;padding-left:{{left}}!important;',
    36573657                ]
     
    36983698                    'show_slider'     => false,
    36993699
    3700                     'selector'       => '.ue-widget-root',
     3700                    'selector'       => '',
    37013701                    'selector_value' => 'z-index:{{value}};',
    37023702
     
    37233723                        'tab'               => self::TAB_ADVANCED,
    37243724                        'items'             => [0, 1],
    3725                         'selector'          => '.ue-widget-root',
     3725                        'selector'          => '',
    37263726                    ]
    37273727                );
     
    37473747                [
    37483748                    'tab' => self::TAB_ADVANCED,
    3749                     'selector' => '.ue-widget-root',
     3749                    'selector' => '',
    37503750                    'selector_value' => 'data-bg-type:{{value}};',
    37513751                ]
     
    37613761                    'tab'                 => self::TAB_ADVANCED,
    37623762                    'elementor_condition' => ['advanced_background_type' => 'solid'],
    3763                     'selector'            => '.ue-widget-root',
     3763                    'selector'            => '',
    37643764                    'selector_value'      => 'background-color:{{value}};',
    37653765                ]
     
    37753775                    'tab'                 => self::TAB_ADVANCED,
    37763776                    'elementor_condition' => ['advanced_background_type' => 'solid'],
    3777                     'selector'            => '.ue-widget-root',
     3777                    'selector'            => '',
    37783778                    'selector_value'      => 'background-image:url({{value}}); background-size:cover; background-repeat:no-repeat;',
    37793779                ]
     
    37893789                    'tab'                 => self::TAB_ADVANCED,
    37903790                    'elementor_condition' => ['advanced_background_type' => 'gradient'],
    3791                     'selector'            => '.ue-widget-root',
     3791                    'selector'            => '',
    37923792                    'selector_value'      => 'background-image:linear-gradient({{advanced_background_gradient_angle}}deg, {{value}}, {{advanced_background_gradient_color2}});',
    37933793                ]
     
    38033803                    'tab'                 => self::TAB_ADVANCED,
    38043804                    'elementor_condition' => ['advanced_background_type' => 'gradient'],
    3805                     'selector'            => '.ue-widget-root',
     3805                    'selector'            => '',
    38063806                    'selector_value'      => 'background-image:linear-gradient({{advanced_background_gradient_angle}}deg, {{advanced_background_gradient_color1}}, {{value}});',
    38073807                ]
     
    38233823                    'units'               => '',
    38243824                    'show_slider'         => true,
    3825                     'selector'            => '.ue-widget-root',
     3825                    'selector'            => '',
    38263826                    'selector_value'      => 'background-image:linear-gradient({{value}}deg, {{advanced_background_gradient_color1}}, {{advanced_background_gradient_color2}});',
    38273827                ]
     
    38523852                    'tab'       => self::TAB_ADVANCED,
    38533853
    3854                         'selector'       => '.ue-widget-root',
     3854                        'selector'       => '',
    38553855                        'selector_value' => 'border-style:{{value}};',
    38563856
     
    38763876                    'elementor_condition' => $borderTypeCondition,
    38773877
    3878                         'selector'       => '.ue-widget-root',
     3878                        'selector'       => '',
    38793879                        'selector_value' =>
    38803880                            'border-top-width:{{top}};' .
     
    39023902                    'elementor_condition' => $borderTypeCondition,
    39033903
    3904                         'selector'       => '.ue-widget-root',
     3904                        'selector'       => '',
    39053905                        'selector_value' =>
    39063906                            'border-top-width:{{top}}{{unit}};' .
     
    39283928                    'elementor_condition' => $borderTypeCondition,
    39293929
    3930                         'selector'       => '.ue-widget-root',
     3930                        'selector'       => '',
    39313931                        'selector_value' =>
    39323932                            'border-top-width:{{top}}{{unit}};' .
     
    39483948                    'elementor_condition' => $borderTypeCondition,
    39493949
    3950                         'selector'       => '.ue-widget-root',
     3950                        'selector'       => '',
    39513951                        'selector_value' => 'border-color:{{value}};',
    39523952
  • unlimited-elements-for-elementor/trunk/provider/woocommerce_integrate.class.php

    r3379552 r3429507  
    251251            $arrProduct["woo_sale_price_to"] = null;
    252252        }else{
    253            
    254             $regularPriceFrom = $this->modifyPrice($regularPriceFrom, $objProduct);
    255             $regularPriceTo = $this->modifyPrice($regularPriceTo, $objProduct);
    256            
     253                       
    257254            $arrProduct["woo_regular_price_from"] = $regularPriceFrom;
    258255            $arrProduct["woo_regular_price_to"] = $regularPriceTo;
     
    726723        $price = UniteFunctionsUC::getVal($arrData, "price");
    727724       
     725        $priceNoTax = wc_get_price_excluding_tax($objInfo);
     726        $priceWithTax = wc_get_price_including_tax($objInfo);
     727       
    728728        $price = apply_filters("woocommerce_product_get_price", $price, $objInfo);
    729729        $salePrice = apply_filters("woocommerce_product_get_sale_price", $salePrice, $objInfo);
    730730        $regularPrice = apply_filters("woocommerce_product_get_regular_price", $regularPrice, $objInfo);
    731731       
    732        
    733732        $salePrice = $this->modifyPrice($salePrice, $objInfo);
    734733        $regularPrice = $this->modifyPrice($regularPrice, $objInfo);
    735734        $price = $this->modifyPrice($price, $objInfo);
    736735       
    737         $priceNoTax = wc_get_price_excluding_tax($objInfo);
    738         $priceWithTax = wc_get_price_including_tax($objInfo);
    739                
    740736        if(empty($regularPrice) && !empty($price))
    741737            $regularPrice = $price;
     
    744740        $arrData["price"] = $price;
    745741        $arrData["sale_price"] = $salePrice;
    746        
    747742       
    748743        $arrProduct = array();
     
    780775           
    781776            $arrProduct = $this->addPricesFromTo($arrProduct, $arrPrices, $objInfo);
    782                        
     777           
    783778            $arrProduct["woo_price"] = $arrProduct["woo_price_from"];
    784779            $arrProduct["woo_price_id"] = $arrProduct["woo_price_from_id"];
     
    816811        //put add to cart link
    817812        $arrProduct = $this->addAddToCartData($arrProduct, $productID, $productSku);
     813       
    818814       
    819815               
  • unlimited-elements-for-elementor/trunk/readme.txt

    r3421055 r3429507  
    940940
    941941== Changelog ==
     942
     943
     944version 2.0.2 2025-12-30 =
     945
     946Plugin Changes:
     947
     948* Feature: add google reviews from serp api feature
     949* Fix - fixed double tax pricing in woocommerce variation
     950* Fix - fixed the entrance animation together with load more issue
     951* Fix - some blocks related bug fixes
     952* Fix - fixed default items not loading js issues
     953* Fix - fixed some small security issue
     954
     955Widgets Changes:
     956
     957* Feature: Unlimited Grid (Pro) - Added Title HTML Tag option for better SEO and accessibility.
     958* Feature: Content Carousel (Free) - Enhanced custom SVG icon support for navigation arrows, and added title and description text shadow options.
     959* Feature: Content Slider (Free) - Added title HTML tag option, improved links by adding link attributes, and introduced Slide Border, Overlay Hover, and Overlay Hover Transition Duration options.
     960* Feature: Video on Hover (Free) - Added a &quot;Schema&quot; option to enable schema markup support for better SEO and AI understand your content for increased visibility in AI powered search features.
     961* Feature: Text Field (Free) - Introduced a dynamic URL Autopopulate feature, allowing fields to automatically retrieve and fill values from custom query string parameters upon page load
     962* Feature: Off Canvas (Pro) - Added Background Color Hover and Text Color Hover options, allowing finer visual control over hover states and enabling consistent styling of the Trigger Button element.
     963* Feature: Side Menu (Free) - Added support for the Conditions widget, enabling seamless control over the Side Menu by allowing it to be opened, closed, or toggled dynamically based on defined conditions
     964* Feature: Conditions (Free) - Added three new actions — UE Open Side Menu, UE Close Side Menu, and UE Toggle Side Menu — allowing full programmatic control over the Side Menu widget behavior
     965* Feature: Snow Background (Free) - Added Speed Mobile option, allowing precise control over animation and interaction speed specifically for mobile devices, ensuring smoother performance, better usability on smaller screens
     966* Feature: Swipe Carousel (Pro) - Added Title Tag option, allowing users to define the HTML tag for the title element to better match the page structure, improve semantic markup, and enhance SEO and accessibility control.
     967* Feature: Grid Gallery (Pro) - Added Enable Link On Main Image option, allowing the main image within each item to function as a clickable link.
     968* Feature: Post Grid (Free) - Made the Title Spacing option fully responsive, allowing different spacing values to be applied across desktop, tablet, and mobile for more precise control of layout and typography.
     969* Feature: Expanding Content Cards (Free) - Added Sub Title option, enabling users to include an additional descriptive text line beneath the main title.
     970* Feature: Vertical Curved Timeline (Free) - Added &quot;Content Vertical Position&quot; option when the image option is enabled, also introduced &quot;Alternate Image Alignment&quot; option for improved design and customization.
     971* Feature: Icon Accordion (Free) - Added multi-source support along with pagination and filtering features, and improved the item color options for easier styling.
     972* Feature: Dynamic Post Popup (Pro) - Added Arrows Type option, introducing support for choosing between icon-based arrows and text-based arrows.
     973* Feature: Portfolio Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked.
     974* Feature: Overlay Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     975* Feature: Material Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked.
     976* Feature: Icon Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     977* Feature: Unlimited Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked.
     978* Feature: Logo Carousel (Free) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     979* Feature: Woo Product Carousel (Free) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked.
     980* Feature: Post Carousel (Free) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     981* Feature: Repeater Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     982* Feature: Flip Box Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     983* Feature: Loop Carousel (Pro) - Added the Slides To Change option, which determines the exact number of carousel items moved when navigation arrows are clicked
     984* Feature: Notification (Free) - The widget&#039;s accessibility was improved by replacing the close div with a semantic &lt;button&gt; element, adding the essential aria-label=&quot;Close Notification&quot; for screen reader clarity, applying role=&quot;status&quot; to the main container for conveying passive informative content.
     985* Feature: Contact Form 7 (Free) - Improved accessibility of the widget by enabling proper keyboard navigation within form elements.
     986* Feature: Fullscreen Menu (Free) - Added Expand Collapse Icon Spacing option, allowing users to precisely control the distance between the expand/collapse icon and the text.
     987* Feature: Gradient Underline Text Effect (Free) - Made the Text Align option responsive, allowing different alignment settings for desktop, tablet, and mobile.
     988* Feature: Post Accordion (Free) - Added Icon Spacing option — introduced a new control that allows adjusting the distance between the icon and its adjacent elements.
     989* Feature: Team Member Carousel (Free) - Added Icon One, Icon Two, Icon Three, Icon Four and Link One, Link Two, Link Three, Link Four options to the Source options
     990* Feature: Unlimited Google Maps (Free) - Added Scroll To Active Navigation Item option, ensuring that navigation automatically scrolls to keep the active item visible.
     991* Feature: 360 Panorama Virtual Tour (Pro) - Enhanced the widget&#039;s accessibility by applying ARIA attributes (role, aria-label) and tabindex=&quot;0&quot; to interactive controls, allowing keyboard-only users to activate them by simulating a click using the Enter or Space key.
     992* Fix: Repeater Table (Pro) - Accessibility for the widget was improved by implementing the scope=&quot;col&quot; attribute on all header cells to explicitly link data to headings
     993* Fix: Restaurant Menu (Free) - Accessibility for the widget was improved by adding role=&quot;list&quot; and role=&quot;listitem&quot; for better navigation structure, converting the &quot;See More&quot; toggle into a keyboard-accessible button with aria-expanded states.
     994* Fix: Loop Grid (Pro) - Fixed an issue where the “Empty Message Type: Template” was displayed even when the Loop Widget had successfully rendered items, causing the empty state template to appear incorrectly alongside actual content
     995* Fix: Border Hero (Free) - The button field was incorrectly configured as a text field and has now been changed to a proper link field. A security vulnerability was also fixed to improve overall safety and stability.
     996* Fix: Content Grid (Free) - Removed empty links to prevent rendering unnecessary anchor elements and to avoid potential accessibility and SEO issues when link fields are left blank
     997* Fix: Comparison List (Pro) - Fixed an issue where column widths were not working correctly on mobile devices, and resolved RTL layout issues.
     998* Fix: Horizontal Timeline (Free) - Removed empty links to prevent rendering unnecessary anchor elements and to avoid potential accessibility and SEO issues when link fields are left blank.
     999* Fix: Price Range Filter (Pro) - Fixed an issue where slider thumbnail elements were displayed incorrectly on RTL (right-to-left) websites, ensuring proper alignment, order, and interaction consistency across all supported directions
     1000* Fix: Random Content (Free) - Accessibility for the Random Content widget was improved by converting the shuffle trigger into a semantic &lt;button&gt;, marking the shuffle icon as aria-hidden=&quot;true&quot; to avoid redundant noise, and applying aria-live=&quot;polite&quot; to the content container
     1001* Fix: Stacking Cards (Free) - Fixed an issue where the Alternate Page Position option was not functioning correctly on the live site and was only applied inside the Elementor editor
     1002* Fix: Protected Content (Free) - Accessibility for the Protected Content widget was improved by correcting the form structure to properly link the &lt;label&gt; (title) to the password &lt;input&gt; using the &quot;for&quot; and &quot;id&quot; attributes, adding aria-required=&quot;true&quot; to the input
     1003* Fix: Cookie Consent (Free) - Accessibility for the Cookie Consent widget was improved by switching interactive &lt;div&gt; elements to semantic &lt;button&gt; tags, and ensuring the main container dynamically uses role=&quot;dialog&quot; and aria-modal=&quot;true&quot; only when the banner is visible, thereby guiding keyboard and screen reader focus correctly.
     1004* Fix: Age Verification (Free) - The Age Verification widget&#039;s accessibility was improved by adding role=&quot;dialog&quot;, aria-modal=&quot;true&quot;, and descriptive aria-label attributes to all input fields and buttons for better screen reader and keyboard navigation
     1005* Fix: Content Tabs (Free) - Fixed an issue where theme-defined padding styles for ul elements were being unintentionally overridden by the widget’s CSS, ensuring better compatibility with various themes and preserving the original list spacing and layout as defined by the active theme
     1006* Fix: Image Tooltip (Free) - Added aria-describedby attribute to the main widget wrapper to improve accessibility, and included additional HTML attributes—such as alt for the image—to ensure better semantic structure, screen-reader support, and overall accessibility compliance
     1007* Fix: Event Box (Free) - Added ARIA attributes to interactive elements and link labels for improved screen reader compatibility.
     1008* Fix: Calendar (Pro) - Increased the CSS priority of the Event Title element, ensuring its styling reliably overrides conflicting theme rules and displays consistently across different layouts and environments.
     1009* Fix: Masonry &amp; Justified Gallery (Free) - Fixed an issue where the Tile Text Panel styling options were not appearing in the widget settings panel, ensuring all relevant controls are now properly displayed and accessible for customization.
     1010* Fix: Submit Button (Free) - Fixed issue where attempting to proceed to the next step of Multi Source widget from the first page without filling mandatory fields caused unwanted spacing to be repeatedly added to the form
     1011* Fix: Vertical Curved Timeline (Free) - Fixed an issue where &quot;Button Spacing&quot; option was not working.
     1012* Fix: Vertical Curved Timeline (Free) - Fixed issue where, when the image element was disabled and the content inside an item had a width below 100%, items with an even item count were not aligning correctly to the side, ensuring proper layout consistency across all configurations.
     1013* Fix: Justified Image Carousel (Pro) - Fixed an issue on touch devices where opening the lightbox required two taps instead of one, ensuring the lightbox now opens correctly on a single tap for a smoother and more responsive user experience.
     1014* Fix: QR Code (Pro) - Accessibility of the QR Code widget was improved by applying role=&quot;img&quot; to the SVG container to define it as a graphic and using aria-label to provide the visible title as the accessible name, ensuring screen readers can announce the image&#039;s content.
     1015* Fix: Animated Mouse Scroll Icon (Free) - The accessibility of the widget was improved by adding aria-label=&quot;Scroll Down&quot; and role=&quot;button&quot; to the link wrapper and using aria-hidden=&quot;true&quot; on the decorative animation elements
     1016* Fix: Vertical Curved Timeline (Free) - Fixed issue when button wasn&#039;t clickable for all items except last one.
     1017* Fix: Repeater Tabs (Free) - Fixed issue when Repeater Tabs couldn&#039;t display all content with JSON / CSV Repeater Source.
     1018* Fix: Social Share Buttons (Free) - Fixed an issue where the Telegram share option was redirecting to Xing instead of Telegram.
     1019* Release: Person Schema (Pro) - Person Schema adds structured data that defines an individual for search engines. Improve SEO by clearly connecting a person to content, roles, and social profiles.
    9421020
    9431021
     
    10571135* Fix: Image Zoom Magnifier (Pro) - Added aria-describedby attribute to Image Zoom Magnifier widget for improved accessibility.
    10581136* Fix: Icon Accordion (Free) - Fixed an issue where the accordion was not opening correctly after the latest update, ensuring proper functionality and access.
    1059 * Fix: Content Slider (Free) - Added a trigger for the resize event after carousel load to prevent layout issues and ensure proper display in all cases.
    10601137* Fix: Comparison List (Pro) - Fixed an issue with column borders not displaying correctly in RTL mode.
    10611138* Fix: Icon Tabs (Free) - Added role attributes and aria-selected attributes to the Icon Tabs widget to improve accessibility.
     
    10711148
    10721149
    1073 version 1.5.150 - 2025-09-10 =
    1074 
    1075 Plugin Changes:
    1076 
    1077 * Update: updated freemius sdk to newest version
    1078 * Fix: fixed bug in background widgets second condition
    1079 * Fix: fixed some double js init with elementor popups
    1080 * Fix: fixed avoid duplicates in post related widgets with filters
    1081 * Fix: fixed svg output instead of url in some cases
    1082 * Fix: fixed some bug with wpml inside loop and elementor grid
    1083 * Fix: prepared the plugin for elementor class optimization
    1084 
    1085 
    1086 Widgets Changes:
    1087 
    1088 * Feature: Content Toggle (Free) - Added an Open Tab Based on URL option, allowing specific tabs to be activated automatically when accessing a page via a direct link.
    1089 * Feature: Age Verification (Free) - Added a Date Inputs Order option, allowing customization of the display order for date input fields to better match regional formats and preferences.
    1090 * Feature: Content Toggle (Free) - Added an Enable Cookie option that allows the selected Content Toggle Item to be remembered, ensuring user choice is preserved across sessions.
    1091 * Feature: Flip Box Carousel (Pro) - Added a Front Image Source option within the Source settings, allowing more flexibility in selecting and managing front image content.
    1092 * Feature: Flip Box (Free) - Added a Front Image Border Radius option, allowing customization of corner rounding for the front image to enhance design flexibility.
    1093 * Feature: Before After (Free) - Before/After slider is now fully keyboard accessible: users can Tab to the handle and move it with arrow keys, while aria-valuenow attribute updates dynamically for screen readers.
    1094 * Feature: Off Canvas Filters (Pro) - Added the possibility to manually add filters into the Off Canvas Filters popup using Items by simply specifying the CSS ID of the desired filter.
    1095 * Feature: Mega Menu (Pro) - Allowed the use of HTML in the Item Title options, enabling richer formatting and enhanced customization of item titles.
    1096 * Feature: Hotspots (Free) - Added an Activate On Page Load option, allowing a specific item to be activated automatically when the page loads for improved user experience and control.
    1097 * Feature: Audio Player (Pro) - Added a Controls Wrap Mode option, allowing better management and layout of control elements within the widget for improved flexibility and appearance.
    1098 * Feature: Breadcrumbs (Free) - Allowed the use of HTML tags in Breadcrumbs text elements, enabling richer formatting and improved customization options.
    1099 * Feature: Hexagon Grid (Pro) - Added a Show Second Background Image option, allowing a secondary image to appear on hover for enhanced visual interactivity and design flexibility.
    1100 * Change: Multi Step Form (Free) - Changed the target Elementor container from `elementor-widget-container` to `.elementor-widget` to ensure the widget functions correctly following the Elementor 3.32 version release.
    1101 * Change: Submit Button (Free) - Changed the target Elementor container from elementor-widget-container to .elementor-widget to ensure the widget functions correctly following the Elementor 3.32 version release.
    1102 * Change: Content Toggle (Free) - Renamed Cookie options into Open Tab Rules
    1103 * Change: Audio Player (Pro) - Changed the source type of the audio library for the widget from CDN to self-hosted, improving performance, reliability, and control over asset loading.
    1104 * Fix: Age Verification (Free) - Fixed an issue where the Load After Delay option was not functioning correctly, ensuring proper delayed loading behavior.
    1105 * Fix: Off Canvas Filters (Pro) - Fixed an issue where the Off Canvas Filter widget was not appending the Accordion Filter widget under its container, ensuring proper structure and functionality.
    1106 * Fix: Flip Box (Free) - Improved accessibility across the widget, enhancing usability for all users, including those relying on assistive technologies.
    1107 * Fix: Masonry &amp; Justified Gallery (Pro) - Fixed an issue related to video playback in the Lightbox when the pagination option was enabled, ensuring smooth and uninterrupted video functionality.
    1108 * Fix: Icon Box Hover Effect (Free) - Added protection to prevent SVG icons from disappearing on hover, ensuring consistent visibility and proper styling.
    1109 * Fix: Background Switcher (Pro) - Fixed an issue where the Item Height option was not working in Vertical Mode on mobile devices, ensuring proper display and responsiveness.
    1110 
    1111 
    1112 version 1.5.149 - 2025-08-21 =
    1113 
    1114 Plugin Changes:
    1115 
    1116 * Feature - acf fields now get taxonomies array
    1117 * Feature - changed users list to all users
    1118 * Feature - added object_id to multisource item fields
    1119 * Fix - added alphabet filter to active filtered items
    1120 * Fix - fixed search by sku in woo ajax search
    1121 * Fix - fixed email likert form field saving and sending
    1122 * Fix - fixed form file field upload
    1123 * Fix - fixed post list stuck when insert on editor
    1124 * Fix - done some protection for the galleries against mallicious code
    1125 
    1126 Widgets Changes:
    1127 
    1128 * Release: Content Toggle (Free) - The Content Toggle Widget lets you switch between two content views with a smooth toggle.
    1129             Ideal for comparisons, light/dark modes, or showing alternative info in the same space.
    1130 * Release: How To (Free) - The How To Widget lets you create step-by-step instructional content with clear titles, descriptions, images, and estimated times. It&#039;s perfect for tutorials, guides, or walkthroughs.
    1131 * Release: Animated Mesh Gradient Background (Pro) - Add a dynamic, fluid feel to your sections with the Animated Mesh Gradient Background widget.
    1132             Smooth, colorful gradients flow and shift to create an eye-catching, modern backdrop.
    1133 * Release: Bracket Maker (Pro) - Create interactive tournament brackets with the Bracket Maker widget. Perfect for sports, games, or competitions, customize teams, rounds, and styles easily.
    1134 
    1135 * Feature: List (Free) - Improved widget behavior: if Enable Link option is disabled, it is now possible to add links inside the Item Text option.
    1136 * Feature: Mega Menu (Pro) - Allowed the use of HTML tags within the Text Graphic element, enabling richer formatting and greater customization of text content.
    1137 * Feature: Flag Icons (Free) - Extended the &quot;Link&quot; option to work with all layout types, not just the dropdown layout, providing greater flexibility and consistency across different designs.
    1138 * Feature: Portfolio Carousel (Pro) - Added a new Image Grow On Hover option, allowing images to smoothly scale up when hovered over.
    1139 * Feature: Justified Image Carousel (Pro) - Added new elements Subtitle and Button to expand available content options in the widget.
    1140 * Feature: Repeater Carousel (Pro) - Added support for WYSIWYG type of ACF field, enabling rich text content to be displayed properly within the widget.
    1141 * Feature: Repeater Grid (Pro) - Added support for WYSIWYG type of ACF field, enabling rich text content to be displayed properly within the widget.
    1142 * Feature: Vertical Curved Timeline (Free) - Added Layout Type option allowing elements to be positioned in a column or a row.
    1143 * Feature: Logo Marquee (Free) - Added Item Image Object Fit and Item Image Object Position options, allowing precise control over how images are scaled and positioned within items.
    1144 * Feature: Payment Method Icons (Free) - Added two new cards as payment method icons: Union Tank Eckstein and DKV, providing broader payment option representation
    1145 * Feature: Compact Gallery (Free) - Added Lightbox option, enabling users to display content in a pop-up overlay for an improved viewing experience
    1146 * Feature: Grid Gallery (Pro) - Added Lightbox option, enabling users to display content in a pop-up overlay for an improved viewing experience
    1147 * Feature: Slider Gallery (Free) - Added Lightbox option, enabling users to display content in a pop-up overlay for an improved viewing experience.
    1148 * Feature: Thumbnail Gallery (Free) - Added Lightbox option, enabling users to display content in a pop-up overlay for an improved viewing experience.
    1149 * Feature: Dropdown Button (Pro) - Added Dropdown Horizontal Align option, allowing users to control the horizontal alignment of dropdown menus.
    1150 * Feature: Post Tabs (Free) - Added Button Typography option allowing customization of font settings (e.g., size, weight, style) for the button element
    1151 * Feature: Post Grid (Free) - Added Categories Position option, allowing users to set the desired position of category labels within the widget
    1152 * Feature: Repeater Accordion (Pro) - Added support for WYSIWYG field type of the ACF plugin in Repeater fields, enabling proper handling of rich text content.
    1153 * Feature: Content Grid (Free) - Added Title Link Type option, allowing the title to open the lightbox on click for improved interactivity.
    1154 * Feature: Repeater Table (Pro) - Added support for WYSIWYG type of ACF field, enabling rich text content to be displayed properly within the widget.
    1155 * Feature: Horizontal Timeline (Pro) - Added Button Text option into Multisource options, allowing users to customize the button label for improved clarity and flexibility.
    1156 * Change: Testimonial Carousel (Free) - Increased the Nav Arrow Spacing option range by extending its minimum and maximum values to -2000 and 2000, providing greater flexibility for customization.
    1157 * Change: Justified Image Carousel (Pro) - Changed the name of the Fix Broken Layout option to Load After Images for clearer understanding.
    1158 * Change: Content Grid (Free) - Changed the option name &quot;Dynamic Popup Select&quot; to &quot;Button Link Type&quot; in order to make its purpose clearer and more intuitive for users.
    1159 * Fix: Mega Menu (Pro) - Fixed an issue where clicking on the Graphic Element would not follow the assigned link when the Clickable Link Item option was enabled, ensuring proper link functionality.
    1160 * Fix: Justified Image Carousel (Pro) - Removed hardcoded data-elementor-lightbox-title and title attributes from widget links, allowing Elementor Lightbox to respect global “Show Title” settings.
    1161 * Fix: Overlay Carousel (Pro) - Added protection to prevent padding from being applied by client website theme CSS, ensuring consistent layout and styling of the widget.
    1162 * Fix: Flag Icons (Free) - Fixed an issue with the Link option where additional link attributes were not being applied, ensuring proper functionality and attribute handling.
    1163 * Fix: Flag Icons (Free) - Fixed the Remote Connection behavior when the layout type is set to Carousel, ensuring proper synchronization and smooth functionality.
    1164 * Fix: Justified Image Carousel (Pro) - Fixed an issue where images in the Lightbox were not displayed at full size, ensuring correct scaling and optimal visual presentation.
    1165 * Fix: Flip Box (Free) - Fixed an issue where the Flip Box element was not flipping back to the front side after the mouse leave event, restoring expected interactive behavior.
    1166 * Fix: Repeater Table (Pro) - Fixed an issue where **Columns** added in the Editor could result in an empty title, ensuring that all column titles display correctly and maintain proper content structure.
    1167 * Fix: 360 Product Viewer (Pro) - Added a tiny delay before initialization to ensure proper functionality when used inside Elementor popups, improving stability and preventing potential loading issues
    1168 * Fix: Expanding Content Cards (Pro) - Fixed an issue where Remote and Sync functionalities were not functioning properly in responsive mode, ensuring smooth operation and consistent behavior across all device sizes.
    1169 * Fix: Justified Image Carousel (Pro) - Added Content Vertical Offset option, available when Content Position is set to Bottom of the Image and Content Placement is set to Bottom.
    1170 * Fix: Layers (Pro) - Fixed an issue in the WordPress Gutenberg editor where images were displaying with an abnormal height property at certain breakpoints.
    1171 * Fix: Scroll Sequence (Pro) - Changed widget default values to display the default example of the Scroll Sequence widget: File Name Prefix Padding: 4, Image Extension: webp, Number Of Images: 59.
    1172 * Fix: Timeline Bullets (Free) - Added missing alt attributes for img elements to improve accessibility and SEO
    1173 * Fix: Video on Hover (Free) - Replaced touchstart with pointerup to allow scrolling on touch devices while still supporting tap to play video.
    1174 * Fix: Thumbnail Gallery (Free) - Fixed bug where the Text Panel (Title and Description) was not displaying.
    1175 * Fix: Masonry &amp; Justified Gallery (Pro) - Allowed using SVG icons for custom icons that include CSS IDs and CSS classes, enabling more flexible styling and customization.
    1176 * Fix: Woo AJAX Search (Free) - Fixed issue where the Price continued to display even when the Show Price in Results option was disabled.
    1177 * Fix: Portfolio Carousel (Pro) - Fixed issue where link element was still rendered even when the Link option was empty.
    1178 * Fix: Smooth Scroll (Pro) - Fixed issue where Smooth Scroll widget was preventing anchor link click from triggering scroll behavior.
    1179 * Fix: Content Carousel (Free) - Fixed issue where Carousel widget was not initializing properly after page load.
    1180 * Fix: Carousel Gallery (Pro) - Fixed issue where the Pause icon was incorrectly displayed at the same time as the Play icon, causing visual overlap and confusion in the video controls.
    1181 * Fix: Logo Marquee (Free) - Fixed issue where the widget did not work on Safari mobile devices, ensuring full compatibility.
    1182 * Fix: Masonry &amp; Justified Gallery (Pro) - Fixed issue where HTML5 videos were not playing correctly when using the Native Pagination functionality
    1183 
    1184 
    1185 version 1.5.148 - 2025-07-21 =
    1186 
    1187 * Fix - elementor rtl issues fix
    1188 
    1189 
    1190 version 1.5.147 - 2025-07-17 =
    1191 
    1192 Plugin Changes:
    1193 
    1194 * Fix - added entity decode for subjects in the forms emails
    1195 * Fix - fixed bug with remove orderby in post selection
    1196 * Fix - some protection of elementor widgets register in case of cache
    1197 * Fix - ajax search with titles only issues
    1198 * Fix - fixed background widgets js code issues
    1199 
    1200 Widgets Changes:
    1201 
    1202 * Feature: Animated Floating Elements Background (Pro) - Added Starting Point option, allowing users to define the initial position or item displayed when the widget loads
    1203 * Feature: Job Listing (Pro) - Added Remote Connect option, also added Fallback Image option to display a default image when the item image is missing.
    1204 * Feature: Post Carousel (Free) - Added Show Full Post Content option, allowing users to display the complete content of a post instead of just an excerpt.
    1205 * Feature: Job Listing (Pro) - Added new styling options for Job Info Items, including Border Radius, Padding, Background Color, Background Color on Hover, Border, and Border on Hover for enhanced visual customization.
    1206 * Feature: Content Box Overlay (Free) - Enabled Image size/resolution selection. Introduced Transition Duration, Title HTML Tag, Icon, and Show Title condition and debug option: &quot;Preview Hidden Content&quot; to assist during styling. Also added Icon, and badge option.
    1207 * Feature: Animated Border Icon Box (Free) - Added Title Condition and Title HTML Tag option. Enabled SVG Icon Upload and introduced &quot;Enable Full Box Link&quot; option. Also introduced a new Layout tab and reorganized related options for clarity. Added Badge Option and moved Title Border settings to the new Separator tab, along with new Border Width and Separator Gap controls.
    1208 * Change: Post Grid (Free) - Added 9 new options in the &quot;Image Object Position&quot; setting to allow precise image alignment: top left, top center, top right, center left, center center, center right, bottom left, bottom center, and bottom right.
    1209 * Change: Content Box Overlay (Free) - Added new styling options, Height, Image Fit, Image Position, Image CSS Filter, Title Spacing, and Separator line styles. Improved overall widget functionality and optimized CSS loading based on conditions, and removed unused CSS for better optimization.
    1210 * Change: Animated Border Icon Box (Free) - Added a dedicated Icon tab in styles, including controls for Icon Size, Color, Shadow, and Gap. Also added a separate Icon Gap setting. Removed  old typography option, and added styling options for the Title. Restructured HTML and CSS, removing unused elements for improved performance.
    1211 * Change: Tabs Filter (Pro) - Added CSS rule to remove text decoration from the tab item link element, enhancing the overall visual clarity.
    1212 * Fix: Repeater Table (Pro) - Fixed issue where CSV and JSON sources for the table were not working with the widget, ensuring proper data loading and display.
    1213 * Fix: Alphabet Filter (Pro) - Fixed issue where enabling the Post Count option triggered an alert displaying an error, ensuring smooth functionality.
    1214 * Fix: Morph Background Slider (Pro) - Fixed Issue when Transition Direction option were not working as expected.
    1215 * Fix: Liquid Full Screen Menu (Pro) - Fixed issue where the Menu was causing horizontal scrolling when resizing the window, ensuring proper responsive behavior.
    1216 * Fix: Testimonial Carousel (Free) - Added aditional check of Masonry Layout Items position and corection in case of misalignment.
    1217 * Fix: Post Grid (Free) - Fixed an issue where, when the List View option was enabled and the layout was switched to list view, post items were not full width as expected. Instead, they were displaying at inconsistent. This update ensures that all post items properly stretch to full width in list view mode for a consistent and cleaner layout.
    1218 * Fix: Underline Link Hover Effect (Pro) - Fixed issue where the transition duration was not applied to the text element, ensuring smooth and consistent animations
    1219 * Other: Select Dropdown Filter (Free) - Added additional instruction for the Select First option, providing clearer guidance on its usage and behavior.
    1220 * Other: Tabs Filter (Pro) - Added additional instruction for the Select First option, providing clearer guidance on its usage and behavior.
    1221 * Release: Flag Icons (Free) - New Widget: Flag Icons. Easily add country flag icons to your Elementor designs perfect for highlighting international destinations, events, or global content!
    1222 
    12231150
    12241151
  • unlimited-elements-for-elementor/trunk/release_log.txt

    r3403331 r3429507  
     1
     2
     3
     4version 2.0.2:
     5
     6* Feature: add google reviews from serp api feature
     7* Fix - fixed double tax pricing in woocommerce variation
     8* Fix - fixed the entrance animation together with load more issue
     9* Fix - some blocks related bug fixes
     10* Fix - fixed default items not loading js issues
     11* Fix - fixed some small security issue
    112
    213
  • unlimited-elements-for-elementor/trunk/unlimited_elements.php

    r3403331 r3429507  
    55* Description: Elementor all-in-one addons pack with the best widgets for Elementor, offering 100+ free widgets, templates, and tools to create stunning websites!
    66* Author: Unlimited Elements
    7 * Version: 2.0.1
     7* Version: 2.0.2
    88* Author URI: http://unlimited-elements.com
    99* Text Domain: unlimited-elements-for-elementor
     
    1111* Requires PHP: 7.4
    1212*
    13 * Tested up to: 6.8.3
    14 * Elementor tested up to: 3.33.2
    15 * Elementor Pro tested up to: 3.33.1
     13* Tested up to: 6.9
     14* Elementor tested up to: 3.34.0
     15* Elementor Pro tested up to: 3.34.0
    1616*
    1717* License: GPLv2 or later
  • unlimited-elements-for-elementor/trunk/views/addondefaults.php

    r3251080 r3429507  
    9595
    9696        $arrOptions = $this->getOptions($addon);
    97 
     97       
    9898        //init addon config
    9999        $addonConfig = new UniteCreatorAddonConfig();
    100100        $addonConfig->setStartAddon($addon);
    101 
     101       
    102102        $this->isDataExists = $addon->isDefaultDataExists();
    103103
Note: See TracChangeset for help on using the changeset viewer.