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.

619 lines (531 loc) 17.8 kB
$(document).ready(function(){ var ASC = RIPPLE.session.mainController , UTIL = RIPPLE.session.utilController , DISPLAY = RIPPLE.session.displayController , CHAT = new ChatController() , choicePopoverOpen = false , clientStatusBtn = $('#client-status-btn') , clearBtn = $('#clear-btn') , responseResizerHold = false , windowResizerHold = false , initialized = 0; now.initialize = function(){ initialized = 1; // Clear Student Questions now.distributeClear(); // Set room number $('#loading').hide(); $('#question-response-wrap').show(); $('#roomDisplay').html(now.room) $('#room-display-btn').slideDown(); // Load Set if needed loadSet(); } // Send message for initialization that taking exceptionally long setTimeout(function(){ if( initialized === 0 ) { var msg = ""; $('body').on('click','#reload-btn', function(){ location.reload(); }) // Alert Message msg += "<h1 class='no-bg'>Possible System Issue</h1>"; msg += "<p>System is having trouble setting up the room for some reason.</p><br />"; msg += "<h6>If the problem persists for 15 seconds, please refresh or close and reopen the session.</h6>" msg += "<button id='reload-btn' class='btn btn-primary'>Refresh</button>"; $('#loading').html(msg); } }, 15000); // Must be available to now or throws errors now.clientClearQuestion = function(){}; now.clientSetPolling = function(){}; now.clientStopSession = function(){}; now.receiveMessage = function(name, message){ CHAT.receiveMessage(name, message); } now.receiveAnswer = function(clientID, name, answer){ ASC.recieveAnswer(clientID, name, answer); } now.receiveQuestion = function(name, message){ } // Make editor wysiwyg $('#qTxt') .wysihtml5( GLOBALS.wysihtml5Options ) //Move modal to body for bug fix of modal being behind overlay layer $('.bootstrap-wysihtml5-insert-image-modal, .bootstrap-wysihtml5-insert-link-modal').appendTo('body') // Check to see if session was reloaded if( GLOBALS.reload ) DISPLAY.reloadPrompt(); // Have logout close parent window $('#btn-close-session').on('click keypress', function(e){ if( !isKeypressEnter(e) ) return; DISPLAY.confirmClose(); }); // Presenter closes window $(window).bind("beforeunload", function(){ now.distributeStopSession(); }); $('#question-response-wrap').hide(); $('#room-fullscreen').click(function(e){ roomURL = "<div class='roomLinkDisplay'>Room ID: <strong>" + now.room + "</strong></div>"; DISPLAY.showRoomFullscreen(roomURL, 'Room ID:'); e.preventDefault(); }); // Send Message $("#message-btn").click(function(){ CHAT.sendMessage(now.distributeMessage); }); $('#message-txt').blur(function(){ window.scrollTo(0,1); }); // Send Question $("#send-btn").click(function(){ // Disable button for 1 second so that double clicks do not initiate sends $(this).attr('disabled','disabled'); setTimeout(function(){ $("#send-btn").removeAttr('disabled'); }, 1000); // Resest Polling setPolling("on"); // Send Question Out ASC.sendQuestion(now.distributeQuestion); // Show Stop & Clear btn clientStatusBtn.show(); clearBtn.show(); }); // Clear Question clearBtn.on("click", function(e){ DISPLAY.reset('clear'); ASC.clearAnsVals(now.question.type); now.distributeClear(); $('#client-status-btn, #clear-btn').hide(); }); // Stop and Restart Client Polling $('#client-status-btn').on("click", function(e){ pollingToggle($(this)); }); // Window resizer $('#window-resizer').on('click', function(e){ if( windowResizerHold ) return; var $this = $(this) , newTitle , iconContract = 'icon-resize-small' , iconExpand = 'icon-resize-full' , removeClass , addClass , icon = ""; if( $this.find('i').hasClass(iconContract) ){ window.resizeTo(320,screen.height); newTitle = "Expand Window"; removeClass = iconContract; addClass = iconExpand; } else { window.resizeTo(screen.width,screen.height); newTitle = "Minimize Window"; removeClass = iconExpand; addClass = iconContract; } // Update button $this .attr('title', newTitle) .tooltip('fixTitle') .tooltip('hide') .find('i') .removeClass(removeClass) .addClass(addClass); // Make sure resizer is effected by double clicks windowResizerHold = true; setTimeout(function(){ windowResizerHold = false; }, 200) }) // Expand Response to take full width $("#response-resizer").on('click', function(e){ if( $(this).find('i').hasClass('icon-resize-full') ) sizeResponse('max'); else sizeResponse('min'); }); // Collapse Answer Option Area in smaller screens $('#question-wrap').on('click keypress', '#qOption-chevron', function(e){ if( !isKeypressEnter(e) ) return; DISPLAY.qOptionToggle('toggle'); }) // Add Resizing when $('#slidebar-btn').click(function(){ checkResponseSize(); }); // Flash functionality $('#answers') // Show answers .on("click", "#flash-show", function(e){ if( !isKeypressEnter(e) ) return; ASC.setOpenFlash( false ); $('#answers .flashwell').stop(true, true).show(); $('#flash-hide').show(); $(this).hide(); }) // Hide answers .on("click", "#flash-hide", function(e){ if( !isKeypressEnter(e) ) return; ASC.setOpenFlash( true ); $('#answers .flashwell').hide(); $('#flash-show').show(); $(this).hide(); }) // Remove Response .on("click keypress", ".flashwell .remove-response", function(e){ var $this = $(this); if( !isKeypressEnter(e) ) return; // Hide well $this.closest(".flashwell").remove(); }); $("#type").change(function(){ displayQuestion($(this).val()); if( $('#set-questions').length ) $('#set-questions').val(0); }); // Hide all the progress labels $('.ui-progress .ui-label').hide(); //hide button choices div $('#question-choices-wrap').hide(); // Make Bootstrap Dropdown $('.dropdown-toggle').dropdown(); // Make Set Question Choice create Question with correct answer $('#set-questions').change(function(){ var qID = $(this).val() , type = (setQuestions[qID]['type']) ? setQuestions[qID]['type'] : ""; $('#type').val(type); displayQuestion(type); var typeSelect = $('#type'); typeSelect.find('option').removeAttr('selected'); typeSelect.find('option[value="' + type + '"]').attr('selected', 'selected'); DISPLAY.fillOptions(setQuestions[qID]); }); // Show/Hide Answer Option Area answerOptionDisplay( $('#type').val() ); displayQuestion($('#type').val()); // Toggle Individual Response Names $('#toggle-names button').on('click keydown', function(e){ // Only run if click was enter or it was a keypress enter if( !isKeypressEnter(e) ) return; var $this = $(this) , stateClass = $this.attr('data-state') , jToggleName = $('#toggle-names') , jResponses = $('#responses') , hideClass = 'hide-names' , activeClasses = 'btn-primary btn-active'; // Change Active State if( stateClass === hideClass) jResponses.addClass(hideClass); else jResponses.removeClass(hideClass); jToggleName.find('button').removeClass(activeClasses); $this.addClass(activeClasses); }); var loadSet = function(){ // Prefill first Question from set if( $('#set-questions').length != 0 ) { var firstID = 0; // Hide display of #type selector $('#type').hide(); $('#type-header').show(); // identify the first question ID for( var item in setQuestions){ firstID = item; break; } // Make the set selector the right value $('#set-questions').val(firstID); // Set the question type var setQType = setQuestions[firstID]['type']; $('#type').val(setQType) displayQuestion( setQType ); // Fill data in for first question in set DISPLAY.fillOptions( setQuestions[firstID] ); // Popover functionality to "Add a Question" popover( $('#btn-question-choice'), "bottom" ); // Make popover hide if clicked outside or close w/ "esc" $(document) .on('click', function(e){ //Do not Fire Action for Question Choice Button var isChild = $(e.target).parent('#btn-question-choice').length if( e.target.id == "btn-question-choice" || isChild ) return false; // Close Popover if open if( choicePopoverOpen ) { popoverClose(); choicePopoverOpen = false; } e.preventDefault(); }) .on('keydown', function(e){ if( isKeypressEsc(e) ) { // Disregard if popover is not open if( !popoverOpen ) return; // Close Popover popoverClose(); choicePopoverOpen = false; $('#btn-question-choice').focus(); } }); // Make popover buttons functional $(document).on('click', 'button.question-type', function(){ var type = $(this).attr('data-qtype') ; $('#type').val( type ); displayQuestion( type ); $('#set-questions').val(0); }); // Close Popover if open $(document).on('focusout', '.wysihtml5-toolbar a[data-wysihtml5-command="bold"], #set-next-btn', function(){ popoverClose(); choicePopoverOpen = false; }); // Previous & Next Button actions $('#set-prev-btn').on('click keypress', function(e){ // Only run if click was enter and it was a keypress if( !isKeypressEnter(e) ) return cycleSetQuestion(e, 'prev'); }) $('#set-next-btn').on('click keypress', function(e){ // Only run if click was enter and it was a keypress if( !isKeypressEnter(e) ) return cycleSetQuestion(e, 'next'); }) // Wysiwyg UX $('#question .wysihtml5-toolbar a.btn') // Make buttons tab able .attr('tabindex', "0") // Make buttons have tooltips .attr('data-placement', "top") .tooltip(); } } $(window).resize(function() { checkResponseSize(); }); function displayQuestion(type){ // Check for Required Class, Methods and Parameters var passCheck = RIPPLE.checkClass(type) , qTypeClass = RIPPLE.questionType[type]; // Clear Display DISPLAY.reset('wipe'); DISPLAY.answers(""); // Clear Timers ASC.clearTimers(); /** * Hook fired when a question type is displayed. * * @event displayQuestionFn */ var hasClearFn = qTypeClass.hasOwnProperty('displayQuestionFn'); if( passCheck && hasClearFn ) qTypeClass.displayQuestionFn(); /** * Property to determine if a question type displays the answer * option area. * * @property displayOptions * @for plugin-client.session * @type boolean * @default null */ var hasClearFn = qTypeClass.hasOwnProperty('displayOptions'); if( passCheck && hasClearFn ) DISPLAY.answerOptionDisplay( qTypeClass.displayOptions ); else DISPLAY.answerOptionDisplay( false ); // Hide Start/Stop btn setPolling('on'); clientStatusBtn.hide(); // Hide Clear Button clearBtn.hide(); // Replicate header for Session with Sets $('#type-header').html( $('#type :selected').text() ); // Clear Student Questions if( now.hasOwnProperty('distributeClear') ) now.distributeClear(); // Check for tooltips $('#qOptions [rel="tooltip"]').tooltip(); } function cycleSetQuestion(e, direction){ var setSelect = $('#set-questions') , setSelectLen = setSelect.find('option').length , selectIndexLen = setSelectLen - 1 , setSelectIndex = setSelect.prop("selectedIndex"); // Determine direction and index to move to if (direction === 'prev') { // If it is the first question item then move to the last of the list if( setSelectIndex === 1 ) setSelectIndex = selectIndexLen else setSelectIndex--; } else if(direction === 'next') { if(setSelectIndex === selectIndexLen ) setSelectIndex = 1; else setSelectIndex++; } // Set new selectedIndex setSelect.prop("selectedIndex", setSelectIndex); // Display new question information var qID = setSelect.val() , type = setQuestions[qID]['type'] ? setQuestions[qID]['type'] : ""; $('#type').val( type ); answerOptionDisplay( type ); displayQuestion( type ); DISPLAY.fillOptions( setQuestions[qID] ); } function sizeResponse(status){ if( responseResizerHold ) return false; var $resizer = $('#response-resizer') , title , addClass , removeClass , wrapWidth , wrapMinHeight , wrapRemoveClass = "" , wrapAddClass = "" , iconMax = 'icon-resize-full' , iconMin = 'icon-resize-small' , wrap = $("#response-wrap") , parent = wrap.parent() , type = $('#type').val(); switch(status){ case "max": // Make space for the response what will be taken out of flow parent.css("height", parent.css("height") ); // Add class which makes div position absolute wrapMinHeight = $('#question-wrap').height() - 340; wrapAddClass = 'max'; // Button Atrributes title = "Minimize Responses" addClass = iconMin; removeClass = iconMax; // Show Question $('#question-sent').show(); break; case "min": // Make parent auto height parent.css("height", "auto"); // Put div back in flow of page wrapMinHeight = "auto"; wrapRemoveClass = 'max'; // Button Atrributes title = "Expand Responses" addClass = iconMax; removeClass = iconMin; // Show Question $('#question-sent').hide(); break; } // Make container width correct wrap .addClass(wrapAddClass) .removeClass(wrapRemoveClass) .css("width", wrapWidth) .css("min-height", wrapMinHeight); $resizer .attr('title', title) .tooltip('hide') .tooltip('fixTitle') .find('i') .removeClass(removeClass) .addClass(addClass) // Make sure resizer is effected by double clicks responseResizerHold = true; setTimeout(function(){ responseResizerHold = false; }, 200) /** * Hook fired when the response area is resized on Client UI * * @event resizeAnswersFn * @for plugin-client.session */ // Check for Class, Methods, & Params var passCheck = RIPPLE.checkClass(type); var hasClearFn = RIPPLE.questionType[type].hasOwnProperty('resizeAnswersFn'); if( passCheck && hasClearFn ) RIPPLE.questionType[type].resizeAnswersFn(); } function checkResponseSize(){ if( $('#response-wrap').hasClass('max') ) { sizeResponse('max'); } }; function popover(jElem, placement){ jElem.popover({ trigger: 'manual', content: $('#question-choices-wrap').html(), placement: placement, title: "Available Question Types", html: true }).click(function(e){ position = ( $(this).attr('data-panel-position') ) ? $(this).attr('data-panel-position') : ""; positionRef = $(this).closest('.question-set-section'); popoverToggle(); // Current focus of popover cases consistency issue so it is commented out // May be added back in at a later point if resolved // if( keyCode(e) ) popoverFocus(); }) } function answerOptionDisplay(type){ var answerOption = $('#question-wrap .answer-options') , display = false; // Determine if answer option is needed. switch(type){ case 'multiple-choice': display = true; break; case 'slider': display = true; break; case 'numeric': display = true; break; } if( display == true ) answerOption.show(); else answerOption.hide(); } function popoverToggle(){ if( !choicePopoverOpen ) { popoverOpen(); choicePopoverOpen = true; popoverFocus(); } else { popoverClose(); choicePopoverOpen = false; } } function pollingToggle($jElem){ var status = $jElem.attr('data-action') , state = ""; // Toggle state & attributes if( status === "stop") { state = "off"; newStatus = "stop"; } else { state = "on"; newStatus = "start"; } setPolling( state ); if( $('#type').val() === 'dial' || $('#type').val() === 'slider' ) ASC.graphPolling( newStatus ); now.question.polling = state; now.distributePolling( state ); } function setPolling (state){ var btnContent = "" , dataAction = "" , startHtml = "Start <i class='icon-repeat'></i>" , stopHtml = "Stop <i class='icon-remove'>" if( state === "on" ){ ASC.setPolling(true); btnContent = stopHtml; dataAction = "stop"; } else { ASC.setPolling(false); btnContent = startHtml; dataAction = "start"; } clientStatusBtn.attr("data-action",dataAction).html(btnContent).show(); } }); function popoverClose() { $('#btn-question-choice').popover('hide'); } function popoverOpen() { $('#btn-question-choice').popover('show'); } function popoverFocus(){ setTimeout(function(){ $('.popover button:first').focus(); }, 250); }