diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..dd48533 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,78 @@ +{ + "rules": { + # "indent": [ + # 2, + # 4 + # ], + # "linebreak-style": [ + # 2, + # "unix" + # ], + "semi": [ + 2, + "always" + ], + "angular/angularelement": 1, + "angular/controller-as": 2, + "angular/controller-as-route": 2, + "angular/controller-as-vm": [2, "vm"], + "angular/controller-name": [2, "/[A-Z].*Controller$/"], + "angular/deferred": 0, + "angular/definedundefined": 0, + "angular/di": [2, "function"], + "angular/di-order": [0, true], + "angular/directive-name": 0, + "angular/directive-restrict": [0, {"restrict": "AE", "explicit": "never"}], + "angular/component-limit": [0, 1], + "angular/document-service": 2, + "angular/empty-controller": 0, + "angular/file-name": 0, + "angular/filter-name": 0, + "angular/foreach": 0, + "angular/function-type": 0, + "angular/interval-service": 2, + "angular/json-functions": 2, + "angular/log": 0, + "angular/module-dependency-order": [0, {"grouped": true, "prefix": null}], + "angular/module-getter": 0, + "angular/module-name": 0, + "angular/module-setter": 2, + "angular/no-angular-mock": 0, + "angular/no-controller": 0, + "angular/no-cookiestore": 2, + "angular/no-digest": 2, + "angular/no-http-callback": 2, + "angular/no-inline-template": [0, {"allowSimple": true}], + "angular/no-jquery-angularelement": 2, + "angular/no-private-call": 2, + "angular/no-run-logic": [0, {"allowParams": true}], + "angular/no-service-method": 2, + "angular/no-services": [2, ["$http", "$resource", "Restangular"]], + "angular/on-watch": 2, + "angular/one-dependency-per-line": 0, + "angular/rest-service": 0, + "angular/service-name": 2, + "angular/timeout-service": 2, + "angular/typecheck-array": 2, + "angular/typecheck-date": 2, + "angular/typecheck-function": 2, + "angular/typecheck-number": 2, + "angular/typecheck-object": 2, + "angular/typecheck-regexp": 2, + "angular/typecheck-string": 2, + "angular/watchers-execution": [0, "$digest"], + "angular/window-service": 2 + }, + "env": { + "browser": true, + "jquery": true, + "jasmine": true, + "protractor": true, + "node": true, + }, + "globals": { + "window": true, + + }, + "extends": "angular" +} diff --git a/css/style.css b/css/style.css index 798a6de..8a413fc 100644 --- a/css/style.css +++ b/css/style.css @@ -372,6 +372,9 @@ h1 br { .Paired .q10-12{color:rgb(255,255,153)} .Paired .q11-12{color:rgb(177,89,40)} +.Red {color:red;} +.Black {color:black;} + /* ui grid */ .observations-grid { diff --git a/css/ui-grid.css b/css/ui-grid.css index 7da12b1..c893dac 100644 --- a/css/ui-grid.css +++ b/css/ui-grid.css @@ -579,8 +579,8 @@ input[type="text"].ui-grid-filter-input:hover { } @font-face { font-family: 'ui-grid'; - src: url('ui-grid.eot'); - src: url('ui-grid.eot#iefix') format('embedded-opentype'), url('ui-grid.woff') format('woff'), url('ui-grid.ttf?') format('truetype'), url('ui-grid.svg?#ui-grid') format('svg'); + src: url('../fonts/ui-grid.eot'); + src: url('../fonts/ui-grid.eot#iefix') format('embedded-opentype'), url('../fonts/ui-grid.woff') format('woff'), url('../fonts/ui-grid.ttf?') format('truetype'), url('../fonts/ui-grid.svg?#ui-grid') format('svg'); font-weight: normal; font-style: normal; } diff --git a/fonts/ui-grid.eot b/fonts/ui-grid.eot new file mode 100644 index 0000000..7c3e956 Binary files /dev/null and b/fonts/ui-grid.eot differ diff --git a/fonts/ui-grid.svg b/fonts/ui-grid.svg new file mode 100644 index 0000000..3556111 --- /dev/null +++ b/fonts/ui-grid.svg @@ -0,0 +1,34 @@ + + + +Copyright (C) 2016 by original authors @ fontello.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/ui-grid.ttf b/fonts/ui-grid.ttf new file mode 100644 index 0000000..9cee108 Binary files /dev/null and b/fonts/ui-grid.ttf differ diff --git a/fonts/ui-grid.woff b/fonts/ui-grid.woff new file mode 100644 index 0000000..fbbbb4e Binary files /dev/null and b/fonts/ui-grid.woff differ diff --git a/index.html b/index.html index ad45356..3c30343 100644 --- a/index.html +++ b/index.html @@ -94,7 +94,7 @@
0) { - UI.showUpdateValue("#update-data", -cost); - UI.showUpdateValue("#update-reputation", item.state.reputation); - } - }; - vs.showInfo = function (r) { - UI.showModal(r.name, r.getInfo()); - UI.showLevels(r.state.level); - }; - }]); + }; - app.controller('DetectorController', ['$scope', 'game', 'detector', function ($scope, game, detector) { + + function DetectorController($scope, game, detector, lab) { var vm = this; vm.elements = detector.elements; vm.dropOptions = { @@ -137,12 +140,12 @@ var app = (function () { vm.onDrop = function (event, ui) { var result = detector.onDrop(event, ui, game); if (result) - game.lab.observe(result); + lab.observe(result); }; vm.click = function () { - game.lab.clickDetector(); + lab.clickDetector(); detector.addEvent(); - UI.showUpdateValue("#update-data", game.lab.state.detector); + UI.showUpdateValue("#update-data", lab.state.detector); game.elements.addKnownToStore(); return false; }; @@ -152,100 +155,135 @@ var app = (function () { }; vm.clearAll = function () { detector.clearAll(game); - } - }]); + }; + }; + DetectorController.$inject = ['$scope', 'game', 'detector', 'lab']; + app.controller('DetectorController', DetectorController); - app.controller('LabController', ['$interval', 'game', 'detector', function ($interval, game, detector) { - this.lab = game.lab; - this.showDetectorInfo = function () { - if (!this._detectorInfo) { - this._detectorInfo = Helpers.loadFile('html/detector.html'); + + function LabController($interval, game, detector, lab) { + // todo give workers instead of game + var vm = this; + vm.lab = lab; + vm.showDetectorInfo = function () { + if (!vm._detectorInfo) { + vm._detectorInfo = Helpers.loadFile('html/detector.html'); } - UI.showModal('Detector', this._detectorInfo); + UI.showModal('Detector', vm._detectorInfo); }; $interval(function () { // one tick - var grant = game.lab.getGrant(); + var grant = lab.getGrant(); UI.showUpdateValue("#update-funding", grant); var sum = 0; for (var i = 0; i < game.workers.length; i++) { sum += game.workers[i].state.hired * game.workers[i].state.rate; } if (sum > 0) { - game.lab.acquireData(sum); + lab.acquireData(sum); UI.showUpdateValue("#update-data", sum); detector.addEventExternal(game.workers.map(function (w) { return w.state.hired; }).reduce(function (a, b) { - return a + b + return a + b; }, 0)); } }, 1000); - }]); + }; + LabController.$inject = ['$interval', 'game', 'detector', 'lab']; + app.controller('LabController', LabController); - app.controller('ObservationsController', ['$scope', 'game', function ($scope, game) { + + function ObservationsController($scope, game, lab) { var vm = this; - vm.observations = game.lab.state.observations; + vm.observations = lab.state.observations; vm.gridOptions = { enableFiltering: true, - columnDefs: [ - { field: 'inputs', filter:{}, visible:true}, - { field: 'reactants', visible:false}, - { field: 'results', visible:true, sort: { direction: 'asc' }}, - { field: 'catalysts', visible:false}, - { field: 'conditions', visible:false}, - ], + columnDefs: [{ + field: 'inputs', + filter: {}, + visible: true + }, { + field: 'reactants', + visible: false + }, { + field: 'results', + visible: true, + sort: { + direction: 'asc' + } + }, { + field: 'catalysts', + visible: false + }, { + field: 'conditions', + visible: false + }, ], data: vm.observations }; - }]); + }; + ObservationsController.$inject = ['$scope', 'game', 'lab']; + app.controller('ObservationsController', ObservationsController); - app.controller('UpgradesController', ['$scope', 'game', function ($scope, game) { - this.upgrades = game.upgrades; - this.isVisible = function (upgrade) { - return upgrade.isVisible(game.lab, game.allObjects); + function UpgradesController($scope, game, lab) { + var vm = this; + vm.upgrades = game.upgrades; + vm.isVisible = function (upgrade) { + return upgrade.isVisible(lab, game.allObjects); }; - this.isAvailable = function (upgrade) { - return upgrade.isAvailable(game.lab, game.allObjects); + vm.isAvailable = function (upgrade) { + return upgrade.isAvailable(lab, game.allObjects); }; - this.upgrade = function (upgrade) { - if (upgrade.buy(game.lab, game.allObjects)) { + vm.upgrade = function (upgrade) { + if (upgrade.buy(lab, game.allObjects)) { UI.showUpdateValue("#update-funding", upgrade.cost); } - } - }]); + }; + }; + UpgradesController.$inject = ['$scope', 'game', 'lab']; + app.controller('UpgradesController', UpgradesController); - app.controller('AchievementsController', function ($scope, game) { - $scope.achievements = game.achievements; - $scope.progress = function () { + function AchievementsController($scope, game, lab) { + var vm = this; + vm.achievements = game.achievements; + vm.progress = function () { return game.achievements.filter(function (a) { - return a.validate(game.lab, game.allObjects, game.lastSaved); + return a.validate(lab, game.allObjects, game.lastSaved); }).length; }; - }); + }; + AchievementsController.$inject = ['$scope', 'game', 'lab']; + app.controller('AchievementsController', AchievementsController); - app.controller('SaveController', ['$scope', '$interval', 'game', function ($scope, $interval, game) { + function SaveController($scope, $interval, $window, game, lab) { + var vm = this; game.lastSaved = new Date().getTime(); - $scope.lastSaved = game.lastSaved; - $scope.saveNow = function () { + vm.lastSaved = game.lastSaved; + vm.saveNow = function () { var saveTime = new Date().getTime(); - game.lab.state.time += saveTime - game.lastSaved; + lab.state.time += saveTime - game.lastSaved; game.save(); game.lastSaved = saveTime; - $scope.lastSaved = game.lastSaved; + vm.lastSaved = game.lastSaved; }; - $scope.restart = function () { - if (window.confirm( + vm.restart = function () { + if ($window.confirm( 'Do you really want to restart the game? All progress will be lost.' )) { ObjectStorage.clear(); - window.location.reload(true); + $window.location.reload(true); } }; - $interval($scope.saveNow, 10000); - }]); + $interval(vm.saveNow, 10000); + }; + SaveController.$inject = ['$scope', '$interval', '$window', 'game', 'lab']; + app.controller('SaveController', SaveController); - app.controller('StatsController', ['$scope', 'game', function ($scope, game) { - $scope.lab = game.lab; - }]); + function StatsController($scope, lab) { + var vm = this; + vm.lab = lab; + }; + StatsController.$inject = ['$scope', 'lab']; + app.controller('StatsController', StatsController); analytics.init(); analytics.sendScreen(analytics.screens.main); diff --git a/js/detector/detector.js b/js/detector/detector.js index ca789db..97282ba 100644 --- a/js/detector/detector.js +++ b/js/detector/detector.js @@ -6,8 +6,8 @@ var Detector = function(){ return { core: { - canvas: null, - ctx: null + // canvas: null, + // ctx: null }, // // events: @@ -19,8 +19,8 @@ var Detector = function(){ flame: { - canvas: null, - ctx: null + // canvas: null, + // ctx: null }, elements: new GameObjects.ElementStores(), @@ -39,15 +39,15 @@ var Detector = function(){ init: function(baseSize,element) { // get canvas - this.core.canvas = document.getElementById('detector-core'); - if (!this.core.canvas) { - this.core.canvas=$(''); - $(element).append(this.core.canvas); - } - this.core.ctx = this.core.canvas.getContext('2d'); - - this.flame.canvas = document.getElementById('detector-flame'); - this.flame.ctx = this.flame.canvas.getContext('2d'); + // this.core.canvas = document.getElementById('detector-core'); + // if (!this.core.canvas) { + // this.core.canvas=$(''); + // $(element).append(this.core.canvas); + // } + // this.core.ctx = this.core.canvas.getContext('2d'); + // + // this.flame.canvas = document.getElementById('detector-flame'); + // this.flame.ctx = this.flame.canvas.getContext('2d'); this.initBubbles(); this.initFlame(); @@ -130,8 +130,8 @@ var Detector = function(){ }, /** Clear an element back to element Store **/ - storeElementByHashKey: function(hashKey,game){ - var i = this.elements.findIndexByHashKey(hashKey); + storeElementBy: function(qObject,game){ + var i = _.findIndex(this.elements,qObject); var removedElement = this.elements.splice(i,1)[0]; return game.elements.get(removedElement.key).state.amount+=1; }, @@ -139,7 +139,7 @@ var Detector = function(){ clearAll: function(game){ var hashKeys = this.elements.map(function(e){return e.$$hashKey;}); for (var i = 0; i < hashKeys.length; i++) { - this.storeElementByHashKey(hashKeys[i], game); + this.storeElementBy({'$$hashKey': hashKeys[i]}, game); } }, @@ -231,7 +231,8 @@ var Detector = function(){ for (var i = 0; i < reactants.length; i++) { // get the uuid from inputs var ingredient = inputs.filter(function(e){return e.key===reactants[i];})[0]; - this.elements.findIndexByHashKey(ingredient.uuid); + var j = _.findIndex(this.elements,{uuid:ingredient.uuid}); + var removed = this.elements.slice(j,1); } // TODO use angular effects to remove in puff of fade diff --git a/js/game.js b/js/game.js index 979954e..912b27a 100644 --- a/js/game.js +++ b/js/game.js @@ -5,19 +5,20 @@ var Game = (function (Helpers, GameObjects, ObjectStorage) { 'use strict'; var Game = function () { - this.lab = new GameObjects.Lab(); + // this.lab = new GameObjects.Lab(); this.elements = null; this.workers = null; this.upgrades = null; this.achievements = null; this.allObjects = { - lab: this.lab + // lab: this.lab }; this.loaded = false; this.rules = null; }; - Game.prototype.load = function () { + Game.prototype.load = function ($http, $q) { + var self = this; if (this.loaded) { return; } @@ -27,50 +28,94 @@ var Game = (function (Helpers, GameObjects, ObjectStorage) { // make it work with Angular. If you know a way, let me know, and I'll // give you a beer. - Kevin this.elements = Helpers.loadFile('json/elements.json'); - this.workers = Helpers.loadFile('json/workers.json'); - this.upgrades = Helpers.loadFile('json/upgrades.json'); - this.achievements = Helpers.loadFile('json/achievements.json'); - this.keywords = Helpers.loadFile('json/keywords.json'); + this.workers = Helpers.loadFile('/json/workers.json'); + this.upgrades = Helpers.loadFile('./json/upgrades.json'); + this.achievements = Helpers.loadFile('./json/achievements.json'); + this.keywords = Helpers.loadFile('./json/keywords.json'); - // Turn JSON files into actual game objects and fill map of all objects - var _this = this; - var makeGameObject = function (type, object) { - // It's okay to define this function here since load is only called - // once anyway... - var o = new type(object); - _this.allObjects[o.key] = o; - return o; - }; - this.elements = this.elements.slice(0,20).map( - function (r) { - return makeGameObject(GameObjects.ElementStore, r); - }); - this.workers = this.workers.map( - function (w) { - return makeGameObject(GameObjects.Worker, w); - }); - this.upgrades = this.upgrades.map( - function (u) { - return makeGameObject(GameObjects.Upgrade, u); - }); - this.achievements = this.achievements.map( - function (a) { - return makeGameObject(GameObjects.Achievement, a); - }); - // Load states from local store - for (var key in this.allObjects) { - var o = this.allObjects[key]; - o.loadState(ObjectStorage.load(key)); - } + // function successCallback(response) { + // return angular.fromJson(response.data); + // } + // + // function errorCallback(response) { + // return console.error('Could not get url', response.statusText, response); + // } + // return $q.all( + // $http.get('json/elements.json', { + // transformResponse: angular.fromJson + // }) + // .then(function (response) { + // return self.elements = response.data; + // }), + // $http.get('json/workers.json', { + // transformResponse: angular.fromJson + // }) + // .then(function (response) { + // return self.workers = response.data; + // }), + // $http.get('json/upgrades.json', { + // transformResponse: angular.fromJson + // }) + // .then( + // function (response) { + // return self.upgrades = response.data; + // }), + // $http.get('json/achievements.json', { + // transformResponse: angular.fromJson + // }) + // .then( + // function (response) { + // return self.achievements = response.data; + // }), + // $http.get('json/keywords.json', { + // transformResponse: angular.fromJson + // }) + // .then( + // function (response) { + // return self.keywords = response.data; + // }) + // ).then(function () { - // put elements in extended array with utility methods - this.elementStore = new GameObjects.ElementStores(); - this.elementStore.push.apply(this.elementStore, this.elements); - this.elements = this.elementStore; + // Turn JSON files into actual game objects and fill map of all objects + var makeGameObject = function (type, object) { + // It's okay to define this function here since load is only called + // once anyway... + var o = new type(object); + self.allObjects[o.key] = o; + return o; + }; + self.elements = self.elements.slice(0, 20).map( + function (r) { + return makeGameObject(GameObjects.ElementStore, r); + }); + self.workers = self.workers.map( + function (w) { + return makeGameObject(GameObjects.Worker, w); + }); + self.upgrades = self.upgrades.map( + function (u) { + return makeGameObject(GameObjects.Upgrade, u); + }); + self.achievements = self.achievements.map( + function (a) { + return makeGameObject(GameObjects.Achievement, a); + }); + // Load states from local store + for (var key in self.allObjects) { + var o = self.allObjects[key]; + o.loadState(ObjectStorage.load(key)); + } - this.rules = this.generateRules(); + // put elements in extended array with utility methods + self.elementStore = new GameObjects.ElementStores(); + self.elementStore.push.apply(self.elementStore, self.elements); + self.elements = self.elementStore; - this.loaded = true; + self.rules = self.generateRules(); + + self.loaded = true; + return self; + // }); }; /** Generate rules between runes **/ diff --git a/js/helpers.js b/js/helpers.js index f2ba604..a903ba4 100644 --- a/js/helpers.js +++ b/js/helpers.js @@ -2,95 +2,102 @@ * Define some useful helpers that are used throughout the game. */ var Helpers = (function () { - 'use strict'; - /** Load a file (usually JSON). - */ - var loadFile = function (filename) { - var res; - $.ajax({ - async: false, - url : filename, - success : function(data) { - res = data; - } - }); - return res; - }; + 'use strict'; + /** Load a file (usually JSON). + */ + var loadFile = function (filename) { + var res; + $.ajax({ + async: false, + url: filename, + success: function (data) { + res = data; + } + }); + return res; + }; - var makeGameObject = function(type, object) { - // It's okay to define this function here since load is only called - // once anyway... - var o = new type(object); - _this.allObjects[o.key] = o; - return o; - }; + /** Format a number with proper postfix. + */ + var formatNumberPostfix = function (number) { + if (typeof number !== "number") { + return 0; + } - /** Format a number with proper postfix. - */ - var formatNumberPostfix = function (number) { - if (typeof number !== "number") { - return 0; + var prefixes = [{ + magnitude: 1e24, + label: 'Y' + }, { + magnitude: 1e21, + label: 'Z' + }, { + magnitude: 1e18, + label: 'E' + }, { + magnitude: 1e15, + label: 'P' + }, { + magnitude: 1e12, + label: 'T' + }, { + magnitude: 1e9, + label: 'B' + }, { + magnitude: 1e6, + label: 'M' + }, { + magnitude: 1e3, + label: 'k' + }]; + + var abs = Math.abs(number); + for (var i = 0; i < prefixes.length; i++) { + if (abs >= prefixes[i].magnitude) { + return (number / prefixes[i].magnitude).toFixed(1) + prefixes[i].label; + } + } + return number; } - var prefixes = [ - { magnitude: 1e24, label: 'Y' }, - { magnitude: 1e21, label: 'Z' }, - { magnitude: 1e18, label: 'E' }, - { magnitude: 1e15, label: 'P' }, - { magnitude: 1e12, label: 'T' }, - { magnitude: 1e9, label: 'B' }, - { magnitude: 1e6, label: 'M' }, - { magnitude: 1e3, label: 'k' } - ]; + var formatTime = function (msec) { + var totals = Math.ceil(msec / 1000); + var days = Math.floor(totals / (24 * 60 * 60)); + var hours = Math.floor((totals % (24 * 60 * 60)) / (60 * 60)); + var totalmin = (totals % (24 * 60 * 60)) % (60 * 60); + var mins = Math.floor(totalmin / 60); + var secs = totalmin % 60; - var abs = Math.abs(number); - for (var i = 0; i < prefixes.length; i++) { - if (abs >= prefixes[i].magnitude) { - return (number / prefixes[i].magnitude).toFixed(1) + prefixes[i].label; - } - } - return number; - } + var str = []; + if (days > 0) { + str.push(days + ' day' + (days % 100 == 1 ? '' : 's')); + } + if (hours > 0) { + str.push(hours + ' h'); + } + if (mins > 0) { + str.push(mins + ' min'); + } + if (secs > 0) { + str.push(secs + ' s'); + } - var formatTime = function (msec) { - var totals = Math.ceil(msec / 1000); - var days = Math.floor(totals / (24 * 60 * 60)); - var hours = Math.floor((totals % (24 * 60 * 60)) / (60 * 60)); - var totalmin = (totals % (24 * 60 * 60)) % (60 * 60); - var mins = Math.floor(totalmin / 60); - var secs = totalmin % 60; + return str.join(', '); + }; - var str = []; - if (days > 0) { - str.push(days + ' day' + (days % 100 == 1 ? '' : 's')); - } - if (hours > 0) { - str.push(hours + ' h'); - } - if (mins > 0) { - str.push(mins + ' min'); - } - if (secs > 0) { - str.push(secs + ' s'); - } + var saveVersion = '1.0'; + var validateSaveVersion = function () { + var ver = ObjectStorage.load('saveVersion'); + if (typeof ver === 'undefined' || ver != saveVersion) { + ObjectStorage.clear(); + ObjectStorage.save('saveVersion', saveVersion); + } + }; - return str.join(', '); - }; - - var saveVersion = '1.0'; - var validateSaveVersion = function () { - var ver = ObjectStorage.load('saveVersion'); - if (typeof ver === 'undefined' || ver != saveVersion) { - ObjectStorage.clear(); - ObjectStorage.save('saveVersion', saveVersion); - } - }; - - return { - loadFile: loadFile, - formatNumberPostfix: formatNumberPostfix, - formatTime: formatTime, - validateSaveVersion: validateSaveVersion, - analytics: '' - }; + return { + loadFile: loadFile, + formatNumberPostfix: formatNumberPostfix, + formatTime: formatTime, + validateSaveVersion: validateSaveVersion, + analytics: '' + }; })(); diff --git a/json/elements.json b/json/elements.json index bc51132..b2655f8 100644 --- a/json/elements.json +++ b/json/elements.json @@ -1,83 +1,59 @@ -[ - {"key":"ᚠ"}, - {"key":"ᚡ"}, - {"key":"ᚢ"}, - {"key":"ᚣ"}, - {"key":"ᚤ"}, - {"key":"ᚥ"}, - {"key":"ᚦ"}, - {"key":"ᚧ"}, - {"key":"ᚨ"}, - {"key":"ᚩ"}, - {"key":"ᚪ"}, - {"key":"ᚫ"}, - {"key":"ᚬ"}, - {"key":"ᚭ"}, - {"key":"ᚮ"}, - {"key":"ᚯ"}, - {"key":"ᚰ"}, - {"key":"ᚱ"}, - {"key":"ᚲ"}, - {"key":"ᚳ"}, - {"key":"ᚴ"}, - {"key":"ᚵ"}, - {"key":"ᚶ"}, - {"key":"ᚷ"}, - {"key":"ᚸ"}, - {"key":"ᚹ"}, - {"key":"ᚺ"}, - {"key":"ᚻ"}, - {"key":"ᚼ"}, - {"key":"ᚽ"}, - {"key":"ᚾ"}, - {"key":"ᚿ"}, - {"key":"ᛀ"}, - {"key":"ᛁ"}, - {"key":"ᛂ"}, - {"key":"ᛃ"}, - {"key":"ᛄ"}, - {"key":"ᛅ"}, - {"key":"ᛆ"}, - {"key":"ᛇ"}, - {"key":"ᛈ"}, - {"key":"ᛉ"}, - {"key":"ᛊ"}, - {"key":"ᛋ"}, - {"key":"ᛌ"}, - {"key":"ᛍ"}, - {"key":"ᛎ"}, - {"key":"ᛏ"}, - {"key":"ᛐ"}, - {"key":"ᛑ"}, - {"key":"ᛒ"}, - {"key":"ᛓ"}, - {"key":"ᛔ"}, - {"key":"ᛕ"}, - {"key":"ᛖ"}, - {"key":"ᛗ"}, - {"key":"ᛘ"}, - {"key":"ᛙ"}, - {"key":"ᛚ"}, - {"key":"ᛛ"}, - {"key":"ᛜ"}, - {"key":"ᛝ"}, - {"key":"ᛞ"}, - {"key":"ᛟ"}, - {"key":"ᛠ"}, - {"key":"ᛡ"}, - {"key":"ᛢ"}, - {"key":"ᛣ"}, - {"key":"ᛤ"}, - {"key":"ᛥ"}, - {"key":"ᛦ"}, - {"key":"ᛧ"}, - {"key":"ᛨ"}, - {"key":"ᛩ"}, - {"key":"ᛪ"}, - {"key":"᛫"}, - {"key":"᛬"}, - {"key":"᛭"}, - {"key":"ᛮ"}, - {"key":"ᛯ"}, - {"key":"ᛰ"} -] +[{"key": "🂡","name":"Ace","value":"1","suite":"Spades","color":"Black","royal":"false","face":"false","number":"false"}, +{"key": "🂢","name":"Two","value":"2","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🂣","name":"Three","value":"3","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🂤","name":"Four","value":"4","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🂥","name":"Five","value":"5","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🂦","name":"Six","value":"6","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🂧","name":"Seven","value":"7","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🂨","name":"Eight","value":"8","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🂩","name":"Nine","value":"9","suite":"Spades","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🂪","name":"Ten","value":"10","suite":"Spades","color":"Black","royal":"false","face":"true","number":"true"}, +{"key": "🂫","name":"Jack","value":"11","suite":"Spades","color":"Black","royal":"true","face":"true","number":"false"}, +{"key": "🂬","name":"Knight","value":"12","suite":"Spades","color":"Black","royal":"true","face":"true","number":"false"}, +{"key": "🂭","name":"Queen","value":"13","suite":"Spades","color":"Black","royal":"true","face":"true","number":"false"}, +{"key": "🂮","name":"King","value":"14","suite":"Spades","color":"Black","royal":"true","face":"true","number":"false"}, +{"key": "🂱","name":"Ace","value":"1","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"false"}, +{"key": "🂲","name":"Two","value":"2","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🂳","name":"Three","value":"3","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🂴","name":"Four","value":"4","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🂵","name":"Five","value":"5","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🂶","name":"Six","value":"6","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🂷","name":"Seven","value":"7","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🂸","name":"Eight","value":"8","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🂹","name":"Nine","value":"9","suite":"Hearts","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🂺","name":"Ten","value":"10","suite":"Hearts","color":"Red","royal":"false","face":"true","number":"true"}, +{"key": "🂻","name":"Jack","value":"11","suite":"Hearts","color":"Red","royal":"true","face":"true","number":"false"}, +{"key": "🂼","name":"Knight","value":"12","suite":"Hearts","color":"Red","royal":"true","face":"true","number":"false"}, +{"key": "🂽","name":"Queen","value":"13","suite":"Hearts","color":"Red","royal":"true","face":"true","number":"false"}, +{"key": "🂾","name":"King","value":"14","suite":"Hearts","color":"Red","royal":"true","face":"true","number":"false"}, +{"key": "🃁","name":"Ace","value":"1","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"false"}, +{"key": "🃂","name":"Two","value":"2","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🃃","name":"Three","value":"3","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🃄","name":"Four","value":"4","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🃅","name":"Five","value":"5","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🃆","name":"Six","value":"6","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🃇","name":"Seven","value":"7","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🃈","name":"Eight","value":"8","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🃉","name":"Nine","value":"9","suite":"Diamonds","color":"Red","royal":"false","face":"false","number":"true"}, +{"key": "🃊","name":"Ten","value":"10","suite":"Diamonds","color":"Red","royal":"false","face":"true","number":"true"}, +{"key": "🃋","name":"Jack","value":"11","suite":"Diamonds","color":"Red","royal":"true","face":"true","number":"false"}, +{"key": "🃌","name":"Knight","value":"12","suite":"Diamonds","color":"Red","royal":"true","face":"true","number":"false"}, +{"key": "🃍","name":"Queen","value":"13","suite":"Diamonds","color":"Red","royal":"true","face":"true","number":"false"}, +{"key": "🃎","name":"King","value":"14","suite":"Diamonds","color":"Red","royal":"true","face":"true","number":"false"}, +{"key": "🃑","name":"Ace","value":"1","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"false"}, +{"key": "🃒","name":"Two","value":"2","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🃓","name":"Three","value":"3","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🃔","name":"Four","value":"4","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🃕","name":"Five","value":"5","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🃖","name":"Six","value":"6","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🃗","name":"Seven","value":"7","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🃘","name":"Eight","value":"8","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🃙","name":"Nine","value":"9","suite":"Clubs","color":"Black","royal":"false","face":"false","number":"true"}, +{"key": "🃚","name":"Ten","value":"10","suite":"Clubs","color":"Black","royal":"false","face":"true","number":"true"}, +{"key": "🃛","name":"Jack","value":"11","suite":"Clubs","color":"Black","royal":"true","face":"true","number":"false"}, +{"key": "🃜","name":"Knight","value":"12","suite":"Clubs","color":"Black","royal":"true","face":"true","number":"false"}, +{"key": "🃝","name":"Queen","value":"13","suite":"Clubs","color":"Black","royal":"true","face":"true","number":"false"}, +{"key": "🃞","name":"King","value":"14","suite":"Clubs","color":"Black","royal":"true","face":"true","number":"false"}, +{"key": "🂠","name":"Playing Card","value":"15","suite":"Black","color":"Black","royal":"false","face":"false","number":"false"}, +{"key": "🃏","name":"Joker","value":"16","suite":"Black","color":"Black","royal":"false","face":"true","number":"false"}, +{"key": "🃟","name":"Joker","value":"16","suite":"Red","color":"Red","royal":"false","face":"true","number":"false"}] diff --git a/package.json b/package.json new file mode 100644 index 0000000..0af1108 --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "name": "sciencealchemy", + "version": "0.0.5", + "description": "Science Alchemy", + "main": "js/app.js", + "directories": { + "test": "tests" + }, + "scripts": { + "postinstall": "bower install", + "prestart": "npm install", + "start": "http-server -a 0.0.0.0 -p 8000", + "pretest": "npm install", + "test": "node node_modules/karma/bin/karma start test/karma.conf.js", + "test-single-run": "node node_modules/karma/bin/karma start test/karma.conf.js --single-run", + "preupdate-webdriver": "npm install", + "update-webdriver": "webdriver-manager update", + "preprotractor": "npm run update-webdriver", + "protractor": "protractor test/protractor-conf.js", + "update-index-async": "node -e \"require('shelljs/global'); sed('-i', /\\/\\/@@NG_LOADER_START@@[\\s\\S]*\\/\\/@@NG_LOADER_END@@/, '//@@NG_LOADER_START@@\\n' + cat('bower_components/angular-loader/angular-loader.min.js') + '\\n//@@NG_LOADER_END@@', 'app/index-async.html');\"" + }, + "author": "wassname", + "license": "MIT", + "devDependencies": { + "bower": "^1.7.7", + "eslint": "^2.2.0", + "eslint-config-angular": "^0.4.0", + "eslint-plugin-angular": "^0.15.0", + "http-server": "^0.9.0", + "jasmine": "^2.4.1", + "karma": "^0.13.21", + "karma-chrome-launcher": "^0.2.2", + "karma-firefox-launcher": "^0.1.7", + "karma-jasmine": "^0.3.7", + "ng-html2js": "^2.0.0", + "protractor": "^3.1.1", + "shelljs": "^0.6.0", + "tmp": "0.0.28", + "webdriver": "0.0.1" + } +} diff --git a/test/e2e/scenarios.js b/test/e2e/scenarios.js new file mode 100644 index 0000000..79b5b6e --- /dev/null +++ b/test/e2e/scenarios.js @@ -0,0 +1,101 @@ +'use strict'; + +/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */ + +describe('PhoneCat App', function() { + + it('should redirect index.html to index.html#/phones', function() { + browser.get('app/index.html'); + browser.getLocationAbsUrl().then(function(url) { + expect(url).toEqual('/phones'); + }); + }); + + + describe('Phone list view', function() { + + beforeEach(function() { + browser.get('app/index.html#/phones'); + }); + + + it('should filter the phone list as a user types into the search box', function() { + + var phoneList = element.all(by.repeater('phone in phones')); + var query = element(by.model('query')); + + expect(phoneList.count()).toBe(20); + + query.sendKeys('nexus'); + expect(phoneList.count()).toBe(1); + + query.clear(); + query.sendKeys('motorola'); + expect(phoneList.count()).toBe(8); + }); + + + it('should be possible to control phone order via the drop down select box', function() { + + var phoneNameColumn = element.all(by.repeater('phone in phones').column('phone.name')); + var query = element(by.model('query')); + + function getNames() { + return phoneNameColumn.map(function(elm) { + return elm.getText(); + }); + } + + query.sendKeys('tablet'); //let's narrow the dataset to make the test assertions shorter + + expect(getNames()).toEqual([ + "Motorola XOOM\u2122 with Wi-Fi", + "MOTOROLA XOOM\u2122" + ]); + + element(by.model('orderProp')).element(by.css('option[value="name"]')).click(); + + expect(getNames()).toEqual([ + "MOTOROLA XOOM\u2122", + "Motorola XOOM\u2122 with Wi-Fi" + ]); + }); + + + it('should render phone specific links', function() { + var query = element(by.model('query')); + query.sendKeys('nexus'); + element.all(by.css('.phones li a')).first().click(); + browser.getLocationAbsUrl().then(function(url) { + expect(url).toEqual('/phones/nexus-s'); + }); + }); + }); + + + describe('Phone detail view', function() { + + beforeEach(function() { + browser.get('app/index.html#/phones/nexus-s'); + }); + + + it('should display nexus-s page', function() { + expect(element(by.binding('phone.name')).getText()).toBe('Nexus S'); + }); + + + it('should display the first phone image as the main phone image', function() { + expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); + }); + + + it('should swap main image if a thumbnail image is clicked on', function() { + element(by.css('.phone-thumbs li:nth-child(3) img')).click(); + expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/); + + element(by.css('.phone-thumbs li:nth-child(1) img')).click(); + expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); + }); + }); +}); diff --git a/test/karma.conf.js b/test/karma.conf.js new file mode 100644 index 0000000..c0189b6 --- /dev/null +++ b/test/karma.conf.js @@ -0,0 +1,101 @@ +module.exports = function (config) { + config.set({ + + basePath: '../', + port: 9876, + // urlRoot: "/", + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + frameworks: ['jasmine'], + + browsers: ['Chrome', 'Firefox'], + + plugins: [ + 'karma-chrome-launcher', + 'karma-firefox-launcher', + 'karma-jasmine' + ], + + junitReporter: { + outputFile: 'test_out/unit.xml', + suite: 'unit' + }, + + preprocessors: { + "*.html": ["ng-html2js"] + }, + + // ngHtml2JsPreprocessor: { + // // If your build process changes the path to your templates, + // // use stripPrefix and prependPrefix to adjust it. + // // stripPrefix: "source/path/to/templates/.*/", + // // prependPrefix: "web/path/to/templates/", + // + // // the name of the Angular module to create + // moduleName: "scienceAlchemy.templates" + // }, + + + // use this to fix server 404 errors. Karma server everything at /base + proxies: { + '/json/': '/base/json/' + }, + + + // list of files / patterns to load in the browser + files: [ + + // dependencies + 'bower_components/jquery/dist/jquery.js', + 'bower_components/jquery-ui/jquery-ui.js', + 'bower_components/bootstrap/dist/js/bootstrap.js', + 'bower_components/angular/angular.js', + 'bower_components/angular-route/angular-route.js', + 'bower_components/angular-resource/angular-resource.js', + 'bower_components/angular-animate/angular-animate.js', + 'bower_components/angular-mocks/angular-mocks.js', + 'bower_components/angular-dragdrop/src/angular-dragdrop.js', + 'bower_components/angular-ui-grid/ui-grid.js', + 'bower_components/lodash/dist/lodash.js', + 'js/external/*.js', + + // fixtures + { + pattern: 'index.html', + watched: true, + served: true, + included: false + }, { + pattern: 'json/*.json', + watched: true, + served: true, + included: false + }, + { + pattern: 'css/*.css', + watched: true, + served: true, + included: false + }, + + // files to test + 'js/storage.js', + 'js/helpers.js', + 'js/analytics.js', + 'js/gameobjects.js', + 'js/detector/flame.js', + 'js/detector/bubblr.js', + 'js/detector/event.js', + 'js/detector/detector.js', + 'js/ui.js', + 'js/game.js', + 'js/app.js', + 'test/unit/**/*.js' + ], + }); +}; diff --git a/test/protractor-conf.js b/test/protractor-conf.js new file mode 100644 index 0000000..30c78c8 --- /dev/null +++ b/test/protractor-conf.js @@ -0,0 +1,22 @@ + +exports.config = { + allScriptsTimeout: 11000, + + specs: [ + 'e2e/*.js' + ], + + capabilities: { + 'browserName': 'chrome' + }, + + chromeOnly: true, + + baseUrl: 'http://localhost:8000/', + + framework: 'jasmine', + + jasmineNodeOpts: { + defaultTimeoutInterval: 30000 + } +}; diff --git a/test/unit/controllersSpec.js b/test/unit/controllersSpec.js new file mode 100644 index 0000000..f4a336c --- /dev/null +++ b/test/unit/controllersSpec.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jasmine specs for controllers go here */ +describe('scienceAlchemy controllers', function () { + var $controller; + + beforeEach(function () { + jasmine.addMatchers({ + toEqualData: function(util, customEqualityTesters) { + return { + compare: function(actual, expected) { + var passed = angular.equals(actual, expected); + return { + pass: passed, + message: 'Expected "' + actual + '"' + (passed ? '' : ' not') + ' to angular.equals "' + expected + '"' + }; + } + }; + } + }); + }); + beforeEach(module('scienceAlchemy')); + beforeEach(inject(function (_$controller_) { + // The injector unwraps the underscores (_) from around the parameter names when matching + $controller = _$controller_; + })); + + describe('ElementController', function () { + var $scope, controller; + + beforeEach(function () { + $scope = {}; + controller = $controller('ElementController',{$scope:$scope}); + }); + + it('should have elements', function () { + expect(controller.elements).toBeDefined(); + }); + + it('should be visible', function () { + var item = controller.elements[0]; + expect(controller.isVisible(item)).toBeDefined(); + }); + + it('should be isAvailable', function () { + var item = controller.elements[0]; + expect(controller.isAvailable(item)).toBeDefined(); + }); + + // onDrop + }); + +}); diff --git a/test/unit/directivesSpec.js b/test/unit/directivesSpec.js new file mode 100644 index 0000000..2e5469a --- /dev/null +++ b/test/unit/directivesSpec.js @@ -0,0 +1,7 @@ +'use strict'; + +/* jasmine specs for directives go here */ + +describe('directives', function() { + +}); diff --git a/test/unit/filtersSpec.js b/test/unit/filtersSpec.js new file mode 100644 index 0000000..43a61c7 --- /dev/null +++ b/test/unit/filtersSpec.js @@ -0,0 +1,53 @@ +'use strict'; + +/* jasmine specs for filters go here */ + +describe('filter', function () { + + beforeEach( + module('scienceAlchemy') + ); + + describe('niceNumber', function () { + it('should make numbers human readable', + inject(function (niceNumberFilter) { + expect(niceNumberFilter(100000000)).toBe("100.0M"); + expect(niceNumberFilter(10000)).toBe("10.0k"); + expect(niceNumberFilter(0.000000001)).toBe(1e-9); + + })); + }); + + describe('niceTime', function () { + it('should make time human readable', + inject(function (niceTimeFilter) { + expect(niceTimeFilter(100000000)).toBe("1 day, 3 h, 46 min, 40 s"); + expect(niceTimeFilter(10000)).toBe("10 s"); + expect(niceTimeFilter(0.000000001)).toBe("1 s"); + + })); + }); + + describe('currency', function () { + it('should make currency human readable', + inject(function (currencyFilter) { + expect(currencyFilter(100000000)).toBe("JTN 100.0M"); + expect(currencyFilter(10000)).toBe("JTN 10.0k"); + expect(currencyFilter(0.000000001)).toBe('JTN 1e-9'); + })); + }); + + describe('reverse', function () { + it('should reverse', + inject(function (reverseFilter) { + expect(reverseFilter([1,2,3])[0]).toBe(3); + expect(reverseFilter([1,2,3])[1]).toBe(2); + expect(reverseFilter([1,2,3])[2]).toBe(1); + expect(reverseFilter([]).length).toBe(0); + expect(reverseFilter([{i:1,2:2},{i:2},{i:3}])[0].i).toBe(3); + expect(reverseFilter([{i:1,2:2},{i:2},{i:3}])[1].i).toBe(2); + expect(reverseFilter([{i:1,2:2},{i:2},{i:3}])[2].i).toBe(1); + + })); + }); +}); diff --git a/test/unit/servicesSpec.js b/test/unit/servicesSpec.js new file mode 100644 index 0000000..d6bd752 --- /dev/null +++ b/test/unit/servicesSpec.js @@ -0,0 +1,27 @@ +'use strict'; + +describe('services', function () { + + //load modules + beforeEach(module('scienceAlchemy')); + + // Test service availability + describe('game', function () { + it('should exist', inject(function (game) { + expect(game).toBeDefined(); + })); + }); + + describe('detector', function () { + it('should exist', inject(function (detector) { + expect(detector).toBeDefined(); + })); + }); + + describe('lab', function () { + it('should exist', inject(function (lab) { + expect(lab).toBeDefined(); + })); + }); + +});