PageSourceSearch

https://www.basilhadad.com/modules/WidgetsManager/js/widgetLoader.js?1

js basilhadad.com collected 2026-10-08 20:19:39 UTC 7,416 bytes, 186 lines download raw bytes

1// Widget loader plugin to handle all widget loading via ajax needs
2var widgetLoader = (function($){
3
4    // Possible events array to keep it consistant.
5    var events = {
6        rendered : 'widgetRendered',
7        fetching: 'widgetFetching',
8        preQueue: 'widgetQueued',
9        preRender: 'widgetPreRender'
10    };
11    
12    // Widget object to store all widget information.
13    var widgets = {};
14
15    // Loader styles
16    var link = document.createElement('link');
17    link.setAttribute('rel', 'stylesheet');
18    link.setAttribute('type', 'text/css');
19    link.setAttribute('href', '/modules/WidgetsManager/css/widgetLoader.css?1');
20    document.getElementsByTagName('head')[0].appendChild(link);
21
22    // Check if we have intersection for this browser and set this value for our variable
23    var intersectionAllowed = (function(){
24        return ('IntersectionObserver' in window);
25    })();
26
27    var isBot = (function(){
28        return (/bot|googlebot|crawler|spider|robot|crawling/i).test(navigator.userAgent);
29    })(); 
30    
31    // On Scroll Event Render all unrendered widgets and remove the scrolled listener
32    var userScrolled = false;
33    var scrolled = window.addEventListener('scroll', function(e){
34        userScrolled = true;
35        window.removeEventListener('scroll',scrolled)
36        Object.keys(widgets).map(function(widget){
37            if(!widgets[widget].rendered && !widgets[widget].speed != 'observer'){
38                fetchWidget(widgets[widget].wid,widgets[widget].module);
39            }
40        });
41    });
42
43    // Widget intersection observer
44    var widgetObserver = '';
45    if(intersectionAllowed){ 
46        widgetObserver = new IntersectionObserver(function(entries, observer){
47            entries.forEach(function(entry){
48                if(entry.isIntersecting){
49                    var widget = widgetModuleID(entry.target.id); // get widget from id
50                    widgetObserver.unobserve(entry.target); // Remove Observer since we have rendered.
51                    fetchWidget(widget.wid,widget.moduleName); // Fetch widget 
52                }
53            });
54        },{rootMargin: '0px',threshold:0.01});
55    };
56
57    // Render Function used to add widget to render Queue or immidiatly render.
58    function renderWidget(_wid,_module,speed){
59        widgets[_wid] = {
60            wid: _wid,
61            module: _module,
62            speed: speed == 'delayed' ? 'delayed' : 'immidiate',
63            rendered: false
64        };
65        triggerEvent(events.preQueue, widgets[_wid]); // Before adding to render quque/rendering pass widget to event in case themers want to alter loading speed
66        // If widget should load immidiatly or intersection is not available for browser load immidiatly
67        if(widgets[_wid].speed === 'immidiate' || !intersectionAllowed || (userScrolled && widgets[_wid].speed !== 'observer')){
68            fetchWidget(_wid,_module);
69        } else {
70            addToObserver(_wid,_module);
71        }
72    };
73
74    // Function to fetch html contents of widget via ajax
75    function fetchWidget(_wid,_module){
76        if(widgets[_wid].rendering){
77            return;
78        }
79        widgets[_wid].rendering = true;
80        triggerEvent(events.fetching, widgets[_wid]);
81        $.ajax({
82            url: '/WidgetsManager/getWidgetContents',
83            dataType: 'html',
84            data: {wid:_wid},
85            type: 'post',
86            success: function(data){
87                // Set response into widget.html and pass this for prerender and use the html for replacing on screen
88                widgets[_wid].html = data;
89                triggerEvent(events.preRender, widgets[_wid]);
90                triggerEvent(events.preRender+'_'+widgets[_wid].wid);// Single Widget PreRender Event
91                triggerEvent(events.preRender+'_'+widgets[_wid].module);// Single Widget module PreRender Event
92                $('#' + _module + '-0-' + _wid + ' .widget-loading').replaceWith(widgets[_wid].html);
93                widgets[_wid].rendered = true;
94                // Clean up variable after render free up some memory
95                widgets[_wid].html = '';
96                triggerEvent(events.rendered, widgets[_wid]);
97                triggerEvent(events.rendered+'_'+widgets[_wid].wid);// Single Widget Render Event
98                triggerEvent(events.rendered+'_'+widgets[_wid].module);// Single Widget module Render Event
99            }
100        })
101    };
102
103    // Helper add to observer function
104    function addToObserver(wid,module){
105        widgetObserver.observe($('#'+module+'-0-'+wid)[0]);
106    };
107
108    // Helper function returns wid and module object
109    function widgetModuleID(target){
110        return {
111            wid: target.match(/[1-9][0-9]*/g)[0],
112            moduleName: target.match(/[a-zA-Z\_]*/g)[0]
113        }
114    };
115
116    // Helper event dispatcher for all potential events and its data.
117    function triggerEvent(event, evData){
118        var event = new CustomEvent(event);
119        event.widget = evData;
120        document.dispatchEvent(event);
121    };
122
123    //if is bot run rendered event for widgets to trigger js
124    if(isBot){
125        window.addEventListener('DOMContentLoaded', function(){
126            $('.block.widget').each(function(){
127                var widget = widgetModuleID($(this).attr('id'));
128                triggerEvent(events.rendered,{wid:widget.wid,module:widget.moduleName})
129            })
130        });
131    }
132
133    // On specific widget Render Helper Method
134    function onSingleWidget(el,callback,event){
135        if(el.length>1){
136            console.log('More then 1 element passsed');
137            return;
138        }
139        if(!callback){
140            console.log("Callback is required");
141            return;
142        }
143        if(typeof(callback) != 'function'){
144            console.log('Callback is not a function. Passed '+typeof(callback)+' instead.');
145            return;
146        }
147        try{
148            var wid = widgetModuleID(el.attr('id')).wid;
149        } catch(e){
150            console.log('Passed element is not a widget.');
151            return;
152        }
153        if(!widgets[wid]){
154            console.log('Passed Widget is not loaded by ajax.');    
155            return;
156        }
157        if(widgets[wid].rendered === true){
158            callback(widgets[wid]);
159            event === events.preRender && console.log('The preRender event has alredy happened.');
160        } else {
161            document.addEventListener(event + '_' + wid, function(){
162                callback(widgets[wid]);
163            });
164        };
165    };
166    
167    // JQUERY EXTEND METHODS
168    // Extending for render and pre render events. Return this for function chaining.
169    $.fn.onWidgetRender = function(callback){
170        onSingleWidget($(this),callback,events.rendered);
171        return this;
172    };
173
174    $.fn.onWidgetPreRender = function(callback){
175        onSingleWidget($(this),callback,events.preRender);
176        return this;
177    };
178
179    // Return api if you need to expose additional functions/variables simple add as: exposedFunctionName: functionInFile
180    return{
181        widgets: widgets,
182        renderWidget: renderWidget,
183        triggerEvent: triggerEvent // exposing trigger event from widgetLoader
184    };
185})(jQuery);
186

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.