{"id":18447093,"url":"https://github.com/zot/domdom","last_synced_at":"2025-04-15T02:45:59.216Z","repository":{"id":66781224,"uuid":"207201060","full_name":"zot/domdom","owner":"zot","description":"A simple, dynamic HTML presentation system that supports local or client/server usage","archived":false,"fork":false,"pushed_at":"2019-11-16T08:53:28.000Z","size":209,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-15T02:45:55.889Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-09T01:44:25.000Z","updated_at":"2019-11-16T08:53:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"08897ccf-10f9-4a42-b5d3-5b07ca42eb8e","html_url":"https://github.com/zot/domdom","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zot%2Fdomdom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zot%2Fdomdom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zot%2Fdomdom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zot%2Fdomdom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zot","download_url":"https://codeload.github.com/zot/domdom/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248997087,"owners_count":21195797,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T07:11:55.208Z","updated_at":"2025-04-15T02:45:59.199Z","avatar_url":"https://github.com/zot.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Domdom: a simple, dynamic HTML presentation system that supports local or client/server usage\n\nCopyright (C) 2019, by Bill Burdick, ZLIB licensed, https://github.com/zot/domdom\n\nDomdom uses a JSON object to implement its own Document Object Model that you can share with your local JavaScipt code or with a server. Domdom renders the JSON object in the browser using definitions you provide and it re-renders parts of the GUI when you change values in the JSON object. You can manage the model either in local JavaScript or on a server. Domdom also binds parts of the JSON object and changes it when users interact with the GUI, transmitting those changes to the local JavaScript code or to the server.\n\nDomdom is engineered to be simple and lightweight, defined in roughly 600 lines of CoffeeScript.\n\n# Overview\n\nDomdom chooses a \"view\" for each nested object in the JSON object you provide by using the object's \"type\" property. Views are defined using Handlebars, displaying with the JSON object as their context. Domdom also supports namespaces for views, i.e. you can define different views on the same type for different contexts (an object could render as a form in one namespace and a list item in another namespace).\n\nWhen the Javascript model (or server, if connected) changes some of Domdom's JSON objects, it automatically rerenders the views for those objects.\n\nDomdom can bind values in its HTML views to paths in its JSON objects so that the HTML can display and/or change the values at thoses paths. When the user changes one of those values, Domdom changes the JSON object at that path and sends an event to the Javascript model (or the server, if connected).\n\n# Views\n\nViews are Handlebars templates that can also contain other views via the `view` Handlebar plugin and `data-path` attributes in divs and spans which each specify a *path* to property in a JSON object.\n\nInput elements in views can also contain `data-path` attributes that specifying a\n*path* to a property in the JSON object, example:\n\n`\u003cinput type=text data-path=\"a.b.c\"\u003e`\n\nIf an element has a non-null data-bind-keypress attribute, any keypresses that are not enter or return will be sent as \"key\" events to the Javascript model (or server, if connected).\n\nAn element is considered to be a button if it has a data-path property and it is either a non-input element, a button element, or a submit element. The behavior on the JSON object depends on its \"value\" attribute (if there is one):\n\n* no value attribute: when you press the button, Domdom does not change the JSON object but it sends a click event to the model (see Events, below)\n* the value is a boolean: it acts as a checkbox and when you press it, Domdom sets the boolean value in the JSON object and sends a \"set\" event (see Events, below)\n* otherwise: when the input element changes (like by focusing out of a field), Domdom sets the JSON path in the object to the value property, parsed as a JSON value (see Events, below)\n\n# Main JSON object\n\nviews: {NAMESPACE: {TYPE: HANDLEBARSDEF}, ...}\ntype: top\ncontent: [DATA, ...]\n\nThe main JSON object supplied to Domdom can optionally provide\n\n# Events\nThe Javascript model (or the server, if you are connecting to one) recieves events for clicks and sets with the JSON path and the new value, if there is one. The model (or server) can then change the JSON model in response to trigger an update on the screen, which re-renders the parts of the model that have changed.\n\n# Viewdefs\n\nYou define views with viewdefs and this is normally in the HTML file by putting `data-viewdef` attributes in HTML elements. the value of the `data-viewdef` element can be:\n\n- `TYPE`, where TYPE is any string value a JSON object might have in its `type` property\n- `NAMESPACE/TYPE`, where namespace is any name you choose to make a namespace and TYPE is as above\n\nYou can use a namespace with the `view` Handlebars plugin (see below).\n\nYou can also define viewdefs in the `views` property of the main JSON object.\n\nWithin a viewdef, you can template attributes in two ways see (example-server.html)[../example-server.html]'s account viewdef:\n\n1. enclose the entire contents of the viewdef in an HTML comment\n2. place all of the attribute templating into a data-subst attribute\n\n# The namespace type\nThe namespace type sets the namespace for its content object or array of objects, like this:\n\n{\"type\": \"namespace\", \"namespace\": \"bubba\", \"content\": ...}\n\nThis will set the namespace to bubba for the content object or array of objects.\n\n# The view plugin for Handlebars\n\nThe predefined `view` plugin lets you show a view on an object or array of objects and you can optionally set the namespace, like this:\n\n{{{view `path.in.JSON.object`}}}\n\nor\n\n{{{view `path.in.JSON.object` `namespace-name`}}}\n\n# Events\nThere are two types of events:\n\n- set(path, value): the user changed something in the GUI that triggered a set event\n- click(path, value): the user clicked a button, which can optionally include a value, depending on the view\n\n# Controllers\nIf you need custom javascript code, you can use a script element. You an use `element.query()`, `element.queryAll()`, `element.closest()`, etc. to access your view. In addition, these properties will be available:\n\n- `document.currentScript` will be the script element (as usual)\n- `Domdom.currentScript` will also hold the script element\n- `Domdom.activating` will be true, check this to verify that a view is actually initializing\n- `Domdom.context` will be the current context object\n- `Domdom.docPath` will be the current docPath (see DocPaths, below)\n\nAlso, each view will have a `data-location` attribute set to its path and a `data-namespace` attribute set to the view's namespace.\n\n# Using Domdom\n\nOn the web side, you need to make sure the files in the js and css directories are available to your HTML file and include these elements (altered to fit your file layout, of course):\n\n\\\u003clink rel=\"stylesheet\" href=\"css/domdom.css\"\u003e\\\u003c/link\u003e\n\\\u003cscript src=\"js/lib/handlebars-v4.0.5.js\"\u003e\\\u003c/script\u003e\n\\\u003cscript src=\"js/domdom.js\"\u003e\\\u003c/script\u003e\n\nIt's also compatible with AMD style so you can use something like require.js:\n\n\\\u003clink rel=\"stylesheet\" href=\"css/domdom.css\"\u003e\\\u003c/link\u003e\n\\\u003cscript data-main=\"js/config\" src=\"js/lib/require-2.1.18.js\"\u003e\\\u003c/script\u003e\n\nYou can implement the model in local JavaScript or in a server. Domdom currently supports Julia servers.\n\n# Connecting to a server\nPut this at the bottom of the body of your web page, with the HOST and PORT of your server in it:\n\n\\\u003cscript\u003eDomdom.connect({}, \"ws://HOST:PORT\")\\\u003c/script\u003e\n\nThe Julia server code supports its own version of event handlers and DocPath (see the JavaScript model documentation below)\n\n# Using Domdom with a JavaScript model\n\n* Create a Javascript object with\n```\n{type: 'document',\n views: {default: {viewdefs...},\n NAMESPACE1: {viewdefs...}},\n contents: [CONTENTS...]}\n```\n\nViews are optional in the object since they can also be in the HTML page.\n\n- Create a context with {top: JSON, handler: HANDLER}\n  - JSON is the JSON object you have created\n  - HANDLER is an event handler\n    - You can use the patternHandler() function to easily specify event handlers (see source for documentation).\n    - Otherwise, the handler is {clickButton: (evt)=\u003e ..., changedValue: (evt)=\u003e ..., key: (evt)=\u003e ...}\n    - the dispatchClick, dispatchKey, and dispatchSet functions dispatch events in a high-level way, using DocPaths (see below)\n## DocPaths\nA DocPath is proxy that makes it easy navigate paths in the JSON object and it lets you change the JSON object and automatically trigger re-rendering for those changes. It's called DocPath because the JSON object is the \"document\" of the Document Object Model. PatternHandler and the three dispatch functions (dispatchClick, dispatchKey, and dispatchSet) each send a DocPath as the first argument to your provided event handler function.\n\nGiven docp is a DocPath...\n\n- `docp.PROP` returns the value in the document at PROP if it is atomic or, if the value is an array or object, it returns a new DocPath for that location (with docp's path extended to include PROP)\n- `docp[INDEX]` returns the value in the document at INDEX if it is atomic or, if the value is an array or object, it returns a new DocPath for that location (with docp's path extended to include INDEX)\n- `docPathValue(docp)` returns docp's value\n- `docp.PROP = VALUE` sets the value in the document and cause Domdom to re-render it\n- `docPathParts(docp)` returns the \"parts\" of a DocPath, the Domdom object, the context, and the path array\n\nYou can use `batch(con, func)` if you need to change DocPaths outside of an event handler for \"event compression\". Batch eliminates re-rendering of the same object multiple times.\n\n# History\n\nI came up with the original concept around 2000 or 2001, as the next step in evolution for Classic Blend (a remote presentation system I first developed in 1995). The idea of the next step was that if you abstracted an entire GUI into a set of shared variables, you could use the variables to control a remote GUI from a server kind of like a [tuple space](https://en.wikipedia.org/wiki/Tuple_space) or like [SNMP](https://en.wikipedia.org/wiki/Simple_Network_Management_Protocol). Beyond this, you could reskin the GUI in dramatically different ways -- far more radically than GTK themes, for instance -- switching from a web browser to the Unreal engine, for example, where menus might be presented as shops (I actually prototyped a Quake-based front end at one point).\n\nI've been using an earlier and quite different variation of this idea since 2006 on an extremely large project. The browser side of the presentation is fully automatic now and we don't write any JavaScript for our front ends anymore, unless we're adding new kinds of widgets.\n\nThis version of the concept, Domdom, grew out of the Leisure project (which will eventually be updated to use Domdom) and I've used variations of this JavaScript and server code in several of my personal projects.\n\nThe [Xus](https://github.com/zot/Xus) project is also related to this and it's also based on shared variables.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzot%2Fdomdom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzot%2Fdomdom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzot%2Fdomdom/lists"}