.. _javascript_plugins: JavaScript plugins ================== Datasette can run custom JavaScript in several different ways: - Datasette plugins written in Python can use the :ref:`extra_js_urls() ` or :ref:`extra_body_script() ` plugin hooks to inject JavaScript into a page - Datasette instances with :ref:`custom templates ` can include additional JavaScript in those templates - The ``extra_js_urls`` key in ``datasette.yaml`` :ref:`can be used to include extra JavaScript ` There are no limitations on what this JavaScript can do. It is executed directly by the browser, so it can manipulate the DOM, fetch additional data and do anything else that JavaScript is capable of. .. warning:: Custom JavaScript has security implications, especially for authenticated Datasette instances where the JavaScript might run in the context of the authenticated user. It's important to carefully review any JavaScript you run in your Datasette instance. .. _javascript_datasette_init: The datasette_init event ------------------------ Datasette emits a custom event called ``datasette_init`` when the page is loaded. This event is dispatched on the ``document`` object, and includes a ``detail`` object with a reference to the :ref:`datasetteManager ` object. Your JavaScript code can listen out for this event using ``document.addEventListener()`` like this: .. code-block:: javascript document.addEventListener("datasette_init", function (evt) { const manager = evt.detail; console.log("Datasette version:", manager.VERSION); }); .. _javascript_datasette_manager: datasetteManager ---------------- The ``datasetteManager`` object ``VERSION`` - string The version of Datasette ``plugins`` - ``Map()`` A Map of currently loaded plugin names to plugin implementations ``registerPlugin(name, implementation)`` Call this to register a plugin, passing its name and implementation ``makeColumnField(context)`` Calls the ``makeColumnField()`` hook on registered plugins, returning the first custom insert/edit field control that matches the provided field context. This is used internally by Datasette's row insert and edit dialogs. ``createModal(options)`` Creates a :ref:`\ ` element, appends it to the page and returns it. Returns ``null`` in browsers without ```` support. ``selectors`` - object An object providing named aliases to useful CSS selectors, :ref:`listed below ` .. _javascript_plugins_datasette_modal: Modal dialogs: the datasette-modal element ------------------------------------------ Datasette provides a ```` Web Component that renders a modal dialog in the same visual style as Datasette's own dialogs - the create/alter table dialogs, the insert/edit/delete row dialogs, the column chooser, the mobile column actions sheet and the ``/`` jump menu are all built on it. The element, and the ``DatasetteModal`` class exposed as ``window.DatasetteModal``, are a stable public API for plugins. Plugins that need a modal dialog should use this component rather than building their own, so their dialogs automatically match Datasette's styling, keyboard handling and accessibility behavior. The component wraps a native ```` element and provides: - Datasette's standard modal frame: sizing, rounded corners, backdrop, open/close animations and an optional header with a title and a "meta" chip - Close on backdrop click and on the ``Escape`` key - A ``busy`` property that blocks the user from dismissing the dialog while a save or delete is in flight - A ``closeGuard`` hook for "Discard unsaved changes?" style confirmation prompts - Focus restoration to the triggering element when the dialog closes - ``datasette-modal-open`` and ``datasette-modal-close`` events Creating a modal ~~~~~~~~~~~~~~~~ The simplest way to create a modal from a plugin is ``datasetteManager.createModal()`` (or the equivalent ``window.DatasetteModal.create()``), which creates the element, appends it to ``document.body`` and returns it: .. code-block:: javascript document.addEventListener("datasette_init", function (event) { const manager = event.detail; const modal = manager.createModal({ id: "my-plugin-dialog", className: "my-plugin-dialog", title: "My plugin", content: `

Hello from a plugin!

`, }); if (!modal) { return; // Browser does not support } modal.dialog .querySelector(".my-plugin-cancel") .addEventListener("click", () => modal.requestClose("cancel")); // Open it later, for example from a button click: // modal.showModal({trigger: button}); }); Calling ``modal.showModal()`` then displays the dialog: .. image:: datasette-modal-example.png :alt: A modal dialog titled "My plugin" containing the text "Hello from a plugin!" and Cancel and Save buttons, shown over a dimmed and blurred Datasette table page. :width: 550px ``createModal(options)`` / ``DatasetteModal.create(options)`` accepts: ``id`` - string, optional ``id`` attribute for the inner ```` element. ``className`` - string, optional ``class`` attribute for the inner ````, useful for scoping custom CSS. ``title`` - string, optional Text for the standard header title. If omitted no header is created and the modal content fills the whole dialog. ``meta`` - string, optional Text for the small "meta" chip shown on the right of the header, for example ``"3 of 12 selected"``. ``titleId`` - string, optional ``id`` for the generated title element. Defaults to ``"-title"``. ``labelledBy`` / ``describedBy`` - strings, optional Explicit ``aria-labelledby`` / ``aria-describedby`` values for the dialog. By default the dialog is labelled by the generated title element. ``content`` - string or DOM node, optional Content placed inside the dialog, after the header. By convention this ends with a ``