可以使用Google应用脚本在Google表单上随机化页面顺序吗?

时间:2017-06-30 20:35:51

标签: google-apps-script google-api google-form

更新#2:好的,我非常确定更新#1中的错误是因为索引超出了数组的范围(我还没有习惯使用JS索引为0)。但这是新问题......如果我手动写出循环的不同组合,请将{1}}中的页面索引设置为1,如下所示:

moveItem()

...我没有收到任何错误,但这些项目最终会出现在不同的页面上!发生了什么事?

更新#1::使用Sandy Good的答案以及我在this WordPress博客上找到的脚本,我已经设法接近我需要的内容。我相信Sandy Good误解了我想做的事情,因为我的问题并不够具体。

我想:

  1. 从页面获取所有项目(章节标题,图片,问题等)
  2. 将它们放入数组
  3. 对所有页面执行此操作,将这些数组添加到数组中(即: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); ...
  4. 随机播放此阵列的元素
  5. 使用此数组的每个元素重新填充新表单。通过这种方式,页面顺序将被随机化。
  6. 我的JavaScript技能很差(这是我第一次使用它)。有一个步骤产生空条目,我不知道为什么......我不得不手动删除它们。因为收到以下错误,我无法完成第5步:

    [[all items from page 1][all items from page 2][all items from page 3]...]

    "项目,项目,项目"是包含特定页面中所有项的数组元素。所以我似乎无法一次向页面添加三个项目?或者是其他事情发生在这里?

    这是我的代码:

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

    原帖:我使用Google表单创建问卷。就我的目的而言,每个问题都需要在一个单独的页面上,但我需要将这些页面随机化。 Google快速搜索显示此功能尚未添加。

    我发现Google应用脚本中的Form class有许多方法可以更改/授予对Google表单各种属性的访问权限。由于我不了解Javascript并且对Google应用程序/ API不太熟悉,因此我想知道我想要做什么甚至可以在潜入并全部解决之前。

    如果有可能,我会很感激有关这项任务的相关方法的任何见解,只是为了给我一些指导方法。

    根据Sandy Good的评论以及herehere发现的两个SE问题,这是我到目前为止的代码:

    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();
    } 
    

2 个答案:

答案 0 :(得分:1)

我测试了这段代码。它创建了一个新表单,然后将新表单中的问题拖了一下。它不包括分页符,图像和节标题。您需要为原始模板表单提供源文件ID。该功能有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();
}

答案 1 :(得分:1)

试试这个。在函数的顶部设置了一些“常量”,检查注释。表格文件复制和开放借用了Sandy Good的答案,谢谢!

// 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);
  });
};