Togglable and configurable read-only mode

One of the first things I noticed with Silverbullet is that I was not that happy with the mobile experience. In default (non-readonly) mode, every tap pops up the on-screen keyboard, blocking half the screen, even when you are tapping links.

Searching the forums, I ran across this thread from June, which gave me the solution. I extended this somewhat and I think it is useful enough to post it here as well instead of just the Ideas category.

This Space Lua code block will add a “Toggle Read-Only Mode” command, and add it to the actionButtons as well. You can also have the button only show up on mobile, which was my main motivation.

I extended it so that it optionally also disables TODO checkboxes, as someone in the old thread complained about tapping them by accident sometimes. I think it’s cool to leave them enabled while going through a shopping list in the store.

I also made it optionally persistent, so that it saves the state and reenables read-only mode if it was enabled before. This way, my phone’s Silverbullet can stay mostly on read-only and desktop on editable.

Here’s the script:

-- 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
}
9 Likes

This currently hides the action button on mobile, which is not what I expected from the mobile key of actionButtons. This might have to be removed from actionButtons in order to have it show on both desktop and mobile.

Great! I was using something similar, and I added your line where you disable editing of the page name.

Would it be possible to also stop the editor to show the markdown syntax while in read-only?

Blockquote Would it be possible to also stop the editor to show the markdown syntax while in read-only?

Do you mean as in the recently added “Toggle Markdown Syntax Rendering” command? That would work.