Определение того, какой элемент был выбран в пользовательском меню - PullRequest
0 голосов
/ 27 июня 2018

Я создал пользовательское меню с несколькими пунктами, но у меня возникают трудности с определением, на какой элемент пользователь нажал. Я хочу использовать одну и ту же функцию для каждого элемента в этом меню, но не могу понять, как передать информацию о том, какой элемент был нажат в мою функцию. Вот несколько идей, которые у меня были, но которые я не смог реализовать: попытка передать параметр при нажатии кнопки (параметр может быть именем кнопки или ее индексом) или попытка каким-то образом определить, какой элемент был нажат по индексу (то есть «пункт 3 был нажат») и передаче этой информации в функцию.

var ui = SpreadsheetApp.getUi(); //shortcut to access ui methods
var ps = PropertiesService.getScriptProperties(); //shortcut to access properties methods
var ss = SpreadsheetApp.getActiveSpreadsheet() //shortcut to access spreadsheet methods

function onOpen() {
  var menu = ui.createMenu('Scripts') //create a menu with this name
  var subMenu = ui.createMenu('Timestamps')
        for (var n = 0; n < ss.getNumSheets(); n++){
          var sheets = ss.getSheets();
          var sheetName = sheets[n].getName();
          Logger.log(sheetName)
          subMenu.addItem(sheetName, 'sheets')
        }
      menu.addSubMenu(subMenu).addToUi(); //add it to the UI
}

function sheets(sheet){
  var response = ui.alert(sheet, 'Add to timestamps?', ui.ButtonSet.YES_NO_CANCEL) //create a button and store the user value in response
  if(response == ui.Button.YES){ //if the user pressed YES (add this item to timestamp list)
    if(sheets.indexOf(sheet) != -1){ //check if item is already in the array. If it is, do nothing
      //item is aleady in array
    }else if(sheets.indexOf(sheet) == -1){ //check if it is NOT in the array. If it isn't, add it
      //item isn't in array, but needs to be added
      sheets.push(sheet) //add the item to the array
    }
  }else if(response == ui.Button.NO){ //if the user pressed NO (remove item from the list)
    if(sheets.indexOf(sheet) != -1){ //if the item already exists but needs to be removed)
      //item exists in array, but needs to be removed
      var index = sheets.indexOf(sheet); //find where the item is stored
      sheets.splice(index, 1); //splice that item out of the array
    }else if(sheets.indexOf(sheet) == -1){ //if the item already doesn't exist in the array, do nothing
      //item already isn't in array
    }
  }
  ps.setProperty('updatedSheets', JSON.stringify(sheets)) //storing the new value of sheets so that we can view it in the properties screen (only for debugging purposes)
}

Что этот код делает в данный момент, так это то, что при открытии электронной таблицы создается меню с именем Scripts с подменю внутри него с именем Timestamps. Внутри временных меток подменю у меня есть один элемент для каждого листа. Цель состоит в том, чтобы, когда пользователь нажимает на один из элементов, появляется всплывающее окно с 3 кнопками: Да, Нет и Отмена. Если они нажимают Да, этот элемент должен быть добавлен в листы массива. Если они нажимают Нет, этот элемент должен быть удален. Если они нажимают Отмена, ничего не происходит. У меня до сих пор работает, чтобы добавить и удалить элементы, если они указывают в коде конкретный лист, но как я могу получить его, чтобы я мог использовать одну и ту же функцию для каждого элемента и передать лист параметров (в зависимости от того, какой элемент был щелкнул) в функциональных листах.

Пример функциональности кода, если я жестко закодировал имя листа, не передав параметр в функцию:

function sheets(){
  var response = ui.alert('Sheet1', 'Add to timestamps?', ui.ButtonSet.YES_NO_CANCEL) //create a button and store the user value in response
  if(response == ui.Button.YES){ //if the user pressed YES (add this item to timestamp list)
    if(sheets.indexOf('Sheet1') != -1){ //check if item is already in the array. If it is, do nothing
      //item is aleady in array
    }else if(sheets.indexOf('Sheet1') == -1){ //check if it is NOT in the array. If it isn't, add it
      //item isn't in array, but needs to be added
      sheets.push('Sheet1') //add the item to the array
    }
  }else if(response == ui.Button.NO){ //if the user pressed NO (remove item from the list)
    if(sheets.indexOf('Sheet1') != -1){ //if the item already exists but needs to be removed)
      //item exists in array, but needs to be removed
      var index = sheets.indexOf('Sheet1'); //find where the item is stored
      sheets.splice(index, 1); //splice that item out of the array
    }else if(sheets.indexOf('Sheet1') == -1){ //if the item already doesn't exist in the array, do nothing
      //item already isn't in array
    }
  }
  ps.setProperty('updatedSheets', JSON.stringify(sheets)) //storing the new value of sheets so that we can view it in the properties screen (only for debugging purposes)
}

Ответы [ 2 ]

0 голосов
/ 27 июня 2018

Это на самом деле не ответ на ваш вопрос, но я думаю, что вы слишком усложнили себя, и этот ответ мог бы помочь другим людям ... Для моего текущего проекта мне нужно то же самое, и я придумал отличную идею , В HTML я сделал таблицы для каждой части меню:

            <ul class='custom-menu' id="main-menu">
              <li data-action="One">Custom menu click one</li>
              <li data-action="Two">Custom menu click two</li>
              <li data-action="Three">Custom menu click three</li>
            </ul>
            <ul class='custom-menu' id="subMenuOne">
              <li data-action="sub1">Sub Menu One</li>
              <li data-action="sub2">Sub Menu Two</li>
              <li data-action="sub3">Sub Menu Three</li>
            </ul>

Затем я добавил стиль к таблицам и сделал так, чтобы при наведении курсора на строку она меняла цвет, на мышке менялся значок. Вам не нужен именно этот стиль. Будьте креативны:

        .custom-menu {
            display: none;
            z-index: 1000;
            position: absolute;
            overflow: hidden;
            border: 1px solid #CCC;
            white-space: nowrap;
            font-family: sans-serif;
            background: #FFF;
            color: #333;
            border-radius: 5px;
            padding: 0;
        }

        .custom-menu li {
            padding: 8px 12px;
            cursor: pointer;
            list-style-type: none;
            transition: all .3s ease;
            user-select: none;
        }
        .custom-menu li:hover {
            background-color: #DEF;
        }

Дисплей : нет , чтобы скрыть таблицу. Он появится при щелчке правой кнопкой мыши ...

Затем мне понадобился JavaScript, чтобы сделать его контекстным меню. Я начал с того, что главное меню появилось при щелчке правой кнопкой мыши:

    $(document).bind("contextmenu", function (event) {
        event.preventDefault();
        $("#main-menu").finish().toggle(100).css({
            top: event.pageY + "px",
            left: event.pageX + "px"
        });
    });

event.preventDefault() предотвращает появление пользовательского меню по умолчанию и позволяет вместо этого отображать мое меню ...

Теперь мне нужно проверить, нажали ли <li></li>:

   $("#main-menu li").click(function(){
        switch($(this).attr("data-action")) {        
            case "One": alert("One"); break;
            case "Two": alert("Two"); break;
            case "Three": alert("three"); break;
        } 
        $("#main-menu").hide(100);
    });

При нажатии <li></li> этот код сначала находит, какой из них был нажат с помощью data-action , присваиваемого каждому <li></li>. Затем, в конце, прячется #main-menu.

Но теперь мы хотим, чтобы появилось подменю. Как ? Что ж, мы просто заставляем его отображаться так же, как и главное меню, но в той же позиции, с этим кодом:

    $("#allBlocks").finish().toggle(100).css({
            top: $("#main-menu").css("top"),
            left: $("#main-menu").css("left"),
    });

Мы просто вставляем этот код вместо предупреждений в один из случаев. Здесь я вставил его в число ТРИ

       $("#main-menu li").click(function(){
            switch($(this).attr("data-action")) {        
                case "One": alert("One"); break;
                case "Two": alert("Two"); break;
                case "Three": 
                    $("#subMenuOne").finish().toggle(100).css({
                        top: $("#main-menu").css("top"),
                        left: $("#main-menu").css("left"),
                    });
                    break;
            } 
            $("#main-menu").hide(100);
        });

Затем, чтобы закончить, мы помещаем тот же механизм щелчка в подменю, VOILA . У вас есть отличное меню, работающее ...

Вот ссылка на JSFiddle , для большего понимания ..

Надеюсь, это кому-то помогло

:) f

0 голосов
/ 27 июня 2018

Я знаю, eval это зло, но я не могу не использовать его. Да, если вы создаете кучу функций динамически через eval, то все остальное тривиально.

var FUNC_STR = 'sheets';  //the real function name (global constant)

function onOpen() {
  //...
  for(var n = 0; n < ss.getNumSheets(); n++){
    var sheets = ss.getSheets();
    var sheetName = sheets[n].getName();
    subMenu.addItem(sheetName, FUNC_STR + n);  //note here
  }
  menu.addSubMenu(subMenu).addToUi();
}


//dynamically make functions
var evalString = '';
for(var n = 0; n < ss.getNumSheets(); n++) {
  evalString += 'function ' + FUNC_STR + n + '() { ' + 
    FUNC_STR + '(' + n + ') }';
}
eval(evalString);


//now you can take a argument.
//function name should be the same as FUNC_STR.
function sheets(sheet) {
  SpreadsheetApp.getUi().alert(sheet);
  //...
}
...