Merge pull request #424 from colkito/feature/mobile-qrcode-scanner
Feature/mobile qrcode scanner
This commit is contained in:
commit
ac7b2373b0
@ -32,7 +32,7 @@ module.exports = function(grunt) {
|
||||
}
|
||||
},
|
||||
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'
|
||||
},
|
||||
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">
|
||||
<h3 class="modal-title">Scan Code</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<canvas id="qr-canvas" width="300" height="225"></canvas>
|
||||
<video id="qrcode-scanner-video" width="300" height="225"></video>
|
||||
<div class="modal-body text-center">
|
||||
<canvas id="qr-canvas" width="200" height="150"></canvas>
|
||||
<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 class="modal-footer">
|
||||
<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 */
|
||||
#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; }
|
||||
#qrcode-scanner-video {
|
||||
margin: 0 auto 10px auto;
|
||||
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 */
|
||||
#wrap {
|
||||
@ -103,7 +95,7 @@ margin-left: 0;
|
||||
.table-hover>tbody>tr:hover>td, .table-hover>tbody>tr:hover>th {
|
||||
background-color: #F0F7E2;
|
||||
}
|
||||
|
||||
.navbar { min-height: 64px; }
|
||||
.navbar-default .navbar-toggle {
|
||||
border-color: #fff;
|
||||
margin-top: 15px;
|
||||
@ -176,7 +168,7 @@ margin-left: 0;
|
||||
|
||||
.navbar-default .navbar-brand {
|
||||
color: #FFFFFF;
|
||||
padding: 22px 15px;
|
||||
padding: 20px 15px;
|
||||
}
|
||||
|
||||
.navbar-form .form-control {
|
||||
@ -195,10 +187,9 @@ margin-left: 0;
|
||||
padding-bottom: 22px;
|
||||
}
|
||||
|
||||
#search {
|
||||
color: #fff;
|
||||
font-family: 'Ubuntu', sans-serif;
|
||||
}
|
||||
#search-form { color: #fff; }
|
||||
|
||||
#search { font-family: 'Ubuntu', sans-serif; }
|
||||
|
||||
#search.loading {
|
||||
background-image: url('/img/loading.gif');
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
angular.module('insight.system').controller('HeaderController',
|
||||
function($scope, $rootScope, $modal, getSocket, Global, Block) {
|
||||
$scope.global = Global;
|
||||
$scope.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
||||
|
||||
$rootScope.currency = {
|
||||
factor: 1,
|
||||
|
||||
@ -4,28 +4,87 @@ angular.module('insight.system').controller('ScannerController',
|
||||
function($scope, $rootScope, $modalInstance, 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;
|
||||
window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
|
||||
|
||||
$scope.isMobile = isMobile.any();
|
||||
$scope.scannerLoading = false;
|
||||
|
||||
var $searchInput = angular.element(document.getElementById('search')),
|
||||
cameraInput,
|
||||
video,
|
||||
canvas,
|
||||
$video,
|
||||
context,
|
||||
localMediaStream;
|
||||
|
||||
var _scan = function() {
|
||||
if (localMediaStream) {
|
||||
context.drawImage(video, 0, 0, 300, 225);
|
||||
var _scan = function(evt) {
|
||||
if ($scope.isMobile) {
|
||||
$scope.scannerLoading = true;
|
||||
var files = evt.target.files;
|
||||
|
||||
try {
|
||||
qrcode.decode();
|
||||
} catch(e) {
|
||||
//qrcodeError(e);
|
||||
if (files.length === 1 && files[0].type.indexOf('image/') === 0) {
|
||||
var file = files[0];
|
||||
|
||||
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) {
|
||||
@ -36,10 +95,13 @@ angular.module('insight.system').controller('ScannerController',
|
||||
};
|
||||
|
||||
var _scanStop = function() {
|
||||
$scope.scannerLoading = false;
|
||||
$modalInstance.close();
|
||||
if (localMediaStream.stop) localMediaStream.stop();
|
||||
localMediaStream = null;
|
||||
video.src = '';
|
||||
if (!$scope.isMobile) {
|
||||
if (localMediaStream.stop) localMediaStream.stop();
|
||||
localMediaStream = null;
|
||||
video.src = '';
|
||||
}
|
||||
};
|
||||
|
||||
var _videoError = function(err) {
|
||||
@ -54,23 +116,34 @@ angular.module('insight.system').controller('ScannerController',
|
||||
console.log('QR code detected: ' + str);
|
||||
$searchInput
|
||||
.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() {
|
||||
_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);
|
||||
});
|
||||
});
|
||||
|
||||
254
public/src/js/ios-imagefile-megapixel/megapix-image.js
Normal file
254
public/src/js/ios-imagefile-megapixel/megapix-image.js
Normal file
@ -0,0 +1,254 @@
|
||||
/**
|
||||
* Mega pixel image rendering library for iOS6 Safari
|
||||
*
|
||||
* Fixes iOS6 Safari's image file rendering issue for large size image (over mega-pixel),
|
||||
* which causes unexpected subsampling when drawing it in canvas.
|
||||
* By using this library, you can safely render the image with proper stretching.
|
||||
*
|
||||
* Copyright (c) 2012 Shinichi Tomita <shinichi.tomita@gmail.com>
|
||||
* Released under the MIT license
|
||||
*/
|
||||
(function() {
|
||||
|
||||
/**
|
||||
* Detect subsampling in loaded image.
|
||||
* In iOS, larger images than 2M pixels may be subsampled in rendering.
|
||||
*/
|
||||
function detectSubsampling(img) {
|
||||
var iw = img.naturalWidth, ih = img.naturalHeight;
|
||||
if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = canvas.height = 1;
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, -iw + 1, 0);
|
||||
// subsampled image becomes half smaller in rendering size.
|
||||
// check alpha channel value to confirm image is covering edge pixel or not.
|
||||
// if alpha value is 0 image is not covering, hence subsampled.
|
||||
return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detecting vertical squash in loaded image.
|
||||
* Fixes a bug which squash image vertically while drawing into canvas for some images.
|
||||
*/
|
||||
function detectVerticalSquash(img, iw, ih) {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = 1;
|
||||
canvas.height = ih;
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, 0, 0);
|
||||
var data = ctx.getImageData(0, 0, 1, ih).data;
|
||||
// search image edge pixel position in case it is squashed vertically.
|
||||
var sy = 0;
|
||||
var ey = ih;
|
||||
var py = ih;
|
||||
while (py > sy) {
|
||||
var alpha = data[(py - 1) * 4 + 3];
|
||||
if (alpha === 0) {
|
||||
ey = py;
|
||||
} else {
|
||||
sy = py;
|
||||
}
|
||||
py = (ey + sy) >> 1;
|
||||
}
|
||||
var ratio = (py / ih);
|
||||
return (ratio===0)?1:ratio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendering image element (with resizing) and get its data URL
|
||||
*/
|
||||
function renderImageToDataURL(img, options, doSquash) {
|
||||
var canvas = document.createElement('canvas');
|
||||
renderImageToCanvas(img, canvas, options, doSquash);
|
||||
return canvas.toDataURL("image/jpeg", options.quality || 0.8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendering image element (with resizing) into the canvas element
|
||||
*/
|
||||
function renderImageToCanvas(img, canvas, options, doSquash) {
|
||||
var iw = img.naturalWidth, ih = img.naturalHeight;
|
||||
var width = options.width, height = options.height;
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
transformCoordinate(canvas, width, height, options.orientation);
|
||||
var subsampled = detectSubsampling(img);
|
||||
if (subsampled) {
|
||||
iw /= 2;
|
||||
ih /= 2;
|
||||
}
|
||||
var d = 1024; // size of tiling canvas
|
||||
var tmpCanvas = document.createElement('canvas');
|
||||
tmpCanvas.width = tmpCanvas.height = d;
|
||||
var tmpCtx = tmpCanvas.getContext('2d');
|
||||
var vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1;
|
||||
var dw = Math.ceil(d * width / iw);
|
||||
var dh = Math.ceil(d * height / ih / vertSquashRatio);
|
||||
var sy = 0;
|
||||
var dy = 0;
|
||||
while (sy < ih) {
|
||||
var sx = 0;
|
||||
var dx = 0;
|
||||
while (sx < iw) {
|
||||
tmpCtx.clearRect(0, 0, d, d);
|
||||
tmpCtx.drawImage(img, -sx, -sy);
|
||||
ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);
|
||||
sx += d;
|
||||
dx += dw;
|
||||
}
|
||||
sy += d;
|
||||
dy += dh;
|
||||
}
|
||||
ctx.restore();
|
||||
tmpCanvas = tmpCtx = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform canvas coordination according to specified frame size and orientation
|
||||
* Orientation value is from EXIF tag
|
||||
*/
|
||||
function transformCoordinate(canvas, width, height, orientation) {
|
||||
switch (orientation) {
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
canvas.width = height;
|
||||
canvas.height = width;
|
||||
break;
|
||||
default:
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
var ctx = canvas.getContext('2d');
|
||||
switch (orientation) {
|
||||
case 2:
|
||||
// horizontal flip
|
||||
ctx.translate(width, 0);
|
||||
ctx.scale(-1, 1);
|
||||
break;
|
||||
case 3:
|
||||
// 180 rotate left
|
||||
ctx.translate(width, height);
|
||||
ctx.rotate(Math.PI);
|
||||
break;
|
||||
case 4:
|
||||
// vertical flip
|
||||
ctx.translate(0, height);
|
||||
ctx.scale(1, -1);
|
||||
break;
|
||||
case 5:
|
||||
// vertical flip + 90 rotate right
|
||||
ctx.rotate(0.5 * Math.PI);
|
||||
ctx.scale(1, -1);
|
||||
break;
|
||||
case 6:
|
||||
// 90 rotate right
|
||||
ctx.rotate(0.5 * Math.PI);
|
||||
ctx.translate(0, -height);
|
||||
break;
|
||||
case 7:
|
||||
// horizontal flip + 90 rotate right
|
||||
ctx.rotate(0.5 * Math.PI);
|
||||
ctx.translate(width, -height);
|
||||
ctx.scale(-1, 1);
|
||||
break;
|
||||
case 8:
|
||||
// 90 rotate left
|
||||
ctx.rotate(-0.5 * Math.PI);
|
||||
ctx.translate(-width, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* MegaPixImage class
|
||||
*/
|
||||
function MegaPixImage(srcImage) {
|
||||
if (window.Blob && srcImage instanceof Blob) {
|
||||
var img = new Image();
|
||||
var URL = window.URL && window.URL.createObjectURL ? window.URL :
|
||||
window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL :
|
||||
null;
|
||||
if (!URL) { throw Error("No createObjectURL function found to create blob url"); }
|
||||
img.src = URL.createObjectURL(srcImage);
|
||||
this.blob = srcImage;
|
||||
srcImage = img;
|
||||
}
|
||||
if (!srcImage.naturalWidth && !srcImage.naturalHeight) {
|
||||
var _this = this;
|
||||
srcImage.onload = function() {
|
||||
var listeners = _this.imageLoadListeners;
|
||||
if (listeners) {
|
||||
_this.imageLoadListeners = null;
|
||||
for (var i=0, len=listeners.length; i<len; i++) {
|
||||
listeners[i]();
|
||||
}
|
||||
}
|
||||
};
|
||||
this.imageLoadListeners = [];
|
||||
}
|
||||
this.srcImage = srcImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendering megapix image into specified target element
|
||||
*/
|
||||
MegaPixImage.prototype.render = function(target, options) {
|
||||
if (this.imageLoadListeners) {
|
||||
var _this = this;
|
||||
this.imageLoadListeners.push(function() { _this.render(target, options) });
|
||||
return;
|
||||
}
|
||||
options = options || {};
|
||||
var imgWidth = this.srcImage.naturalWidth, imgHeight = this.srcImage.naturalHeight,
|
||||
width = options.width, height = options.height,
|
||||
maxWidth = options.maxWidth, maxHeight = options.maxHeight,
|
||||
doSquash = !this.blob || this.blob.type === 'image/jpeg';
|
||||
if (width && !height) {
|
||||
height = (imgHeight * width / imgWidth) << 0;
|
||||
} else if (height && !width) {
|
||||
width = (imgWidth * height / imgHeight) << 0;
|
||||
} else {
|
||||
width = imgWidth;
|
||||
height = imgHeight;
|
||||
}
|
||||
if (maxWidth && width > maxWidth) {
|
||||
width = maxWidth;
|
||||
height = (imgHeight * width / imgWidth) << 0;
|
||||
}
|
||||
if (maxHeight && height > maxHeight) {
|
||||
height = maxHeight;
|
||||
width = (imgWidth * height / imgHeight) << 0;
|
||||
}
|
||||
var opt = { width : width, height : height };
|
||||
for (var k in options) opt[k] = options[k];
|
||||
|
||||
var tagName = target.tagName.toLowerCase();
|
||||
if (tagName === 'img') {
|
||||
target.src = renderImageToDataURL(this.srcImage, opt, doSquash);
|
||||
} else if (tagName === 'canvas') {
|
||||
renderImageToCanvas(this.srcImage, target, opt, doSquash);
|
||||
}
|
||||
if (typeof this.onrender === 'function') {
|
||||
this.onrender(target);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Export class to global
|
||||
*/
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define([], function() { return MegaPixImage; }); // for AMD loader
|
||||
} else {
|
||||
this.MegaPixImage = MegaPixImage;
|
||||
}
|
||||
|
||||
})();
|
||||
@ -15,9 +15,9 @@
|
||||
<a href="/{{item.link}}">{{item.title}}</a>
|
||||
</li>
|
||||
</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}">
|
||||
<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 class="no_matching text-danger" data-ng-show="badQuery">No matching records found!</div>
|
||||
</form>
|
||||
@ -42,7 +42,7 @@
|
||||
<strong>Height</strong> {{totalBlocks || info.blocks}}
|
||||
</div>
|
||||
</li>
|
||||
<li data-ng-if="getUserMedia">
|
||||
<li>
|
||||
<a href="#" data-ng-click="openScannerModal()"><span class="glyphicon glyphicon-qrcode"></span> Scan</a>
|
||||
</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}">
|
||||
<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 class="no_matching text-danger" data-ng-show="badQuery">No matching records found!</div>
|
||||
</form>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user