简单用例: Jane和Sue正在Google Doc中合作即兴创作一个故事。每次最多添加几个句子并点击一个图标,通知另一个轮到她。
要求:理想情况下,通知很明显但不引人注目,因为协作者可能会在对故事的贡献之间执行其他任务。发送电子邮件或文本消息的解决方案是不可取的,因为协作可以生成数百个这样的消息,没有人想要更杂乱的收件箱。一个好的解决方案可能会弹出警报或更改浏览器中图标的颜色。
另请注意,这与通知文件中的更改不同,因为如果作者停下来考虑下一个短语的措辞,Google Doc AutoSave将很乐意保存不完整的句子。通知需要由作者控制。
我会接受特定于Chrome和/或OS X的解决方案,但越普遍越好。
修改 看起来将Chrome扩展程序API与Google Docs API结合使用是一种可行的方法。下面是我想要创建的应用程序逻辑的CoffeeScript伪代码模型。由于我目前使用这两种API的经验有限,我很欣赏这些API中是否存在必要功能的反馈。 (注意:我的伪代码中的函数名不能与任何API调用的名称匹配。它们只是标识我想要做的事。)
在下面的代码中,“stickholder”一词指的是美洲原住民说话棒的概念,这是一种令其当前持有者有权与该群体交谈的令牌。在这种情况下,持有人是合作者的身份,轮到他们做出下一个贡献。
$(extension_icon).on "click", clickHandler
$(extension).on "changed_doc", changeHandler
clickHandler = () ->
adoc = getActiveBrowserPage()
if isEditableGDoc adoc
# Add to locally stored doc list
# (if it's not there already)
addToMonitoredDocList adoc
# Check stick holder and adjust extension state.
stickholder = getStickHolder adoc
if isMe stickholder
# Relinquish the stick
setStickHolder adoc, ""
setExtensionState adoc, "notmyturn"
else if stickholder == ''
# Stick is available. Takeit.
setStickHolder adoc, myId()
setExtensionState adoc, "myturn"
else
# Stick is held by another collaborator.
setExtensionState adoc, "notmyturn"
else
# Not an editable doc, show the stickholders
# for all the docs I'm monitoring.
showMonitoredDocInfo()
changeHandler = (adoc) ->
# Called when a monitored doc is changed
stickholder = getStickHolder adoc
if stickholder == ''
# Another collaborator has relinquished it
# Let me know it's available
setExtensionState adoc, "possiblymyturn"
getActiveBrowserPage () ->
# TODO Use Chrome Extension API to return URL
# of active tab.
return null
isEditableGDoc = (adoc) ->
# TODO Use Chrome Extension API and GDocs API
# to find out if this is a GDoc to which
# I have editing rights. Return true or false.
return null
addToMonitoredDocList = (adoc) ->
# TODO Use Extension and GDoc API's tp
# set up a change notification listener
# for this doc and add the doc url to a locally
# stored list for persistence.
return null
getStickHolder = (adoc) ->
if hasMetaDataKey adoc, "StickHolder"
return getMetaDataValue adoc, "StickHolder"
else
setMetaData adoc, "StickHolder", ''
return ''
isMe = (stickholder) ->
return stickholder = myID()
myID = () ->
# TODO Use Extension API to get my UserID
return null
setExtensionState = (adoc, statestring) ->
states = ["myturn", "notmyturn", "possiblymyturn"]
assert statestring in states, "#{statestring} is not a valid state"
# TODO get present state from local storage,
# compare to new state,
# alert me if adoc haa changed availability.
# save new state to local storage.
return null
hasMetaDataKey = (adoc, keystring) ->
# TODO Use GDoc API to check existence of
# keystring in doc's metadata (aka Properties)
# returns true or false
return null
getMetaDataValue = (adoc, keystring) ->
# TODO Use GDoc API to return value of doc metadata
# associated with keystring
return null
showMonitoredDocInfo = () ->
# TODO Use Storage API to fetch list of all docs being monitored.
# For each doc, look up current stickholder and present it to me
# as a menu or page from which I can choose to claim an available doc.
return null
assert = (bool, msg) ->
if not bool
throw new Error "Assertion Failed: " + msg