- From: Domenic Denicola <notifications@github.com>
- Date: Tue, 14 Dec 2021 08:42:10 -0800
- To: w3c/clipboard-apis <clipboard-apis@noreply.github.com>
- Cc: Subscribed <subscribed@noreply.github.com>
- Message-ID: <w3c/clipboard-apis/pull/158/review/831736786@github.com>
@domenic commented on this pull request. > + </p> + + Each of these [=/MIME type=]s describe a different [=representation=] of the same [=clipboard item=] at different levels of fidelity and make the [=clipboard item=] more consumable by target applications during paste. + + <p class=note> + Making the range of cells available as an image will allow the user to paste the cells into a photo editing app, while the text/plain format can be used by text editor apps. + </p> + + A [=clipboard item=] can also optionally have a <dfn>presentation style</dfn> that helps distinguish whether apps "pasting" a [=clipboard item=] should insert the contents of an appropriate [=representation=] inline at the point of paste or if it should be treated as an attachment. + + Apps that support pasting only a single [=clipboard item=] should use the first [=clipboard item=]. + Apps that support pasting more than one [=clipboard item=] could, for example, provide a user interface that previews the contents of each [=clipboard item=] and allow the user to choose which one to paste. + Further, apps are expected to enumerate the [=/MIME type=]s of the [=clipboard item=] they are pasting and select the one best-suited for the app according to some app-specific algorithm. + Alternatively, an app can present the user with options on how to paste a [=clipboard item=], e.g. "paste as image" or "paste formatted text", etc. + + A {{ClipboardItem}} object has an associated <dfn for="ClipboardItem">clipboardItem</dfn>, which is a [=clipboard item=]. This change is not great. You should instead keep the names in normal style, i.e. "clipboard item", and then make sure you qualify every reference as either `[=/clipboard item=]` (the type) or `[=ClipboardItem/clipboard item=]` the internal slot. > + <p class=note> + Making the range of cells available as an image will allow the user to paste the cells into a photo editing app, while the text/plain format can be used by text editor apps. + </p> + + A [=clipboard item=] can also optionally have a <dfn>presentation style</dfn> that helps distinguish whether apps "pasting" a [=clipboard item=] should insert the contents of an appropriate [=representation=] inline at the point of paste or if it should be treated as an attachment. + + Apps that support pasting only a single [=clipboard item=] should use the first [=clipboard item=]. + Apps that support pasting more than one [=clipboard item=] could, for example, provide a user interface that previews the contents of each [=clipboard item=] and allow the user to choose which one to paste. + Further, apps are expected to enumerate the [=/MIME type=]s of the [=clipboard item=] they are pasting and select the one best-suited for the app according to some app-specific algorithm. + Alternatively, an app can present the user with options on how to paste a [=clipboard item=], e.g. "paste as image" or "paste formatted text", etc. + + A {{ClipboardItem}} object has an associated <dfn for="ClipboardItem">clipboardItem</dfn>, which is a [=clipboard item=]. + + A {{ClipboardItem}} object has an associated <dfn for="ClipboardItem">types array</dfn>, which is a {{FrozenArray}}. + + To <dfn>create a {{ClipboardItem}} object</dfn>, given a [=clipboard item=] |clipboardItem| and a [=global object/Realm=] |realm|, run these steps: ```suggestion To <dfn>create a {{ClipboardItem}} object</dfn>, given a [=clipboard item=] |clipboardItem| and a Realm |realm|, run these steps: ``` You are not referring to the "realm" internal slot of "global object". You are referring to the general concept of Realm. > + + 1. Let |p1| be the |representation|'s [=representation/data=]. + + 1. [=promise/React=] to |p1|: + + 1. If |p1| was fulfilled with value |v|, then: + + 1. If |v| is a {{DOMString}}, then follow the below steps: + + 1. Let |v1| be the result of [=/encoding=] |v|. + + 1. Let |blobData| be a [=Blob=] created using |v1| with its {{Blob/type}} set to |mimeType|, [=serialize a MIME type|serialized=]. + + 1. Resolve |p| with |blobData|. + + 1. Return |p|. You shouldn't return |p| from within these steps, since they're reaction steps. You can just return |p| at the end, like you are doing. So just delete all the "Return |p|" steps before the end. > - dictionary ClipboardItemOptions { - PresentationStyle presentationStyle = "unspecified"; + 1. Resolve |p| with |v|. + + 1. Return |p|. + + 1. If |p1| was rejected, then: + + 1. [=Reject=] |p| with {{"NotFoundError"}} DOMException in |realm|. Interesting. Are you sure you don't want to pass along the rejection reason? Your version here is valid but it's a bit surprising we would not expose that potentially-useful rejection information to the developer. > - dictionary ClipboardItemOptions { - PresentationStyle presentationStyle = "unspecified"; + 1. Resolve |p| with |v|. To double-check, this means that if someone does ```js const blob = new Blob(["hello", { type: "text/plain" }]); const promise = Promise.resolve(blob); const clipboardItem = new ClipboardItem({ "text/plain": promise }); const resultBlob = await clipboardItem.getType("text/plain"); ``` then `resultBlob === blob`. Is this intended? If so, make sure you have tests for this case. > + + 1. Let |mimeType| be the result of [=parsing a MIME type=] given |type|. + + 1. If |mimeType| is failure, then throw a {{TypeError}}. + + 1. Let |itemTypeList| be [=this=]'s [=ClipboardItem/clipboardItem=]'s [=list of representations=]. + + 1. Let |p| be [=a new promise=] in |realm|. + + 1. For each |representation| in |itemTypeList|: + + 1. If |representation|'s [=representation/MIME type=] is |mimeType|, then: + + 1. Let |p1| be the |representation|'s [=representation/data=]. + + 1. [=promise/React=] to |p1|: No need to indent this further; it should be a sibling step with "Let p1 be..." > - dictionary ClipboardItemOptions { - PresentationStyle presentationStyle = "unspecified"; + 1. Resolve |p| with |v|. + + 1. Return |p|. + + 1. If |p1| was rejected, then: + + 1. [=Reject=] |p| with {{"NotFoundError"}} DOMException in |realm|. ```suggestion 1. [=Reject=] |p| with {{"NotFoundError"}} {{DOMException}} in |realm|. ``` > - dictionary ClipboardItemOptions { - PresentationStyle presentationStyle = "unspecified"; + 1. Resolve |p| with |v|. + + 1. Return |p|. + + 1. If |p1| was rejected, then: + + 1. [=Reject=] |p| with {{"NotFoundError"}} DOMException in |realm|. + + 1. Return |p|. + + 1. [=Reject=] |p| with {{"NotFoundError"}} DOMException in |realm|. ```suggestion 1. [=Reject=] |p| with {{"NotFoundError"}} {{DOMException}} in |realm|. ``` > 1. Run the following steps [=in parallel=]: - 1. Let |r| be the result of running [=check clipboard read permission=] [=in parallel=] + 1. Let |r| be the result of running [=check clipboard read permission=]. + + Note: Clipboard permission is not supported on Safari. However, the read() method must be called inside + a user gesture event and the user must select the paste option from the native context menu that pops up + when read() is called from JS, otherwise, the promise will be rejected. + + 1. If |r| is false, then: + + 1. [=Queue a global task=] on the [=permission task source=], given |realm|'s [=Realm/global object=], to [=reject=] |p| with {{"NotAllowedError"}} DOMException in |realm|. ```suggestion 1. [=Queue a global task=] on the [=permission task source=], given |realm|'s [=Realm/global object=], to [=reject=] |p| with {{"NotAllowedError"}} {{DOMException}} in |realm|. ``` > - 1. If |data| contains a "text/plain" item |textItem|, then: + 1. If |data| contains a "text/plain" item |textItem|, then: The algorithm starts to get a bit fuzzy here. That's understandable given how our model might not match exactly to the operating system, but we can tighten it up a bit. Some things we should do: - We should phrase `|data| contains a "text/plain" item |textItem|` better, by explicitly inspecting `|data|'s [=list of representations=]` and seeing if any of the representations contain something with a `text/plain` `[=representation/MIME type=]` - We should state the exact criteria for the MIME type matching. Should it match `text/plain;someparam=somevalue`? Just `text/plain`? What about `text/css`? - We need to handle the case where there is no such text representation. Do you reject the promise? Right now the spec leaves the promise pending forever. - We need to handle the fact that, in our model, `[=representation/data=]` is not really a string; it's a `Promise<(Blob or DOMString)>`. So you need to do something similar to what you did in `getType()`, where once you get the data, you react to it, and handle the cases where it rejects, etc. > - 1. Resolve |p|. + 1. Let |type| be the |blob|'s {{Blob/type}}. + + 1. If |type| is not in the [=mandatory data types=] list, then [=reject=] |p| with {{"NotAllowedError"}} DOMException in |realm|. Probably you also want "and abort these steps"? > + + 1. If |type| is not in the [=mandatory data types=] list, then [=reject=] |p| with {{"NotAllowedError"}} DOMException in |realm|. + + 1. Let |cleanItem| be a sanitized copy of |blob|. + + Issue: Add definition of sanitized copy. + + 1. If unable to create a sanitized copy, then follow the below steps: + + 1. [=Reject=] |p| with {{"NotAllowedError"}} DOMException in |realm|. + + 1. Return |p|. + + 1. Add |cleanItem| to |cleanItemList|. + + 1. Add |cleanItemList| to |clipboardItemList|. So here you are appending a `sequence<Blob>` to a list of clipboard items. That doesn't seem right. > + 1. Let |clipboardItemObject| be a [=new=] {{ClipboardItem}} with |realm|. + + 1. Set |clipboardItemObject|'s [=clipboard item=] to |clipboardItem|. + + The <dfn constructor for="ClipboardItem" lt="ClipboardItem(items, options)"><code>new ClipboardItem(<var>items</var>, <var>options</var>)</code></dfn> constructor steps are: + 1. Set [=this=]'s [=ClipboardItem/clipboardItem=] to a new [=clipboard item=]. + + 1. Set [=this=]'s [=ClipboardItem/clipboardItem=]'s [=presentation style=] to |options|["{{ClipboardItemOptions/presentationStyle}}"]. + + 1. Let |types| be a list of {{DOMString}}. + + 1. For each (|key|, |value|) in |items|: + + 1. Let |mimeType| be the result of [=parsing a MIME type=] given |key|. + + 1. If |mimeType| is failure, then throw a {{TypeError}}. That's a good thing to spot. So to be clear, you are suggesting that if you include two duplicates, the implementation must throw: e.g., `{ "text/html": x, "TEXT/HTML": y }`. The current spec would have the later one win. I'm not sure which semantics are desired. If you did want to go for throwing, I would suggest not doing the `|listOfRepresentations|` alias, but instead just inserting `If [=this=]'s [=ClipboardItem/clipboard item=]'s [=list of representations=] [=list/contains=] |mimeType|, then throw a {{TypeError}}`. -- You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub: https://github.com/w3c/clipboard-apis/pull/158#pullrequestreview-831736786
Received on Tuesday, 14 December 2021 16:42:25 UTC