UNPKG

ripple-core

Version:

Ripple is an interactive audience response system that allows presenters to survey audience members in real time communication through their mobile devices.

468 lines (387 loc) 14.1 kB
/** * Client Plugin Session API Module. * * @author William Myers * @class plugin-client.client * @title client * @space RIPPLE.questionType['<i>pluginName</i>'].client<br /> <span class="note"><i>pluginName</i> will be replaced by your plugin's name</span> */ RIPPLE.namespace('client'); // Set up session components RIPPLE.client.validator = new ClientValidator(); RIPPLE.client.controller = new ClientController(); RIPPLE.activeController = "client"; function ClientController(){ var that = this , VALID = RIPPLE.client.validator , notifyTimer = 0 , notifySpeed = 250 , controls = {} , announce = true , answer = "" , replace = true , displayAnswer = '' , sendBtn = $('#send-button'); /** * Clears previous question information */ this.clearQuestion = function(type){ console.log("Clear Question :: ", type); type = type || ''; switch(type){ case 'stop': $('#question').html('<h2>Presenter closed the session.</h2>'); break; default: $('#question').html('<h2>Waiting for Question...</h2>'); } $('#answer').html(''); $('#alert').html(''); $('#send-btn').hide(); sendBtn.removeAttr('disabled').hide(); // Close Growl $("div.jGrowl").jGrowl("close"); } /** * Show a Question that came from the presenter * @param {string} name [Type of question to show] */ this.showQuestion = function(name){ var that = this , qOptionsHTML = "" , cnt=0; // Compile Question Options if( now.question != null){ cnt++; var type = now.question.type; // Close Growl if open $("div.jGrowl").jGrowl("close"); // Show Question $("#question").html(now.question.qTxt); // Close Chat for new question GLOBALS.jPM.close(); // Scroll to top to show new question window.scrollTo(0, 0); // Remove data('disabled'); $('#answer').removeData('disabled'); // Check for Class, Methods, & Params /** * Hook fired when question is displayed to client * * @event displayFn */ var passCheck = RIPPLE.checkClass(type, 'displayFn') if( !passCheck ) return false; // Display html of question RIPPLE.questionType[type].displayFn( now.question ); // Move focus to input var firstInput = $('#answer input:first'); if( firstInput.length ) firstInput.focus(); // Android 2.x bug fix if(navigator.userAgent.match(/Android 2/)) { var contentHeight = $(window).height() + $('#answer').height(); $('body').css({'height':contentHeight}); } } }; this.sendInAnswer = function(elem, e){ var type = now.question.type; that.answer = ""; that.announce = true; that.replace = true; that.displayAnswer = ""; isValid = VALID.answer( type ); if( !isValid ) return false; // Check for Class, Methods, & Params var passCheck = RIPPLE.checkClass(type, 'sendFn') if( !passCheck ) return false; RIPPLE.questionType[type].sendFn(elem); // alert answer sent if( !that.replace && that.announce ) $.jGrowl( that.answerText(that.answer) ); if( that.replace ) { var displayAnswer = that.displayAnswer || that.answer; $('#answer').html('<div class="well display-answer">Your answer was submitted as:<br /><span class="submitted-answer">' + displayAnswer + '</span>'); } e.stopPropagation(); }; this.answerContent = function(html){ return $('#answer').html(html); }; this.alert = function(html){ return $('#alert').html(html); } this.showAnswer = function(html){ that.answerContent(html).show(); } this.sendBtn = { show: function(){ sendBtn.show(); }, disable: function(){ sendBtn.prop("disabled", true); }, enable: function(){ sendBtn.prop("disabled", false); }, hide: function(){ sendBtn.hide(); } }; this.createSlider = function(){ // load script if( $.data(document, "sliderScriptLoad") == undefined) { $.ajax({ url: '/static/js?jquery-ui-1.9.1.slider.min.js&jquery.ui.touch-punch.min.js', dataType: "script", cache: true, error: function(e, jqxhr, settings, exception) { $.jGrowl("SYSTEM ERROR :: jQuery UI not loaded - " + jqxhr); }, success: function(){ // Used so that script is only pulled once $.data(document, "sliderScriptLoad", true); that.sliderLoad(); } }); } else that.sliderLoad(); // add css $('head').append('<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.9.1/themes/base/jquery-ui.css" type="text/css" />'); }; this.sliderLoad = function(){ var that = this; controls.slider = {}; //Convert to usage associative array var qOptionsArr = now.question.qOptions; // Assign new array to current controller for use throughout script var qOptions = controls.slider.qOptions = that.convertQOptions(qOptionsArr); var submitOption = controls.slider.qOptions.submitOption; // Set min, max, and step controls.slider.minScale = 0; controls.slider.maxScale = (qOptions["scale"] != undefined) ? parseInt(qOptions["scale"]) : 10; controls.slider.stepScale = 1; // Create the Slider $("#slider").slider({ min: controls.slider.minScale, max: controls.slider.maxScale, step: controls.slider.stepScale, create: that.jqSliderCreate, slide: that.jqSliderMove }); $('.ui-slider-handle').bind('click', function(){ $(this).focus(); }); }; this.jqSliderCreate = function(event, ui){ var tickmarks = ["0","20","40","60","80", "100"] , tickDiv = ''; for (var i = tickmarks.length - 1; i >= 0; i--) { var tickPercentage = parseInt(tickmarks[i]) / 100; tickValue = controls.slider.maxScale * tickPercentage; if( tickValue < 10 && tickValue != 0 ) tickClass = 'single-digit'; else if( tickValue < 100) tickClass = 'double-digit'; else if( tickValue < 1000) tickClass = 'triple-digit'; else tickClass =''; var tickValueHtml = '<span class="tick-values ' + tickClass +'">' + tickValue + '</span>'; tickDiv += '<span class="tickmark marker-' + tickmarks[i] + '" style="left:' + tickmarks[i] + '%;position:absolute;"> <span class="tick-pipe">|</span> <br />' + tickValueHtml + '</span>'; } $("#slider").append("<div class='tickmark-wrap'>"+tickDiv+"</div>"); }; this.jqSliderMove = function( event, ui ){ var submitOption = controls.slider.qOptions.submitOption , send = false; // Create Tooltip $(this).find('.ui-slider-handle:last').html('<div class="tooltip top slider-tip"><div class="tooltip-arrow"></div><div class="tooltip-inner">' + ui.value + '</div></div>'); // Determine Submit Type switch(submitOption){ case 'continuous': that.jqSliderSendResponse( ui.value ); break; case 'variable': that.jqSliderSendResponseDelay( ui.value, 500 ); break; } }; // Current not in use for stop event because mobile Android does not fire event!!! // May be able to implement at a later point // // this.jqSliderStop = function( event, ui ) { // console.log("[jqSliderStop] args", arguments); // var submitOption = controls.slider.qOptions.submitOption // , send = false; // //alert("sent", ui.value); // console.log(controls.slider); // // alert(controls.slider) // // Determine Submit Type // switch(submitOption){ // case 'variable': // send = true; // break; // } // if(send) { // that.jqSliderSendResponseDelay( ui.value ); // } // }; this.jqSliderSendResponse = function(answer){ var submitOption = controls.slider.qOptions.submitOption; $('#slide-value').html("You Answered: " + answer); now.distributeAnswer({ answer: answer, qID: now.question.qID }); // Determin notification works based on submit type if( submitOption == 'variable') that.sliderSingleNotify(answer); else if ( submitOption == 'continuous') that.sliderContinuousNotify(answer); }; this.jqSliderSendResponseDelay = function(answer, wait){ var notifySpeed = wait || notifySpeed; // Clear Timer clearTimeout( notifyTimer ); // Reset Timer notifyTimer = setTimeout( function(){ that.jqSliderSendResponse(answer); }, notifySpeed); }; this.sliderSingleNotify = function(answer){ $("div.jGrowl").jGrowl("close"); $.jGrowl( that.answerText(answer), { beforeOpen: function(){ $("div.jGrowl").find('div.jGrowl-notification').children().parent().remove(); } }); }; this.sliderContinuousNotify = function(answer){ var slider = $('#slider'); if( slider.data('notify') != undefined && slider.data('notify') == 1 ) { $(".jGrowl-message").html("Sending... " + answer); clearTimeout( notifyTimer ); closeSpeed = notifySpeed * 2; notifyTimer = setTimeout( function(){ $.jGrowl("close"); }, closeSpeed); } else { slider.data('notify',1); $.jGrowl("Sending... " + answer,{ sticky: true, close: function() { slider.removeData('notify'); } }) } }; this.createNumeric = function(){ var that = this; controls.numeric = {}; qOptions = that.convertQOptions( now.question.qOptions ); // Create Select Options var inputOptions = ''; // Define paramters var min = controls.numeric.min = (qOptions["min"] != undefined) ? parseFloat(qOptions["min"]) : 0; var max = controls.numeric.max = (qOptions["max"] != undefined && qOptions["max"] != "") ? parseFloat(qOptions["max"]) : 10; var step = controls.numeric.step = (qOptions["step"] != undefined) ? parseFloat(qOptions["step"]) : 1; // Create Control var inputControl = '<input id="numeric" name="numeric" type="number" pattern="\\d+(\\.\\d*)?" min="' + min + '" max="' + max + '" step="' + step + '" value=""></input>'; inputControl += this.keypadHtml(); var controlHtml = '<div id="numeric-wrap">' + inputControl + '</div>'; return controlHtml; }; this.keypadHtml = function(){ var that = this , keypadHtml ="" , tmpHtml = "" , keypadArray = [] , corners = { "1": "btn-top-left", "3": "btn-top-right", ".": "btn-bottom-left", "CLR": "btn-bottom-right" } , rowEnd = [3,6,9]; for (var i = 1; i < 10; i++) { var buttonCornerClass = "" , indexString = i.toString(); // Added corner Classes if( corners[indexString] ) buttonCornerClass = corners[indexString]; // Create buttons tmpHtml += that.keypadButtonHtml(i, buttonCornerClass); // Wrap if end of row if( rowEnd.indexOf(i) !== -1) { // Wrap row tmpHtml = that.keypadRowHtml(tmpHtml); // Amend to keypadHtml keypadHtml += tmpHtml; // Clear tmpHtml tmpHtml = ""; } }; // Create Bottom row tmpHtml = that.keypadButtonHtml(".",corners["."]) + that.keypadButtonHtml("0") + that.keypadButtonHtml("CLR", corners["CLR"]); tmpHtml = that.keypadRowHtml(tmpHtml); keypadHtml += tmpHtml; tmpHtml = "" // Wrap keypad div keypadHtml = "<div id='keypad'>" + keypadHtml + "</div>"; return keypadHtml; }; this.keypadButtonHtml = function(value, classes){ classes = classes || ""; if( !value ) return; var keyClass = ( value === "CLR" ) ? 'control-key' : 'key'; return "<button class='span3 " + keyClass + " no-submit btn " + classes + "' tabindex='0'>" + value + "</button>"; } this.keypadRowHtml = function(buttonHtml){ return "<div class='row no-space'>" + buttonHtml + "</div>"; } this.numericKeypadLoad = function(e){ var numeric = $('#numeric'); if(numeric.val() == null) numeric.val(""); $('.key').on('click keypress', function(e){ if( !isKeypressEnter(e) ) return; var inputValue = ( numeric.val() ==="" && $(this).html() === "." ) ? "0." : this.innerHTML numeric.val( numeric.val() + inputValue ).focus(); e.preventDefault(); }); $('.control-key').on('click keypress', function(e){ if( !isKeypressEnter(e) ) return; numeric.val(""); e.preventDefault(); }); } this.answerText = function(answer){ return '<div class="answer-sent"><i class="icon-ok-sign"></i> Answer Sent :: ' + answer + '</div>' } this.buttonAnswerDistribute = function(elem){ var parent = $(elem).parent() , container = $('#answer') , display = ""; // If well is disabled exit function if( container.data('disabled') === true) { that.announce = false; return; } // Determine if it is a button click or a click inside the well if( parent.hasClass('buttonAnswers') ){ // Was well click var button = $(elem).find(":input[type='button']"); that.answer = button.val(); $(elem).addClass("highlight"); display = $(elem).find('.text-wrap').html(); } else{ // Was button click that.answer = $(elem).val(); $(elem).closest('.button-answer').addClass("highlight"); display = $(elem).closest('.button-answer').find('.text-wrap').html(); } // Disable Buttons & further clicks container.data('disabled', true); container.find('input').attr('disabled', 'disabled'); now.distributeAnswer({ answer: that.answer, qID: now.question.qID }); return display; }; } ClientController.prototype.convertQOptions = function(qOptionsArr){ var qOptions = {}; //Change to associative array for easy use for (var i = 0; i < qOptionsArr.length; i++) { var optionName = qOptionsArr[i].name; var optionValue = qOptionsArr[i].value; qOptions[optionName] = optionValue; }; return qOptions; };