/* -----
Material Design JS for ioBroker.vis
(c) 2017 Uhula, MIT License
https://github.com/Uhula/ioBroker-Material-Design-Style
V1.7 28.12.2017
o Korrektur mdui-lnav/rnav. Funktionierte mit mdui-toggle nicht korrekt
V1.6 16.10.2017
O _toggleFullscreen geändert, damit die function auch im ioBroker
fullscreen Mode funktioniert
o Delegator-Eventhandler für body gesetzt (bisher #vis_container, wirkten dann aber in Dialogen nicht)
V1.5 11.10.2017
o MDUI.handleTables fertig
V1.3 24.09.2017
+ MDUI.handleTables hinzu (in Entwicklung)
V1.0 01.09.2017
----- */
// Zur sicheren CSS-Erkennung der Runtime eine CSS-Klasse anlegen
document.documentElement.className += " mdui-runtime";
// Überprüfen ob touch zur Verfügung steht und entsprechend eine
// CSS Klasse touch bzw no-touch erzeugen
document.documentElement.className +=
(("ontouchstart" in document.documentElement) ? " mdui-touch" : " mdui-notouch");
/* -----
MDUI
-----
Sammlung von JS-Funktionen für das Material Design
(c) 2017 Uhula, MIT License
*/
var MDUI = (function () {
var isSubtreeModified = false;
// liefert den suffix einer gegeben class zurück-Navigieren
// Bsp: mdui-target-w00002 -> w00002
// mdui-zoom-to-200 -> 200
function _getClassSuffix( $ele, classname ) {
var suf = "";
if ($ele) {
var c = $ele.attr( "class" );
suf = c.substr(c.indexOf(classname)+classname.length,1000)+" ";
suf = suf.substr(0,suf.indexOf(" "));
}
return suf;
}
//
function _getGroupID( ele ) { return _getClassSuffix(ele, "mdui-group-" ); }
//
function _getTargetID( ele ) { return _getClassSuffix(ele, "mdui-target-" ); }
//
function _getScrollbarWidth() {
var $outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
widthWithScroll = $('<div>').css({width: '100%'}).appendTo($outer).outerWidth();
$outer.remove();
return 100 - widthWithScroll;
}
//
function _getScrollbarHeight() {
var $outer = $('<div>').css({visibility: 'hidden', height: 100, overflow: 'scroll'}).appendTo('body'),
heightWithScroll = $('<div>').css({height: '100%'}).appendTo($outer).outerHeight();
$outer.remove();
return 100 - heightWithScroll;
}
function _formatDatetime(date, format) {
function fill(comp) {
return ((parseInt(comp) < 10) ? ('0' + comp) : comp)
}
var months = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'];
var d = format;
var o = {
"y+": date.getFullYear(), // year
"m+": fill(date.getMonth()+1), //month
"M+": months[date.getMonth()], //month
"d+": fill(date.getDate()), //day
"H+": fill((date.getHours() > 12) ? date.getHours() % 12 : date.getHours()), //hour
"h+": fill(date.getHours()), //hour
"n+": fill(date.getMinutes()), //minute
"s+": fill(date.getSeconds()), //second
"S+": fill(date.getMilliseconds()), //millisecond,
"b+": (date.getHours() >= 12) ? 'PM' : 'AM'
};
for (var k in o) {
if (new RegExp("(" + k + ")").test(format)) {
d = d.replace(RegExp.$1, o[k]);
}
}
return d;
}
// alle Elemente mit class "mdui-group-XXX" togglen, in denen
// XXX aus class "mdui-group-XXX" des ele ist UND
// alle Elemente mit class "mdui-target-XXX" togglen, in denen
// XXX aus class "mdui-target-XXX" des ele ist
function _toggleVisibility( $ele ) {
$ele.toggleClass("ui-state-active");
var id = _getGroupID( $ele );
if (id!=="")
$("[class*='mdui-group-"+id+"']").not("[class*='mdui-toggle']").each( function (index) {
$(this).toggleClass("mdui-hide");
});
id = _getTargetID( $ele );
if (id!=="")
$( "[class*='mdui-target-"+id+"']").not("[class*='mdui-toggle']").each( function (index) {
$(this).toggleClass("mdui-hide");
});
}
// das in ele class \"mdui-target-XXX\" angegeben Element mit der id \"XXX\" wird
// - fullscreen angezeigt, wenn es noch nicht fullscreen ist
// - wieder normal angezeigt, wenn es fullscreen ist
function _toggleFullscreen( $ele ){
if (!$ele) return;
var $target = $ele.closest(".vis-view");
if (!$target) return;
var styleold = $target.attr("styleold");
if (styleold) {
$target.attr("style",styleold);
$target.removeAttr("styleold");
$target.appendTo(".mdui-id-"+$target.attr("id"));
} else {
$target.parent().addClass("mdui-id-"+$target.attr("id"));
$target.attr("styleold",$target.attr("style"));
$target.attr("style","position:fixed; left:0; top:0; width:100%; height:100%; z-index: 2147483647 !important;background:#212121 !important; ");
$target.appendTo( "body" );
//$target.appendTo( "body #vis_container" );
}
}
// ele muss class Einträge für das Target und den Skalierungsmodus haben
// "mdui-target-(id) mdui-scale-(scalemode)"
// id: Ziel-Element mit id=id, welches ein zu skalierendes img enthält
// scalemode: fit / hfit / vfit / in / out / (number)
// number: Zahl in %
function _scale( ele ) {
var id = _getTargetID( ele );
var $img = $( "#"+id+" img" );
if ($img) {
var scale = _getClassSuffix(ele, "mdui-scale-" );
$img.width("1px"); // Scrollbars entfernen um die echte Höhe zu bekommen
$img.height("1px");
var dim = {
pw : $img.parent().width(),
ph : $img.parent().height(),
w : $img[0].naturalWidth,
h : $img[0].naturalHeight
};
switch(scale) {
case "fit":
if (dim.pw / dim.w < dim.ph / dim.h ) scale = dim.pw / dim.w;
else scale = dim.ph / dim.h;
break;
case "hfit":
if (dim.pw / dim.w < dim.ph / dim.h ) scale = dim.pw / dim.w;
else scale = (dim.pw - _getScrollbarWidth() - 4 ) / dim.w;
break;
case "vfit":
if ( dim.pw / dim.w > dim.ph / dim.h ) scale = dim.ph / dim.h;
else scale = (dim.ph - _getScrollbarHeight() - 4 ) / dim.h;
break;
case "in":
case "out":
var old = $img.attr( "style" );
old = old.substr(old.indexOf("scale(")+6,20);
old = old.substr(0,old.indexOf(")"));
if (old * 1==0) scale = 1;
else if (scale=="in") scale = old * 1.41;
else scale = old / 1.41;
break;
default:
if (scale<=0 || scale>10000)
scale = 100;
scale = scale/100;
}
scale = Math.round(scale*100)/100;
$img.attr( "style", "position:absolute;top:0;left:0;transform-origin:0 0;transition: transform 0.3s ease-out; transform:scale("+scale+");" );
}
}
// ersetzt im src-Attribute des Unter-Elements von (id) den "&range=&
// durch den Wert des in ele angegebenen (span). Für flot-Diagramme
// "mdui-target-(id) mdui-timespan-(span)"
// id: Ziel-Element mit id=id, welches das flot (src) enthält
// span: inc / dec / (number)
// number: Zahl in Minuten
function _timespan( ele ) {
var id = _getTargetID( ele );
var target = $( "#"+id+" [src]" );
if (target) {
var timespan = _getClassSuffix(ele, "mdui-timespan-" );
var src = target.attr( "src" );
var min = src.substr(src.indexOf("&range=")+7,20);
min = min.substr(0,min.indexOf("&"));
switch(timespan) {
case "inc":
min = min * 2;
break;
case "dec":
min = min / 2;
break;
default:
if ( timespan<=0 )
timespan = 1440;
min = timespan;
}
src = src.replace(/&range=[0-9]*&/g, "&range="+min+"&");
target.attr("src",src);
}
}
/* */
function _resetTable( $ele, $table ) {
$ele.removeClass("mdui-table-tile");
$ele.removeClass("mdui-table-card");
$ele.removeClass("mdui-table-list");
$table.find("tbody>tr").each( function(index) {
$(this).width("auto");
$(this).height("auto");
$(this).find("td").each( function(index) {
$(this).attr("labelth","");
});
});
}
/* */
function _handleTable( $ele, $table, opt ) {
function setColWidth( colwidth ) {
$table.find("tbody>tr").each( function(index) {
$(this).outerWidth(colwidth);
});
}
function setColHeight() {
var height = 0;
$table.find("tbody>tr").each( function(index) {
if ($(this).height() > height ) height = $(this).height();
});
if ( height > 0 )
$table.find("tbody>tr").each( function(index) {
$(this).height( height );
});
}
var innerWidth = $ele.innerWidth();
_resetTable($ele, $table);
$ele.addClass("mdui-table-"+opt.type);
if (opt.label) {
// Zellen mit Labels aus <th> ergänzen ?
var labels = [];
$table.find("thead>tr>th").each( function(index) {
labels[index] = $(this).text();
});
$table.find("tbody>tr").each( function(index) {
$(this).find("td").each( function(index) {
if (index < labels.length)
$(this).attr("labelth",labels[index]);
});
});
}
if (opt.colwidth>1) setColWidth(opt.colwidth);
if (opt.colwidth>2) setColHeight();
return true;
}
/* Alle mdui-table durchlaufen und überprüfen, ob die minimale Width erreicht
wurde um sie in den responsive State zu überführen
mdui-table-(mode)(-opt1)(-opt2)...(-optn)
mdui-table-ascard-r600-w200-l */
function _handleTables( ) {
$("[class*='mdui-table ']").each( function (index) {
var $ele = $(this);
var $table;
$table = $ele;
if (!$table.is("table")) $table=$table.find("table");
if (!$table.is("table")) return true; // next each
var innerWidth = $ele.innerWidth();
var classes = $ele.attr("class")
.split(" ")
.filter( function ( ele ) {
return (ele.indexOf("mdui-table-ascard") > -1)
|| (ele.indexOf("mdui-table-astile") > -1)
|| (ele.indexOf("mdui-table-aslist") > -1); });
var opts = [];
var opt;
for (var i = 0; i < classes.length; i++) {
opts[i] = [];
opts[i].reswidth = 9999;
opts[i].colwidth = 0;
opts[i].label = false;
opts[i].type = classes[i].substr(13,4);
opt = classes[i].substr(18,200).split("-");
for (var j = 0; j < opt.length; j++) {
switch(opt[j][0]) {
case "r":
opts[i].reswidth = parseInt(opt[j].substr(1,5));
break;
case "w":
opts[i].colwidth = parseInt(opt[j].substr(1,5));
break;
case "c":
opts[i].colwidth = parseInt(opt[j].substr(1,5));
if (opts[i].colwidth>0) opts[i].colwidth = (innerWidth-_getScrollbarWidth()-8) / opts[i].colwidth;
break;
case "l":
opts[i].label = true;
break;
default:
}
}
}
opts.sort(function(a, b){return a.reswidth-b.reswidth});
//console.log(opts);
if (opts.length === 0) return true; // next each
var handled = false;
for (i = 0; i < opts.length; i++) {
if ( innerWidth < opts[i].reswidth )
handled = _handleTable( $ele, $table, opts[i]);
if (handled) break;
}
if (!handled) _resetTable($ele, $table);
});
}
// DOM SubTree-Änderungen einmalig alle 500ms auswerten (diese Events werden
// u.U. 1000-fach gefeuert und müssen deswegen verzögert ausgeführt werden)
function _onSubTreeModified( $ele ) {
if (!isSubtreeModified) {
isSubtreeModified = true;
setTimeout(function () {
_handleTables();
isSubtreeModified=false;
}, 500);
}
}
return {
toggleVisibility: _toggleVisibility,
toggleFullscreen: _toggleFullscreen,
scale: _scale,
timespan: _timespan,
handleTables: _handleTables,
onSubTreeModified : _onSubTreeModified
};
})();
// Eventhandler für body-Delegators setzen (früher:#vis_container)
setTimeout(function () {
// click-Event für das left-nav Element zum Öffnen
$("body").on( "click", ".mdui-lnavbutton", function() {
$( ".mdui-lnav" ).addClass( "mdui-lnav-open" );
} );
// click-Event für die left-nav zum Schließen
$("body").on( "click", ".mdui-lnav", function() {
$( ".mdui-lnav" ).removeClass( "mdui-lnav-open" );
} );
// click-Event für das right-nav Element zum Öffnen
$("body").on( "click", ".mdui-rnavbutton", function() {
$( ".mdui-rnav" ).addClass( "mdui-rnav-open" );
} );
// click-Event für die right-nav zum Schließen
$("body").on( "click", ".mdui-rnav", function() {
$( ".mdui-rnav" ).removeClass( "mdui-rnav-open" );
} );
// click-Eventhandler für "mdui-scale-" setzen
$("body").on( "click", "[class*='mdui-scale-']", function(event) {
MDUI.scale( $(this) );
} );
// click-Handler für "mdui-toggle"
$("body").on( "click", ".mdui-toggle", function(event) {
event.preventDefault();
event.stopImmediatePropagation();
MDUI.toggleVisibility( $(this) );
} );
// click-Handler für "mdui-fullscreen"
$("body").on( "click", ".mdui-fullscreen", function(event) {
MDUI.toggleFullscreen( $(this) );
} );
// click-Handler für "mdui-timepsan-"
$("body").on( "click", "[class*='mdui-timespan-']", function(event) {
MDUI.timespan( $(this) );
} );
$( window ).on("resize", function() {
MDUI.handleTables();
});
// Überwachen des #vis_containers auf Änderungen (z.B. wenn views nachgeladen
// werden)
$( "#vis_container" ).on( "DOMSubtreeModified", function(event) {
MDUI.onSubTreeModified( $(this) );
} );
// für den ersten load einmal aufrufen
MDUI.onSubTreeModified( );
}, 1000);