I just tried out the “forcedROMode” described in the docs in the ActionButtons section.
While implementing a “RO-Toggle” command, my demand came up: I’d like to edit the Action-Buttons “on-the-fly” to change a button/icon to represent the current status.
Would be nice, if the “actionbutton.define” function would get an “actionbutton.update” equivalent
(or maybe an “actionbutton.delete” to remove a button to create it new)
Dont’t know, if changing buttons at runtime is possible, anyway…
actionButton.define {
icon = (editor.getUiOption("forcedROMode") and "eye-off") or "eye",
run = function()
local mode = editor.getUiOption("forcedROMode")
editor.setUiOption("forcedROMode", not mode)
editor.rebuildEditorState()
editor.reloadConfigAndCommands()
end
}
Tried it and it works like a charm! Thanks again!
In fact, that basically is exactly what I tried to achieve.
The puzzle piece I was missing obviously is the “actionbutton.define” function.
Until now I used the "config.set { actionbuttons = … } definition.
And thanks for the idea to simply reload the config/UI. Did not see the forest for the trees here…
Only thing I have to figure out now is how to define the position of the button, as via “actionbuttons.define”, the button is placed at the end (which is only a cosmetic issue for me…)
Glad that worked
Looking at the implementation, the config.set { actionbuttons = ... } method should still work, as actionbutton.define is just a wrapper for that. I think what’s changed is that instead of the command key you’d use the run key with a function value. That way you can still control the order in wich the buttons are placed. Didn’t try that yet though.
local ro = editor.getUiOption("forcedROMode")
actionButton.define {
mobile = true,
icon = (ro and "edit2") or "eye",
run = function()
local cursor = editor.getCursor()
editor.setUiOption("forcedROMode", not ro)
editor.rebuildEditorState()
editor.reloadConfigAndCommands()
js.window.document.querySelector(".sb-mini-editor .cm-content").contentEditable = ro
editor.moveCursor(cursor, true)
end
}
Some support for ordering is needed for actionButton.define{}. I’ve no time to inspect now, but perhaps there is some already. It would be weird a little to not allow ordering of the buttons in the first plan.
I found one more thing that should not be “editable” in read-only mode. Tasks can still be clicked and edited. (I hit this one accidentaly while on mobile where I use this primarily.)
Also, it would be nice if we can hide the edit icon for ${} queries.
Anything else? It will be splendid if we hack all of this together to achieve truly safe read-only mode to be used while rumbling on public transportation vehicles, won’t it?
Well, from my point of view I like it exacty the way it is now.
For example:
I write my shopping list to a note at home. Then I switch to readonly.
Later in the shop I can still check my purchased items, but it prevents editing of the list itself.
Before I discovered readonly, I had several times, that I deleted some text by mistake instead of checking.
I destroyed many things historicaly while using SB in weird and rushy situations that I would rather be safe on mobile. Just looking for a way to do it. The effort is also worth as example of what can be done using the more advanced APIs. And, it’s just a Lua function in the end. Put whatever suit you best in it.
So I extended this with all of the above and some extra features like persistence, and made it easily configurable. You can now also (optionally):
Disable the checkboxes!
Remember the read-only mode across sessions and set it on reload, so that for example on mobile it will stay on read-only mode
This is what I’ve got now and it works great!
-- Must be set before actionButtons
config.set {
readOnly = {
mobileOnlyActionButton = false,
disableCheckboxes = true,
shortcut = 'Ctrl-alt-t',
persistent = true,
enabledIcon = 'edit',
disabledIcon = 'eye'
}
}
config.set {
actionButtons = {
-- Your other action buttons here...
{
mobile = config.get('readOnly').mobileOnlyActionButton,
icon = editor.getUiOption("forcedROMode") and config.get('readOnly').enabledIcon or config.get('readOnly').disabledIcon,
description = editor.getUiOption("forcedROMode") and "Enable edit mode" or "Enable read-only mode",
run = function()
editor.invokeCommand("Toggle Read-Only Mode")
end
}
}
}
--
-- Read-only mode implementation
function toggleReadOnlyMode()
local cursor = editor.getCursor()
local mode = editor.getUiOption('forcedROMode')
editor.setUiOption('forcedROMode', not mode)
editor.rebuildEditorState()
editor.reloadConfigAndCommands()
js.window.document.querySelector('.sb-mini-editor .cm-content').contentEditable = mode
if config.get('readOnly').persistent then
clientStore.set('readOnly', not mode)
end
if mode == false and config.get('readOnly').disableCheckboxes then
js.window.document.head.insertAdjacentHTML('beforeend',
'<style id="readonly-checkbox-css">' ..
'.sb-checkbox input[type="checkbox"] { pointer-events: none; cursor: default; opacity: 0.5; }' ..
'</style>'
)
else
checkbox_css = js.window.document.getElementById('readonly-checkbox-css')
if checkbox_css ~= nil then
checkbox_css.remove()
end
end
editor.moveCursor(cursor, true)
end
command.define {
name = 'Toggle Read-Only Mode',
key = config.get('readOnly').shortcut,
run = function()
toggleReadOnlyMode()
end
}
event.listen {
name = 'system:ready',
run = function(e)
if config.get('readOnly').persistent
then
local readOnlyConfig = clientStore.get('readOnly')
local readOnlyCurrent = editor.getUiOption('forcedROMode')
if readOnlyConfig and not readOnlyCurrent then
toggleReadOnlyMode()
end
end
end
}