-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathindex.bs
673 lines (544 loc) · 26.9 KB
/
index.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
<pre class="metadata">
Title: Controlled Frame API
Abstract: This document defines an API for embedding arbitrary web content only
within the context of an Isolated Web Application (IWA). The embedded
content is a new top-level browsing context within and controlled by the
embedder.
Repository: chasephillips/controlled-frame
Status: w3c/CG-DRAFT
ED: TBD
Shortname: controlled-frame
Level: 1
Editor: Chase Phillips 115880, Google LLC https://google.com, [email protected]
Editor: Robbie McElrath 139758, Google LLC https://google.com, [email protected]
Group: WICG
Markup Shorthands: markdown yes
</pre>
<style>
.domintro::before {
content: 'For web developers (non-normative)';
text-transform: initial;
}
.domintro dt {
font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace;
padding-top: 0.5em;
padding-bottom: 1em;
}
.domintro dt a {
color: inherit; border-bottom-style: none;
}
.domintro dt code {
font-size: inherit;
}
</style>
<pre class="biblio">
{
"isolated-web-apps": {
"authors": [
"Reilly Grant"
],
"href": "https://github.com/WICG/isolated-web-apps/blob/main/README.md",
"title": "Isolated Web Apps Explainer"
},
"high-watermark-permissions": {
"authors": [
"Robbie McElrath"
],
"href": "https://github.com/WICG/isolated-web-apps/blob/main/Permissions.md",
"title": "Isolated Web Apps High Watermark Permissions Explainer"
}
}
</pre>
<!-- ====================================================================== -->
# Introduction # {#introduction}
<!-- ====================================================================== -->
This specification describes a content embedding API that satisfies some
critical use cases for IWAs that <{iframe}> does not support. This embedding
environment should allow embedding all content without express permission from
the embedded site, including content which <{iframe}> cannot embed, and provide
embedding sites more control over that embedded content.
Since this is a particularly powerful API, its use and availability makes an app
a target of various types of hacking. As a result, this API is limited to use in
[[Isolated-Web-Apps|Isolated Web Applications]] (IWAs) which have addtional
safeguards in place to protect users and developers. IWAs are not a normal web
application and can exist only at a special 'isolated-app:' scheme. This means
by design that this API will not be available to normal web pages.
Note: This API is not intended to be a replacement or substitute for <{iframe}>.
All <{iframe}> use cases are still valid and should continue to use <{iframe}>,
including IWAs where possible.
<!-- ====================================================================== -->
# Usage Overview # {#usage-overview}
<!-- ====================================================================== -->
Lorem ipsum. Insert basic info and example here.
<!-- ====================================================================== -->
# Motivating Applications # {#motivating-applications}
<!-- ====================================================================== -->
*This section is non-normative.*
<!-- ====================================================================== -->
## Latency-sensitive applications in virtualized sessions ## {#browser-content-redirection}
<!-- ====================================================================== -->
In virtualized environments, users typically have a local thin client that
renders a full virtual desktop. The actual desktop execution environment will be
running on a remote virtualization server. If the user's browser navigates to a
latency-sensitive application (such as a video app), the rendered content will
have additional latency ("lag") that makes the experience difficult or
impossible for the user. This also applies for applications that record the
user, such as video conferencing applications. In these latency-sensitive
applications, the virtual desktop application can render the latency-sensitive
content locally and overlay it on top of the rendered remote content to reduce
this latency. This use case is also known as "browser content redirection."
<!-- ====================================================================== -->
## Embedding third party web content without restriction ## {#no-embedding-prohibitions}
<!-- ====================================================================== -->
In a kiosk environment, applications must load content from third parties and
display that content on screens within their applications. A teacher may trigger
the navigation event, or it may be configured by an administrator such as a
shopping mall manager. The content may prohibit embedding by <{iframe}> through
the use of X-Frame-Options and CSP. An controlled frame, however, should be able
to load all content, even content that prohibits embedding by <{iframe}>.
<!-- ====================================================================== -->
## Remote display and manipulation of web content ## {#remote-content-control}
<!-- ====================================================================== -->
In a kiosk environment, applications must ensure that content continues to
display on screens and may need to interrupt content with their own supplied
behaviors. This behavior should work without local attendance by an
administrator, and ideally can be managed remotely over the network. If content
were to crash, for example, these applications should observe and respond to the
crash by reloading the content in a fresh embedded view.
<!-- ====================================================================== -->
## Clearing user content after each session ## {#clearing-session-data}
<!-- ====================================================================== -->
In some environments, someone only uses a single device for a brief time to
complete their task, like ordering in a restaurant. When their task is complete,
the embedder application should be able to clear all of the local user data
associated with the task and then restart the embedded instance.
<!-- ====================================================================== -->
## Monitor for idle sessions ## {#monitor-idle-sessions}
<!-- ====================================================================== -->
While users interact with embedded content, the user may not explicitly end
their session. This content may assume the user is present when they have
actually finished or departed without completing the task. Embedder applications
want to detect when users idle over their case's threshold and begin a fresh
session.
<!-- ====================================================================== -->
## Arbitrarily blocking navigations ## {#blocking-navigations}
<!-- ====================================================================== -->
While displaying embedded web content that's not authored by the embedder, pages
may link to third party web content that's disallowed. Allowing the embedder to
edit elements in embedded content through arbitrary script injection into the
web content can ensure navigation cannot occur to blocked pages. The embedder
can also use the Controlled Frame API to capture navigation events and ensure
that only pages to approved sites can be loaded within that controlled frame.
<!-- ====================================================================== -->
# Security, Privacy, and Accessibility Considerations # {#considerations}
<!-- ====================================================================== -->
*This section is non-normative.*
<!-- ====================================================================== -->
## Security ## {#security}
<!-- ====================================================================== -->
<b>Controlled Frame is based upon [[Isolated-Web-Apps]] (IWA)
and integrates with core security specs</b>
Since Controlled Frame is a particularly powerful API, using it or even having
it available makes an app a target of various types of hacking. As a result,
this API is limited to use in [[Isolated-Web-Apps|IWA]] which have additional
safeguards in place to protect application developers and users. The Isolated
Web App explainer has this to say:
> <i>"A user agent may also force an application to adopt this threat model if
the developer needs access to APIs which would make the application an appealing
target for XSS or server-side attacks."</i>
Controlled Frame makes just such an appealing target, and to expose this with
caution we're opting into [[Isolated-Web-Apps|IWA]] to guard against certain
attacks. Generally, [[Isolated-Web-Apps|IWAs]] provide strong security
assurances that each of the resources in an application are secure both at rest
and in-transit. You can read more about [[Isolated-Web-Apps|IWAs]] security and
permissions in the [[Isolated-Web-Apps|IWA]] explainer and the
[[Isolated-Web-Apps|IWAs]] [[High-Watermark-Permissions]] explainer.
Controlled Frame integrates with [[!Permissions-Policy]] and [[!Permissions]].
You can read more about [[Permissions-Policy#privacy]] and
[[Permissions#security-considerations]] (note the entry is currently sparse).
<b>Attacking web sites could display content that doesn't otherwise allow itself
to be embedded and trick users on non-[[Isolated-Web-Apps|IWAs]].</b>
Planned mitigation:
- Controlled Frame will only be available within [[Isolated-Web-Apps|IWAs]]
<b>An [[Isolated-Web-Apps|IWA]] may embed another [[Isolated-Web-Apps|IWA]] (or
itself) via Controlled Frame to manipulate our [[Isolated-Web-Apps|IWA]]
policies somehow (e.g. an Controlled Frame embedded [[Isolated-Web-Apps|IWA]]
may detect it's being embedded due to the absence of the "controlledframe"
policy-controlled feature).</b>
Planned mitigation:
- Controlled Frame can only point to "https" schemes, excluding the
"isolated-app" scheme used for [[Isolated-Web-Apps|IWAs]]
<b>Controlled Frame could gain access to the powerful <controlledframe>
element.</b>
An [[Isolated-Web-Apps|IWA]] that's not expected to use Controlled Frame may
attempt to embed content.
Planned mitigation:
- Only embedder applications and their same-origin [[Isolated-Web-Apps|IWA]]
child navigables that have been granted the "controlledframe"
policy-controlled feature will be allowed access to the Controlled Frame
element.
- Same-origin child navigables without the "controlledframe"
policy-controlled feature will not be allowed to use a Controlled Frame
element (to be confirmed, see note below)
- Cross-origin iframes to [[Isolated-Web-Apps|IWAs]] can use the "allow"
attribute to disable Controlled Frame
- Cross-origin iframes to non-[[Isolated-Web-Apps|IWAs]] will not have
access to the "controlledframe" policy-controlled feature, and so will not
be allowed to use a Controlled Frame element
- See the "Embedder Policies Using the "controlledframe" Feature" section
above for more details
<b>An IWA may attempt to embed content from non-https schemes, such as 'http:'
or 'isolated-app:'</b>
Planned mitigation:
- Controlled Frame will only work when the navigable's "src" URL has an
'https:' scheme
<b>Malicious Controlled Frame could access the embedder's running process (eg.
Spectre attack)</b>
Planned mitigation:
- Controlled Frame will be executed in a separate process from the
embedder's process
<b>Controlled Frame for a given "https origin" could interact or interfere with
the user's own storage user agent data for that https origin</b>
Planned mitigation:
- Controlled Frame will always store data in a separate storage user agent
that's apart from the default storage user agent
- Data written to by a given "https origin" while the user accesses that
origin via an [[Isolated-Web-Apps|IWA]] Controlled Frame will be isolated
from the user's storage user agent that backs "normal" window and tab usage,
and vice versa
<b>Malicious Controlled Frame could overwrite embedder's stored data</b>
- The embedder and embedded storage user agent could overlap, and possibly
multiple same-site [[Isolated-Web-Apps|IWA]] child navigables could be
affected by activity in the Controlled Frame
- if storage user agents were shared between the embedder and embedded
sites, clearing data for either one could negatively impact the other
Planned mitigation:
- [[Isolated-Web-Apps|IWA]] and Controlled Frame will always have separate
storage user agents
- A Controlled Frame should not have read or write access to other storage
user agents besides its own
<b>Malicious Controlled Frame may detect it is embedded and attempt to attack
the embedder application</b>
Planned mitigation:
- The user agent will match the browser.
- The Controlled Frame storage user agent will be separate from the
[[Isolated-Web-Apps|IWA]] and the default storage user agents.
- The Controlled Frame process will be separate from the
[[Isolated-Web-Apps|IWA]] and the default renderer and browser processes.
- The Controlled Frame environment will appear to be the top-most navigable:
- window should match window.parent and window.top
- List of policy-controlled features and their disable/enable status
should match the default for a navigable
Ideas:
- Investigate for potential interactions around filesystem, quota storage,
and localStorage APIs
<b>User may not be able to verify the origin of the page being viewed in the
Controlled Frame</b>
Ideas:
- Expose the origin to the user somehow, such as adding UI at the top of a
Controlled Frame that displays the origin?
- Have the [[Isolated-Web-Apps|IWA]] specify in the manifest the origins that
they expect to access?
<b>Controlled Frame may exploit vulnerabilities in out-of-date browser
engine</b>
Already addressed with:
- Existing browser engine auto-update mechanisms
<!-- ====================================================================== -->
## Privacy ## {#privacy}
<!-- ====================================================================== -->
Controlled Frame integrates with Permissions Policy and Permissions. You can
read more about [[Permissions-Policy#privacy]]. You can read more about
[[Permissions#security-considerations]].
For Controlled Frame specifically, we've identified the following privacy
considerations:
- Users' browsing within Controlled Frame will be visible to the
[[Isolated-Web-Apps|IWA]]
- [[Isolated-Web-Apps|IWAs]] can access and exfiltrate the Controlled Frame's
session cookies (this only applies to the Controlled Frame's session since
they use a separate storage partition from the [[Isolated-Web-Apps|IWA]] and
the third party origin when browsed in a tab)
- User activity in Controlled Frame can be observed by the
[[Isolated-Web-Apps|IWA]] (e.g. keyboard events can be monitored, password
entry can be sniffed)
- User file upload to Controlled Frame can be hijacked
- User data held in the Controlled Frame's remote server could be accessed by
code implanted by the [[Isolated-Web-Apps|IWA]]
- Users that wish to clear their session history must also do so via the
[[Isolated-Web-Apps|IWA]], which will then need to clear the associated
storage user agents
- This would be necessary since embedded storage user agents are separate
from the non-embedded storage user agents for any given https origin
- We plan to investigate browser UX to allow users to clear the Controlled
Frame storage user agents, the following cases will be considered:
- If a user wants to clear site data for an [[Isolated-Web-Apps|IWA]], the
associated embedded storage user agents will also be cleared
- This is because if the [[Isolated-Web-Apps|IWA]]'s data is cleared,
the app will no longer have any context for the associated embedded
storage user agents and therefore will no longer be used or useful
to the user or organization
- As a result, we expect that clearing an [[Isolated-Web-Apps|IWA]]'s
site data will require clearing all of the associated embedded
storage user agents
- A user may want to clear all site data for a given "https origin", even
if that origin is stored within an [[Isolated-Web-Apps|IWA]]'s embedded
storage user agent
- We may choose to provide the ability to clear all
[[Isolated-Web-Apps|IWA]] site data for that "https origin" even if
that site data is held within an embedded storage user agent
- If we chose to clear the "https origin" data,
[[Isolated-Web-Apps|IWAs]] would need to prepare for the possibility
that embedded storage user agents may be removed outside of their
control, and this may be disruptive to the [[Isolated-Web-Apps|IWA]]
and introduce complexity of implementation
- Supporting this in the browser user agent exposes browser vendors,
developers, and users to additional complexity, so we may choose not
to support this approach and instead leave this up to
[[Isolated-Web-Apps|IWA]] developers to implement
- As a counter example to supporting clearing a single given "https
origin"'s embedded storage user agent, consider that to our
knowledge no operating system behaves that way
- i.e. there's no central "clear browsing data" option which clears
storage for all installed browser engines, each application's
storage is treated as its own to manage
- User wants to clear the site data for a given [[Isolated-Web-Apps|IWA]]'s
Controlled Frame-embedded storage user agent for a given "https origin"
- User wants to clear the site data for a given [[Isolated-Web-Apps|IWA]]'s
Controlled Frame-embedded storage user agents for all "https origins"
- An [[Isolated-Web-Apps|IWA]] will need the ability to clear the storage user
agent's Controlled Frame-embedded storage user agent for a given "https
origin"
<!-- ====================================================================== -->
## Accessibility ## {#accessibility}
<!-- ====================================================================== -->
For Controlled Frame, we've identified the following accessibility
considerations:
- Browser user agents' accessibility tools and APIs should have visibility into
Controlled Frame
- [[Isolated-Web-Apps|IWAs]] should expect to provide their own accessibility
tools for Controlled Frame content in order to properly integrate
accessibility features for some use cases (such as "browser content
redirection")
<!-- ====================================================================== -->
# Concepts # {#concepts}
<!-- ====================================================================== -->
<!-- ====================================================================== -->
# API # {#api}
<!-- ====================================================================== -->
<!-- ====================================================================== -->
## Controlled Frame HTML Element ## {#html-element}
<!-- ====================================================================== -->
<xmp class="idl">
[Exposed=Window, SecureContext]
interface ControlledFrame : HTMLElement {
[HTMLConstructor] constructor();
[CEReactions] attribute USVString src;
[CEReactions] attribute DOMString name;
[CEReactions] attribute boolean allowfullscreen;
[CEReactions] attribute boolean allowscaling;
[CEReactions] attribute boolean allowtransparency;
[CEReactions] attribute boolean autosize;
[CEReactions] attribute DOMString maxheight;
[CEReactions] attribute DOMString maxwidth;
[CEReactions] attribute DOMString minheight;
[CEReactions] attribute DOMString minwidth;
attribute DOMString partition;
readonly attribute WindowProxy? contentWindow;
readonly attribute ContextMenus contextMenus;
// Navigation methods.
Promise<undefined> back();
boolean canGoBack();
boolean canGoForward();
Promise<undefined> forward();
Promise<undefined> go(long relativeIndex);
undefined reload();
undefined stop();
// Scripting methods.
undefined addContentScripts(sequence<ContentScriptDetails> contentScriptList);
Promise<any> executeScript(optional InjectDetails details = {});
Promise<undefined> insertCSS(optional InjectDetails details = {});
undefined removeContentScripts(sequence<DOMString>? scriptNameList);
// Configuration methods.
Promise<undefined> clearData(
optional ClearDataOptions options = {},
optional ClearDataTypeSet types = {});
Promise<boolean> getAudioState();
Promise<long> getZoom();
Promise<boolean> isAudioMuted();
undefined setAudioMuted(boolean mute);
Promise<undefined> setZoom(long zoomFactor);
// Capture methods.
undefined captureVisibleRegion();
undefined print();
};
</xmp>
If the "controlled-frame" feature is enabled for an IWA in its manifest, each
IWA frame will have access to a ControlledFrame element.
<!-- ====================================================================== -->
## Navigation methods ## {#api-nav}
<!-- ====================================================================== -->
<div class="domintro note">
: {{ControlledFrame/go()|go}}()
:: Reloads the current page.
: {{ControlledFrame/go()|go}}(<var>relativeIndex</var>)
:: Goes back or forward <var>relativeIndex</var> number of steps in the overall
<a href="https://html.spec.whatwg.org/multipage/document-sequences.html#tn-session-history-entries">
session history entries </a> list for the current
<a href="https://html.spec.whatwg.org/multipage/document-sequences.html#traversable-navigable">
traversable navigable</a>.
A zero relative index will reload the current page.
If the relative index is out of range, does nothing.
: {{ControlledFrame/back()|back}}()
:: Goes back one step in the overall
<a href="https://html.spec.whatwg.org/multipage/document-sequences.html#tn-session-history-entries">
session history entries </a> list for the
<a href="https://html.spec.whatwg.org/multipage/document-sequences.html#traversable-navigable">
traversable navigable</a> in the Controlled Frame.
If there is no previous page, does nothing.
: {{ControlledFrame/forward()|forward}}()
:: Goes forward one step in the overall
<a href="https://html.spec.whatwg.org/multipage/document-sequences.html#tn-session-history-entries">
session history entries </a> list for the
<a href="https://html.spec.whatwg.org/multipage/document-sequences.html#traversable-navigable">
traversable navigable</a> in the Controlled Frame.
If there is no next page, does nothing.
: {{ControlledFrame/canGoBack()|canGoBack}}()
:: Returns true if the current
<a href="https://html.spec.whatwg.org/multipage/document-sequences.html#nav-current-history-entry">
current session history entry</a> is not the first one in the navigation
history entry list. This means that there is a previous
<a href="https://html.spec.whatwg.org/multipage/browsing-the-web.html#session-history-entry">
session history entry</a> for this
<a href="https://html.spec.whatwg.org/multipage/document-sequences.html#navigable">
navigable</a>.
: {{ControlledFrame/reload()|reload}}()
:: Reloads the current page.
: {{ControlledFrame/stop()|stop}}()
:: Cancels the document load.
</div>
<!-- ====================================================================== -->
## Scripting methods ## {#api-scripting}
<!-- ====================================================================== -->
<xmp class="idl">
// One of |code| or |file| must be specified but not both.
dictionary InjectDetails {
DOMString code;
DOMString file;
};
dictionary InjectionItems {
DOMString code;
sequence<DOMString> files;
};
enum RunAt {
"document_start",
"document_end",
"document_idle",
};
dictionary ContentScriptDetails {
boolean all_frames;
InjectionItems css;
sequence<DOMString> exclude_globs;
sequence<DOMString> exclude_matches;
sequence<DOMString> include_globs;
InjectionItems js;
boolean match_about_blank;
required sequence<DOMString> matches;
required DOMString name;
RunAt run_at;
};
</xmp>
<!-- ====================================================================== -->
## Configuration methods ## {#api-config}
<!-- ====================================================================== -->
<xmp class="idl">
dictionary ClearDataOptions {
long since;
};
dictionary ClearDataTypeSet {
boolean appcache;
boolean cache;
boolean cookies;
boolean fileSystems;
boolean indexedDB;
boolean localStorage;
boolean persistentCookies;
boolean sessionCookies;
boolean webSQL;
};
</xmp>
<!-- ====================================================================== -->
## Capture methods ## {#api-capture}
<!-- ====================================================================== -->
<!-- ====================================================================== -->
## Event listener API ## {#api-event}
<!-- ====================================================================== -->
<!-- ====================================================================== -->
# Controlled Frame API # {#controlled-frame-api}
<!-- ====================================================================== -->
<xmp class="idl">
enum ContextType {
"all",
"page",
"frame",
"selection",
"link",
"editable",
"image",
"video",
"audio",
};
enum ItemType {
"normal",
"checkbox",
"radio",
"separator",
};
dictionary OnClickData {
boolean checked;
required boolean editable;
long frameId;
USVString frameUrl;
USVString linkUrl;
DOMString mediaType;
required (DOMString or long) menuItemId;
USVString pageUrl;
(DOMString or long) parentMenuId;
DOMString selectionText;
USVString srcUrl;
boolean wasChecked;
};
callback ContextMenusEventListener = undefined (OnClickData data);
dictionary ContextMenusProperties {
boolean checked;
sequence<ContextType> context;
DOMString documentUrlPatterns;
boolean enabled;
DOMString parentId;
DOMString targetUrlPatterns;
DOMString title;
ItemType type;
ContextMenusEventListener onclick;
};
dictionary ContextMenusCreateProperties : ContextMenusProperties {
DOMString id;
};
callback ContextMenusCallback = undefined ();
[Exposed=Window, SecureContext]
interface ContextMenus {
// TODO: Define the `onShow` property.
// Returns the ID of the newly created menu item.
(DOMString or long) create(
ContextMenusCreateProperties properties,
ContextMenusCallback? callback);
undefined remove(
(DOMString or long) menuItemId,
ContextMenusCallback? callback);
undefined removeAll(ContextMenusCallback? callback);
undefined update(
(DOMString or long) id,
ContextMenusProperties properties,
ContextMenusCallback? callback);
};
</xmp>
# Acknowledgements # {#acknowledgements}
The following people contributed to the development of this document.
* <a href="https://github.com/odejesush">Ovidio Ruiz-Henríquez</a>