Converted to es6 imports and exports

This commit is contained in:
2016-12-10 12:54:33 +08:00
parent 68375a99a9
commit 8656333b1f
45 changed files with 13930 additions and 13902 deletions
+4 -2
View File
@@ -1,5 +1,5 @@
/** Custom google analystics events **/
var Helpers = require("js/helpers");
import Helpers from "js/helpers";
// google analystics async code
(function (i, s, o, g, r, a, m) {
@@ -14,7 +14,7 @@ var Helpers = require("js/helpers");
m.parentNode.insertBefore(a, m);
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
var analytics = module.exports =
var analytics =
{
enabled: true,
@@ -95,3 +95,5 @@ var analytics = module.exports =
}
}
};
export default analytics
+487 -485
View File
@@ -1,485 +1,487 @@
/**
* Define the angular app
*/
'use strict';
//deps
var jquery = require("jquery");
var jqueryUi = require("jquery-ui");
var jqueryUiTouchPunch = require("jquery-ui-touch-punch");
var jsCookie = require("js-cookie");
var angular = require("angular");
var angularDragdrop = require("angular-dragdrop");
var angularAnimate = require("angular-animate");
var angulartics = require('angulartics');
var angularticsGoogleAnalytics = require('angulartics-google-analytics');
var ngAlertify = require("alertify.js/dist/js/ngAlertify.js");
//app
var ObjectStorage = require("js/storage");
var Helpers = require("js/helpers");
var GameObjects = require("js/gameobjects");
var analytics = require("js/analytics");
var Game = require("js/game");
var Rules = require("js/rules.js");
var UI = require("js/ui.js");
var app = (function (Helpers,analytics,Game,Rules) {
Helpers.validateSaveVersion();
var app = angular.module('cardsForScience', ['ngDragDrop','ngAnimate','angulartics', angularticsGoogleAnalytics,"ngAlertify"]);
// config
app.config(function ($analyticsProvider) {
$analyticsProvider.firstPageview(true); /* Records pages that don't use $state or $route */
$analyticsProvider.withAutoBase(true); /* Records full path */
});
// directives
/**
* Make little "+2" "-1" score animations when score changes requires ng-model="score"
* Associated css:
* ```
* .update-value { // set constant height, and the position
position: relative;
right: -2em;
top: -1.42857em;
height: 1.42857em;
}
.update-plus { // if the change is +ve
color: green;
position: relative;
}
.update-minus {
color: red;
position: relative;
}
*/
function cfsScoreChange($compile) {
return {
link: function (scope, element, attrs) {
scope.$watch(attrs.ngModel, function (newValue, oldValue) {
// showUpdateValue
var num = newValue-oldValue;
var formatted = Helpers.formatNumberPostfix(num);
var insert;
if (num > 0) {
insert = angular.element("<div class=''></div>")
.attr("class", "update-plus")
.html("+" + formatted);
} else {
insert = angular.element("<div></div>")
.attr("class", "update-minus")
.html(formatted);
}
// TODO it would be better to use an ::after element for this
// showUpdate
element.append(insert);
insert.animate({
"bottom":"+=30px",
"opacity": 0
}, { duration: 500, complete: function() {
angular.element(this).remove();
}});
});
}
};
};
cfsScoreChange.$inject = ['$compile'];
app.directive('cfsScoreChange', cfsScoreChange);
/**
* Directive to render a rule and bind it's option with select boxes
* This expects ng-model="rule" as an attribute
*/
// function cfsRule($compile) {
// return {
// link: function (scope, element, attrs) {
// var rule = scope.$eval(attrs.ngModel);
//
// // first generate a select box for each option (using lodash templating)
// _.templateSettings.interpolate = /<%=([\s\S]+?)%>/g;
// var optionTmpl = '' +
// '<select \n' +
// ' name="<%=option%>" \n' +
// ' convert-to-number="{{rule.optionDesc.<%=option%>.type===\'Number\'}}" \n' +
// ' ng-model="rule.options.<%=option%>" \n' +
// ' class="form-control input-sm" \n' +
// ' ng-options="v for v in rule.optionDesc.<%=option%>.possibleVals track by v" \n' +
// '>\n' +
// '</select>\n';
//
// var tmplParams = _.defaults({},rule.options,rule.otherOptions);
// for (var option in rule.optionDesc) {
// if (rule.optionDesc.hasOwnProperty(option)) {
// var vals = rule.optionDesc[option].possibleVals;
// if (vals) {
// tmplParams[option] = _.template(optionTmpl)({
// option: option
// });
// } else {
// // if there are no options replace '{{color}}' with 'color'
// tmplParams[option] = option;
// }
// }
// }
// // now put each select box into description
// // replace '{{color}}' with '<select name="color"...'
// var template = _.template(rule.description)(tmplParams);
//
// // now compile with angular
// element.html(template).show();
// $compile(element.contents())(scope);
// }
// };
// };
// cfsRule.$inject = ['$compile'];
// app.directive('cfsRule', cfsRule);
// factories to provide services. They serve shared game objects
// app.factory('cards', function () {
// var cards = Helpers.loadFile('json/cards.json');
// cards = cards.map(
// function (r) {
// return new GameObjects.Card(r);
// });
// // put in extended array with helper methods
// Cards = new GameObjects.Cards();
// Cards.push.apply(Cards,cards);
// return Cards;
// });
function game($http, $q, lab) {
var game = new Game();
game.lab = lab;
game.allObjects.lab = lab;
var promise = game.load($http, $q);
game.reset();
// return promise;
return game;
};
game.$inject = ['$http', '$q', 'lab'];
app.factory('game', game);
function lab() {
if (!this.lab) this.lab = new GameObjects.Lab();
return this.lab;
};
app.factory('lab', lab);
// add helpers as filters
function niceNumber($filter) {
return Helpers.formatNumberPostfix;
};
niceNumber.$inject = ['$filter'];
app.filter('niceNumber', niceNumber);
/** transpose data for a table **/
// function transpose($filter) {
// return function (input) {
// return _.zip(input);
// };
// };
// transpose.$inject = ['$filter'];
// app.filter('transpose', transpose);
function boolToTick($filter) {
return function (input) {
if (input===true) return '✓';
else if (input===false) return '';
else return input;
};
};
boolToTick.$inject = ['$filter'];
app.filter('boolToTick', boolToTick);
function niceTime($filter) {
return Helpers.formatTime;
};
niceTime.$inject = ['$filter'];
app.filter('niceTime', niceTime);
function currency($filter) {
return function (input) {
return 'JTN ' + $filter('niceNumber')(input);
};
};
currency.$inject = ['$filter'];
app.filter('currency', currency);
function reverse($filter) {
return function (items) {
if (items instanceof Array)
return items.slice().reverse();
else
return items;
};
};
reverse.$inject = ['$filter'];
app.filter('reverse', reverse);
// controllers
app.controller('CardController', CardController);
CardController.$inject = ['$scope', '$compile', 'game', 'lab'];
function CardController($scope, $compile, game, lab) {
var vm = this;
vm.dataJqyouiOptions = {
revert: "invalid",
zIndex: 100,
cancel: false,
};
vm.jqyouiDraggable = {
containment:'offset',
onStart:'rc.dragStart(r)',
onStop:'rc.dragStop(r)',
animate:true,
};
vm.onClick = function (card) {
// don't click if it was dragged within .222 seconds
// (to prevent double firing)
if (!card.state.lastDragged || new Date()-new Date(card.state.lastDragged)>300)
game.play(card);
else
console.log('clickprevent',card.state.lastDragged);
};
vm.dragStart = function(event, ui,card){
card.state.lastDragged=new Date();
console.log('startDrag');
};
vm.dragStop = function(event, ui,card){
card.state.lastDragged=new Date();
console.log('endDrag');
};
vm.cards = game.cards;
vm.isVisible = function (item) {
return item.isVisible(lab);
};
vm.isAvailable = function (item) {
return item.isAvailable(lab);
};
};
function TableController($scope, game, lab, $filter) {
var vm = this;
vm.cards = detector.cards;
vm.ruleInfo = game.ruleInfo;
vm.hints = game.hints;
vm.limit = -12;
vm.hintCost = 10;
vm.ruleCost = 300;
vm.lastCards = game.lastCards;
vm.incorrectCards = game.incorrectCards;
vm.dataJqyouiOptions = {
// accept: ".rune",
addClasses: true,
// greedy: true,
// tolerance: "pointer",
activeClass: "ui-state-hover",
hoverClass: "ui-state-active",
};
vm.jqyouiDroppable={onDrop: 'dc.onDrop',multiple:true};
vm.onDrop = function (event, ui) {
var result = game.onDrop(event, ui, game);
};
vm.revealRule = function () {
if (vm.ruleInfo.length===0){
vm.ruleInfo.push(game.rule.describe());
lab.state.score -= vm.ruleCost;
};
};
vm.revealHint = function () {
var hint = game.rule.nextHint();
if (hint) {
vm.hints.push(hint);
lab.state.score -= vm.hintCost;
}
};
};
TableController.$inject = ['$scope', 'game', 'lab', '$filter'];
app.controller('TableController', TableController);
function RulesController($scope, game, lab,$analytics,alertify) {
var vm = this;
// present just a few hypothesis
// emit event track (with category and label properties for GA)
$analytics.eventTrack('rule', {
category: 'rule', label: game.rule.describe()
});
vm.hypotheses = game.hypotheses;
vm.upgrades = game.upgrades;
vm.isVisible = function (upgrade) {
return upgrade.isVisible(lab, game.allObjects);
};
vm.isAvailable = function (upgrade) {
return upgrade.isAvailable(lab, game.allObjects);
};
/** return a class based on none right or wrong guessed **/
vm.isGuessed = function(rule){
if (rule.guessed===true) return 'bg-success';
else if (rule.guessed===false) return 'bg-danger';
else return '';
};
vm.guess = function (e, rule) {
var params = angular.element(e.target).parent('form').serializeArray();
var sameRule = rule.description == game.rule.description;
var sameOpts = angular.equals(rule.options, game.rule.options);
if (sameRule && sameOpts) {
// right!
lab.state.score += 200;
lab.state.rulesGuessed.push({
key: game.rule.key,
options: game.rule.options,
description: game.rule.describe(),
});
if (!rule.state) rule.state={};
rule.guessed=true;
alertify.alert(
'You have won using inductive logic! <p> <p> Play again?',
function(event){
event.preventDefault();
// ObjectStorage.clear();
// $window.location.reload(true); /// reloads are better for ads?
game.reset();
// since this confirmation was away from the dom we need to
// manually refresh
$scope.$apply();
},function(){}
);
} else {
lab.state.score -= 200;
rule.guessed=false;
lab.state.rulesFailed.push({
key: rule.key,
options: rule.options,
description: rule.describe(),
});
}
console.log('guess', arguments);
// vm.winDialouge = function () {
// if (!vm._winDialouge) {
// vm._winDialouge = Helpers.loadFile('html/win.html');
// }
// UI.showModal('Win', vm._winDialouge);
// };
};
};
RulesController.$inject = ['$scope', 'game', 'lab','$analytics','alertify'];
app.controller('RulesController', RulesController);
function AchievementsController($scope, game, lab) {
var vm = this;
vm.achievements = game.achievements;
vm.progress = function () {
return game.achievements.filter(function (a) {
return a.validate(lab, game.allObjects, game.lastSaved);
}).length;
};
};
AchievementsController.$inject = ['$scope', 'game', 'lab'];
app.controller('AchievementsController', AchievementsController);
function SaveController($scope, $interval, $window, alertify, game, lab) {
var vm = this;
game.lastSaved = new Date().getTime();
vm.lastSaved = game.lastSaved;
;
vm.saveNow = function () {
var saveTime = new Date().getTime();
lab.state.time += saveTime - game.lastSaved;
game.save();
game.lastSaved = saveTime;
vm.lastSaved = game.lastSaved;
// if (lab.state.score<0){
// alertify.alert(
// 'Your score is below zero, so you lost :( Want to try a different rule?',
// function(event){
// event.preventDefault();
// // ObjectStorage.clear();
// // $window.location.reload(true); /// reloads are better for ads?
// game.reset();
// // since this confirmation was away from the dom we need to
// // manually refresh
// $scope.$apply();
// },function(){}
// );
// }
};
vm.restart = function () {
console.log('restart');
alertify.confirm(
'Do you really want to restart the game? All progress will be lost.',
function(event){
alertify.alert('Restarting. <p> The rule was: <p>"'+game.rule.describe(),function(){
event.preventDefault();
// ObjectStorage.clear();
// $window.location.reload(true); /// reloads are better for ads?
game.reset();
// since this confirmation was away from the dom we need to
// manually refresh
$scope.$apply();
});
},function(){}
);
};
$interval(vm.saveNow, 10000);
};
SaveController.$inject = ['$scope', '$interval', '$window', 'alertify', 'game', 'lab'];
app.controller('SaveController', SaveController);
function StatsController($scope, lab,game,alertify) {
var vm = this;
vm.lab = lab;
vm.lost=false;
$scope.$watch('lc.lab.state.score', function (newValue, oldValue) {
if (newValue<0&&!vm.lost){
vm.lost=true;
alertify.alert(
'<p>You lost :( Play again? <p><p> The rule was: <p>"'+game.rule.describe()+'"',
function(event){
event.preventDefault();
// ObjectStorage.clear();
// $window.location.reload(true); /// reloads are better for ads?
game.reset();
// since this confirmation was away from the dom we need to
// manually refresh
$scope.$apply();
vm.lost=false;
},function(){}
);
};
});
};
StatsController.$inject = ['$scope', 'lab','game','alertify'];
app.controller('StatsController', StatsController);
analytics.init();
analytics.sendScreen(analytics.screens.main);
})(Helpers,analytics,Game,Rules);
module.exports=app;
/**
* Define the angular app
*/
'use strict';
//deps
import jquery from "jquery";
import jqueryUi from "jquery-ui";
import jqueryUiTouchPunch from "jquery-ui-touch-punch";
import jsCookie from "js-cookie";
import angular from "angular";
import angularDragdrop from "angular-dragdrop";
import angularAnimate from "angular-animate";
import angulartics from 'angulartics';
import angularticsGoogleAnalytics from 'angulartics-google-analytics';
import ngAlertify from "alertify.js/dist/js/ngAlertify.js";
//app
import ObjectStorage from "js/storage";
import Helpers from "js/helpers";
import GameObjects from "js/gameobjects";
import analytics from "js/analytics";
import Game from "js/game";
import Rules from "js/rules.js";
import UI from "js/ui.js";
var app = (function (Helpers,analytics,Game,Rules) {
Helpers.validateSaveVersion();
var app = angular.module('cardsForScience', ['ngDragDrop','ngAnimate','angulartics', angularticsGoogleAnalytics,"ngAlertify"]);
// config
app.config(function ($analyticsProvider) {
$analyticsProvider.firstPageview(true); /* Records pages that don't use $state or $route */
$analyticsProvider.withAutoBase(true); /* Records full path */
});
// directives
/**
* Make little "+2" "-1" score animations when score changes requires ng-model="score"
* Associated css:
* ```
* .update-value { // set constant height, and the position
position: relative;
right: -2em;
top: -1.42857em;
height: 1.42857em;
}
.update-plus { // if the change is +ve
color: green;
position: relative;
}
.update-minus {
color: red;
position: relative;
}
*/
function cfsScoreChange($compile) {
return {
link: function (scope, element, attrs) {
scope.$watch(attrs.ngModel, function (newValue, oldValue) {
// showUpdateValue
var num = newValue-oldValue;
var formatted = Helpers.formatNumberPostfix(num);
var insert;
if (num > 0) {
insert = angular.element("<div class=''></div>")
.attr("class", "update-plus")
.html("+" + formatted);
} else {
insert = angular.element("<div></div>")
.attr("class", "update-minus")
.html(formatted);
}
// TODO it would be better to use an ::after element for this
// showUpdate
element.append(insert);
insert.animate({
"bottom":"+=30px",
"opacity": 0
}, { duration: 500, complete: function() {
angular.element(this).remove();
}});
});
}
};
};
cfsScoreChange.$inject = ['$compile'];
app.directive('cfsScoreChange', cfsScoreChange);
/**
* Directive to render a rule and bind it's option with select boxes
* This expects ng-model="rule" as an attribute
*/
// function cfsRule($compile) {
// return {
// link: function (scope, element, attrs) {
// var rule = scope.$eval(attrs.ngModel);
//
// // first generate a select box for each option (using lodash templating)
// _.templateSettings.interpolate = /<%=([\s\S]+?)%>/g;
// var optionTmpl = '' +
// '<select \n' +
// ' name="<%=option%>" \n' +
// ' convert-to-number="{{rule.optionDesc.<%=option%>.type===\'Number\'}}" \n' +
// ' ng-model="rule.options.<%=option%>" \n' +
// ' class="form-control input-sm" \n' +
// ' ng-options="v for v in rule.optionDesc.<%=option%>.possibleVals track by v" \n' +
// '>\n' +
// '</select>\n';
//
// var tmplParams = _.defaults({},rule.options,rule.otherOptions);
// for (var option in rule.optionDesc) {
// if (rule.optionDesc.hasOwnProperty(option)) {
// var vals = rule.optionDesc[option].possibleVals;
// if (vals) {
// tmplParams[option] = _.template(optionTmpl)({
// option: option
// });
// } else {
// // if there are no options replace '{{color}}' with 'color'
// tmplParams[option] = option;
// }
// }
// }
// // now put each select box into description
// // replace '{{color}}' with '<select name="color"...'
// var template = _.template(rule.description)(tmplParams);
//
// // now compile with angular
// element.html(template).show();
// $compile(element.contents())(scope);
// }
// };
// };
// cfsRule.$inject = ['$compile'];
// app.directive('cfsRule', cfsRule);
// factories to provide services. They serve shared game objects
// app.factory('cards', function () {
// var cards = Helpers.loadFile('json/cards.json');
// cards = cards.map(
// function (r) {
// return new GameObjects.Card(r);
// });
// // put in extended array with helper methods
// Cards = new GameObjects.Cards();
// Cards.push.apply(Cards,cards);
// return Cards;
// });
function game($http, $q, lab) {
var game = new Game();
game.lab = lab;
game.allObjects.lab = lab;
var promise = game.load($http, $q);
game.reset();
// return promise;
return game;
};
game.$inject = ['$http', '$q', 'lab'];
app.factory('game', game);
function lab() {
if (!this.lab) this.lab = new GameObjects.Lab();
return this.lab;
};
app.factory('lab', lab);
// add helpers as filters
function niceNumber($filter) {
return Helpers.formatNumberPostfix;
};
niceNumber.$inject = ['$filter'];
app.filter('niceNumber', niceNumber);
/** transpose data for a table **/
// function transpose($filter) {
// return function (input) {
// return _.zip(input);
// };
// };
// transpose.$inject = ['$filter'];
// app.filter('transpose', transpose);
function boolToTick($filter) {
return function (input) {
if (input===true) return '';
else if (input===false) return '❌';
else return input;
};
};
boolToTick.$inject = ['$filter'];
app.filter('boolToTick', boolToTick);
function niceTime($filter) {
return Helpers.formatTime;
};
niceTime.$inject = ['$filter'];
app.filter('niceTime', niceTime);
function currency($filter) {
return function (input) {
return 'JTN ' + $filter('niceNumber')(input);
};
};
currency.$inject = ['$filter'];
app.filter('currency', currency);
function reverse($filter) {
return function (items) {
if (items instanceof Array)
return items.slice().reverse();
else
return items;
};
};
reverse.$inject = ['$filter'];
app.filter('reverse', reverse);
// controllers
app.controller('CardController', CardController);
CardController.$inject = ['$scope', '$compile', 'game', 'lab'];
function CardController($scope, $compile, game, lab) {
var vm = this;
vm.dataJqyouiOptions = {
revert: "invalid",
zIndex: 100,
cancel: false,
};
vm.jqyouiDraggable = {
containment:'offset',
onStart:'rc.dragStart(r)',
onStop:'rc.dragStop(r)',
animate:true,
};
vm.onClick = function (card) {
// don't click if it was dragged within .222 seconds
// (to prevent double firing)
if (!card.state.lastDragged || new Date()-new Date(card.state.lastDragged)>300)
game.play(card);
else
console.log('clickprevent',card.state.lastDragged);
};
vm.dragStart = function(event, ui,card){
card.state.lastDragged=new Date();
console.log('startDrag');
};
vm.dragStop = function(event, ui,card){
card.state.lastDragged=new Date();
console.log('endDrag');
};
vm.cards = game.cards;
vm.isVisible = function (item) {
return item.isVisible(lab);
};
vm.isAvailable = function (item) {
return item.isAvailable(lab);
};
};
function TableController($scope, game, lab, $filter) {
var vm = this;
vm.cards = detector.cards;
vm.ruleInfo = game.ruleInfo;
vm.hints = game.hints;
vm.limit = -12;
vm.hintCost = 10;
vm.ruleCost = 300;
vm.lastCards = game.lastCards;
vm.incorrectCards = game.incorrectCards;
vm.dataJqyouiOptions = {
// accept: ".rune",
addClasses: true,
// greedy: true,
// tolerance: "pointer",
activeClass: "ui-state-hover",
hoverClass: "ui-state-active",
};
vm.jqyouiDroppable={onDrop: 'dc.onDrop',multiple:true};
vm.onDrop = function (event, ui) {
var result = game.onDrop(event, ui, game);
};
vm.revealRule = function () {
if (vm.ruleInfo.length===0){
vm.ruleInfo.push(game.rule.describe());
lab.state.score -= vm.ruleCost;
};
};
vm.revealHint = function () {
var hint = game.rule.nextHint();
if (hint) {
vm.hints.push(hint);
lab.state.score -= vm.hintCost;
}
};
};
TableController.$inject = ['$scope', 'game', 'lab', '$filter'];
app.controller('TableController', TableController);
function RulesController($scope, game, lab,$analytics,alertify) {
var vm = this;
// present just a few hypothesis
// emit event track (with category and label properties for GA)
$analytics.eventTrack('rule', {
category: 'rule', label: game.rule.describe()
});
vm.hypotheses = game.hypotheses;
vm.upgrades = game.upgrades;
vm.isVisible = function (upgrade) {
return upgrade.isVisible(lab, game.allObjects);
};
vm.isAvailable = function (upgrade) {
return upgrade.isAvailable(lab, game.allObjects);
};
/** return a class based on none right or wrong guessed **/
vm.isGuessed = function(rule){
if (rule.guessed===true) return 'bg-success';
else if (rule.guessed===false) return 'bg-danger';
else return '';
};
vm.guess = function (e, rule) {
var params = angular.element(e.target).parent('form').serializeArray();
var sameRule = rule.description == game.rule.description;
var sameOpts = angular.equals(rule.options, game.rule.options);
if (sameRule && sameOpts) {
// right!
lab.state.score += 200;
lab.state.rulesGuessed.push({
key: game.rule.key,
options: game.rule.options,
description: game.rule.describe(),
});
if (!rule.state) rule.state={};
rule.guessed=true;
alertify.alert(
'You have won using inductive logic! <p> <p> Play again?',
function(event){
event.preventDefault();
// ObjectStorage.clear();
// $window.location.reload(true); /// reloads are better for ads?
game.reset();
// since this confirmation was away from the dom we need to
// manually refresh
$scope.$apply();
},function(){}
);
} else {
lab.state.score -= 200;
rule.guessed=false;
lab.state.rulesFailed.push({
key: rule.key,
options: rule.options,
description: rule.describe(),
});
}
console.log('guess', arguments);
// vm.winDialouge = function () {
// if (!vm._winDialouge) {
// vm._winDialouge = Helpers.loadFile('html/win.html');
// }
// UI.showModal('Win', vm._winDialouge);
// };
};
};
RulesController.$inject = ['$scope', 'game', 'lab','$analytics','alertify'];
app.controller('RulesController', RulesController);
function AchievementsController($scope, game, lab) {
var vm = this;
vm.achievements = game.achievements;
vm.progress = function () {
return game.achievements.filter(function (a) {
return a.validate(lab, game.allObjects, game.lastSaved);
}).length;
};
};
AchievementsController.$inject = ['$scope', 'game', 'lab'];
app.controller('AchievementsController', AchievementsController);
function SaveController($scope, $interval, $window, alertify, game, lab) {
var vm = this;
game.lastSaved = new Date().getTime();
vm.lastSaved = game.lastSaved;
;
vm.saveNow = function () {
var saveTime = new Date().getTime();
lab.state.time += saveTime - game.lastSaved;
game.save();
game.lastSaved = saveTime;
vm.lastSaved = game.lastSaved;
// if (lab.state.score<0){
// alertify.alert(
// 'Your score is below zero, so you lost :( Want to try a different rule?',
// function(event){
// event.preventDefault();
// // ObjectStorage.clear();
// // $window.location.reload(true); /// reloads are better for ads?
// game.reset();
// // since this confirmation was away from the dom we need to
// // manually refresh
// $scope.$apply();
// },function(){}
// );
// }
};
vm.restart = function () {
console.log('restart');
alertify.confirm(
'Do you really want to restart the game? All progress will be lost.',
function(event){
alertify.alert('Restarting. <p> The rule was: <p>"'+game.rule.describe(),function(){
event.preventDefault();
// ObjectStorage.clear();
// $window.location.reload(true); /// reloads are better for ads?
game.reset();
// since this confirmation was away from the dom we need to
// manually refresh
$scope.$apply();
});
},function(){}
);
};
$interval(vm.saveNow, 10000);
};
SaveController.$inject = ['$scope', '$interval', '$window', 'alertify', 'game', 'lab'];
app.controller('SaveController', SaveController);
function StatsController($scope, lab,game,alertify) {
var vm = this;
vm.lab = lab;
vm.lost=false;
$scope.$watch('lc.lab.state.score', function (newValue, oldValue) {
if (newValue<0&&!vm.lost){
vm.lost=true;
alertify.alert(
'<p>You lost :( Play again? <p><p> The rule was: <p>"'+game.rule.describe()+'"',
function(event){
event.preventDefault();
// ObjectStorage.clear();
// $window.location.reload(true); /// reloads are better for ads?
game.reset();
// since this confirmation was away from the dom we need to
// manually refresh
$scope.$apply();
vm.lost=false;
},function(){}
);
};
});
};
StatsController.$inject = ['$scope', 'lab','game','alertify'];
app.controller('StatsController', StatsController);
analytics.init();
analytics.sendScreen(analytics.screens.main);
})(Helpers,analytics,Game,Rules);
export default app;
+269 -267
View File
@@ -1,267 +1,269 @@
/**
* Game object load/saves game resources and stores game objects
*/
var ObjectStorage = require("js/storage.js");
var Helpers = require("js/helpers.js");
var GameObjects = require("js/gameobjects.js");
var Rules = require("js/rules.js");
var cards = require("json/cards.json");
var achievements = require("json/achievements.json");
var ruleSimulations = require("json/simulations.json");
var Game = module.exports =(function (Helpers, GameObjects, ObjectStorage,Rules,cards,achievements) {
'use strict';
var Game = function () {
this.lab = null;
this.cards = null;
this.workers = null;
this.upgrades = null;
this.achievements = null;
this.allObjects = {
// lab: this.lab
};
this.loaded = false;
this.hypotheses = [];
this.lastCards= [];
this.hints=[];
this.ruleInfo=[];
this.incorrectCards= [];
this.rule=undefined;
this.rules=Rules.rules;
this.Rule=Rules.Rule;
};
Game.prototype.load = function ($http, $q) {
var self = this;
if (this.loaded) {
return;
}
this.cards = cards; //Helpers.loadFile('json/cards.json');
this.achievements = require("json/achievements.json"); //Helpers.loadFile('./json/achievements.json');
// 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.cards = self.cards.map(
function (r) {
return makeGameObject(GameObjects.Card, r);
});
self.achievements = self.achievements.map(
function (a) {
return makeGameObject(GameObjects.Achievement, a);
});
// put cards in extended array with utility methods
self.Card = new GameObjects.Cards();
self.Card.push.apply(self.Card, self.cards);
self.cards = self.Card;
// add rules to load and save states
self.rules.map(function(o){
self.allObjects[o.key] = o;
});
// TODO save and load lastCards and incorrectCards
// Load states from local store
for (var key in self.allObjects) {
var o = self.allObjects[key];
o.loadState(ObjectStorage.load(key));
}
self.loaded = true;
return self;
};
Game.prototype.reset = function () {
// setup game
this.rule = this.newRule();
this.dealHand();
// deal new initial cards that follow the rule
this.lastCards.splice(0,this.lastCards.length);
this.lastCards.push(angular.copy(_.sample(this.cards)));
var error,i;
for (i = 0; i < 52; i++) {
if (this.lastCards.length>2) break; // stop here
var card = angular.copy(_.sample(this.cards));
var res;
try{
res = this.rule.test(card,this.lastCards,this.cards);
} catch(e){
error=e;
// in case of an error just add a random card
// this is probobly because it is looking back 2 or 3 cards
// yet we only have 1
this.lastCards.push(card);
}
if (res) this.lastCards.push(angular.copy(_.sample(this.cards)));
}
if (this.lastCards.length<3) {
console.warn(
'Could not deal cards for rule after:',
i,
this.rule.key,
this.rule.options,
this.rule.describe(),
_.map(this.lastCards,'key'),
error?error.message:''
);
// feck, just deal 3 random then
this.lastCards.splice(0,this.lastCards.length);
this.lastCards.push(angular.copy(_.sample(this.cards)));
this.lastCards.push(angular.copy(_.sample(this.cards)));
this.lastCards.push(angular.copy(_.sample(this.cards)));
}
// this.lastCards.push.apply(this.lastCards,_.sampleSize(this.cards,3));
this.ruleInfo.splice(0,this.ruleInfo.length);
this.hints.splice(0,this.hints.length);
// empty incorrect cards
this.incorrectCards.splice(0,this.incorrectCards.length);
this.incorrectCards.push([]);
this.incorrectCards.push([]);
this.incorrectCards.push([]);
// reset score
this.lab.state.score = 200;
// new set of hypothes
this.hypotheses=this.genHypotheses();
return this;
};
Game.prototype.genHypotheses = function () {
// get some hypotheses
var hypo=[];
// a random 2, 2 variations of each
for (var i = 0; i < 1; i++) {
var rule = _.sample(this.rules);
rule = angular.copy(rule);
rule.randomize();
hypo.push(rule);
rule = angular.copy(rule);
rule.randomize();
hypo.push(rule);
}
// add the real rule
var rule = angular.copy(this.rule);
hypo.push(rule);
// and a variation of the real rule
var rule = angular.copy(this.rule);
rule.randomize();
hypo.push(rule);
// clean and remember
hypo = _.uniq(hypo);
hypo = _.shuffle(hypo);
// empty old ones
this.hypotheses.splice(0,this.hypotheses.length);
// put in new ones
for (var i = 0; i < hypo.length; i++) {
this.hypotheses.push(hypo[i]);
}
return this.hypotheses;
};
Game.prototype.newRule = function () {
// FIXME
var okRules = _.filter(ruleSimulations,function(s){
return s.ratioRight>0.1&&s.ratioRight<0.6;
});
// var okRules = this.rules;
// _.map(this.rules,function(r){return r.randomize();});
// choose and ok rule
var ruleConfig = _.sample(okRules);
// now find the rule and set these options
var rule = _.find(this.rules,{key:ruleConfig.key});
var options = ruleConfig.options;
if (typeof options==="string") options = JSON.parse(options);
rule.setOptions(options);
return this.rule = rule;
};
Game.prototype.dealHand = function (n) {
n=n||12;
var sample=_.sampleSize(this.cards,n);
// empty all cards
this.cards.map(function(card){
card.state.amount=0;
});
// now increase the value of our sample
for (var i = 0; i < sample.length; i++) {
var card = sample[i];
this.cards.get(card.key).state.amount++;
}
};
Game.prototype.onClick = function (event, ui) {
var self=this;
console.debug('onClick',arguments);
var cardType = angular.element(ui.draggable).data('cards');
var card = _.find(this.cards,{key:cardType});
return this.play(card);
};
Game.prototype.onDrop = function (event, ui) {
var self=this;
console.debug('onDrop',arguments);
var cardType = angular.element(ui.draggable).data('cards');
var card = _.find(this.cards,{key:cardType});
return this.play(card);
};
Game.prototype.play = function (card) {
var self=this;
card.state.amount-=1;
var turn = this.lastCards.length-1;
var correct = this.test(card);
if (correct){
if(!this.incorrectCards[turn]) this.incorrectCards[turn]=[];
this.lastCards.push(angular.copy(card));
if(!this.incorrectCards[turn+1]) this.incorrectCards[turn+1]=[];
this.lab.state.score+=1;
} else {
// add incorrect one to sidelines
if (!this.incorrectCards[turn]) this.incorrectCards[turn]=[];
this.incorrectCards[turn].push(angular.copy(card));
// deal 2 random cards
_.sample(this.cards).state.amount+=1;
_.sample(this.cards).state.amount+=1;
this.lab.state.score-=2;
}
return correct;
};
/** Test the rule **/
Game.prototype.test = function (card) {
return this.rule.test(card,this.lastCards,this.cards);
};
Game.prototype.save = function () {
// Save every object's state to local storage
for (var key in this.allObjects) {
ObjectStorage.save(key, this.allObjects[key].state);
}
};
return Game;
}(Helpers, GameObjects, ObjectStorage,Rules,cards,achievements));
/**
* Game object load/saves game resources and stores game objects
*/
import ObjectStorage from 'js/storage.js';
import * as Helpers from './helpers'
import GameObjects from './gameobjects';
import * as Rules from './rules.js';
import cards from 'json/cards.json';
import achievements from 'json/achievements.json';
import ruleSimulations from 'json/simulations.json';
var Game = (function (Helpers, GameObjects, ObjectStorage,Rules,cards,achievements) {
'use strict';
var Game = function () {
this.lab = null;
this.cards = null;
this.workers = null;
this.upgrades = null;
this.achievements = null;
this.allObjects = {
// lab: this.lab
};
this.loaded = false;
this.hypotheses = [];
this.lastCards= [];
this.hints=[];
this.ruleInfo=[];
this.incorrectCards= [];
this.rule=undefined;
this.rules=Rules.rules;
this.Rule=Rules.Rule;
};
Game.prototype.load = function ($http, $q) {
var self = this;
if (this.loaded) {
return;
}
this.cards = cards; //Helpers.loadFile('json/cards.json');
this.achievements = require("json/achievements.json"); //Helpers.loadFile('./json/achievements.json');
// 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.cards = self.cards.map(
function (r) {
return makeGameObject(GameObjects.Card, r);
});
self.achievements = self.achievements.map(
function (a) {
return makeGameObject(GameObjects.Achievement, a);
});
// put cards in extended array with utility methods
self.Card = new GameObjects.Cards();
self.Card.push.apply(self.Card, self.cards);
self.cards = self.Card;
// add rules to load and save states
self.rules.map(function(o){
self.allObjects[o.key] = o;
});
// TODO save and load lastCards and incorrectCards
// Load states from local store
for (var key in self.allObjects) {
var o = self.allObjects[key];
o.loadState(ObjectStorage.load(key));
}
self.loaded = true;
return self;
};
Game.prototype.reset = function () {
// setup game
this.rule = this.newRule();
this.dealHand();
// deal new initial cards that follow the rule
this.lastCards.splice(0,this.lastCards.length);
this.lastCards.push(angular.copy(_.sample(this.cards)));
var error,i;
for (i = 0; i < 52; i++) {
if (this.lastCards.length>2) break; // stop here
var card = angular.copy(_.sample(this.cards));
var res;
try{
res = this.rule.test(card,this.lastCards,this.cards);
} catch(e){
error=e;
// in case of an error just add a random card
// this is probobly because it is looking back 2 or 3 cards
// yet we only have 1
this.lastCards.push(card);
}
if (res) this.lastCards.push(angular.copy(_.sample(this.cards)));
}
if (this.lastCards.length<3) {
console.warn(
'Could not deal cards for rule after:',
i,
this.rule.key,
this.rule.options,
this.rule.describe(),
_.map(this.lastCards,'key'),
error?error.message:''
);
// feck, just deal 3 random then
this.lastCards.splice(0,this.lastCards.length);
this.lastCards.push(angular.copy(_.sample(this.cards)));
this.lastCards.push(angular.copy(_.sample(this.cards)));
this.lastCards.push(angular.copy(_.sample(this.cards)));
}
// this.lastCards.push.apply(this.lastCards,_.sampleSize(this.cards,3));
this.ruleInfo.splice(0,this.ruleInfo.length);
this.hints.splice(0,this.hints.length);
// empty incorrect cards
this.incorrectCards.splice(0,this.incorrectCards.length);
this.incorrectCards.push([]);
this.incorrectCards.push([]);
this.incorrectCards.push([]);
// reset score
this.lab.state.score = 200;
// new set of hypothes
this.hypotheses=this.genHypotheses();
return this;
};
Game.prototype.genHypotheses = function () {
// get some hypotheses
var hypo=[];
// a random 2, 2 variations of each
for (var i = 0; i < 1; i++) {
var rule = _.sample(this.rules);
rule = angular.copy(rule);
rule.randomize();
hypo.push(rule);
rule = angular.copy(rule);
rule.randomize();
hypo.push(rule);
}
// add the real rule
var rule = angular.copy(this.rule);
hypo.push(rule);
// and a variation of the real rule
var rule = angular.copy(this.rule);
rule.randomize();
hypo.push(rule);
// clean and remember
hypo = _.uniq(hypo);
hypo = _.shuffle(hypo);
// empty old ones
this.hypotheses.splice(0,this.hypotheses.length);
// put in new ones
for (var i = 0; i < hypo.length; i++) {
this.hypotheses.push(hypo[i]);
}
return this.hypotheses;
};
Game.prototype.newRule = function () {
// FIXME
var okRules = _.filter(ruleSimulations,function(s){
return s.ratioRight>0.1&&s.ratioRight<0.6;
});
// var okRules = this.rules;
// _.map(this.rules,function(r){return r.randomize();});
// choose and ok rule
var ruleConfig = _.sample(okRules);
// now find the rule and set these options
var rule = _.find(this.rules,{key:ruleConfig.key});
var options = ruleConfig.options;
if (typeof options==="string") options = JSON.parse(options);
rule.setOptions(options);
return this.rule = rule;
};
Game.prototype.dealHand = function (n) {
n=n||12;
var sample=_.sampleSize(this.cards,n);
// empty all cards
this.cards.map(function(card){
card.state.amount=0;
});
// now increase the value of our sample
for (var i = 0; i < sample.length; i++) {
var card = sample[i];
this.cards.get(card.key).state.amount++;
}
};
Game.prototype.onClick = function (event, ui) {
var self=this;
console.debug('onClick',arguments);
var cardType = angular.element(ui.draggable).data('cards');
var card = _.find(this.cards,{key:cardType});
return this.play(card);
};
Game.prototype.onDrop = function (event, ui) {
var self=this;
console.debug('onDrop',arguments);
var cardType = angular.element(ui.draggable).data('cards');
var card = _.find(this.cards,{key:cardType});
return this.play(card);
};
Game.prototype.play = function (card) {
var self=this;
card.state.amount-=1;
var turn = this.lastCards.length-1;
var correct = this.test(card);
if (correct){
if(!this.incorrectCards[turn]) this.incorrectCards[turn]=[];
this.lastCards.push(angular.copy(card));
if(!this.incorrectCards[turn+1]) this.incorrectCards[turn+1]=[];
this.lab.state.score+=1;
} else {
// add incorrect one to sidelines
if (!this.incorrectCards[turn]) this.incorrectCards[turn]=[];
this.incorrectCards[turn].push(angular.copy(card));
// deal 2 random cards
_.sample(this.cards).state.amount+=1;
_.sample(this.cards).state.amount+=1;
this.lab.state.score-=2;
}
return correct;
};
/** Test the rule **/
Game.prototype.test = function (card) {
return this.rule.test(card,this.lastCards,this.cards);
};
Game.prototype.save = function () {
// Save every object's state to local storage
for (var key in this.allObjects) {
ObjectStorage.save(key, this.allObjects[key].state);
}
};
return Game;
}(Helpers, GameObjects, ObjectStorage,Rules,cards,achievements));
export default Game
+299 -297
View File
@@ -1,297 +1,299 @@
/**
* Game objects such as workers, research, upgrades, and achievements.
*/
var GameObjects = module.exports = (function () {
'use strict';
var GLOBAL_VISIBILITY_THRESHOLD = 0.5;
/** @class GameObject
* Base class for all objects in the game. This works together with the
* saving mechanism.
*/
var GameObject = function (obj) {
this.state = {};
$.extend(this, obj);
if (!this.key) {
throw 'Error: GameObject has to have a key!';
}
};
GameObject.prototype.loadState =
function (state) {
$.extend(this.state, state);
};
GameObject.prototype.guid = function () {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
};
/** @class Lab
*/
var Lab = function () {
GameObject.apply(this, [{
key: 'lab',
state: {
name: 'Write your name here',
detector: 1,
factor: 5,
data: 0,
money: 0,
reputation: 0,
clicks: 0,
moneyCollected: 0,
moneySpent: 0,
dataCollected: 0,
dataSpent: 0,
time: 0,
observations: [],
score: 0,
highScore: 0,
hints: 0,
rulesGuessed: [],
rulesFailed: [],
}
}]);
};
Lab.prototype = Object.create(GameObject.prototype);
Lab.prototype.constructor = Lab;
Lab.prototype.getGrant = function () {
var addition = this.state.reputation * this.state.factor;
this.state.money += addition;
this.state.moneyCollected += addition;
return addition;
};
Lab.prototype.acquireData = function (amount) {
this.state.data += amount;
this.state.dataCollected += amount;
};
Lab.prototype.clickDetector = function () {
this.state.clicks += 1;
this.acquireData(this.state.detector);
};
Lab.prototype.research = function (cost, reputation) {
if (this.state.data >= cost) {
this.state.data -= cost;
this.state.dataSpent += cost;
this.state.reputation += reputation;
return true;
}
return false;
};
/**
* Takes in a rule/observation object and records observation in journal
* with reactants, inputs, catalysts, conditions, results
**/
Lab.prototype.observe = function (observation) {
// join the arrays into strings for display
var obsText = {};
for (var k in observation) {
if (observation.hasOwnProperty(k)) {
obsText[k] = observation[k].sort().join('');
}
}
obsText.amount=1;
// check if an obs with all the attributes matching (extra attribs are ok)
var index = _.findIndex(this.state.observations,obsText);
if (index>-1)
this.state.observations[index].amount+=1;
else
this.state.observations.push(obsText);
};
Lab.prototype.buy = function (cost) {
if (this.state.money >= cost) {
this.state.money -= cost;
this.state.moneySpent += cost;
return true;
}
return false;
};
var Cards = function (obj) {
this.push.apply(this, obj);
};
Cards.prototype = Object.create(Array.prototype);
Cards.prototype.constructor = Array.constructor;
Cards.prototype.pushAll = function (items) {
this.push.apply(this, items);
};
/** Add a random element or specify it's key **/
Cards.prototype.addToStore = function (element) {
if (element) this.get(element);
if (!element) element = this.select();
return element.state.amount += 1;
};
/** Add a random discovered element or specify it's key **/
Cards.prototype.addKnownToStore = function (element) {
var discovered = this.filter(function (e) {
return e.state.discovered;
});
discovered = new GameObjects.Cards(discovered);
if (element) discovered.get(element);
if (!element) element = discovered.select();
return element.state.amount += 1;
};
/** Select random element from store **/
Cards.prototype.select = function () {
var i = Math.round((this.length - 1) * Math.random());
return this[i];
};
/** Get element by key **/
Cards.prototype.get = function (key) {
return this.filter(function (e) {
return e.key === key;
})[0];
};
/** Get element by hashid **/
Cards.prototype.getByHashKey = function (hashKey) {
if (hashKey === undefined) {
console.warn('GetByHashKey given an undefined hashkey', hashKey)
return;
}
var res = this.filter(function (e) {
return e.$$hashKey === hashKey;
});
if (res.length == 1) return res[0];
else if (res.length) {
console.warn('Got multiple results when filtering on hashKey', hashKey);
return res[0];
} else {
console.warn('Got no results when filtering on hashKey', hashKey);
return;
}
};
/** @class Card
*/
var Card = function (obj) {
// load from localStorage by obj.key
GameObject.apply(this, [obj]);
// apply defaults to undefined values
this.state = _.defaults(this.state,{
amount: 0,
discovered: false,
interesting: false,
});
// generate uuid
this.uuid = this.uuid || this.guid();
};
Card.prototype = Object.create(GameObject.prototype);
Card.prototype.constructor = Card;
Card.prototype.isVisible = function (lab) {
if (!lab) {
return false;
}
return this.state.discovered;
};
Card.prototype.isAvailable = function (lab) {
if (!lab) {
return false;
}
return this.state.amount > 0;
};
Card.prototype.research = function (lab) {
if (lab && lab.research(this.state.cost, this.state.reputation)) {
this.state.level++;
if (this.state.info_levels.length > 0 &&
this.state.level === this.state.info_levels[0]) {
this.state.interesting = true;
this.state.info_levels.splice(0, 1);
}
var old_cost = this.state.cost;
this.state.cost = Math.floor(this.state.cost * this.cost_increase);
return old_cost;
}
return -1;
};
Card.prototype.getInfo = function () {
if (!this._info) {
this._info = Helpers.loadFile(this.info);
}
this.state.interesting = false;
return this._info;
};
/** Create a new element for the test tube from this Card **/
Card.prototype.spawn = function () {
var element = angular.copy(this);
element.uuid = element.guid();
element.state = undefined;
// this.state.amount -= 1;
return element;
};
Card.prototype.decreaseStore = function () {
return this.state.amount -= 1;
};
/** @class Achievement
*/
var Achievement = function (obj) {
GameObject.apply(this, [obj]);
this.state.timeAchieved = null;
};
Achievement.prototype = Object.create(GameObject.prototype);
Achievement.prototype.validate = function (lab, allObjects, saveTime) {
if (this.state.timeAchieved) {
return true;
}
if (allObjects.hasOwnProperty(this.targetKey) &&
allObjects[this.targetKey].state.hasOwnProperty(this.targetProperty) &&
allObjects[this.targetKey].state[this.targetProperty] >= this.threshold) {
this.state.timeAchieved = lab.state.time + new Date().getTime() - saveTime;
UI.showAchievement(this);
return true;
}
return false;
};
Achievement.prototype.isAchieved = function () {
if (this.state.timeAchieved) {
return true;
} else {
return false;
}
};
// Expose classes in module.
return {
Lab: Lab,
Card: Card,
Achievement: Achievement,
Cards: Cards
};
}());
/**
* Game objects such as workers, research, upgrades, and achievements.
*/
var GameObjects = (function () {
'use strict';
var GLOBAL_VISIBILITY_THRESHOLD = 0.5;
/** @class GameObject
* Base class for all objects in the game. This works together with the
* saving mechanism.
*/
var GameObject = function (obj) {
this.state = {};
$.extend(this, obj);
if (!this.key) {
throw 'Error: GameObject has to have a key!';
}
};
GameObject.prototype.loadState =
function (state) {
$.extend(this.state, state);
};
GameObject.prototype.guid = function () {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
};
/** @class Lab
*/
var Lab = function () {
GameObject.apply(this, [{
key: 'lab',
state: {
name: 'Write your name here',
detector: 1,
factor: 5,
data: 0,
money: 0,
reputation: 0,
clicks: 0,
moneyCollected: 0,
moneySpent: 0,
dataCollected: 0,
dataSpent: 0,
time: 0,
observations: [],
score: 0,
highScore: 0,
hints: 0,
rulesGuessed: [],
rulesFailed: [],
}
}]);
};
Lab.prototype = Object.create(GameObject.prototype);
Lab.prototype.constructor = Lab;
Lab.prototype.getGrant = function () {
var addition = this.state.reputation * this.state.factor;
this.state.money += addition;
this.state.moneyCollected += addition;
return addition;
};
Lab.prototype.acquireData = function (amount) {
this.state.data += amount;
this.state.dataCollected += amount;
};
Lab.prototype.clickDetector = function () {
this.state.clicks += 1;
this.acquireData(this.state.detector);
};
Lab.prototype.research = function (cost, reputation) {
if (this.state.data >= cost) {
this.state.data -= cost;
this.state.dataSpent += cost;
this.state.reputation += reputation;
return true;
}
return false;
};
/**
* Takes in a rule/observation object and records observation in journal
* with reactants, inputs, catalysts, conditions, results
**/
Lab.prototype.observe = function (observation) {
// join the arrays into strings for display
var obsText = {};
for (var k in observation) {
if (observation.hasOwnProperty(k)) {
obsText[k] = observation[k].sort().join('');
}
}
obsText.amount=1;
// check if an obs with all the attributes matching (extra attribs are ok)
var index = _.findIndex(this.state.observations,obsText);
if (index>-1)
this.state.observations[index].amount+=1;
else
this.state.observations.push(obsText);
};
Lab.prototype.buy = function (cost) {
if (this.state.money >= cost) {
this.state.money -= cost;
this.state.moneySpent += cost;
return true;
}
return false;
};
var Cards = function (obj) {
this.push.apply(this, obj);
};
Cards.prototype = Object.create(Array.prototype);
Cards.prototype.constructor = Array.constructor;
Cards.prototype.pushAll = function (items) {
this.push.apply(this, items);
};
/** Add a random element or specify it's key **/
Cards.prototype.addToStore = function (element) {
if (element) this.get(element);
if (!element) element = this.select();
return element.state.amount += 1;
};
/** Add a random discovered element or specify it's key **/
Cards.prototype.addKnownToStore = function (element) {
var discovered = this.filter(function (e) {
return e.state.discovered;
});
discovered = new GameObjects.Cards(discovered);
if (element) discovered.get(element);
if (!element) element = discovered.select();
return element.state.amount += 1;
};
/** Select random element from store **/
Cards.prototype.select = function () {
var i = Math.round((this.length - 1) * Math.random());
return this[i];
};
/** Get element by key **/
Cards.prototype.get = function (key) {
return this.filter(function (e) {
return e.key === key;
})[0];
};
/** Get element by hashid **/
Cards.prototype.getByHashKey = function (hashKey) {
if (hashKey === undefined) {
console.warn('GetByHashKey given an undefined hashkey', hashKey)
return;
}
var res = this.filter(function (e) {
return e.$$hashKey === hashKey;
});
if (res.length == 1) return res[0];
else if (res.length) {
console.warn('Got multiple results when filtering on hashKey', hashKey);
return res[0];
} else {
console.warn('Got no results when filtering on hashKey', hashKey);
return;
}
};
/** @class Card
*/
var Card = function (obj) {
// load from localStorage by obj.key
GameObject.apply(this, [obj]);
// apply defaults to undefined values
this.state = _.defaults(this.state,{
amount: 0,
discovered: false,
interesting: false,
});
// generate uuid
this.uuid = this.uuid || this.guid();
};
Card.prototype = Object.create(GameObject.prototype);
Card.prototype.constructor = Card;
Card.prototype.isVisible = function (lab) {
if (!lab) {
return false;
}
return this.state.discovered;
};
Card.prototype.isAvailable = function (lab) {
if (!lab) {
return false;
}
return this.state.amount > 0;
};
Card.prototype.research = function (lab) {
if (lab && lab.research(this.state.cost, this.state.reputation)) {
this.state.level++;
if (this.state.info_levels.length > 0 &&
this.state.level === this.state.info_levels[0]) {
this.state.interesting = true;
this.state.info_levels.splice(0, 1);
}
var old_cost = this.state.cost;
this.state.cost = Math.floor(this.state.cost * this.cost_increase);
return old_cost;
}
return -1;
};
Card.prototype.getInfo = function () {
if (!this._info) {
this._info = Helpers.loadFile(this.info);
}
this.state.interesting = false;
return this._info;
};
/** Create a new element for the test tube from this Card **/
Card.prototype.spawn = function () {
var element = angular.copy(this);
element.uuid = element.guid();
element.state = undefined;
// this.state.amount -= 1;
return element;
};
Card.prototype.decreaseStore = function () {
return this.state.amount -= 1;
};
/** @class Achievement
*/
var Achievement = function (obj) {
GameObject.apply(this, [obj]);
this.state.timeAchieved = null;
};
Achievement.prototype = Object.create(GameObject.prototype);
Achievement.prototype.validate = function (lab, allObjects, saveTime) {
if (this.state.timeAchieved) {
return true;
}
if (allObjects.hasOwnProperty(this.targetKey) &&
allObjects[this.targetKey].state.hasOwnProperty(this.targetProperty) &&
allObjects[this.targetKey].state[this.targetProperty] >= this.threshold) {
this.state.timeAchieved = lab.state.time + new Date().getTime() - saveTime;
UI.showAchievement(this);
return true;
}
return false;
};
Achievement.prototype.isAchieved = function () {
if (this.state.timeAchieved) {
return true;
} else {
return false;
}
};
// Expose classes in module.
return {
Lab: Lab,
Card: Card,
Achievement: Achievement,
Cards: Cards
};
}());
export default GameObjects
+106 -106
View File
@@ -1,106 +1,106 @@
/** @module Helpers
* Define some useful helpers that are used throughout the game.
*/
var ObjectStorage = require("js/storage");
var jquery = require("jquery");
var Helpers = (function ($,ObjectStorage) {
'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;
};
/** 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 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 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');
}
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: 'UA-51809277-5'
};
})(jquery, ObjectStorage);
module.exports=Helpers;
/** @module Helpers
* Define some useful helpers that are used throughout the game.
*/
import ObjectStorage from "js/storage";
import jquery from "jquery";
var Helpers = (function ($,ObjectStorage) {
'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;
};
/** 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 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 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');
}
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: 'UA-51809277-5'
};
})(jquery, ObjectStorage);
export default Helpers;
+707 -718
View File
File diff suppressed because it is too large Load Diff
+73 -73
View File
@@ -1,73 +1,73 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Simulate rules</title>
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> -->
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.11/css/jquery.dataTables.min.css">
<link rel="stylesheet" href="../../../clientApp.css">
</head>
<body>
<h1>Simulate rules</h1>
<textarea rows="10" style="width: 1000px; height: 400px" id="summary"></textarea>
<textarea rows="3" style="width: 1000px; height: 100px" id="oks"></textarea>
<div id="export"></div>
<table id="results" class="table">
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://cdn.datatables.net/1.10.11/js/jquery.dataTables.min.js"></script>
<!-- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> -->
<script src="../../../clientApp.bundle.js"></script>
<script>
var simulation = new clientApp.Rules.Simulation(clientApp.Rules.rules,clientApp.cards);
var results=simulation.run();
var summary = simulation.summarize()
// var results = [];
// for (var i = 0; i < clientApp.Rules.rules.length; i++) {
// var rule = clientApp.Rules.rules[i];
// var res = rule.simulate(clientApp.cards);
// results.push.apply(results,res);
// }
$('#oks').text('ok: '+_.map(results,'ok').reduce(_.add)+'/'+results.length);
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(results));
$('<a class="btn btn-default" href="data:' + data + '" download="data.json">export table as JSON</a>').appendTo('#export');
results=_.map(results,function(r){
r.options=JSON.stringify(r.options);
return r;
})
// just get keys we want and in order
var keys = [ "n","time", "ratioRight","ok", "right", "wrong", "error", "key", "options", "rule", "description","rights","wrongs","errors", ]
var table=$('#results');
var ts='';
ts+='<thead><tr><th>'+keys.join('</th><th>')+'</th></tr></thead><tbody>';
for (var i = 0; i < results.length; i++) {
// order them into an array
var result = _.map(keys,function(key){return results[i][key];});
// make table row
ts+='<tr><td>'+result.join('</td><td>')+'</td></tr>';
}
ts+='</tbody>';
table.append(ts);
$('#results').dataTable();
var summaryJson = JSON.stringify(summary,null,4);
$('#summary').text(summaryJson);
</script>
</head>
<body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Simulate rules</title>
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> -->
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.11/css/jquery.dataTables.min.css">
<link rel="stylesheet" href="../../../clientApp.css">
</head>
<body>
<h1>Simulate rules</h1>
<textarea rows="10" style="width: 1000px; height: 400px" id="summary"></textarea>
<textarea rows="3" style="width: 1000px; height: 100px" id="oks"></textarea>
<div id="export"></div>
<table id="results" class="table">
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://cdn.datatables.net/1.10.11/js/jquery.dataTables.min.js"></script>
<!-- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> -->
<script src="../../../clientApp.bundle.js"></script>
<script>
var simulation = new clientApp.Rules.Simulation(clientApp.Rules.rules,clientApp.cards);
var results=simulation.run();
var summary = simulation.summarize()
// var results = [];
// for (var i = 0; i < clientApp.Rules.rules.length; i++) {
// var rule = clientApp.Rules.rules[i];
// var res = rule.simulate(clientApp.cards);
// results.push.apply(results,res);
// }
$('#oks').text('ok: '+_.map(results,'ok').reduce(_.add)+'/'+results.length);
var data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(results));
$('<a class="btn btn-default" href="data:' + data + '" download="data.json">export table as JSON</a>').appendTo('#export');
results=_.map(results,function(r){
r.options=JSON.stringify(r.options);
return r;
})
// just get keys we want and in order
var keys = [ "n","time", "ratioRight","ok", "right", "wrong", "error", "key", "options", "rule", "description","rights","wrongs","errors", ]
var table=$('#results');
var ts='';
ts+='<thead><tr><th>'+keys.join('</th><th>')+'</th></tr></thead><tbody>';
for (var i = 0; i < results.length; i++) {
// order them into an array
var result = _.map(keys,function(key){return results[i][key];});
// make table row
ts+='<tr><td>'+result.join('</td><td>')+'</td></tr>';
}
ts+='</tbody>';
table.append(ts);
$('#results').dataTable();
var summaryJson = JSON.stringify(summary,null,4);
$('#summary').text(summaryJson);
</script>
</head>
<body>
</html>
+32 -30
View File
@@ -1,30 +1,32 @@
/** Allows to save objects to HTML5 local storage.
* However, it can only save properties, not functions.
*/
var ObjectStorage = module.exports = (function() {
'use strict';
try {
var _s = localStorage;
return {
save :
function(key, item) {
_s.setItem(key, JSON.stringify(item, function(key, val) {
if (key == '$$hashKey') {
return undefined;
}
return val;
}));
},
load : function(key) { return JSON.parse(_s.getItem(key)); },
clear : function() { _s.clear(); }
};
} catch (e) {
alert('There is no local storage for you.' +
' If you refresh the page, all progress will be lost');
return {
save : function(key, item) {},
load : function(key) { return null; },
clear : function() {}
};
};
}());
/** Allows to save objects to HTML5 local storage.
* However, it can only save properties, not functions.
*/
var ObjectStorage = (function() {
'use strict';
try {
var _s = localStorage;
return {
save :
function(key, item) {
_s.setItem(key, JSON.stringify(item, function(key, val) {
if (key == '$$hashKey') {
return undefined;
}
return val;
}));
},
load : function(key) { return JSON.parse(_s.getItem(key)); },
clear : function() { _s.clear(); }
};
} catch (e) {
alert('There is no local storage for you.' +
' If you refresh the page, all progress will be lost');
return {
save : function(key, item) {},
load : function(key) { return null; },
clear : function() {}
};
};
}());
export default ObjectStorage
+163 -162
View File
@@ -1,162 +1,163 @@
'use strict';
/** Define UI specific stuff.
*/
var FastClick = require("fastclick");
var Cookies = require("js-cookie");
var UI = module.exports = (function (FastClick,Cookies) {
/** Introduce FastClick for faster clicking on mobile.
*/
$(function() {
FastClick.attach(document.body);
});
// $('.prevent-select').on('mousedown', function(e) {
// e.preventDefault();
// });
/** Show a bootstrap modal with dynamic content e.g. background info **/
var showModal = function(title, text, level) {
var $modal = $('#infoBox');
$modal.find('#infoBoxLabel').html(title);
$modal.find('.modal-body').html(text);
$modal.modal({show: true});
};
/** Display only the cards with data-min-level above a certain
* threshold.
*/
var showLevels = function(level) {
$('#infoBox').find('[data-min-level]').each(function() {
if (level >= $(this).data('min-level')) {
$(this).show();
} else {
$(this).hide();
}
});
};
var showUpdateValue = function(ident, num) {
if (num != 0) {
var formatted = Helpers.formatNumberPostfix(num);
var insert;
if (num > 0) {
insert = $("<div></div>")
.attr("class", "update-plus")
.html("+" + formatted);
} else {
insert = $("<div></div>")
.attr("class", "update-minus")
.html(formatted);
}
showUpdate(ident, insert);
}
}
var showUpdate = function(ident, insert) {
var elem = $(ident);
elem.append(insert);
insert.animate({
"bottom":"+=30px",
"opacity": 0
}, { duration: 500, complete: function() {
$(this).remove();
}});
}
var showAchievement = function(obj) {
var alert = '<div class="alert alert-success alert-dismissible" role="alert">';
alert += '<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>';
alert += '<span class="fa ' + obj.icon + ' alert-glyph"></span> <span class="alert-text">' + obj.description + '</span>';
alert += '</div>';
alert = $(alert);
$('#achievements-container').prepend(alert);
var remove = function(a)
{
return function()
{
a.slideUp(300, function() { a.remove(); });
};
};
window.setTimeout(remove(alert), 2000);
}
// display cookie warning
if (typeof Cookies.get('cookielaw') === 'undefined') {
var alert = '<div id="cookielaw" class="alert alert-info" role="alert">';
alert += '<button type="button" class="btn btn-primary">OK</button>';
alert += '<i class="fa fa-info-circle alert-glyph"></i> <span class="alert-text">Cards for science uses local storage to store your current progress.</span>';
alert += '</div>';
alert = $(alert);
alert.find('button').click(function ()
{
Cookies.set('cookielaw', 'informed', { expires: 365 });
$('#cookielaw').slideUp(300, function() { $('#cookielaw').remove(); });
})
$('#messages-container').append(alert);
}
// display new user alert
// if (typeof Cookies.get('cern60') === 'undefined') {
// var alert = '<div id="cern60" class="alert alert-info" role="alert">';
// alert += '<button type="button" class="btn btn-primary">Close</button>';
// alert += '<i class="fa fa-area-chart alert-glyph"></i> <span class="alert-text"><a class="alert-link" href="http://home.web.cern.ch/about/updates/2014/12/take-part-cern-60-public-computing-challenge" target="_blank">Join the CERN 60 computing challenge!</a></span>';
// alert += '</div>';
// alert = $(alert);
// alert.find('button').click(function ()
// {
// Cookies.set('cern60', 'closed', { expires: 365 });
// $('#cern60').slideUp(300, function() { $('#cern60').remove(); });
// })
//
// $('#messages-container').append(alert);
// }
return {
showAchievement: showAchievement,
showModal: showModal,
showLevels: showLevels,
showUpdateValue: showUpdateValue
};
})(FastClick,Cookies);
//
// // I don't know what this is for, so I leave it here for the moment...
// (function() {
// var hidden = "hidden";
//
// // Standards:
// if (hidden in document)
// document.addEventListener("visibilitychange", onchange);
// else if ((hidden = "mozHidden") in document)
// document.addEventListener("mozvisibilitychange", onchange);
// else if ((hidden = "webkitHidden") in document)
// document.addEventListener("webkitvisibilitychange", onchange);
// else if ((hidden = "msHidden") in document)
// document.addEventListener("msvisibilitychange", onchange);
// // IE 9 and lower:
// else if ('onfocusin' in document)
// document.onfocusin = document.onfocusout = onchange;
// // All others:
// else
// window.onpageshow = window.onpagehide
// = window.onfocus = window.onblur = onchange;
//
// function onchange (evt) {
// var v = 'visible', h = 'hidden',
// evtMap = {
// focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
// };
//
// evt = evt || window.event;
// if (evt.type in evtMap)
// detector.visible = evtMap[evt.type] == 'visible';
// else
// detector.visible = !this[hidden];
// }
// })();
'use strict';
/** Define UI specific stuff.
*/
var FastClick = require("fastclick");
var Cookies = require("js-cookie");
export default UI
var UI = (function (FastClick,Cookies) {
/** Introduce FastClick for faster clicking on mobile.
*/
$(function() {
FastClick.attach(document.body);
});
// $('.prevent-select').on('mousedown', function(e) {
// e.preventDefault();
// });
/** Show a bootstrap modal with dynamic content e.g. background info **/
var showModal = function(title, text, level) {
var $modal = $('#infoBox');
$modal.find('#infoBoxLabel').html(title);
$modal.find('.modal-body').html(text);
$modal.modal({show: true});
};
/** Display only the cards with data-min-level above a certain
* threshold.
*/
var showLevels = function(level) {
$('#infoBox').find('[data-min-level]').each(function() {
if (level >= $(this).data('min-level')) {
$(this).show();
} else {
$(this).hide();
}
});
};
var showUpdateValue = function(ident, num) {
if (num != 0) {
var formatted = Helpers.formatNumberPostfix(num);
var insert;
if (num > 0) {
insert = $("<div></div>")
.attr("class", "update-plus")
.html("+" + formatted);
} else {
insert = $("<div></div>")
.attr("class", "update-minus")
.html(formatted);
}
showUpdate(ident, insert);
}
}
var showUpdate = function(ident, insert) {
var elem = $(ident);
elem.append(insert);
insert.animate({
"bottom":"+=30px",
"opacity": 0
}, { duration: 500, complete: function() {
$(this).remove();
}});
}
var showAchievement = function(obj) {
var alert = '<div class="alert alert-success alert-dismissible" role="alert">';
alert += '<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>';
alert += '<span class="fa ' + obj.icon + ' alert-glyph"></span> <span class="alert-text">' + obj.description + '</span>';
alert += '</div>';
alert = $(alert);
$('#achievements-container').prepend(alert);
var remove = function(a)
{
return function()
{
a.slideUp(300, function() { a.remove(); });
};
};
window.setTimeout(remove(alert), 2000);
}
// display cookie warning
if (typeof Cookies.get('cookielaw') === 'undefined') {
var alert = '<div id="cookielaw" class="alert alert-info" role="alert">';
alert += '<button type="button" class="btn btn-primary">OK</button>';
alert += '<i class="fa fa-info-circle alert-glyph"></i> <span class="alert-text">Cards for science uses local storage to store your current progress.</span>';
alert += '</div>';
alert = $(alert);
alert.find('button').click(function ()
{
Cookies.set('cookielaw', 'informed', { expires: 365 });
$('#cookielaw').slideUp(300, function() { $('#cookielaw').remove(); });
})
$('#messages-container').append(alert);
}
// display new user alert
// if (typeof Cookies.get('cern60') === 'undefined') {
// var alert = '<div id="cern60" class="alert alert-info" role="alert">';
// alert += '<button type="button" class="btn btn-primary">Close</button>';
// alert += '<i class="fa fa-area-chart alert-glyph"></i> <span class="alert-text"><a class="alert-link" href="http://home.web.cern.ch/about/updates/2014/12/take-part-cern-60-public-computing-challenge" target="_blank">Join the CERN 60 computing challenge!</a></span>';
// alert += '</div>';
// alert = $(alert);
// alert.find('button').click(function ()
// {
// Cookies.set('cern60', 'closed', { expires: 365 });
// $('#cern60').slideUp(300, function() { $('#cern60').remove(); });
// })
//
// $('#messages-container').append(alert);
// }
return {
showAchievement: showAchievement,
showModal: showModal,
showLevels: showLevels,
showUpdateValue: showUpdateValue
};
})(FastClick,Cookies);
//
// // I don't know what this is for, so I leave it here for the moment...
// (function() {
// var hidden = "hidden";
//
// // Standards:
// if (hidden in document)
// document.addEventListener("visibilitychange", onchange);
// else if ((hidden = "mozHidden") in document)
// document.addEventListener("mozvisibilitychange", onchange);
// else if ((hidden = "webkitHidden") in document)
// document.addEventListener("webkitvisibilitychange", onchange);
// else if ((hidden = "msHidden") in document)
// document.addEventListener("msvisibilitychange", onchange);
// // IE 9 and lower:
// else if ('onfocusin' in document)
// document.onfocusin = document.onfocusout = onchange;
// // All others:
// else
// window.onpageshow = window.onpagehide
// = window.onfocus = window.onblur = onchange;
//
// function onchange (evt) {
// var v = 'visible', h = 'hidden',
// evtMap = {
// focus:v, focusin:v, pageshow:v, blur:h, focusout:h, pagehide:h
// };
//
// evt = evt || window.event;
// if (evt.type in evtMap)
// detector.visible = evtMap[evt.type] == 'visible';
// else
// detector.visible = !this[hidden];
// }
// })();