From 0331a1cbdfb184827f5aa98cbc88ea0c8a74d603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Fri, 18 Sep 2020 21:21:47 +1000 Subject: [PATCH 1/8] Add canShare() method --- index.html | 71 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/index.html b/index.html index f013ef7..259fb43 100644 --- a/index.html +++ b/index.html @@ -103,6 +103,7 @@

           partial interface Navigator {
+            boolean canShare(optional ShareData data = {});
             [SecureContext] Promise<undefined> share(optional ShareData data = {});
           };
         
@@ -136,6 +137,23 @@

+
+

+ canShare() method +

+

+ When the {{Navigator/canShare()}} method is called with argument + |data:ShareData|, run the following steps: +

+
    +
  1. Let |base| be [=this=]'s [=relevant settings object=]'s + [=environment settings object/API base URL=]. +
  2. +
  3. Return the result of [=validate share data=] with |data| and + |base|. +
  4. +
+

share() method @@ -165,25 +183,19 @@

{{ShareData/text}}, or {{ShareData/url}} or {{ShareData/file}} are present, return a promise rejected with a {{TypeError}}. -
  • If |data|'s {{ShareData/files}} member is present: -
      -
    1. If |data|'s {{ShareData/files}} member is empty, or if the - implementation does not support file sharing, return a - promise rejected with a {{TypeError}}, and abort these - steps. -
    2. -
    +
  • Let |base:URL| be the [=this=] value's relevant settings + object's [=environment settings object/api base URL=]. +
  • +
  • If running the steps to [=validate share data=] with |data| and + |base| return false, then return a promise rejected with a + {{TypeError}}.
  • If |data|'s {{ShareData/url}} member is present:
      -
    1. Let |base:URL| be the [=this=] value's relevant settings - object's [=environment settings object/api base URL=]. -
    2. Let |url:URL| be the result of running the URL parser on |data|'s {{ShareData/url}} with |base|.
    3. -
    4. If |url| is failure, return a promise rejected with - {{TypeError}}. +
    5. Assert: |url| is {{URL}}.
    6. If |url|'s [=URL/scheme=] is not "http" or "https", return a promise rejected with {{TypeError}}. @@ -269,6 +281,39 @@

      or bypassing the UI if there is only a single share target.

  • +
    +

    + Validate share data +

    +

    + To validate share data with |data:ShareData| and + |base:URL|, run the following steps: +

    +
      +
    1. If none of |data|'s members {{ShareData/title}}, + {{ShareData/text}}, or {{ShareData/url}} or {{ShareData/files}} are + present, return false. +
    2. +
    3. If |data|'s {{ShareData/files}} member is present: +
        +
      1. If |data|'s {{ShareData/files}} member is empty, or if the + implementation does not support file sharing, return false. +
      2. +
      +
    4. +
    5. If |data|'s url member is present: +
        +
      1. Let |url:URL| be the result of running the [=URL parser]= + on |data|'s url, with |base|, and no encoding override. +
      2. +
      3. If |url| is failure, return false. +
      4. +
      +
    6. +
    7. Return true. +
    8. +
    +

    From a130e8dfb4a2ceacc55fbefdc60e8b450c3f953c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Mon, 21 Sep 2020 17:59:40 +1000 Subject: [PATCH 2/8] add SecureContext and allowed to use check --- index.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 259fb43..08b86d8 100644 --- a/index.html +++ b/index.html @@ -103,7 +103,7 @@

               partial interface Navigator {
    -            boolean canShare(optional ShareData data = {});
    +            [SecureContext] boolean canShare(optional ShareData data = {});
                 [SecureContext] Promise<undefined> share(optional ShareData data = {});
               };
             
    @@ -146,6 +146,10 @@

    |data:ShareData|, run the following steps:

      +
    1. If the current settings object's responsible document is not + allowed to use the "[=web-share-feature|web-share=]" + permission, return false. +
    2. Let |base| be [=this=]'s [=relevant settings object=]'s [=environment settings object/API base URL=].
    3. From f36224b113b3725e5e795a620b8cef941ad59bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Mon, 21 Sep 2020 19:34:18 +1000 Subject: [PATCH 3/8] Add http+https checks to validation --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 08b86d8..aecaa3a 100644 --- a/index.html +++ b/index.html @@ -201,9 +201,6 @@

    4. Assert: |url| is {{URL}}.
    5. -
    6. If |url|'s [=URL/scheme=] is not "http" or "https", return - a promise rejected with {{TypeError}}. -
    7. Set |data| to a copy of |data|, with its {{ShareData/url}} member set to the result of running the URL serializer on |url|. @@ -312,6 +309,9 @@

    8. If |url| is failure, return false.
    9. +
    10. If |url|'s [=URL/scheme=] is not "http" or "https", return + return false. +
  • Return true. From 0ec77e98aa24062cfdc7e073ff54a9ef8502e0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Wed, 23 Sep 2020 16:07:59 +1000 Subject: [PATCH 4/8] Handle empty files sequence --- index.html | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index aecaa3a..c67812f 100644 --- a/index.html +++ b/index.html @@ -47,7 +47,7 @@ }; - +

    This specification defines an API for sharing text, links and other @@ -295,10 +295,23 @@

    {{ShareData/text}}, or {{ShareData/url}} or {{ShareData/files}} are present, return false.

  • +
  • Let |titleTextOrUrl:boolean| be true if any of + {{ShareData/title}}, or {{ShareData/text}}, or {{ShareData/url}} is + present. +
  • If |data|'s {{ShareData/files}} member is present:
      -
    1. If |data|'s {{ShareData/files}} member is empty, or if the - implementation does not support file sharing, return false. +
    2. If |titleTextOrUrl| is false, and if |data|'s + {{ShareData/files}} member is empty, or return false. +

      + This causes a `{ files: [] }` dictionary to be treated as + an empty dictionary. However, passing a dictionary like + `{text: "text" files: []}` is fine, as `files` is just + ignored. +

      +
    3. +
    4. If the implementation does not support file sharing, return + false.
  • From 53bf3f0e0e71af258389f1c44d6ba828427d771f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Wed, 23 Sep 2020 17:58:40 +1000 Subject: [PATCH 5/8] Update index.html Co-authored-by: Kagami Sascha Rosylight --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index c67812f..4640e90 100644 --- a/index.html +++ b/index.html @@ -323,7 +323,7 @@

  • If |url| is failure, return false.
  • If |url|'s [=URL/scheme=] is not "http" or "https", return - return false. + false.
  • From fc20b1bf95f615e254f74283c1f35742b122a9d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Wed, 23 Sep 2020 20:00:34 +1000 Subject: [PATCH 6/8] Add purpose for canShare() --- index.html | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/index.html b/index.html index 4640e90..6a062ca 100644 --- a/index.html +++ b/index.html @@ -141,6 +141,28 @@

    canShare() method

    +

    When the {{Navigator/canShare()}} method is called with argument |data:ShareData|, run the following steps: From 32bfa3ee6dc1bb4df0cb3a172d47882fc3ed66f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Wed, 28 Oct 2020 15:52:44 +1100 Subject: [PATCH 7/8] Add canShare overload --- index.html | 296 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 213 insertions(+), 83 deletions(-) diff --git a/index.html b/index.html index 6a062ca..b98fcf0 100644 --- a/index.html +++ b/index.html @@ -47,7 +47,7 @@ }; - +

    This specification defines an API for sharing text, links and other @@ -93,18 +93,24 @@

    target to share this title and the page URL to.

    -
    +

    API definition

    -
    +

    Extensions to the `Navigator` interface

               partial interface Navigator {
    -            [SecureContext] boolean canShare(optional ShareData data = {});
    -            [SecureContext] Promise<undefined> share(optional ShareData data = {});
    +            [SecureContext]
    +            Promise<undefined> share(optional ShareData data = {});
    +
    +            [SecureContext]
    +            boolean canShare(optional ShareData data = {});
    +
    +            [SecureContext]
    +            boolean canShare(DOMString name, optional CanShareQuery options = {});
               };
             

    @@ -137,49 +143,6 @@

    -
    -

    - canShare() method -

    - -

    - When the {{Navigator/canShare()}} method is called with argument - |data:ShareData|, run the following steps: -

    -
      -
    1. If the current settings object's responsible document is not - allowed to use the "[=web-share-feature|web-share=]" - permission, return false. -
    2. -
    3. Let |base| be [=this=]'s [=relevant settings object=]'s - [=environment settings object/API base URL=]. -
    4. -
    5. Return the result of [=validate share data=] with |data| and - |base|. -
    6. -
    -

    share() method @@ -189,10 +152,10 @@

    |data:ShareData|, run the following steps:

      -
    1. If the current settings object's responsible document is not - allowed to use the "[=web-share-feature|web-share=]" - permission, return [=a promise rejected with=] with a - {{"NotAllowedError"}} {{DOMException}}. +
    2. If the [=current settings object=]'s [=environment settings + object/responsible document=] is not allowed to use the + "[=web-share-feature|web-share=]" permission, return [=a promise + rejected with=] with a {{"NotAllowedError"}} {{DOMException}}.
    3. If {{[[sharePromise]]}} is not `null`, return a promise rejected with {{InvalidStateError}}. @@ -306,50 +269,105 @@

    - Validate share data + `canShare(data)` method

    +

    - To validate share data with |data:ShareData| and - |base:URL|, run the following steps: + When the canShare(data) method is + called with argument {{ShareData}} |data:ShareData|, run the + following steps:

      -
    1. If none of |data|'s members {{ShareData/title}}, - {{ShareData/text}}, or {{ShareData/url}} or {{ShareData/files}} are - present, return false. +
    2. If the [=current settings object=]'s [=environment settings + object/responsible document=] is not allowed to use the + "[=web-share-feature|web-share=]" permission, return false.
    3. -
    4. Let |titleTextOrUrl:boolean| be true if any of - {{ShareData/title}}, or {{ShareData/text}}, or {{ShareData/url}} is - present. +
    5. Let |base| be [=this=]'s [=relevant settings object=]'s + [=environment settings object/API base URL=]. +
    6. +
    7. Return the result of [=validate share data=] with |data| and + |base|.
    8. -
    9. If |data|'s {{ShareData/files}} member is present: +
    +
    +
    +

    + `canShare(name, options)` method +

    + +

    + When the canShare(name, + options) method is called with arguments {{DOMString}} + |name:DOMString| and {{CanShareQuery}} |options:CanShareQuery|, run + the following steps: +

    +
      +
    1. If the [=current settings object=]'s [=environment settings + object/responsible document=] is not allowed to use the + "[=web-share-feature|web-share=]" permission, return false. +
    2. +
    3. If |name| is "url", return either `true` or `false` depending + on if sharing URLs is [=supported=]. +
    4. +
    5. If |name| is "text", return either `true` or `false` depending + on if sharing text is [=supported=]. +
    6. +
    7. If |name| is "files":
        -
      1. If |titleTextOrUrl| is false, and if |data|'s - {{ShareData/files}} member is empty, or return false. -

        - This causes a `{ files: [] }` dictionary to be treated as - an empty dictionary. However, passing a dictionary like - `{text: "text" files: []}` is fine, as `files` is just - ignored. -

        +
      2. If sharing files is not [=supported=], return `false`.
      3. -
      4. If the implementation does not support file sharing, return - false. +
      5. If |options| is doesn't have a {{CanShareQuery/type}} + member, return `true`.
      6. -
      -
    8. -
    9. If |data|'s url member is present: -
        -
      1. Let |url:URL| be the result of running the [=URL parser]= - on |data|'s url, with |base|, and no encoding override. +
      2. Let |type| be the result of [=parse a MIME type=] with + {{CanShareQuery/type}} as input.
      3. -
      4. If |url| is failure, return false. +
      5. If |type| is failure, throw a {{TypeError}}.
      6. -
      7. If |url|'s [=URL/scheme=] is not "http" or "https", return - false. +
      8. Return either `true` or `false` depending on if the user + agent supports sharing the [=MIME type/essence=] of |type|.
    10. -
    11. Return true. +
    12. |name| is not a [=supported share member=], return `false`.
    @@ -365,7 +383,7 @@

    USVString text; USVString url; }; - +

    The ShareData dictionary consists of several optional members: @@ -397,6 +415,10 @@

    A URL string referring to a resource being shared. +

    + A member is supported if the use agent supports sharing + the value of a {{ShareData}} member with [=share targets=]. +

    These members are {{USVString}} (as opposed to {{DOMString}}) because they are not allowed to contain surrogate code points. Among other @@ -412,6 +434,114 @@

    an [^a^] element, before being given to the share target.

    +
    +

    + Validate share data +

    +

    + To validate share data with |data:ShareData| and + |base:URL|, run the following steps: +

    +
      +
    1. If none of |data|'s members {{ShareData/title}}, + {{ShareData/text}}, or {{ShareData/url}} or {{ShareData/files}} are + present, return false. +
    2. +
    3. Let |titleTextOrUrl:boolean| be true if any of + {{ShareData/title}}, or {{ShareData/text}}, or {{ShareData/url}} is + present. +
    4. +
    5. If |data|'s {{ShareData/files}} member is present: +
        +
      1. If |titleTextOrUrl| is false and |data|'s {{ShareData/files}} + member is empty, return false. +

        + This causes a `{ files: [] }` dictionary to be treated as an + empty dictionary. However, passing a dictionary like `{text: + "text", files: []}` is fine, as `files` is just ignored. +

        +
      2. +
      3. If the implementation does not support file sharing, return + false. +
      4. +
      5. If the user agent believes sharing any of the files in + `files` would result in a potentially hostile share, return + false. +
        +
      6. +
      +
    6. +
    7. If |data|'s url member is present: +
        +
      1. Let |url:URL| be the result of running the [=URL parser=] on + |data|'s url, with |base|, and no encoding override. +
      2. +
      3. If |url| is failure, return false. +
      4. +
      5. If |url|'s [=URL/scheme=] is not "http" or "https", return + false. +
      6. +
      +
    8. +
    9. Return true. +
    10. +
    +
    +
    +

    + `CanShareQuery` dictionary +

    +
    +            dictionary CanShareQuery {
    +              DOMString type;
    +            };
    +          
    +
    +

    + `type` member +

    +

    + The type member is a [=MIME Type=] that the developer + would like to check support for. +

    +
    +
    +
    +

    + Supported share members +

    +

    + The supported share members provide a means for developers + to check if particular sharing capabilities are supported by the user + agent. They are represented by the following string literals: +

    +
    +
    + "files" +
    +
    + Represents support for the {{ShareData/files}} member. +
    +
    + "url" +
    +
    + Represents support for the {{ShareData/url}} member. +
    +
    + "text" +
    +
    + Represents support for the {{ShareData/text}} member. +
    +
    +

    + The choice to use string literals instead of an [=enumeration=] is + deliberate. Doing so allows implementers to gracefully support future + {{ShareData}} member values, while also giving the user agent the + ability to disable sharing those members if needed. +

    +

    From 338d7fa709b4e91ad831d39330ecc38d4aeba7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Wed, 18 Aug 2021 16:02:26 +1000 Subject: [PATCH 8/8] Specify minimum canShare() to match Chrome/Safari --- index.html | 245 +++++++---------------------------------------------- 1 file changed, 31 insertions(+), 214 deletions(-) diff --git a/index.html b/index.html index 39f9826..2630c11 100644 --- a/index.html +++ b/index.html @@ -47,7 +47,7 @@ }; - +

    This specification defines an API for sharing text, links and other @@ -92,25 +92,39 @@

    display a picker or chooser dialog, allowing the user to select a target to share this title and the page URL to.

    +

    + Calling {{Navigator/canShare()}} method with a {{ShareData}} dictionary + [=validate share data|validates=] the shared data. unlike + {{Navigator/share()}}, it can be called without [=transient + activation=]. +

    +
    +        const file = new File([], "some.png", { type: "image/png" });
    +
    +        // Check if files are supported
    +        if (navigates.canShare({files: [file]})) {
    +          // Sharing a png file would probably be ok...
    +        }
    +
    +        // Check if a URL is ok to share...
    +        if (navigates.canShare({ url: someURL })) {
    +          // The URL is valid and can probably be shared...
    +        }
    +      

    -
    +

    API definition

    -
    +

    Extensions to the `Navigator` interface

               partial interface Navigator {
    -            [SecureContext]
    -            Promise<undefined> share(optional ShareData data = {});
    +            [SecureContext] Promise<undefined> share(optional ShareData data = {});
     
    -            [SecureContext]
    -            boolean canShare(optional ShareData data = {});
    -
    -            [SecureContext]
    -            boolean canShare(DOMString name, optional CanShareQuery options = {});
    +            [SecureContext] boolean canShare(optional ShareData data = {});
               };
             

    @@ -268,103 +282,18 @@

    `canShare(data)` method

    -

    - When the canShare(data) method is - called with argument {{ShareData}} |data:ShareData|, run the - following steps: + When the canShare(data) method is called with argument + {{ShareData}} |data:ShareData|, run the following steps:

    1. If the [=current settings object=]'s [=environment settings - object/responsible document=] is not allowed to use the - "[=web-share-feature|web-share=]" permission, return false. -
    2. -
    3. Let |base| be [=this=]'s [=relevant settings object=]'s - [=environment settings object/API base URL=]. + object/responsible document=] is not allowed to use + "web-share", return false.
    4. Return the result of [=validate share data=] with |data| and - |base|. -
    5. -
    -
    -
    -

    - `canShare(name, options)` method -

    - -

    - When the canShare(name, - options) method is called with arguments {{DOMString}} - |name:DOMString| and {{CanShareQuery}} |options:CanShareQuery|, run - the following steps: -

    -
      -
    1. If the [=current settings object=]'s [=environment settings - object/responsible document=] is not allowed to use the - "[=web-share-feature|web-share=]" permission, return false. -
    2. -
    3. If |name| is "url", return either `true` or `false` depending - on if sharing URLs is [=supported=]. -
    4. -
    5. If |name| is "text", return either `true` or `false` depending - on if sharing text is [=supported=]. -
    6. -
    7. If |name| is "files": -
        -
      1. If sharing files is not [=supported=], return `false`. -
      2. -
      3. If |options| is doesn't have a {{CanShareQuery/type}} - member, return `true`. -
      4. -
      5. Let |type| be the result of [=parse a MIME type=] with - {{CanShareQuery/type}} as input. -
      6. -
      7. If |type| is failure, throw a {{TypeError}}. -
      8. -
      9. Return either `true` or `false` depending on if the user - agent supports sharing the [=MIME type/essence=] of |type|. -
      10. -
      -
    8. -
    9. |name| is not a [=supported share member=], return `false`. + [=this=]'s [=relevant settings object=]'s [=environment settings + object/API base URL=].
    @@ -439,7 +368,7 @@

    USVString text; USVString url; }; - +

    The ShareData dictionary consists of several optional members: @@ -471,10 +400,6 @@

    A URL string referring to a resource being shared. -

    - A member is supported if the use agent supports sharing - the value of a {{ShareData}} member with [=share targets=]. -

    These members are {{USVString}} (as opposed to {{DOMString}}) because they are not allowed to contain surrogate code points. Among other @@ -490,114 +415,6 @@

    an [^a^] element, before being given to the share target.

    -
    -

    - Validate share data -

    -

    - To validate share data with |data:ShareData| and - |base:URL|, run the following steps: -

    -
      -
    1. If none of |data|'s members {{ShareData/title}}, - {{ShareData/text}}, or {{ShareData/url}} or {{ShareData/files}} are - present, return false. -
    2. -
    3. Let |titleTextOrUrl:boolean| be true if any of - {{ShareData/title}}, or {{ShareData/text}}, or {{ShareData/url}} is - present. -
    4. -
    5. If |data|'s {{ShareData/files}} member is present: -
        -
      1. If |titleTextOrUrl| is false and |data|'s {{ShareData/files}} - member is empty, return false. -

        - This causes a `{ files: [] }` dictionary to be treated as an - empty dictionary. However, passing a dictionary like `{text: - "text", files: []}` is fine, as `files` is just ignored. -

        -
      2. -
      3. If the implementation does not support file sharing, return - false. -
      4. -
      5. If the user agent believes sharing any of the files in - `files` would result in a potentially hostile share, return - false. -
        -
      6. -
      -
    6. -
    7. If |data|'s url member is present: -
        -
      1. Let |url:URL| be the result of running the [=URL parser=] on - |data|'s url, with |base|, and no encoding override. -
      2. -
      3. If |url| is failure, return false. -
      4. -
      5. If |url|'s [=URL/scheme=] is not "http" or "https", return - false. -
      6. -
      -
    8. -
    9. Return true. -
    10. -
    -
    -
    -

    - `CanShareQuery` dictionary -

    -
    -            dictionary CanShareQuery {
    -              DOMString type;
    -            };
    -          
    -
    -

    - `type` member -

    -

    - The type member is a [=MIME Type=] that the developer - would like to check support for. -

    -
    -
    -
    -

    - Supported share members -

    -

    - The supported share members provide a means for developers - to check if particular sharing capabilities are supported by the user - agent. They are represented by the following string literals: -

    -
    -
    - "files" -
    -
    - Represents support for the {{ShareData/files}} member. -
    -
    - "url" -
    -
    - Represents support for the {{ShareData/url}} member. -
    -
    - "text" -
    -
    - Represents support for the {{ShareData/text}} member. -
    -
    -

    - The choice to use string literals instead of an [=enumeration=] is - deliberate. Doing so allows implementers to gracefully support future - {{ShareData}} member values, while also giving the user agent the - ability to disable sharing those members if needed. -

    -