added a new way to scan qr codes from mobile browsers
This commit is contained in:
parent
dac2f8b949
commit
83681967df
@ -32,7 +32,7 @@ module.exports = function(grunt) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
vendors: {
|
vendors: {
|
||||||
src: ['public/lib/qrcode-generator/js/qrcode.js', 'public/src/js/jsqrcode/grid.js', 'public/src/js/jsqrcode/version.js', 'public/src/js/jsqrcode/detector.js', 'public/src/js/jsqrcode/formatinf.js', 'public/src/js/jsqrcode/errorlevel.js', 'public/src/js/jsqrcode/bitmat.js', 'public/src/js/jsqrcode/datablock.js', 'public/src/js/jsqrcode/bmparser.js', 'public/src/js/jsqrcode/datamask.js', 'public/src/js/jsqrcode/rsdecoder.js', 'public/src/js/jsqrcode/gf256poly.js', 'public/src/js/jsqrcode/gf256.js', 'public/src/js/jsqrcode/decoder.js', 'public/src/js/jsqrcode/qrcode.js', 'public/src/js/jsqrcode/findpat.js', 'public/src/js/jsqrcode/alignpat.js', 'public/src/js/jsqrcode/databr.js', 'public/lib/momentjs/min/moment.min.js', 'public/lib/zeroclipboard/ZeroClipboard.min.js'],
|
src: ['public/src/js/ios-imagefile-megapixel/megapix-image.js', 'public/lib/qrcode-generator/js/qrcode.js', 'public/src/js/jsqrcode/grid.js', 'public/src/js/jsqrcode/version.js', 'public/src/js/jsqrcode/detector.js', 'public/src/js/jsqrcode/formatinf.js', 'public/src/js/jsqrcode/errorlevel.js', 'public/src/js/jsqrcode/bitmat.js', 'public/src/js/jsqrcode/datablock.js', 'public/src/js/jsqrcode/bmparser.js', 'public/src/js/jsqrcode/datamask.js', 'public/src/js/jsqrcode/rsdecoder.js', 'public/src/js/jsqrcode/gf256poly.js', 'public/src/js/jsqrcode/gf256.js', 'public/src/js/jsqrcode/decoder.js', 'public/src/js/jsqrcode/qrcode.js', 'public/src/js/jsqrcode/findpat.js', 'public/src/js/jsqrcode/alignpat.js', 'public/src/js/jsqrcode/databr.js', 'public/lib/momentjs/min/moment.min.js', 'public/lib/zeroclipboard/ZeroClipboard.min.js'],
|
||||||
dest: 'public/js/vendors.js'
|
dest: 'public/js/vendors.js'
|
||||||
},
|
},
|
||||||
angular: {
|
angular: {
|
||||||
|
|||||||
2
public/css/main.min.css
vendored
2
public/css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -18,9 +18,20 @@
|
|||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3 class="modal-title">Scan Code</h3>
|
<h3 class="modal-title">Scan Code</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body text-center">
|
||||||
<canvas id="qr-canvas" width="300" height="225"></canvas>
|
<canvas id="qr-canvas" width="200" height="150"></canvas>
|
||||||
<video id="qrcode-scanner-video" width="300" height="225"></video>
|
<div data-ng-show="isMobile">
|
||||||
|
<div id="file-input-wrapper" class="btn btn-primary">
|
||||||
|
<span class="pull-left text-center">
|
||||||
|
<i class="glyphicon glyphicon-refresh icon-rotate"></i>
|
||||||
|
Get QR code
|
||||||
|
</span>
|
||||||
|
<input id="qrcode-camera" type="file" capture="camera" accept="image/*">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div data-ng-hide="isMobile">
|
||||||
|
<video id="qrcode-scanner-video" width="300" height="225" data-ng-hide="isMobile"></video>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button class="btn btn-default" data-ng-click="cancel()" data-dismiss="modal">Close</button>
|
<button class="btn btn-default" data-ng-click="cancel()" data-dismiss="modal">Close</button>
|
||||||
|
|||||||
4
public/js/angularjs-all.min.js
vendored
4
public/js/angularjs-all.min.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/main.min.js
vendored
2
public/js/main.min.js
vendored
File diff suppressed because one or more lines are too long
8
public/js/vendors.min.js
vendored
8
public/js/vendors.min.js
vendored
File diff suppressed because one or more lines are too long
@ -51,24 +51,16 @@ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* QR modal */
|
/* QR modal */
|
||||||
#qrcode-scanner-container {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
background-color: #fff;
|
|
||||||
z-index: 10000;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: center;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
#qrcode-scanner-container.active { display: block; }
|
|
||||||
#qr-canvas { display: none; }
|
#qr-canvas { display: none; }
|
||||||
#qrcode-scanner-video {
|
#qrcode-scanner-video {
|
||||||
margin: 0 auto 10px auto;
|
margin: 0 auto 10px auto;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
#file-input-wrapper { width: 100%; }
|
||||||
|
#file-input-wrapper input { opacity: 0; }
|
||||||
|
#file-input-wrapper span { width: 100%; }
|
||||||
|
#file-input-wrapper i { display: none; }
|
||||||
|
#file-input-wrapper:hover i { display: inline-block; }
|
||||||
|
|
||||||
/* Wrapper for page content to push down footer */
|
/* Wrapper for page content to push down footer */
|
||||||
#wrap {
|
#wrap {
|
||||||
@ -103,7 +95,7 @@ margin-left: 0;
|
|||||||
.table-hover>tbody>tr:hover>td, .table-hover>tbody>tr:hover>th {
|
.table-hover>tbody>tr:hover>td, .table-hover>tbody>tr:hover>th {
|
||||||
background-color: #F0F7E2;
|
background-color: #F0F7E2;
|
||||||
}
|
}
|
||||||
|
.navbar { min-height: 64px; }
|
||||||
.navbar-default .navbar-toggle {
|
.navbar-default .navbar-toggle {
|
||||||
border-color: #fff;
|
border-color: #fff;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
@ -176,7 +168,7 @@ margin-left: 0;
|
|||||||
|
|
||||||
.navbar-default .navbar-brand {
|
.navbar-default .navbar-brand {
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
padding: 22px 15px;
|
padding: 20px 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-form .form-control {
|
.navbar-form .form-control {
|
||||||
@ -195,10 +187,9 @@ margin-left: 0;
|
|||||||
padding-bottom: 22px;
|
padding-bottom: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#search {
|
#search-form { color: #fff; }
|
||||||
color: #fff;
|
|
||||||
font-family: 'Ubuntu', sans-serif;
|
#search { font-family: 'Ubuntu', sans-serif; }
|
||||||
}
|
|
||||||
|
|
||||||
#search.loading {
|
#search.loading {
|
||||||
background-image: url('/img/loading.gif');
|
background-image: url('/img/loading.gif');
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
angular.module('insight.system').controller('HeaderController',
|
angular.module('insight.system').controller('HeaderController',
|
||||||
function($scope, $rootScope, $modal, getSocket, Global, Block) {
|
function($scope, $rootScope, $modal, getSocket, Global, Block) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
$scope.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
|
||||||
|
|
||||||
$rootScope.currency = {
|
$rootScope.currency = {
|
||||||
factor: 1,
|
factor: 1,
|
||||||
|
|||||||
@ -4,28 +4,87 @@ angular.module('insight.system').controller('ScannerController',
|
|||||||
function($scope, $rootScope, $modalInstance, Global) {
|
function($scope, $rootScope, $modalInstance, Global) {
|
||||||
$scope.global = Global;
|
$scope.global = Global;
|
||||||
|
|
||||||
|
// Detect mobile devices
|
||||||
|
var isMobile = {
|
||||||
|
Android: function() {
|
||||||
|
return navigator.userAgent.match(/Android/i);
|
||||||
|
},
|
||||||
|
BlackBerry: function() {
|
||||||
|
return navigator.userAgent.match(/BlackBerry/i);
|
||||||
|
},
|
||||||
|
iOS: function() {
|
||||||
|
return navigator.userAgent.match(/iPhone|iPad|iPod/i);
|
||||||
|
},
|
||||||
|
Opera: function() {
|
||||||
|
return navigator.userAgent.match(/Opera Mini/i);
|
||||||
|
},
|
||||||
|
Windows: function() {
|
||||||
|
return navigator.userAgent.match(/IEMobile/i);
|
||||||
|
},
|
||||||
|
any: function() {
|
||||||
|
return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
||||||
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
||||||
|
|
||||||
|
$scope.isMobile = isMobile.any();
|
||||||
|
$scope.scannerLoading = false;
|
||||||
|
|
||||||
var $searchInput = angular.element(document.getElementById('search')),
|
var $searchInput = angular.element(document.getElementById('search')),
|
||||||
|
cameraInput,
|
||||||
video,
|
video,
|
||||||
canvas,
|
canvas,
|
||||||
$video,
|
$video,
|
||||||
context,
|
context,
|
||||||
localMediaStream;
|
localMediaStream;
|
||||||
|
|
||||||
var _scan = function() {
|
var _scan = function(evt) {
|
||||||
if (localMediaStream) {
|
if ($scope.isMobile) {
|
||||||
context.drawImage(video, 0, 0, 300, 225);
|
$scope.scannerLoading = true;
|
||||||
|
var files = evt.target.files;
|
||||||
|
|
||||||
try {
|
if (files.length === 1 && files[0].type.indexOf('image/') === 0) {
|
||||||
qrcode.decode();
|
var file = files[0];
|
||||||
} catch(e) {
|
|
||||||
//qrcodeError(e);
|
var reader = new FileReader();
|
||||||
|
reader.onload = (function(theFile) {
|
||||||
|
return function(e) {
|
||||||
|
var mpImg = new MegaPixImage(file);
|
||||||
|
mpImg.render(canvas, { maxWidth: 200, maxHeight: 200, orientation: 6 });
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
//qrcode.width = canvas.width;
|
||||||
|
//qrcode.height = canvas.height;
|
||||||
|
//qrcode.imagedata = context.getImageData(0, 0, qrcode.width, qrcode.height);
|
||||||
|
|
||||||
|
try {
|
||||||
|
//alert(JSON.stringify(qrcode.process(context)));
|
||||||
|
qrcode.decode();
|
||||||
|
} catch (e) {
|
||||||
|
alert(e);
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
})(file);
|
||||||
|
|
||||||
|
// Read in the file as a data URL
|
||||||
|
reader.readAsDataURL(file);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
if (localMediaStream) {
|
||||||
|
context.drawImage(video, 0, 0, 300, 225);
|
||||||
|
|
||||||
setTimeout(_scan, 500);
|
try {
|
||||||
|
qrcode.decode();
|
||||||
|
} catch(e) {
|
||||||
|
//qrcodeError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(_scan, 500);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var _successCallback = function(stream) {
|
var _successCallback = function(stream) {
|
||||||
@ -36,10 +95,13 @@ angular.module('insight.system').controller('ScannerController',
|
|||||||
};
|
};
|
||||||
|
|
||||||
var _scanStop = function() {
|
var _scanStop = function() {
|
||||||
|
$scope.scannerLoading = false;
|
||||||
$modalInstance.close();
|
$modalInstance.close();
|
||||||
if (localMediaStream.stop) localMediaStream.stop();
|
if (!$scope.isMobile) {
|
||||||
localMediaStream = null;
|
if (localMediaStream.stop) localMediaStream.stop();
|
||||||
video.src = '';
|
localMediaStream = null;
|
||||||
|
video.src = '';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var _videoError = function(err) {
|
var _videoError = function(err) {
|
||||||
@ -54,23 +116,34 @@ angular.module('insight.system').controller('ScannerController',
|
|||||||
console.log('QR code detected: ' + str);
|
console.log('QR code detected: ' + str);
|
||||||
$searchInput
|
$searchInput
|
||||||
.val(str)
|
.val(str)
|
||||||
.triggerHandler('change');
|
.triggerHandler('change')
|
||||||
|
.triggerHandler('submit');
|
||||||
};
|
};
|
||||||
|
|
||||||
$modalInstance.opened.then(function() {
|
|
||||||
//Start the scanner
|
|
||||||
setTimeout(function() {
|
|
||||||
video = document.getElementById('qrcode-scanner-video');
|
|
||||||
canvas = document.getElementById('qr-canvas');
|
|
||||||
$video = angular.element(video);
|
|
||||||
context = canvas.getContext('2d');
|
|
||||||
context.clearRect(0, 0, 300, 225);
|
|
||||||
|
|
||||||
navigator.getUserMedia({video: true}, _successCallback, _videoError);
|
|
||||||
}, 800);
|
|
||||||
});
|
|
||||||
|
|
||||||
$scope.cancel = function() {
|
$scope.cancel = function() {
|
||||||
_scanStop();
|
_scanStop();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$modalInstance.opened.then(function() {
|
||||||
|
$rootScope.isCollapsed = true;
|
||||||
|
|
||||||
|
// Start the scanner
|
||||||
|
setTimeout(function() {
|
||||||
|
canvas = document.getElementById('qr-canvas');
|
||||||
|
context = canvas.getContext('2d');
|
||||||
|
|
||||||
|
if ($scope.isMobile) {
|
||||||
|
cameraInput = document.getElementById('qrcode-camera');
|
||||||
|
cameraInput.addEventListener('change', _scan, false);
|
||||||
|
} else {
|
||||||
|
video = document.getElementById('qrcode-scanner-video');
|
||||||
|
$video = angular.element(video);
|
||||||
|
canvas.width = 300;
|
||||||
|
canvas.height = 225;
|
||||||
|
context.clearRect(0, 0, 300, 225);
|
||||||
|
|
||||||
|
navigator.getUserMedia({video: true}, _successCallback, _videoError);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -15,9 +15,9 @@
|
|||||||
<a href="/{{item.link}}">{{item.title}}</a>
|
<a href="/{{item.link}}">{{item.title}}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<form data-ng-controller="SearchController" class="navbar-form navbar-left hidden-xs" role="search" data-ng-submit="search()">
|
<form id="search-form" data-ng-controller="SearchController" class="navbar-form navbar-left hidden-xs" role="search" data-ng-submit="search()">
|
||||||
<div class="form-group" data-ng-class="{'has-error': badQuery}">
|
<div class="form-group" data-ng-class="{'has-error': badQuery}">
|
||||||
<input id="search" type="text" class="form-control" data-ng-model="q" data-ng-class="{'loading': loading}" placeholder="Search for block, transaction or address" data-ng-change="search()">
|
<input id="search" type="text" class="form-control" data-ng-model="q" data-ng-class="{'loading': loading}" placeholder="Search for block, transaction or address" data-ng-submit="search()">
|
||||||
</div>
|
</div>
|
||||||
<div class="no_matching text-danger" data-ng-show="badQuery">No matching records found!</div>
|
<div class="no_matching text-danger" data-ng-show="badQuery">No matching records found!</div>
|
||||||
</form>
|
</form>
|
||||||
@ -42,7 +42,7 @@
|
|||||||
<strong>Height</strong> {{totalBlocks || info.blocks}}
|
<strong>Height</strong> {{totalBlocks || info.blocks}}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li data-ng-if="getUserMedia">
|
<li>
|
||||||
<a href="#" data-ng-click="openScannerModal()"><span class="glyphicon glyphicon-qrcode"></span> Scan</a>
|
<a href="#" data-ng-click="openScannerModal()"><span class="glyphicon glyphicon-qrcode"></span> Scan</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="dropdown" data-ng-controller="CurrencyController" data-ng-include="'/views/includes/currency.html'"></li>
|
<li class="dropdown" data-ng-controller="CurrencyController" data-ng-include="'/views/includes/currency.html'"></li>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<form data-ng-controller="SearchController" class="visible-xs" role="search" data-ng-submit="search()">
|
<form id="search-form-mobile" data-ng-controller="SearchController" class="visible-xs" role="search" data-ng-submit="search()">
|
||||||
<div class="form-group" data-ng-class="{'has-error': badQuery}">
|
<div class="form-group" data-ng-class="{'has-error': badQuery}">
|
||||||
<input id="search" type="text" class="form-control" data-ng-model="q" data-ng-class="{'loading': loading}" placeholder="Search for block, transaction or address">
|
<input id="search" type="text" class="form-control" data-ng-model="q" data-ng-class="{'loading': loading}" placeholder="Search for block, transaction or address" data-ng-submit="search()">
|
||||||
</div>
|
</div>
|
||||||
<div class="no_matching text-danger" data-ng-show="badQuery">No matching records found!</div>
|
<div class="no_matching text-danger" data-ng-show="badQuery">No matching records found!</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user