Можете погуглить скрипт приложения будут использоваться в случайном порядке на странице Google Формы?


Update #2: Хорошо, я почти уверен, что моя ошибка в обновлении #1 была вызвана индексацией за пределами массива (я все еще не привык к индексации JS в 0). Но вот новая проблема... если я выпишу различные комбинации цикла вручную, установив индекс страницы на 1 в moveItem() примерно так:

newForm.moveItem(itemsArray[0][0], 1);
newForm.moveItem(itemsArray[0][1], 1);
newForm.moveItem(itemsArray[0][2], 1);
newForm.moveItem(itemsArray[1][0], 1);
newForm.moveItem(itemsArray[1][1], 1);
newForm.moveItem(itemsArray[1][2], 1);
newForm.moveItem(itemsArray[2][0], 1);
...

...Я не получаю никаких ошибок, но элементы в конечном итоге на разных страницах! Что происходит?


Update #1: : использование ответа Сэнди Гуда, а также сценария Я нашел в этом блоге WordPress, мне удалось приблизиться к тому, что мне было нужно. Я думаю, что Сэнди Гуд неверно истолковал то, что я хотел сделать, потому что я не был достаточно конкретен в своем вопросе.

Я хотел бы:

  1. получить все элементы со страницы (заголовок раздела, изображения, вопрос и т.д.)
  2. поместите их в массив
  3. сделайте это для всех страниц, добавив эти массивы в массив (т. е.: [[all items from page 1][all items from page 2][all items from page 3]...])
  4. перетасуйте элементы этого массива
  5. заново заселить новый форма с каждым элементом этого массива. Таким образом, порядок страниц будет рандомизирован.

Мои навыки JavaScript плохи (это первый раз, когда я использую его). Есть шаг, который производит нулевые записи, и я не знаю, почему... Мне пришлось удалить их вручную. Я не могу выполнить шаг 5, так как получаю следующую ошибку:

Cannot convert Item,Item,Item to (class).

"Item, Item, Item" - это элемент массива, содержащий все элементы с определенной страницы. Таким образом, кажется, что я не могу добавить три элемента на страницу в время? Или здесь происходит что-то еще?

Вот мой код:

function shuffleForms() {
  var itemsArray,shuffleQuestionsInNewForm,fncGetQuestionID,
      newFormFile,newForm,newID,shuffle, sections;

  // Copy template form by ID, set a new name
  newFormFile = DriveApp.getFileById('1prfcl-RhaD4gn0b2oP4sbcKaRcZT5XoCAQCbLm1PR7I')
               .makeCopy();
  newFormFile.setName('AAAAA_Shuffled_Form');

  // Get ID of new form and open it
  newID = newFormFile.getId();
  newForm = FormApp.openById(newID);

  // Initialize array to put IDs in
  itemsArray = [];

  function getPageItems(thisPageNum) {
    Logger.log("Getting items for page number: " + thisPageNum );
    var thisPageItems = []; // Used for result
    var thisPageBreakIndex = getPageItem(thisPageNum).getIndex();
    Logger.log( "This is index num : " + thisPageBreakIndex );

    // Get all items from page
    var allItems = newForm.getItems();
    thisPageItems.push(allItems[thisPageBreakIndex]);
    Logger.log( "Added pagebreak item: " + allItems[thisPageBreakIndex].getIndex() );
    for( var i = thisPageBreakIndex+1; ( i < allItems.length ) && ( allItems[i].getType() != FormApp.ItemType.PAGE_BREAK ); ++i ) {
      thisPageItems.push(allItems[i]);
      Logger.log( "Added non-pagebreak item: " + allItems[i].getIndex() );
    }
    return thisPageItems;
  }

  function shuffle(array) {
    var currentIndex = array.length, temporaryValue, randomIndex;

    Logger.log('shuffle ran')

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

      // Pick a remaining element...
      randomIndex = Math.floor(Math.random() * currentIndex);
      currentIndex -= 1;

      // And swap it with the current element.
      temporaryValue = array[currentIndex];
      array[currentIndex] = array[randomIndex];
      array[randomIndex] = temporaryValue;
  }

  return array;
  }

  function shuffleAndMove() {

    // Get page items for all pages into an array
    for(i = 2; i <= 5; i++) {
      itemsArray[i] = getPageItems(i);
    }

    // Removes null values from array
    itemsArray = itemsArray.filter(function(x){return x});

    // Shuffle page items
    itemsArray = shuffle(itemsArray);

    // Move page items to the new form
    for(i = 2; i <= 5; ++i) {
      newForm.moveItem(itemsArray[i], i);
    }
  }

  shuffleAndMove();
} 

Оригинальное сообщение: я использовал Google forms для создания анкеты. Для моих целей каждый вопрос должен быть на отдельной странице, но мне нужно, чтобы страницы были рандомизированы. Быстрый поиск в Google показывает, что эта функция еще не добавлена.

Я вижу, что класс Form в скрипте Google apps имеет ряд методов, которые изменяют / дают доступ к различным свойствам Google Формы. Поскольку я не знаю Javascript и не слишком хорошо знаком с Google apps / API, я хотел бы знать, возможно ли то, что я пытаюсь сделать, прежде чем погружаться и выяснять все это.

Если это возможно,я был бы признателен за любое понимание того, какие методы будут уместны для этой задачи, просто чтобы дать мне некоторое направление для начала.

Основываясь на комментариях Сэнди Гуда и двух вопросах SE, найденных здесь и здесь , это код, который я так далеко:

// Script to shuffle question in a Google Form when the questions are in separate sections

function shuffleFormSections() {
  getQuestionID();
  createNewShuffledForm();
}

// Get question IDs
  function getQuestionID() {
    var form = FormApp.getActiveForm();
    var items = form.getItems();
    arrayID = [];
    for (var i in items) { 
      arrayID[i] = items[i].getId();
    }
    // Logger.log(arrayID);
    return(arrayID);
}

// Shuffle function
  function shuffle(a) {
    var j, x, i;
    for (i = a.length; i; i--) {
        j = Math.floor(Math.random() * i);
        x = a[i - 1];
        a[i - 1] = a[j];
        a[j] = x;
    }
}

// Shuffle IDs and create new form with new question order
function createNewShuffledForm() {
    shuffle(arrayID);
    // Logger.log(arrayID);
    var newForm = FormApp.create('Shuffled Form');
    for (var i in arrayID) {
      arrayID[i].getItemsbyId();
  }
}
2 2

2 ответа:

Попробуйте это. Есть несколько "констант", которые нужно установить в верхней части функции, проверьте комментарии. Копирование и открытие файла формы заимствовано из ответа Сэнди Гуда, спасибо!

// This is the function to run, all the others here are helper functions
// You'll need to set your source file id and your destination file name in the
// constants at the top of this function here.
// It appears that the "Title" page does not count as a page, so you don't need
// to include it in the PAGES_AT_BEGINNING_TO_NOT_SHUFFLE count. 
function shuffleFormPages() {   
  // UPDATE THESE CONSTANTS AS NEEDED
  var PAGES_AT_BEGINNING_TO_NOT_SHUFFLE = 2; // preserve X intro pages; shuffle everything after page X
  var SOURCE_FILE_ID = 'YOUR_SOURCE_FILE_ID_HERE'; 
  var DESTINATION_FILE_NAME = 'YOUR_DESTINATION_FILE_NAME_HERE';

  // Copy template form by ID, set a new name
  var newFormFile = DriveApp.getFileById(SOURCE_FILE_ID).makeCopy();
  newFormFile.setName(DESTINATION_FILE_NAME);

  // Open the duplicated form file as a form
  var newForm = FormApp.openById(newFormFile.getId());

  var pages = extractPages(newForm);
  shuffleEndOfPages(pages, PAGES_AT_BEGINNING_TO_NOT_SHUFFLE); 
  var shuffledFormItems = flatten(pages);

  setFormItems(newForm, shuffledFormItems);  
}

// Builds an array of "page" arrays. Each page array starts with a page break
// and continues until the next page break.
function extractPages(form) {
  var formItems = form.getItems();
  var currentPage = [];
  var allPages = [];

  formItems.forEach(function(item) { 
    if (item.getType() == FormApp.ItemType.PAGE_BREAK && currentPage.length > 0) {
      // found a page break (and it isn't the first one)
      allPages.push(currentPage); // push what we've built for this page onto the output array
      currentPage = [item]; // reset the current page to just this most recent item
    } else {
      currentPage.push(item);
    }
  });
  // We've got the last page dangling, so add it
  allPages.push(currentPage);
  return allPages;
};

// startIndex is the array index to start shuffling from. E.g. to start
// shuffling on page 5, startIndex should be 4. startIndex could also be thought
// of as the number of pages to keep unshuffled.
// This function has no return value, it just mutates pages
function shuffleEndOfPages(pages, startIndex) {
  var currentIndex = pages.length;

  // While there remain elements to shuffle...
  while (currentIndex > startIndex) {
    // Pick an element between startIndex and currentIndex (inclusive)
    var randomIndex = Math.floor(Math.random() * (currentIndex - startIndex)) + startIndex;

    currentIndex -= 1;

    // And swap it with the current element.
    var temporaryValue = pages[currentIndex];
    pages[currentIndex] = pages[randomIndex];
    pages[randomIndex] = temporaryValue;
  }
};

// Sourced from elsewhere on SO:
// https://stackoverflow.com/a/15030117/4280232
function flatten(array) {
  return array.reduce(
    function (flattenedArray, toFlatten) {
      return flattenedArray.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
    }, 
    []
  );
};

// No safety checks around items being the same as the form length or whatever.
// This mutates form.
function setFormItems(form, items) {
  items.forEach(function(item, index) {
    form.moveItem(item, index);
  });
};

Я протестировал этот код. Он создал новую форму, а затем перетасовал вопросы в новой форме. Он исключает разрывы страниц, изображения и заголовки разделов. Необходимо указать идентификатор исходного файла для исходной формы шаблона. Эта функция имеет 3 внутренних подфункции. Внутренние функции находятся вверху, а они вызываются внизу внешней функции. Переменную arrayOfIDs не нужно возвращать или передавать другой функции, поскольку она доступна во внешней области видимости.

function shuffleFormSections() {
  var arrayOfIDs,shuffleQuestionsInNewForm,fncGetQuestionID,
      newFormFile,newForm,newID,items,shuffle;

  newFormFile = DriveApp.getFileById('Put the source file ID here')
               .makeCopy();
  newFormFile.setName('AAAAA_Shuffled_Form');

  newID = newFormFile.getId();

  newForm = FormApp.openById(newID);

  arrayOfIDs = [];

  fncGetQuestionID = function() {
    var i,L,thisID,thisItem,thisType;

    items = newForm.getItems();
    L = items.length;

    for (i=0;i<L;i++) {
      thisItem = items[i];
      thisType = thisItem.getType();

      if (thisType === FormApp.ItemType.PAGE_BREAK || 
      thisType === FormApp.ItemType.SECTION_HEADER || 
      thisType === FormApp.ItemType.IMAGE) {
       continue; 
      }

      thisID = thisItem.getId();
      arrayOfIDs.push(thisID);
    }

    Logger.log('arrayOfIDs: ' + arrayOfIDs);
    //the array arrayOfIDs does not need to be returned since it is available
    //in the outermost scope
  }// End of fncGetQuestionID function

  shuffle = function() {// Shuffle function
    var j, x, i;
    Logger.log('shuffle ran')

    for (i = arrayOfIDs.length; i; i--) {
      j = Math.floor(Math.random() * i);
      Logger.log('j: ' + j)

      x = arrayOfIDs[i - 1];
      Logger.log('x: ' + x)

      arrayOfIDs[i - 1] = arrayOfIDs[j];

      arrayOfIDs[j] = x;
    }

    Logger.log('arrayOfIDs: ' + arrayOfIDs)
  }

  shuffleQuestionsInNewForm = function() {
    var i,L,thisID,thisItem,thisQuestion,questionType;

    L = arrayOfIDs.length;

    for (i=0;i<L;i++) {
      thisID = arrayOfIDs[i];
      Logger.log('thisID: ' + thisID)
      thisItem = newForm.getItemById(thisID);

      newForm.moveItem(thisItem, i)
    }
  }

  fncGetQuestionID();//Get all the question ID's and put them into an array
  shuffle();

  shuffleQuestionsInNewForm();
}