UNPKG

@gohelpfund/insight-ui

Version:

An open-source frontend for the Insight API. The Insight API provides you with a convenient, powerful and simple way to query and broadcast data on the Help network and build your own services with it.

1,480 lines (1,281 loc) 82.6 kB
// Source: public/src/js/app.js var defaultLanguage = localStorage.getItem('insight-language') || 'en'; var defaultCurrency = localStorage.getItem('insight-currency') || 'HELP'; angular.module('insight',[ 'ngAnimate', 'ngResource', 'ngRoute', 'ngProgress', 'ui.bootstrap', 'ui.route', 'monospaced.qrcode', 'gettext', 'angularMoment', 'insight.system', 'insight.socket', 'insight.blocks', 'insight.transactions', 'insight.address', 'insight.search', 'insight.status', 'insight.connection', 'insight.currency', 'insight.messages', 'insight.richlist' ]); angular.module('insight.system', []); angular.module('insight.socket', []); angular.module('insight.blocks', []); angular.module('insight.transactions', []); angular.module('insight.address', []); angular.module('insight.search', []); angular.module('insight.status', []); angular.module('insight.connection', []); angular.module('insight.currency', []); angular.module('insight.messages', []); angular.module('insight.richlist', []); // Source: public/src/js/controllers/address.js angular.module('insight.address').controller('AddressController', function($scope, $rootScope, $routeParams, $location, Global, Address, getSocket) { $scope.global = Global; var socket = getSocket($scope); var addrStr = $routeParams.addrStr; var _startSocket = function() { socket.on('helpd/addresstxid', function(data) { if (data.address === addrStr) { $rootScope.$broadcast('tx', data.txid); var base = document.querySelector('base'); var beep = new Audio(base.href + '/sound/transaction.mp3'); beep.play(); } }); socket.emit('subscribe', 'helpd/addresstxid', [addrStr]); }; var _stopSocket = function () { socket.emit('unsubscribe', 'helpd/addresstxid', [addrStr]); }; socket.on('connect', function() { _startSocket(); }); $scope.$on('$destroy', function(){ _stopSocket(); }); $scope.params = $routeParams; $scope.findOne = function() { $rootScope.currentAddr = $routeParams.addrStr; _startSocket(); Address.get({ addrStr: $routeParams.addrStr }, function(address) { $rootScope.titleDetail = address.addrStr.substring(0, 7) + '...'; $rootScope.flashMessage = null; $scope.address = address; }, function(e) { if (e.status === 400) { $rootScope.flashMessage = 'Invalid Address: ' + $routeParams.addrStr; } else if (e.status === 503) { $rootScope.flashMessage = 'Backend Error. ' + e.data; } else { $rootScope.flashMessage = 'Address Not Found'; } $location.path('/'); }); }; }); // Source: public/src/js/controllers/blocks.js angular.module('insight.blocks').controller('BlocksController', function($scope, $rootScope, $routeParams, $location, Global, Block, Blocks, BlockByHeight) { $scope.global = Global; $scope.loading = false; if ($routeParams.blockHeight) { BlockByHeight.get({ blockHeight: $routeParams.blockHeight }, function(hash) { $location.path('/block/' + hash.blockHash); }, function() { $rootScope.flashMessage = 'Bad Request'; $location.path('/'); }); } var toUTCDate = function(date){ var _utc = new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()); return _utc; }; var millisToUTCDate = function(millis){ return toUTCDate(new Date(millis* 1000)); }; $scope.toUTCDate = toUTCDate; $scope.millisToUTCDate = millisToUTCDate; //Datepicker var _formatTimestamp = function (date) { var yyyy = date.getUTCFullYear().toString(); var mm = (date.getUTCMonth() + 1).toString(); // getMonth() is zero-based var dd = date.getUTCDate().toString(); return yyyy + '-' + (mm[1] ? mm : '0' + mm[0]) + '-' + (dd[1] ? dd : '0' + dd[0]); //padding }; $scope.$watch('dt', function(newValue, oldValue) { if (newValue !== oldValue) { $location.path('/blocks-date/' + _formatTimestamp(newValue)); } }); $scope.openCalendar = function($event) { $scope.opened = true; setTimeout(function(){ angular.element(document.querySelector('.uib-datepicker-popup'))[0].style.display = "block"; }, 100); }; $scope.humanSince = function(time) { var m = moment.unix(time).startOf('day'); var b = moment().startOf('day'); return m.max().from(b); }; $scope.list = function() { $scope.loading = true; if ($routeParams.blockDate) { $scope.detail = 'On ' + $routeParams.blockDate; } if ($routeParams.startTimestamp) { var d=new Date($routeParams.startTimestamp*1000); var m=d.getMinutes(); if (m<10) m = '0' + m; $scope.before = ' before ' + d.getHours() + ':' + m; } $rootScope.titleDetail = $scope.detail; Blocks.get({ blockDate: $routeParams.blockDate, startTimestamp: $routeParams.startTimestamp }, function(res) { $scope.loading = false; $scope.blocks = res.blocks; $scope.pagination = res.pagination; $scope.pagination.olderBlocks = $scope.pagination.moreTs; for (var key in $scope.blocks) { if($scope.blocks[key].time < $scope.pagination.olderBlocks){ $scope.pagination.olderBlocks = $scope.blocks[key].time; } } }); }; $scope.findOne = function() { $scope.loading = true; Block.get({ blockHash: $routeParams.blockHash }, function(block) { $rootScope.titleDetail = block.height; $rootScope.flashMessage = null; $scope.loading = false; $scope.block = block; }, function(e) { if (e.status === 400) { $rootScope.flashMessage = 'Invalid Transaction ID: ' + $routeParams.txId; } else if (e.status === 503) { $rootScope.flashMessage = 'Backend Error. ' + e.data; } else { $rootScope.flashMessage = 'Block Not Found'; } $location.path('/'); }); }; $scope.params = $routeParams; }); // Source: public/src/js/controllers/connection.js angular.module('insight.connection').controller('ConnectionController', function($scope, $window, Status, getSocket, PeerSync) { // Set initial values $scope.apiOnline = true; $scope.serverOnline = true; $scope.clienteOnline = true; var socket = getSocket($scope); // Check for the node server connection socket.on('connect', function() { $scope.serverOnline = true; socket.on('disconnect', function() { $scope.serverOnline = false; }); }); // Check for the api connection $scope.getConnStatus = function() { PeerSync.get({}, function(peer) { $scope.apiOnline = peer.connected; $scope.host = peer.host; $scope.port = peer.port; }, function() { $scope.apiOnline = false; }); }; socket.emit('subscribe', 'sync'); socket.on('status', function(sync) { $scope.sync = sync; $scope.apiOnline = (sync.status !== 'aborted' && sync.status !== 'error'); }); // Check for the client conneciton $window.addEventListener('offline', function() { $scope.$apply(function() { $scope.clienteOnline = false; }); }, true); $window.addEventListener('online', function() { $scope.$apply(function() { $scope.clienteOnline = true; }); }, true); }); // Source: public/src/js/controllers/currency.js angular.module('insight.currency', ['ui.router','ui.bootstrap']).controller('CurrencyController', function($scope, $rootScope, Currency) { $rootScope.currency.symbol = defaultCurrency; var _roundFloat = function(x, n) { if(!parseInt(n, 10) || !parseFloat(x)) n = 0; return Math.round(x * Math.pow(10, n)) / Math.pow(10, n); }; $rootScope.currency.getConvertion = function(value) { value = value * 1; // Convert to number if (!isNaN(value) && typeof value !== 'undefined' && value !== null) { if (value === 0.00000000) return '0 ' + this.symbol; // fix value to show var response; if (this.symbol === 'USD') { response = _roundFloat((value * this.factor), 2); } else if (this.symbol === 'mHELP') { this.factor = 1000; response = _roundFloat((value * this.factor), 5); } else if (this.symbol === 'uHELP') { this.factor = 1000000; response = _roundFloat((value * this.factor), 2); } else { this.factor = 1; response = value; } // prevent sci notation if (response < 1e-7) response=response.toFixed(8); return response + ' ' + this.symbol; } return 'value error'; }; $scope.setCurrency = function(currency) { $rootScope.currency.symbol = currency; localStorage.setItem('insight-currency', currency); if (currency === 'USD') { Currency.get({}, function(res) { $rootScope.currency.factor = $rootScope.currency.bitstamp = res.data.bitstamp; }); } else if (currency === 'mHELP') { $rootScope.currency.factor = 1000; } else if (currency === 'uHELP') { $rootScope.currency.factor = 1000000; } else { $rootScope.currency.factor = 1; } }; // Get initial value Currency.get({}, function(res) { $rootScope.currency.factor = $rootScope.currency.bitstamp = res.data.bitstamp; }); }); // Source: public/src/js/controllers/footer.js angular.module('insight.system').controller('FooterController', function($scope, $route, $templateCache, gettextCatalog, amMoment, Version) { $scope.defaultLanguage = defaultLanguage; var _getVersion = function() { Version.get({}, function(res) { $scope.version = res.version; }); }; $scope.version = _getVersion(); $scope.availableLanguages = [{ name: 'Deutsch', isoCode: 'de_DE', }, { name: 'English', isoCode: 'en', }, { name: 'French', isoCode: 'fr_FR', }, { name: 'Spanish', isoCode: 'es', }, { name: 'Portuguese', isoCode: 'pt_BR', }, { name: 'Japanese', isoCode: 'ja', }, { name: 'Chinese', isoCode: 'zh', }]; $scope.setLanguage = function(isoCode) { gettextCatalog.currentLanguage = $scope.defaultLanguage = defaultLanguage = isoCode; amMoment.changeLocale(isoCode); localStorage.setItem('insight-language', isoCode); var currentPageTemplate = $route.current.templateUrl; $templateCache.remove(currentPageTemplate); $route.reload(); }; }); // Source: public/src/js/controllers/header.js angular.module('insight.system').controller('HeaderController', function($scope, $rootScope, $uibModal, getSocket, Global, Block) { $scope.global = Global; $rootScope.currency = { factor: 1, bitstamp: 0, symbol: 'HELP' }; $scope.menu = [ { 'title': 'Blocks', 'link': 'blocks' }, { 'title': 'More', 'items': [ { 'title': 'Rich list', 'link': 'richlist' }, { 'title': 'Status', 'link': 'status' } ] } ]; $scope.openScannerModal = function() { var modalInstance = $uibModal.open({ templateUrl: 'scannerModal.html', controller: 'ScannerController' }); }; var _getBlock = function(hash) { Block.get({ blockHash: hash }, function(res) { $scope.totalBlocks = res.height; }); }; var socket = getSocket($scope); socket.on('connect', function() { socket.emit('subscribe', 'inv'); socket.on('block', function(block) { var blockHash = block.toString(); _getBlock(blockHash); }); }); $rootScope.isCollapsed = true; }); // Source: public/src/js/controllers/index.js var TRANSACTION_DISPLAYED = 10; var BLOCKS_DISPLAYED = 5; angular.module('insight.system').controller('IndexController', function($scope, Global, getSocket, Blocks) { $scope.global = Global; var _getBlocks = function() { Blocks.get({ limit: BLOCKS_DISPLAYED }, function(res) { $scope.blocks = res.blocks; $scope.blocksLength = res.length; }); }; var socket = getSocket($scope); var _startSocket = function() { socket.emit('subscribe', 'inv'); socket.on('tx', function(tx) { $scope.txs.unshift(tx); if (parseInt($scope.txs.length, 10) >= parseInt(TRANSACTION_DISPLAYED, 10)) { $scope.txs = $scope.txs.splice(0, TRANSACTION_DISPLAYED); } }); socket.on('block', function() { _getBlocks(); }); }; socket.on('connect', function() { _startSocket(); }); $scope.humanSince = function(time) { var m = moment.unix(time); return m.max().fromNow(); }; $scope.index = function() { _getBlocks(); _startSocket(); }; $scope.txs = []; $scope.blocks = []; }); // Source: public/src/js/controllers/messages.js angular.module('insight.messages').controller('VerifyMessageController', function($scope, $http) { $scope.message = { address: '', signature: '', message: '' }; $scope.verification = { status: 'unverified', // ready|loading|verified|error result: null, error: null, address: '' }; $scope.verifiable = function() { return ($scope.message.address && $scope.message.signature && $scope.message.message); }; $scope.verify = function() { $scope.verification.status = 'loading'; $scope.verification.address = $scope.message.address; $http.post(window.apiPrefix + '/messages/verify', $scope.message) .success(function(data, status, headers, config) { if(typeof(data.result) != 'boolean') { // API returned 200 but result was not true or false $scope.verification.status = 'error'; $scope.verification.error = null; return; } $scope.verification.status = 'verified'; $scope.verification.result = data.result; }) .error(function(data, status, headers, config) { $scope.verification.status = 'error'; $scope.verification.error = data; }); }; // Hide the verify status message on form change var unverify = function() { $scope.verification.status = 'unverified'; }; $scope.$watch('message.address', unverify); $scope.$watch('message.signature', unverify); $scope.$watch('message.message', unverify); }); // Source: public/src/js/controllers/richlist.js angular.module('insight.richlist') .controller('RichListController', function ($scope, RichList) { $scope.items = []; RichList.query({}, function (addrs) { for (var i = 0; i < addrs.length; i++) { $scope.items.push({ rank: i + 1, addr: addrs[i].address, balance: addrs[i].balance }); } }); }) .controller('RealSupplyController', function($scope, $http) { $scope.realSupply = 'Not available'; $http.get("http://insight.gohelpfund.com/insight-api/supply") .then(function(response) { $scope.realSupply = response.data.circulating.toFixed(2).replace(/(\B)(?=(\d{3})+(?!\d))/g, '$1 ') + ' HELP'; $scope.realSupplyRaw = response.data.circulating; }); }); ; // Source: public/src/js/controllers/scanner.js angular.module('insight.system').controller('ScannerController', function($scope, $rootScope, $uibModalInstance, 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(evt) { if ($scope.isMobile) { $scope.scannerLoading = true; var files = evt.target.files; 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); } }, 1500); }; })(file); // Read in the file as a data URL reader.readAsDataURL(file); } } else { if (localMediaStream) { context.drawImage(video, 0, 0, 300, 225); try { qrcode.decode(); } catch(e) { //qrcodeError(e); } } setTimeout(_scan, 500); } }; var _successCallback = function(stream) { video.src = (window.URL && window.URL.createObjectURL(stream)) || stream; localMediaStream = stream; video.play(); setTimeout(_scan, 1000); }; var _scanStop = function() { $scope.scannerLoading = false; $uibModalInstance.close(); if (!$scope.isMobile) { if (localMediaStream.stop) localMediaStream.stop(); localMediaStream = null; video.src = ''; } }; var _videoError = function(err) { console.log('Video Error: ' + JSON.stringify(err)); _scanStop(); }; qrcode.callback = function(data) { _scanStop(); var str = (data.indexOf('help:') === 0) ? data.substring(8) : data; console.log('QR code detected: ' + str); $searchInput .val(str) .triggerHandler('change') .triggerHandler('submit'); }; $scope.cancel = function() { _scanStop(); }; $uibModalInstance.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); }); }); // Source: public/src/js/controllers/search.js angular.module('insight.search').controller('SearchController', function($scope, $routeParams, $location, $timeout, Global, Block, Transaction, Address, BlockByHeight) { $scope.global = Global; $scope.loading = false; var _badQuery = function() { $scope.badQuery = true; $timeout(function() { $scope.badQuery = false; }, 2000); }; var _resetSearch = function() { $scope.q = ''; $scope.loading = false; }; $scope.search = function() { var q = $scope.q; $scope.badQuery = false; $scope.loading = true; Block.get({ blockHash: q }, function() { _resetSearch(); $location.path('address/' + q); }, function() { //address not found, search on TX Transaction.get({ txId: q }, function() { _resetSearch(); $location.path('tx/' + q); }, function() { //tx not found, search on Address Address.get({ addrStr: q }, function() { _resetSearch(); $location.path('block/' + q); }, function() { // block by height not found if (isFinite(q)) { // ensure that q is a finite number. A logical height value. BlockByHeight.get({ blockHeight: q }, function(hash) { _resetSearch(); $location.path('/block/' + hash.blockHash); }, function() { //not found, fail :( $scope.loading = false; _badQuery(); }); } else { $scope.loading = false; _badQuery(); } }); }); }); }; }); // Source: public/src/js/controllers/status.js angular.module('insight.status').controller('StatusController', function($scope, $routeParams, $location, Global, Status, Sync, getSocket) { $scope.global = Global; $scope.getStatus = function(q) { Status.get({ q: 'get' + q }, function(d) { $scope.loaded = 1; angular.extend($scope, d); }, function(e) { $scope.error = 'API ERROR: ' + e.data; }); }; $scope.humanSince = function(time) { var m = moment.unix(time / 1000); return m.max().fromNow(); }; var _onSyncUpdate = function(sync) { $scope.sync = sync; }; var _startSocket = function () { socket.emit('subscribe', 'sync'); socket.on('status', function(sync) { _onSyncUpdate(sync); }); }; var socket = getSocket($scope); socket.on('connect', function() { _startSocket(); }); $scope.getSync = function() { _startSocket(); Sync.get({}, function(sync) { _onSyncUpdate(sync); }, function(e) { var err = 'Could not get sync information' + e.toString(); $scope.sync = { error: err }; }); }; }); // Source: public/src/js/controllers/transactions.js angular.module('insight.transactions').controller('transactionsController', function($scope, $rootScope, $routeParams, $location, Global, Transaction, TransactionsByBlock, TransactionsByAddress) { $scope.global = Global; $scope.loading = false; $scope.loadedBy = null; var pageNum = 0; var pagesTotal = 1; var COIN = 100000000; var _aggregateItems = function(items) { if (!items) return []; var l = items.length; var ret = []; var tmp = {}; var u = 0; for(var i=0; i < l; i++) { var notAddr = false; // non standard input if (items[i].scriptSig && !items[i].addr) { items[i].addr = 'Unparsed address [' + u++ + ']'; items[i].notAddr = true; notAddr = true; } // non standard output if (items[i].scriptPubKey && !items[i].scriptPubKey.addresses) { items[i].scriptPubKey.addresses = ['Unparsed address [' + u++ + ']']; items[i].notAddr = true; notAddr = true; } // multiple addr at output if (items[i].scriptPubKey && items[i].scriptPubKey.addresses.length > 1) { items[i].addr = items[i].scriptPubKey.addresses.join(','); ret.push(items[i]); continue; } var addr = items[i].addr || (items[i].scriptPubKey && items[i].scriptPubKey.addresses[0]); if (!tmp[addr]) { tmp[addr] = {}; tmp[addr].valueSat = 0; tmp[addr].count = 0; tmp[addr].addr = addr; tmp[addr].items = []; } tmp[addr].isSpent = items[i].spentTxId; tmp[addr].doubleSpentTxID = tmp[addr].doubleSpentTxID || items[i].doubleSpentTxID; tmp[addr].doubleSpentIndex = tmp[addr].doubleSpentIndex || items[i].doubleSpentIndex; tmp[addr].dbError = tmp[addr].dbError || items[i].dbError; tmp[addr].valueSat += Math.round(items[i].value * COIN); tmp[addr].items.push(items[i]); tmp[addr].notAddr = notAddr; if (items[i].unconfirmedInput) tmp[addr].unconfirmedInput = true; tmp[addr].count++; } angular.forEach(tmp, function(v) { v.value = v.value || parseInt(v.valueSat) / COIN; ret.push(v); }); return ret; }; var _processTX = function(tx) { tx.vinSimple = _aggregateItems(tx.vin); tx.voutSimple = _aggregateItems(tx.vout); }; var _paginate = function(data) { $scope.loading = false; pagesTotal = data.pagesTotal; pageNum += 1; data.txs.forEach(function(tx) { _processTX(tx); $scope.txs.push(tx); }); }; var _byBlock = function() { TransactionsByBlock.get({ block: $routeParams.blockHash, pageNum: pageNum }, function(data) { _paginate(data); }); }; var _byAddress = function () { TransactionsByAddress.get({ address: $routeParams.addrStr, pageNum: pageNum }, function(data) { _paginate(data); }); }; var _findTx = function(txid) { Transaction.get({ txId: txid }, function(tx) { $rootScope.titleDetail = tx.txid.substring(0,7) + '...'; $rootScope.flashMessage = null; $scope.tx = tx; _processTX(tx); $scope.txs.unshift(tx); }, function(e) { if (e.status === 400) { $rootScope.flashMessage = 'Invalid Transaction ID: ' + $routeParams.txId; } else if (e.status === 503) { $rootScope.flashMessage = 'Backend Error. ' + e.data; } else { $rootScope.flashMessage = 'Transaction Not Found'; } $location.path('/'); }); }; $scope.findThis = function() { _findTx($routeParams.txId); }; //Initial load $scope.load = function(from) { $scope.loadedBy = from; $scope.loadMore(); }; //Load more transactions for pagination $scope.loadMore = function() { if (pageNum < pagesTotal && !$scope.loading) { $scope.loading = true; if ($scope.loadedBy === 'address') { _byAddress(); } else { _byBlock(); } } }; // Highlighted txout if ($routeParams.v_type == '>' || $routeParams.v_type == '<') { $scope.from_vin = $routeParams.v_type == '<' ? true : false; $scope.from_vout = $routeParams.v_type == '>' ? true : false; $scope.v_index = parseInt($routeParams.v_index); $scope.itemsExpanded = true; } //Init without txs $scope.txs = []; $scope.$on('tx', function(event, txid) { _findTx(txid); }); }); angular.module('insight.transactions').controller('SendRawTransactionController', function($scope, $http) { $scope.transaction = ''; $scope.status = 'ready'; // ready|loading|sent|error $scope.txid = ''; $scope.error = null; $scope.formValid = function() { return !!$scope.transaction; }; $scope.send = function() { var postData = { rawtx: $scope.transaction }; $scope.status = 'loading'; $http.post(window.apiPrefix + '/tx/send', postData) .success(function(data, status, headers, config) { if(typeof(data.txid) != 'string') { // API returned 200 but the format is not known $scope.status = 'error'; $scope.error = 'The transaction was sent but no transaction id was got back'; return; } $scope.status = 'sent'; $scope.txid = data.txid; }) .error(function(data, status, headers, config) { $scope.status = 'error'; if(data) { $scope.error = data; } else { $scope.error = "No error message given (connection error?)" } }); }; }); // Source: public/src/js/services/address.js angular.module('insight.address').factory('Address', function($resource) { return $resource(window.apiPrefix + '/addr/:addrStr/?noTxList=1', { addrStr: '@addStr' }, { get: { method: 'GET', interceptor: { response: function (res) { return res.data; }, responseError: function (res) { if (res.status === 404) { return res; } } } } }); }); // Source: public/src/js/services/blocks.js angular.module('insight.blocks') .factory('Block', function($resource) { return $resource(window.apiPrefix + '/block/:blockHash', { blockHash: '@blockHash' }, { get: { method: 'GET', interceptor: { response: function (res) { return res.data; }, responseError: function (res) { if (res.status === 404) { return res; } } } } }); }) .factory('Blocks', function($resource) { return $resource(window.apiPrefix + '/blocks'); }) .factory('BlockByHeight', function($resource) { return $resource(window.apiPrefix + '/block-index/:blockHeight'); }); // Source: public/src/js/services/currency.js angular.module('insight.currency').factory('Currency', function($resource) { return $resource(window.apiPrefix + '/currency'); }); // Source: public/src/js/services/global.js //Global service for global variables angular.module('insight.system') .factory('Global',[ function() { return { get: function () { return null; } } } ]) .factory('Version', function($resource) { return $resource(window.apiPrefix + '/version'); }); // Source: public/src/js/services/richlist.js angular.module('insight.richlist').factory('RichList', function ($resource) { return $resource(window.apiPrefix + '/richlist'); }); // Source: public/src/js/services/socket.js var ScopedSocket = function(socket, $rootScope) { this.socket = socket; this.$rootScope = $rootScope; this.listeners = []; }; ScopedSocket.prototype.removeAllListeners = function(opts) { if (!opts) opts = {}; for (var i = 0; i < this.listeners.length; i++) { var details = this.listeners[i]; if (opts.skipConnect && details.event === 'connect') { continue; } this.socket.removeListener(details.event, details.fn); } this.listeners = []; }; ScopedSocket.prototype.on = function(event, callback) { var socket = this.socket; var $rootScope = this.$rootScope; var wrapped_callback = function() { var args = arguments; $rootScope.$apply(function() { callback.apply(socket, args); }); }; socket.on(event, wrapped_callback); this.listeners.push({ event: event, fn: wrapped_callback }); }; ScopedSocket.prototype.emit = function(event, data, callback) { var socket = this.socket; var $rootScope = this.$rootScope; var args = Array.prototype.slice.call(arguments); args.push(function() { var args = arguments; $rootScope.$apply(function() { if (callback) { callback.apply(socket, args); } }); }); socket.emit.apply(socket, args); }; angular.module('insight.socket').factory('getSocket', function($rootScope) { var socket = io.connect(null, { 'reconnect': true, 'reconnection delay': 500, }); return function(scope) { var scopedSocket = new ScopedSocket(socket, $rootScope); scope.$on('$destroy', function() { scopedSocket.removeAllListeners(); }); socket.on('connect', function() { scopedSocket.removeAllListeners({ skipConnect: true }); }); return scopedSocket; }; }); // Source: public/src/js/services/status.js angular.module('insight.status') .factory('Status', function($resource) { return $resource(window.apiPrefix + '/status', { q: '@q' }); }) .factory('Sync', function($resource) { return $resource(window.apiPrefix + '/sync'); }) .factory('PeerSync', function($resource) { return $resource(window.apiPrefix + '/peer'); }); // Source: public/src/js/services/transactions.js angular.module('insight.transactions') .factory('Transaction', function($resource) { return $resource(window.apiPrefix + '/tx/:txId', { txId: '@txId' }, { get: { method: 'GET', interceptor: { response: function (res) { return res.data; }, responseError: function (res) { if (res.status === 404) { return res; } } } } }); }) .factory('TransactionsByBlock', function($resource) { return $resource(window.apiPrefix + '/txs', { block: '@block' }); }) .factory('TransactionsByAddress', function($resource) { return $resource(window.apiPrefix + '/txs', { address: '@address' }); }) .factory('Transactions', function($resource) { return $resource(window.apiPrefix + '/txs'); }); // Source: public/src/js/directives.js angular.module('insight') .directive('scroll', function ($window) { return function(scope, element, attrs) { angular.element($window).bind('scroll', function() { if (this.pageYOffset >= 200) { scope.secondaryNavbar = true; } else { scope.secondaryNavbar = false; } scope.$apply(); }); }; }) .directive('whenScrolled', function($window) { return { restric: 'A', link: function(scope, elm, attr) { var pageHeight, clientHeight, scrollPos; $window = angular.element($window); var handler = function() { pageHeight = window.document.documentElement.scrollHeight; clientHeight = window.document.documentElement.clientHeight; scrollPos = window.pageYOffset; if (pageHeight - (scrollPos + clientHeight) === 0) { scope.$apply(attr.whenScrolled); } }; $window.on('scroll', handler); scope.$on('$destroy', function() { return $window.off('scroll', handler); }); } }; }) .directive('clipCopy', function() { return { restric: 'A', scope: { clipCopy: '=clipCopy' }, template: '<div class="tooltip fade right in" style="display: none;"><div class="tooltip-arrow"></div><div class="tooltip-inner">Copied!</div></div>', link: function(scope, elm) { elm.on('mousedown', function(event) { var text = scope.clipCopy; var textArea = document.createElement("textarea"); // Place in top-left corner of screen regardless of scroll position. textArea.style.position = 'fixed'; textArea.style.top = 0; textArea.style.left = 0; // Ensure it has a small width and height. Setting to 1px / 1em // doesn't work as this gives a negative w/h on some browsers. textArea.style.width = '2em'; textArea.style.height = '2em'; // We don't need padding, reducing the size if it does flash render. textArea.style.padding = 0; // Clean up any borders. textArea.style.border = 'none'; textArea.style.outline = 'none'; textArea.style.boxShadow = 'none'; // Avoid flash of white box if rendered for any reason. textArea.style.background = 'transparent'; var regex = /<br\s*[\/]?>/gi; textArea.value = text.replace(regex, "\n"); document.body.appendChild(textArea); textArea.select(); try { var successful = document.execCommand('copy'); document.execCommand("RemoveFormat"); var msg = successful ? 'successful' : 'unsuccessful'; //console.log('Copying text command was ' + msg); angular.element(elm[0].querySelector('.tooltip'))[0].style.display = "block"; angular.element(elm[0].querySelector('.tooltip'))[0].style.opacity = "1"; setTimeout(function(){ angular.element(elm[0].querySelector('.tooltip'))[0].style.opacity = "0"; angular.element(elm[0].querySelector('.tooltip'))[0].style.display = "none";}, 1000); } catch (err) { console.log('Oops, unable to copy'); } document.body.removeChild(textArea); }); } }; }) .directive('focus', function ($timeout) { return { scope: { trigger: '@focus' }, link: function (scope, element) { scope.$watch('trigger', function (value) { if (value === "true") { $timeout(function () { element[0].focus(); }); } }); } }; }); // Source: public/src/js/filters.js angular.module('insight') .filter('startFrom', function() { return function(input, start) { start = +start; //parse to int return input.slice(start); } }) .filter('split', function() { return function(input, delimiter) { var delimiter = delimiter || ','; return input.split(delimiter); } }); // Source: public/src/js/config.js //Setting up route angular.module('insight').config(function($routeProvider) { $routeProvider. when('/block/:blockHash', { templateUrl: 'views/block.html', title: 'Help Block ' }). when('/block-index/:blockHeight', { controller: 'BlocksController', templateUrl: 'views/redirect.html' }). when('/tx/send', { templateUrl: 'views/transaction_sendraw.html', title: 'Broadcast Raw Transaction' }). when('/tx/:txId/:v_type?/:v_index?', { templateUrl: 'views/transaction.html', title: 'Help Transaction ' }). when('/', { templateUrl: 'views/index.html', title: 'Home' }). when('/blocks', { templateUrl: 'views/block_list.html', title: 'Help Blocks solved Today' }). when('/blocks-date/:blockDate/:startTimestamp?', { templateUrl: 'views/block_list.html', title: 'Help Blocks solved ' }). when('/address/:addrStr', { templateUrl: 'views/address.html', title: 'Help Address ' }). when('/status', { templateUrl: 'views/status.html', title: 'Status' }). when('/messages/verify', { templateUrl: 'views/messages_verify.html', title: 'Verify Message' }). when('/richlist', { templateUrl: 'views/richlist.html', title: 'Rich list' }) .otherwise({ templateUrl: 'views/404.html', title: 'Error' }); }); //Setting HTML5 Location Mode angular.module('insight') .config(function($locationProvider) { $locationProvider.html5Mode(true); $locationProvider.hashPrefix('!'); }) .run(function($rootScope, $route, $location, $routeParams, $anchorScroll, ngProgressFactory, gettextCatalog, amMoment) { var ngProgress = ngProgressFactory.createInstance(); gettextCatalog.currentLanguage = defaultLanguage; amMoment.changeLocale(defaultLanguage); $rootScope.$on('$routeChangeStart', function() { ngProgress.start(); }); $rootScope.$on('$routeChangeSuccess', function() { ngProgress.complete(); //Change page title, based on Route information $rootScope.titleDetail = ''; $rootScope.title = $route.current.title; $rootScope.isCollapsed = true; $rootScope.currentAddr = null; $location.hash($routeParams.scrollTo); $anchorScroll(); }); }); // Source: public/src/js/init.js angular.element(document).ready(function() { // Init the app // angular.bootstrap(document, ['insight']); }); // Source: public/src/js/translations.js angular.module('insight').run(['gettextCatalog', function (gettextCatalog) { /* jshint -W100 */ gettextCatalog.setStrings('de_DE', {"(Input unconfirmed)":"(Eingabe unbestätigt)","404 Page not found :(":"404 Seite nicht gefunden :(","<strong>insight</strong> is an <a href=\"http://live.insight.is/\" target=\"_blank\">open-source Help blockchain explorer</a> with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by helpd RPC. Check out the <a href=\"https://github.com/gohelpfund/insight-ui\" target=\"_blank\">source code</a>.":"<strong>insight</strong> ist ein <a href=\"http://live.insight.is/\" target=\"_blank\">Open Source Help Blockchain Explorer</a> mit vollständigen REST und Websocket APIs um eigene Wallets oder Applikationen zu implementieren. Hierbei werden fortschrittlichere Abfragen der Blockchain ermöglicht, bei denen die RPC des helpd nicht mehr ausreichen. Der aktuelle <a href=\"https://github.com/gohelpfund/insight-ui\" target=\"_blank\">Quellcode</a> ist auf Github zu finden.","<strong>insight</strong> is still in development, so be sure to report any bugs and provide feedback for improvement at our <a href=\"https://github.com/gohelpfund/insight/issues\" target=\"_blank\">github issue tracker</a>.":"<strong>insight</strong> befindet sich aktuell noch in der Entwicklung. Bitte sende alle gefundenen Fehler (Bugs) und Feedback zur weiteren Verbesserung an unseren <a href=\"https://github.com/gohelpfund/insight-ui/issues\" target=\"_blank\">Github Issue Tracker</a>.","About":"Über insight","Address":"Adresse","Age":"Alter","Application Status":"Programmstatus","Best Block":"Bester Block","Help node information":"Help-Node Info","Block":"Block","Block Reward":"Belohnung","Blocks":"Blöcke","Bytes Serialized":"Serialisierte Bytes","Can't connect to helpd to get live updates from the p2p network. (Tried connecting to helpd at {{host}}:{{port}} and failed.)":"Es ist nicht möglich mit helpd zu verbinden um live Aktualisierungen vom P2P Netzwerk zu erhalten. (Verbindungsversuch zu helpd an {{host}}:{{port}} ist fehlgeschlagen.)","Can't connect to insight server. Attempting to reconnect...":"Keine Verbindung zum insight-Server möglich. Es wird versucht die Verbindung neu aufzubauen...","Can't connect to internet. Please, check your connection.":"Keine Verbindung zum Internet möglich, bitte Zugangsdaten prüfen.","Complete":"Vollständig","Confirmations":"Bestätigungen","Conn":"Verbindungen","Connections to other nodes":"Verbindungen zu Nodes","Current Blockchain Tip (insight)":"Aktueller Blockchain Tip (insight)","Current Sync Status":"Aktueller Status","Details":"Details","Difficulty":"Schwierigkeit","Double spent attempt detected. From tx:":"Es wurde ein \"double Spend\" Versuch erkannt.Von tx:","Error!":"Fehler!","Fee":"Gebühr","Final Balance":"Schlussbilanz","Finish Date":"Fertigstellung","Go to home":"Zur Startseite","Hash Serialized":"Hash Serialisiert","Height":"Höhe","Included in Block":"Eingefügt in Block","Incoherence in levelDB detected:":"Es wurde eine Zusammenhangslosigkeit in der LevelDB festgestellt:","Info Errors":"Fehlerbeschreibung","Initial Block Chain Height":"Ursprüngliche Blockchain Höhe","Input":"Eingänge","Last Block":"Letzter Block","Last Block Hash (helpd)":"Letzter Hash (helpd)","Latest Blocks":"Letzte Blöcke","Latest Transactions":"Letzte Transaktionen","Loading Address Information":"Lade Adressinformationen","Loading Block Information":"Lade Blockinformation","Loading Selected Date...":"Lade gewähltes Datum...","Loading Transaction Details":"Lade Transaktionsdetails","Loading Transactions...":"Lade Transaktionen...","Loading...":"Lade...","Mined Time":"Block gefunden (Mining)","Mined by":"Gefunden von","Mining Difficulty":"Schwierigkeitgrad","Next Block":"Nächster Block","No Inputs (Newly Generated Coins)":"Keine Eingänge (Neu generierte Coins)","No blocks yet.":"Keine Blöcke bisher.","No matching records found!":"Keine passenden Einträge gefunden!","No. Transactions":"Anzahl Transaktionen","Number Of Transactions":"Anzahl der Transaktionen","Output":"Ausgänge","Powered by":"Powered by","Previous Block":"Letzter Block","Protocol version":"Protokollversion","Proxy setting":"Proxyeinstellung","Received Time":"Eingangszeitpunkt","Redirecting...":"Umleitung...","Search for block, transaction or address":"Suche Block, Transaktion oder Adresse","See all blocks":"Alle Blöcke anzeigen","Show Transaction Output data":"Zeige Abgänge","Show all":"Zeige Alles","Show input":"Zeige Eingänge","Show less":"Weniger anzeigen","Show more":"Mehr anzeigen","Size":"Größe","Size (bytes)":"Größe (bytes)","Skipped Blocks (previously synced)":"Verworfene Blöcke (bereits syncronisiert)","Start Date":"Startdatum","Status":"Status","Summary":"Zusammenfassung","Summary <small>confirmed</small>":"Zusammenfassung <small>bestätigt</small>","Sync Progress":"Fortschritt","Sync Status":"Syncronisation","Sync Type":"Art der Syncronisation","Synced Blocks":"Syncronisierte Blöcke","Testnet":"Testnet aktiv","There are no transactions involving this address.":"Es gibt keine Transaktionen zu dieser Adressse","Time Offset":"Zeitoffset zu UTC","Timestamp":"Zeitstempel","Today":"Heute","Total Amount":"Gesamtsumme","Total Received":"Insgesamt empfangen","Total Sent":"Insgesamt gesendet","Transaction":"Transaktion","Transaction Output Set Information":"Transaktions Abgänge","Transaction Outputs":"Abgänge","Transactions":"Transaktionen","Type":"Typ","Unconfirmed":"Unbestätigt","Unconfirmed Transaction!":"Unbestätigte Transaktion!","Unconfirmed Txs Balance":"Unbestätigtes Guthaben","Value Out":"Wert","Version":"Version","Waiting for blocks...":"Warte auf Blöcke...","Waiting for transactions...":"Warte auf Transaktionen...","by date.":"nach Datum.","first seen at":"zuerst gesehen am","mined":"gefunden","mined on:":"vom:","Waiting for blocks":"Warte auf Blöcke"}); gettextCatalog.setStrings('es', {"(Input unconfirmed)":"(Entrada sin confirmar)","404 Page not found :(":"404 Página no encontrada :(","<strong>insight</strong> is an <a href=\"http://live.insight.is/\" target=\"_blank\">open-source Help blockchain explorer</a> with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by helpd RPC. Check out the <a href=\"https://github.com/gohelpfund/insight-ui\" target=\"_blank\">source code</a>.":"<strong>insight</strong> es un <a href=\"http://live.insight.is/\" target=\"_blank\">explorador de bloques de Help open-source</a> con un completo conjunto de REST y APIs de websockets que pueden ser usadas para escribir monederos de Helps y otras aplicaciones que requieran consultar un explorador de bloques. Obtén el código en <a href=\"http://github.com/gohelpfund/insight\" target=\"_blank\">el repositorio abierto de Github</a>.","<strong>insight</strong> is still in development, so be sure to report any bugs and provide feedback for improvement at our <a href=\"https://github.com/gohelpfund/insight/issues\" target=\"_blank\">github issue tracker</a>.":"<strong>insight</strong> esta en desarrollo aún, por ello agradecemos que nos reporten errores o sugerencias para mejorar el software. <a href=\"https://github.com/gohelpfund/insight-ui/issues\" target=\"_blank\">Github issue tracker</a>.","About":"Acerca de","Address":"Dirección","Age":"Edad","Application Status":"Estado de la Aplicación","Best Block":"Mejor Bloque","Help node information":"Información del nodo Help","Block":"Bloque","Block Reward":"Bloque Recompensa","Blocks":"Bloqu