jQuery slickQuiz plugin: support multiple quizes on the same page? - javascript

Please see comment under question first.
I apologize to those that have read this question so far (10 views). I'm still not sure of the syntax to pass in the quiz configuration but she apparently allows it.
I'm trying to make a small change so the slickQuiz plugin supports multiple quizes on the same page, which the author 3 years suggested it probably can do. However it's loading in the same quiz questions and it seems due to the defining of quizJSON in slickQuiz-config.js file:
// Setup your quiz text and questions here
var quizJSON = {
"info": {
"name": "Test Your Knowledge!!",
"main": "<p>Think you're smart enough to be on Jeopardy?
... continues on ...
}
};
and the following line in slickQuiz.js, apparently allowing no variability on the quizJSON configuration loaded in:
// Set via json option or quizJSON variable (see slickQuiz-config.js)
var quizValues = (plugin.config.json ? plugin.config.json : typeof quizJSON != 'undefined' ? quizJSON : null);
I'm quite new to Javascript and am not sure how I could pass something in to set which quiz configuration (questions/answers) file is used for quizValues . Note the plugin includes a tiny master.js file, where it appears I can set a different id for each quiz:
// master.js file -- originally just defined #slickQuiz
$(function () {
$('#slickQuiz').slickQuiz();
});
$(function () {
$('#slickQuiz2').slickQuiz();
});
But how do I pass a parameter into slickQuiz() that I can use inside slickQuiz.js? This is probably trivial, but the way the function is invoked and its options are confusing to me new to JS.
Note here is how the slickQuiz id gets used in the plugin's example html file:
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type">
<title>SlickQuiz Demo</title>
<link href="css/reset.css" media="screen" rel="stylesheet" type="text/css">
<link href="css/slickQuiz.css" media="screen" rel="stylesheet" type="text/css">
<link href="css/master.css" media="screen" rel="stylesheet" type="text/css">
</head>
<body id="slickQuiz">
<h1 class="quizName"><!-- where the quiz name goes --></h1>
<div class="quizArea">
<div class="quizHeader">
<!-- where the quiz main copy goes -->
<a class="button startQuiz" href="#">Get Started!</a>
</div>
<!-- where the quiz gets built -->
</div>
<div class="quizResults">
<h3 class="quizScore">You Scored: <span><!-- where the quiz score goes --></span></h3>
<h3 class="quizLevel"><strong>Ranking:</strong> <span><!-- where the quiz ranking level goes --></span></h3>
<div class="quizResultsCopy">
<!-- where the quiz result copy goes -->
</div>
</div>
<script src="js/jquery.js"></script>
<script src="js/slickQuiz-config.js"></script>
<script src="js/slickQuiz.js"></script>
<script src="js/master.js"></script>
</body>
</html>
Here is most of the slickQuiz.js file (only allowed to copy in so much, rest at link above):
/*!
* SlickQuiz jQuery Plugin
(function($){
$.slickQuiz = function(element, options) {
var plugin = this,
$element = $(element),
_element = '#' + $element.attr('id'),
defaults = {
checkAnswerText: 'Check My Answer!',
nextQuestionText: 'Next »',
backButtonText: '',
completeQuizText: '',
tryAgainText: '',
questionCountText: 'Question %current of %total',
preventUnansweredText: 'You must select at least one answer.',
questionTemplateText: '%count. %text',
scoreTemplateText: '%score / %total',
nameTemplateText: '<span>Quiz: </span>%name',
skipStartButton: false,
numberOfQuestions: null,
randomSortQuestions: false,
randomSortAnswers: false,
preventUnanswered: false,
disableScore: false,
disableRanking: false,
scoreAsPercentage: false,
perQuestionResponseMessaging: true,
perQuestionResponseAnswers: false,
completionResponseMessaging: false,
displayQuestionCount: true, // Deprecate?
displayQuestionNumber: true, // Deprecate?
animationCallbacks: { // only for the methods that have jQuery animations offering callback
setupQuiz: function () {},
startQuiz: function () {},
resetQuiz: function () {},
checkAnswer: function () {},
nextQuestion: function () {},
backToQuestion: function () {},
completeQuiz: function () {}
},
events: {
onStartQuiz: function (options) {},
onCompleteQuiz: function (options) {} // reserved: options.questionCount, options.score
}
},
// Class Name Strings (Used for building quiz and for selectors)
questionCountClass = 'questionCount',
questionGroupClass = 'questions',
questionClass = 'question',
answersClass = 'answers',
responsesClass = 'responses',
completeClass = 'complete',
correctClass = 'correctResponse',
incorrectClass = 'incorrectResponse',
correctResponseClass = 'correct',
incorrectResponseClass = 'incorrect',
checkAnswerClass = 'checkAnswer',
nextQuestionClass = 'nextQuestion',
lastQuestionClass = 'lastQuestion',
backToQuestionClass = 'backToQuestion',
tryAgainClass = 'tryAgain',
// Sub-Quiz / Sub-Question Class Selectors
_questionCount = '.' + questionCountClass,
_questions = '.' + questionGroupClass,
_question = '.' + questionClass,
_answers = '.' + answersClass,
_answer = '.' + answersClass + ' li',
_responses = '.' + responsesClass,
_response = '.' + responsesClass + ' li',
_correct = '.' + correctClass,
_correctResponse = '.' + correctResponseClass,
_incorrectResponse = '.' + incorrectResponseClass,
_checkAnswerBtn = '.' + checkAnswerClass,
_nextQuestionBtn = '.' + nextQuestionClass,
_prevQuestionBtn = '.' + backToQuestionClass,
_tryAgainBtn = '.' + tryAgainClass,
// Top Level Quiz Element Class Selectors
_quizStarter = _element + ' .startQuiz',
_quizName = _element + ' .quizName',
_quizArea = _element + ' .quizArea',
_quizResults = _element + ' .quizResults',
_quizResultsCopy = _element + ' .quizResultsCopy',
_quizHeader = _element + ' .quizHeader',
_quizScore = _element + ' .quizScore',
_quizLevel = _element + ' .quizLevel',
// Top Level Quiz Element Objects
$quizStarter = $(_quizStarter),
$quizName = $(_quizName),
$quizArea = $(_quizArea),
$quizResults = $(_quizResults),
$quizResultsCopy = $(_quizResultsCopy),
$quizHeader = $(_quizHeader),
$quizScore = $(_quizScore),
$quizLevel = $(_quizLevel)
;
// Reassign user-submitted deprecated options
var depMsg = '';
if (options && typeof options.disableNext != 'undefined') {
if (typeof options.preventUnanswered == 'undefined') {
options.preventUnanswered = options.disableNext;
}
depMsg += 'The \'disableNext\' option has been deprecated, please use \'preventUnanswered\' in it\'s place.\n\n';
}
if (options && typeof options.disableResponseMessaging != 'undefined') {
if (typeof options.preventUnanswered == 'undefined') {
options.perQuestionResponseMessaging = options.disableResponseMessaging;
}
depMsg += 'The \'disableResponseMessaging\' option has been deprecated, please use' +
' \'perQuestionResponseMessaging\' and \'completionResponseMessaging\' in it\'s place.\n\n';
}
if (options && typeof options.randomSort != 'undefined') {
if (typeof options.randomSortQuestions == 'undefined') {
options.randomSortQuestions = options.randomSort;
}
if (typeof options.randomSortAnswers == 'undefined') {
options.randomSortAnswers = options.randomSort;
}
depMsg += 'The \'randomSort\' option has been deprecated, please use' +
' \'randomSortQuestions\' and \'randomSortAnswers\' in it\'s place.\n\n';
}
if (depMsg !== '') {
if (typeof console != 'undefined') {
console.warn(depMsg);
} else {
alert(depMsg);
}
}
// End of deprecation reassignment
plugin.config = $.extend(defaults, options);
// Set via json option or quizJSON variable (see slickQuiz-config.js)
var quizValues = (plugin.config.json ? plugin.config.json : typeof quizJSON != 'undefined' ? quizJSON : null);
// Get questions, possibly sorted randomly
var questions = plugin.config.randomSortQuestions ?
quizValues.questions.sort(function() { return (Math.round(Math.random())-0.5); }) :
quizValues.questions;
// Count the number of questions
var questionCount = questions.length;
// Select X number of questions to load if options is set
if (plugin.config.numberOfQuestions && questionCount >= plugin.config.numberOfQuestions) {
questions = questions.slice(0, plugin.config.numberOfQuestions);
questionCount = questions.length;
}
// some special private/internal methods
var internal = {method: {
// get a key whose notches are "resolved jQ deferred" objects; one per notch on the key
// think of the key as a house key with notches on it
getKey: function (notches) { // returns [], notches >= 1
var key = [];
for (i=0; i<notches; i++) key[i] = $.Deferred ();
return key;
},
// put the key in the door, if all the notches pass then you can turn the key and "go"
turnKeyAndGo: function (key, go) { // key = [], go = function ()
// when all the notches of the key are accepted (resolved) then the key turns and the engine (callback/go) starts
$.when.apply (null, key). then (function () {
go ();
});
},
// get one jQ
getKeyNotch: function (key, notch) { // notch >= 1, key = []
// key has several notches, numbered as 1, 2, 3, ... (no zero notch)
// we resolve and return the "jQ deferred" object at specified notch
return function () {
key[notch-1].resolve (); // it is ASSUMED that you initiated the key with enough notches
};
}
}};
plugin.method = {
// Sets up the questions and answers based on above array
setupQuiz: function(options) { // use 'options' object to pass args
var key, keyNotch, kN;
key = internal.method.getKey (3); // how many notches == how many jQ animations you will run
keyNotch = internal.method.getKeyNotch; // a function that returns a jQ animation callback function
kN = keyNotch; // you specify the notch, you get a callback function for your animation
$quizName.hide().html(plugin.config.nameTemplateText
.replace('%name', quizValues.info.name) ).fadeIn(1000, kN(key,1));
$quizHeader.hide().prepend($('<div class="quizDescription">' + quizValues.info.main + '</div>')).fadeIn(1000, kN(key,2));
$quizResultsCopy.append(quizValues.info.results);
// add retry button to results view, if enabled
if (plugin.config.tryAgainText && plugin.config.tryAgainText !== '') {
$quizResultsCopy.append('<p><a class="button ' + tryAgainClass + '" href="#">' + plugin.config.tryAgainText + '</a></p>');
}
// Setup questions
var quiz = $('<ol class="' + questionGroupClass + '"></ol>'),
count = 1;
// Loop through questions object
for (i in questions) {
if (questions.hasOwnProperty(i)) {
var question = questions[i];
var questionHTML = $('<li class="' + questionClass +'" id="question' + (count - 1) + '"></li>');
if (plugin.config.displayQuestionCount) {
questionHTML.append('<div class="' + questionCountClass + '">' +
plugin.config.questionCountText
.replace('%current', '<span class="current">' + count + '</span>')
.replace('%total', '<span class="total">' +
questionCount + '</span>') + '</div>');
}
var formatQuestion = '';
if (plugin.config.displayQuestionNumber) {
formatQuestion = plugin.config.questionTemplateText
.replace('%count', count).replace('%text', question.q);
} else {
formatQuestion = question.q;
}
questionHTML.append('<h3>' + formatQuestion + '</h3>');
// Count the number of true values
var truths = 0;
for (i in question.a) {
if (question.a.hasOwnProperty(i)) {
answer = question.a[i];
if (answer.correct) {
truths++;
}
}
}
// Now let's append the answers with checkboxes or radios depending on truth count
var answerHTML = $('<ul class="' + answersClass + '"></ul>');
// Get the answers
var answers = plugin.config.randomSortAnswers ?
question.a.sort(function() { return (Math.round(Math.random())-0.5); }) :
question.a;
// prepare a name for the answer inputs based on the question
var selectAny = question.select_any ? question.select_any : false,
forceCheckbox = question.force_checkbox ? question.force_checkbox : false,
checkbox = (truths > 1 && !selectAny) || forceCheckbox,
inputName = $element.attr('id') + '_question' + (count - 1),
inputType = checkbox ? 'checkbox' : 'radio';
if( count == quizValues.questions.length ) {
nextQuestionClass = nextQuestionClass + ' ' + lastQuestionClass;
}
for (i in answers) {
if (answers.hasOwnProperty(i)) {
answer = answers[i],
optionId = inputName + '_' + i.toString();
// If question has >1 true answers and is not a select any, use checkboxes; otherwise, radios
var input = '<input id="' + optionId + '" name="' + inputName +
'" type="' + inputType + '" /> ';
var optionLabel = '<label for="' + optionId + '">' + answer.option + '</label>';
var answerContent = $('<li></li>')
.append(input)
.append(optionLabel);
answerHTML.append(answerContent);
}
}
// Append answers to question
questionHTML.append(answerHTML);
// If response messaging is NOT disabled, add it
if (plugin.config.perQuestionResponseMessaging || plugin.config.completionResponseMessaging) {
// Now let's append the correct / incorrect response messages
var responseHTML = $('<ul class="' + responsesClass + '"></ul>');
responseHTML.append('<li class="' + correctResponseClass + '">' + question.correct + '</li>');
responseHTML.append('<li class="' + incorrectResponseClass + '">' + question.incorrect + '</li>');
// Append responses to question
questionHTML.append(responseHTML);
}
// Appends check answer / back / next question buttons
if (plugin.config.backButtonText && plugin.config.backButtonText !== '') {
questionHTML.append('' + plugin.config.backButtonText + '');
}
var nextText = plugin.config.nextQuestionText;
if (plugin.config.completeQuizText && count == questionCount) {
nextText = plugin.config.completeQuizText;
}
// If we're not showing responses per question, show next question button and make it check the answer too
if (!plugin.config.perQuestionResponseMessaging) {
questionHTML.append('' + nextText + '');
} else {
questionHTML.append('' + nextText + '');
questionHTML.append('' + plugin.config.checkAnswerText + '');
}
// Append question & answers to quiz
quiz.append(questionHTML);
count++;
}
}
// Add the quiz content to the page
$quizArea.append(quiz);
// Toggle the start button OR start the quiz if start button is disabled
if (plugin.config.skipStartButton || $quizStarter.length == 0) {
$quizStarter.hide();
plugin.method.startQuiz.apply (this, [{callback: plugin.config.animationCallbacks.startQuiz}]); // TODO: determine why 'this' is being passed as arg to startQuiz method
kN(key,3).apply (null, []);
} else {
$quizStarter.fadeIn(500, kN(key,3)); // 3d notch on key must be on both sides of if/else, otherwise key won't turn
}
internal.method.turnKeyAndGo (key, options && options.callback ? options.callback : function () {});
},
// Starts the quiz (hides start button and displays first question)
startQuiz: function(options) {
var key, keyNotch, kN;
key = internal.method.getKey (1); // how many notches == how many jQ animations you will run
keyNotch = internal.method.getKeyNotch; // a function that returns a jQ animation callback function
kN = keyNotch; // you specify the notch, you get a callback function for your animation
function start(options) {
var firstQuestion = $(_element + ' ' + _questions + ' li').first();
if (firstQuestion.length) {
firstQuestion.fadeIn(500, function () {
if (options && options.callback) options.callback ();
});
}
}
if (plugin.config.skipStartButton || $quizStarter.length == 0) {
start({callback: kN(key,1)});
} else {
$quizStarter.fadeOut(300, function(){
start({callback: kN(key,1)}); // 1st notch on key must be on both sides of if/else, otherwise key won't turn
});
}
internal.method.turnKeyAndGo (key, options && options.callback ? options.callback : function () {});
if (plugin.config.events &&
plugin.config.events.onStartQuiz) {
plugin.config.events.onStartQuiz.apply (null, []);
}
},
*** had to delete code because stackoverflow limits what I can put into a question,
here is the end of the slickQuiz file found at the link above:
plugin.init();
};
$.fn.slickQuiz = function(options) {
return this.each(function() {
if (undefined === $(this).data('slickQuiz')) {
var plugin = new $.slickQuiz(this, options);
$(this).data('slickQuiz', plugin);
}
});
};
})(jQuery);

Related

Definig element.sortable()-function

My html table supports changing the row-order using mouse drag and drop. The used jquery-ui version is v1.12.1. It works for old tables (i.e. those whose row count is known since load of the page), but it doesn't work for rows added after the page has been loaded. I think the reason is that the below sortable()-function is inside document.ready()-function.
<script type="text/javascript">
<script src="{% static 'js/jquery-ui.js' %}"></script>
$(document).ready(function(){
$('#luok_table tbody').sortable({
stop: function( event, ui ){
$(this).find('tr').each(function(i){
$(this).attr("id", $(this).attr("id").replace(/\d+/, i) );
$(this).find(':input').each(function(){
$(this).attr("id", $(this).attr("id").replace(/\d+/, i) );
$(this).attr("name", $(this).attr("name").replace(/\d+/, i) );
});
});
}
});
});
</script>
If that's the reason, where should I define the sortable()-function ?
The table rows are added by jquery-formset-js-script:
;(function($) {
$.fn.formset = function(opts)
{
var options = $.extend({}, $.fn.formset.defaults, opts),
flatExtraClasses = options.extraClasses.join(' '),
$$ = $(this),
applyExtraClasses = function(row, ndx) {
if (options.extraClasses) {
row.removeClass(flatExtraClasses);
row.addClass(options.extraClasses[ndx % options.extraClasses.length]);
}
},
updateElementIndex = function(elem, prefix, ndx) {
var idRegex = new RegExp('(' + prefix + '-\\d+-)|(^)'),
replacement = prefix + '-' + ndx + '-';
if (elem.attr("for")) elem.attr("for", elem.attr("for").replace(idRegex, replacement));
if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement));
if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement));
},
hasChildElements = function(row) {
return row.find('input,select,textarea,label').length > 0;
},
insertDeleteLink = function(row) {
if (row.is('TR')) {
// If the forms are laid out in table rows, insert
// the remove button into the last table cell:
row.children(':last').append('<a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + '</a>');
} else if (row.is('UL') || row.is('OL')) {
// If they're laid out as an ordered/unordered list,
// insert an <li> after the last list item:
row.append('<li><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a></li>');
} else {
// Otherwise, just insert the remove button as the
// last child element of the form's container:
row.append('<a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a>');
}
row.find('a.' + options.deleteCssClass).click(function() {
var row = $(this).parents('.' + options.formCssClass),
del = row.find('input:hidden[id $= "-DELETE"]');
if (del.length) {
// We're dealing with an inline formset; rather than remove
// this form from the DOM, we'll mark it as deleted and hide
// it, then let Django handle the deleting:
del.val('on');
row.hide();
} else {
row.remove();
// Update the TOTAL_FORMS form count.
// Also update names and IDs for all remaining form controls so they remain in sequence:
var forms = $('.' + options.formCssClass).not('.formset-custom-template');
$('#id_' + options.prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
applyExtraClasses(forms.eq(i), i);
forms.eq(i).find('input,select,textarea,label').each(function() {
updateElementIndex($(this), options.prefix, i);
});
}
}
// If a post-delete callback was provided, call it with the deleted form:
if (options.removed) options.removed(row);
return false;
});
};
$$.each(function(i) {
var row = $(this),
del = row.find('input:checkbox[id $= "-DELETE"]');
if (del.length) {
// If you specify "can_delete = True" when creating an inline formset,
// Django adds a checkbox to each form in the formset.
// Replace the default checkbox with a hidden field:
del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" />');
del.remove();
}
if (hasChildElements(row)) {
insertDeleteLink(row);
row.addClass(options.formCssClass);
applyExtraClasses(row, i);
}
});
if ($$.length) {
var addButton, template;
if (options.formTemplate) {
// If a form template was specified, we'll clone it to generate new form instances:
template = (options.formTemplate instanceof $) ? options.formTemplate : $(options.formTemplate);
template.removeAttr('id').addClass(options.formCssClass).addClass('formset-custom-template');
template.find('input,select,textarea,label').each(function() {
updateElementIndex($(this), options.prefix, 2012);
});
insertDeleteLink(template);
} else {
// Otherwise, use the last form in the formset; this works much better if you've got
// extra (>= 1) forms (thnaks to justhamade for pointing this out):
template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');
template.find('input:hidden[id $= "-DELETE"]').remove();
template.find('input,select,textarea,label').each(function() {
var elem = $(this);
// If this is a checkbox or radiobutton, uncheck it.
// This fixes Issue 1, reported by Wilson.Andrew.J:
if (elem.is('input:checkbox') || elem.is('input:radio')) {
elem.attr('checked', false);
} else {
elem.val('');
}
});
}
// FIXME: Perhaps using $.data would be a better idea?
options.formTemplate = template;
if ($$.attr('tagName') == 'TR') {
// If forms are laid out as table rows, insert the
// "add" button in a new table row:
var numCols = $$.eq(0).children().length;
$$.parent().append('<tr><td colspan="' + numCols + '"><a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a></tr>');
addButton = $$.parent().find('tr:last a');
addButton.parents('tr').addClass(options.formCssClass + '-add');
} else {
// Otherwise, insert it immediately after the last form:
$$.filter(':last').after('<a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a>');
addButton = $$.filter(':last').next();
}
addButton.click(function() {
var formCount = parseInt($('#id_' + options.prefix + '-TOTAL_FORMS').val()),
row = options.formTemplate.clone(true).removeClass('formset-custom-template'),
buttonRow = $(this).parents('tr.' + options.formCssClass + '-add').get(0) || this;
applyExtraClasses(row, formCount);
row.insertBefore($(buttonRow)).show();
row.find('input,select,textarea,label').each(function() {
updateElementIndex($(this), options.prefix, formCount);
});
$('#id_' + options.prefix + '-TOTAL_FORMS').val(formCount + 1);
// If a post-add callback was supplied, call it with the added form:
if (options.added) options.added(row);
return false;
});
}
return $$;
}
/* Setup plugin defaults */
$.fn.formset.defaults = {
prefix: 'form', // The form prefix for your django formset
formTemplate: null, // The jQuery selection cloned to generate new form instances
addText: 'add another', // Text for the add link
deleteText: 'remove', // Text for the delete link
addCssClass: 'add-row', // CSS class applied to the add link
deleteCssClass: 'delete-row', // CSS class applied to the delete link
formCssClass: 'dynamic-form', // CSS class applied to each form in a formset
extraClasses: [], // Additional CSS classes, which will be applied to each form in turn
added: null, // Function called each time a new form is added
removed: null // Function called each time a form is deleted
};
})(jQuery)

Jquery script doen't load in a logical order

I got this code here in a JS file, where I've put two console.log(), one at the beginning and one at the end, to see why I'm having problems targeting the with a specific ID / class. Now I see that the console.log() at the end loads before the one in the beginning. Even when I place a console.log() outside of the file underneath the <script> tag which loads this JS file, it loads before the JS file, which doesn't make any sense to me. How can I fix this problem?
/*!
* jquery.instagramFeed
*
* #version 1.2.7
*
* #author Javier Sanahuja Liebana <bannss1#gmail.com>
* #contributor csanahuja <csanahuja10#gmail.com>
*
* https://github.com/jsanahuja/jquery.instagramFeed
*
*/
(function($){
var defaults = {
'host': "https://www.instagram.com/",
'username': 'username',
'tag': '',
'container': '#instagram',
'display_profile': true,
'display_biography': true,
'display_gallery': true,
'display_igtv': false,
'get_data': false,
'callback': null,
'styling': true,
'items': 8,
'items_per_row': 4,
'margin': 0.5,
'image_size': 640
};
var image_sizes = {
"150": 0,
"240": 1,
"320": 2,
"480": 3,
"640": 4
};
var escape_map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'/': '/',
'`': '`',
'=': '='
};
function escape_string(str){
return str.replace(/[&<>"'`=\/]/g, function (char) {
return escape_map[char];
});
}
$.instagramFeed = function(opts){
//console log at the beginning of the function
console.log("Beginning instagramFeed");
var options = $.fn.extend({}, defaults, opts);
if(options.username == "" && options.tag == ""){
console.error("Instagram Feed: Error, no username or tag found.");
return false;
}
if(typeof options.get_raw_json !== "undefined"){
console.warn("Instagram Feed: get_raw_json is deprecated. See use get_data instead");
options.get_data = options.get_raw_json;
}
if(!options.get_data && options.container == ""){
console.error("Instagram Feed: Error, no container found.");
return false;
}
if(options.get_data && options.callback == null){
console.error("Instagram Feed: Error, no callback defined to get the raw json");
return false;
}
var is_tag = options.username == "",
url = is_tag ? options.host + "explore/tags/"+ options.tag + "/" : options.host + options.username + "/";
$.get(url, function(data){
try{
data = data.split("window._sharedData = ")[1].split("<\/script>")[0];
}catch(e){
console.error("Instagram Feed: It looks like the profile you are trying to fetch is age restricted. See https://github.com/jsanahuja/InstagramFeed/issues/26");
return;
}
data = JSON.parse(data.substr(0, data.length - 1));
data = data.entry_data.ProfilePage || data.entry_data.TagPage;
if(typeof data === "undefined"){
console.error("Instagram Feed: It looks like YOUR network has been temporary banned because of too many requests. See https://github.com/jsanahuja/jquery.instagramFeed/issues/25");
return;
}
data = data[0].graphql.user || data[0].graphql.hashtag;
if(options.get_data){
options.callback(data);
return;
}
//Setting styles
var styles = {
'profile_container': "",
'profile_image': "",
'profile_name': "",
'profile_biography': "",
'gallery_image': ""
};
if(options.styling){
styles.profile_container = " style='text-align:center;'";
styles.profile_image = " style='border-radius:10em;width:15%;max-width:125px;min-width:50px;'";
styles.profile_name = " style='font-size:1.2em;'";
styles.profile_biography = " style='font-size:1em;'";
var width = (100 - options.margin * 2 * options.items_per_row)/options.items_per_row;
styles.gallery_image = " style='margin:"+options.margin+"% "+options.margin+"%;width:"+width+"%;float:left;'";
}
var html = "";
//Displaying profile
if(options.display_profile){
html += "<div class='instagram_profile'" +styles.profile_container +">";
html += "<img class='instagram_profile_image' src='"+ data.profile_pic_url +"' alt='"+ (is_tag ? data.name + " tag pic" : data.username + " profile pic") +"'"+ styles.profile_image +" />";
if(is_tag)
html += "<p class='instagram_tag'"+ styles.profile_name +"><a href='https://www.instagram.com/explore/tags/"+ options.tag +"' rel='noopener' target='_blank'>#"+ options.tag +"</a></p>";
else
html += "<p class='instagram_username'"+ styles.profile_name +">#"+ data.full_name +" (<a href='https://www.instagram.com/"+ options.username +"' rel='noopener' target='_blank'>#"+options.username+"</a>)</p>";
if(!is_tag && options.display_biography)
html += "<p class='instagram_biography'"+ styles.profile_biography +">"+ data.biography +"</p>";
html += "</div>";
}
//image size
var image_index = typeof image_sizes[options.image_size] !== "undefined" ? image_sizes[options.image_size] : image_sizes[640];
if(options.display_gallery){
if(typeof data.is_private !== "undefined" && data.is_private === true){
html += "<p class='instagram_private'><strong>This profile is private</strong></p>";
}else{
var imgs = (data.edge_owner_to_timeline_media || data.edge_hashtag_to_media).edges;
max = (imgs.length > options.items) ? options.items : imgs.length;
html += "<div class='instagram_gallery'>";
for(var i = 0; i < max; i++){
var url = "https://www.instagram.com/p/" + imgs[i].node.shortcode,
image, type_resource, caption, date, likes, comments;
switch(imgs[i].node.__typename){
case "GraphSidecar":
type_resource = "sidecar"
image = imgs[i].node.thumbnail_resources[image_index].src;
date = new Date(imgs[i].node.taken_at_timestamp * 1000);
likes = imgs[i].node.edge_media_preview_like.count;
comments = imgs[i].node.edge_media_to_comment.count;
break;
case "GraphVideo":
type_resource = "video";
image = imgs[i].node.thumbnail_src
break;
default:
type_resource = "image";
image = imgs[i].node.thumbnail_resources[image_index].src;
date = new Date(imgs[i].node.taken_at_timestamp * 1000);
likes = imgs[i].node.edge_media_preview_like.count;
comments = imgs[i].node.edge_media_to_comment.count;
}
console.log(date);
console.log(likes);
console.log(comments);
if(
typeof imgs[i].node.edge_media_to_caption.edges[0] !== "undefined" &&
typeof imgs[i].node.edge_media_to_caption.edges[0].node !== "undefined" &&
typeof imgs[i].node.edge_media_to_caption.edges[0].node.text !== "undefined" &&
imgs[i].node.edge_media_to_caption.edges[0].node.text !== null
){
caption = imgs[i].node.edge_media_to_caption.edges[0].node.text;
}else if(
typeof imgs[i].node.accessibility_caption !== "undefined" &&
imgs[i].node.accessibility_caption !== null
){
caption = imgs[i].node.accessibility_caption;
}else{
caption = (is_tag ? data.name : data.username) + " image " + i;
}
html += "<a id='instagramID" + i + "' class='instagramimg instagram-" + type_resource + "' rel='noopener' target='_blank'>";
html += "<img class='instagramicon' src='https://cdn.shopify.com/s/files/1/0278/9644/7113/files/instagram-icon.svg?v=1592246117' alt='instagramicon'>";
html += "<div class='instagramhover'></div>";
html += "<img src='" + image + "' alt='" + escape_string(caption) + "'"/* + styles.gallery_image*/ +" />";
html += "</a>";
}
}
}
if(options.display_igtv && typeof data.edge_felix_video_timeline !== "undefined"){
var igtv = data.edge_felix_video_timeline.edges,
max = (igtv.length > options.items) ? options.items : igtv.length
if(igtv.length > 0){
html += "<div class='instagram_igtv'>";
for(var i = 0; i < max; i++){
html += "<a href='https://www.instagram.com/p/"+ igtv[i].node.shortcode +"' rel='noopener' target='_blank'>";
html += "<img src='"+ igtv[i].node.thumbnail_src +"' alt='"+ options.username +" instagram image "+ i+"'"+styles.gallery_image+" />";
html += "</a>";
}
html += "</div>";
}
}
$(options.container).html(html);
}).fail(function(e){
console.error("Instagram Feed: Unable to fetch the given user/tag. Instagram responded with the status code: ", e.status);
});
return true;
};
// Ending of the code
console.log("Ending instagramFeed");
})(jQuery);
This function gets called like this in the html part. Also here, the console.log("before instagramFeed.JS"); loads together with console.log("after instagramFeed.JS");, and after that I receive the
console.log(date);
console.log(likes);
console.log(comments);
which are inside the for loop of the function.
<script src="{{ 'jquery.instagramFeed.js' | asset_url }}"></script>
<div id="instagram"></div>
<script>
console.log("before instagramFeed.JS");
(function($){
$(window).on('load', function(){
$.instagramFeed({
'username': 'username',
'container': "#instagram",
'display_profile': false,
'display_biography': false,
'display_gallery': true,
'callback': null,
'styling': true,
'items': 10,
'items_per_row': 5,
'margin': 0.2
});
});
})(jQuery);
console.log("after instagramFeed.JS");
</script>
Your code is executed in the following order:
first snippet (definition of instagramFeed plugin) is executed during page load. console.log statements outside of that plugin are executed as well.
window is loaded (all script tag contents are read and executed), your window load handler kicks in. It calls your instagramFeed function the way you set it in the second snippet. before/after instagramFeed.JS logs are executed here. instagramFeed function starts a network call the result of which is processed after the load handler finishes running.
network call response is processed. comments, likes and date are logged at this stage.
As a result, everything is working as expected if I understand the purpose correctly.
UPD: to use the elements generated by network call response handler (provided you have an opportunity to edit the plugin code directly) you can add a function into options object, say onImageElementsCreated and call it after the loop in the plugin. Then you can provide your function as another option in the second snippet.
I can't say this with 100% certainty, as I haven't run the code.
However, I think the line console.log("Ending instagramFeed"); is being run before the line console.log("Beginning instagramFeed");, because it's outside the function $.instagramFeed = function(opts).
The function is created, then the ending log line is called, then something is calling the function, then the beginning log line is called.
Where in your code do you call $.instagramFeed()?

Multiple events from .on('click', function(e) - SlickQuiz

Firstly a disclaimer: I am a complete coding novice. In fact, worse than that, I know enough to cause trouble, but not enough to fix it or do it properly (I am learning, slowly).
I am using the code from: https://github.com/jewlofthelotus/SlickQuiz
to develop an online quiz.
See an example SlickQuiz here http://users.jyu.fi/~joahtika/quiz_theses/ (not mine - that's not online yet).
I have everything working well, except one small issue.
My questions are quite long, and when you press one of the check answer/next/back/complete quiz buttons, the window does not scroll back to the top of page (or more specifically back to the question text - as top of page would be too far).
I have tried to use previously asked questions on here, but if there is one that answers this already I apologise for not finding it.
I have found a bit of the code within https://github.com/jewlofthelotus/SlickQuiz/blob/master/js/slickQuiz.js that looks like the right bit to ammend:
// Bind "next" buttons
$(_element + ' ' + _nextQuestionBtn).on('click', function(e) {
e.preventDefault();
plugin.method.nextQuestion(this, {callback: plugin.config.animationCallbacks.nextQuestion});
});
I have tried adding various things (e.g. $.scrollTo($('#myDiv'), or similar - there is a <div class="quizHeader"> in https://github.com/jewlofthelotus/SlickQuiz/blob/master/index.html that looks promising), with a variety of results. Almost all either don't do anything, or they work, but prevent the button from functioning.
If anyone is able to help it would be much appreciated. I apologise in advance, but due to my lack of experience I might need a bit of hand-holding to walk me through where various code goes.
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>JSON QUIZ</title>
<link href="https://ese-web-dev.digitalconnect.co.uk/media/1373/stylsheet.css" media="screen" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Sansita" rel="stylesheet">
<link rel="icon" type href="img/favicon.png">
</head>
<body id="slickQuiz">
<header class="container-fluid">
<div class="row">
<div class="logo">
</div>
<ul id="mainnavigation">
<img src="img/1486331709_file_documents-25.png" height="70px" width="70px">
<a href="http://mcqstack.com/">
<h2 class="headd">MCQSTACK<br>JSON</h2>
</a>
</ul>
</div>
</header>
<br><br>
<h1 class="quizName">
<!-- where the quiz name goes -->
</h1>
<div class="quizArea">
<div class="quizHeader">
<!-- where the quiz main copy goes -->
<a class="button startQuiz" href="#">Get Started!</a>
</div>
<!-- where the quiz gets built -->
</div>
<div class="quizResults">
<h3 class="quizScore">You Scored: <span><!-- where the quiz score goes --></span></h3>
<h3 class="quizLevel"><strong>Ranking:</strong> <span><!-- where the quiz ranking level goes --></span></h3>
<div class="quizResultsCopy">
<!-- where the quiz result copy goes -->
</div>
</div>
<script src="https://ese-web-dev.digitalconnect.co.uk/media/1374/jquery.js"></script>
<p id="licence">Modified within regulations of a Quicken Loans license</p>
</body>
</html>
<!-- end snippet -->
JS
var quizJSON = {
"info": {
"name": "Test Your Knowledge!!",
"main": "<p>Good Luck</p>",
"results": "<h5>You're done</h5><p></p>",
"level1": "Expert",
"level2": "Skilled",
"level3": "Learner",
"level4": "Novice",
"level5": "Amateur Stay in school, kid..." // no comma here
},
"questions": [
//no1
{ // Question 1 - Multiple Choice, Single True Answer
"q": "If I put a long question in here <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>Then you have scrolled down some way before answering. Then when you press next (if the next question is also long...",
"a": [{
"option": "True",
"correct": true
},
{
"option": "False",
"correct": false
} // no comma here
],
"select_any": true,
"correct": "<p><span>That's right!</span></p>",
"incorrect": "<p><span>Hmmm.</span> You might want to reconsider your options ,Correct answer is True.</p>" // no comma here
},
//no3
{ // Question 3 - Multiple Choice, Multiple True Answers, Select All
"q": "This question is also long so.... <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>It loads scrolled down. Which is not ideal. It would be best if it scrolled up to the question at this point (not the page top, as there will be a large nav menu there).",
"a": [{
"option": "Function",
"correct": false
},
{
"option": "Undefined",
"correct": false
},
{
"option": "Date",
"correct": false
},
{
"option": "All of the above",
"correct": true
} // no comma here
],
"correct": "<p><span>Brilliant!</span> You're seriously a genius, (wo)man.</p>",
"incorrect": "<p><span>Not Quite.</span> You might want to reconsider your options ,Correct answer is All of the above.</p>" // no comma here
} // no comma here
]
};
// Put all your page JS here
$(function() {
$('#slickQuiz').slickQuiz();
});
/*!
* SlickQuiz jQuery Plugin
* http://github.com/jewlofthelotus/SlickQuiz
*
* #updated October 25, 2014
* #version 1.5.20
*
* #author Julie Cameron - http://www.juliecameron.com
* #copyright (c) 2013 Quicken Loans - http://www.quickenloans.com
* #license MIT
*/
(function($) {
$.slickQuiz = function(element, options) {
var plugin = this,
$element = $(element),
_element = '#' + $element.attr('id'),
defaults = {
checkAnswerText: 'Check My Answer!',
nextQuestionText: 'Next »',
backButtonText: '',
completeQuizText: '',
tryAgainText: '',
questionCountText: 'Question %current of %total',
preventUnansweredText: 'You must select at least one answer.',
questionTemplateText: '%count. %text',
scoreTemplateText: '%score / %total',
nameTemplateText: '<span>Quiz: </span>%name',
skipStartButton: false,
numberOfQuestions: null,
randomSortQuestions: false,
randomSortAnswers: false,
preventUnanswered: false,
disableScore: false,
disableRanking: false,
scoreAsPercentage: false,
perQuestionResponseMessaging: true,
perQuestionResponseAnswers: false,
completionResponseMessaging: false,
displayQuestionCount: true, // Deprecate?
displayQuestionNumber: true, // Deprecate?
animationCallbacks: { // only for the methods that have jQuery animations offering callback
setupQuiz: function() {},
startQuiz: function() {},
resetQuiz: function() {},
checkAnswer: function() {},
nextQuestion: function() {},
backToQuestion: function() {},
completeQuiz: function() {}
},
events: {
onStartQuiz: function(options) {},
onCompleteQuiz: function(options) {} // reserved: options.questionCount, options.score
}
},
// Class Name Strings (Used for building quiz and for selectors)
questionCountClass = 'questionCount',
questionGroupClass = 'questions',
questionClass = 'question',
answersClass = 'answers',
responsesClass = 'responses',
completeClass = 'complete',
correctClass = 'correctResponse',
incorrectClass = 'incorrectResponse',
correctResponseClass = 'correct',
incorrectResponseClass = 'incorrect',
checkAnswerClass = 'checkAnswer',
nextQuestionClass = 'nextQuestion',
lastQuestionClass = 'lastQuestion',
backToQuestionClass = 'backToQuestion',
tryAgainClass = 'tryAgain',
// Sub-Quiz / Sub-Question Class Selectors
_questionCount = '.' + questionCountClass,
_questions = '.' + questionGroupClass,
_question = '.' + questionClass,
_answers = '.' + answersClass,
_answer = '.' + answersClass + ' li',
_responses = '.' + responsesClass,
_response = '.' + responsesClass + ' li',
_correct = '.' + correctClass,
_correctResponse = '.' + correctResponseClass,
_incorrectResponse = '.' + incorrectResponseClass,
_checkAnswerBtn = '.' + checkAnswerClass,
_nextQuestionBtn = '.' + nextQuestionClass,
_prevQuestionBtn = '.' + backToQuestionClass,
_tryAgainBtn = '.' + tryAgainClass,
// Top Level Quiz Element Class Selectors
_quizStarter = _element + ' .startQuiz',
_quizName = _element + ' .quizName',
_quizArea = _element + ' .quizArea',
_quizResults = _element + ' .quizResults',
_quizResultsCopy = _element + ' .quizResultsCopy',
_quizHeader = _element + ' .quizHeader',
_quizScore = _element + ' .quizScore',
_quizLevel = _element + ' .quizLevel',
// Top Level Quiz Element Objects
$quizStarter = $(_quizStarter),
$quizName = $(_quizName),
$quizArea = $(_quizArea),
$quizResults = $(_quizResults),
$quizResultsCopy = $(_quizResultsCopy),
$quizHeader = $(_quizHeader),
$quizScore = $(_quizScore),
$quizLevel = $(_quizLevel);
// Reassign user-submitted deprecated options
var depMsg = '';
if (options && typeof options.disableNext != 'undefined') {
if (typeof options.preventUnanswered == 'undefined') {
options.preventUnanswered = options.disableNext;
}
depMsg += 'The \'disableNext\' option has been deprecated, please use \'preventUnanswered\' in it\'s place.\n\n';
}
if (options && typeof options.disableResponseMessaging != 'undefined') {
if (typeof options.preventUnanswered == 'undefined') {
options.perQuestionResponseMessaging = options.disableResponseMessaging;
}
depMsg += 'The \'disableResponseMessaging\' option has been deprecated, please use' +
' \'perQuestionResponseMessaging\' and \'completionResponseMessaging\' in it\'s place.\n\n';
}
if (options && typeof options.randomSort != 'undefined') {
if (typeof options.randomSortQuestions == 'undefined') {
options.randomSortQuestions = options.randomSort;
}
if (typeof options.randomSortAnswers == 'undefined') {
options.randomSortAnswers = options.randomSort;
}
depMsg += 'The \'randomSort\' option has been deprecated, please use' +
' \'randomSortQuestions\' and \'randomSortAnswers\' in it\'s place.\n\n';
}
if (depMsg !== '') {
if (typeof console != 'undefined') {
console.warn(depMsg);
} else {
alert(depMsg);
}
}
// End of deprecation reassignment
plugin.config = $.extend(defaults, options);
// Set via json option or quizJSON variable (see slickQuiz-config.js)
var quizValues = (plugin.config.json ? plugin.config.json : typeof quizJSON != 'undefined' ? quizJSON : null);
// Get questions, possibly sorted randomly
var questions = plugin.config.randomSortQuestions ?
quizValues.questions.sort(function() {
return (Math.round(Math.random()) - 0.5);
}) :
quizValues.questions;
// Count the number of questions
var questionCount = questions.length;
// Select X number of questions to load if options is set
if (plugin.config.numberOfQuestions && questionCount >= plugin.config.numberOfQuestions) {
questions = questions.slice(0, plugin.config.numberOfQuestions);
questionCount = questions.length;
}
// some special private/internal methods
var internal = {
method: {
// get a key whose notches are "resolved jQ deferred" objects; one per notch on the key
// think of the key as a house key with notches on it
getKey: function(notches) { // returns [], notches >= 1
var key = [];
for (i = 0; i < notches; i++) key[i] = $.Deferred();
return key;
},
// put the key in the door, if all the notches pass then you can turn the key and "go"
turnKeyAndGo: function(key, go) { // key = [], go = function ()
// when all the notches of the key are accepted (resolved) then the key turns and the engine (callback/go) starts
$.when.apply(null, key).then(function() {
go();
});
},
// get one jQ
getKeyNotch: function(key, notch) { // notch >= 1, key = []
// key has several notches, numbered as 1, 2, 3, ... (no zero notch)
// we resolve and return the "jQ deferred" object at specified notch
return function() {
key[notch - 1].resolve(); // it is ASSUMED that you initiated the key with enough notches
};
}
}
};
plugin.method = {
// Sets up the questions and answers based on above array
setupQuiz: function(options) { // use 'options' object to pass args
var key, keyNotch, kN;
key = internal.method.getKey(3); // how many notches == how many jQ animations you will run
keyNotch = internal.method.getKeyNotch; // a function that returns a jQ animation callback function
kN = keyNotch; // you specify the notch, you get a callback function for your animation
$quizName.hide().html(plugin.config.nameTemplateText
.replace('%name', quizValues.info.name)).fadeIn(1000, kN(key, 1));
$quizHeader.hide().prepend($('<div class="quizDescription">' + quizValues.info.main + '</div>')).fadeIn(1000, kN(key, 2));
$quizResultsCopy.append(quizValues.info.results);
// add retry button to results view, if enabled
if (plugin.config.tryAgainText && plugin.config.tryAgainText !== '') {
$quizResultsCopy.append('<p><a class="button ' + tryAgainClass + '" href="#">' + plugin.config.tryAgainText + '</a></p>');
}
// Setup questions
var quiz = $('<ol class="' + questionGroupClass + '"></ol>'),
count = 1;
// Loop through questions object
for (i in questions) {
if (questions.hasOwnProperty(i)) {
var question = questions[i];
var questionHTML = $('<li class="' + questionClass + '" id="question' + (count - 1) + '"></li>');
if (plugin.config.displayQuestionCount) {
questionHTML.append('<div class="' + questionCountClass + '">' +
plugin.config.questionCountText
.replace('%current', '<span class="current">' + count + '</span>')
.replace('%total', '<span class="total">' +
questionCount + '</span>') + '</div>');
}
var formatQuestion = '';
if (plugin.config.displayQuestionNumber) {
formatQuestion = plugin.config.questionTemplateText
.replace('%count', count).replace('%text', question.q);
} else {
formatQuestion = question.q;
}
questionHTML.append('<h3>' + formatQuestion + '</h3>');
// Count the number of true values
var truths = 0;
for (i in question.a) {
if (question.a.hasOwnProperty(i)) {
answer = question.a[i];
if (answer.correct) {
truths++;
}
}
}
// Now let's append the answers with checkboxes or radios depending on truth count
var answerHTML = $('<ul class="' + answersClass + '"></ul>');
// Get the answers
var answers = plugin.config.randomSortAnswers ?
question.a.sort(function() {
return (Math.round(Math.random()) - 0.5);
}) :
question.a;
// prepare a name for the answer inputs based on the question
var selectAny = question.select_any ? question.select_any : false,
forceCheckbox = question.force_checkbox ? question.force_checkbox : false,
checkbox = (truths > 1 && !selectAny) || forceCheckbox,
inputName = $element.attr('id') + '_question' + (count - 1),
inputType = checkbox ? 'checkbox' : 'radio';
if (count == quizValues.questions.length) {
nextQuestionClass = nextQuestionClass + ' ' + lastQuestionClass;
}
for (i in answers) {
if (answers.hasOwnProperty(i)) {
answer = answers[i],
optionId = inputName + '_' + i.toString();
// If question has >1 true answers and is not a select any, use checkboxes; otherwise, radios
var input = '<input id="' + optionId + '" name="' + inputName +
'" type="' + inputType + '" /> ';
var optionLabel = '<label for="' + optionId + '">' + answer.option + '</label>';
var answerContent = $('<li></li>')
.append(input)
.append(optionLabel);
answerHTML.append(answerContent);
}
}
// Append answers to question
questionHTML.append(answerHTML);
// If response messaging is NOT disabled, add it
if (plugin.config.perQuestionResponseMessaging || plugin.config.completionResponseMessaging) {
// Now let's append the correct / incorrect response messages
var responseHTML = $('<ul class="' + responsesClass + '"></ul>');
responseHTML.append('<li class="' + correctResponseClass + '">' + question.correct + '</li>');
responseHTML.append('<li class="' + incorrectResponseClass + '">' + question.incorrect + '</li>');
// Append responses to question
questionHTML.append(responseHTML);
}
// Appends check answer / back / next question buttons
if (plugin.config.backButtonText && plugin.config.backButtonText !== '') {
questionHTML.append('' + plugin.config.backButtonText + '');
}
var nextText = plugin.config.nextQuestionText;
if (plugin.config.completeQuizText && count == questionCount) {
nextText = plugin.config.completeQuizText;
}
// If we're not showing responses per question, show next question button and make it check the answer too
if (!plugin.config.perQuestionResponseMessaging) {
questionHTML.append('' + nextText + '');
} else {
questionHTML.append('' + nextText + '');
questionHTML.append('' + plugin.config.checkAnswerText + '');
}
// Append question & answers to quiz
quiz.append(questionHTML);
count++;
}
}

Javascript If variable value type

I have the following function which populates elements options.
player.onTracksChanged_ = function(event) {
// Update the track lists.
var lists = {
video: document.getElementById('videoTracks'),
audio: document.getElementById('audiotrackButton'),
text: document.getElementById('captionButton')
};
var formatters = {
video: function(track) {
return track.width + 'x' + track.height + ', ' +
track.bandwidth + ' bits/s';
},
audio: function(track) {
return 'language: ' + track.language + ', ' +
track.bandwidth + ' bits/s';
},
text: function(track) {
return 'language: ' + track.language + ' ' +
'(' + track.kind + ')';
}
};
// Clear the old track lists.
Object.keys(lists).forEach(function(type) {
var list = lists[type];
while (list.firstChild) {
list.removeChild(list.firstChild);
}
});
// Populate with the new tracks.
var tracks = player.getTracks();
tracks.sort(function(t1, t2) {
// Sort by language, then by bandwidth.
if (t1.language) {
var ret = t1.language.localeCompare(t2.language);
if (ret) return ret;
}
return t1.bandwidth - t2.bandwidth;
});
tracks.forEach(function(track) {
var list = lists[track.type];
var option = document.createElement('option');
option.textContent = formatters[track.type](track);
option.track = track;
option.value = track.id;
option.selected = track.active;
list.appendChild(option);
});
};
What I am trying to achieve is an if statement based on this which determines if the number of each 'type' of 'track' is greater than or equal to 2, this is what I've got:-
var mediaTracks = player.getTracks();
if (mediaTracks.length >= 2) {
console.log('there are more than 2 tracks');
} else {
console.log('there are less than 2 tracks');
};
When in fact I need to do something more like this:-
var mediaTracksVideo = player.getTracks(video)
var mediaTracksAudio = player.getTracks(audio)
Then do something like:-
if (mediaTracksAudio >= 2) {...
But when I try player.getTracks(audio); the console logs 'audio is not defined'.
Any idea why?
With player.getTracks(audio) you're using the variable audio, which is undefined. You probably want to use player.getTracks('audio'), where 'audio' is a string.

conditional statements in jquery shortcode generation

I want to convert this shortcode generating form into one that will generate either of two different shortcodes depending on a value selected in the form. So, a radio button says, "Which shortcode do you want to build?" Then they choose it, then they go on with the other fields to fill out the attribute values. Then when it comes time to generate the code, the JS will condition its output based on the radio button question. I've tried to modify it myself, but the problem is, this script generates the attributes from the options index, so I don't know how to include an option that doesn't go into the index:
var table = form.find('table');
form.appendTo('body').hide();
form.find('#myshortcodeidstem-submit').click(function(){
var options = {
'shortcodename' : '', \\ THIS IS THE ONE TO DETERMINE THE SHORTCODE NAME
'attribute' : '', \\ THIS IS THE ATTRIBUTE THAT BOTH SHORTCODES SHARE
};
var shortcode = '[myshortcode'; \\ THIS LINE NEEDS TO BE CONDITIONAL ON OPTION 1
for( var index in options) {
var value = table.find('#myshortcodeidstem-' + index).val();
if ( value !== options[index] && value != null )
shortcode += ' ' + index + '="' + value + '"';
}
shortcode += '] Content Here [/myshortcode]'; \\ THIS LINE CONDITIONAL ON OP1
--- UPDATE ---
Barmar pointed me in the right direction, and I got it to work, but I'd like to know if there's a more economical way to do it. Here's what I have:
var table = form.find('table');
form.appendTo('body').hide();
form.find('#myshortcodeid-submit').click(function(){
var codeselector = table.find('#myshortcodeid-codeselector').val();
if (codeselector === '1'){
var options = {
'attribute' : '',
};
var shortcode = '[shortcode_one';
for( var index in options) {
var value = table.find('#myshortcodeid-' + index).val();
if ( value !== options[index] && value != null )
shortcode += ' ' + index + '="' + value + '"';
}
shortcode += '] Content Here [/shortcode_one]';
}
if (codeselector === '2'){
var options = {
'attribute' : '',
};
var shortcode = '[shortcode_two';
for( var index in options) {
var value = table.find('#myshortcodeid-' + index).val();
if ( value !== options[index] && value != null )
shortcode += ' ' + index + '="' + value + '"';
}
shortcode += '] Content Here [/shortcode_two]';
}
--- UPDATE ---
Found a more economical way, without repeating the options index. See the answer below.
Here's the most economic way I could come up with. Doesn't repeat the options index this way. Working good. Just had to create a var for the dropdown field that chooses the shortcode, then do if statements referencing that var's value.
var codeselector = table.find('#myid-codeselector').val();
if (codeselector === '1'){
var shortcode = '[shortcode_one';
}
if (codeselector === '2'){
var shortcode = '[shortcode_two';
}
var options = {
'attribute' : '',
};
for( var index in options) {
var value = table.find('#myid-' + index).val();
if ( value !== options[index] && value != null )
shortcode += ' ' + index + '="' + value + '"';
}
if (codeselector === '1'){
shortcode += '] Content Here [/shortcode_one]';
}
if (codeselector === '2'){
shortcode += '] Content Here [/shortcode_two]';
}

Categories

Resources