Widget:Hotspots-Filter: Unterschied zwischen den Versionen

Aus Freifunk Dresden - Anwender-Wiki
Zur Navigation springen Zur Suche springen
Zeile 1: Zeile 1:
 +
 +
<!--
 +
IMPORTANT: it is important to load javascript data before loading jQuery.
 +
Because when jQuery is loaded it starts running and as soon as DOM is read, "handler" is
 +
called. When loading data file after jQuery, then jQuery may be faster to call handler, but
 +
without any data.
 +
https://datatables.net/manual/styling/classes
 +
 +
-->
 
<script type="text/javascript" src="https://api.freifunk-dresden.de/freifunk-dresden-hotspots.json.js"></script>
 
<script type="text/javascript" src="https://api.freifunk-dresden.de/freifunk-dresden-hotspots.json.js"></script>
  
Zeile 7: Zeile 16:
  
 
<link rel="stylesheet" type="text/css" href="/hotspots/datatables/datatables.min.css"/>
 
<link rel="stylesheet" type="text/css" href="/hotspots/datatables/datatables.min.css"/>
<script type="text/javascript" src="/hotspots/datatables/datatables.min.js"></script>
+
<script type="text/javascript" src="/hotspots/datatables/datatables.min.js"></script>
  
 
<style>
 
<style>
Zeile 42: Zeile 51:
 
}
 
}
  
</style>
+
</style>
 +
 
  
 
<div>
 
<div>
<b>Spalten anzeigen:</b>
+
<b>Spalten anzeigen:</b>  
 
<!-- <a class="toggle-vis" data-column="2">Stats</a>, -->
 
<!-- <a class="toggle-vis" data-column="2">Stats</a>, -->
 
  <a class="toggle-vis" data-column="3">IP-Adresse</a>,
 
  <a class="toggle-vis" data-column="3">IP-Adresse</a>,
 
  <a class="toggle-vis" data-column="5">Uptime</a>,
 
  <a class="toggle-vis" data-column="5">Uptime</a>,
 
  <a class="toggle-vis" data-column="6">Erstmalig registriert</a>,
 
  <a class="toggle-vis" data-column="6">Erstmalig registriert</a>,
  <a class="toggle-vis" data-column="7">Registriert</a>,</div>
+
  <a class="toggle-vis" data-column="7">Registriert</a>,
 +
 
 +
<a class="toggle-vis" data-column="12">SSID</a>,
 +
<a class="toggle-vis" data-column="13">Gateway</a>,
 +
<a class="toggle-vis" data-column="14">Model</a>
 +
</div>
  
 
<table id="hotspots" class="display cell-border compact" style="width:100%;">
 
<table id="hotspots" class="display cell-border compact" style="width:100%;">
Zeile 80: Zeile 95:
 
         </tfoot>
 
         </tfoot>
 
  </table>
 
  </table>
 +
  
 
<script type="text/javascript">
 
<script type="text/javascript">
Zeile 93: Zeile 109:
 
https://api.jquery.com/jquery.noconflict/
 
https://api.jquery.com/jquery.noconflict/
  
If for some reason two versions of jQuery are loaded (which is not recommended),
+
If for some reason two versions of jQuery are loaded (which is not recommended),  
calling $.noConflict(true) from the second version will return the globally
+
calling $.noConflict(true) from the second version will return the globally  
 
scoped jQuery variables to those of the first version.
 
scoped jQuery variables to those of the first version.
 
Some times it could be issue with older version (or not stable) of JQuery files.
 
Some times it could be issue with older version (or not stable) of JQuery files.
Zeile 106: Zeile 122:
 
// use new way to call function when DOM is ready. old way was $(document).ready(handler)
 
// use new way to call function when DOM is ready. old way was $(document).ready(handler)
 
my.query(function() {
 
my.query(function() {
  // Filter aus dem Parameter 'filter' anwenden
 
  var filterParam = "<!--{$filter|escape:'html'}-->";
 
 
  console.log("Filter Parameter:", filterParam); // Debugging-Ausgabe
 
 
 
   // remember Table, to later access it via event function when a link is clicked with
 
   // remember Table, to later access it via event function when a link is clicked with
 
   // specific class name to make columns visible
 
   // specific class name to make columns visible
 
   var myTable = my.query('#hotspots').DataTable( {
 
   var myTable = my.query('#hotspots').DataTable( {
 
"processing": true,
 
"processing": true,
 +
                "searching": false,
 
//"pageLength" : 25,
 
//"pageLength" : 25,
 
//"lengthMenu": [[ 25, 50, 100, 200, -1 ], [25,50,100,200,"All"]],
 
//"lengthMenu": [[ 25, 50, 100, 200, -1 ], [25,50,100,200,"All"]],
 
paging: false,
 
paging: false,
 
"order" : [[0,'asc']],
 
"order" : [[0,'asc']],
 +
 
// extensions
 
// extensions
 
"fixedHeader": true,
 
"fixedHeader": true,
 
//"responsive": true,
 
//"responsive": true,
"searching": false, // Deaktiviert das Suchfeld
+
"language":{
 +
                        "search":"Filter"
 +
},
  
 
// define nowrap for specific columns
 
// define nowrap for specific columns
Zeile 132: Zeile 147:
 
],
 
],
 
         "data": dataSet,
 
         "data": dataSet,
        "drawCallback": function(settings) {
 
            console.log("Table drawn"); // Debugging-Ausgabe
 
        },
 
        "initComplete": function(settings, json) {
 
            console.log("Table initialized"); // Debugging-Ausgabe
 
            if (filterParam) {
 
                console.log("Applying filter:", filterParam); // Debugging-Ausgabe
 
                myTable.search(filterParam).draw();
 
            }
 
        },
 
  
 
         // https://datatables.net/reference/option/rowCallback
 
         // https://datatables.net/reference/option/rowCallback
 
"rowCallback": function( row, data ) {
 
"rowCallback": function( row, data ) {
 
+
 
if ( data.id < 1000 )
 
if ( data.id < 1000 )
 
{
 
{
Zeile 159: Zeile 164:
  
 
if ( data.status.offline_since > 2 )
 
if ( data.status.offline_since > 2 )
{
+
{
 
//row.style.backgroundColor= (row.className=="odd") ? "#cccccc" : "#dddddd";
 
//row.style.backgroundColor= (row.className=="odd") ? "#cccccc" : "#dddddd";
 
row.style.backgroundColor= "#cccccc";
 
row.style.backgroundColor= "#cccccc";
Zeile 193: Zeile 198:
 
},
 
},
 
                 //connections
 
                 //connections
{ "data": "status.connection_types",
+
{ "data": "status.connection_types",  
 
  "render" : function (data, type, row) {
 
  "render" : function (data, type, row) {
 
if ( type === 'display' || type === 'filter' ) {
 
if ( type === 'display' || type === 'filter' ) {
var wifi = data.wifi ? '<img title="meshing via wifi" src="/hotspots/images/wifi-on-24.png">'
+
var wifi = data.wifi ? '<img title="meshing via wifi" src="/hotspots/images/wifi-on-24.png">'  
 
    : '<img title="Kein wifi meshing" src="/hotspots/images/wifi-off-24.png">';
 
    : '<img title="Kein wifi meshing" src="/hotspots/images/wifi-off-24.png">';
 
var backbone = data.backbone ? '<img title="meshing via backbone" src="/hotspots/images/backbone-on-24.png">'
 
var backbone = data.backbone ? '<img title="meshing via backbone" src="/hotspots/images/backbone-on-24.png">'
Zeile 224: Zeile 229:
 
},
 
},
 
                 //online/gw/tage
 
                 //online/gw/tage
{ "data": "status",
+
{ "data": "status",  
 
  "render" : function (data, type, row) {
 
  "render" : function (data, type, row) {
 
if ( type === 'display' || type === 'filter' ) {
 
if ( type === 'display' || type === 'filter' ) {
Zeile 240: Zeile 245:
 
                                         // tage sind offline oder online tage, abhaengig vom aktuellen zustand.
 
                                         // tage sind offline oder online tage, abhaengig vom aktuellen zustand.
 
                                         var days = data.online ? Math.floor(data.uptime / 86400) : data.offline_since;
 
                                         var days = data.online ? Math.floor(data.uptime / 86400) : data.offline_since;
                                         var title_o = data.online ? 'Online seit ' + Math.floor(data.uptime / 86400) + ' Tagen': 'Offline seit ' + data.offline_since + ' Tagen';
+
                                         var title_o = data.online ? 'Online seit ' + Math.floor(data.uptime / 86400) + ' Tagen': 'Offline seit ' + data.offline_since + ' Tagen';  
 
                                         var title_g = data.gateway && data.online ? 'Gateway' : 'Kein Gateway';
 
                                         var title_g = data.gateway && data.online ? 'Gateway' : 'Kein Gateway';
  
Zeile 248: Zeile 253:
 
return '<img search="'+search_g+'" title="'+title_o+'" src="/hotspots/images/' + img_o + '">'
 
return '<img search="'+search_g+'" title="'+title_o+'" src="/hotspots/images/' + img_o + '">'
 
+ '<img title="'+title_g+'" src="/hotspots/images/' + img_g + '">'
 
+ '<img title="'+title_g+'" src="/hotspots/images/' + img_g + '">'
                                                 + '[' + days + ']';
+
                                                 + '[' + days + ']' ;
 
}
 
}
 
return data.online ? - Math.floor(data.uptime / 86400) : data.offline_since;
 
return data.online ? - Math.floor(data.uptime / 86400) : data.offline_since;
Zeile 260: Zeile 265:
 
// If display or filter data is requested, format the date
 
// If display or filter data is requested, format the date
 
if ( type === 'display' || type === 'filter' ) {
 
if ( type === 'display' || type === 'filter' ) {
 
+
                                       
 
                                         var days = Math.floor(rest / 86400);
 
                                         var days = Math.floor(rest / 86400);
 
                                         rest = rest % 86400;
 
                                         rest = rest % 86400;
Zeile 274: Zeile 279:
 
                 },
 
                 },
 
                 //firstseen
 
                 //firstseen
{ "data": "status.firstseen",
+
{ "data": "status.firstseen",  
 
  "render" : function (data, type, row) {
 
  "render" : function (data, type, row) {
 
if ( type === 'display' || type === 'filter' ) {
 
if ( type === 'display' || type === 'filter' ) {
Zeile 289: Zeile 294:
 
},
 
},
 
                 //registerred
 
                 //registerred
{ "data": "status.registered",
+
{ "data": "status.registered",  
 
  "render" : function (data, type, row) {
 
  "render" : function (data, type, row) {
 
if ( type === 'display' || type === 'filter' ) {
 
if ( type === 'display' || type === 'filter' ) {
Zeile 311: Zeile 316:
 
  "render" : function (data, type, row) {
 
  "render" : function (data, type, row) {
 
if ( type === 'display' || type === 'filter' ) {
 
if ( type === 'display' || type === 'filter' ) {
  return '<a href="https://meshviewer.freifunk-dresden.de/' + data + '" target="_blank">Map</a>';
+
  return '<a href="https://meshviewer.freifunk-dresden.de/' + data + '" target="_blank">Map</a>';  
 
}
 
}
 
return 0;
 
return 0;
Zeile 358: Zeile 363:
 
         ]
 
         ]
 
     } );
 
     } );
 +
 +
        // Apply initial filter from widget parser params (if provided).
 +
        // Supported ways to pass params from MediaWiki parser:
 +
        // 1) Insert a JSON script before this widget: <script id="Hotspots-params" type="application/json">{"filter":"+gw"}</script>
 +
        // 2) Set a global variable before this widget: window.hotspotsWidgetParams = {filter: "+gw"};
 +
        // 3) Expand Smarty params inside HTML comments or elements (e.g. <!--{$filter|escape:'html'}-->).
 +
        try {
 +
                var params = {};
 +
 +
                // a) JSON script element
 +
                var paramsEl = document.getElementById('Hotspots-params');
 +
                if (paramsEl && paramsEl.textContent && paramsEl.textContent.trim().length) {
 +
                        try { Object.assign(params, JSON.parse(paramsEl.textContent)); } catch(e){}
 +
                }
 +
 +
                // b) global var
 +
                if (window.hotspotsWidgetParams && typeof window.hotspotsWidgetParams === 'object') {
 +
                        Object.assign(params, window.hotspotsWidgetParams);
 +
                }
 +
 +
                // c) explicit element with id 'Hotspots-param-<name>' (textContent or comment-expanded)
 +
                try {
 +
                        var els = document.querySelectorAll('[id^="Hotspots-param-"]');
 +
                        els.forEach(function(el){
 +
                                var name = el.id.replace('Hotspots-param-','');
 +
                                var val = (el.textContent || '').trim();
 +
                                if (val) params[name] = val;
 +
                        });
 +
                } catch(e){}
 +
 +
                // d) scan HTML comment nodes for parser-expanded params / JSON / key=value
 +
                try {
 +
                        var walker = document.createTreeWalker(document, NodeFilter.SHOW_COMMENT, null, false);
 +
                        var cnode;
 +
                        while (cnode = walker.nextNode()) {
 +
                                var txt = (cnode.nodeValue || '').trim();
 +
                                if (!txt) continue;
 +
                                // try JSON
 +
                                if (txt.charAt(0) === '{') {
 +
                                        try { Object.assign(params, JSON.parse(txt)); continue; } catch(e){}
 +
                                }
 +
                                // key=value pairs separated by & or newline
 +
                                if (txt.indexOf('=') !== -1) {
 +
                                        txt.split(/[&\n;]+/).forEach(function(pair){
 +
                                                var kv = pair.split('=');
 +
                                                if (kv.length>=2) params[kv[0].trim()] = decodeURIComponent(kv.slice(1).join('=').trim());
 +
                                        });
 +
                                        continue;
 +
                                }
 +
                                // plain filter string like +gw or -au or any non-empty token
 +
                                if (!params.filter && txt.length > 0) {
 +
                                        params.filter = txt;
 +
                                }
 +
                        }
 +
                } catch(e){}
 +
 +
                if (params.filter) {
 +
                        myTable.search(params.filter).draw();
 +
                }
 +
        } catch (e) {
 +
                console.warn('Hotspots widget: could not parse params', e);
 +
        }
  
 
     //function that is called each time a link with class "toggle-vis" is clicked.
 
     //function that is called each time a link with class "toggle-vis" is clicked.
Zeile 363: Zeile 430:
 
     my.query('a.toggle-vis').on( 'click', function (e) {
 
     my.query('a.toggle-vis').on( 'click', function (e) {
 
         e.preventDefault();
 
         e.preventDefault();
 
+
 
         // Get the column API object
 
         // Get the column API object
 
         var column = myTable.column( $(this).attr('data-column') );
 
         var column = myTable.column( $(this).attr('data-column') );
 
+
 
         // Toggle the visibility
 
         // Toggle the visibility
 
         column.visible( ! column.visible() );
 
         column.visible( ! column.visible() );
     });
+
     } );
 +
 
  
 
     //register event handler
 
     //register event handler

Version vom 16. Februar 2026, 15:48 Uhr

<script type="text/javascript" src="https://api.freifunk-dresden.de/freifunk-dresden-hotspots.json.js"></script>

<script type="text/javascript" src="/hotspots/jquery/jquery.js"></script> <script type="text/javascript" src="/hotspots/jquery/jquery-ui.min.js"></script> <link rel="stylesheet" type="text/css" href="/hotspots/jquery/jquery-ui.min.css"/>

<link rel="stylesheet" type="text/css" href="/hotspots/datatables/datatables.min.css"/> <script type="text/javascript" src="/hotspots/datatables/datatables.min.js"></script>

<style> .stats {} .statsx {

  background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAOCSURBVEiJ5ZfLbxtVGMV/c2fcelon9diOG1dGNN4QYiJYsGGBQGp4qkiwQbBBleiGP6AS/AM8VB5LNoAilmzKhrJBQgoIdYVAbVVqSBrn4feMX01dxzO+LBzfempHrcGhC87mes74+879zpwZzcADggbw3idfnTaE/mXH7cQPSigQMIpex337/XNnvwMwAHQhll99+dloLGJxdW2LdCrpK5oEV7arx7/9/sdlYAZAALiuG41FrEkOOISZqIXrurH+sTG4s1G/D4pTwn2L7mVht1FHTB/7R/avrNzhxdBW7oHdzPVxS0ZifOHVvx6McGftz4kIjxcuKQlnrqvz/1m4us0mhVaLR+NhrpVqvv955RJ/NHcPJlxe1fatg7j926/jtNpf2CuXRghXfesg2lcuT0a4demXIa5rV3yrgpTsXvkdTcr7Ft43XFM//0Q2/aSPC66tYwKF1XV4eF7ViEaNYzs7cLPx78K1kIiS37jBQiKKZpoqILUfOrRn4kRkh+2Bmva1OjagV8o88nh6SPS+w+XmcyBlbx2AV3UIzKXoVh0/Xyz0mjn+S9Dd2UFrtUZJ7CO83bPGzW37GzkOh+ZSeI4/1W6xiAiFEHel3d3Mopfy4wmLUEht4I6wTeBkCs/xT9wtFTi8+AT6XaHrbGTRC37X+hgZLieTQc4v0s5k2Og/pTI3sG42WTWOEm42wHVVzXQ2S/upZzh8acXX58jlqxja6HCpidOppAqBWbNJLC1h1mzFzVtH0YJBFhbn0YJBRLOuagL1GnPPLyEcW3HpVJKpegVRzPt6D02s4Hl4VYdDjy3iOTbS83q0Y6NbEQD0sIWo1wCQt26hGQb61DRSCGSrhWaaICWdrU30rgQpQdNGT9yH7lQwjs+iGQGM+KxKrOfYiD1hYUUQzQYAbrGAMZsAoBuL4xZ7YfLKJURoCmkewauU97daEaUCRvKhnh3JJO7W5p6wgx4O93jLQtSre8J59MSJnnB0Rm20s5ElcHIO70SSTnZ9SFhZnXvjNQBCgPPcaXJrW5jmNK1PP8ICGsDtp0/1eC2AefECuYsXAGi98Arba1sEIzGcz86r5q1TL6FNRXA+/qBHvPimOqcBvHv+C/nOmdeBybzK7sd9vvwNH547q8Ge1bqhV4tl/705aRRLNoZhqCeM+pLQhfa163oH9nJt6LrT9by3+l8S/z/8Dfo07AAuLNF8AAAAAElFTkSuQmCC');
   background-size: 30px;
   background-repeat: no-repeat;
   background-position: center;
   display: block;
   width: 30px;
   height: 30px;
   text-decoration: none;
   cursor: pointer;
   overflow: hidden;
   text-indent: 100%;
   white-space:nowrap;

} .grafanax {

  background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABHNCSVQICAgIfAhkiAAABYhJREFUSImdln1sldUdxz/nPC/33t5Su7RYirSsKJDBVlKsmQkoCoti4prokgkxZG9ZhvtjJm5LDC/6h875p2+Jc6KQadSsccoGIYrGzaHorLBWZVBaBhRKu9rS1/v2POf89sctvX287a3wS07uy/md7+d8f+d5zjlKRIQrDHPhvygvjq6uvaxxIoK+UmjQ8QHjD21ifMcPCDoOXdZYpRTqShybvjNM7PwhkhrNCyUrSD7SilNT/7U1LtuxiJB989kpKIBMjJJtfQrTdwYRmWr2y15Mz0lm8jajYxFBKRX5JMgSfLif3If7MMfbwIQzTkxVzsdtXIvpasf2ngKtKf/9XpxF10Xy3Ok/7NhFcgdfxXR+iuk7CwhObQO6bhnh0b/nheaqyPAAwftvTBO1hJ1HSoNNVzvZ15+OJIQD52Gmh0cpVHkluqYedVUVyothh/qx57uRiZFobhgUDY+AVSI5pyMcF2/N9/HXtuBc24iKl0W6JT1B2N1O8P5ego/2gzFk9+3CW30runphgTV9je3wAGO/Wj/r+ukFiym7/0mc+uVzTxAwPSdJ/3Eb5tTnOEubSG7fjfJiea2I44oqnOVNoKSo6WsaSO586WtDAZy6pSS378Ft/h6m6yi5d14pmIiAtSa2cQv4gCdTTZV5JH7+KLpyfpG4WIMd6iM82UbYfRR7sR+ZVjEVT1J23+O4K1eTe2cPkk0DX1ljALdpA05dA/ZCFyhAwLtxI851TVGgCPbsF2T+/DvM6Q4IcyCA6+EsWo5382a8G+9CuR4qniTxs8cYf+xuwhOH8RrXF28gMnERGe0Bf9JxDPwNW1BKRfLCtr+SeuIezJlPQGXzub6AzmF6PyPz2jZST27GDvbkS3v1YmK3/wTTdbi41AD27L9BpVC+RfkWffUCdP13Ijnm3BdkWh8ElcZtvImyrX8gufMtyh54jdjGraiKJMq32PNHSD17L3akDwBv7SZkvL+41JJLER47kJ/9ZDiLV0bcigjBP58DlcFb9yNid+5AOQUZd0kzbnMLmZd+gf3yNDLWQ/bNHcS3PIeeV4276raoYzt0mvSL9xB2tE65Vb5FV1ZFSxJkMOc+RlfNJ3bbAxHo1GQXLCN+7zOouEb5FtP9LvZ8R971qjsLYDvSS+blTdiB9vw6TW8qF1U1WTDDON9sRCUqiqCXQteuwP3WuslnxRAe3x/tF2vJHdyGpM6hPFvU7EhXVNFLoCqrQdKzQiF/5uq6xikdGTr2FfDgcey594qdTjYZbEfSQwVBN4bbeDe2/yNM7ycl4UimoCWpKFhVLcP77n0oX83oGJ0m/Gw3TDs9vRt+idOwhtyBnxIeewU73osd7cH2HSkwRZCBtoLj8S7s4H8KBiQf2FN/I/jX48joDEefP49Yy1501YqCsMliOl/HnNqHZAbRlUtxV21FV38bAHvxBNnW9SCmAKtaSeyuAyjHjx4SYgPs2YPY/o8xnS8jwVhh0Lx6/Ntb0RUNpcsLSJgi9/ZmbN/hYg93/AWndu0sdy4RwhO7CNu2k98HJ+GJGtzVD6PrW1BObGZoup/g8P3Y3nejHTqGXrgBt/lRdHnd7Jc9EUv46W8x3XuiHUqhypfgNGxG16xDJRaAcpDx09j+f2C6diOZ/xXS/W/grfkTat4SiNdMbUYlb5l24BDBoZbZui9Jg3bBFt8ycBK4zbtwFt5R1FW87UwLGf8cfDsHGMAU/aO8atym59Hzb51xREkwKkB5sxakZDgNW2aFzglW5dfmX35AoaBsOU79byC+CBk7gqQ6IRhCUsfz3y+NQ6Gqbi45sZJrLOEw9sIL4CRQ5dejyptQ2i/Oy/VhTvwYGfsARFBX3YKz4g2U9q4MfDkhEiLDB5GRt9G1v0bFFpXM/z/LE5JTSgZnuwAAAABJRU5ErkJggg==');
   background-size: 30px;
   background-repeat: no-repeat;
   background-position: center;
   display: block;
   width: 30px;
   height: 30px;
   text-decoration: none;
   cursor: pointer;
   overflow: hidden;
   text-indent: 100%;
   white-space:nowrap;

}

</style>


Spalten anzeigen:

<a class="toggle-vis" data-column="3">IP-Adresse</a>,
<a class="toggle-vis" data-column="5">Uptime</a>,
<a class="toggle-vis" data-column="6">Erstmalig registriert</a>,
<a class="toggle-vis" data-column="7">Registriert</a>,
<a class="toggle-vis" data-column="12">SSID</a>,
<a class="toggle-vis" data-column="13">Gateway</a>,
<a class="toggle-vis" data-column="14">Model</a>
<thead> </thead> <tfoot> </tfoot>
Node Stat Meshing IP Ok
GW
Tage
Uptime Erstmalig
registriert
Registriert Name Map Firmware AU SSID Gateway
aktuell/bevorzugt.
Model Ort Kommentar


<script type="text/javascript">

function getIp(node) {

var _middle = Math.floor((node / 255)) % 256;
var _minor  = (node % 255) + 1;
return '10.200.' + _middle.toString() + '.' + _minor.toString();

}

/* https://api.jquery.com/jquery.noconflict/

If for some reason two versions of jQuery are loaded (which is not recommended), calling $.noConflict(true) from the second version will return the globally scoped jQuery variables to those of the first version. Some times it could be issue with older version (or not stable) of JQuery files.

Solution: move new jQuery completely in new object and use this.

  • /

var my = {}; my.query = jQuery.noConflict( true );

// use new way to call function when DOM is ready. old way was $(document).ready(handler) my.query(function() {

 // remember Table, to later access it via event function when a link is clicked with
 // specific class name to make columns visible
 var myTable = my.query('#hotspots').DataTable( {

"processing": true,

               "searching": false,

//"pageLength" : 25, //"lengthMenu": [[ 25, 50, 100, 200, -1 ], [25,50,100,200,"All"]], paging: false, "order" : 0,'asc',

// extensions "fixedHeader": true, //"responsive": true, "language":{

                       "search":"Filter"

},

// define nowrap for specific columns "columnDefs": [ { className: "dt-nowrap", "targets": [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] }, // default: visible { visible: false, "targets": [3,5,6,7,12,13,14] }

],

       "data": dataSet,
       // https://datatables.net/reference/option/rowCallback

"rowCallback": function( row, data ) {

if ( data.id < 1000 ) { row.style.backgroundColor= (row.className=="odd") ? "#bbddbb" : "#cceecc"; //row.firstChild.style.backgroundColor = row.style.backgroundColor; }

if ( data.id > 1000 && data.id < 51000 ) { row.style.backgroundColor= (row.className=="odd") ? "#ddddee" : "#eeeeff"; //row.firstChild.style.backgroundColor = row.style.backgroundColor; }

if ( data.status.offline_since > 2 ) { //row.style.backgroundColor= (row.className=="odd") ? "#cccccc" : "#dddddd"; row.style.backgroundColor= "#cccccc"; //row.firstChild.style.backgroundColor = row.style.backgroundColor; } },

       // see: https://datatables.net/manual/data/orthogonal-data
       "columns": [
               // node

{ "data": "id", "render" : function (data, type, row) { // If display or filter data is requested, format the date if ( type === 'display' || type === 'filter' ) { return '<a href="http://' + data + '.freifunk-dresden.de/" target="_blank">' + data + '</a>'; } //else return id that is used when sorting this column return data; } },

               // statistic icon

{ "data": "id", "render" : function (data, type, row) { // If display or filter data is requested, format the date if ( type === 'display' || type === 'filter' ) { var stat = '<a class="stats" data="' + data + '"></a>';

                                       var grafana = '<a href="https://grafana.freifunk-dresden.de/' + data + '" target="_blank"></a>';
                                       return stat + grafana;

} //else return id that is used when sorting this column return data; } },

               //connections

{ "data": "status.connection_types", "render" : function (data, type, row) { if ( type === 'display' || type === 'filter' ) { var wifi = data.wifi ? '' : ''; var backbone = data.backbone ? '' : ''; var lan = data.lan ? '' : ''; return wifi + ' ' + backbone + ' ' + lan; }

                               // sort
                               var sort_value = data.lan ? 1 : 0;
                               if(data.backbone) sort_value += 10;
                               if(data.wifi) sort_value += 100;

return sort_value; } },

               //ip

{ "data": "id", //use "id" as input data for renderer "render" : function (data, type, row) { // If display or filter data is requested, format the date if ( type === 'display' || type === 'filter' ) { var ip = getIp(data); return '<a href="http://' + ip + '/" target="_blank">' + ip + '</a>'; } //else return id that is used when sorting this column return data; } },

               //online/gw/tage

{ "data": "status", "render" : function (data, type, row) { if ( type === 'display' || type === 'filter' ) {

                                       var t = new Date(data.lastseen*1000);

var day = ( '0' + t.getDate() ).slice(-2); var month = ( '0' + (t.getMonth() + 1) ).slice(-2); var h = ( '0' + t.getHours() ).slice(-2); var m = ( '0' + t.getMinutes() ).slice(-2); var stat_time = day + '.' + month + '.' + t.getFullYear() + ' ' + h + ':' + m;

var img_o = data.online ? 'yes.png' : 'no.png'; var img_g = data.gateway && data.online ? 'yes.png' : 'no-grey.png';

                                       // tage sind offline oder online tage, abhaengig vom aktuellen zustand.
                                       var days = data.online ? Math.floor(data.uptime / 86400) : data.offline_since;
                                       var title_o = data.online ? 'Online seit ' + Math.floor(data.uptime / 86400) + ' Tagen': 'Offline seit ' + data.offline_since + ' Tagen'; 
                                       var title_g = data.gateway && data.online ? 'Gateway' : 'Kein Gateway';
                                       // definiere einfach ein attribut, was ebenfalls von data-table beim filtern verwendet wird.
                                       var search_g= data.gateway && data.online ? '+gw' : '-gw';

return '' + ''

                                               + '[' + days + ']' ;

} return data.online ? - Math.floor(data.uptime / 86400) : data.offline_since; } },

               //uptime
               { "data": "status",
                 "render" : function (data, type, row) {
                               var rest = 0;
                               if(data.online){ rest = data.uptime };

// If display or filter data is requested, format the date if ( type === 'display' || type === 'filter' ) {

                                       var days = Math.floor(rest / 86400);
                                       rest = rest % 86400;
                                       var hours = Math.floor(rest / 3600);
                                       rest = rest % 3600;
                                       var minutes = Math.floor(rest/60);

return days+'d '+hours+'h '+minutes+'m'; } //else return id that is used when sorting this column return rest; }

               },
               //firstseen

{ "data": "status.firstseen", "render" : function (data, type, row) { if ( type === 'display' || type === 'filter' ) { var t = new Date(data*1000); var day = ( '0' + t.getDate() ).slice(-2); var month = ( '0' + (t.getMonth() + 1) ).slice(-2); var h = ( '0' + t.getHours() ).slice(-2); var m = ( '0' + t.getMinutes() ).slice(-2); return day + '.' + month + '.' + t.getFullYear() + ' ' + h + ':' + m; } return data; } },

               //registerred

{ "data": "status.registered", "render" : function (data, type, row) { if ( type === 'display' || type === 'filter' ) { var t = new Date(data*1000); var day = ( '0' + t.getDate() ).slice(-2); var month = ( '0' + (t.getMonth() + 1) ).slice(-2); var h = ( '0' + t.getHours() ).slice(-2); var m = ( '0' + t.getMinutes() ).slice(-2); return day + '.' + month + '.' + t.getFullYear() + ' ' + h + ':' + m; } return data; } },

               //nick

{ "data": "name", "render" : function (data, type, row) { return data.substring(0,15); } },

               //map

{ "data": "id", "render" : function (data, type, row) { if ( type === 'display' || type === 'filter' ) { return '<a href="https://meshviewer.freifunk-dresden.de/' + data + '" target="_blank">Map</a>'; } return 0; } },

               //firmware version

{ "data": "firmware" },

               //autoupdate

{ "data": "status.autoupdate", "render" : function (data, type, row) { if ( type === 'display' || type === 'filter' ) { var img_au = data ? 'yes.png' : 'no.png';

                                       var title_au = data ? 'Auto-Update' : 'Kein Auto-Update';
                                       // definiere einfach ein attribut, was ebenfalls von data-table beim filtern verwendet wird.
                                       var search_au= data ? '+au' : '-au';

return ''; } return data; } },

               //wifi ssid

{ "data": "status.ssid"},

               //preverred gateway

{ "data": "status", "render" : function (data, type, row) { if ( type === 'display' || type === 'filter' ) { return data.selected_gateway + '(' + data.preferred_gateway + ')'; } return data.selected_gateway; } },

               //device model

{ "data": "model", "render" : function (data, type, row) { return data.substring(0,25); } },

               //location

{ "data": "location", "render" : function (data, type, row) { return data.substring(0,25); } },

               //comment

{ "data": "note", "render" : function (data, type, row) { return data.substring(0,60); } },

       ]
   } );
       // Apply initial filter from widget parser params (if provided).
       // Supported ways to pass params from MediaWiki parser:
       // 1) Insert a JSON script before this widget: <script id="Hotspots-params" type="application/json">{"filter":"+gw"}</script>
       // 2) Set a global variable before this widget: window.hotspotsWidgetParams = {filter: "+gw"};
       // 3) Expand Smarty params inside HTML comments or elements (e.g. ).
       try {
               var params = {};
               // a) JSON script element
               var paramsEl = document.getElementById('Hotspots-params');
               if (paramsEl && paramsEl.textContent && paramsEl.textContent.trim().length) {
                       try { Object.assign(params, JSON.parse(paramsEl.textContent)); } catch(e){}
               }
               // b) global var
               if (window.hotspotsWidgetParams && typeof window.hotspotsWidgetParams === 'object') {
                       Object.assign(params, window.hotspotsWidgetParams);
               }
               // c) explicit element with id 'Hotspots-param-<name>' (textContent or comment-expanded)
               try {
                       var els = document.querySelectorAll('[id^="Hotspots-param-"]');
                       els.forEach(function(el){
                               var name = el.id.replace('Hotspots-param-',);
                               var val = (el.textContent || ).trim();
                               if (val) params[name] = val;
                       });
               } catch(e){}
               // d) scan HTML comment nodes for parser-expanded params / JSON / key=value
               try {
                       var walker = document.createTreeWalker(document, NodeFilter.SHOW_COMMENT, null, false);
                       var cnode;
                       while (cnode = walker.nextNode()) {
                               var txt = (cnode.nodeValue || ).trim();
                               if (!txt) continue;
                               // try JSON
                               if (txt.charAt(0) === '{') {
                                       try { Object.assign(params, JSON.parse(txt)); continue; } catch(e){}
                               }
                               // key=value pairs separated by & or newline
                               if (txt.indexOf('=') !== -1) {
                                       txt.split(/[&\n;]+/).forEach(function(pair){
                                               var kv = pair.split('=');
                                               if (kv.length>=2) params[kv[0].trim()] = decodeURIComponent(kv.slice(1).join('=').trim());
                                       });
                                       continue;
                               }
                               // plain filter string like +gw or -au or any non-empty token
                               if (!params.filter && txt.length > 0) {
                                       params.filter = txt;
                               }
                       }
               } catch(e){}
               if (params.filter) {
                       myTable.search(params.filter).draw();
               }
       } catch (e) {
               console.warn('Hotspots widget: could not parse params', e);
       }
   //function that is called each time a link with class "toggle-vis" is clicked.
   //Then corresponding column visibility toggles
   my.query('a.toggle-vis').on( 'click', function (e) {
       e.preventDefault();

       // Get the column API object
       var column = myTable.column( $(this).attr('data-column') );

       // Toggle the visibility
       column.visible( ! column.visible() );
   } );


   //register event handler
   my.query('#hotspots tbody').on('click', 'a.stats', function () {
       var id = this.attributes['data'].nodeValue;

//create

var popup = '
'
                 + 'Knoten: ' + id + '
' + '<button id="btn_h_'+id+'" onclick=\'switchTime(' + id + ', "6hour")\'>6 Stunden</button>' + '<button id="btn_d_'+id+'" onclick=\'switchTime(' + id + ', "1day")\'>Tag</button>' + '<button id="btn_w_'+id+'" onclick=\'switchTime(' + id + ', "1week")\'>Woche</button>' + '<button id="btn_m_'+id+'" onclick=\'switchTime(' + id + ', "1month")\'>Monat</button>' + '<button id="btn_y_'+id+'" onclick=\'switchTime(' + id + ', "1year")\'>Jahr</button>' + '
' + '' + '
' + '' + '
' + '' + '
' + '' + '
' + ''
+ '
';
       my.query('body').append(popup);
      // elements must exist as DOM objects before accessing
      switchTime(id, '1day');
       //show popup
       my.query( '#statdialog' + id ).dialog({
          resizable: false,
          height: "auto",
          //width: 792, //16+380+380+16 (margin is 16)
          //width: 792, //16+350+16 (margin is 16)
          width: "auto",
          modal: false,
          // position: { my: "left top", at: "left top"},
          close: function( event, ui ) {
                   my.query( '#statdialog' ).remove();  //remove div
                 }
       });
   }); //event handler statistic
} );
//function must be global, so it can be found by onclick handlers.
       function switchTime(id,period){
           //var period='1day'; //6hour,1day,1week,1month,1year
           var srcTiming='https://stats.freifunk-dresden.de/' + id + '/timing/' + period;
           var srcClients='https://stats.freifunk-dresden.de/' + id + '/clients/' + period;
           var srcBackbone='https://stats.freifunk-dresden.de/' + id + '/backbone/' + period;
           var srcAp='https://stats.freifunk-dresden.de/' + id + '/ap/' + period;
           var srcVpn='https://stats.freifunk-dresden.de/' + id + '/vpn/' + period;
           my.query('#img_timing_'+id).attr("src",srcTiming);
           my.query('#img_clients_'+id).attr("src",srcClients);
           my.query('#img_backbone_'+id).attr("src",srcBackbone);
           my.query('#img_ap_'+id).attr("src",srcAp);
           my.query('#img_vpn_'+id).attr("src",srcVpn);
           //mark button (boarder)
           my.query('#btn_h_'+id).attr("style","background-color:none;");
           my.query('#btn_d_'+id).attr("style","background-color:none;");
           my.query('#btn_w_'+id).attr("style","background-color:none;");
           my.query('#btn_m_'+id).attr("style","background-color:none;");
           my.query('#btn_y_'+id).attr("style","background-color:none;");
           if(period=="6hour") my.query('#btn_h_'+id).attr("style","background-color:powderblue;");
           if(period=="1day") my.query('#btn_d_'+id).attr("style","background-color:powderblue;");
           if(period=="1week") my.query('#btn_w_'+id).attr("style","background-color:powderblue;");
           if(period=="1month") my.query('#btn_m_'+id).attr("style","background-color:powderblue;");
           if(period=="1year") my.query('#btn_y_'+id).attr("style","background-color:powderblue;");
       }

</script>