简体   繁体   中英

Lock/Protect cells in a whole Google spreadsheet containing a specific text value

I have the following script ( from this answer ) which inserts a specific text value to a range of cells based on the date on the second column (B) in the same row.....

function onEdit(e) {
  if (e.range.getColumn() == 2) {
    //User edited the date column
    if (typeof e.range.getValue() === typeof new Date()) {
      //Value of edit was a date
      endColumns(e.range.getRow(), e.range.getValue());
    } else if (e.range.getValue() === ""  || e.range.getValue() === null) {
      var sheets = SpreadsheetApp.getActiveSheet();
      // Delete all "ENDED" values:
      var resetRange = sheets.getRange(e.range.getRow(), e.range.getColumn() + 1, 1, sheets.getMaxColumns() - e.range.getColumn());
      var resetValues = resetRange.getValues()[0];
      for(var i = 0; i < resetValues.length; i++) {
        if(resetValues[i] == "ENDED") {
          var resetCell = sheets.getRange(e.range.getRow(), e.range.getColumn() + 1 + i);
          resetCell.clearContent();
        }
      }      
    }
  }
}

function endColumns(rowNum, limitDate) {
  var sheets = SpreadsheetApp.getActiveSheet();

  var colOffset = 3; //Offset to account for your row Headers
  var dateHeader = sheets.getRange(1, colOffset, 1, sheets.getMaxColumns() - colOffset);

  var availableDates = dateHeader.getValues()[0];

  var foundCol = 0;
  for (var i = 0; i < availableDates.length; i++) {
    if (availableDates[i] >= limitDate) {
      break;
    }
    foundCol++;
  }

  var rewriteCells = sheets.getRange(rowNum, foundCol + colOffset, 1, sheets.getMaxColumns() - (foundCol + colOffset - 1));

  //Add your formatting and text below:
  rewriteCells.setValue("ENDED");

  // Clear past dates if new date is later:
  var beforeDate = sheets.getRange(rowNum, colOffset, 1, foundCol);
  var beforeValues = beforeDate.getValues()[0];
  for(var i = 0; i < beforeValues.length; i++) {
    if(beforeValues[i] == "ENDED") {
      sheets.getRange(rowNum, colOffset + i).clearContent();
    }  
  }


  // Clear all cells that are "white" (no header)
  for (var i = 0; i < availableDates.length; i++) {
    if (availableDates[i] === "" || availableDates[i] === null) {
      sheets.getRange(rowNum, colOffset+i).clear();
    }
  }
}

I want these cells, containing that specific text value, to be lock/protect from edit/delete by any other user except me (which i am the owner of the file). If the date in second column (B) is deleted then the above script clears the text values and the cells should be available for editing from all users.

I've try many codes snippets to do this with no luck and the closest approach that i found is the bellow script, but it locks only one column and all the cells in that column. Not only those with a specific value...

function onEdit(event)
{
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = SpreadsheetApp.getActiveSheet();
  var CellRow = SpreadsheetApp.getActiveRange().getRow();
  var CellColumn = SpreadsheetApp.getActiveRange().getColumn();

  if (CellColumn == 7){
    sheet.getRange(CellRow, CellColumn).setValue("ENDED");
    Browser.msgBox("YOU CANNOT ADD DATA HERE!");
  }
}

Any idea how can i lock only the cells containing that specific text value ("ENDED") and unlock/un-protect them when that value it's cleared?.

The workflow would be as following:

  • Incorporate a function that when run, protects all cells of your range with the content "ENDED"
  • Modify your existing onEdit() function by adding additional code that will check if the content of a cell in column B has been deleted

Below is a sample:

function myStartFunction(){
  var sheets = SpreadsheetApp.getActive().getActiveSheet();
  //adapt according to your datarange
  var myRange=sheets.getRange(1,3,sheets.getLastRow(),sheets.getLastColumn());
  var values=myRange.getValues();
  for(var i=0;i<values.length;i++){
    for(var j=0;j<values[0].length;j++){
      if(values[i][j]=="ENDED"){
        var cell=myRange.getCell(i+1,j+1);
        var protection = cell.protect();
        protection.removeEditors(protection.getEditors());
      }
    }
  }       
}
function onEdit(e){
  //YOUR EXISTING CODE
  if (e.range.getColumn() == 2) {
    //User edited the date column
    if (typeof e.range.getValue() === typeof new Date()) {
      //Value of edit was a date
      endColumns(e.range.getRow(), e.range.getValue());
    } else if (e.range.getValue() === ""  || e.range.getValue() === null) {
      var sheets = SpreadsheetApp.getActiveSheet();
      // Delete all "ENDED" values:
      var resetRange = sheets.getRange(e.range.getRow(), e.range.getColumn() + 1, 1, sheets.getMaxColumns() - e.range.getColumn());
      var resetValues = resetRange.getValues()[0];
      for(var i = 0; i < resetValues.length; i++) {
        if(resetValues[i] == "ENDED") {
          var resetCell = sheets.getRange(e.range.getRow(), e.range.getColumn() + 1 + i);
          resetCell.clearContent();
        }
      }      
    }  
  }

  //HERE COMES THE ADDITIONAL PART
  if(e.range.getColumn() == 2 &&  e.oldValue != "" && e.range.getValue() == "") {
    var row=e.range.getRow();
    var sheets = SpreadsheetApp.getActiveSheet();
    var protections=sheets.getProtections(SpreadsheetApp.ProtectionType.RANGE);
    for (var i = 0; i < protections.length; i++) {
     var protection = protections[i];
     if (protection.getRange().getRow()==row) {
       protection.remove();
      }
    }
  }
}

UPDATE

To implement protection changes on each edit, you can modify the code as following:

var sheets = SpreadsheetApp.getActiveSheet();

function Open(){
  var sheets = SpreadsheetApp.getActive().getActiveSheet();
  //adapt according to your datarange
  var myRange=sheets.getRange(3,3,sheets.getLastRow(),sheets.getLastColumn());
  var values=myRange.getValues();
  for(var i=0;i<values.length;i++){
    for(var j=0;j<values[0].length;j++){
      if(values[i][j]=="ENDED"){
        var cell=myRange.getCell(i+1,j+1);
        var protection = cell.protect();
        protection.removeEditors(protection.getEditors());
      }
    }
  }
}



function onEdit(e) {  
  if (e.range.getColumn() == 2) {
    //User edited the date column
    if (typeof e.range.getValue() === typeof new Date()) {
      //Value of edit was a date
      endColumns(e.range.getRow(), e.range.getValue());
      // wait until the function endColumns() finished
      SpreadsheetApp.flush();
      var myRange=sheets.getRange(e.range.getRow(),3,1,sheets.getLastColumn());
      var values=myRange.getValues();
      for(var j=0;j<values[0].length;j++){
        if(values[0][j]=="ENDED"){
          var cell=myRange.getCell(1,j+1);
          var protection = cell.protect();
          protection.removeEditors(protection.getEditors());
        }
      }      
    } else if (e.range.getValue() === ""  || e.range.getValue() === null) {
        // Delete all "ENDED" values:
        var resetRange = sheets.getRange(e.range.getRow(), e.range.getColumn() + 1, 1, sheets.getMaxColumns() - e.range.getColumn());
        var resetValues = resetRange.getValues()[0];
        for(var i = 0; i < resetValues.length; i++) {
          if(resetValues[i] == "ENDED") {
            var resetCell = sheets.getRange(e.range.getRow(), e.range.getColumn() + 1 + i);
            resetCell.clearContent();                                
          }
        }
      Logger.log('date removed');
      var row=e.range.getRow();
      var protections=sheets.getProtections(SpreadsheetApp.ProtectionType.RANGE);
      for (var i = 0; i < protections.length; i++) {
        var protection = protections[i];
        if (protection.getRange().getRow()==row) {
          protection.remove();
         }
       }      
     }  
  }
}
function endColumns(rowNum, limitDate) {
...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM