Difference between revisions of "MediaWiki:Common.js"

From SQLZOO
Jump to: navigation, search
Line 640: Line 640:
 
     if (readCookie('randid') % 2 == 1){
 
     if (readCookie('randid') % 2 == 1){
 
       $('#gamelink a').text('Click here to play duplicates game');
 
       $('#gamelink a').text('Click here to play duplicates game');
 +
      $('#gamelink a').attr('href','http://sqlzoo.net/brain/bt.htm');
 
     }
 
     }
 
   }
 
   }
 
})
 
})

Revision as of 14:38, 17 July 2017

/* gobutton.js */
$(function () {
  var engine =
   $('<li/>',{id:'pick-engine'})
    .append($('<span/>',{id:'engineTxt',css:{}})
     .append($('<span>SQL Engine: </span>'))
          .append($('<select id=engine/>')
            .append('<option value=mysql>MySQL</option>')
            .append('<option value=oracle>Oracle</option>')
            .append('<option value=mssql>SQL Server</option>')
//            .append('<option value=postgres>PostgreSQL</option>')
//            .append('<option value=ingres>Ingres</option>')
//            .append('<option value=db2>DB2</option>')
          )
    );
  $('#right-navigation').append(engine);
  if(readCookie('pref-engine'))
    $('#engine').val(readCookie('pref-engine'));
  $('#engine').on('change',function(){
    createCookie('pref-engine',$(this).val(),30);
  });
  var startAt = Math.max(1, $('#startAt').text() * 1);
  var numberOfQuestions = 0;
  var qu = $('.qu,.ht,.err');
  var curEng = $('#engine').val();
  for (var i = 0; i < qu.length; i++) {
    var id = i + 1;
    var q = qu[i];
    var lsName = mw.config.get('wgPageName') + '_' + 'frm__' + id;
    var def = $('.def', q);
    if (def.length > 1) {
      var pick = def.filter(function () {
        var clss = $(this).attr('class').split(' ');
        for (var k = 0; k < clss.length; k++)
          if (clss[k].match("^e-")) return false;
        return true
      });
      for (var j = 0; j < def.length; j++)
        if ($(def[j]).hasClass('e-' + curEng))
          pick = $(def[j]);
      def = pick;
    }
    var txt = def.text();
    // replace the default text with user's last query if available in LS
    if (localStorage.getItem(lsName + "_arr_" + curEng)) {
      var lsArray = JSON.parse(localStorage.getItem(lsName + "_arr_" + curEng));
      txt = lsArray[lsArray.length - 1];
    }

    var ans = $('.ans', q).text();
    var nrows = 2 + Math.max(Math.max(4, txt.split(/[\n\r]+/).length), ans.split(/[\n\r]+/).length);
    var ncols = 2 + Math.max(Math.max(45, maxlen(txt.split(/[\n\r]+/))), maxlen(ans.split(/[\n\r]+/)));
    var tdy = $('.tidy', q).text();
    var frm = $('<form/>', {
      name: 'frm__' + id,
      id: 'frm__' + id
    })
      .append($('<div/>', {
          'class': 'quf'
        })
        .append($('<textarea></textarea>', {
          spellcheck:false,
          rows: nrows,
          cols: ncols,
          'class': 'sql',
          id: 'txtar_' + id,
          focusin:function(){
            if($(this).data('firstfocus')===undefined){
              $(this).data('firstfocus',(new Date()).getTime());
            }
          }
        }).val($.trim(txt)))
        .append($('<button/>', {
          text: 'Submit SQL',
          'class': 'submitSQL',
          click: goBaby
        }))
        .append($('<div/>', {
          text: 'Restore default',
          'class': 'reset',
          click: function () {
            var qu = $(this).parents('.qu, .ht, .err');
            var def = $('.def', qu);
            var txt = findBestDefText(qu, $('#engine').val());
            qu.find('textarea.sql').val(txt);
          }
        }))
    );

    def.after(frm);
    var lhs = $('<div/>', {
      css: {
        //width: (ncols+10)+'ex'
      }
    });
    lhs.append($('<span/>', {
      text: (startAt + i) + '.',
      'class': 'id'
    }));
    lhs.append($(q).children());
    $(q).append(lhs);
    $(q).append($('<div/>', {
      text: 'result',
      'class': 'res'
    }));

    //Show additional info if available for active angine
    var ecomm = $('.ecomm,.link', q);
    var ecomm1 = ecomm.filter(false);
    if (ecomm.length > 0) {
      var curEng = $('#engine').val();
      for (var j = 0; j < ecomm.length; j++)
        if ($(ecomm[j]).hasClass('e-' + curEng))
          ecomm1 = $(ecomm[j]);
    }
    for (var j = 0; j < ecomm.length; j++) {
      if ($(ecomm[j]).get(0) == ecomm1.get(0)) {
        $(ecomm[j]).show();
      } else {
        $(ecomm[j]).hide();
      }
    }

    var ecomm = $('.link', q);
    var ecomm1 = def.filter(function () {
      var clss = ($(this).attr('class')||'').split(' ');
      for (var k = 0; k < clss.length; k++)
        if (clss[k].match("^e-")) return false;
      return true
    });
    if (ecomm.length > 0) {
      var curEng = $('#engine').val();
      for (var j = 0; j < ecomm.length; j++)
        if ($(ecomm[j]).hasClass('e-' + curEng))
          ecomm1 = $(ecomm[j]);
    }
    for (var j = 0; j < ecomm.length; j++) {
      if ($(ecomm[j]).get(0) == ecomm1.get(0)) {
        $(ecomm[j]).show();
      } else {
        $(ecomm[j]).hide();
      }
    }
    numberOfQuestions = id;
    //You've been zooified - show yourself as such
    $(q).addClass('zood');
  }

  if (numberOfQuestions == 0)
    numberOfQuestions = 1;
  //Put in the answers if url includes answer=1
  if (window.location.search && /answer/.test(window.location.search)) {
    $('<def/>', {
      text: "Cheat mode",
      css: {
        position: 'fixed',
        right: '2ex',
        bottom: '2ex',
        width: '14ex',
        backgroundColor: 'yellow',
        padding: '2ex',
        textAlign: 'center'
      }
    })
      .appendTo($('body'));
    $('.quf textarea').each(function () {
      $(this).val($(this).closest('form').next('.ans').text());
    })
  }

  //Fill in default answers
  if ((mw.config.get('wgUserName') || readCookie('randid')) && mw.config.get('wgPageName')) {
    $.ajax({
      url:'/userDetails.php',
      data: {
        action: 'getMostRecent',
        wgUserName: mw.config.get('wgUserName'),
        wgPageName: mw.config.get('wgPageName')
      },
      dataType:'json',
      cache:false,
      success: function (d) {
        for (var i = 0; i < d.ret.length; i++) {
          var q = d.ret[i].question;
          q = q.replace(/\./g, '');
          var ta = $('#frm__' + q + ' div.quf textarea');
          ta.val(d.ret[i].txt);
          if (d.ret[i].score == 100)
            showCorrect($('#frm__' + q).parents('.qu,.ht,.err'));
        }
        // Fill in the quiz answers
        var qlst = $('.quiz .q');
        for(var i=0;i<d.quiz.length && i<qlst.length;i++){
          if(d.quiz[i].txt>0){
            $($('.d',qlst[i])[d.quiz[i].txt]).addClass('picked');
          }
        }
        // Now score it
        $('.quiz button').trigger('click');
    }});
  }
})
//Find the text that best matches the specified engine
//The div.qu (or div.ht) node contains a number of div.def
//These may be specific to an engine in which case they have one or more e-sqlserver e-mysql classes
function findBestDefText(quNode, engine) {
  var def = $('.def', quNode);
  if (def.length == 0) return "";
  if (def.length == 1) return def.text();
  var perfect = $('.def.e-' + engine)
  if (perfect.length == 1) return perfect.text();
  for (var k = 0; k < def.length; k++) {
    if (!$(def[k]).attr('class').match('e-'))
      return $(def[k]).text();
  }
  //No match found, no default found - just give the first one
  return $(def[0]).text();
}

function goBaby() {
  var qu = $(this).parents('.qu, .ht, .err');
  var lsUse = ((qu[0].getAttribute('class') != 'ht') && ($(qu[0]).find('.ans').length > 0));
  var lsName = mw.config.get('wgPageName') + '_' + $(this).parents('form').attr('id');
  var sql = qu.find('textarea.sql').val();
  var thinkingTime = (new Date()).getTime()-qu.find('textarea.sql').data('firstfocus');
  var parlst = $('.params').text().split(';');
  var params = {};
  for (var i = 0; i < parlst.length; i++) {
    var pair = parlst[i].split(':');
    if (pair.length==2)
       params[pair[0].trim()] = pair[1].trim();
  }
  qu.find('.res').addClass('waiting');
  $.ajax({
    url: '/sqlgo.pl',
    cache: false,
    'type': 'post',
    dataType: 'json',
    data: {
      sql: sql.replace(/\xA0/g, ' '), //Mediawiki inserts &nbsp; before a %. We need to change it back to a space.CM 13/6/12
      format: 'json',
      question: $('.id', qu).text(),
      wgUserName: mw.config.get('wgUserName'),
      page: mw.config.get('wgPageName'),
      server: $('#engine').val(),
      setup: $('.setup', qu).text().replace(/\xA0/g, ' '),
      tidy: $('.tidy', qu).text().replace(/\xA0/g, ' '),
      answer: $('.ans', qu).text().replace(/\xA0/g, ' '),
      schema: params['schema'],
      respectorder:$('.respectorder',qu).length,
      iplo:$('body').data('iplo'),
      thinkingTime:thinkingTime || 0
    },
    success: function (d) {
      var res = qu.find('.res');
      res.empty().removeClass('waiting')
      if (d.error) {
        res.append($('<h1/>', {
          text: 'SQLZoo System Error:'
        }))
        res.append($('<div/>', {
          text: d.error
        }))
        return;
      }
      var headerPresent = false;
      for (var i = 0; i < d.sql.length; i++) {
        if (!d || !d.sql || !d.sql[i]) {
          res.append($('<h1/>', {
            text: 'SQLZoo System Error:'
          }))
          res.append($('<div/>', {
            text: "Problem with d or d.sql or d.sql[0]"
          }))
          return;
        }
        if (d.sql[i].error) {
          res.append($('<h1/>', {
            text: 'Error:'
          }))
          res.append($('<div/>', {
            text: d.sql[i].error
          }))
          return;
        }
        var legend = "Result:";
        if (d.score && d.answer && d.answer.length == 1 && d.answer[0].fields) {
          if (d.score == 100)
            legend = showCorrect(qu);
          else if (d.answer[0].fields.length > d.sql[0].fields.length)
            legend = hideCorrect(qu,'Wrong answer. Too few columns');
          else if (d.answer[0].fields.length < d.sql[0].fields.length)
            legend = hideCorrect(qu,'Wrong answer. Too many columns');
          else if (d.answer[0].rows.length > d.sql[0].rows.length)
            legend = hideCorrect(qu,'Wrong answer. Too few rows');
          else if (d.answer[0].rows.length < d.sql[0].rows.length)
            legend = hideCorrect(qu,'Wrong answer. Too many rows');
          else
            legend = hideCorrect(qu,'Wrong answer. Some of the data is incorrect.');
        }
        if (!headerPresent) {
          res.append($('<h1/>', {
            text: legend
          }));
          headerPresent = true;
        }
        var t = mkTable(d.sql[i]);
        t.addClass('sqlmine')
          .appendTo(res);
        if (d.answer && d.answer.length > 0  && d.answer[0].rows && (d.score || 0) < 100) {
          res.append($('<div/>', {
              text: 'Show what the answer should be...',
              'class': 'showtxt'
            })
            .click(function () {
              $(this).next().show('slow');
            })
          );
          var a = mkTable(d.answer[0]);
          a.addClass('sqlans');
          a.appendTo(res);
        }
      } //End of success of goBaby
    },
    error: function (jqXHR, textStatus, errorThrown) {
      qu.find('.res').empty().removeClass('waiting')
        .append($('<h1/>', {
          'class': 'syserr',
          text: 'SQLZOO system error:'
        }))
        .append($('<div/>', {
          text: textStatus
        }))
        .append($('<div/>', {
          text: errorThrown
        }))
        .append($('<div/>').html(jqXHR.responseText))
    }
  });
  return false;
} //GoBaby
function showCorrect(qu) {
  var legend = 'Correct answer';
  if ($(".qcorrect", qu).length == 0) {
    var qcorr = $('<div/>', {
      'class': 'qcorrect',
      'title': 'You have answered this question correctly.'
    });
    qcorr.hide();
    $('.id',qu).before(qcorr);
    qcorr.show('slow');
  }
  return legend;
}
function hideCorrect(qu,message){
  if($(".qcorrect",qu).length > 0){
    $('.qcorrect',qu).hide('slow',function(){
      $(this).remove();
    });
  }
  return message;
}
function maxlen(l) {
  var r = 0;
  for (var i = 0; i < l.length; i++)
    r = Math.max(r, l[i].length);
  return r;
}

function truncate(s) {
  if (s.length < 15) return s;
  return s.substring(0, 13) + "..";
}

function mkTable(a) {
  var t = $('<table/>');
  t.append($('<tr/>'));
  var isnum = [];
  if (!a.fields || !a.rows) return t;
  for (var i = 0; i < a.fields.length; i++) {
    $('tr', t).append($('<th/>', {
      text: truncate(a.fields[i])
    }));
    var allNum = 1;
    for (var j = 0; j < a.rows.length; j++) {
      if (a.rows[j] && a.rows[j][i] && (typeof a.rows[j][i] == "string") && !a.rows[j][i].match(/^[0-9.]*$/) && a.rows[j][i]!='null')
        allNum = 0;
    }
    isnum.push(allNum);
  }
  for (var j = 0; j < a.rows.length; j++) {
    var tr = $('<tr/>').appendTo(t);
    for (var k = 0; k < a.rows[j].length; k++) {
      var td = $('<td/>', {
        text: a.rows[j][k]
      });
      if (isnum[k]) td.addClass('r');
      td.appendTo(tr);
    }
  }
  if (a.truncated){
    var tr = $('<tr/>').appendTo(t);
    tr.append($('<td/>',{text:'Results truncated. Only the first '+a.rows.length+' rows have been shown.',
                         colspan:a.fields.length}));
  }
  return t;
}
function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}

function createCookie(name, value, days) {
    var expires;

    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        expires = "; expires=" + date.toGMTString();
    } else {
        expires = "";
    }
    document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/";
}

/* quiz.js */
$(function () {
  $('.quiz .q').each(function(i){
    $(this).prepend((i+1)+'. ');
//    $('table.d',this).each(function(i){
//      $(this).prepend($('<caption/>',{text:'Table-'+'ABDCE'[i]}));
//    });
    $('.d',this).click(function(){
      $(this).parents('.q').find('.picked').removeClass('picked');
      $(this).addClass('picked');
    });
  });
  $('.quiz').append($('<button/>',{
    text:'Score the test',
    click:function(){
      var selection = [];
      var scores = [];
      $('.quiz .q').each(function(){
        $('.d.picked',this).addClass('mark-wrong');
        $('.d.y.picked',this).removeClass('mark-wrong');
        $('.d.y.picked',this).addClass('mark-correct');
        selection.push($('.d',this).index($('.d.picked',this)));
        scores.push($('.d.y.picked',this).length);
      });
      var quiz = $(this).parents('.quiz');
      $('.feedback',quiz).remove();
      var score = $('.mark-correct',quiz).length;
      var outof = $('.q',quiz).length;
      var feedback = $('<div/>',{'class':'feedback',
        text:'Your score is: '+score+
             ' out of '+outof});
      feedback.hide();
      $(this).after(feedback);
      feedback.slideDown();
      $.getJSON('/userDetails.php',{
        action:'recordQuiz',
        wgPageName:mw.config.get('wgPageName'),
        wgUserName:mw.config.get('wgUserName'),
        selection:selection.join(','),
        scores:scores.join(','),
        score:score,
        outof:outof
      });
    }
  }));
});






/* progress.js */
$(function(){
  //Find the left tutorial elements
  //We want to show progress for these
  var lst = $('#mw-panel .portal:first li');
  lst.each(function(){
    $(this).append($('<div/>',{'class':'progressbarbg1'})
      .append($('<div/>',{'class':'progressbar1',css:{'width':'0px'}})));
  });
  $.getJSON('/userDetails.php',{action:'getProgress',path:'main',wgUserName:mw.config.get('wgUserName')},
    function(d){
      var maxWidth = 4.5-.2-.2; // From css - width of ..progressbarbg1 - borders of progressbarbg1 - 2*left progressbar1
      var h = {};
      for(var i=0;i<d.progress.length;i++)
        h[d.progress[i][0]] = {page:d.progress[i][0],done:d.progress[i][1],outof:d.progress[i][2]};
      // Over write the quiz pages
      for(var i=0;i<d.quiz.length;i++)
        h[d.quiz[i][0]] = {page:d.quiz[i][0],done:d.quiz[i][1],outof:d.quiz[i][2]};
      $('.progressbar1').each(function(){
        var tgt = $(this).parent().prev().attr('href');
        if (tgt){
          var pages = tgt.split('/');
          if (pages.length>0){
            var prgr = h[pages[pages.length-1]];
            if(prgr){
              $(this).css({width:(prgr.done*maxWidth/prgr.outof)+'ex'});
              $(this).parent().attr('title','Completed '+prgr.done+' of '+prgr.outof);
            }else{
              console.log('pathQust and wiki out of sync - please tell a.cumming@napier.ac.uk: '+tgt);
            }
          }
        }
      });
    });
});










/* other.js */
$(function(){
  //Allow all the tables to be collapsible
  //items move into the "More" actions
  //Change the following to change the word "More"
  //http://sqlzoo.net/dev/MediaWiki:Vector-more-actions
  $('#ca-view,#ca-viewsource,#ca-edit').addClass('collapsible');

  $('#mw-head').append(
    $('<div/>',{id:'cog-cont'}).append(
      $('<div/>',{
        css:{'background-image':'url(/design/Cog_font_awesome.svg)',
             'z-index':1003,
             width:32,height:32,position:'absolute',right:0,top:0},
        title:'Wiki Controls',
        id:'cog',
        click:function(){
          $('#coglist').slideToggle();
          if ($('#overlay').length==0){
            $('<div/>',{id:'overlay',
              click:function(){
                $('#coglist').slideUp();
                $('#overlay').remove();
              },
              css:{
                position:'absolute',
                top:0,left:0,background:'#aaaaaa',
                width:'100%',height:'100%',
                opacity:0.3,
                'z-index':1002
            }})
              .appendTo('body');
          }else{
            $('#overlay').remove();
          }
        }
      }))
  );
  $('.hint').each(function(){
    $(this).before($('<div/>',{'class':'tease',
        text:$(this).attr('title') || 'hint',
        click:function(){
          $(this).next().slideToggle();
        }}));
    $(this).hide();
  });
  $('#cog-cont').append(
    $('<ul/>',{id:'coglist',css:{display:'none','z-index':1003}})
      .append($('<li/>').append($('#p-search')))
      .append($('#pick-engine'))
      .append($('#pt-createaccount'))
      .append($('#pt-userpage'))
      .append($('#pt-mytalk'))
      .append($('#pt-preferences'))
      .append($('#pt-watchlist'))
      .append($('#pt-mycontris'))
      .append($('#pt-login'))
      .append($('#pt-logout'))
      .append($('#ca-view'))
      .append($('#ca-viewsource'))
      .append($('#ca-edit'))
      .append($('#ca-history'))
      .append($('#ca-nstab-main'))
      .append($('#ca-talk'))
      .append($('#ca-watch'))
      .append($('#ca-unwatch'))
      .append($('#ca-move'))
      .append($('#ca-delete'))
      .append($('#ca-protect'))
  );
  $('#pt-login,#pt-logout').before($('#pick-engine'));
/*
  //Animated gif to School of Computing postgrad
  $('#mw-head').prepend($('<a/>',{
     id:'napier-ad',
     href:'http://www.napier.ac.uk/about-us/our-schools/school-of-computing/courses/postgraduate?sz',
     title:'SQLZoo: developed and maintained at Edinburgh Napier University'
  }));
*/
  if (window.location.hostname=='zh.sqlzoo.net' ||
       window.location.hostname=='ac.sqlzoo.net' || 
       mw.config.get('wgCanonicalNamespace') == 'MediaWiki' ||
       mw.config.get('wgCanonicalNamespace') == 'Special'){
  }else{
    var ins = $('<ins/>',{'class':'adsbygoogle',
       style:"display:block;",
       'data-ad-client':"ca-pub-0803888854272698",
       'data-ad-slot':"2184001182",'data-ad-format':'auto'});
    ins.prependTo('#footer');
    $.getScript("//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js",
      function(){
        (adsbygoogle = window.adsbygoogle || []).push({});
    });
  }
});

/*
 Tweek the Log in scheme
 * */
$(function(){
  $('#mw-user-domain-section').hide();
  $('#wpRemember').attr('checked',true);
});
$(function(){
  if (mw.config.get('wgUserGroups').indexOf('teacher')!==-1 &&
      document.location.hostname.startsWith('ac'))
    $.ajax({url:'https://tracker.napier.ac.uk/teacher.js',cache:true,dataType:'script'});
})

$(function(){
  if ($('#gamelink').length>0){
    if (readCookie('randid') % 2 == 1){
      $('#gamelink a').text('Click here to play duplicates game');
      $('#gamelink a').attr('href','http://sqlzoo.net/brain/bt.htm');
    }
  }
})