[virtualcommons-developer] commit/vcweb: alllee: updating bootstrap tour and setup tour functions
Status: Beta
Brought to you by:
alllee
From: <com...@bi...> - 2013-03-28 01:20:55
|
1 new commit in vcweb: https://bitbucket.org/virtualcommons/vcweb/commits/23749c5b2471/ Changeset: 23749c5b2471 User: alllee Date: 2013-03-28 02:20:36 Summary: updating bootstrap tour and setup tour functions Affected #: 2 files diff -r 692ba46bcd6e5764dbf51180b04029fa8d5b04f6 -r 23749c5b2471a37184240038ba2dccd91ecfad02 vcweb/broker/templates/broker/participate.html --- a/vcweb/broker/templates/broker/participate.html +++ b/vcweb/broker/templates/broker/participate.html @@ -22,8 +22,7 @@ <div> Please wait. The experiment will continue shortly once all the participants are ready. <p> -<span class='badge' - data-bind='css: { "badge-important": readyParticipants() < (totalNumberOfParticipants() / 2), "badge-success": readyParticipants() > (totalNumberOfParticipants() / 2)}, text: readyParticipants'></span> + <span class='badge' data-bind='css: { "badge-important": readyParticipants() < (totalNumberOfParticipants() / 2), "badge-success": readyParticipants() > (totalNumberOfParticipants() / 2)}, text: readyParticipants'></span> of <span class='badge badge-success' data-bind='text: totalNumberOfParticipants'></span> participants are ready. </p> @@ -288,6 +287,7 @@ This is a practice round. The decisions you make in this round will <b>NOT</b> contribute to your earnings. <span data-bind="if: isFirstPracticeRound"> + <button class='btn btn-primary' data-bind='click: setupFirstPracticeRoundTour'>Tour</button><a href="#" data-bind="">Show me 1st Instructions again</a></span> @@ -493,26 +493,102 @@ }); model.setupFirstPracticeRoundTour = function () { // set up first bootstrap tour - alert("setting up first practice round tour"); - + var tourFirst = new Tour({ + useLocalStorage: true, + onShow: function(tour) { + alert("showing tour"); + } + }); + tourFirst.addStep({ + element: "harvestDecisionId", + title: "Here's where you insert your harvesting decision", + content: "For this practice round, go ahead and put 6 hours into harvesting. Each round you will have a maximum of 6 minute to make a harvest decision.", /* content of the popover */ + placement: "right" + }); + tourFirst.addStep({ + element: "conservationDecision", + title: "Your conservation decision", + content: "Note that the rest of your available hours will be put into conservation.", + placement: "right" + }); + tourFirst.addStep({ + element: "submitDecision", + title: "Submit your decision", + content: "Now click here to submit your harvest choice. Your choice will be submitted automatically when time is up. A countdown will alert you when there are 10 seconds remaining to make a harvest. The default harvest is zero.", /* content of the popover */ + placement: "right" + }); + tourFirst.start(true); + tour = tourFirst; + console.debug("set up tour"); + console.debug(tour); }; model.setupSecondPracticeRoundTour = function () { - alert("setting up second practice round tour"); + var tourSecond = new Tour(); + tourSecond.addStep({ + element: "lastRoundHarvestPayOff", + title: "Your round earnings", + content: "Here you will see how much you earned in each round. You receive 0.6 from harvesting. Because everyone contributed 4 hours to conservation, resulting in 8 hours for group A and 8 hours for group B.", + placement: "right" + }); + tourSecond.addStep({ + element: "lastRoundGroupLocalBonus", + title: "Bonus", + content: "So the standard revenue of $0.10/hour has been increased by 50% you receive an extra $0.30 and your total is $0.90. If the sum within your group was less than 5 hours you would not receive benefits. ", + placement: "right" + }); + tourSecond.addStep({ + element: "lastRoundMyGroupConservation", + title: "Bonus", + content: "If the sum of conservation time of all players were more than 22 hours you would get a further increase of 50% in the revenues.", + placement: "right" + }); + tourSecond.addStep({ + element: "totalEarning", + title: "Total Earning", + content: "Here you can your total earning throughout the game", + placement: "right" + }); + tourSecond.addStep({ + element: "totalEarning", + title: "Communication", + content: "At some point during the game you will have the option of communicating to other players. Communication to the other player within your group is FREE. Communication with the other group costs 2 hours.", + }); + tourSecond.addStep({ + element: "totalEarning", + title: "", + content: "For this practice, go ahead and choose 'Communication within Group' and 'Communication with other Group'", + + }); + tourSecond.addStep({ + element: "totalEarning", + title: "Chat rooms", + content: "Communication will happen through these chat windows. Communications is time bound. Each message you send will be targeted a single player. Go ahead and send a message. It will not be seen by others for this practice.", + onHide: function (tourSecond) { + // post a dummy message to the chat... "Here's an example of a reply message" + } + + }); + tourSecond.addStep({ + element: "totalEarning", + title: "Chat rooms", + content: "Remember that all your choices are independent and none will see what your decisions are.", + }); + tourSecond.start(); }; model.update = function () { $.get('view-model', { participant_group_id: model.participantGroupId(), }, - function (response) { - console.debug("updating with response: "); - console.debug(response); - ko.mapping.fromJS(response, model); - if (model.isFirstPracticeRound()) { - model.setupFirstPracticeRoundTour(); - } - else if (model.isSecondPracticeRound()) { - model.setupSecondPracticeRoundTour(); - } - }); + function (response) { + console.debug("updating with response: "); + console.debug(response); + ko.mapping.fromJS(response, model); + if (model.isFirstPracticeRound()) { + model.setupFirstPracticeRoundTour(); + } + else if (model.isSecondPracticeRound()) { + model.setupSecondPracticeRoundTour(); + } + }); }; // activate instructions click bindings model.activateInstructionsPageOne = function () { @@ -555,54 +631,54 @@ model.conservationDecision = ko.computed(function () { return model.maxHarvestDecision() - model.harvestDecision(); }); -// model.numberOfTreesPerRow = ko.observable(10); -// model.isResourceEmpty = ko.computed(function() { -// return model.resourceLevel() == 0; -// }); -// model.resourcesToDisplay = ko.computed(function() { -// if (model.resourceLevel() > 0) { -// return Math.min(model.resourceLevel(), 20); -// } -// return 0; -// }); + // model.numberOfTreesPerRow = ko.observable(10); + // model.isResourceEmpty = ko.computed(function() { + // return model.resourceLevel() == 0; + // }); + // model.resourcesToDisplay = ko.computed(function() { + // if (model.resourceLevel() > 0) { + // return Math.min(model.resourceLevel(), 20); + // } + // return 0; + // }); -// + // model.startChatTimer = function () { model.enableChat(); model.secondsLeft(60); model.setCurrentInterval( - setInterval(function () { - model.tick(); - if (!model.isTimerRunning()) { - model.disableChat(); - model.clearCurrentInterval(); - } - }, - 1000)); + setInterval(function () { + model.tick(); + if (!model.isTimerRunning()) { + model.disableChat(); + model.clearCurrentInterval(); + } + }, + 1000)); }; model.startHarvestDecisionTimer = function () { model.secondsLeft(10); model.setCurrentInterval(setInterval(function () { - model.tick(); - if (!model.isTimerRunning()) { - model.submitDecision(); - model.clearCurrentInterval(); - } - }, - 1000)); + model.tick(); + if (!model.isTimerRunning()) { + model.submitDecision(); + model.clearCurrentInterval(); + } + }, + 1000)); }; model.startChatOptionTimer = function () { model.enableChatOption(); model.secondsLeft(10); model.setCurrentInterval( - setInterval(function () { - model.tick(); - if (!model.isTimerRunning()) { - model.disableChatOption(); - model.clearCurrentInterval(); - } - }, - 1000)); + setInterval(function () { + model.tick(); + if (!model.isTimerRunning()) { + model.disableChatOption(); + model.clearCurrentInterval(); + } + }, + 1000)); }; model.submitDecision = function (data, evt) { var formData = $('#vcweb-form').serialize(); @@ -618,36 +694,6 @@ // model.clearCurrentInterval(); }); }; -// model.submitChatMessage = function(data, evt) { -// evt.preventDefault(); -// console.log("clicking chat message"); -// var message = $('#chatText').val(); -// if (message) { -// $('#chatText').val(''); -// getWebSocket().send(createMessageEvent(message)); -// $('#chatText').focus(); -// } -// } -// model.disableChat = function() { -// $('#content').removeClass('span6').addClass('span9'); -// $('#sidebar').removeClass('span6').addClass('span3'); -// $('.chat-action').addClass('disabled').attr('disabled', true); -// model.chatEnabled(false); -// } -// model.enableChat = function() { -// $('#content').removeClass('span9').addClass('span6'); -// $('#sidebar').removeClass('span3').addClass('span6'); -// $('.chat-action').removeClass('disabled').attr('disabled', false); -// model.chatEnabled(true); -// } -// -// model.disableChatOption = function() { -// model.chatOptionEnabled(false); -// } -// model.enableChatOption = function() { -// model.chatOptionEnabled(true); -// } -// return model; } @@ -663,129 +709,22 @@ switch (data.event_type) { case 'chat': experimentModel.withinGroupChatMessages.unshift(data); - break; + break; case 'update': console.debug("updating view model"); experimentModel.update(); break; case 'participant_ready': experimentModel.readyParticipants(Math.min(experimentModel.totalNumberOfParticipants(), experimentModel.readyParticipants() + 1)); - // FIXME: replace with this later - // experimentModel.checkReadyParticipants(); - break; + // FIXME: replace with this later + // experimentModel.checkReadyParticipants(); + break; default: console.debug("unhandled json message:" + json); - break; + break; } }; -// $('#harvestDecision').keyup(function() { -// $('#harvestDecision').val(this.value.match(/\d+/)); -// }); - $('#pick-template').change(function () { - var templateName = $(this).val(); - console.debug("switching to template: " + templateName); - if (templateName === "PRACTICE") { - templateName = "REGULAR"; - experimentModel.practiceRound(true); - if (experimentModel.isFirstPracticeRound) { - console.debug("starting first practice round tour"); - - var tourFirst = new Tour({ - useLocalStorage: true - }); - tourFirst.addStep({ - element: "harvestDecisionId", - title: "Here's where you insert your harvesting decision", - content: "For this practice round, go ahead and put 6 hours into harvesting. Each round you will have a maximum of 6 minute to make a harvest decision.", /* content of the popover */ - placement: "right" - }); - tourFirst.addStep({ - element: "conservationDecision", - title: "Your conservation decision", - content: "Note that the rest of your available hours will be put into conservation.", - placement: "right" - }); - tourFirst.addStep({ - element: "submitDecision", - title: "Submit your decision", - content: "Now click here to submit your harvest choice. Your choice will be submitted automatically when time is up. A countdown will alert you when there are 10 seconds remaining to make a harvest. The default harvest is zero.", /* content of the popover */ - placement: "right" - }); - tourFirst.start(true); - tour = tourFirst; - console.debug("tour started"); - - - } else if (experimentModel.isSecondPracticeRound) { - var tourSecond = new Tour(); - alert("second tour"); - tourSecond.addStep({ - element: "lastRoundHarvestPayOff", - title: "Your round earnings", - content: "Here you will see how much you earned in each round. You receive 0.6 from harvesting. Because everyone contributed 4 hours to conservation, resulting in 8 hours for group A and 8 hours for group B.", - placement: "right" - }); - tourSecond.addStep({ - element: "lastRoundGroupLocalBonus", - title: "Bonus", - content: "So the standard revenue of $0.10/hour has been increased by 50% you receive an extra $0.30 and your total is $0.90. If the sum within your group was less than 5 hours you would not receive benefits. ", - placement: "right" - }); - tourSecond.addStep({ - element: "lastRoundMyGroupConservation", - title: "Bonus", - content: "If the sum of conservation time of all players were more than 22 hours you would get a further increase of 50% in the revenues.", - placement: "right" - }); - tourSecond.addStep({ - element: "totalEarning", - title: "Total Earning", - content: "Here you can your total earning throughout the game", - placement: "right" - }); - - tourSecond.addStep({ - element: "totalEarning", - title: "Communication", - content: "At some point during the game you will have the option of communicating to other players. Communication to the other player within your group is FREE. Communication with the other group costs 2 hours.", - }); - tourSecond.addStep({ - element: "totalEarning", - title: "", - content: "For this practice, go ahead and choose 'Communication within Group' and 'Communication with other Group'", - - }); - tourSecond.addStep({ - element: "totalEarning", - title: "Chat rooms", - content: "Communication will happen through these chat windows. Communications is time bound. Each message you send will be targeted a single player. Go ahead and send a message. It will not be seen by others for this practice.", - onHide: function (tourSecond) { - // post a dummy message to the chat... "Here's an example of a reply message" - } - - }); - tourSecond.addStep({ - element: "totalEarning", - title: "Chat rooms", - content: "Remember that all your choices are independent and none will see what your decisions are.", - }); - tourSecond.start(); - - - } - } - else if (templateName === "REGULAR") { - experimentModel.practiceRound(false); - } - experimentModel.templateName(templateName); - }); -// $('#pick-network-structure').change(function() { -// var networkStructure = $(this).val(); -// console.debug("choosing network structure: " + networkStructure); -// experimentModel.networkStructure(networkStructure); -// }); - } var experimentModelJson = $.parseJSON("{{ experimentModelJson|escapejs }}"); @@ -793,4 +732,4 @@ }); </script> -{% endblock %} + {% endblock %} diff -r 692ba46bcd6e5764dbf51180b04029fa8d5b04f6 -r 23749c5b2471a37184240038ba2dccd91ecfad02 vcweb/static/js/bootstrap-tour.js --- a/vcweb/static/js/bootstrap-tour.js +++ b/vcweb/static/js/bootstrap-tour.js @@ -1,10 +1,9 @@ -// Generated by CoffeeScript 1.6.1 - +// Generated by CoffeeScript 1.6.2 /* ============================================================ -# bootstrap-tour.js v0.1 -# http://pushly.github.com/bootstrap-tour/ +# bootstrap-tour.js v0.3.0 +# http://bootstraptour.com/ # ============================================================== -# Copyright 2012 Push.ly +# Copyright 2012-2013 Ulrich Sossou # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,12 +20,11 @@ (function() { - (function($, window) { var Tour, document; + document = window.document; Tour = (function() { - function Tour(options) { this._options = $.extend({ name: 'tour', @@ -35,19 +33,29 @@ next: 'Next »', prev: '« Prev' }, + template: "<div class='popover tour'><div class='arrow'></div><h3 class='popover-title'></h3><div class='popover-content'></div></div>", + container: 'body', keyboard: true, useLocalStorage: false, + debug: false, + backdrop: false, afterSetState: function(key, value) {}, afterGetState: function(key, value) {}, afterRemoveState: function(key) {}, onStart: function(tour) {}, onEnd: function(tour) {}, onShow: function(tour) {}, + onShown: function(tour) {}, onHide: function(tour) {}, - onShown: function(tour) {} + onHidden: function(tour) {} }, options); this._steps = []; this.setCurrentStep(); + this.backdrop = { + overlay: null, + step: null, + background: null + }; } Tour.prototype.setState = function(key, value) { @@ -77,6 +85,7 @@ Tour.prototype.getState = function(key) { var value; + if (this._options.useLocalStorage) { value = window.localStorage.getItem("" + this._options.name + "_" + key); } else { @@ -100,12 +109,16 @@ placement: "right", title: "", content: "", + id: "step-" + i, next: i === this._steps.length - 1 ? -1 : i + 1, prev: i - 1, animation: true, onShow: this._options.onShow, + onShown: this._options.onShown, onHide: this._options.onHide, - onShown: this._options.onShown + onHidden: this._options.onHidden, + template: this._options.template, + container: this._options.container }, this._steps[i]); } }; @@ -113,11 +126,12 @@ Tour.prototype.start = function(force) { var promise, _this = this; + if (force == null) { force = false; } if (this.ended() && !force) { - return; + return this._debug("Tour ended, start prevented."); } $(document).off("click.bootstrap-tour", ".popover .next").on("click.bootstrap-tour", ".popover .next", function(e) { e.preventDefault(); @@ -141,23 +155,28 @@ Tour.prototype.next = function() { var promise; + promise = this.hideStep(this._current); return this._callOnPromiseDone(promise, this.showNextStep); }; Tour.prototype.prev = function() { var promise; - return promise = this.hideStep(this._current); + + promise = this.hideStep(this._current); + return this._callOnPromiseDone(promise, this.showPrevStep); }; Tour.prototype.end = function() { var endHelper, hidePromise, _this = this; + endHelper = function(e) { $(document).off("click.bootstrap-tour"); $(document).off("keyup.bootstrap-tour"); $(window).off("resize.bootstrap-tour"); _this.setState("end", "yes"); + _this._hideBackdrop(); if (_this._options.onEnd != null) { return _this._options.onEnd(_this); } @@ -180,13 +199,21 @@ Tour.prototype.hideStep = function(i) { var hideStepHelper, promise, step, _this = this; + step = this.getStep(i); promise = this._makePromise((step.onHide != null ? step.onHide(this) : void 0)); hideStepHelper = function(e) { var $element; + $element = $(step.element).popover("hide"); if (step.reflex) { - return $element.css("cursor", "").off("click.boostrap-tour"); + $element.css("cursor", "").off("click.boostrap-tour"); + } + if (step.backdrop) { + _this._hideBackdrop(); + } + if (step.onHidden != null) { + return step.onHidden(_this); } }; this._callOnPromiseDone(promise, hideStepHelper); @@ -196,27 +223,36 @@ Tour.prototype.showStep = function(i) { var promise, showStepHelper, step, _this = this; + step = this.getStep(i); if (!step) { return; } promise = this._makePromise((step.onShow != null ? step.onShow(this) : void 0)); showStepHelper = function(e) { - var path; + var current_path, path; + _this.setCurrentStep(i); path = typeof step.path === "function" ? step.path.call() : step.path; - if (_this._redirect(path, document.location.pathname)) { + current_path = [document.location.pathname, document.location.hash].join(''); + if (_this._redirect(path, current_path)) { + _this._debug("Redirect to " + path); document.location.href = path; return; } if (!((step.element != null) && $(step.element).length !== 0 && $(step.element).is(":visible"))) { + _this._debug("Skip the step " + (_this._current + 1) + ". The element does not exist or is not visible."); _this.showNextStep(); return; } + if (step.backdrop) { + _this._showBackdrop(step.element); + } _this._showPopover(step, i); if (step.onShown != null) { - return step.onShown(_this); + step.onShown(_this); } + return _this._debug("Step " + (_this._current + 1) + " of " + _this._steps.length); }; return this._callOnPromiseDone(promise, showStepHelper); }; @@ -237,23 +273,32 @@ Tour.prototype.showNextStep = function() { var step; + step = this.getStep(this._current); return this.showStep(step.next); }; Tour.prototype.showPrevStep = function() { var step; + step = this.getStep(this._current); return this.showStep(step.prev); }; + Tour.prototype._debug = function(text) { + if (this._options.debug) { + return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text); + } + }; + Tour.prototype._redirect = function(path, currentPath) { return (path != null) && path !== "" && path.replace(/\?.*$/, "").replace(/\/?$/, "") !== currentPath.replace(/\/?$/, ""); }; Tour.prototype._showPopover = function(step, i) { - var content, nav, options, tip, + var $tip, content, nav, options, _this = this; + content = "" + step.content + "<br /><p>"; options = $.extend({}, this._options); if (step.options) { @@ -266,10 +311,10 @@ } nav = []; if (step.prev >= 0) { - nav.push("<a href='#" + step.prev + "' class='prev'>" + options.labels.prev + "</a>"); + nav.push("<a href='#' class='prev'>" + options.labels.prev + "</a>"); } if (step.next >= 0) { - nav.push("<a href='#" + step.next + "' class='next'>" + options.labels.next + "</a>"); + nav.push("<a href='#' class='next'>" + options.labels.next + "</a>"); } content += nav.join(" | "); content += "<a href='#' class='pull-right end'>" + options.labels.end + "</a>"; @@ -280,15 +325,18 @@ content: content, html: true, animation: step.animation, - container: "body" + container: step.container, + template: step.template }).popover("show"); - tip = $(step.element).data("popover").tip(); - this._reposition(tip, step); - return this._scrollIntoView(tip); + $tip = $(step.element).data("popover").tip(); + $tip.attr("id", step.id); + this._reposition($tip, step); + return this._scrollIntoView($tip); }; Tour.prototype._reposition = function(tip, step) { var offsetBottom, offsetRight, original_left, original_offsetHeight, original_offsetWidth, original_top, tipOffset; + original_offsetWidth = tip[0].offsetWidth; original_offsetHeight = tip[0].offsetHeight; tipOffset = tip.offset(); @@ -326,6 +374,7 @@ Tour.prototype._scrollIntoView = function(tip) { var tipRect; + tipRect = tip.get(0).getBoundingClientRect(); if (!(tipRect.top >= 0 && tipRect.bottom < $(window).height() && tipRect.left >= 0 && tipRect.right < $(window).width())) { return tip.get(0).scrollIntoView(true); @@ -341,6 +390,7 @@ Tour.prototype._setupKeyboardNavigation = function() { var _this = this; + if (this._options.keyboard) { return $(document).on("keyup.bootstrap-tour", function(e) { if (!e.which) { @@ -351,6 +401,8 @@ e.preventDefault(); if (_this._current < _this._steps.length - 1) { return _this.next(); + } else { + return _this.end(); } break; case 37: @@ -373,6 +425,7 @@ Tour.prototype._callOnPromiseDone = function(promise, cb, arg) { var _this = this; + if (promise) { return promise.then(function(e) { return cb.call(_this, arg); @@ -382,6 +435,57 @@ } }; + Tour.prototype._showBackdrop = function(el) { + if (this.backdrop.overlay !== null) { + return; + } + this._showOverlay(); + return this._showOverlayElement(el); + }; + + Tour.prototype._hideBackdrop = function() { + if (this.backdrop.overlay === null) { + return; + } + this._hideOverlayElement(); + return this._hideOverlay(); + }; + + Tour.prototype._showOverlay = function() { + this.backdrop = $('<div/>'); + this.backdrop.addClass('tour-backdrop'); + this.backdrop.height($(document).innerHeight()); + return $('body').append(this.backdrop); + }; + + Tour.prototype._hideOverlay = function() { + this.backdrop.remove(); + return this.backdrop.overlay = null; + }; + + Tour.prototype._showOverlayElement = function(el) { + var background, offset, padding, step; + + step = $(el); + padding = 5; + offset = step.offset(); + offset.top = offset.top - padding; + offset.left = offset.left - padding; + background = $('<div/>'); + background.width(step.innerWidth() + padding).height(step.innerHeight() + padding).addClass('tour-step-background').offset(offset); + step.addClass('tour-step-backdrop'); + $('body').append(background); + this.backdrop.step = step; + return this.backdrop.background = background; + }; + + Tour.prototype._hideOverlayElement = function() { + this.backdrop.step.removeClass('tour-step-backdrop'); + this.backdrop.background.remove(); + this.backdrop.step = null; + return this.backdrop.background = null; + }; + return Tour; })(); Repository URL: https://bitbucket.org/virtualcommons/vcweb/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |