├── .gitignore ├── LICENSE ├── README.md ├── _config.yml ├── dist └── observable-press.js ├── examples ├── aai │ ├── index.html │ ├── observable-press.js │ └── style.css ├── pantry │ ├── index.html │ ├── observable-press.js │ └── style.css ├── simple-ui │ ├── index.html │ ├── observable-press.js │ └── style.css ├── simple │ ├── index.html │ ├── observable-press.js │ └── style.css └── todo │ ├── index.html │ ├── observable-press.js │ └── style.css ├── package-lock.json ├── package.json ├── src ├── index.js ├── initialize.js ├── library.js ├── style.css └── util.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Zev Youra 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # observable-press 2 | An opinionated way to publish [Observable notebooks](//observablehq.com). 3 | 4 | The core idea is to do all your coding in your notebook, write an HTML skeleton for its presentation, and let `observable-press` glue it all together. 5 | 6 | The [Observable Runtime](https://github.com/observablehq/runtime) makes this pretty easy to do with no library, but `observable-press` adds a consistent pattern that allows you to write zero code outside your notebook, and also adds some small conveniences (initial loading indicator, new `height` builtin). 7 | 8 | ### Simplest Example 9 | 10 | [code](examples/simple/index.html) // [demo](https://zzzev.github.io/observable-press/examples/simple) // [source notebook](//observablehq.com/@zzzev/slit-scan-effect) 11 | 12 | A very simple example looks like this: 13 | ``` 14 | 15 | 16 | 17 | 18 | 19 | ``` 20 | 21 | First, we include some simple default styles. These are optional, though you will need some similar styles if you want to have full-window rendering with no margins. 22 | 23 | Then, we include the `observable-press` library in a script tag. The `data-notebook` attribute on this tag is used to specify the notebook that should be loaded. 24 | 25 | `data-override-height` is an optional attribute, if present it will delete the named variable `height` from the notebook (which causes it to instead use the builtin provided by `observable-press` which matches window height). 26 | 27 | Because there are no HTML nodes in the document with `data-cell` set, the library picks the first "content-like" variable in the notebook and renders it into the body. 28 | 29 | ### Using `data-cell`s and `.loading` 30 | 31 | [code](examples/simple-ui/index.html) // [demo](https://zzzev.github.io/observable-press/examples/simple-ui) // [source notebook](//observablehq.com/@zzzev/reversable-zoom) 32 | 33 | A slightly more complex example has an HTML body like this: 34 | ``` 35 |
36 |
37 |
loading...
38 | ``` 39 | 40 | This includes two tags with `data-cell` attributes, which will be populated by the matching named variables from the notebook. Since there's at least one explicitly specified `data-cell`, it won't pick one automatically. Note that `viewof` must be included in the cell name if you want to render the view of a variable. 41 | 42 | This also includes a tag with the class `loading`, which will be automatically removed once the specified `data-cell`s have all rendered at least once. This makes it easy to include a simple loading indicator. 43 | 44 | ### Other Examples 45 | #### Pantry Nutrition Explorer 46 | [code](examples/pantry/index.html) // [demo](https://zzzev.github.io/observable-press/examples/pantry) // [source notebook](//observablehq.com/@zzzev/pantry-nutrition-explorer) 47 | 48 | #### TODO List 49 | [code](examples/todo/index.html) // [demo](https://zzzev.github.io/observable-press/examples/todo) // [source notebook](//observablehq.com/@zzzev/todopress) 50 | 51 | Based on [TodoMVC](//todomvc.com). 52 | 53 | #### Animated Average Images 54 | [code](examples/aai/index.html) // [demo](https://zzzev.github.io/observable-press/examples/aai) // [source notebook](//observablehq.com/@zzzev/animated-average-images-ii) 55 | 56 | Note: the animation in this notebook is somewhat choppy. 57 | 58 | ## Troubleshooting 59 | If your notebook has special CORS access rules set up, it probably won't work if rehosted on a different domain. 60 | 61 | ## TODOs 62 | - Nicer default loading indicator 63 | - Better pending/error indication 64 | 65 | ## Licensing 66 | `observable-press` is MIT licensed 67 | 68 | Notebooks published on Observable without an explicit license are licensed under [the terms described here](https://observablehq.com/terms-of-service), and cannot be freely re-used on a different site unless you are the original author or have permission. 69 | 70 | This project is not affiliated or endorsed by Observable, Inc. 71 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /dist/observable-press.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.observablePress=t():e.observablePress=t()}(window,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=15)}([function(e,t,n){"use strict";n.d(t,"c",(function(){return l})),n.d(t,"b",(function(){return u})),n.d(t,"a",(function(){return c})),n.d(t,"e",(function(){return d})),n.d(t,"d",(function(){return h}));var r=n(7),i=n(5),o=n(1),s=n(6),a=n(2),l=1,u=2,c=3,d={};function h(e,t,n){var r;null==n&&(n=d),Object.defineProperties(this,{_observer:{value:n,writable:!0},_definition:{value:m,writable:!0},_duplicate:{value:void 0,writable:!0},_duplicates:{value:void 0,writable:!0},_indegree:{value:NaN,writable:!0},_inputs:{value:[],writable:!0},_invalidate:{value:a.a,writable:!0},_module:{value:t},_name:{value:null,writable:!0},_outputs:{value:new Set,writable:!0},_promise:{value:Promise.resolve(void 0),writable:!0},_reachable:{value:n!==d,writable:!0},_rejector:{value:(r=this,function(e){if(e===m)throw new o.a(r._name+" is not defined",r._name);throw new o.a(r._name+" could not be resolved",r._name)})},_type:{value:e},_value:{value:void 0,writable:!0},_version:{value:0,writable:!0}})}function f(e){e._module._runtime._dirty.add(e),e._outputs.add(this)}function p(e){e._module._runtime._dirty.add(e),e._outputs.delete(this)}function m(){throw m}function g(e){return function(){throw new o.a(e+" is defined more than once")}}function b(e,t,n){var r=this._module._scope,i=this._module._runtime;if(this._inputs.forEach(p,this),t.forEach(f,this),this._inputs=t,this._definition=n,this._value=void 0,n===a.a?i._variables.delete(this):i._variables.add(this),e==this._name&&r.get(e)===this)this._outputs.forEach(i._updates.add,i._updates);else{var o,s;if(this._name)if(this._outputs.size)r.delete(this._name),(s=this._module._resolve(this._name))._outputs=this._outputs,this._outputs=new Set,s._outputs.forEach((function(e){e._inputs[e._inputs.indexOf(this)]=s}),this),s._outputs.forEach(i._updates.add,i._updates),i._dirty.add(s).add(this),r.set(this._name,s);else if((s=r.get(this._name))===this)r.delete(this._name);else{if(s._type!==c)throw new Error;s._duplicates.delete(this),this._duplicate=void 0,1===s._duplicates.size&&(s=s._duplicates.keys().next().value,o=r.get(this._name),s._outputs=o._outputs,o._outputs=new Set,s._outputs.forEach((function(e){e._inputs[e._inputs.indexOf(o)]=s})),s._definition=s._duplicate,s._duplicate=void 0,i._dirty.add(o).add(s),i._updates.add(s),r.set(this._name,s))}if(this._outputs.size)throw new Error;e&&((s=r.get(e))?s._type===c?(this._definition=g(e),this._duplicate=n,s._duplicates.add(this)):s._type===u?(this._outputs=s._outputs,s._outputs=new Set,this._outputs.forEach((function(e){e._inputs[e._inputs.indexOf(s)]=this}),this),i._dirty.add(s).add(this),r.set(e,this)):(s._duplicate=s._definition,this._duplicate=n,(o=new h(c,this._module))._name=e,o._definition=this._definition=s._definition=g(e),o._outputs=s._outputs,s._outputs=new Set,o._outputs.forEach((function(e){e._inputs[e._inputs.indexOf(s)]=o})),o._duplicates=new Set([this,s]),i._dirty.add(s).add(o),i._updates.add(s).add(o),r.set(e,o)):r.set(e,this)),this._name=e}return i._updates.add(this),i._compute(),this}Object.defineProperties(h.prototype,{_pending:{value:function(){this._observer.pending&&this._observer.pending()},writable:!0,configurable:!0},_fulfilled:{value:function(e){this._observer.fulfilled&&this._observer.fulfilled(e,this._name)},writable:!0,configurable:!0},_rejected:{value:function(e){this._observer.rejected&&this._observer.rejected(e,this._name)},writable:!0,configurable:!0},define:{value:function(e,t,n){switch(arguments.length){case 1:n=e,e=t=null;break;case 2:n=t,"string"==typeof e?t=null:(t=e,e=null)}return b.call(this,null==e?null:e+"",null==t?[]:r.b.call(t,this._module._resolve,this._module),"function"==typeof n?n:Object(i.a)(n))},writable:!0,configurable:!0},delete:{value:function(){return b.call(this,null,[],a.a)},writable:!0,configurable:!0},import:{value:function(e,t,n){arguments.length<3&&(n=t,t=e);return b.call(this,t+"",[n._resolve(e+"")],s.a)},writable:!0,configurable:!0}})},function(e,t,n){"use strict";function r(e,t){this.message=e+"",this.input=t}n.d(t,"a",(function(){return r})),r.prototype=Object.create(Error.prototype),r.prototype.name="RuntimeError",r.prototype.constructor=r},function(e,t,n){"use strict";t.a=function(){}},function(e,t,n){"use strict";(function(e){n.d(t,"b",(function(){return d})),n.d(t,"c",(function(){return h})),n.d(t,"a",(function(){return f}));var r=n(4),i=n(1),o=n(10),s=n(11),a=n(8),l=n(2),u=n(0);const c="function"==typeof requestAnimationFrame?requestAnimationFrame:e;var d={},h={};function f(e=new r.b,t=k){var n=this.module();if(Object.defineProperties(this,{_dirty:{value:new Set},_updates:{value:new Set},_computing:{value:null,writable:!0},_init:{value:null,writable:!0},_modules:{value:new Map},_variables:{value:new Set},_disposed:{value:!1,writable:!0},_builtin:{value:n},_global:{value:t}}),e)for(var i in e)new u.d(u.b,n).define(i,[],e[i])}function p(e){const t=new Set(e._inputs);for(const n of t){if(n===e)return!0;n._inputs.forEach(t.add,t)}return!1}function m(e){++e._indegree}function g(e){--e._indegree}function b(e){return e._promise.catch(e._rejector)}function v(e){return new Promise((function(t){e._invalidate=t}))}function _(e,t){let n,r,i="function"==typeof IntersectionObserver&&t._observer&&t._observer._node,o=!i,s=l.a,a=l.a;return i&&((r=new IntersectionObserver(([e])=>(o=e.isIntersecting)&&(n=null,s()))).observe(i),e.then(()=>(r.disconnect(),r=null,a()))),function(e){return o?Promise.resolve(e):r?(n||(n=new Promise((e,t)=>(s=e,a=t))),n.then(()=>e)):Promise.reject()}}function y(e){e._invalidate(),e._invalidate=l.a,e._pending();var t=e._value,n=++e._version,r=null,i=e._promise=Promise.all(e._inputs.map(b)).then((function(i){if(e._version===n){for(var o=0,s=i.length;ot._reachable?this._updates.add(t):n{e._invalidate(),e._version=NaN})},writable:!0,configurable:!0},module:{value:function(e,t=l.a){let n;if(void 0===e)return(n=this._init)?(this._init=null,n):new a.a(this);if(n=this._modules.get(e))return n;this._init=n=new a.a(this),this._modules.set(e,n);try{e(this,t)}finally{this._init=null}return n},writable:!0,configurable:!0},fileAttachments:{value:r.a,writable:!0,configurable:!0}})}).call(this,n(12).setImmediate)},function(e,t,n){"use strict";async function r(e){const t=await fetch(await e.url());if(!t.ok)throw new Error(`Unable to load file: ${e.name}`);return t}class i{constructor(e,t){Object.defineProperties(this,{_url:{value:e},name:{value:t,enumerable:!0}})}async url(){return this._url}async blob(){return(await r(this)).blob()}async arrayBuffer(){return(await r(this)).arrayBuffer()}async text(){return(await r(this)).text()}async json(){return(await r(this)).json()}async stream(){return(await r(this)).body}async image(){const e=await this.url();return new Promise((t,n)=>{const r=new Image;new URL(e,document.baseURI).origin!==new URL(location).origin&&(r.crossOrigin="anonymous"),r.onload=()=>t(r),r.onerror=()=>n(new Error(`Unable to load file: ${this.name}`)),r.src=e})}}function o(e){throw new Error(`File not found: ${e}`)}function s(e){return t=>{const n=e(t+="");if(null==n)throw new Error(`File not found: ${t}`);return new i(n,t)}}var a=function(e){return function(){return e}},l={math:"http://www.w3.org/1998/Math/MathML",svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},u=0;function c(e){this.id=e,this.href=new URL(`#${e}`,location)+""}c.prototype.toString=function(){return"url("+this.href+")"};var d={canvas:function(e,t){var n=document.createElement("canvas");return n.width=e,n.height=t,n},context2d:function(e,t,n){null==n&&(n=devicePixelRatio);var r=document.createElement("canvas");r.width=e*n,r.height=t*n,r.style.width=e+"px";var i=r.getContext("2d");return i.scale(n,n),i},download:function(e,t="untitled",n="Save"){const r=document.createElement("a"),i=r.appendChild(document.createElement("button"));async function o(){await new Promise(requestAnimationFrame),URL.revokeObjectURL(r.href),r.removeAttribute("href"),i.textContent=n,i.disabled=!1}return i.textContent=n,r.download=t,r.onclick=async t=>{if(i.disabled=!0,r.href)return o();i.textContent="Saving…";try{const t=await("function"==typeof e?e():e);i.textContent="Download",r.href=URL.createObjectURL(t)}catch(e){i.textContent=n}if(t.eventPhase)return o();i.disabled=!1},r},element:function(e,t){var n,r=e+="",i=r.indexOf(":");i>=0&&"xmlns"!==(r=e.slice(0,i))&&(e=e.slice(i+1));var o=l.hasOwnProperty(r)?document.createElementNS(l[r],e):document.createElement(e);if(t)for(var s in t)i=(r=s).indexOf(":"),n=t[s],i>=0&&"xmlns"!==(r=s.slice(0,i))&&(s=s.slice(i+1)),l.hasOwnProperty(r)?o.setAttributeNS(l[r],s,n):o.setAttribute(s,n);return o},input:function(e){var t=document.createElement("input");return null!=e&&(t.type=e),t},range:function(e,t,n){1===arguments.length&&(t=e,e=null);var r=document.createElement("input");return r.min=e=null==e?0:+e,r.max=t=null==t?1:+t,r.step=null==n?"any":n=+n,r.type="range",r},select:function(e){var t=document.createElement("select");return Array.prototype.forEach.call(e,(function(e){var n=document.createElement("option");n.value=n.textContent=e,t.appendChild(n)})),t},svg:function(e,t){var n=document.createElementNS("http://www.w3.org/2000/svg","svg");return n.setAttribute("viewBox",[0,0,e,t]),n.setAttribute("width",e),n.setAttribute("height",t),n},text:function(e){return document.createTextNode(e)},uid:function(e){return new c("O-"+(null==e?"":e+"-")+ ++u)}},h={buffer:function(e){return new Promise((function(t,n){var r=new FileReader;r.onload=function(){t(r.result)},r.onerror=n,r.readAsArrayBuffer(e)}))},text:function(e){return new Promise((function(t,n){var r=new FileReader;r.onload=function(){t(r.result)},r.onerror=n,r.readAsText(e)}))},url:function(e){return new Promise((function(t,n){var r=new FileReader;r.onload=function(){t(r.result)},r.onerror=n,r.readAsDataURL(e)}))}};function f(){return this}function p(e,t){let n=!1;return{[Symbol.iterator]:f,next:()=>n?{done:!0}:(n=!0,{done:!1,value:e}),return:()=>(n=!0,t(e),{done:!0}),throw:()=>({done:n=!0})}}var m=function(e){let t,n,r=!1;const i=e((function(e){n?(n(e),n=null):r=!0;return t=e}));return{[Symbol.iterator]:f,throw:()=>({done:!0}),return:()=>(null!=i&&i(),{done:!0}),next:function(){return{done:!1,value:r?(r=!1,Promise.resolve(t)):new Promise(e=>n=e)}}}};function g(e){switch(e.type){case"range":case"number":return e.valueAsNumber;case"date":return e.valueAsDate;case"checkbox":return e.checked;case"file":return e.multiple?e.files:e.files[0];default:return e.value}}var b={disposable:p,filter:function*(e,t){for(var n,r=-1;!(n=e.next()).done;)t(n.value,++r)&&(yield n.value)},input:function(e){return m((function(t){var n=function(e){switch(e.type){case"button":case"submit":case"checkbox":return"click";case"file":return"change";default:return"input"}}(e),r=g(e);function i(){t(g(e))}return e.addEventListener(n,i),void 0!==r&&t(r),function(){e.removeEventListener(n,i)}}))},map:function*(e,t){for(var n,r=-1;!(n=e.next()).done;)yield t(n.value,++r)},observe:m,queue:function(e){let t;const n=[],r=e((function(e){n.push(e),t&&(t(n.shift()),t=null);return e}));return{[Symbol.iterator]:f,throw:()=>({done:!0}),return:()=>(null!=r&&r(),{done:!0}),next:function(){return{done:!1,value:n.length?Promise.resolve(n.shift()):new Promise(e=>t=e)}}}},range:function*(e,t,n){e=+e,t=+t,n=(i=arguments.length)<2?(t=e,e=0,1):i<3?1:+n;for(var r=-1,i=0|Math.max(0,Math.ceil((t-e)/n));++r{n.terminate(),URL.revokeObjectURL(t)})}};function v(e,t){return function(n){var r,i,o,s,a,l,u,c,d=n[0],h=[],f=null,p=-1;for(a=1,l=arguments.length;a0){for(o=new Array(p),s=document.createTreeWalker(f,NodeFilter.SHOW_COMMENT,null,!1);s.nextNode();)i=s.currentNode,/^o:/.test(i.nodeValue)&&(o[+i.nodeValue.slice(2)]=i);for(a=0;a[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:N,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};function w(e){this.tokens=[],this.tokens.links={},this.options=e||P.defaults,this.rules=y.normal,this.options.gfm&&(this.options.tables?this.rules=y.tables:this.rules=y.gfm)}y.bullet=/(?:[*+-]|\d+\.)/,y.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,y.item=$(y.item,"gm")(/bull/g,y.bullet)(),y.list=$(y.list)(/bull/g,y.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+y.def.source+")")(),y.blockquote=$(y.blockquote)("def",y.def)(),y._tag="(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b",y.html=$(y.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,y._tag)(),y.paragraph=$(y.paragraph)("hr",y.hr)("heading",y.heading)("lheading",y.lheading)("blockquote",y.blockquote)("tag","<"+y._tag)("def",y.def)(),y.normal=j({},y),y.gfm=j({},y.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),y.gfm.paragraph=$(y.paragraph)("(?!","(?!"+y.gfm.fences.source.replace("\\1","\\2")+"|"+y.list.source.replace("\\1","\\3")+"|")(),y.tables=j({},y.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/}),w.rules=y,w.lex=function(e,t){return new w(t).lex(e)},w.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},w.prototype.token=function(e,t,n){var r,i,o,s,a,l,u,c,d;for(e=e.replace(/^ +$/gm,"");e;)if((o=this.rules.newline.exec(e))&&(e=e.substring(o[0].length),o[0].length>1&&this.tokens.push({type:"space"})),o=this.rules.code.exec(e))e=e.substring(o[0].length),o=o[0].replace(/^ {4}/gm,""),this.tokens.push({type:"code",text:this.options.pedantic?o:o.replace(/\n+$/,"")});else if(o=this.rules.fences.exec(e))e=e.substring(o[0].length),this.tokens.push({type:"code",lang:o[2],text:o[3]||""});else if(o=this.rules.heading.exec(e))e=e.substring(o[0].length),this.tokens.push({type:"heading",depth:o[1].length,text:o[2]});else if(t&&(o=this.rules.nptable.exec(e))){for(e=e.substring(o[0].length),l={type:"table",header:o[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:o[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:o[3].replace(/\n$/,"").split("\n")},c=0;c ?/gm,""),this.token(o,t,!0),this.tokens.push({type:"blockquote_end"});else if(o=this.rules.list.exec(e)){for(e=e.substring(o[0].length),s=o[2],this.tokens.push({type:"list_start",ordered:s.length>1}),r=!1,d=(o=o[0].match(this.rules.item)).length,c=0;c1&&a.length>1||(e=o.slice(c+1).join("\n")+e,c=d-1)),i=r||/\n\n(?!\s*$)/.test(l),c!==d-1&&(r="\n"===l.charAt(l.length-1),i||(i=r)),this.tokens.push({type:i?"loose_item_start":"list_item_start"}),this.token(l,!1,n),this.tokens.push({type:"list_item_end"});this.tokens.push({type:"list_end"})}else if(o=this.rules.html.exec(e))e=e.substring(o[0].length),this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&("pre"===o[1]||"script"===o[1]||"style"===o[1]),text:o[0]});else if(!n&&t&&(o=this.rules.def.exec(e)))e=e.substring(o[0].length),this.tokens.links[o[1].toLowerCase()]={href:o[2],title:o[3]};else if(t&&(o=this.rules.table.exec(e))){for(e=e.substring(o[0].length),l={type:"table",header:o[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:o[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:o[3].replace(/(?: *\| *)?\n$/,"").split("\n")},c=0;c])/,autolink:/^<([^ <>]+(@|:\/)[^ <>]+)>/,url:N,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^<'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)([\s\S]*?[^`])\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:N,text:/^[\s\S]+?(?=[\\/g,">").replace(/"/g,""").replace(/'/g,"'")}function $(e,t){return e=e.source,t=t||"",function n(r,i){return r?(i=(i=i.source||i).replace(/(^|[^\[])\^/g,"$1"),e=e.replace(r,i),n):new RegExp(e,t)}}function T(e,t){return L[" "+e]||(/^[^:]+:\/*[^/]*$/.test(e)?L[" "+e]=e+"/":L[" "+e]=e.replace(/[^/]*$/,"")),e=L[" "+e],"//"===t.slice(0,2)?e.replace(/:[\s\S]*/,":")+t:"/"===t.charAt(0)?e.replace(/(:\/*[^/]*)[\s\S]*/,"$1")+t:e+t}x._inside=/(?:\[[^\]]*\]|\\[\[\]]|[^\[\]]|\](?=[^\[]*\]))*/,x._href=/\s*?(?:\s+['"]([\s\S]*?)['"])?\s*/,x.link=$(x.link)("inside",x._inside)("href",x._href)(),x.reflink=$(x.reflink)("inside",x._inside)(),x.normal=j({},x),x.pedantic=j({},x.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/}),x.gfm=j({},x.normal,{escape:$(x.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:$(x.text)("]|","~]|")("|","|https?://|")()}),x.breaks=j({},x.gfm,{br:$(x.br)("{2,}","*")(),text:$(x.gfm.text)("{2,}","*")()}),k.rules=x,k.output=function(e,t,n){return new k(t,n).output(e)},k.prototype.output=function(e){for(var t,n,r,i,o="";e;)if(i=this.rules.escape.exec(e))e=e.substring(i[0].length),o+=i[1];else if(i=this.rules.autolink.exec(e))e=e.substring(i[0].length),"@"===i[2]?(n=S(":"===i[1].charAt(6)?this.mangle(i[1].substring(7)):this.mangle(i[1])),r=this.mangle("mailto:")+n):r=n=S(i[1]),o+=this.renderer.link(r,null,n);else if(this.inLink||!(i=this.rules.url.exec(e))){if(i=this.rules.tag.exec(e))!this.inLink&&/^/i.test(i[0])&&(this.inLink=!1),e=e.substring(i[0].length),o+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(i[0]):S(i[0]):i[0];else if(i=this.rules.link.exec(e))e=e.substring(i[0].length),this.inLink=!0,o+=this.outputLink(i,{href:i[2],title:i[3]}),this.inLink=!1;else if((i=this.rules.reflink.exec(e))||(i=this.rules.nolink.exec(e))){if(e=e.substring(i[0].length),t=(i[2]||i[1]).replace(/\s+/g," "),!(t=this.links[t.toLowerCase()])||!t.href){o+=i[0].charAt(0),e=i[0].substring(1)+e;continue}this.inLink=!0,o+=this.outputLink(i,t),this.inLink=!1}else if(i=this.rules.strong.exec(e))e=e.substring(i[0].length),o+=this.renderer.strong(this.output(i[2]||i[1]));else if(i=this.rules.em.exec(e))e=e.substring(i[0].length),o+=this.renderer.em(this.output(i[2]||i[1]));else if(i=this.rules.code.exec(e))e=e.substring(i[0].length),o+=this.renderer.codespan(S(i[2].trim(),!0));else if(i=this.rules.br.exec(e))e=e.substring(i[0].length),o+=this.renderer.br();else if(i=this.rules.del.exec(e))e=e.substring(i[0].length),o+=this.renderer.del(this.output(i[1]));else if(i=this.rules.text.exec(e))e=e.substring(i[0].length),o+=this.renderer.text(S(this.smartypants(i[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else e=e.substring(i[0].length),r=n=S(i[1]),o+=this.renderer.link(r,null,n);return o},k.prototype.outputLink=function(e,t){var n=S(t.href),r=t.title?S(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,S(e[1]))},k.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},k.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,i=0;i.5&&(t="x"+t.toString(16)),n+="&#"+t+";";return n},E.prototype.code=function(e,t,n){if(this.options.highlight){var r=this.options.highlight(e,t);null!=r&&r!==e&&(n=!0,e=r)}return t?'
'+(n?e:S(e,!0))+"\n
\n":"
"+(n?e:S(e,!0))+"\n
"},E.prototype.blockquote=function(e){return"
\n"+e+"
\n"},E.prototype.html=function(e){return e},E.prototype.heading=function(e,t,n){return"'+e+"\n"},E.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"},E.prototype.list=function(e,t){var n=t?"ol":"ul";return"<"+n+">\n"+e+"\n"},E.prototype.listitem=function(e){return"
  • "+e+"
  • \n"},E.prototype.paragraph=function(e){return"

    "+e+"

    \n"},E.prototype.table=function(e,t){return"\n\n"+e+"\n\n"+t+"\n
    \n"},E.prototype.tablerow=function(e){return"\n"+e+"\n"},E.prototype.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' style="text-align:'+t.align+'">':"<"+n+">")+e+"\n"},E.prototype.strong=function(e){return""+e+""},E.prototype.em=function(e){return""+e+""},E.prototype.codespan=function(e){return""+e+""},E.prototype.br=function(){return this.options.xhtml?"
    ":"
    "},E.prototype.del=function(e){return""+e+""},E.prototype.link=function(e,t,n){if(this.options.sanitize){try{var r=decodeURIComponent(function(e){return e.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi,(function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""}))}(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return n}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:")||0===r.indexOf("data:"))return n}this.options.baseUrl&&!q.test(e)&&(e=T(this.options.baseUrl,e));var i='
    "},E.prototype.image=function(e,t,n){this.options.baseUrl&&!q.test(e)&&(e=T(this.options.baseUrl,e));var r=''+n+'":">"},E.prototype.text=function(e){return e},C.parse=function(e,t,n){return new C(t,n).parse(e)},C.prototype.parse=function(e){this.inline=new k(e.links,this.options,this.renderer),this.tokens=e.reverse();for(var t="";this.next();)t+=this.tok();return t},C.prototype.next=function(){return this.token=this.tokens.pop()},C.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},C.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},C.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var e,t,n,r,i="",o="";for(n="",e=0;eAn error occurred:

    "+S(e.message+"",!0)+"
    ";throw e}}N.exec=N,P.options=P.setOptions=function(e){return j(P.defaults,e),P},P.defaults={gfm:!0,tables:!0,breaks:!1,pedantic:!1,sanitize:!1,sanitizer:null,mangle:!0,smartLists:!1,silent:!1,highlight:null,langPrefix:"lang-",smartypants:!1,headerPrefix:"",renderer:new E,xhtml:!1,baseUrl:null},P.Parser=C,P.parser=C.parse,P.Renderer=E,P.Lexer=w,P.lexer=w.lex,P.InlineLexer=k,P.inlineLexer=k.output,P.parse=P;var O=P;const M="https://cdn.jsdelivr.net/npm/@observablehq/highlight.js@2.0.0/";var A=function(e){return function(){return v((function(t){var n=document.createElement("div");n.innerHTML=O(t,{langPrefix:""}).trim();var r=n.querySelectorAll("pre code[class]");return r.length>0&&e(M+"highlight.min.js").then((function(t){r.forEach((function(n){function r(){t.highlightBlock(n),n.parentNode.classList.add("observablehq--md-pre")}t.getLanguage(n.className)?r():e(M+"async-languages/index.js").then(r=>{if(r.has(n.className))return e(M+"async-languages/"+r.get(n.className)).then(e=>{t.registerLanguage(n.className,e)})}).then(r,r)}))})),n}),(function(){return document.createElement("div")}))}};function I(e){let t;Object.defineProperties(this,{generator:{value:m(e=>void(t=e))},value:{get:()=>e,set:n=>t(e=n)}}),void 0!==e&&t(e)}var U=function*(){for(;;)yield Date.now()},R=new Map;function z(e,t){var n;return(n=R.get(e=+e))?n.then(a(t)):(n=Date.now())>=e?Promise.resolve(t):function(e,t){var n=new Promise((function(n){R.delete(t);var r=t-e;if(!(r>0))throw new Error("invalid time");if(r>2147483647)throw new Error("too long to wait");setTimeout(n,r)}));return R.set(t,n),n}(n,e).then(a(t))}var F={delay:function(e,t){return new Promise((function(n){setTimeout((function(){n(t)}),e)}))},tick:function(e,t){return z(Math.ceil((Date.now()+1)/e)*e,t)},when:z};function D(e,t){if(/^(\w+:)|\/\//i.test(e))return e;if(/^[.]{0,2}\//i.test(e))return new URL(e,null==t?location:t).href;if(!e.length||/^[\s._]/.test(e)||/\s$/.test(e))throw new Error("illegal name");return"https://unpkg.com/"+e}const B=new Map,H=[],W=H.map,G=H.some,V=H.hasOwnProperty,J="https://cdn.jsdelivr.net/npm/",K=/^((?:@[^/@]+\/)?[^/@]+)(?:@([^/]+))?(?:\/(.*))?$/,Y=/^\d+\.\d+\.\d+(-[\w-.+]+)?$/,X=/\.[^/]*$/,Q=["unpkg","jsdelivr","browser","main"];class Z extends Error{constructor(e){super(e)}}function ee(e){const t=K.exec(e);return t&&{name:t[1],version:t[2],path:t[3]}}function te(e){const t=`${J}${e.name}${e.version?`@${e.version}`:""}/package.json`;let n=B.get(t);return n||B.set(t,n=fetch(t).then(e=>{if(!e.ok)throw new Z("unable to load package.json");return e.redirected&&!B.has(e.url)&&B.set(e.url,n),e.json()})),n}Z.prototype.name=Z.name;var ne=re((async function(e,t){if(e.startsWith(J)&&(e=e.substring(J.length)),/^(\w+:)|\/\//i.test(e))return e;if(/^[.]{0,2}\//i.test(e))return new URL(e,null==t?location:t).href;if(!e.length||/^[\s._]/.test(e)||/\s$/.test(e))throw new Z("illegal name");const n=ee(e);if(!n)return`${J}${e}`;if(!n.version&&null!=t&&t.startsWith(J)){const e=await te(ee(t.substring(J.length)));n.version=e.dependencies&&e.dependencies[n.name]||e.peerDependencies&&e.peerDependencies[n.name]}if(n.path&&!X.test(n.path)&&(n.path+=".js"),n.path&&n.version&&Y.test(n.version))return`${J}${n.name}@${n.version}/${n.path}`;const r=await te(n);return`${J}${r.name}@${r.version}/${n.path||function(e){for(const t of Q){const n=e[t];if("string"==typeof n)return X.test(n)?n:`${n}.js`}}(r)||"index.js"}`}));function re(e){const t=new Map,n=i(null);function r(e){if("string"!=typeof e)return e;let n=t.get(e);return n||t.set(e,n=new Promise((t,n)=>{const r=document.createElement("script");r.onload=()=>{try{t(H.pop()(i(e)))}catch(e){n(new Z("invalid module"))}r.remove()},r.onerror=()=>{n(new Z("unable to load module")),r.remove()},r.async=!0,r.src=e,window.define=ae,document.head.appendChild(r)})),n}function i(t){return n=>Promise.resolve(e(n,t)).then(r)}function o(e){return arguments.length>1?Promise.all(W.call(arguments,n)).then(ie):n(e)}return o.alias=function(t){return re((n,r)=>n in t&&(r=null,"string"!=typeof(n=t[n]))?n:e(n,r))},o.resolve=e,o}function ie(e){const t={};for(const n of e)for(const e in n)V.call(n,e)&&(null==n[e]?Object.defineProperty(t,e,{get:oe(n,e)}):t[e]=n[e]);return t}function oe(e,t){return()=>e[t]}function se(e){return"exports"===(e+="")||"module"===e}function ae(e,t,n){const r=arguments.length;r<2?(n=e,t=[]):r<3&&(n=t,t="string"==typeof e?[]:e),H.push(G.call(t,se)?e=>{const r={},i={exports:r};return Promise.all(W.call(t,t=>"exports"===(t+="")?r:"module"===t?i:e(t))).then(e=>(n.apply(null,e),i.exports))}:e=>Promise.all(W.call(t,e)).then(e=>"function"==typeof n?n.apply(null,e):n))}ae.amd={};var le=function(e){return null==e?ne:re(e)},ue=v((function(e){var t=document.createElementNS("http://www.w3.org/2000/svg","g");return t.innerHTML=e.trim(),t}),(function(){return document.createElementNS("http://www.w3.org/2000/svg","g")})),ce=String.raw;function de(e){return new Promise((function(t,n){var r=document.createElement("link");r.rel="stylesheet",r.href=e,r.onerror=n,r.onload=t,document.head.appendChild(r)}))}var he=function(e){return function(){return Promise.all([e("@observablehq/katex@0.11.1/dist/katex.min.js"),e.resolve("@observablehq/katex@0.11.1/dist/katex.min.css").then(de)]).then((function(e){var t=e[0],n=r();function r(e){return function(){var n=document.createElement("div");return t.render(ce.apply(String,arguments),n,e),n.removeChild(n.firstChild)}}return n.options=r,n.block=r({displayMode:!0}),n}))}},fe=function(){return m((function(e){var t=e(document.body.clientWidth);function n(){var n=document.body.clientWidth;n!==t&&e(t=n)}return window.addEventListener("resize",n),function(){window.removeEventListener("resize",n)}}))};function pe(e){const t=le(e);Object.defineProperties(this,{DOM:{value:d,writable:!0,enumerable:!0},FileAttachment:{value:a(o),writable:!0,enumerable:!0},Files:{value:h,writable:!0,enumerable:!0},Generators:{value:b,writable:!0,enumerable:!0},html:{value:a(_),writable:!0,enumerable:!0},md:{value:A(t),writable:!0,enumerable:!0},Mutable:{value:a(I),writable:!0,enumerable:!0},now:{value:U,writable:!0,enumerable:!0},Promises:{value:F,writable:!0,enumerable:!0},require:{value:a(t),writable:!0,enumerable:!0},resolve:{value:a(D),writable:!0,enumerable:!0},svg:{value:a(ue),writable:!0,enumerable:!0},tex:{value:he(t),writable:!0,enumerable:!0},width:{value:fe,writable:!0,enumerable:!0}})}n.d(t,"a",(function(){return s})),n.d(t,"b",(function(){return pe}))},function(e,t,n){"use strict";t.a=function(e){return function(){return e}}},function(e,t,n){"use strict";t.a=function(e){return e}},function(e,t,n){"use strict";n.d(t,"b",(function(){return i})),n.d(t,"a",(function(){return o}));var r=Array.prototype,i=r.map,o=r.forEach},function(e,t,n){"use strict";var r=n(7),i=n(5),o=n(1),s=n(6),a=function(e){return function(){throw e}},l=n(3),u=n(0);function c(e,t=[]){Object.defineProperties(this,{_runtime:{value:e},_scope:{value:new Map},_builtins:{value:new Map([["invalidation",l.b],["visibility",l.c],...t])},_source:{value:null,writable:!0}})}function d(e){return e._name}n.d(t,"a",(function(){return c})),Object.defineProperties(c.prototype,{_copy:{value:function(e,t){e._source=this,t.set(this,e);for(const[o,a]of this._scope){var n=e._scope.get(o);if(!n||n._type!==u.c)if(a._definition===s.a){var r=a._inputs[0],i=r._module;e.import(r._name,o,t.get(i)||(i._source?i._copy(new c(e._runtime,e._builtins),t):i))}else e.define(o,a._inputs.map(d),a._definition)}return e},writable:!0,configurable:!0},_resolve:{value:function(e){var t,n=this._scope.get(e);if(!n)if(n=new u.d(u.b,this),this._builtins.has(e))n.define(e,Object(i.a)(this._builtins.get(e)));else if(this._runtime._builtin._scope.has(e))n.import(e,this._runtime._builtin);else{try{t=this._runtime._global(e)}catch(t){return n.define(e,a(t))}void 0===t?this._scope.set(n._name=e,n):n.define(e,Object(i.a)(t))}return n},writable:!0,configurable:!0},redefine:{value:function(e){var t=this._scope.get(e);if(!t)throw new o.a(e+" is not defined");if(t._type===u.a)throw new o.a(e+" is defined more than once");return t.define.apply(t,arguments)},writable:!0,configurable:!0},define:{value:function(){var e=new u.d(u.c,this);return e.define.apply(e,arguments)},writable:!0,configurable:!0},derive:{value:function(e,t){var n=new c(this._runtime,this._builtins);return n._source=this,r.a.call(e,(function(e){"object"!=typeof e&&(e={name:e+""}),null==e.alias&&(e.alias=e.name),n.import(e.name,e.alias,t)})),Promise.resolve().then(()=>{const e=new Set([this]);for(const t of e)for(const n of t._scope.values())if(n._definition===s.a){const t=n._inputs[0]._module,r=t._source||t;if(r===this)return void console.warn("circular module definition; ignoring");e.add(r)}this._copy(n,new Map)}),n},writable:!0,configurable:!0},import:{value:function(){var e=new u.d(u.c,this);return e.import.apply(e,arguments)},writable:!0,configurable:!0},value:{value:async function(e){var t=this._scope.get(e);if(!t)throw new o.a(e+" is not defined");t._observer===u.e&&(t._observer=!0,this._runtime._dirty.add(t));return await this._runtime._compute(),t._promise},writable:!0,configurable:!0},variable:{value:function(e){return new u.d(u.c,this,e)},writable:!0,configurable:!0},builtin:{value:function(e,t){this._builtins.set(e,t)},writable:!0,configurable:!0}})},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";function r(e){return e&&"function"==typeof e.next&&"function"==typeof e.return}n.d(t,"a",(function(){return r}))},function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var r=n(4),i=n(3);function o(e,t,n){if("function"==typeof t&&(n=t,t=null),"function"!=typeof n)throw new Error("invalid observer");null==t&&(t=new r.b);const{modules:o,id:s}=e,a=new Map,l=new i.a(t),u=c(s);function c(e){let t=a.get(e);return t||a.set(e,t=l.module()),t}for(const e of o){const t=c(e.id);let r=0;for(const i of e.variables)i.from?t.import(i.remote,i.name,c(i.from)):t===u?t.variable(n(i,r,e.variables)).define(i.name,i.inputs,i.value):t.define(i.name,i.inputs,i.value),++r}return l}},function(e,t,n){(function(e){var r=void 0!==e&&e||"undefined"!=typeof self&&self||window,i=Function.prototype.apply;function o(e,t){this._id=e,this._clearFn=t}t.setTimeout=function(){return new o(i.call(setTimeout,r,arguments),clearTimeout)},t.setInterval=function(){return new o(i.call(setInterval,r,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},o.prototype.unref=o.prototype.ref=function(){},o.prototype.close=function(){this._clearFn.call(r,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout((function(){e._onTimeout&&e._onTimeout()}),t))},n(13),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(this,n(9))},function(e,t,n){(function(e,t){!function(e,n){"use strict";if(!e.setImmediate){var r,i,o,s,a,l=1,u={},c=!1,d=e.document,h=Object.getPrototypeOf&&Object.getPrototypeOf(e);h=h&&h.setTimeout?h:e,"[object process]"==={}.toString.call(e.process)?r=function(e){t.nextTick((function(){p(e)}))}:!function(){if(e.postMessage&&!e.importScripts){var t=!0,n=e.onmessage;return e.onmessage=function(){t=!1},e.postMessage("","*"),e.onmessage=n,t}}()?e.MessageChannel?((o=new MessageChannel).port1.onmessage=function(e){p(e.data)},r=function(e){o.port2.postMessage(e)}):d&&"onreadystatechange"in d.createElement("script")?(i=d.documentElement,r=function(e){var t=d.createElement("script");t.onreadystatechange=function(){p(e),t.onreadystatechange=null,i.removeChild(t),t=null},i.appendChild(t)}):r=function(e){setTimeout(p,0,e)}:(s="setImmediate$"+Math.random()+"$",a=function(t){t.source===e&&"string"==typeof t.data&&0===t.data.indexOf(s)&&p(+t.data.slice(s.length))},e.addEventListener?e.addEventListener("message",a,!1):e.attachEvent("onmessage",a),r=function(t){e.postMessage(s+t,"*")}),h.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),n=0;n1)for(var n=1;n!0===e[t]);if(!t.length)return;const n=t.find(e=>!e.modifier),r="Map"===n.name&&t.find(e=>e.modifier&&e.prefix),i=t.some(e=>e.arrayish),o=t.some(e=>e.setish);return{name:`${r?r.name:""}${n.name}`,symbols:t,arrayish:i&&!o,setish:o}}catch(e){return null}}const{getPrototypeOf:_,getOwnPropertyDescriptors:y}=Object,w=_({});function x(e,t,n,o){let a,l,u,c,d=i(e);e instanceof Map?(a=`Map(${e.size})`,l=k):e instanceof Set?(a=`Set(${e.size})`,l=E):d?(a=`${e.constructor.name}(${e.length})`,l=S):(c=v(e))?(a=`Immutable.${c.name}${"Record"===c.name?"":`(${e.size})`}`,d=c.arrayish,l=c.arrayish?$:c.setish?C:q):o?(a=m(e),l=T):(a=m(e),l=L);const h=document.createElement("span");h.className="observablehq--expanded",n&&h.appendChild(s(n));const f=h.appendChild(document.createElement("a"));f.innerHTML="\n \n ",f.appendChild(document.createTextNode(`${a}${d?" [":" {"}`)),f.addEventListener("mouseup",(function(t){t.stopPropagation(),ce(h,A(e,null,n,o))})),l=l(e);for(let e=0;!(u=l.next()).done&&e<20;++e)h.appendChild(u.value);if(!u.done){const e=h.appendChild(document.createElement("a"));e.className="observablehq--field",e.style.display="block",e.appendChild(document.createTextNode(" … more")),e.addEventListener("mouseup",(function(e){e.stopPropagation(),h.insertBefore(u.value,h.lastChild.previousSibling);for(let e=0;!(u=l.next()).done&&e<19;++e)h.insertBefore(u.value,h.lastChild.previousSibling);u.done&&h.removeChild(h.lastChild.previousSibling),r(h,"load")}))}return h.appendChild(document.createTextNode(d?"]":"}")),h}function*k(e){for(const[t,n]of e)yield P(t,n);yield*L(e)}function*E(e){for(const t of e)yield O(t);yield*L(e)}function*C(e){for(const t of e)yield O(t)}function*S(e){for(let t=0,n=e.length;t ")),n.appendChild(ue(t)),n}function O(e){const t=document.createElement("div");return t.className="observablehq--field",t.appendChild(document.createTextNode(" ")),t.appendChild(ue(e)),t}function M(e){const t=window.getSelection();return"Range"===t.type&&(t.containsNode(e,!0)||t.anchorNode.isSelfOrDescendant(e)||t.focusNode.isSelfOrDescendant(e))}function A(e,t,n,r){let o,a,l,u,c=i(e);if(e instanceof Map?(o=`Map(${e.size})`,a=I):e instanceof Set?(o=`Set(${e.size})`,a=U):c?(o=`${e.constructor.name}(${e.length})`,a=F):(u=v(e))?(o=`Immutable.${u.name}${"Record"===u.name?"":`(${e.size})`}`,c=u.arrayish,a=u.arrayish?z:u.setish?R:B):(o=m(e),a=D),t){const t=document.createElement("span");return t.className="observablehq--shallow",n&&t.appendChild(s(n)),t.appendChild(document.createTextNode(o)),t.addEventListener("mouseup",(function(n){M(t)||(n.stopPropagation(),ce(t,A(e)))})),t}const d=document.createElement("span");d.className="observablehq--collapsed",n&&d.appendChild(s(n));const h=d.appendChild(document.createElement("a"));h.innerHTML="\n \n ",h.appendChild(document.createTextNode(`${o}${c?" [":" {"}`)),d.addEventListener("mouseup",(function(t){M(d)||(t.stopPropagation(),ce(d,x(e,0,n,r)))}),!0),a=a(e);for(let e=0;!(l=a.next()).done&&e<20;++e)e>0&&d.appendChild(document.createTextNode(", ")),d.appendChild(l.value);return l.done||d.appendChild(document.createTextNode(", …")),d.appendChild(document.createTextNode(c?"]":"}")),d}function*I(e){for(const[t,n]of e)yield G(t,n);yield*D(e)}function*U(e){for(const t of e)yield ue(t,!0);yield*D(e)}function*R(e){for(const t of e)yield ue(t,!0)}function*z(e){let t=-1,n=0;for(const r=e.size;nt+1&&(yield H(n-t-1)),yield ue(e.get(n),!0),t=n;n>t+1&&(yield H(n-t-1))}function*F(e){let t=-1,n=0;for(const r=e.length;nt+1&&(yield H(n-t-1)),yield ue(g(e,n),!0),t=n);n>t+1&&(yield H(n-t-1));for(const t in e)!o(t)&&p(e,t)&&(yield W(t,g(e,t),"observablehq--key"));for(const t of f(e))yield W(l(t),g(e,t),"observablehq--symbol")}function*D(e){for(const t in e)p(e,t)&&(yield W(t,g(e,t),"observablehq--key"));for(const t of f(e))yield W(l(t),g(e,t),"observablehq--symbol")}function*B(e){for(const[t,n]of e)yield W(t,n,"observablehq--key")}function H(e){const t=document.createElement("span");return t.className="observablehq--empty",t.textContent=1===e?"empty":`empty × ${e}`,t}function W(e,t,n){const r=document.createDocumentFragment(),i=r.appendChild(document.createElement("span"));return i.className=n,i.textContent=e,r.appendChild(document.createTextNode(": ")),r.appendChild(ue(t,!0)),r}function G(e,t){const n=document.createDocumentFragment();return n.appendChild(ue(e,!0)),n.appendChild(document.createTextNode(" => ")),n.appendChild(ue(t,!0)),n}function V(e,t){var n=e+"",r=n.length;return r9999?"+"+V(e,6):V(e,4)}var K=Error.prototype.toString;var Y=RegExp.prototype.toString;const X=20;function Q(e){return e.replace(/[\\`\x00-\x09\x0b-\x19]|\${/g,Z)}function Z(e){var t=e.charCodeAt(0);switch(t){case 8:return"\\b";case 9:return"\\t";case 11:return"\\v";case 12:return"\\f";case 13:return"\\r"}return t<16?"\\x0"+t.toString(16):t<32?"\\x"+t.toString(16):"\\"+e}function ee(e,t){for(var n=0;t.exec(e);)++n;return n}var te=Function.prototype.toString,ne={prefix:"async ƒ"},re={prefix:"async ƒ*"},ie={prefix:"class"},oe={prefix:"ƒ"},se={prefix:"ƒ*"};function ae(e,t,n){var r=document.createElement("span");r.className="observablehq--function",n&&r.appendChild(s(n));var i=r.appendChild(document.createElement("span"));return i.className="observablehq--keyword",i.textContent=e.prefix,r.appendChild(document.createTextNode(t)),r}const{prototype:{toString:le}}=Object;function ue(e,t,n,r,i){let o=typeof e;switch(o){case"boolean":case"undefined":e+="";break;case"number":e=0===e&&1/e<0?"-0":e+"";break;case"bigint":e+="n";break;case"symbol":e=l(e);break;case"function":return function(e,t){var n,r,i=te.call(e);switch(e.constructor&&e.constructor.name){case"AsyncFunction":n=ne;break;case"AsyncGeneratorFunction":n=re;break;case"GeneratorFunction":n=se;break;default:n=/^class\b/.test(i)?ie:oe}return n===ie?ae(n,"",t):(r=/^(?:async\s*)?(\w+)\s*=>/.exec(i))?ae(n,"("+r[1]+")",t):(r=/^(?:async\s*)?\(\s*(\w+(?:\s*,\s*\w+)*)?\s*\)/.exec(i))?ae(n,r[1]?"("+r[1].replace(/\s*,\s*/g,", ")+")":"()",t):(r=/^(?:async\s*)?function(?:\s*\*)?(?:\s*\w+)?\s*\(\s*(\w+(?:\s*,\s*\w+)*)?\s*\)/.exec(i))?ae(n,r[1]?"("+r[1].replace(/\s*,\s*/g,", ")+")":"()",t):ae(n,"(…)",t)}(e,r);case"string":return function(e,t,n,r){if(!1===t){if(ee(e,/["\n]/g)<=ee(e,/`|\${/g)){const t=document.createElement("span");r&&t.appendChild(s(r));const n=t.appendChild(document.createElement("span"));return n.className="observablehq--string",n.textContent=JSON.stringify(e),t}const i=e.split("\n");if(i.length>X&&!n){const n=document.createElement("div");r&&n.appendChild(s(r));const o=n.appendChild(document.createElement("span"));o.className="observablehq--string",o.textContent="`"+Q(i.slice(0,X).join("\n"));const a=n.appendChild(document.createElement("span")),l=i.length-X;return a.textContent=`Show ${l} truncated line${l>1?"s":""}`,a.className="observablehq--string-expand",a.addEventListener("mouseup",(function(i){i.stopPropagation(),ce(n,ue(e,t,!0,r))})),n}const o=document.createElement("span");r&&o.appendChild(s(r));const a=o.appendChild(document.createElement("span"));return a.className=`observablehq--string${n?" observablehq--expanded":""}`,a.textContent="`"+Q(e)+"`",o}const i=document.createElement("span");r&&i.appendChild(s(r));const o=i.appendChild(document.createElement("span"));return o.className="observablehq--string",o.textContent=JSON.stringify(e.length>100?`${e.slice(0,50)}…${e.slice(-49)}`:e),i}(e,t,n,r);default:if(null===e){o=null,e="null";break}if(e instanceof Date){o="date",a=e,e=isNaN(a)?"Invalid Date":function(e){return 0===e.getUTCMilliseconds()&&0===e.getUTCSeconds()&&0===e.getUTCMinutes()&&0===e.getUTCHours()}(a)?J(a.getUTCFullYear())+"-"+V(a.getUTCMonth()+1,2)+"-"+V(a.getUTCDate(),2):J(a.getFullYear())+"-"+V(a.getMonth()+1,2)+"-"+V(a.getDate(),2)+"T"+V(a.getHours(),2)+":"+V(a.getMinutes(),2)+(a.getMilliseconds()?":"+V(a.getSeconds(),2)+"."+V(a.getMilliseconds(),3):a.getSeconds()?":"+V(a.getSeconds(),2):"");break}if(e===h){o="forbidden",e="[forbidden]";break}switch(le.call(e)){case"[object RegExp]":o="regexp",e=function(e){return Y.call(e)}(e);break;case"[object Error]":case"[object DOMException]":o="error",e=function(e){return e.stack||K.call(e)}(e);break;default:return(n?x:A)(e,t,r,i)}}var a;const u=document.createElement("span");r&&u.appendChild(s(r));const c=u.appendChild(document.createElement("span"));return c.className=`observablehq--${o}`,c.textContent=e,u}function ce(e,t){e.classList.contains("observablehq--inspect")&&t.classList.add("observablehq--inspect"),e.parentNode.replaceChild(t,e),r(t,"load")}const de=/\s+\(\d+:\d+\)$/m;class he{constructor(e){if(!e)throw new Error("invalid node");this._node=e,e.classList.add("observablehq")}pending(){const{_node:e}=this;e.classList.remove("observablehq--error"),e.classList.add("observablehq--running")}fulfilled(e,t){const{_node:n}=this;if((!(e instanceof Element||e instanceof Text)||e.parentNode&&e.parentNode!==n)&&(e=ue(e,!1,n.firstChild&&n.firstChild.classList&&n.firstChild.classList.contains("observablehq--expanded"),t)).classList.add("observablehq--inspect"),n.classList.remove("observablehq--running","observablehq--error"),n.firstChild!==e)if(n.firstChild){for(;n.lastChild!==n.firstChild;)n.removeChild(n.lastChild);n.replaceChild(e,n.firstChild)}else n.appendChild(e);r(n,"update")}rejected(e,t){const{_node:n}=this;for(n.classList.remove("observablehq--running"),n.classList.add("observablehq--error");n.lastChild;)n.removeChild(n.lastChild);var i=document.createElement("div");i.className="observablehq--inspect",t&&i.appendChild(s(t)),i.appendChild(document.createTextNode((e+"").replace(de,""))),n.appendChild(i),r(n,"error",{error:e})}}he.into=function(e){if("string"==typeof e&&null==(e=document.querySelector(e)))throw new Error("container not found");return function(){return new he(e.appendChild(document.createElement("div")))}};var fe=n(4),pe=(n(1),n(3));const me=()=>{const e=new fe.b;return Object.defineProperty(e,"height",{value:ge(e.Generators.observe),writable:!0,enumerable:!0}),e},ge=e=>(function(){return e((function(e){var t=e(window.innerHeight);function n(){var n=window.innerHeight;n!==t&&e(t=n)}return window.addEventListener("resize",n),function(){window.removeEventListener("resize",n)}}))}),be=()=>{let e={};return e.promise=new Promise((t,n)=>{e.resolve=t,e.reject=n}),e},ve=(e,t)=>({pending:()=>{e.classList.add("pending")},fulfilled:n=>{t.resolve(n),e.classList.remove("pending"),e.innerHTML="",n instanceof Node?e.appendChild(n):e.innerText=JSON.stringify(n)},rejected:n=>{t.reject(n),e.classList.remove("pending"),e.classList.add("error"),e.innerText=n.message}});new Set(["canvas","svg","content","chart","map"]);var _e=async function(e,{loadAll:t,overrideHeight:n}){document.querySelector("title")||(document.title="Loading notebook...");const r=e.id;let i=[];const o=0!==document.querySelectorAll("[data-cell]").length,s=(me(),new pe.a(me()));let a;if(o)a=s.module(e,e=>{let n;if(e&&(n=document.querySelector(`[data-cell="${e}"]`))){let e=be();return i.push(e.promise),ve(n,e)}return t});else{const t=be();i.push(t.promise);const r=document.createElement("div");r.classList.add("content"),document.body.appendChild(r),a=s.module(e,()=>{const e=be(),i=document.createElement("div");n&&i.classList.add("override-height");const o=ve(i,e);return{pending:()=>{o.pending()},fulfilled:e=>{e instanceof HTMLCanvasElement||e instanceof SVGElement?(t.resolve(),o.fulfilled(e),r.innerHTML="",r.appendChild(i)):o.fulfilled(e)},rejected:e=>{o.rejected(e)}}})}n&&a.redefine("height",()=>null).delete();try{await Promise.all(i),document.querySelectorAll(".loading").forEach(e=>e.remove()),document.querySelector("title")||(document.title=`Observable Press Notebook: ${r}`)}catch(e){console.error(e)}};n.d(t,"initialize",(function(){return _e}));const ye=document.querySelector("[data-notebook]").getAttribute("data-notebook"),we=null!==document.querySelector("[data-load-all]"),xe=null!==document.querySelector("[data-override-height]"),ke=`\nimport notebook from '${`https://api.observablehq.com/${ye}.js?v=3`}';\n\nobservablePress.initialize(notebook, ${JSON.stringify({loadAll:we,overrideHeight:xe})});\n`,Ee=document.createElement("script");Ee.innerHTML=ke,Ee.setAttribute("type","module"),document.head.appendChild(Ee)}])})); -------------------------------------------------------------------------------- /examples/aai/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Animated Average Images 7 | 8 | 43 | 44 | 45 |
    46 |
    47 |
    48 |
    49 |
    50 |
    51 |
    loading...
    52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /examples/aai/observable-press.js: -------------------------------------------------------------------------------- 1 | ../../dist/observable-press.js -------------------------------------------------------------------------------- /examples/aai/style.css: -------------------------------------------------------------------------------- 1 | ../../src/style.css -------------------------------------------------------------------------------- /examples/pantry/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Pantry Nutrition Explorer 7 | 8 | 48 | 49 | 50 |
    loading...
    51 |

    Pantry Nutrition Explorer

    52 |
    53 |
    54 |
    55 |
    56 |
    57 |
    58 |
    59 |

    Food Groups

    60 |
    61 |
    62 |
    63 |

    64 | Visualization by Zev Youra, 65 | data from USDA National Nutrient Database 66 |

    67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /examples/pantry/observable-press.js: -------------------------------------------------------------------------------- 1 | ../../dist/observable-press.js -------------------------------------------------------------------------------- /examples/pantry/style.css: -------------------------------------------------------------------------------- 1 | ../../src/style.css -------------------------------------------------------------------------------- /examples/simple-ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 |
    loading...
    20 |
    21 |
    22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/simple-ui/observable-press.js: -------------------------------------------------------------------------------- 1 | ../../dist/observable-press.js -------------------------------------------------------------------------------- /examples/simple-ui/style.css: -------------------------------------------------------------------------------- 1 | ../../src/style.css -------------------------------------------------------------------------------- /examples/simple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/simple/observable-press.js: -------------------------------------------------------------------------------- 1 | ../../dist/observable-press.js -------------------------------------------------------------------------------- /examples/simple/style.css: -------------------------------------------------------------------------------- 1 | ../../src/style.css -------------------------------------------------------------------------------- /examples/todo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 99 | 100 | 101 |
    loading...
    102 |

    todos

    103 |
    104 |
    105 |
    106 | 111 |
    112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /examples/todo/observable-press.js: -------------------------------------------------------------------------------- 1 | ../../dist/observable-press.js -------------------------------------------------------------------------------- /examples/todo/style.css: -------------------------------------------------------------------------------- 1 | ../../src/style.css -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "observable-press", 3 | "version": "0.0.1", 4 | "description": "An opinionated way to publish [Observable notebooks](//observablehq.com).", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/zzzev/observable-press.git" 8 | }, 9 | "scripts": { 10 | "build": "webpack" 11 | }, 12 | "author": "zevyoura@gmail.com", 13 | "license": "MIT", 14 | "bugs": { 15 | "url": "https://github.com/zzzev/observable-press/issues" 16 | }, 17 | "homepage": "https://github.com/zzzev/observable-press#readme", 18 | "devDependencies": { 19 | "webpack": "^4.29.6", 20 | "webpack-cli": "^3.3.0" 21 | }, 22 | "dependencies": { 23 | "@observablehq/runtime": "^4.4.4" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import initialize from './initialize'; 2 | 3 | // This script pulls the options from the HTML document and invokes the bootstrap 4 | // function from observable-press.js 5 | const notebookAttribute = 'data-notebook'; 6 | const notebookId = document.querySelector(`[${notebookAttribute}]`) 7 | .getAttribute(notebookAttribute); 8 | 9 | const loadAll = document.querySelector('[data-load-all]') !== null; 10 | 11 | const overrideHeight = document.querySelector('[data-override-height]') !== null; 12 | 13 | const apiUrl = `https://api.observablehq.com/${notebookId}.js?v=3`; 14 | 15 | // Somewhat hacky workaround for dynamic imports. 16 | // 17 | // Since we only have one (the notebook), it's much simpler to do this than 18 | // use something like shimport. 19 | const scriptSrc = ` 20 | import notebook from '${apiUrl}'; 21 | 22 | observablePress.initialize(notebook, ${JSON.stringify({loadAll, overrideHeight})}); 23 | `; 24 | 25 | const script = document.createElement('script'); 26 | script.innerHTML = scriptSrc; 27 | script.setAttribute('type', 'module'); 28 | document.head.appendChild(script); 29 | 30 | export {initialize}; 31 | -------------------------------------------------------------------------------- /src/initialize.js: -------------------------------------------------------------------------------- 1 | import {Runtime} from '@observablehq/runtime'; 2 | import {getLibrary} from './library' 3 | import {getPromiseParts, createNodeObserver} from './util'; 4 | 5 | // Given an Observable notebook module [notebook], run it, placing 6 | // all named cells into the HTML tag with the matching data-cell 7 | // attribute. 8 | // 9 | // If no data-cell attributes are set, attempts to find the first named 10 | // cell with a "content-looking" name. If none is found, it chooses the 11 | // first cell which returns an SVG or canvas element. This cell is then 12 | // rendered into the body of the document. 13 | // 14 | // [loadAll] will cause all cells to be observed, even if not rendered. 15 | // [overrideHeight] will redefine the height variable to be equal to the 16 | // window height, similar to the way width works in normal notebooks. 17 | const initialize = async function initialize(notebook, {loadAll, overrideHeight}) { 18 | if (!document.querySelector('title')) { 19 | document.title = 'Loading notebook...'; 20 | } 21 | 22 | const notebookId = notebook.id; 23 | 24 | let firstRenderPromises = []; 25 | 26 | // If there are HTML nodes with data-cell attributes, we load cells with the given names 27 | // into them. 28 | // If there are no such nodes, we load the first cell we find with a content-like name. 29 | const dataCells = document.querySelectorAll('[data-cell]'); 30 | const hasDefinedCells = dataCells.length !== 0; 31 | 32 | const library = getLibrary(); 33 | 34 | const runtime = new Runtime(getLibrary()); 35 | 36 | let notebookModule; 37 | 38 | if (!hasDefinedCells) { 39 | // If no cell names are specified, observe all nodes and show the first 40 | // one that comes back as a canvas or svg element 41 | const firstContentPromiseParts = getPromiseParts(); 42 | firstRenderPromises.push(firstContentPromiseParts.promise); 43 | const contentWrapper = document.createElement('div'); 44 | contentWrapper.classList.add('content') 45 | document.body.appendChild(contentWrapper); 46 | 47 | notebookModule = runtime.module(notebook, () => { 48 | const promiseParts = getPromiseParts(); 49 | const node = document.createElement('div'); 50 | if (overrideHeight) { 51 | node.classList.add('override-height'); 52 | } 53 | const observer = createNodeObserver(node, promiseParts); 54 | return { 55 | pending: () => { 56 | observer.pending(); 57 | }, 58 | fulfilled: (value) => { 59 | if (value instanceof HTMLCanvasElement || value instanceof SVGElement) { 60 | firstContentPromiseParts.resolve(); 61 | observer.fulfilled(value); 62 | contentWrapper.innerHTML = ''; 63 | contentWrapper.appendChild(node); 64 | } else { 65 | observer.fulfilled(value); 66 | } 67 | }, 68 | rejected: (error) => { 69 | observer.rejected(error); 70 | } 71 | }; 72 | }) 73 | } else { 74 | // We want specific cells (named in data-cell attr), so only observe those. 75 | notebookModule = runtime.module(notebook, cellName => { 76 | let node; 77 | if (cellName) { 78 | node = document.querySelector(`[data-cell="${cellName}"]`); 79 | if (node) { 80 | let promiseParts = getPromiseParts(); 81 | firstRenderPromises.push(promiseParts.promise); 82 | return createNodeObserver(node, promiseParts); 83 | } 84 | } 85 | return loadAll; 86 | }); 87 | } 88 | 89 | if (overrideHeight) { 90 | notebookModule.redefine('height', () => null).delete(); 91 | } 92 | 93 | // Await initial fulfillment of all observed cells 94 | try { 95 | await Promise.all(firstRenderPromises); 96 | document.querySelectorAll('.loading').forEach(node => node.remove()); 97 | if (!document.querySelector('title')) { 98 | document.title = `Observable Press Notebook: ${notebookId}`; 99 | } 100 | } catch (e) { 101 | console.error(e); 102 | // TODO: better error handling of initial load 103 | } 104 | } 105 | 106 | // Names which are considered "content-like" and will be rendered if no 107 | // data-cell is specified. 108 | const renderableNames = new Set(['canvas', 'svg', 'content', 'chart', 'map']); 109 | const isRenderableName = name => renderableNames.has(name); 110 | 111 | export default initialize; 112 | -------------------------------------------------------------------------------- /src/library.js: -------------------------------------------------------------------------------- 1 | import {Library} from '@observablehq/runtime'; 2 | 3 | // A normal Observable Library, but with additional `height` builtin. 4 | const getLibrary = () => { 5 | const lib = new Library(); 6 | Object.defineProperty(lib, 'height', { 7 | value: getHeightBuiltin(lib.Generators.observe), 8 | writable: true, 9 | enumerable: true 10 | }); 11 | return lib; 12 | } 13 | 14 | // Slightly altered version of observablehq/stdlib/src/width.js 15 | const getHeightBuiltin = observe => { 16 | return function() { 17 | return observe(function(change) { 18 | var height = change(window.innerHeight); 19 | function resized() { 20 | var h = window.innerHeight; 21 | if (h !== height) change(height = h); 22 | } 23 | window.addEventListener("resize", resized); 24 | return function() { 25 | window.removeEventListener("resize", resized); 26 | }; 27 | }); 28 | } 29 | } 30 | 31 | export {getLibrary}; -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | /* Default styles for observable-press */ 2 | html,body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: sans-serif; 6 | min-height: 100%; 7 | } 8 | 9 | .loading { 10 | background: white; 11 | display: flex; 12 | align-items: center; 13 | justify-content: center; 14 | position: fixed; 15 | top: 0; 16 | right: 0; 17 | left: 0; 18 | bottom: 0; 19 | } 20 | 21 | .error { 22 | background: red; 23 | } 24 | 25 | .pending { 26 | background: rgba(0,0,0,0.2); 27 | } 28 | 29 | .override-height { 30 | position: fixed; 31 | left: 0; 32 | right: 0; 33 | top: 0; 34 | bottom: 0; 35 | z-index: 0; 36 | } -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | // A convenience function that returns a promise and its resolve and reject callbacks. 2 | const getPromiseParts = () => { 3 | let parts = {}; 4 | parts.promise = new Promise((resolve, reject) => { 5 | parts.resolve = resolve; 6 | parts.reject = reject; 7 | }); 8 | return parts; 9 | } 10 | 11 | // Common code that returns an observer which will populate the given [node] when 12 | // fulfilled and also update the passed in [promiseParts] 13 | const createNodeObserver = (node, promiseParts) => ({ 14 | pending: () => { 15 | node.classList.add('pending'); 16 | }, 17 | fulfilled: (value) => { 18 | // resolve promise -- note this only has an effect the first time this is called 19 | promiseParts.resolve(value); 20 | node.classList.remove('pending'); 21 | node.innerHTML = ''; 22 | if (value instanceof Node) { 23 | node.appendChild(value); 24 | } else { 25 | node.innerText = JSON.stringify(value); 26 | } 27 | }, 28 | rejected: (error) => { 29 | promiseParts.reject(error); 30 | node.classList.remove('pending'); 31 | node.classList.add('error'); 32 | node.innerText = error.message; 33 | } 34 | }); 35 | 36 | export { getPromiseParts, createNodeObserver }; -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | mode: 'production', 5 | entry: './src/index.js', 6 | output: { 7 | filename: 'observable-press.js', 8 | path: path.resolve(__dirname, 'dist'), 9 | library: 'observablePress', 10 | libraryTarget: 'umd' 11 | } 12 | }; 13 | --------------------------------------------------------------------------------