@prefix sioc: <http://rdfs.org/sioc/ns#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix content: <http://purl.org/rss/1.0/modules/content/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<https://lhero.org/?post_type=lh-portfolio-doc&#038;p=152398>
  a sioc:Post ;
  dc:title "Development" ;
  dcterms:identifier 152398 ;
  dc:modified "2026-10-25T02:45:19Z"^^xsd:dateTime ;
  dc:created "2026-10-25T01:48:58Z"^^xsd:dateTime ;
  sioc:link <https://lhero.org/portfolio/lh-spreadsheets/development/> ;
  sioc:has_creator <https://lhero.org/author/1/#account> ;
  sioc:has_container <https://lhero.org/#posts> ;
  content:encoded "<ul class=\"lh_portfolio-meta\"><li><strong>Part of:</strong> <a href=\"https://lhero.org/portfolio/lh-spreadsheets/\">LH Spreadsheets</a></li></ul><h2 class=\"wp-block-heading\">Saving edits</h2><ul class=\"wp-block-list\"><li>The host listens to Univer&#8217;s <code>CommandExecuted</code> event and reacts only to mutations of this workbook: <code>type</code> is <code>MUTATION</code>, the mutation is not <code>onlyLocal</code> (formula calculation), and <code>params.unitId</code> is the workbook&#8217;s id. The cell editor is a separate internal Univer document that mutates on every keystroke; without the unit check the post was marked dirty as soon as it opened.</li><li>Changes are debounced (400 ms), then the edit component compares the snapshot&#8217;s JSON with the last one it saw and only then calls <code>setAttributes( { workbook } )</code>. WordPress&#8217;s own Save, autosave and revisions take it from there.</li><li>When the attribute changes from outside the grid (editor undo, a restored revision, a collaborator&#8217;s save) the grid reloads from it.</li></ul><h2 class=\"wp-block-heading\">Collaboration</h2><p class=\"wp-block-paragraph\">The block editor&#8217;s real-time collaboration syncs the whole workbook as one attribute, so two people editing different cells at the same moment overwrite each other: the last change wins for the whole workbook. Presence, title, status and terms sync normally. Cell-level co-editing needs Univer&#8217;s mutations mapped onto the editor&#8217;s Yjs document (planned).</p><h2 class=\"wp-block-heading\">REST API</h2><p class=\"wp-block-paragraph\">Namespace <code>lh/v1</code>, base <code>spreadsheets</code> (filters <code>lh_spreadsheets_rest_return_namespace</code>, <code>lh_spreadsheets_rest_return_rest_base</code>). <code>GET</code> lists up to 50 (own only without <code>edit_others_posts</code>), <code>POST</code> creates, and <code>GET</code>, <code>PUT</code> and <code>DELETE</code> on <code>/{id}</code> read, patch and delete. Writes take <code>title</code>, <code>description</code>, <code>status</code> and <code>workbook</code> (an object); the API wraps the workbook in the block itself. Publishing without <code>publish_posts</code> is demoted to <code>pending</code>. Core&#8217;s <code>wp/v2/spreadsheets</code> route also exists, returning the raw block markup.</p><h2 class=\"wp-block-heading\">Building</h2><p class=\"wp-block-paragraph\">Source is in <code>src/</code>; <code>build/</code> is generated with <code>npm install</code> then <code>npm run build</code> and deployed as is (nothing is built on the server). <code>webpack.config.js</code> runs two builds: the block with WordPress packages as externals, and the Univer host with everything bundled. Univer is pinned to an exact version in <code>package.json</code>; upgrade it deliberately and retest, since its API has moved between releases.</p><h2 class=\"wp-block-heading\">Roadmap</h2><ul class=\"wp-block-list\"><li>Cell-level collaboration over the block editor&#8217;s Yjs transport.</li><li>A Grist-compatible API adapter.</li></ul>"^^rdf:XMLLiteral ;
  sioc:content "Part of: LH SpreadsheetsSaving editsThe host listens to Univer&#8217;s CommandExecuted event and reacts only to mutations of this workbook: type is MUTATION, the mutation is not onlyLocal (formula calculation), and params.unitId is the workbook&#8217;s id. The cell editor is a separate internal Univer document that mutates on every keystroke; without the unit check the post was marked dirty as soon as it opened.Changes are debounced (400 ms), then the edit component compares the snapshot&#8217;s JSON with the last one it saw and only then calls setAttributes( { workbook } ). WordPress&#8217;s own Save, autosave and revisions take it from there.When the attribute changes from outside the grid (editor undo, a restored revision, a collaborator&#8217;s save) the grid reloads from it.CollaborationThe block editor&#8217;s real-time collaboration syncs the whole workbook as one attribute, so two people editing different cells at the same moment overwrite each other: the last change wins for the whole workbook. Presence, title, status and terms sync normally. Cell-level co-editing needs Univer&#8217;s mutations mapped onto the editor&#8217;s Yjs document (planned).REST APINamespace lh/v1, base spreadsheets (filters lh_spreadsheets_rest_return_namespace, lh_spreadsheets_rest_return_rest_base). GET lists up to 50 (own only without edit_others_posts), POST creates, and GET, PUT and DELETE on /{id} read, patch and delete. Writes take title, description, status and workbook (an object); the API wraps the workbook in the block itself. Publishing without publish_posts is demoted to pending. Core&#8217;s wp/v2/spreadsheets route also exists, returning the raw block markup.BuildingSource is in src/; build/ is generated with npm install then npm run build and deployed as is (nothing is built on the server). webpack.config.js runs two builds: the block with WordPress packages as externals, and the Univer host with everything bundled. Univer is pinned to an exact version in package.json; upgrade it deliberately and retest, since its API has moved between releases.RoadmapCell-level collaboration over the block editor&#8217;s Yjs transport.A Grist-compatible API adapter." ;
  sioc:topic <https://lhero.org/?taxonomy=author&term=cap-1> .

<https://lhero.org/author/1/#account> rdfs:seeAlso <https://lhero.org/author/1/?feed=lhrdf&format=turtle> .
<https://lhero.org/?taxonomy=author&term=cap-1> rdfs:seeAlso <https://lhero.org/?taxonomy=author&term=cap-1&feed=lhrdf&format=turtle> .
