google-apps-script - 创建一个基本的聊天栏?

标签 google-apps-script chat google-docs

以下是旧的;查看底部更新的文本。

因此,我和我的 friend 在学校时使用 Google 文档进行交流,我们设置了挑战,以创建一个可用且“高效”的聊天栏,以取得更好的效果。我使用 JavaScript 已经有一段时间了,但之前从未使用过 Google Apps 脚本。我们使用文档应用程序进行聊天;我想出的代码如下,但我有一些问题:

  1. 当用户关闭它,然后转到工具栏中的聊天 -> 打开聊天重新打开时出现错误,并显示“遇到错误:发生意外错误 ”;没有指定行或原因
  2. 需要在文档中的某个位置有一个隐藏元素,该元素可以允许用户查看其他人键入的内容,但如果不使用聊天框,他们就无法进行编辑(将添加事件监听器以在修改文本时更新聊天框)<

//Main function, ran when the document first opens.
function onOpen() {
    var app = UiApp.createApplication(); //Create a Ui App to use for the chat bar

    if(getCurrentUser()=="dev1"||getCurrentUser()=="dev2"){ //user-Id's hidden for privacy
        DocumentApp.getUi().createMenu('Chat')
          .addItem('AutoColor', 'autoColor')
          .addItem('Open Chat', 'createChatBox')
          .addItem('Elements', 'displayElements') //Hidden as it is not important for regular use
          .addItem('MyID', 'showUser')
          .addToUi();
    }else{
        DocumentApp.getUi().createMenu('Chat')
          .addItem('AutoColor', 'autoColor')
          .addItem('Open Chat', 'createChatBox')
          .addToUi();
   }
}

//Creates and returns the chats GUI
function createChatBox(){
    var app = UiApp.getActiveApplication()
    app.setTitle("Chat Bar (not yet working)");
    var vPanel = app.createVerticalPanel().setId('chatPanel').setWidth('100%');
    var textArea = app.createTextArea().setId('chatBox').setName('chatBox').setReadOnly(true).setText('').setSize('250px', '450px'); //Read only so they can not edit the text, even if it won't affect overall chat
    var textBox = app.createTextBox().setId('messageBox').setName('messageBox').setText('Words');
    var chatHandler = app.createServerHandler("sayChat").addCallbackElement(textArea).addCallbackElement(textBox);
    var chatButton = app.createButton().setId("sayButton").setText("Say!").addMouseUpHandler(chatHandler);

    vPanel.add(textArea);
    vPanel.add(textBox);
    vPanel.add(chatButton);

    app.add(vPanel);
    DocumentApp.getUi().showSidebar(app);
    return app;
}

//The event handler for when the "Say!" (post) button is pressed. Is probably where the conflict stems from.
function sayChat(eventInfo){
    var app = UiApp.getActiveApplication();
    var parameter = eventInfo.parameter;

    app.getElementById("chatBox").setText(parameter.chatBox+"["+getCurrentUser()+"]: "+parameter.messageBox);
    app.getElementById("messageBox").setText("");

    return app;
}

//A debug function and a function to tell you the unique part of your email (useless, really)
function showUser(){
    DocumentApp.getUi().alert("Your userId is: "+getCurrentUser());
}

//Returns the unique part of a person's email; if their email is "<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="761b17111f150305130436111b171f1a5815191b" rel="noreferrer noopener nofollow">[email protected]</a>", it returns "magicuser"
function getCurrentUser(){
    var email = Session.getActiveUser().getEmail();
    return email.substring(0,email.indexOf("@"));
}
//The Auto-color and displayElements methods are hidden as they contain other user-info. They both work as intended and are not part of the issue.

我不需要有人重写代码(尽管我们会非常感激!),而是指出我做错了什么或建议更改/添加一些内容。

最后,在您建议之前,Google 文档聊天功能不适用于我们的计算机。这不是文档的错误,但可能是我们的浏览器的兼容性错误。正是因为这个问题,我们才经历了这个有趣但仓促的过程来制作我们自己的聊天方法。

更新

我决定放弃使用纯 Google Apps 脚本的我的聊天版本,并使用 G-A-S 和 HTML 帮助改进我 friend 的版本。我添加了使用命令/img 或/image 的图像缩略图/链接支持,以及改进的时间和计数器,以及其他一些幕后更新。这是它的快速屏幕截图:

Google Apps Script chat

从头开始编写的精彩聊天,没有错误的更新方法,只是随意刷新数据库来检查消息并设置 HTML 文本区域文本。不再有 bug 的 getText 方法。对于数据库中的每条新消息,无论是针对用户还是针对聊天中的每个人,我们都会加载所有数据库消息直至达到限制(一次 50 条消息),然后显示它们。消息中 HTML 的使用是其外观和功能(例如图像)的关键。

function getChat() {
  var chat = "";
  var time = getTime();

  var username = getCurrentUsername();

  var db = ScriptDb.getMyDb();
  var query = db.query({time : db.greaterThan(getJoinTime())}).sortBy('time', db.DESCENDING).limit(50);

  var flag = query.getSize() % 2 != 0;

  while(query.hasNext()) {
    var record = query.next();
    if(record.showTo == "all" || record.showTo == getCurrentUsername()) {
      var text = record.text;
      for(var i = 0; i < text.split(" ").length; i++) {
        var substr = text.split(" ")[i];
        if(substr.indexOf("http://") == 0 || substr.indexOf("https://") == 0) {
          text = text.replace(substr, "<a href='" + substr + "'>" + substr + "</a>");
        }
      }
      var message = "<pre style='display:inline;'><span class='" + (flag? "even" : "odd") + "'><b>[" + record.realTime + "]</b>" + text;
      message += "</span></pre>";
      chat += message;
      flag = !flag;
    }
  }
  //DocumentApp.getUi().alert(getTime() - time);

  return chat;
}

我将重新执行他的 getChat() 方法,以仅检查新消息,而不是在每次刷新时加载每条消息。

最佳答案

要消除错误消息,首先要在 createChat 函数中创建 UiApp,而不是 onOpen

我还使用了客户端处理程序来清除文本框,因为它更加高效。这是修改后的代码:

代码已删除,请参阅下面的更新

至于你的第二个请求,我不确定我是否完全理解你想要做什么...你能更准确地解释一下你期望的行为吗? (这更多的是评论而不是答案,但我使用“答案字段”更具可读性)


编辑:我稍微研究了一下这段代码,发现它几乎可以工作......它仍然需要改进,但值得展示它是如何工作的。

我使用 scriptProperties 来存储对话的公共(public)部分,我认为这是一个很好的方法,但问题是它知道何时更新其内容。这是我到目前为止的代码,当然我一直对任何建议/改进持开放态度。

代码已删除,新版本如下


编辑 2:这是一个具有自动更新功能的版本,效果非常好,脚本会在一定时间内自动更新聊天区域...如果没有事件,则会停止并等待用户操作。请测试(使用 2 个帐户)并让我们知道您的想法。

请注意,我使用了一个复选框来处理自动更新,出于测试目的,我将其保持可见,但当然它可以在最终版本中隐藏。

编辑3:添加了一条消息,以在用户离线时警告用户 + 将文本框更改为彩色文本区域,以允许更长的消息 + 清除消息框的条件,以便警告消息不会出现参与对话。 (为了测试目的,将超时设置为很短的值,更改计数器值以恢复到您的需要)

function onOpen() {

    if(getCurrentUser()=="dev1"||getCurrentUser()=="dev2"){ //user-Id's hidden for privacy
        DocumentApp.getUi().createMenu('Chat')
          .addItem('AutoColor', 'autoColor')
          .addItem('Open Chat', 'createChatBox')
          .addItem('Elements', 'displayElements') //Hidden as it is not important for regular use
          .addItem('MyID', 'showUser')
          .addToUi();
    }else{
        DocumentApp.getUi().createMenu('Chat')
          .addItem('AutoColor', 'autoColor')
          .addItem('Open Chat', 'createChatBox')
          .addToUi();
   }
}

function createChatBox(){
  ScriptProperties.setProperty('chatContent','');
  var app = UiApp.createApplication().setWidth(252);
  app.setTitle("Chat Bar");
  var vPanel = app.createVerticalPanel().setId('chatPanel').setWidth('100%');
  var chatHandler = app.createServerHandler("sayChat").addCallbackElement(vPanel);
  var textArea = app.createTextArea().setId('chatBox').setName('chatBox').setReadOnly(true).setText('').setSize('250px', '450px');
  var textBox = app.createTextArea().setId('messageBox').setName('messageBox').setText('Start chat...').setPixelSize(250,100).setStyleAttributes({'padding':'5px','background':'#ffffcc'}).addKeyPressHandler(chatHandler);
  var clearTextBoxClientHandler = app.createClientHandler().forTargets(textBox).setText('');
  textBox.addClickHandler(clearTextBoxClientHandler);
  var chatButton = app.createButton().setId("sayButton").setText("Say!").addMouseUpHandler(chatHandler);
  var chkHandler = app.createServerHandler('autoUpdate').addCallbackElement(vPanel);
  var chk = app.createCheckBox().setId('chk').addValueChangeHandler(chkHandler);
  vPanel.add(textArea);
  vPanel.add(textBox);
  vPanel.add(chatButton);
  vPanel.add(chk);
  app.add(vPanel);
  DocumentApp.getUi().showSidebar(app);
  return app;
}

function sayChat(e){
  var app = UiApp.getActiveApplication();  
  var user = '['+getCurrentUser()+'] : ';
  if(e.parameter.messageBox=="You have been put offline because you didn't type anything for more than 5 minutes..., please click here to refresh the conversation"){
    app.getElementById('messageBox').setText('');// clear messageBox
    ScriptProperties.setProperty('chatTimer',0);// reset counter
    return app;
  }
  if(e.parameter.source=='messageBox'&&e.parameter.keyCode!=13){return app};
  var content = ScriptProperties.getProperty('chatContent');
  ScriptProperties.setProperty('chatContent',content+"\n"+user+e.parameter.messageBox)
  app.getElementById("chatBox").setText(content+"\n"+user+e.parameter.messageBox+'\n');
  app.getElementById('messageBox').setText('');
  app.getElementById('chk').setValue(true,true);
  ScriptProperties.setProperty('chatTimer',0);
  return app;
}

function autoUpdate(){
  var app = UiApp.getActiveApplication();
  var content = ScriptProperties.getProperty('chatContent');
  var counter = Number(ScriptProperties.getProperty('chatTimer'));
  ++counter;
  if(counter>20){
    app.getElementById('chk').setValue(false);
    app.getElementById('messageBox').setText("You have been put offline because you didn't type anything for more than 5 minutes..., please click here to refresh the conversation");
    return app;
  }
  ScriptProperties.setProperty('chatTimer',counter);
  var content = ScriptProperties.getProperty('chatContent');
  app.getElementById("chatBox").setText(content+'*'); // the * is there only for test purpose
  app.getElementById('chk').setValue(false);
  Utilities.sleep(750);
  app.getElementById('chk').setValue(true,true).setText('timer = '+counter);
  return app;
}

function showUser(){
  DocumentApp.getUi().alert("Your userId is: "+getCurrentUser());
}

function getCurrentUser(){
  var email = Session.getEffectiveUser().getEmail();
  return email.substring(0,email.indexOf("@"));
}

关于google-apps-script - 创建一个基本的聊天栏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19648798/

相关文章:

c - TCP/IP 轮询客户端在 c 中发送和接收

java - 聊天java网络服务器,http部分响应

csv - 以 CSV 格式下载公共(public) Google 电子表格?

google-apps-script - 确定 Apps 脚本中的当前用户

google-apps-script - 如何禁用 SpreadsheetApp.addMenu 项

javascript - 使用 AJAX/PHP 上传和下载变量

javascript - 在 Google Apps 脚本中的文本前插入换行符

google-apps-script - 如何获取表格宽度

javascript - Google Apps 脚本挂起 (javascript)

google-apps-script - DocumentApp 表 : How do I merge cells in a column? [w/workaround]