Commit ca75628c authored by nextime's avatar nextime

Whoa! new clima GUI

parent 2d56e6da
......@@ -128,3 +128,5 @@ CREATE TABLE IF NOT EXISTS `ioconf_pwm` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
ALTER TABLE `user_gui_panels` CHANGE `panel_type` `panel_type` ENUM( 'standard', 'gauge', 'thermostat', 'graph', 'macrobuttons', 'bookmarks', 'cameras', 'video', 'gxv3175_left', 'gxv3175_center', 'gxv3175_right' ) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'standard';
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -591,6 +591,94 @@ input::-webkit-input-speech-button {
body.theme-dmblack {
color: #fff;
-webkit-touch-callout:none;
-webkit-user-select:none;
-khtml-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
-webkit-tap-highlight-color:rgba(0,0,0,0);
}
.thermo-program-block {
/* display:inline-block; */
float:left;
width:50%;
min-width: 211px;
}
.thermo-program-pane[max-width~="422px"] .thermo-program-block {
width:100%;
}
.thermo-program-container {
/* display:inline-block; */
width:8.33%;
min-width: 14px;
float:left;
}
.thermo-program-subcont {
display:inline-block;
}
.thermo-program-show {
display:block;
font-size: 10px;
max-width: 13px;
overflow: visible;
transform:rotate(-90deg);
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
transform-origin: 50% 50%;
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-o-transform-origin: 50% 50%;
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
}
/*
.thermo-program-show:hover {
font-size: 24px;
}
*/
.btn-noUI {
padding: 0;
line-height:1;
margin-top: 10px;
margin-bottom:10px;
width:10px;
height:16px;
}
.noUi-connect {
background: #428bca !important;
}
.noUI-thermo-program {
height:100px !important;
width:3px !important;
margin-left:5px !important;
margin-right:5px !important;
}
.noUI-thermo-program .noUi-base > .noUi-origin > .noUi-handle {
height: 14px;
top:-8px;
left:-7px;
width: 14px;
border-radius:8px;
background: #428bca;
border-color: #428bff;
}
.noUI-thermo-program .noUi-base > .noUi-origin > .noUi-handle:after,
.noUI-thermo-program .noUi-base > .noUi-origin > .noUi-handle:before {
display:none;
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -408,13 +408,11 @@
$('#speech').bind('webkitspeechchange',function(event) {
event.preventDefault();
console.debug("AAAA");
sendSpeech($("#speech"));
});
$('#speechsm').bind('webkitspeechchange',function(event) {
event.preventDefault();
console.debug("BBBBB");
sendSpeech($("#speechsm"));
});
......@@ -422,8 +420,6 @@
var keycode = (event.keyCode ? event.keyCode : event.which);
if(keycode == 13) {
event.preventDefault();
console.debug("CCCC");
console.debug($("#speech"));
sendSpeech($("#speech"));
}
});
......@@ -462,7 +458,6 @@
lo: $(this).attr('data-dmval-high')/$(this).attr('data-dmval-divider'),
hi: $(this).attr('data-dmval-max')/$(this).attr('data-dmval-divider')}
];
console.debug(customS);
} else {
var customS=false;
var levelC=new Array(
......@@ -483,13 +478,15 @@
labelFontColor: "#999999",
label: $(this).attr('data-domotika-label'),
customSectors: customS,
shadowSize: 10,
showinnerShadow: true,
shadowOpacity: 1
});
gaugeArray[$(this).attr('id')].refresh($(this).attr('data-dmval')/$(this).attr('data-dmval-divider'));
$(this).data('gauge', gaugeArray[$(this).attr('id')]);
}
);
var es = new EventSource("/sse");
var syncReceived = function(event) {
......
<? @include_once("../includes/common.php"); ?>
<div class="left-drawer">
<div id="websectionlist" class="panel drawer-container scrollable">
<a href="<?=$BASEGUIPATH."/cameras"?>" data-guisubsection='' class="btn btn-block btn-default">Clima Home</a>
<a href="<?=$BASEGUIPATH."/clima"?>" data-guisubsection='' class="btn btn-block btn-default">Clima Home</a>
<?
$v=DB::query("SELECT id,name FROM thermostats WHERE active=1");
$v=DB::query("SELECT id,name,button_name FROM thermostats WHERE active='yes'");
$links=array();
foreach($v as $the)
{
$links[$the['name']]=$the['id'];
$links[$the['name']]=$the['button_name'];
}
ksort($links, SORT_NATURAL | SORT_FLAG_CASE);
foreach($links as $k => $v)
{
?>
<a href="<?=$BASEGUIPATH."/clima/".$k?>" data-guisubsection='<?=$v?>' class="btn btn-block btn-default"><?=str_replace(".", " ", $k)?></a>
<a href="<?=$BASEGUIPATH."/clima/".$k?>" data-guisubsection='<?=$k?>' class="btn btn-block btn-default"><?=$v?></a>
<?
}
?>
......
......@@ -28,6 +28,8 @@ js/starthammer.js
../../resources/EventSource/eventsource.js
../../resources/js/jquery.easing.1.3.min.js
../../resources/js/jquery.alterclass.js
../../resources/js/jquery.continouoshold.js
../../resources/js/jquery.mousewheel.js
../../resources/noUiSlider/jquery.nouislider.js
../../resources/js/jqplot/jquery.jqplot.min.js
../../resources/js/jqplot/plugins/jqplot.dateAxisRenderer.min.js
......@@ -37,6 +39,8 @@ js/starthammer.js
../../resources/js/jqplot/plugins/jqplot.canvasAxisTickRenderer.min.js
../../resources/js/raphael.min.js
../../resources/js/justgage.js
../../resources/js/ResizeSensor.js
../../resources/css-element-queries/src/ElementQueries.js
js/fastclick.js
js/speech.js
js/domotika.js
......
......@@ -23,14 +23,14 @@ if($GUISUBSECTION=="")
'panel_websections'=>'clima','panel_cols'=>4, 'panel_height'=>'100%')+$PANELDEFAULTS+$paneldimensions;
} else {
$thermostats=DB::query("SELECT * from thermostats WHERE name=%s", $GUISUBSECTION);
$thermostats=DB::query("SELECT * from thermostats WHERE name=%s AND active='yes'", $GUISUBSECTION);
foreach($thermostats as $t)
{
$ptype='standard';
$pname=str_replace(".", " ", $t['name']);
if($t['sensor_type']=='analog') $ptype='gauge';
$panels[]=array('panel_title'=>$pname,'panel_sections'=>$t['sensor_type'], 'panel_websections'=>'clima',
'panel_type'=>$ptype, 'panel_content'=>$t['sensor_domain'],'panel_cols'=>4, 'panel_height'=>'50%')+$PANELDEFAULTS;
$panels[]=array('panel_title'=>$t['button_name'],'panel_sections'=>$t['sensor_type'], 'panel_websections'=>'clima',
'panel_type'=>'thermostat', 'panel_content'=>$t['sensor_domain'],'panel_cols'=>5, 'panel_height'=>'80%')+$PANELDEFAULTS;
$panels[]=array('panel_title'=>'programmazione '.$t['button_name'],'panel_sections'=>$t['sensor_type'], 'panel_websections'=>'clima',
'panel_type'=>'thermostat_program', 'panel_content'=>$t['name'],'panel_cols'=>5, 'panel_height'=>'80%')+$PANELDEFAULTS;
}
}
include($FSPATH."/panels/include.php");
......
......@@ -9,6 +9,8 @@ if($panel && is_array($panel)) {
if(count($buttonar)<=0) {
$visible.=" hidden-xs hidden-sm";
}
if(!array_key_exists('id', $panel))
$panel['id']=mt_rand();
?>
<div class="panel panel-theme-<?=$_DOMOTIKA['gui_theme']?> col-lg-<?=$panel['panel_cols']?> panel-media-low <?=$visible?>" style="height:<?=$panel['panel_height'];?>;">
<?
......@@ -40,8 +42,8 @@ if($panel && is_array($panel)) {
<?
foreach($buttonar as $button) {
if($button['devtype']=='analog') {
//$_SESSION['PANELS_CHARTS'][$chart['name']."-".$panel['id']]=$chart;
?>
<div style="width:100%;">
<div id="gauge-<?=$button['id']."-".$panel['id']?>" data-domotika-type="gauge"
data-dmval-min="<?=floatval($button['minval'])?>"
data-dmval-max="<?=floatval($button['maxval'])?>"
......@@ -55,7 +57,9 @@ if($panel && is_array($panel)) {
data-domotika-name="<?=$button['button_name']?>"
data-dmval="<?=floatval($button['status'])?>"
data-domotika-label="<?=$button['unit']?>"
data-domotika-gaugeid="<?=$button['id']?>" style="height:200px;width:550px"></div>
data-domotika-gaugeid="<?=$button['id']?>" style="height:200px;width:250px;margin:0 auto;text-align: center;">
</div>
</div>
<?
}
}?>
......
<? @include_once("../../includes/common.php"); ?>
<?
if($panel && is_array($panel)) {
$buttonar=getPanelButtons($_DOMOTIKA['username'],$panel['panel_content'],$panel['panel_sections'],$panel['panel_websections'],$panel['panel_selector'],true);
$climastatus=DB::queryOneField("value", "SELECT * FROM uniques WHERE name='climastatus'");
if(!$climastatus) {
DB::insert('uniques', array('name'=>'climastatus','value'=>'WINTER'));
$climastatus='WINTER';
}
$climastatuses=DB::query("SELECT DISTINCT(clima_status) FROM thermostats_progs group by clima_status");
if(is_numeric($panel['panel_height'])) $panel['panel_height'].="px";
$visible="";
if($panel['panel_visible']!="all") $visible=$panel['panel_visible'];
if(count($buttonar)<=0) {
$visible.=" hidden-xs hidden-sm";
}
if(!array_key_exists('id', $panel))
$panel['id']=mt_rand();
?>
<div class="panel panel-theme-<?=$_DOMOTIKA['gui_theme']?> col-lg-<?=$panel['panel_cols']?> panel-media-low <?=$visible?>" style="height:<?=$panel['panel_height'];?>;">
<?
if($panel['panel_title']!="") {
?>
<div class="panel-heading panel-head-theme-<?=$_DOMOTIKA['gui_theme']?>"><h2 class="panel-title"><?=$panel['panel_title']?></h2></div>
<?
}
$height="";
$dmfull="";
if($panel['panel_height']!="" && intval($panel['panel_height'])>0) {
$height="style=\"height:".$panel['panel_height']."\"";
$dmheight="style=\"height:".strval(intval($panel['panel_height'])-70)."px\"";
if(endsWith($panel['panel_height'], '%')) {
$dmfull="domotika-panel-full";
$dmheight="style=\"height:100%;\"";
}
}
elseif($panel['panel_height']!="" && intval($panel['panel_height'])==0) {
$height="style=\"height:100%;\"";
$dmfull="domotika-panel-full";
$dmheight="style=\"height:100%;\"";
}
?>
<div class="domotika-panel <?=$dmfull;?>" <?=$dmheight;?>>
<div class="home-panel" <?=$dmheight;?>>
<div class="list-group theme-<?=$_DOMOTIKA['gui_theme']?>">
<?
foreach($buttonar as $button) {
if($button['devtype']=='analog') {
//$_SESSION['PANELS_CHARTS'][$chart['name']."-".$panel['id']]=$chart;
?>
<div style="width:100%;margin:0 auto;text-align:center;" class="devlist-item devlist-item-theme-<?=$_DOMOTIKA['gui_theme']?>">
<div>
<button type="button" data-domotika-type="btn-choosestatuses"
id="thermo-btnchoosestatus-<?=$button['id']."-".$panel['id']?>"
class="btn btn-primary" style="width:150px;height:40px;"><b><?=$climastatus?></b>
<i class="glyphicon glyphicon-chevron-down"></i>
</button>
</div>
<div id="thermo-statuschooselist-<?=$button['id']."-".$panel['id']?>"
class="panel panel-theme-<?=$_DOMOTIKA['gui_theme']?> thermo-statuspanel text-on-white-theme-<?=$_DOMOTIKA['gui_theme']?>">
<div class="notifylist">
<div class="list-group theme-<?=$_DOMOTIKA['gui_theme']?>" data-snap-ignore="true">
<? foreach($climastatuses as $cs) { if($cs['clima_status']!=$climastatus) { ?>
<button type="button" style="width:100%;margin-top:5px;"
data-domotika-statusselect="<?=$cs['clima_status']?>"
data-domotika-type="statuschoose"
data-domotika-panel="thermo-statuschooselist-<?=$button['id']."-".$panel['id']?>"
class="btn btn-success"><?=$cs['clima_status']?></button>
<? }} ?>
</div>
</div>
</div>
<div style="display:inline-block;margin:0 auto;text-align:center;">
<div id="gauge-<?=$button['id']."-".$panel['id']?>" data-domotika-type="gauge"
data-dmval-min="<?=floatval($button['minval'])?>"
data-dmval-max="<?=floatval($button['maxval'])?>"
data-dmval-low="<?=floatval($button['lowval'])?>"
data-dmval-high="<?=floatval($button['highval'])?>"
data-dmval-divider="<?=floatval($button['divider'])?>"
data-dmcolor-min="<?=$button['color_min']?>"
data-dmcolor-low="<?=$button['color_low']?>"
data-dmcolor-medium="<?=$button['color_medium']?>"
data-dmcolor-high="<?=$button['color_high']?>"
data-domotika-name="<?=$button['button_name']?>"
data-dmval="<?=floatval($button['status'])?>"
data-domotika-label="<?=$button['unit']?>"
data-domotika-gaugeid="<?=$button['id']?>" style="height:250px;min-width:240px;margin:0 auto;text-align:center;">
</div>
</div>
<div style="display:inline-block;width:20%;min-width:68px;height:250px;margin:0 auto;text-align:center;">
<div><button type="button" id="thermo-showset-<?=$button['id']."-".$panel['id']?>" class="btn btn-gray">--.-</button></div>
<div style="margin:0 auto;text-align:center;height:150px;margin-top:25px;margin-bottom:25px;"
id="thermo-level-<?=$button['id']."-".$panel['id']?>" data-domotika-type="thermo-level">
</div>
<div class="btn-group">
<button type="button" class="btn btn-primary btn-small"><i class="glyphicon glyphicon-chevron-down"></i></button>
<button type="button" class="btn btn-danger btn-small"><i class="glyphicon glyphicon-chevron-up"></i></button>
</div>
</div>
<div style="margin-top:45px;">
<button type="button" class="btn btn-gray " style="width:150px;height:40px;"><b>Manual</b></button>
<button type="button" class="btn btn-primary " style="width:150px;height:40px;"><b>Program</b></button>
</div>
</div>
<?
}
}?>
</div>
</div>
</div>
</div>
<?}?>
This diff is collapsed.
<? @include_once("../../includes/common.php"); ?>
<script>
$("[data-domotika-type=thermo-level]").each(
function(){
$(this).noUiSlider({
range: [-10, 50],
start: 20,
handles: 1,
connect: 'lower',
orientation: 'vertical',
direction: 'rtl',
step:0.1,
slide: function() {
var parts=$(this).attr('id').split("-");
$("#thermo-showset-"+parts[2]+'-'+parts[3]).text(parseFloat($(this).val()).toFixed(1));
},
});
var parts=$(this).attr('id').split('-');
var btn=$("#thermo-showset-"+parts[2]+'-'+parts[3]);
btn.text(parseFloat($(this).val()).toFixed(1));
$(this).mousewheel(function(event) {
if(event.deltaY>0)
$(this).val(parseFloat($(this).val())+0.5);
else if(event.deltaY<0)
$(this).val(parseFloat($(this).val())-0.5);
if(event.deltaY!=0)
{
$('#'+$(this).attr('id').replace('thermo-level-','thermo-showset-')).text(parseFloat($(this).val()).toFixed(1));
}
});
}
);
$("[data-domotika-type=btn-choosestatuses]").each(
function() {
$(this).fastClick(function(){
var parts=$(this).attr('id').split("-");
var panel="#thermo-statuschooselist-"+parts[2]+"-"+parts[3];
if($(panel).css('display')=='block')
{
$(panel).hide(150);
} else {
$(panel).show(300);
}
});
}
);
$("[data-domotika-type=statusselect]").each(
function(){
$(this).fastClick(function(){
var panel="#"+$(this).attr('data-domotika-panel');
$(panel).hide(150);
});
}
);
</script>
<? @include_once("../../includes/common.php"); ?>
<script>
$("[data-domotika-type=thermoprogram]").each(
function(){
$(this).noUiSlider({
range: [parseFloat($(this).attr('data-domotika-thermo-minslide')), parseFloat($(this).attr('data-domotika-thermo-maxslide'))],
start: $(this).attr('data-domotika-thermo-startvalue'),
handles: 1,
direction: 'rtl',
step:0.1,
orientation: 'vertical',
slide: function() {
var parts=$(this).attr('id').split("-");
$('#thermo-reset-'+parts[2]+'-'+parts[3]).removeAttr('disabled');
$('#thermo-save-'+parts[2]+'-'+parts[3]).removeAttr('disabled');
$('#'+$(this).attr('id').replace('thermo-levels-','thermo-values-')).text(parseFloat($(this).val()).toFixed(1));
},
});
$(this).mousewheel(function(event) {
if(event.deltaY>0)
$(this).val(parseFloat($(this).val())+0.5);
else if(event.deltaY<0)
$(this).val(parseFloat($(this).val())-0.5);
if(event.deltaY!=0)
{
$('#'+$(this).attr('id').replace('thermo-levels-','thermo-values-')).text(parseFloat($(this).val()).toFixed(1));
var parts=$(this).attr('id').split("-");
$('#thermo-reset-'+parts[2]+'-'+parts[3]).removeAttr('disabled');
$('#thermo-save-'+parts[2]+'-'+parts[3]).removeAttr('disabled');
}
});
var plus=$('#'+$(this).attr('id').replace('thermo-levels-','thermo-plus-'));
var minus=$('#'+$(this).attr('id').replace('thermo-levels-','thermo-minus-'));
minus.continouoshold(function(){
var slide=$('#'+$(this).attr('id').replace('thermo-minus-','thermo-levels-'));
slide.val(parseFloat(slide.val())-0.5);
$('#'+$(this).attr('id').replace('thermo-minus-','thermo-values-')).text(parseFloat(slide.val()).toFixed(1));
var parts=$(this).attr('id').split("-");
$('#thermo-reset-'+parts[2]+'-'+parts[3]).removeAttr('disabled');
$('#thermo-save-'+parts[2]+'-'+parts[3]).removeAttr('disabled');
}, 200, 1000, true);
plus.continouoshold(function(){
var slide=$('#'+$(this).attr('id').replace('thermo-plus-','thermo-levels-'));
slide.val(parseFloat(slide.val())+0.5);
$('#'+$(this).attr('id').replace('thermo-plus-','thermo-values-')).text(parseFloat(slide.val()).toFixed(1));
var parts=$(this).attr('id').split("-");
$('#thermo-reset-'+parts[2]+'-'+parts[3]).removeAttr('disabled');
$('#thermo-save-'+parts[2]+'-'+parts[3]).removeAttr('disabled');
}, 200, 1000, true);
}
);
$("[data-domotika-type=btn-statuses]").each(
function() {
$(this).fastClick(function(){
var parts=$(this).attr('id').split("-");
var panel="#thermo-statuslist-"+parts[2]+"-"+parts[3];
if($(panel).css('display')=='block')
{
$(panel).hide(150);
} else {
$(panel).show(300);
}
});
}
);
$("[data-domotika-type=statuschoose]").each(
function(){
$(this).fastClick(function(){
var panel="#"+$(this).attr('data-domotika-panel');
$(panel).hide(150);
});
}
);
$("[data-domotika-type=thermo-save]").each(
function(){
$(this).on('click', function(){
var parts=$(this).attr('id').split("-");
$(this).prop('disabled', true);
$('#thermo-reset-'+parts[2]+'-'+parts[3]).prop('disabled', true);
});
}
);
$("[data-domotika-type=thermo-reset]").each(
function(){
$(this).on('click', function(){
var parts=$(this).attr('id').split("-");
$(this).prop('disabled', true);
$('#thermo-save-'+parts[2]+'-'+parts[3]).prop('disabled', true);
});
}
);
$('a[data-toggle="tab"]').on('shown.bs.tab',function(){
$(window).trigger('resize');
});
$(function () {
$('.thermotab a:first').tab('show');
});
</script>
......@@ -24,6 +24,8 @@
<!-- jquery easing plugin -->
<script src="/resources/js/jquery.easing.1.3.min.js"></script>
<script src="/resources/js/jquery.alterclass.js"></script>
<script src="/resources/js/jquery.continouoshold.js"></script>
<script src="/resources/js/jquery.mousewheel.js"></script>
<!-- jqplot -->
<script src="/resources/js/jqplot/jquery.jqplot.min.js" ></script>
<script type="text/javascript" src="/resources/js/jqplot/plugins/jqplot.dateAxisRenderer.min.js"></script>
......@@ -31,6 +33,10 @@
<script type="text/javascript" src="/resources/js/jqplot/plugins/jqplot.cursor.min.js"></script>
<script type="text/javascript" src="/resources/js/jqplot/plugins/jqplot.canvasTextRenderer.min.js"></script>
<script type="text/javascript" src="/resources/js/jqplot/plugins/jqplot.canvasAxisTickRenderer.min.js"></script>
<!-- <script type="text/javascript" src="/resources/js/jqplot/plugins/jqplot.categoryAxisRenderer.min.js"></script>
<script type="text/javascript" src="/resources/js/jqplot/plugins/jqplot.barRenderer.min.js"></script> -->
<script type="text/javascript" src="/resources/js/ResizeSensor.js"></script>
<script type="text/javascript" src="/resources/css-element-queries/src/ElementQueries.js"></script>
<script type="text/javascript" src="/resources/js/raphael.min.js"></script>
<script type="text/javascript" src="/resources/js/justgage.js"></script>
<script type="text/javascript" src="/resources/noUiSlider/jquery.nouislider.js"></script>
......
......@@ -27,7 +27,10 @@ if($_DOMOTIKA['gui_theme']=='dmblack')
<div id="notifypanel" class="panel panel-theme-<?=$_DOMOTIKA['gui_theme']?> notifypanel text-on-white-theme-<?=$_DOMOTIKA['gui_theme']?>">
<div class="panel-heading panel-head-theme-<?=$_DOMOTIKA['gui_theme']?>"><h4>Notifications<i class="glyphicon glyphicon-remove pull-right" id="notify-removeall"></i></h4></div>
<div class="notifylist">
<div id="notifications" class="list-group theme-<?=$_DOMOTIKA['gui_theme']?>" data-snap-ignore="true">
<div class="list-group theme-<?=$_DOMOTIKA['gui_theme']?>" data-snap-ignore="true">
<div class="list-group-item">
AAAA
</div>
</div>
</div>
</div>
......
CSS Element Queries
===================
Element Queries is a polyfill adding support for element based media-queries to all new browsers (incl. IE8+).
It allows not only to define media-queries based on window-size but also adds 'media-queries' functionality depending on element (any selector supported)
size while not causing performance lags due to event based implementation.
It's a proof-of-concept event-based CSS element dimension query with valid CSS selector syntax.
Features:
- no performance issues
- no interval/timeout detection. Truly event-based
- no CSS modifications. Valid CSS Syntax
- all CSS selectors available. Uses regular attribute selector
- supports and tested in webkit, gecko and IE(8/9/10).
- `min-width`, `min-height`, `max-width` and `max-height` are supported so far
- works with any layout modifications: HTML (innerHTML etc), inline styles, DOM mutation, CSS3 transitions, fluid layout changes (also percent changes), pseudo classes (:hover etc.), window resizes and more
- no Javascript-Framework dependency (works with jQuery, Mootools, etc.)
More demos and information: http://marcj.github.io/css-element-queries/
Example
-------
```css
.widget-name {
padding: 25px;
}
.widget-name[max-width="200px"] {
padding: 0;
}
.widget-name[min-width="500px"] {
padding: 55px;
}
/* responsive images /*
.responsive-image img {
width: 100%;
}
.responsive-image[max-width^='400px'] img {
content: url(demo/image-400px.jpg);
}
.responsive-image[max-width^='1000px'] img {
content: url(demo/image-1000px.jpg);
}
.responsive-image[min-width='1000px'] img {
content: url(demo/image-full.jpg);
}
```
Include the javascript files at the bottom and you're good to go. No custom javascript calls needed.
```html
<script src="src/ResizeSensor.js"></script>
<script src="src/ElementQueries.js"></script>
```
Issues
------
- So far does not work on `img` tags. Wrapping with a `div` works fine though (See demo).
- [only non-IE]: Adds additional hidden element into selected target element and forces target element to be relative or absolute.
Event-Based resize detection inspired by [backalleycoder.com](http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/) <3
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/marcj/css-element-queries/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
;
(function() {
/**
*
* @type {Function}
* @constructor
*/
var ElementQueries = this.ElementQueries = function() {
/**
*
* @param element
* @returns {Number}
*/
function getEmSize(element) {
if (!element) {
element = document.documentElement;
}
var fontSize = getComputedStyle(element, 'fontSize');
return parseFloat(fontSize) || 16;
}
/**
*
* @copyright https://github.com/Mr0grog/element-query
*
* @param element
* @param value
* @param units
* @returns {*}
*/
function convertToPx(element, value) {
var units = value.replace(/[0-9]*/, '');
value = parseFloat(value);
switch (units) {
case "px":
return value;
case "em":
return value * getEmSize(element);
case "rem":
return value * getEmSize();
// Viewport units!
// According to http://quirksmode.org/mobile/tableViewport.html
// documentElement.clientWidth/Height gets us the most reliable info
case "vw":
return value * document.documentElement.clientWidth / 100;
case "vh":
return value * document.documentElement.clientHeight / 100;
case "vmin":
case "vmax":
var vw = document.documentElement.clientWidth / 100;
var vh = document.documentElement.clientHeight / 100;
var chooser = Math[units === "vmin" ? "min" : "max"];
return value * chooser(vw, vh);
default:
return value;
// for now, not supporting physical units (since they are just a set number of px)
// or ex/ch (getting accurate measurements is hard)
}
}
/**
*
* @param {HTMLElement} element
* @constructor
*/
function SetupInformation(element) {
this.element = element;
this.options = [];
var i, j, option, width = 0, height = 0, value, actualValue, attrValues, attrValue, attrName;
/**
* @param option {mode: 'min|max', property: 'width|height', value: '123px'}
*/
this.addOption = function(option) {
this.options.push(option);
}
var attributes = ['min-width', 'min-height', 'max-width', 'max-height'];
/**
* Extracts the computed width/height and sets to min/max- attribute.
*/
this.call = function() {
// extract current dimensions
width = this.element.offsetWidth;
height = this.element.offsetHeight;
attrValues = {};
for (i = 0, j = this.options.length; i < j; i++) {
option = this.options[i];
value = convertToPx(this.element, option.value);
actualValue = option.property == 'width' ? width : height;
attrName = option.mode + '-' + option.property;
attrValue = '';
if (option.mode == 'min' && actualValue >= value) {
attrValue += option.value;
}
if (option.mode == 'max' && actualValue <= value) {
attrValue += option.value;
}
if (!attrValues[attrName]) attrValues[attrName] = '';
if (attrValue && -1 === (' '+attrValues[attrName]+' ').indexOf(' ' + attrValue + ' ')) {
attrValues[attrName] += ' ' + attrValue;
}
}
for (var k in attributes) {
if (attrValues[attributes[k]]) {
this.element.setAttribute(attributes[k], attrValues[attributes[k]].substr(1));
} else {
this.element.removeAttribute(attributes[k]);
}
}
};
}
/**
* @param {HTMLElement} element
* @param {Object} options
*/
function setupElement(element, options) {
if (element.elementQueriesSetupInformation) {
element.elementQueriesSetupInformation.addOption(options);
} else {
element.elementQueriesSetupInformation = new SetupInformation(element);
element.elementQueriesSetupInformation.addOption(options);
new ResizeSensor(element, function() {
element.elementQueriesSetupInformation.call();
});
}
element.elementQueriesSetupInformation.call();
}
/**
* @param {String} selector
* @param {String} mode min|max
* @param {String} property width|height
* @param {String} value
*/
function queueQuery(selector, mode, property, value) {
var query = document.querySelectorAll;
if ('undefined' !== typeof $$) query = $$;
if ('undefined' !== typeof jQuery) query = jQuery;
if (!query) {
throw 'No document.querySelectorAll, jQuery or Mootools\'s $$ found.';
}
var elements = query(selector);
for (var i = 0, j = elements.length; i < j; i++) {
setupElement(elements[i], {
mode: mode,
property: property,
value: value
});
}
}
var regex = /,?([^,\n]*)\[[\s\t]*(min|max)-(width|height)[\s\t]*[~$\^]?=[\s\t]*"([^"]*)"[\s\t]*]([^\n\s\{]*)/mgi;
/**
* @param {String} css
*/
function extractQuery(css) {
var match;
css = css.replace(/'/g, '"');
while (null !== (match = regex.exec(css))) {
if (5 < match.length) {
queueQuery(match[1] || match[5], match[2], match[3], match[4]);
}
}
}
/**
* @param {CssRule[]|String} rules
*/
function readRules(rules) {
var selector = '';
if (!rules) {
return;
}
if ('string' === typeof rules) {
rules = rules.toLowerCase();
if (-1 !== rules.indexOf('min-width') || -1 !== rules.indexOf('max-width')) {
extractQuery(rules);
}
} else {
for (var i = 0, j = rules.length; i < j; i++) {
if (1 === rules[i].type) {
selector = rules[i].selectorText || rules[i].cssText;
if (-1 !== selector.indexOf('min-width') || -1 !== selector.indexOf('max-width')) {
extractQuery(selector);
}
} else if (4 === rules[i].type) {
readRules(rules[i].cssRules || rules[i].rules);
}
}
}
}
/**
* Searches all css rules and setups the event listener to all elements with element query rules..
*/
this.init = function() {
for (var i = 0, j = document.styleSheets.length; i < j; i++) {
readRules(document.styleSheets[i].cssText || document.styleSheets[i].cssRules || document.styleSheets[i].rules);
}
}
}
function init() {
new ElementQueries().init();
}
if (window.addEventListener) {
window.addEventListener('load', init, false);
} else {
window.attachEvent('onload', init);
}
})();
;
(function() {
/**
* Class for dimension change detection.
*
* @param {Element|Element[]|Elements|jQuery} element
* @param {Function} callback
*
* @constructor
*/
this.ResizeSensor = function(element, callback) {
/**
* Adds a listener to the over/under-flow event.
*
* @param {HTMLElement} element
* @param {Function} callback
*/
function addResizeListener(element, callback) {
if (window.OverflowEvent) {
//webkit
element.addEventListener('overflowchanged', function(e) {
callback.call(this, e);
});
} else {
element.addEventListener('overflow', function(e) {
callback.call(this, e);
});
element.addEventListener('underflow', function(e) {
callback.call(this, e);
});
}
}
/**
*
* @constructor
*/
function EventQueue() {
this.q = [];
this.add = function(ev) {
this.q.push(ev);
};
var i, j;
this.call = function() {
for (i = 0, j = this.q.length; i < j; i++) {
this.q[i].call();
}
};
}
/**
* @param {HTMLElement} element
* @param {String} prop
* @returns {String|Number}
*/
function getComputedStyle(element, prop) {
if (element.currentStyle) {
return element.currentStyle[prop];
} else if (window.getComputedStyle) {
return window.getComputedStyle(element, null).getPropertyValue(prop);
} else {
return element.style[prop];
}
}
/**
*
* @param {HTMLElement} element
* @param {Function} resized
*/
function attachResizeEvent(element, resized) {
if (!element.resizedAttached) {
element.resizedAttached = new EventQueue();
element.resizedAttached.add(resized);
} else if (element.resizedAttached) {
element.resizedAttached.add(resized);
return;
}
if ('onresize' in element) {
//internet explorer
if (element.attachEvent) {
element.attachEvent('onresize', function() {
element.resizedAttached.call();
});
} else if (element.addEventListener) {
element.addEventListener('resize', function(){
element.resizedAttached.call();
});
}
} else {
var myResized = function() {
if (setupSensor()) {
element.resizedAttached.call();
}
};
element.resizeSensor = document.createElement('div');
element.resizeSensor.className = 'resize-sensor';
var style =
'position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: -1;';
element.resizeSensor.style.cssText = style;
element.resizeSensor.innerHTML =
'<div class="resize-sensor-overflow" style="' + style + '">' +
'<div></div>' +
'</div>' +
'<div class="resize-sensor-underflow" style="' + style + '">' +
'<div></div>' +
'</div>';
element.appendChild(element.resizeSensor);
if ('absolute' !== getComputedStyle(element, 'position')) {
element.style.position = 'relative';
}
var x = -1,
y = -1,
firstStyle = element.resizeSensor.firstElementChild.firstChild.style,
lastStyle = element.resizeSensor.lastElementChild.firstChild.style;
function setupSensor() {
var change = false,
width = element.resizeSensor.offsetWidth,
height = element.resizeSensor.offsetHeight;
if (x != width) {
firstStyle.width = (width - 1) + 'px';
lastStyle.width = (width + 1) + 'px';
change = true;
x = width;
}
if (y != height) {
firstStyle.height = (height - 1) + 'px';
lastStyle.height = (height + 1) + 'px';
change = true;
y = height;
}
return change;
}
setupSensor();
addResizeListener(element.resizeSensor, myResized);
addResizeListener(element.resizeSensor.firstElementChild, myResized);
addResizeListener(element.resizeSensor.lastElementChild, myResized);
}
}
if ('array' === typeof element
|| ('undefined' !== typeof jQuery && element instanceof jQuery) //jquery
|| ('undefined' !== typeof Elements && element instanceof Elements) //mootools
) {
var i = 0, j = element.length;
for (; i < j; i++) {
attachResizeEvent(element[i], callback);
}
} else {
attachResizeEvent(element, callback);
}
}
})();
;
(function() {
/**
* Class for dimension change detection.
*
* @param {Element|Element[]|Elements|jQuery} element
* @param {Function} callback
*
* @constructor
*/
this.ResizeSensor = function(element, callback) {
/**
*
* @constructor
*/
function EventQueue() {
this.q = [];
this.add = function(ev) {
this.q.push(ev);
};
var i, j;
this.call = function() {
for (i = 0, j = this.q.length; i < j; i++) {
this.q[i].call();
}
};
}
/**
* @param {HTMLElement} element
* @param {String} prop
* @returns {String|Number}
*/
function getComputedStyle(element, prop) {
if (element.currentStyle) {
return element.currentStyle[prop];
} else if (window.getComputedStyle) {
return window.getComputedStyle(element, null).getPropertyValue(prop);
} else {
return element.style[prop];
}
}
/**
*
* @param {HTMLElement} element
* @param {Function} resized
*/
function attachResizeEvent(element, resized) {
if (!element.resizedAttached) {
element.resizedAttached = new EventQueue();
element.resizedAttached.add(resized);
} else if (element.resizedAttached) {
element.resizedAttached.add(resized);
return;
}
$(window).bind('resize', function(){
$(element).trigger('jQueryResizeSensorEvent');
});
$(element).bind('jQueryResizeSensorEvent', function() {
element.resizedAttached.call();
});
}
if ('array' === typeof element
|| ('undefined' !== typeof jQuery && element instanceof jQuery) //jquery
|| ('undefined' !== typeof Elements && element instanceof Elements) //mootools
) {
var i = 0, j = element.length;
for (; i < j; i++) {
attachResizeEvent(element[i], callback);
}
} else {
attachResizeEvent(element, callback);
}
}
})();
$.fn.continouoshold = function(selector, fn, delay, startdelay, first) {
if (typeof selector === "function") {
// ( fn, delay, startdelay)
first = startdelay;
startdelay = delay;
delay = fn;
fn = selector;
selector = undefined;
}
if (typeof delay === "undefined") {
// (selector, fn) || (fn)
delay = 100;
}
if (typeof startdelay === "undefined") {
startdelay = 1000;
}
if (typeof first === "undefined") {
first = false;
}
if (fn && typeof fn == 'function') {
var timer = 0, times = 1;
var clear = function() {
times = 1;
clearInterval(timer);
};
var initcont = function(evt) {
var $self = $(this);
timer = setTimeout(function() {
$self.trigger("continouoshold");
}, startdelay);
if(first)
fn.call(this, evt);
};
this.each(function() {
$(this).on({
mousedown: initcont,
touchstart: initcont,
continouoshold: function(evt) {
var $self = $(this);
evt.times = times++;
timer = setTimeout(function() {
$self.trigger("continouoshold");
}, delay);
fn.call(this, evt);
},
mouseout: clear,
mouseup: clear,
mouseleave: clear,
touchmove: clear,
touchend: clear
}, selector);
});
}
return this;
};
$.fn.mousehold = function(selector, fn, delay) {
if (typeof selector === "function") {
// ( fn, delay )
delay = fn;
fn = selector;
selector = undefined;
}
if (typeof delay === "undefined") {
// (selector, fn) || (fn)
delay = 100;
}
if (fn && typeof fn == 'function') {
var timer = 0, times = 1;
var clear = function() {
times = 1;
clearInterval(timer);
};
this.each(function() {
$(this).on({
mousedown: function(evt) {
var $self = $(this);
evt.times = times++;
timer = setTimeout(function() {
$self.trigger("mousedown");
}, delay);
fn.call(this, evt);
},
mouseout: clear,
mouseup: clear
}, selector);
});
}
return this;
};
/*! Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh)
/* Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh)
* Licensed under the MIT License (LICENSE.txt).
*
* Version: 3.1.9
......@@ -199,4 +199,3 @@
}
}));
// @author Rich Adams <rich@richadams.me>
// Implements a tap and hold functionality. If you click/tap and release, it will trigger a normal
// click event. But if you click/tap and hold for 1s (default), it will trigger a taphold event instead.
;(function($)
{
// Default options
var defaults = {
duration: 1000, // ms
clickHandler: null
}
// When start of a taphold event is triggered.
function startHandler(event)
{
var $elem = jQuery(this);
// Merge the defaults and any user defined settings.
settings = jQuery.extend({}, defaults, event.data);
// If object also has click handler, store it and unbind. Taphold will trigger the
// click itself, rather than normal propagation.
if (typeof $elem.data("events") != "undefined"
&& typeof $elem.data("events").click != "undefined")
{
// Find the one without a namespace defined.
for (var c in $elem.data("events").click)
{
if ($elem.data("events").click[c].namespace == "")
{
var handler = $elem.data("events").click[c].handler
$elem.data("taphold_click_handler", handler);
$elem.unbind("click", handler);
break;
}
}
}
// Otherwise, if a custom click handler was explicitly defined, then store it instead.
else if (typeof settings.clickHandler == "function")
{
$elem.data("taphold_click_handler", settings.clickHandler);
}
// Reset the flags
$elem.data("taphold_triggered", false); // If a hold was triggered
$elem.data("taphold_clicked", false); // If a click was triggered
$elem.data("taphold_cancelled", false); // If event has been cancelled.
// Set the timer for the hold event.
$elem.data("taphold_timer",
setTimeout(function()
{
// If event hasn't been cancelled/clicked already, then go ahead and trigger the hold.
if (!$elem.data("taphold_cancelled")
&& !$elem.data("taphold_clicked"))
{
// Trigger the hold event, and set the flag to say it's been triggered.
$elem.trigger(jQuery.extend(event, jQuery.Event("taphold")));
$elem.data("taphold_triggered", true);
}
}, settings.duration));
}
// When user ends a tap or click, decide what we should do.
function stopHandler(event)
{
var $elem = jQuery(this);
// If taphold has been cancelled, then we're done.
if ($elem.data("taphold_cancelled")) { return; }
// Clear the hold timer. If it hasn't already triggered, then it's too late anyway.
clearTimeout($elem.data("taphold_timer"));
// If hold wasn't triggered and not already clicked, then was a click event.
if (!$elem.data("taphold_triggered")
&& !$elem.data("taphold_clicked"))
{
// If click handler, trigger it.
if (typeof $elem.data("taphold_click_handler") == "function")
{
$elem.data("taphold_click_handler")(jQuery.extend(event, jQuery.Event("click")));
}
// Set flag to say we've triggered the click event.
$elem.data("taphold_clicked", true);
}
}
// If a user prematurely leaves the boundary of the object we're working on.
function leaveHandler(event)
{
// Cancel the event.
$(this).data("taphold_cancelled", true);
}
// Determine if touch events are supported.
var touchSupported = ("ontouchstart" in window) // Most browsers
|| ("onmsgesturechange" in window); // Microsoft
var taphold = $.event.special.taphold =
{
setup: function(data)
{
$(this).bind((touchSupported ? "touchstart" : "mousedown"), data, startHandler)
.bind((touchSupported ? "touchend" : "mouseup"), stopHandler)
.bind((touchSupported ? "touchmove" : "mouseleave"), leaveHandler);
},
teardown: function(namespaces)
{
$(this).unbind((touchSupported ? "touchstart" : "mousedown"), startHandler)
.unbind((touchSupported ? "touchend" : "mouseup"), stopHandler)
.unbind((touchSupported ? "touchmove" : "mouseleave"), leaveHandler);
}
};
})(jQuery);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment