@pageboard/html 0.14.39 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/elements/form.js CHANGED
@@ -38,7 +38,7 @@ exports.query_form = {
38
38
  title: 'Page',
39
39
  nullable: true,
40
40
  type: "string",
41
- format: "pathname",
41
+ format: "page",
42
42
  $helper: "page"
43
43
  },
44
44
  parameters: {
@@ -79,7 +79,7 @@ exports.api_form = {
79
79
  properties: {
80
80
  name: {
81
81
  title: 'Name',
82
- description: "Used by query 'submit' or 'toggle'\nExposes /.api/form/$name",
82
+ description: "Used by query 'submit' or 'toggle'\nExposes /@api/form/$name",
83
83
  type: 'string',
84
84
  format: 'id',
85
85
  nullable: true
@@ -101,15 +101,71 @@ exports.api_form = {
101
101
  description: 'Choose a service',
102
102
  $ref: '/writes'
103
103
  },
104
+ request: {
105
+ title: 'Map inputs',
106
+ description: `
107
+ expr is supposed to be used to merge stuff into html,
108
+ not really to merge stuff into methods parameters
109
+ Also expr has a bad design because
110
+ - it can be replaced by a binding element inside the block
111
+ - it forces the expression to be in a specific attribute,
112
+ and mostly when a block has no content (so a binding cannot be used)
113
+ - the editor is ugly and shows fields that might not even be merged into html
114
+ Use cases
115
+ - links in anchors, images
116
+ - input or buttons values, checked attributes
117
+ - hidden attributes
118
+ - show/hide blocks depending on response
119
+ The "expr" mecanism could instead be a list of expressions like
120
+ [url|as:url|assign:.query.reservation:$query.reservation]
121
+ [url][$query|pick:text:cover|as:query]
122
+
123
+ Things to solve:
124
+ - do we want expr to be able to do changes outside the DOM of the block itself ? (no, this should be done by a binding element)
125
+ - do we want expr to change only data before merge - outside of any dom context ? Possibly ! In which case the current system is not that bad,
126
+ but it should not use matchdom dom plugin at all
127
+ - how to deal with "template" expressions when one cannot insert a binding
128
+ element ? Is it really something that happens ?
129
+
130
+
131
+
132
+ `,
133
+ type: 'object',
134
+ nullable: true
135
+ },
136
+ response: {
137
+ title: 'Map outputs',
138
+ description: `
139
+ 'item.id': '[item.data.id]'
140
+ 'item.title': '[item.content.title]'
141
+ // etc...
142
+ `,
143
+ type: 'object',
144
+ nullable: true
145
+ },
104
146
  redirection: {
105
147
  title: 'Success',
148
+ description: `
149
+ redirection can be used by client,
150
+ to change the page state. In which case the "url" is not an api url.
151
+ It can be used by the server, in which case the "url" is an api url.
152
+ The parameters for a page url make the query, and $query, $request, $response are available.
153
+ The parameters for a user api call are...?
154
+ The user api endpoint is a real url (/@api/xxx) that can expect
155
+ a body ($request) and a query ($query) too.
156
+ Currently client pages use a trick to redirect and submit: a specific parameter triggers a form submit on the redirected page. This makes sense in the context of page navigation - the body is filled by the form that is triggered by the parameters.
157
+ How can that be transposed for internal user api redirection ?
158
+ 1. since it redirects, output mapping can be done to format the $response
159
+ 2. in the next api call, parameters mean $query, $response becomes $request ?
160
+ 3. this works if output can merge $query, $request as well
161
+ `,
106
162
  type: 'object',
107
163
  properties: {
108
164
  url: {
109
165
  title: 'Page',
110
166
  nullable: true,
111
167
  type: "string",
112
- format: "pathname",
168
+ format: "page",
113
169
  $helper: "page"
114
170
  },
115
171
  parameters: {
@@ -160,7 +216,7 @@ exports.api_form = {
160
216
  contents: 'block+',
161
217
  tag: 'form[method="post"]',
162
218
  html: `<form is="element-form" method="post" name="[name]" masked="[masked]"
163
- action="/.api/form/[name|else:$id]"
219
+ action="/@api/form/[name|else:$id]"
164
220
  parameters="[$expr?.action?.parameters|as:expressions]"
165
221
  success="[redirection.url][redirection.parameters|as:query]"
166
222
  badrequest="[badrequest.url][badrequest.parameters|as:query]"
@@ -50,7 +50,7 @@ exports.input_property = {
50
50
  return node;
51
51
  }
52
52
  // list[0] = "data";
53
- // /.api/form wraps it into block.data
53
+ // /@api/form wraps it into block.data
54
54
  list.shift();
55
55
  name = list.join('.');
56
56
  const id = scope.$id;
package/elements/link.js CHANGED
@@ -29,7 +29,7 @@ exports.link = {
29
29
  nullable: true,
30
30
  $helper: {
31
31
  name: 'datalist',
32
- url: '/.api/languages'
32
+ url: '/@api/languages'
33
33
  }
34
34
  },
35
35
  id: {
@@ -75,7 +75,7 @@ exports.link_button = {
75
75
  nullable: true,
76
76
  $helper: {
77
77
  name: 'datalist',
78
- url: '/.api/languages'
78
+ url: '/@api/languages'
79
79
  }
80
80
  },
81
81
  full: {
@@ -108,7 +108,7 @@ exports.link_button = {
108
108
  default: null
109
109
  }
110
110
  },
111
- contents: "text*",
111
+ contents: "inline*",
112
112
  group: "block",
113
113
  html: '<a href="[url|lang:[lang]]" hreflang="[lang]" class="ui [full|alt:fluid:] [icon] [compact] [float|post:%20floated] button"></a>',
114
114
  stylesheets: [
package/elements/menu.js CHANGED
@@ -105,7 +105,7 @@ exports.menu_item_link = {
105
105
  nullable: true,
106
106
  $helper: {
107
107
  name: 'datalist',
108
- url: '/.api/languages'
108
+ url: '/@api/languages'
109
109
  }
110
110
  },
111
111
  labeled: {
@@ -0,0 +1,21 @@
1
+ /*! formdata-polyfill. MIT License. Jimmy W?rting <https://jimmy.warting.se/opensource> */
2
+ ;(function(){var h;function l(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}}var m="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a};
3
+ function n(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}throw Error("Cannot find global object");}var q=n(this);function r(a,b){if(b)a:{var c=q;a=a.split(".");for(var d=0;d<a.length-1;d++){var e=a[d];if(!(e in c))break a;c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&m(c,a,{configurable:!0,writable:!0,value:b})}}
4
+ r("Symbol",function(a){function b(f){if(this instanceof b)throw new TypeError("Symbol is not a constructor");return new c(d+(f||"")+"_"+e++,f)}function c(f,g){this.A=f;m(this,"description",{configurable:!0,writable:!0,value:g})}if(a)return a;c.prototype.toString=function(){return this.A};var d="jscomp_symbol_"+(1E9*Math.random()>>>0)+"_",e=0;return b});
5
+ r("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),c=0;c<b.length;c++){var d=q[b[c]];"function"===typeof d&&"function"!=typeof d.prototype[a]&&m(d.prototype,a,{configurable:!0,writable:!0,value:function(){return u(l(this))}})}return a});function u(a){a={next:a};a[Symbol.iterator]=function(){return this};return a}
6
+ function v(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):{next:l(a)}}var w;if("function"==typeof Object.setPrototypeOf)w=Object.setPrototypeOf;else{var y;a:{var z={a:!0},A={};try{A.__proto__=z;y=A.a;break a}catch(a){}y=!1}w=y?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null}var B=w;function C(){this.m=!1;this.j=null;this.v=void 0;this.h=1;this.u=this.C=0;this.l=null}
7
+ function D(a){if(a.m)throw new TypeError("Generator is already running");a.m=!0}C.prototype.o=function(a){this.v=a};C.prototype.s=function(a){this.l={D:a,F:!0};this.h=this.C||this.u};C.prototype.return=function(a){this.l={return:a};this.h=this.u};function E(a,b){a.h=3;return{value:b}}function F(a){this.g=new C;this.G=a}F.prototype.o=function(a){D(this.g);if(this.g.j)return G(this,this.g.j.next,a,this.g.o);this.g.o(a);return H(this)};
8
+ function I(a,b){D(a.g);var c=a.g.j;if(c)return G(a,"return"in c?c["return"]:function(d){return{value:d,done:!0}},b,a.g.return);a.g.return(b);return H(a)}F.prototype.s=function(a){D(this.g);if(this.g.j)return G(this,this.g.j["throw"],a,this.g.o);this.g.s(a);return H(this)};
9
+ function G(a,b,c,d){try{var e=b.call(a.g.j,c);if(!(e instanceof Object))throw new TypeError("Iterator result "+e+" is not an object");if(!e.done)return a.g.m=!1,e;var f=e.value}catch(g){return a.g.j=null,a.g.s(g),H(a)}a.g.j=null;d.call(a.g,f);return H(a)}function H(a){for(;a.g.h;)try{var b=a.G(a.g);if(b)return a.g.m=!1,{value:b.value,done:!1}}catch(c){a.g.v=void 0,a.g.s(c)}a.g.m=!1;if(a.g.l){b=a.g.l;a.g.l=null;if(b.F)throw b.D;return{value:b.return,done:!0}}return{value:void 0,done:!0}}
10
+ function J(a){this.next=function(b){return a.o(b)};this.throw=function(b){return a.s(b)};this.return=function(b){return I(a,b)};this[Symbol.iterator]=function(){return this}}function K(a,b){b=new J(new F(b));B&&a.prototype&&B(b,a.prototype);return b}function L(a,b){a instanceof String&&(a+="");var c=0,d=!1,e={next:function(){if(!d&&c<a.length){var f=c++;return{value:b(f,a[f]),done:!1}}d=!0;return{done:!0,value:void 0}}};e[Symbol.iterator]=function(){return e};return e}
11
+ r("Array.prototype.entries",function(a){return a?a:function(){return L(this,function(b,c){return[b,c]})}});
12
+ if("undefined"!==typeof Blob&&("undefined"===typeof FormData||!FormData.prototype.keys)){var M=function(a,b){for(var c=0;c<a.length;c++)b(a[c])},N=function(a){return a.replace(/\r?\n|\r/g,"\r\n")},O=function(a,b,c){if(b instanceof Blob){c=void 0!==c?String(c+""):"string"===typeof b.name?b.name:"blob";if(b.name!==c||"[object Blob]"===Object.prototype.toString.call(b))b=new File([b],c);return[String(a),b]}return[String(a),String(b)]},P=function(a,b){if(a.length<b)throw new TypeError(b+" argument required, but only "+
13
+ a.length+" present.");},Q="object"===typeof globalThis?globalThis:"object"===typeof window?window:"object"===typeof self?self:this,R=Q.FormData,S=Q.XMLHttpRequest&&Q.XMLHttpRequest.prototype.send,T=Q.Request&&Q.fetch,U=Q.navigator&&Q.navigator.sendBeacon,V=Q.Element&&Q.Element.prototype,W=Q.Symbol&&Symbol.toStringTag;W&&(Blob.prototype[W]||(Blob.prototype[W]="Blob"),"File"in Q&&!File.prototype[W]&&(File.prototype[W]="File"));try{new File([],"")}catch(a){Q.File=function(b,c,d){b=new Blob(b,d||{});
14
+ Object.defineProperties(b,{name:{value:c},lastModified:{value:+(d&&void 0!==d.lastModified?new Date(d.lastModified):new Date)},toString:{value:function(){return"[object File]"}}});W&&Object.defineProperty(b,W,{value:"File"});return b}}var escape=function(a){return a.replace(/\n/g,"%0A").replace(/\r/g,"%0D").replace(/"/g,"%22")},X=function(a){this.i=[];var b=this;a&&M(a.elements,function(c){if(c.name&&!c.disabled&&"submit"!==c.type&&"button"!==c.type&&!c.matches("form fieldset[disabled] *"))if("file"===
15
+ c.type){var d=c.files&&c.files.length?c.files:[new File([],"",{type:"application/octet-stream"})];M(d,function(e){b.append(c.name,e)})}else"select-multiple"===c.type||"select-one"===c.type?M(c.options,function(e){!e.disabled&&e.selected&&b.append(c.name,e.value)}):"checkbox"===c.type||"radio"===c.type?c.checked&&b.append(c.name,c.value):(d="textarea"===c.type?N(c.value):c.value,b.append(c.name,d))})};h=X.prototype;h.append=function(a,b,c){P(arguments,2);this.i.push(O(a,b,c))};h.delete=function(a){P(arguments,
16
+ 1);var b=[];a=String(a);M(this.i,function(c){c[0]!==a&&b.push(c)});this.i=b};h.entries=function b(){var c,d=this;return K(b,function(e){1==e.h&&(c=0);if(3!=e.h)return c<d.i.length?e=E(e,d.i[c]):(e.h=0,e=void 0),e;c++;e.h=2})};h.forEach=function(b,c){P(arguments,1);for(var d=v(this),e=d.next();!e.done;e=d.next()){var f=v(e.value);e=f.next().value;f=f.next().value;b.call(c,f,e,this)}};h.get=function(b){P(arguments,1);var c=this.i;b=String(b);for(var d=0;d<c.length;d++)if(c[d][0]===b)return c[d][1];
17
+ return null};h.getAll=function(b){P(arguments,1);var c=[];b=String(b);M(this.i,function(d){d[0]===b&&c.push(d[1])});return c};h.has=function(b){P(arguments,1);b=String(b);for(var c=0;c<this.i.length;c++)if(this.i[c][0]===b)return!0;return!1};h.keys=function c(){var d=this,e,f,g,k,p;return K(c,function(t){1==t.h&&(e=v(d),f=e.next());if(3!=t.h){if(f.done){t.h=0;return}g=f.value;k=v(g);p=k.next().value;return E(t,p)}f=e.next();t.h=2})};h.set=function(c,d,e){P(arguments,2);c=String(c);var f=[],g=O(c,
18
+ d,e),k=!0;M(this.i,function(p){p[0]===c?k&&(k=!f.push(g)):f.push(p)});k&&f.push(g);this.i=f};h.values=function d(){var e=this,f,g,k,p,t;return K(d,function(x){1==x.h&&(f=v(e),g=f.next());if(3!=x.h){if(g.done){x.h=0;return}k=g.value;p=v(k);p.next();t=p.next().value;return E(x,t)}g=f.next();x.h=2})};X.prototype._asNative=function(){for(var d=new R,e=v(this),f=e.next();!f.done;f=e.next()){var g=v(f.value);f=g.next().value;g=g.next().value;d.append(f,g)}return d};X.prototype._blob=function(){var d="----formdata-polyfill-"+
19
+ Math.random(),e=[],f="--"+d+'\r\nContent-Disposition: form-data; name="';this.forEach(function(g,k){return"string"==typeof g?e.push(f+escape(N(k))+('"\r\n\r\n'+N(g)+"\r\n")):e.push(f+escape(N(k))+('"; filename="'+escape(g.name)+'"\r\nContent-Type: '+(g.type||"application/octet-stream")+"\r\n\r\n"),g,"\r\n")});e.push("--"+d+"--");return new Blob(e,{type:"multipart/form-data; boundary="+d})};X.prototype[Symbol.iterator]=function(){return this.entries()};X.prototype.toString=function(){return"[object FormData]"};
20
+ V&&!V.matches&&(V.matches=V.matchesSelector||V.mozMatchesSelector||V.msMatchesSelector||V.oMatchesSelector||V.webkitMatchesSelector||function(d){d=(this.document||this.ownerDocument).querySelectorAll(d);for(var e=d.length;0<=--e&&d.item(e)!==this;);return-1<e});W&&(X.prototype[W]="FormData");if(S){var Y=Q.XMLHttpRequest.prototype.setRequestHeader;Q.XMLHttpRequest.prototype.setRequestHeader=function(d,e){Y.call(this,d,e);"content-type"===d.toLowerCase()&&(this.B=!0)};Q.XMLHttpRequest.prototype.send=
21
+ function(d){d instanceof X?(d=d._blob(),this.B||this.setRequestHeader("Content-Type",d.type),S.call(this,d)):S.call(this,d)}}T&&(Q.fetch=function(d,e){e&&e.body&&e.body instanceof X&&(e.body=e.body._blob());return T.call(this,d,e)});U&&(Q.navigator.sendBeacon=function(d,e){e instanceof X&&(e=e._asNative());return U.call(this,d,e)});Q.FormData=X};})();
@@ -0,0 +1,243 @@
1
+ var objectFitImages = (function () {
2
+ 'use strict';
3
+
4
+ function getDefaultExportFromCjs (x) {
5
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
6
+ }
7
+
8
+ /*! npm.im/object-fit-images 3.2.4 */
9
+
10
+ var OFI = 'bfred-it:object-fit-images';
11
+ var propRegex = /(object-fit|object-position)\s*:\s*([-.\w\s%]+)/g;
12
+ var testImg = typeof Image === 'undefined' ? {style: {'object-position': 1}} : new Image();
13
+ var supportsObjectFit = 'object-fit' in testImg.style;
14
+ var supportsObjectPosition = 'object-position' in testImg.style;
15
+ var supportsOFI = 'background-size' in testImg.style;
16
+ var supportsCurrentSrc = typeof testImg.currentSrc === 'string';
17
+ var nativeGetAttribute = testImg.getAttribute;
18
+ var nativeSetAttribute = testImg.setAttribute;
19
+ var autoModeEnabled = false;
20
+
21
+ function createPlaceholder(w, h) {
22
+ return ("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='" + w + "' height='" + h + "'%3E%3C/svg%3E");
23
+ }
24
+
25
+ function polyfillCurrentSrc(el) {
26
+ if (el.srcset && !supportsCurrentSrc && window.picturefill) {
27
+ var pf = window.picturefill._;
28
+ // parse srcset with picturefill where currentSrc isn't available
29
+ if (!el[pf.ns] || !el[pf.ns].evaled) {
30
+ // force synchronous srcset parsing
31
+ pf.fillImg(el, {reselect: true});
32
+ }
33
+
34
+ if (!el[pf.ns].curSrc) {
35
+ // force picturefill to parse srcset
36
+ el[pf.ns].supported = false;
37
+ pf.fillImg(el, {reselect: true});
38
+ }
39
+
40
+ // retrieve parsed currentSrc, if any
41
+ el.currentSrc = el[pf.ns].curSrc || el.src;
42
+ }
43
+ }
44
+
45
+ function getStyle(el) {
46
+ var style = getComputedStyle(el).fontFamily;
47
+ var parsed;
48
+ var props = {};
49
+ while ((parsed = propRegex.exec(style)) !== null) {
50
+ props[parsed[1]] = parsed[2];
51
+ }
52
+ return props;
53
+ }
54
+
55
+ function setPlaceholder(img, width, height) {
56
+ // Default: fill width, no height
57
+ var placeholder = createPlaceholder(width || 1, height || 0);
58
+
59
+ // Only set placeholder if it's different
60
+ if (nativeGetAttribute.call(img, 'src') !== placeholder) {
61
+ nativeSetAttribute.call(img, 'src', placeholder);
62
+ }
63
+ }
64
+
65
+ function onImageReady(img, callback) {
66
+ // naturalWidth is only available when the image headers are loaded,
67
+ // this loop will poll it every 100ms.
68
+ if (img.naturalWidth) {
69
+ callback(img);
70
+ } else {
71
+ setTimeout(onImageReady, 100, img, callback);
72
+ }
73
+ }
74
+
75
+ function fixOne(el) {
76
+ var style = getStyle(el);
77
+ var ofi = el[OFI];
78
+ style['object-fit'] = style['object-fit'] || 'fill'; // default value
79
+
80
+ // Avoid running where unnecessary, unless OFI had already done its deed
81
+ if (!ofi.img) {
82
+ // fill is the default behavior so no action is necessary
83
+ if (style['object-fit'] === 'fill') {
84
+ return;
85
+ }
86
+
87
+ // Where object-fit is supported and object-position isn't (Safari < 10)
88
+ if (
89
+ !ofi.skipTest && // unless user wants to apply regardless of browser support
90
+ supportsObjectFit && // if browser already supports object-fit
91
+ !style['object-position'] // unless object-position is used
92
+ ) {
93
+ return;
94
+ }
95
+ }
96
+
97
+ // keep a clone in memory while resetting the original to a blank
98
+ if (!ofi.img) {
99
+ ofi.img = new Image(el.width, el.height);
100
+ ofi.img.srcset = nativeGetAttribute.call(el, "data-ofi-srcset") || el.srcset;
101
+ ofi.img.src = nativeGetAttribute.call(el, "data-ofi-src") || el.src;
102
+
103
+ // preserve for any future cloneNode calls
104
+ // https://github.com/bfred-it/object-fit-images/issues/53
105
+ nativeSetAttribute.call(el, "data-ofi-src", el.src);
106
+ if (el.srcset) {
107
+ nativeSetAttribute.call(el, "data-ofi-srcset", el.srcset);
108
+ }
109
+
110
+ setPlaceholder(el, el.naturalWidth || el.width, el.naturalHeight || el.height);
111
+
112
+ // remove srcset because it overrides src
113
+ if (el.srcset) {
114
+ el.srcset = '';
115
+ }
116
+ try {
117
+ keepSrcUsable(el);
118
+ } catch (err) {
119
+ if (window.console) {
120
+ console.warn('https://bit.ly/ofi-old-browser');
121
+ }
122
+ }
123
+ }
124
+
125
+ polyfillCurrentSrc(ofi.img);
126
+
127
+ el.style.backgroundImage = "url(\"" + ((ofi.img.currentSrc || ofi.img.src).replace(/"/g, '\\"')) + "\")";
128
+ el.style.backgroundPosition = style['object-position'] || 'center';
129
+ el.style.backgroundRepeat = 'no-repeat';
130
+ el.style.backgroundOrigin = 'content-box';
131
+
132
+ if (/scale-down/.test(style['object-fit'])) {
133
+ onImageReady(ofi.img, function () {
134
+ if (ofi.img.naturalWidth > el.width || ofi.img.naturalHeight > el.height) {
135
+ el.style.backgroundSize = 'contain';
136
+ } else {
137
+ el.style.backgroundSize = 'auto';
138
+ }
139
+ });
140
+ } else {
141
+ el.style.backgroundSize = style['object-fit'].replace('none', 'auto').replace('fill', '100% 100%');
142
+ }
143
+
144
+ onImageReady(ofi.img, function (img) {
145
+ setPlaceholder(el, img.naturalWidth, img.naturalHeight);
146
+ });
147
+ }
148
+
149
+ function keepSrcUsable(el) {
150
+ var descriptors = {
151
+ get: function get(prop) {
152
+ return el[OFI].img[prop ? prop : 'src'];
153
+ },
154
+ set: function set(value, prop) {
155
+ el[OFI].img[prop ? prop : 'src'] = value;
156
+ nativeSetAttribute.call(el, ("data-ofi-" + prop), value); // preserve for any future cloneNode
157
+ fixOne(el);
158
+ return value;
159
+ }
160
+ };
161
+ Object.defineProperty(el, 'src', descriptors);
162
+ Object.defineProperty(el, 'currentSrc', {
163
+ get: function () { return descriptors.get('currentSrc'); }
164
+ });
165
+ Object.defineProperty(el, 'srcset', {
166
+ get: function () { return descriptors.get('srcset'); },
167
+ set: function (ss) { return descriptors.set(ss, 'srcset'); }
168
+ });
169
+ }
170
+
171
+ function hijackAttributes() {
172
+ function getOfiImageMaybe(el, name) {
173
+ return el[OFI] && el[OFI].img && (name === 'src' || name === 'srcset') ? el[OFI].img : el;
174
+ }
175
+ if (!supportsObjectPosition) {
176
+ HTMLImageElement.prototype.getAttribute = function (name) {
177
+ return nativeGetAttribute.call(getOfiImageMaybe(this, name), name);
178
+ };
179
+
180
+ HTMLImageElement.prototype.setAttribute = function (name, value) {
181
+ return nativeSetAttribute.call(getOfiImageMaybe(this, name), name, String(value));
182
+ };
183
+ }
184
+ }
185
+
186
+ function fix(imgs, opts) {
187
+ var startAutoMode = !autoModeEnabled && !imgs;
188
+ opts = opts || {};
189
+ imgs = imgs || 'img';
190
+
191
+ if ((supportsObjectPosition && !opts.skipTest) || !supportsOFI) {
192
+ return false;
193
+ }
194
+
195
+ // use imgs as a selector or just select all images
196
+ if (imgs === 'img') {
197
+ imgs = document.getElementsByTagName('img');
198
+ } else if (typeof imgs === 'string') {
199
+ imgs = document.querySelectorAll(imgs);
200
+ } else if (!('length' in imgs)) {
201
+ imgs = [imgs];
202
+ }
203
+
204
+ // apply fix to all
205
+ for (var i = 0; i < imgs.length; i++) {
206
+ imgs[i][OFI] = imgs[i][OFI] || {
207
+ skipTest: opts.skipTest
208
+ };
209
+ fixOne(imgs[i]);
210
+ }
211
+
212
+ if (startAutoMode) {
213
+ document.body.addEventListener('load', function (e) {
214
+ if (e.target.tagName === 'IMG') {
215
+ fix(e.target, {
216
+ skipTest: opts.skipTest
217
+ });
218
+ }
219
+ }, true);
220
+ autoModeEnabled = true;
221
+ imgs = 'img'; // reset to a generic selector for watchMQ
222
+ }
223
+
224
+ // if requested, watch media queries for object-fit change
225
+ if (opts.watchMQ) {
226
+ window.addEventListener('resize', fix.bind(null, imgs, {
227
+ skipTest: opts.skipTest
228
+ }));
229
+ }
230
+ }
231
+
232
+ fix.supportsObjectFit = supportsObjectFit;
233
+ fix.supportsObjectPosition = supportsObjectPosition;
234
+
235
+ hijackAttributes();
236
+
237
+ var ofi_commonJs = fix;
238
+
239
+ var ofi_commonJs$1 = /*@__PURE__*/getDefaultExportFromCjs(ofi_commonJs);
240
+
241
+ return ofi_commonJs$1;
242
+
243
+ })();
@@ -0,0 +1,546 @@
1
+ /*!
2
+ * Stickyfill – `position: sticky` polyfill
3
+ * v. 2.1.0 | https://github.com/wilddeer/stickyfill
4
+ * MIT License
5
+ */
6
+
7
+ ;(function(window, document) {
8
+ 'use strict';
9
+
10
+ /*
11
+ * 1. Check if the browser supports `position: sticky` natively or is too old to run the polyfill.
12
+ * If either of these is the case set `seppuku` flag. It will be checked later to disable key features
13
+ * of the polyfill, but the API will remain functional to avoid breaking things.
14
+ */
15
+
16
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
17
+
18
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
19
+
20
+ var seppuku = false;
21
+
22
+ var isWindowDefined = typeof window !== 'undefined';
23
+
24
+ // The polyfill can’t function properly without `window` or `window.getComputedStyle`.
25
+ if (!isWindowDefined || !window.getComputedStyle) seppuku = true;
26
+ // Dont’t get in a way if the browser supports `position: sticky` natively.
27
+ else {
28
+ (function () {
29
+ var testNode = document.createElement('div');
30
+
31
+ if (['', '-webkit-', '-moz-', '-ms-'].some(function (prefix) {
32
+ try {
33
+ testNode.style.position = prefix + 'sticky';
34
+ } catch (e) {}
35
+
36
+ return testNode.style.position != '';
37
+ })) seppuku = true;
38
+ })();
39
+ }
40
+
41
+ /*
42
+ * 2. “Global” vars used across the polyfill
43
+ */
44
+ var isInitialized = false;
45
+
46
+ // Check if Shadow Root constructor exists to make further checks simpler
47
+ var shadowRootExists = typeof ShadowRoot !== 'undefined';
48
+
49
+ // Last saved scroll position
50
+ var scroll = {
51
+ top: null,
52
+ left: null
53
+ };
54
+
55
+ // Array of created Sticky instances
56
+ var stickies = [];
57
+
58
+ /*
59
+ * 3. Utility functions
60
+ */
61
+ function extend(targetObj, sourceObject) {
62
+ for (var key in sourceObject) {
63
+ if (sourceObject.hasOwnProperty(key)) {
64
+ targetObj[key] = sourceObject[key];
65
+ }
66
+ }
67
+ }
68
+
69
+ function parseNumeric(val) {
70
+ return parseFloat(val) || 0;
71
+ }
72
+
73
+ function getDocOffsetTop(node) {
74
+ var docOffsetTop = 0;
75
+
76
+ while (node) {
77
+ docOffsetTop += node.offsetTop;
78
+ node = node.offsetParent;
79
+ }
80
+
81
+ return docOffsetTop;
82
+ }
83
+
84
+ /*
85
+ * 4. Sticky class
86
+ */
87
+
88
+ var Sticky = function () {
89
+ function Sticky(node) {
90
+ _classCallCheck(this, Sticky);
91
+
92
+ if (!(node instanceof HTMLElement)) throw new Error('First argument must be HTMLElement');
93
+ if (stickies.some(function (sticky) {
94
+ return sticky._node === node;
95
+ })) throw new Error('Stickyfill is already applied to this node');
96
+
97
+ this._node = node;
98
+ this._stickyMode = null;
99
+ this._active = false;
100
+
101
+ stickies.push(this);
102
+
103
+ this.refresh();
104
+ }
105
+
106
+ _createClass(Sticky, [{
107
+ key: 'refresh',
108
+ value: function refresh() {
109
+ if (seppuku || this._removed) return;
110
+ if (this._active) this._deactivate();
111
+
112
+ var node = this._node;
113
+
114
+ /*
115
+ * 1. Save node computed props
116
+ */
117
+ var nodeComputedStyle = getComputedStyle(node);
118
+ var nodeComputedProps = {
119
+ position: nodeComputedStyle.position,
120
+ top: nodeComputedStyle.top,
121
+ display: nodeComputedStyle.display,
122
+ marginTop: nodeComputedStyle.marginTop,
123
+ marginBottom: nodeComputedStyle.marginBottom,
124
+ marginLeft: nodeComputedStyle.marginLeft,
125
+ marginRight: nodeComputedStyle.marginRight,
126
+ cssFloat: nodeComputedStyle.cssFloat
127
+ };
128
+
129
+ /*
130
+ * 2. Check if the node can be activated
131
+ */
132
+ if (isNaN(parseFloat(nodeComputedProps.top)) || nodeComputedProps.display == 'table-cell' || nodeComputedProps.display == 'none') return;
133
+
134
+ this._active = true;
135
+
136
+ /*
137
+ * 3. Check if the current node position is `sticky`. If it is, it means that the browser supports sticky positioning,
138
+ * but the polyfill was force-enabled. We set the node’s position to `static` before continuing, so that the node
139
+ * is in it’s initial position when we gather its params.
140
+ */
141
+ var originalPosition = node.style.position;
142
+ if (nodeComputedStyle.position == 'sticky' || nodeComputedStyle.position == '-webkit-sticky') node.style.position = 'static';
143
+
144
+ /*
145
+ * 4. Get necessary node parameters
146
+ */
147
+ var referenceNode = node.parentNode;
148
+ var parentNode = shadowRootExists && referenceNode instanceof ShadowRoot ? referenceNode.host : referenceNode;
149
+ var nodeWinOffset = node.getBoundingClientRect();
150
+ var parentWinOffset = parentNode.getBoundingClientRect();
151
+ var parentComputedStyle = getComputedStyle(parentNode);
152
+
153
+ this._parent = {
154
+ node: parentNode,
155
+ styles: {
156
+ position: parentNode.style.position
157
+ },
158
+ offsetHeight: parentNode.offsetHeight
159
+ };
160
+ this._offsetToWindow = {
161
+ left: nodeWinOffset.left,
162
+ right: document.documentElement.clientWidth - nodeWinOffset.right
163
+ };
164
+ this._offsetToParent = {
165
+ top: nodeWinOffset.top - parentWinOffset.top - parseNumeric(parentComputedStyle.borderTopWidth),
166
+ left: nodeWinOffset.left - parentWinOffset.left - parseNumeric(parentComputedStyle.borderLeftWidth),
167
+ right: -nodeWinOffset.right + parentWinOffset.right - parseNumeric(parentComputedStyle.borderRightWidth)
168
+ };
169
+ this._styles = {
170
+ position: originalPosition,
171
+ top: node.style.top,
172
+ bottom: node.style.bottom,
173
+ left: node.style.left,
174
+ right: node.style.right,
175
+ width: node.style.width,
176
+ marginTop: node.style.marginTop,
177
+ marginLeft: node.style.marginLeft,
178
+ marginRight: node.style.marginRight
179
+ };
180
+
181
+ var nodeTopValue = parseNumeric(nodeComputedProps.top);
182
+ this._limits = {
183
+ start: nodeWinOffset.top + window.pageYOffset - nodeTopValue,
184
+ end: parentWinOffset.top + window.pageYOffset + parentNode.offsetHeight - parseNumeric(parentComputedStyle.borderBottomWidth) - node.offsetHeight - nodeTopValue - parseNumeric(nodeComputedProps.marginBottom)
185
+ };
186
+
187
+ /*
188
+ * 5. Ensure that the node will be positioned relatively to the parent node
189
+ */
190
+ var parentPosition = parentComputedStyle.position;
191
+
192
+ if (parentPosition != 'absolute' && parentPosition != 'relative') {
193
+ parentNode.style.position = 'relative';
194
+ }
195
+
196
+ /*
197
+ * 6. Recalc node position.
198
+ * It’s important to do this before clone injection to avoid scrolling bug in Chrome.
199
+ */
200
+ this._recalcPosition();
201
+
202
+ /*
203
+ * 7. Create a clone
204
+ */
205
+ var clone = this._clone = {};
206
+ clone.node = document.createElement('div');
207
+
208
+ // Apply styles to the clone
209
+ extend(clone.node.style, {
210
+ width: nodeWinOffset.right - nodeWinOffset.left + 'px',
211
+ height: nodeWinOffset.bottom - nodeWinOffset.top + 'px',
212
+ marginTop: nodeComputedProps.marginTop,
213
+ marginBottom: nodeComputedProps.marginBottom,
214
+ marginLeft: nodeComputedProps.marginLeft,
215
+ marginRight: nodeComputedProps.marginRight,
216
+ cssFloat: nodeComputedProps.cssFloat,
217
+ padding: 0,
218
+ border: 0,
219
+ borderSpacing: 0,
220
+ fontSize: '1em',
221
+ position: 'static'
222
+ });
223
+
224
+ referenceNode.insertBefore(clone.node, node);
225
+ clone.docOffsetTop = getDocOffsetTop(clone.node);
226
+ }
227
+ }, {
228
+ key: '_recalcPosition',
229
+ value: function _recalcPosition() {
230
+ if (!this._active || this._removed) return;
231
+
232
+ var stickyMode = scroll.top <= this._limits.start ? 'start' : scroll.top >= this._limits.end ? 'end' : 'middle';
233
+
234
+ if (this._stickyMode == stickyMode) return;
235
+
236
+ switch (stickyMode) {
237
+ case 'start':
238
+ extend(this._node.style, {
239
+ position: 'absolute',
240
+ left: this._offsetToParent.left + 'px',
241
+ right: this._offsetToParent.right + 'px',
242
+ top: this._offsetToParent.top + 'px',
243
+ bottom: 'auto',
244
+ width: 'auto',
245
+ marginLeft: 0,
246
+ marginRight: 0,
247
+ marginTop: 0
248
+ });
249
+ break;
250
+
251
+ case 'middle':
252
+ extend(this._node.style, {
253
+ position: 'fixed',
254
+ left: this._offsetToWindow.left + 'px',
255
+ right: this._offsetToWindow.right + 'px',
256
+ top: this._styles.top,
257
+ bottom: 'auto',
258
+ width: 'auto',
259
+ marginLeft: 0,
260
+ marginRight: 0,
261
+ marginTop: 0
262
+ });
263
+ break;
264
+
265
+ case 'end':
266
+ extend(this._node.style, {
267
+ position: 'absolute',
268
+ left: this._offsetToParent.left + 'px',
269
+ right: this._offsetToParent.right + 'px',
270
+ top: 'auto',
271
+ bottom: 0,
272
+ width: 'auto',
273
+ marginLeft: 0,
274
+ marginRight: 0
275
+ });
276
+ break;
277
+ }
278
+
279
+ this._stickyMode = stickyMode;
280
+ }
281
+ }, {
282
+ key: '_fastCheck',
283
+ value: function _fastCheck() {
284
+ if (!this._active || this._removed) return;
285
+
286
+ if (Math.abs(getDocOffsetTop(this._clone.node) - this._clone.docOffsetTop) > 1 || Math.abs(this._parent.node.offsetHeight - this._parent.offsetHeight) > 1) this.refresh();
287
+ }
288
+ }, {
289
+ key: '_deactivate',
290
+ value: function _deactivate() {
291
+ var _this = this;
292
+
293
+ if (!this._active || this._removed) return;
294
+
295
+ this._clone.node.parentNode.removeChild(this._clone.node);
296
+ delete this._clone;
297
+
298
+ extend(this._node.style, this._styles);
299
+ delete this._styles;
300
+
301
+ // Check whether element’s parent node is used by other stickies.
302
+ // If not, restore parent node’s styles.
303
+ if (!stickies.some(function (sticky) {
304
+ return sticky !== _this && sticky._parent && sticky._parent.node === _this._parent.node;
305
+ })) {
306
+ extend(this._parent.node.style, this._parent.styles);
307
+ }
308
+ delete this._parent;
309
+
310
+ this._stickyMode = null;
311
+ this._active = false;
312
+
313
+ delete this._offsetToWindow;
314
+ delete this._offsetToParent;
315
+ delete this._limits;
316
+ }
317
+ }, {
318
+ key: 'remove',
319
+ value: function remove() {
320
+ var _this2 = this;
321
+
322
+ this._deactivate();
323
+
324
+ stickies.some(function (sticky, index) {
325
+ if (sticky._node === _this2._node) {
326
+ stickies.splice(index, 1);
327
+ return true;
328
+ }
329
+ });
330
+
331
+ this._removed = true;
332
+ }
333
+ }]);
334
+
335
+ return Sticky;
336
+ }();
337
+
338
+ /*
339
+ * 5. Stickyfill API
340
+ */
341
+
342
+
343
+ var Stickyfill = {
344
+ stickies: stickies,
345
+ Sticky: Sticky,
346
+
347
+ forceSticky: function forceSticky() {
348
+ seppuku = false;
349
+ init();
350
+
351
+ this.refreshAll();
352
+ },
353
+ addOne: function addOne(node) {
354
+ // Check whether it’s a node
355
+ if (!(node instanceof HTMLElement)) {
356
+ // Maybe it’s a node list of some sort?
357
+ // Take first node from the list then
358
+ if (node.length && node[0]) node = node[0];else return;
359
+ }
360
+
361
+ // Check if Stickyfill is already applied to the node
362
+ // and return existing sticky
363
+ for (var i = 0; i < stickies.length; i++) {
364
+ if (stickies[i]._node === node) return stickies[i];
365
+ }
366
+
367
+ // Create and return new sticky
368
+ return new Sticky(node);
369
+ },
370
+ add: function add(nodeList) {
371
+ // If it’s a node make an array of one node
372
+ if (nodeList instanceof HTMLElement) nodeList = [nodeList];
373
+ // Check if the argument is an iterable of some sort
374
+ if (!nodeList.length) return;
375
+
376
+ // Add every element as a sticky and return an array of created Sticky instances
377
+ var addedStickies = [];
378
+
379
+ var _loop = function _loop(i) {
380
+ var node = nodeList[i];
381
+
382
+ // If it’s not an HTMLElement – create an empty element to preserve 1-to-1
383
+ // correlation with input list
384
+ if (!(node instanceof HTMLElement)) {
385
+ addedStickies.push(void 0);
386
+ return 'continue';
387
+ }
388
+
389
+ // If Stickyfill is already applied to the node
390
+ // add existing sticky
391
+ if (stickies.some(function (sticky) {
392
+ if (sticky._node === node) {
393
+ addedStickies.push(sticky);
394
+ return true;
395
+ }
396
+ })) return 'continue';
397
+
398
+ // Create and add new sticky
399
+ addedStickies.push(new Sticky(node));
400
+ };
401
+
402
+ for (var i = 0; i < nodeList.length; i++) {
403
+ var _ret2 = _loop(i);
404
+
405
+ if (_ret2 === 'continue') continue;
406
+ }
407
+
408
+ return addedStickies;
409
+ },
410
+ refreshAll: function refreshAll() {
411
+ stickies.forEach(function (sticky) {
412
+ return sticky.refresh();
413
+ });
414
+ },
415
+ removeOne: function removeOne(node) {
416
+ // Check whether it’s a node
417
+ if (!(node instanceof HTMLElement)) {
418
+ // Maybe it’s a node list of some sort?
419
+ // Take first node from the list then
420
+ if (node.length && node[0]) node = node[0];else return;
421
+ }
422
+
423
+ // Remove the stickies bound to the nodes in the list
424
+ stickies.some(function (sticky) {
425
+ if (sticky._node === node) {
426
+ sticky.remove();
427
+ return true;
428
+ }
429
+ });
430
+ },
431
+ remove: function remove(nodeList) {
432
+ // If it’s a node make an array of one node
433
+ if (nodeList instanceof HTMLElement) nodeList = [nodeList];
434
+ // Check if the argument is an iterable of some sort
435
+ if (!nodeList.length) return;
436
+
437
+ // Remove the stickies bound to the nodes in the list
438
+
439
+ var _loop2 = function _loop2(i) {
440
+ var node = nodeList[i];
441
+
442
+ stickies.some(function (sticky) {
443
+ if (sticky._node === node) {
444
+ sticky.remove();
445
+ return true;
446
+ }
447
+ });
448
+ };
449
+
450
+ for (var i = 0; i < nodeList.length; i++) {
451
+ _loop2(i);
452
+ }
453
+ },
454
+ removeAll: function removeAll() {
455
+ while (stickies.length) {
456
+ stickies[0].remove();
457
+ }
458
+ }
459
+ };
460
+
461
+ /*
462
+ * 6. Setup events (unless the polyfill was disabled)
463
+ */
464
+ function init() {
465
+ if (isInitialized) {
466
+ return;
467
+ }
468
+
469
+ isInitialized = true;
470
+
471
+ // Watch for scroll position changes and trigger recalc/refresh if needed
472
+ function checkScroll() {
473
+ if (window.pageXOffset != scroll.left) {
474
+ scroll.top = window.pageYOffset;
475
+ scroll.left = window.pageXOffset;
476
+
477
+ Stickyfill.refreshAll();
478
+ } else if (window.pageYOffset != scroll.top) {
479
+ scroll.top = window.pageYOffset;
480
+ scroll.left = window.pageXOffset;
481
+
482
+ // recalc position for all stickies
483
+ stickies.forEach(function (sticky) {
484
+ return sticky._recalcPosition();
485
+ });
486
+ }
487
+ }
488
+
489
+ checkScroll();
490
+ window.addEventListener('scroll', checkScroll);
491
+
492
+ // Watch for window resizes and device orientation changes and trigger refresh
493
+ window.addEventListener('resize', Stickyfill.refreshAll);
494
+ window.addEventListener('orientationchange', Stickyfill.refreshAll);
495
+
496
+ //Fast dirty check for layout changes every 500ms
497
+ var fastCheckTimer = void 0;
498
+
499
+ function startFastCheckTimer() {
500
+ fastCheckTimer = setInterval(function () {
501
+ stickies.forEach(function (sticky) {
502
+ return sticky._fastCheck();
503
+ });
504
+ }, 500);
505
+ }
506
+
507
+ function stopFastCheckTimer() {
508
+ clearInterval(fastCheckTimer);
509
+ }
510
+
511
+ var docHiddenKey = void 0;
512
+ var visibilityChangeEventName = void 0;
513
+
514
+ if ('hidden' in document) {
515
+ docHiddenKey = 'hidden';
516
+ visibilityChangeEventName = 'visibilitychange';
517
+ } else if ('webkitHidden' in document) {
518
+ docHiddenKey = 'webkitHidden';
519
+ visibilityChangeEventName = 'webkitvisibilitychange';
520
+ }
521
+
522
+ if (visibilityChangeEventName) {
523
+ if (!document[docHiddenKey]) startFastCheckTimer();
524
+
525
+ document.addEventListener(visibilityChangeEventName, function () {
526
+ if (document[docHiddenKey]) {
527
+ stopFastCheckTimer();
528
+ } else {
529
+ startFastCheckTimer();
530
+ }
531
+ });
532
+ } else startFastCheckTimer();
533
+ }
534
+
535
+ if (!seppuku) init();
536
+
537
+ /*
538
+ * 7. Expose Stickyfill
539
+ */
540
+ if (typeof module != 'undefined' && module.exports) {
541
+ module.exports = Stickyfill;
542
+ } else if (isWindowDefined) {
543
+ window.Stickyfill = Stickyfill;
544
+ }
545
+
546
+ })(window, document);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pageboard/html",
3
- "version": "0.14.39",
3
+ "version": "0.15.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -16,7 +16,7 @@
16
16
  "dependencies": {},
17
17
  "devDependencies": {
18
18
  "nouislider": "^15.7.1",
19
- "postinstall": "^0.9.0"
19
+ "postinstall": "^0.10.3"
20
20
  },
21
21
  "postinstall": {},
22
22
  "prepare": {
package/ui/image.js CHANGED
@@ -9,27 +9,20 @@ const HTMLElementImageConstructor = Superclass => class extends Superclass {
9
9
 
10
10
  #defer;
11
11
 
12
- static getZoom({ w, h, rw, rh, fit }) {
13
- let z = 100;
14
- if (!rw && !rh) return z;
15
- if (!rw) rw = rh * w / h;
16
- if (!rh) rh = rw * h / w;
17
- z = Math.ceil((fit == "contain" ? Math.min : Math.max)(rw / w, rh / h) * 100 * (window.devicePixelRatio || 1));
18
- // svg need to be resized to scale to its intrinsic dimension
19
- if (z > 100) z = 100;
20
- const zstep = 5;
21
- z = Math.ceil(z / zstep) * zstep;
22
- return z;
23
- }
24
12
  get dimensions() {
13
+ // dimension in pixels of the (extracted) source image
25
14
  let w = parseInt(this.dataset.width);
26
15
  let h = parseInt(this.dataset.height);
27
- const r = this.crop;
28
- w = Math.round(w * r.w / 100);
29
- h = Math.round(h * r.h / 100);
30
- if (r.z != 100 && this.fit == "none") {
31
- w = Math.round(w * r.z / 100);
32
- h = Math.round(h * r.z / 100);
16
+ const { crop } = this;
17
+ if (crop.w != 100) {
18
+ w = Math.round(w * crop.w / 100);
19
+ }
20
+ if (crop.h != 100) {
21
+ h = Math.round(h * crop.h / 100);
22
+ }
23
+ if (crop.z != 100) {
24
+ w = Math.round(w * crop.z / 100);
25
+ h = Math.round(h * crop.z / 100);
33
26
  }
34
27
  return { w, h };
35
28
  }
@@ -53,12 +46,12 @@ const HTMLElementImageConstructor = Superclass => class extends Superclass {
53
46
  });
54
47
  }
55
48
  get crop() {
56
- let [x, y, w, h, z] = (this.dataset.crop || ";;;;").split(";").map(x => parseFloat(x));
57
- if (Number.isNaN(x)) x = 50;
58
- if (Number.isNaN(y)) y = 50;
59
- if (Number.isNaN(w)) w = 100;
60
- if (Number.isNaN(h)) h = 100;
61
- if (Number.isNaN(z)) z = 100;
49
+ const defs = [50, 50, 100, 100, 100];
50
+ const list = (this.dataset.crop || ";;;;").split(";").map(x => parseFloat(x));
51
+ for (let i = 0; i < defs.length; i++) {
52
+ if (Number.isNaN(list[i])) list[i] = defs[i];
53
+ }
54
+ const [x, y, w, h, z] = list;
62
55
  return { x, y, w, h, z };
63
56
  }
64
57
  set crop({ x, y, w, h, z }) {
@@ -99,6 +92,44 @@ const HTMLElementImageConstructor = Superclass => class extends Superclass {
99
92
  else return src;
100
93
  }
101
94
 
95
+ requestSrc(srcLoc) {
96
+ const { crop, fit } = this;
97
+ const { w, h } = this.dimensions;
98
+ const r = {};
99
+ if (!Number.isNaN(w) && !Number.isNaN(h)) {
100
+ if (fit == "none") {
101
+ r.width = w;
102
+ r.height = h;
103
+ } else {
104
+ const rect = this.getBoundingClientRect();
105
+ r.width = rect.width;
106
+ r.height = rect.height;
107
+ }
108
+ }
109
+ if (!r.width && !r.height) {
110
+ // don't show
111
+ return;
112
+ }
113
+ if (crop.x != 50 || crop.y != 50 || crop.w != 100 || crop.h != 100) {
114
+ if (Math.round((crop.x - crop.w / 2) * 100) < 0 || Math.round((crop.x + crop.w / 2) * 100) > 10000) {
115
+ crop.w = 2 * Math.min(crop.x, 100 - crop.x);
116
+ }
117
+ if (Math.round((crop.y - crop.h / 2) * 100) < 0 || Math.round((crop.y + crop.h / 2) * 100) > 10000) {
118
+ crop.h = 2 * Math.min(crop.y, 100 - crop.y);
119
+ }
120
+ srcLoc.query.ex = `x-${crop.x}_y-${crop.y}_w-${crop.w}_h-${crop.h}`;
121
+ }
122
+
123
+ if (!r.width) r.width = r.height * w / h;
124
+ if (!r.height) r.height = r.width * h / w;
125
+ const clientHintWidth = Math.ceil(
126
+ (fit == "contain" ? Math.min : Math.max)(r.width / w, r.height / h)
127
+ * w * (window.devicePixelRatio || 1)
128
+ );
129
+ srcLoc.query.rs = `w-${clientHintWidth}`; // max, min ?
130
+ return srcLoc.toString();
131
+ }
132
+
102
133
  reveal(state) {
103
134
  const img = this.image;
104
135
  if (!this.options.src) {
@@ -108,47 +139,15 @@ const HTMLElementImageConstructor = Superclass => class extends Superclass {
108
139
  if (this.classList.contains('loading')) {
109
140
  return;
110
141
  }
111
- const fit = this.fit;
112
- const r = this.crop;
113
-
114
- let loc = Page.parse(this.options.src);
115
- if (loc.hostname && loc.hostname != document.location.hostname) {
116
- loc = Page.parse({
117
- pathname: "/.api/image",
118
- query: {
119
- url: this.options.src
120
- }
121
- });
122
- }
123
-
124
- if (r.x != 50 || r.y != 50 || r.w != 100 || r.h != 100) {
125
- if (Math.round((r.x - r.w / 2) * 100) < 0 || Math.round((r.x + r.w / 2) * 100) > 10000) {
126
- r.w = 2 * Math.min(r.x, 100 - r.x);
127
- }
128
- if (Math.round((r.y - r.h / 2) * 100) < 0 || Math.round((r.y + r.h / 2) * 100) > 10000) {
129
- r.h = 2 * Math.min(r.y, 100 - r.y);
130
- }
131
- loc.query.ex = `x-${r.x}_y-${r.y}_w-${r.w}_h-${r.h}`;
132
- }
133
- const { w, h } = this.dimensions;
134
- if (fit == "none") {
135
- loc.query.rs = `z-${r.z}`;
136
- } else if (!Number.isNaN(w) && !Number.isNaN(h)) {
137
- const rect = this.getBoundingClientRect();
138
- const rw = rect.width;
139
- const rh = rect.height;
140
- if (rw == 0 && rh == 0) {
141
- // don't show
142
- return;
143
- }
144
- loc.query.rs = "z-" + this.constructor.getZoom({ w, h, rw, rh, fit });
145
- }
146
- const curSrc = loc.toString();
147
- if (curSrc != this.currentSrc) {
142
+ const srcLoc = Page.parse(this.options.src);
143
+ const reqSrc = this.requestSrc(srcLoc);
144
+ if (!reqSrc) {
145
+ img.setAttribute('src', '');
146
+ } else if (reqSrc != this.currentSrc) {
148
147
  this.classList.add('loading');
149
148
  this.#defer?.resolve();
150
149
  this.#defer = new Deferred();
151
- img.setAttribute('src', curSrc);
150
+ img.setAttribute('src', reqSrc);
152
151
  return this.#defer;
153
152
  }
154
153
  }
package/ui/input-file.js CHANGED
@@ -73,9 +73,10 @@ class HTMLElementInputFile extends Page.create(HTMLInputElement) {
73
73
  this.#defer = null;
74
74
  };
75
75
  const pass = (obj) => {
76
- if (!obj.items || obj.items.length == 0) return fail(new Error("File rejected"));
77
- const val = obj.items[0];
78
- this.value = val;
76
+ if (!obj.hrefs?.length) {
77
+ return fail(new Error("File rejected"));
78
+ }
79
+ this.value = obj.hrefs[0]?.pathname;
79
80
  field.classList.add('success');
80
81
  field.classList.remove('loading');
81
82
  this.#xhr = null;
@@ -124,7 +125,7 @@ class HTMLElementInputFile extends Page.create(HTMLInputElement) {
124
125
  fail(err);
125
126
  });
126
127
  try {
127
- xhr.open("POST", `/.api/upload/${this.id}`, true);
128
+ xhr.open("POST", `/@api/upload/${this.id}`, true);
128
129
  xhr.setRequestHeader('Accept', "application/json; q=1.0");
129
130
  xhr.send(fd);
130
131
  this.#xhr = xhr;
package/ui/layout.js CHANGED
@@ -14,48 +14,16 @@ class HTMLElementLayout extends Page.create(HTMLDivElement) {
14
14
  this.style.backgroundImage = '';
15
15
  return;
16
16
  }
17
- const fit = this.fit;
18
- const r = this.crop;
19
-
20
- let loc = Page.parse(this.options.src);
21
- if (loc.hostname && loc.hostname != document.location.hostname) {
22
- loc = Page.parse({
23
- pathname: "/.api/image",
24
- query: {
25
- url: this.options.src
26
- }
27
- });
28
- }
29
-
30
- if (r.x != 50 || r.y != 50 || r.w != 100 || r.h != 100) {
31
- if (Math.round((r.x - r.w / 2) * 100) < 0 || Math.round((r.x + r.w / 2) * 100) > 10000) {
32
- r.w = 2 * Math.min(r.x, 100 - r.x);
33
- }
34
- if (Math.round((r.y - r.h / 2) * 100) < 0 || Math.round((r.y + r.h / 2) * 100) > 10000) {
35
- r.h = 2 * Math.min(r.y, 100 - r.y);
36
- }
37
- loc.query.ex = `x-${r.x}_y-${r.y}_w-${r.w}_h-${r.h}`;
38
- }
39
- const {w, h} = this.dimensions;
40
- if (fit == "none") {
41
- loc.query.rs = `z-${r.z}`;
42
- } else if (!Number.isNaN(w) && !Number.isNaN(h)) {
43
- const rect = this.getBoundingClientRect();
44
- const rw = rect.width;
45
- const rh = rect.height;
46
- if (rw == 0 && rh == 0) {
47
- // don't show
48
- return;
49
- }
50
- loc.query.rs = "z-" + HTMLElementLayout.getZoom({w, h, rw, rh, fit});
17
+ const srcLoc = Page.parse(this.options.src);
18
+ const reqSrc = this.requestSrc(srcLoc);
19
+ try {
20
+ this.currentSrc = reqSrc;
21
+ } catch (e) {
22
+ // pass
51
23
  }
52
- const curSrc = loc.toString();
53
- if (curSrc != this.currentSrc) {
54
- try {
55
- this.currentSrc = curSrc;
56
- } catch(e) {
57
- // pass
58
- }
24
+ if (!reqSrc) {
25
+ this.style.backgroundImage = '';
26
+ } else if (reqSrc != this.currentSrc) {
59
27
  this.#defer?.resolve();
60
28
  this.#defer = new Deferred();
61
29
  const img = new Image();
@@ -63,8 +31,8 @@ class HTMLElementLayout extends Page.create(HTMLDivElement) {
63
31
  img.addEventListener('error',
64
32
  e => this.#defer.reject(new Error(this.currentSrc))
65
33
  );
66
- img.src = curSrc;
67
- this.style.backgroundImage = `url("${curSrc}")`;
34
+ img.src = reqSrc;
35
+ this.style.backgroundImage = `url("${reqSrc}")`;
68
36
  return this.#defer;
69
37
  }
70
38
  }
@@ -74,14 +42,13 @@ class HTMLElementLayout extends Page.create(HTMLDivElement) {
74
42
  }
75
43
 
76
44
  (function(HTMLElementImage) {
77
- HTMLElementLayout.getZoom = HTMLElementImage.getZoom;
78
- for (const name of ['crop', 'dimensions']) {
79
- Object.defineProperty(
80
- HTMLElementLayout.prototype,
81
- name,
82
- Object.getOwnPropertyDescriptor(HTMLElementImage.prototype, name)
83
- );
84
- }
45
+ for (const name of ['crop', 'dimensions', 'requestSrc']) {
46
+ Object.defineProperty(
47
+ HTMLElementLayout.prototype,
48
+ name,
49
+ Object.getOwnPropertyDescriptor(HTMLElementImage.prototype, name)
50
+ );
51
+ }
85
52
  })(window.customElements.get('element-image'));
86
53
 
87
54
  Page.define(`element-layout`, HTMLElementLayout, 'div');
package/ui/pagination.js CHANGED
@@ -9,7 +9,7 @@ class HTMLElementPagination extends Page.create(HTMLAnchorElement) {
9
9
  #update(state) {
10
10
  const { fetch } = this.dataset;
11
11
  const node = this.ownerDocument.querySelector(
12
- `element-template[action="/.api/query/${fetch}"]`
12
+ `element-template[action="/@api/query/${fetch}"]`
13
13
  );
14
14
  if (!node) {
15
15
  console.warn("pagination does not find fetch node", fetch);