Memrise Review Selection

Review the words you select (for a given level)

// ==UserScript==
// @name           Memrise Review Selection
// @description    Review the words you select (for a given level)
// @match          http://*.memrise.com/course/*
// @match          https://*.memrise.com/course/*
// @run-at         document-end
// @version        1.0
// @grant          none
// @namespace      https://gf.qytechs.cn/users/213706
// ==/UserScript==		

/* jshint esversion:6 */

function main() {
  var ReviewSelection = {};

  //+------------------------------------------------------
  //|
  //| Handles the Level's details page
  //|  https://decks.memrise.com/course/ID_COURSE/SLUG/ID_LEVEL/
  //|
  //+------------------------------------------------------

  ReviewSelection.list = {
    HIDDEN: true,
    reviewBtn: null,

    /**
     * Init elements
     */
    init() {

      // Add CSS
      var styles = `
          .review-show, .review-10 {
            cursor: pointer;
						margin-right: 5px;
          }
          .reviewSelection {
            background-image: none;
            text-shadow: none;
          }
          .reviewSelection.hide {
            display: none;
          }`;

      var styleSheet = document.createElement("style");
      styleSheet.type = "text/css";
      styleSheet.innerText = styles;
      document.head.appendChild(styleSheet);

      // Add the button "review" (to toggle checkboxes)
      var toggleBtn = document.createElement('a');
      toggleBtn.setAttribute('title', "Select the words to review");
      toggleBtn.setAttribute('class', "review-show mini pull-left");
      toggleBtn.innerText = 'Review';

      document.querySelector('.things-header').appendChild(toggleBtn)
              .addEventListener('click', ReviewSelection.list.toggleCheckbox);

      // Add the button "+10 last" (to check the 10 mast checkboxes)
      var checkLastBtn = document.createElement('a');
      checkLastBtn.setAttribute('title', "Select the 10 last words");
      checkLastBtn.setAttribute('class', "review-10 mini pull-left hide");
      checkLastBtn.innerText = '+10 last';

      ReviewSelection.list.checkLastBtn = document.querySelector('.things-header').appendChild(checkLastBtn);
			ReviewSelection.list.checkLastBtn.addEventListener('click', ReviewSelection.list.check10last);

      // Add the button "review the selected words" to the end of the list
      var reviewBtn = document.createElement('button');
      reviewBtn.setAttribute('type', 'button');
      reviewBtn.setAttribute('class', 'btn-primary btn-large btn-block reviewSelection hide');
      reviewBtn.innerText = 'Review the selected words';

      ReviewSelection.list.reviewBtn = document.querySelector('.things-footer').appendChild(reviewBtn);
			ReviewSelection.list.reviewBtn.addEventListener('click', ReviewSelection.list.launchReviewSession);

      // Hide "review the selected words" when clicking on "Ignore"
      document.querySelector('.ignore-show').addEventListener('click', function(){
        ReviewSelection.list.reviewBtn.classList.add('hide');
        ReviewSelection.list.HIDDEN = true;
        ReviewSelection.list.checkLastBtn.classList.add('hide');
      });
    },

    /**
     * Toggle display/hide checkboxes
     */
    toggleCheckbox() {
      ReviewSelection.list.HIDDEN = !ReviewSelection.list.HIDDEN;
      ReviewSelection.list.selectWords(ReviewSelection.list.HIDDEN);
      
      if(ReviewSelection.list.HIDDEN) {
      	ReviewSelection.list.checkLastBtn.classList.add('hide');
      } else {
        ReviewSelection.list.checkLastBtn.classList.remove('hide');
      }
    },
    
    /**
     * Check the last 10 words to review
     */
    check10last() {
      var things = document.querySelectorAll('.thing'),
          c      = 0;
          n      = 0;

      for(let i=things.length-1; i>=0; i--) {
        let thing     = things[i],
            thinguser = thing.querySelector('.thinguser');

        if(thinguser.firstElementChild.classList.contains('ico-seed')) {
        	continue;
        }
        if(!thing.querySelector('input').checked) {
          thing.querySelector('input').checked = true;
          c++;
        }
        if(++n == 10) {
          if(c == 0) {
          	n = 0;
          } else {
          	break;
          }
        }
      }
    },

    /**
     * Show or hide the checkboxes
     */
    selectWords(hide) {
      if(typeof hide != 'boolean') {
        hide = false;
      }

      var things       = document.querySelectorAll('.thing'),
          showDelay    = hide ? 'block' : 'none',
          showCheckbox = hide ? 'none' : 'block';

      for(let i=0; i<things.length; i++) {
        let thing     = things[i],
            thinguser = thing.querySelector('.thinguser');

        if(thinguser.firstElementChild.classList.contains('ico-seed')) {
        	continue;
        }
        thinguser.style.display = showDelay;
        thing.querySelector('.ignore-ui').style.display = showCheckbox;
      }

      if(hide) {
        ReviewSelection.list.reviewBtn.classList.add('hide');
      } else {
        ReviewSelection.list.reviewBtn.classList.remove('hide');
      }
    },

    /**
     * Retrieve the list of checked boxes
     * Save the selection in the localStorage
     * Then start a review session
     */
    launchReviewSession() {

      // Get the selection
      var divs      = document.querySelectorAll('.ignore-ui'),
          selection = {},
          c         = 0,
          n         = 0;

      for(let i=0; i<divs.length; i++) {
        let div = divs[i];
        if(!div.classList.contains('pull-right') || div.style.display !== 'block' || !div.firstElementChild) {
          continue;
        }
        if(div.firstElementChild.checked) {
          let id = div.parentNode.getAttribute('data-learnable-id');
          selection[id] = 1;
          c++;
        }
        n++;
      }
      divs = null;
      if(c == 0) {
        alert('Please select the words to review');
        return;
      }

      // Save the selection to localStorage      
      var url  = window.location.pathname,
          data = {time: Date.now(), list: selection, ntotal: n};

      [,idCourse,idxLevel] = url.match(/\/course\/(\d+)\/[^/]+\/(\d+)/);

      localStorage.setItem('reviewSession_' + idCourse + '_' + idxLevel, JSON.stringify(data));

      // Redirect to review
      url += 'garden/classic_review/?selection';
      window.location.href = url;
    }
  };

  
  //+------------------------------------------------------
  //|
  //| Handles the Review page
  //|  https://decks.memrise.com/course/ID_COURSE/SLUG/ID_LEVEL/garden/classic_review/*?selection
  //|
  //+------------------------------------------------------

  ReviewSelection.session = {
    isLoaded: false,
    key: '',

    /**
     * Init elements
     */
  	init() {

      // Check that we have a selection in memory
      var idCourse   = MEMRISE.garden.session_params.course_id,
          idxLevel   = MEMRISE.garden.session_params.level_index;

      ReviewSelection.session.key = 'reviewSession_' + idCourse + '_' + idxLevel;

      var dataFilter = localStorage.getItem(ReviewSelection.session.key);
      if(!dataFilter) {
        window.location = ReviewSelection.session.get_redirect_url();
      	return;
      }

      // Retrieve our selection
      //localStorage.removeItem(ReviewSelection.session.key);

      try {
        ReviewSelection.session.dataFilter = JSON.parse(dataFilter);
      } catch(e) {
        window.location = ReviewSelection.session.get_redirect_url();
				return;
      }

      // Whenever we receive a JSON response:
      // Filter the data
      $.ajaxSetup({
        converters: {
        	'text json': function(txt) {
            var data = JSON.parse(txt);
            
            if(data.boxes) {
            	ReviewSelection.session.filter(data);
            }
            return data;
          }
        }
      });
    },

    /**
     * Returns the URL of the current level details
     */
    get_redirect_url() {
      return `/course/${MEMRISE.garden.session_params.course_id}/${MEMRISE.garden.session_params.clouse_slug}/${MEMRISE.garden.session_params.level_index}/`;
    },

    /**
     * Filter the retrieved review data
     * To only include the selection
     */
    filter(data) {
      
      // Filter
      var boxes  = [],
          learns = [];

      for(let i=0; i<data.boxes.length; i++) {
        let box          = data.boxes[i],
            learnable_id = box.learnable_id;

        if(ReviewSelection.session.dataFilter.list[learnable_id]) {
          box.template  = 'sentinel';
          box.review_me = true;
          boxes.push(box);
          learns.push(data.learnables[i]);
        }
      }

      // Randomize
      var tmp, rand,
          n = boxes.length;

      while(n > 1) {
        rand = Math.floor(Math.random() * n);
        n--;

        tmp          = boxes[n];
        boxes[n]     = boxes[rand];
        boxes[rand]  = tmp;

        tmp          = learns[n];
        learns[n]    = learns[rand];
        learns[rand] = tmp;
      }

      // Save
      data.boxes             = boxes;
      data.learnables        = learns;
      data.session.num_items = boxes.length;
      data.session.slug      = 'classic_review';
  	}
  };
  
  //+------------------------------------------------------
  //|
  //| Init
  //|
  //+------------------------------------------------------

  if(MEMRISE.garden) {
    if(window.location.search == '?selection') {
      MEMRISE.garden.session_params.session_slug = 'preview'; // retrieve every words of the current level
	  	ReviewSelection.session.init();
    }

  } else if(document.querySelector('.things-header')) {
  	ReviewSelection.list.init();
  }
}

// Inject JS directly in page to prevent limitations of access
var script = document.createElement('script');

script.setAttribute("type", "application/javascript");
script.appendChild(document.createTextNode('('+ main +')();'));
document.body.appendChild(script);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址