mbeditor 0.13.1 → 0.14.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +132 -0
- data/app/assets/javascripts/mbeditor/application.js +5 -0
- data/app/assets/javascripts/mbeditor/audit_log.js +165 -0
- data/app/assets/javascripts/mbeditor/collaboration_service.js +248 -26
- data/app/assets/javascripts/mbeditor/components/ChangelogView.js +89 -94
- data/app/assets/javascripts/mbeditor/components/CodeReviewPanel.js +6 -9
- data/app/assets/javascripts/mbeditor/components/CollapsibleSection.js +12 -7
- data/app/assets/javascripts/mbeditor/components/CombinedDiffViewer.js +20 -0
- data/app/assets/javascripts/mbeditor/components/CombinedFileView.js +214 -0
- data/app/assets/javascripts/mbeditor/components/DiffViewer.js +1 -1
- data/app/assets/javascripts/mbeditor/components/EditorPanel.js +442 -248
- data/app/assets/javascripts/mbeditor/components/FileHistoryPanel.js +6 -9
- data/app/assets/javascripts/mbeditor/components/FileTree.js +26 -12
- data/app/assets/javascripts/mbeditor/components/GitPanel.js +3 -0
- data/app/assets/javascripts/mbeditor/components/Gutter.js +51 -0
- data/app/assets/javascripts/mbeditor/components/ImportConflictModal.js +60 -5
- data/app/assets/javascripts/mbeditor/components/LogPanel.js +3 -44
- data/app/assets/javascripts/mbeditor/components/MbeditorApp.js +1241 -1256
- data/app/assets/javascripts/mbeditor/components/ModelGraph.js +94 -37
- data/app/assets/javascripts/mbeditor/components/PastePlaceModal.js +329 -0
- data/app/assets/javascripts/mbeditor/components/ProblemsPanel.js +47 -65
- data/app/assets/javascripts/mbeditor/components/QuickOpenDialog.js +26 -8
- data/app/assets/javascripts/mbeditor/components/SettingsModal.js +342 -0
- data/app/assets/javascripts/mbeditor/components/ShortcutHelp.js +18 -1
- data/app/assets/javascripts/mbeditor/components/TabBar.js +67 -98
- data/app/assets/javascripts/mbeditor/editor_plugins.js +705 -323
- data/app/assets/javascripts/mbeditor/file_import.js +13 -15
- data/app/assets/javascripts/mbeditor/file_service.js +48 -39
- data/app/assets/javascripts/mbeditor/git_service.js +15 -1
- data/app/assets/javascripts/mbeditor/history_service.js +5 -13
- data/app/assets/javascripts/mbeditor/search_service.js +9 -0
- data/app/assets/javascripts/mbeditor/tab_manager.js +127 -49
- data/app/assets/javascripts/mbeditor/websocket_service.js +13 -5
- data/app/assets/stylesheets/mbeditor/application.css +6 -1
- data/app/assets/stylesheets/mbeditor/editor.css +672 -249
- data/app/assets/stylesheets/mbeditor/glass.css +174 -0
- data/app/assets/stylesheets/mbeditor/themes.css +93 -33
- data/app/channels/mbeditor/collaboration_channel.rb +17 -4
- data/app/controllers/mbeditor/application_controller.rb +26 -3
- data/app/controllers/mbeditor/editors_controller.rb +124 -439
- data/app/services/mbeditor/archive_service.rb +137 -0
- data/app/services/mbeditor/collaboration_doc_store.rb +143 -14
- data/app/services/mbeditor/editor_state_service.rb +14 -51
- data/app/services/mbeditor/file_history_service.rb +222 -0
- data/app/services/mbeditor/git_info_service.rb +6 -0
- data/app/services/mbeditor/js_syntax_check_service.rb +42 -16
- data/app/services/mbeditor/lint_service.rb +137 -0
- data/app/services/mbeditor/locked_json_file.rb +67 -0
- data/app/services/mbeditor/process_runner.rb +32 -0
- data/app/services/mbeditor/ruby_lsp_result_translator.rb +226 -0
- data/app/services/mbeditor/ruby_method_ranges_service.rb +120 -0
- data/app/services/mbeditor/search_replace_service.rb +8 -0
- data/app/views/layouts/mbeditor/application.html.erb +1 -1
- data/lib/mbeditor/audit_log.rb +203 -0
- data/lib/mbeditor/configuration.rb +6 -1
- data/lib/mbeditor/rack/pending_migration_bypass.rb +31 -10
- data/lib/mbeditor/route_map.rb +5 -0
- data/lib/mbeditor/ruby_lsp_client.rb +82 -14
- data/lib/mbeditor/version.rb +1 -1
- data/lib/mbeditor.rb +1 -0
- data/public/monaco-editor/VERSIONS +1 -1
- data/public/monaco-editor/codicon.ttf +0 -0
- data/public/monaco-editor/css.worker.js +41 -37
- data/public/monaco-editor/editor.worker.js +19 -15
- data/public/monaco-editor/html.worker.js +53 -49
- data/public/monaco-editor/json.worker.js +36 -32
- data/public/monaco-editor/monaco.css +1 -1
- data/public/monaco-editor/monaco.js +388 -301
- data/public/monaco-editor/ts.worker.js +226 -222
- data/vendor/assets/javascripts/axios.min.js +3 -3
- metadata +15 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d6faf6632c3072f98fe34083c809069a4e37ed9e956fd6722fd2fb188ed13c55
|
|
4
|
+
data.tar.gz: 24e179af4efd250cef7ddeec7d81a8c033891af89cb286980ddbb3541f543239
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 800cbc5afda678e3ae3298dc781f39054c32ecb0098dc82e68df9c6f0f8222ba4e5c06d0c6b424e50360dda0f02ed678169c4f4922353c432c8c0b446f28f428
|
|
7
|
+
data.tar.gz: 49bca37c5e4a696a4ba1ec4f5f01454899d006cb827f109e11a96e46feb65544ac7c85afdc55756076302618a2af30ced210e1b149b85690899b6801f5dcd37b
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,138 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.14.1] - 2026-10-19
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Combined View.** Ctrl/Cmd-select files or folders in the explorer, right-click,
|
|
12
|
+
"Open in Combined View": every file on one scrolling page under its path, with
|
|
13
|
+
Copy and Download per file. Folders expand recursively; capped at 200 files with
|
|
14
|
+
a visible note. The tab is virtual and is not restored on reload.
|
|
15
|
+
- **Method picking and Markdown export.** In Combined View, Ruby files get a
|
|
16
|
+
method checklist; "Download .md" / "Copy .md" bundle the view into one file,
|
|
17
|
+
method-limited files keeping their `class`/`module` skeleton with `# ...`
|
|
18
|
+
between pieces. Built for chat assistants that take only a few attachments.
|
|
19
|
+
- **Paste & Place** (editor context menu or F1, Ruby). Paste methods from a
|
|
20
|
+
chat reply and mbeditor finds where each goes: the active file, then a repo
|
|
21
|
+
search for `def name` narrowed by class. New methods go into the file that
|
|
22
|
+
holds the class, before `private`. Diff preview first; Apply is one undoable
|
|
23
|
+
edit in the buffer and nothing is saved.
|
|
24
|
+
- **Compare on upload conflicts.** When an upload or drop would overwrite a
|
|
25
|
+
file, each text file gets a "Compare" diff of disk vs incoming.
|
|
26
|
+
- `POST /ruby_methods`: Ripper-based method ranges (owner, singleton, doc
|
|
27
|
+
comment start) behind the two features above.
|
|
28
|
+
- A help-panel section describing all of the above.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
- **Unreadable status bar and buttons.** The Liquid Glass status bar and the
|
|
32
|
+
title-bar buttons painted "text on the accent fill" onto panel-coloured
|
|
33
|
+
surfaces; glass also hid the amber pending-migration background; Dracula,
|
|
34
|
+
Night Owl and Tomorrow Night had white text on light accents. 44 combinations
|
|
35
|
+
(11 themes × glass × pending) now all clear 4.5:1 on the status bar.
|
|
36
|
+
- **Flicker while migrations are pending.** `/cable` was not covered by the
|
|
37
|
+
pending-migration bypass, so every reconnect raised and the live channel
|
|
38
|
+
(presence, collaboration, file-change push) stayed dead.
|
|
39
|
+
- Paste & Place searches use POSIX classes, because the `git grep` search tier
|
|
40
|
+
is ERE and silently matches nothing for `\s`.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
- **Monaco 0.57.0** (from 0.55.1). Its TypeScript API moved from
|
|
44
|
+
`monaco.languages.typescript` to `monaco.typescript`; every call site is
|
|
45
|
+
migrated. DOMPurify inside Monaco is still 3.4.15 (advisory rated low) until a
|
|
46
|
+
Monaco release ships 3.4.16+.
|
|
47
|
+
- **axios 1.20.0** (from 1.17.0 vendored), for new high-severity advisories.
|
|
48
|
+
|
|
49
|
+
## [0.14.0] - 2026-09-21
|
|
50
|
+
|
|
51
|
+
### Added
|
|
52
|
+
- **Liquid Glass chrome, opt-in** (Settings → Appearance). Translucent, blurred
|
|
53
|
+
panels layered over whichever theme is active — it is a layer, not a twelfth
|
|
54
|
+
theme, so every colour is derived from the existing `--ide-*` tokens. Monaco
|
|
55
|
+
itself stays solid: legibility beats the effect, and a blurred backdrop under
|
|
56
|
+
a text editor costs a re-composite per repaint. The default chrome is the new
|
|
57
|
+
Modern one, matching VS Code's Dark Modern.
|
|
58
|
+
- **Drag-to-open gutters.** One `Gutter` component owns every draggable gap.
|
|
59
|
+
Drag the strip above the status bar to open Problems, the right edge to open
|
|
60
|
+
the git panel, and the collapsed sidebar's gutter rightwards to snap the
|
|
61
|
+
explorer back open.
|
|
62
|
+
- **Settings is a searchable modal**, not an editor tab, so it no longer takes a
|
|
63
|
+
pane or persists into your tab list.
|
|
64
|
+
- **The model graph opens as its own view**, not a tab: the activity-bar icon
|
|
65
|
+
toggles it, it takes the whole centre column, and both side panels hide with
|
|
66
|
+
it. A layered graph is inherently wide and the tab gave it whatever was left
|
|
67
|
+
beside the explorer.
|
|
68
|
+
- **A downloadable audit log** (Settings → Diagnostics) that structurally cannot
|
|
69
|
+
carry a file name, path or URL — every field is a number, boolean or authored
|
|
70
|
+
Symbol.
|
|
71
|
+
- **Quick Open as a frosted palette** over the title bar, with a chevron
|
|
72
|
+
breadcrumb and VS Code-style Open Editors rows.
|
|
73
|
+
- Auto-close tags in ERB and multi-line JSX, linked tag pairs, and `props.x`
|
|
74
|
+
completion.
|
|
75
|
+
- Multi-select download in the explorer.
|
|
76
|
+
- A `toolbarLabels` preference: toolbar button labels are now opt-in.
|
|
77
|
+
- Accessibility: a focus-visible ring throughout, a real tab-close button, a
|
|
78
|
+
higher-contrast version chip, and the offline pulse respects reduced-motion.
|
|
79
|
+
|
|
80
|
+
### Changed
|
|
81
|
+
- **The pending-migration warning is no longer a banner.** It sat above
|
|
82
|
+
everything and pushed the editor down the page every time it appeared. The
|
|
83
|
+
status bar turns amber instead and carries a "Migrations pending" item. Both
|
|
84
|
+
halves of that colour are per-theme, because `--ide-warning` is authored as a
|
|
85
|
+
foreground colour and several themes pick an ochre that is unreadable as a
|
|
86
|
+
background; measured contrast is 4.87:1 to 14.97:1 across the eleven themes.
|
|
87
|
+
- **Peer presence is an avatar stack**, not one chip per peer. Eight people used
|
|
88
|
+
to mean eight buttons across the title bar; it is now three overlapping dots
|
|
89
|
+
and a `+N`, fixed width whatever the roster size. Hovering a dot opens the
|
|
90
|
+
usual card, clicking follows or unfollows, and the `+N` opens a list of
|
|
91
|
+
everyone else with a follow toggle per row.
|
|
92
|
+
- The title bar says "Mbeditor" rather than the full window title; the host and
|
|
93
|
+
port are in the browser's own address bar.
|
|
94
|
+
- The file-tree section header has no chevron. Collapsing it left an empty
|
|
95
|
+
sidebar, so there was nothing to collapse to.
|
|
96
|
+
- Tabs are rounded chips on the strip, the Problems panel wears VS Code chrome,
|
|
97
|
+
and problem counts are neutral rather than alarming.
|
|
98
|
+
- `.scss` files open as scss and `.less` files as less, instead of css and
|
|
99
|
+
plaintext.
|
|
100
|
+
- Audit recording moved off the subprocess critical path.
|
|
101
|
+
|
|
102
|
+
### Fixed
|
|
103
|
+
- **The pending-migration warning stuck after `rails db:migrate`**, and
|
|
104
|
+
flickered before that. The header announcing it was only *set* when a
|
|
105
|
+
migration was pending, and those responses are conditional-GET cacheable: a
|
|
106
|
+
304 updates the stored headers of the cached 200 but never removes one it
|
|
107
|
+
omits, so the browser replayed "pending" for as long as the cache entry
|
|
108
|
+
lived. It is now always sent, `1` or `0`, and an absent header counts as no
|
|
109
|
+
evidence either way.
|
|
110
|
+
- **The model graph was unusable on a large app.** The cost was in click and
|
|
111
|
+
hover, not pan and zoom: `focused` was a dependency of the scene memo, so
|
|
112
|
+
every click-to-centre rebuilt every SVG element inside the click handler;
|
|
113
|
+
node hover scanned the whole scene per mouseenter; and the hover card and
|
|
114
|
+
edge tooltip each read `getBoundingClientRect` per pointer move, right after
|
|
115
|
+
hover had dirtied the style, forcing a full-scene layout. Measured on a
|
|
116
|
+
420-model, 1,249-association app: click-to-centre 20.4 ms → 7.9 ms median,
|
|
117
|
+
hover 45.7 ms → 33.2 ms.
|
|
118
|
+
- Collaboration data-loss paths, and the per-keystroke buffer work that went
|
|
119
|
+
with them.
|
|
120
|
+
- Undo tracking starts after the file load, not before, so the first undo no
|
|
121
|
+
longer empties a freshly opened file.
|
|
122
|
+
- Ruby hover skips comments and the route-hint decoration space, and
|
|
123
|
+
go-to-definition starts the Ripper fallback alongside ruby-lsp rather than
|
|
124
|
+
after it.
|
|
125
|
+
- Closing a markdown file closes its preview, and source and preview scroll in
|
|
126
|
+
sync.
|
|
127
|
+
- Markdown anchor links, upload UX, the conflict chip and the cursor readout.
|
|
128
|
+
- `RubyLspClient` performs its handshake outside the state lock, bounds the
|
|
129
|
+
document-lock wait, and keeps an LRU of documents.
|
|
130
|
+
- `JsSyntaxCheckService` remembers a broken babel bundle instead of retrying it,
|
|
131
|
+
and bounds its lock wait.
|
|
132
|
+
- The test-result `localStorage` cache is capped, and failed draft backups are
|
|
133
|
+
surfaced rather than silently dropped.
|
|
134
|
+
- `json` is pinned below 3 so the suite runs.
|
|
135
|
+
|
|
136
|
+
### Removed
|
|
137
|
+
- Stale agent docs, the dead `build_js` rake task and a set of duplicated
|
|
138
|
+
helpers — about 1,100 lines.
|
|
139
|
+
|
|
8
140
|
## [0.13.1] - 2026-08-26
|
|
9
141
|
|
|
10
142
|
### Removed
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
//= require mbeditor/application_iife_head
|
|
2
|
+
//= require mbeditor/audit_log
|
|
2
3
|
//= require mbeditor/editor_store
|
|
3
4
|
//= require mbeditor/file_icon
|
|
4
5
|
//= require mbeditor/file_service
|
|
@@ -17,12 +18,15 @@
|
|
|
17
18
|
//= require mbeditor/ruby_outline
|
|
18
19
|
//= require mbeditor/js_outline
|
|
19
20
|
//= require mbeditor/components/CollapsibleSection
|
|
21
|
+
//= require mbeditor/components/SettingsModal
|
|
22
|
+
//= require mbeditor/components/Gutter
|
|
20
23
|
//= require mbeditor/components/ShortcutHelp
|
|
21
24
|
//= require mbeditor/components/DiffViewer
|
|
22
25
|
//= require mbeditor/components/CombinedDiffViewer
|
|
23
26
|
//= require mbeditor/components/CommitGraph
|
|
24
27
|
//= require mbeditor/components/ModelGraph
|
|
25
28
|
//= require mbeditor/components/ChangelogView
|
|
29
|
+
//= require mbeditor/components/CombinedFileView
|
|
26
30
|
//= require mbeditor/components/FileHistoryPanel
|
|
27
31
|
//= require mbeditor/components/TestResultsPanel
|
|
28
32
|
//= require mbeditor/components/LogPanel
|
|
@@ -39,5 +43,6 @@
|
|
|
39
43
|
// whole app down the first time it renders.
|
|
40
44
|
//= require mbeditor/components/ImportConflictModal
|
|
41
45
|
//= require mbeditor/components/ImportDialog
|
|
46
|
+
//= require mbeditor/components/PastePlaceModal
|
|
42
47
|
//= require mbeditor/components/MbeditorApp
|
|
43
48
|
//= require mbeditor/application_iife_tail
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// Audit/telemetry ring the developer can download and hand to an AI to analyse.
|
|
2
|
+
//
|
|
3
|
+
// The privacy guarantee is structural, not a scrubber: rec() is the only way
|
|
4
|
+
// in, and it drops any argument whose typeof is not 'number'. A path, a file
|
|
5
|
+
// name, a URL or a line of source cannot be represented at all. Enumerated
|
|
6
|
+
// dimensions (file extension, search backend tier, LSP method, collab phase)
|
|
7
|
+
// travel as small integers whose meaning lives in LEGEND. LEGEND stays here and
|
|
8
|
+
// is merged into the file at download time: sending it to the server would be
|
|
9
|
+
// the one path in this module that carries an arbitrary string, which is
|
|
10
|
+
// exactly the property the rest of it exists to deny.
|
|
11
|
+
window.MbeditorAudit = (function () {
|
|
12
|
+
var CAPACITY = 512;
|
|
13
|
+
var FLUSH_AT = CAPACITY / 2;
|
|
14
|
+
|
|
15
|
+
var EV = Object.freeze({
|
|
16
|
+
BOOT: 1,
|
|
17
|
+
OPEN: 2,
|
|
18
|
+
SAVE: 3,
|
|
19
|
+
SEARCH: 4,
|
|
20
|
+
TREE_POLL: 5,
|
|
21
|
+
GIT_POLL: 6,
|
|
22
|
+
LINT: 7,
|
|
23
|
+
FORMAT: 8,
|
|
24
|
+
LSP: 9,
|
|
25
|
+
COLLAB: 10,
|
|
26
|
+
LONGTASK: 11,
|
|
27
|
+
ERR: 12
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
var LEGEND = {
|
|
31
|
+
ev: {},
|
|
32
|
+
// What a, b and c mean per event. A field named after one of the
|
|
33
|
+
// enumerated dimensions below carries an index into that table.
|
|
34
|
+
fields: {
|
|
35
|
+
BOOT: ['msToReady', '', ''],
|
|
36
|
+
OPEN: ['ext', 'bytes', 'ms'],
|
|
37
|
+
SAVE: ['ext', 'bytes', 'ms'],
|
|
38
|
+
SEARCH: ['searchBackend', 'ms', 'hits'],
|
|
39
|
+
TREE_POLL: ['ms', 'changed', ''],
|
|
40
|
+
GIT_POLL: ['ms', 'changedFiles', ''],
|
|
41
|
+
LINT: ['ext', 'ms', 'markers'],
|
|
42
|
+
FORMAT: ['ext', 'ms', 'bytes'],
|
|
43
|
+
LSP: ['lspMethod', 'ms', 'ok'],
|
|
44
|
+
COLLAB: ['collabPhase', 'peers', 'ms'],
|
|
45
|
+
LONGTASK: ['ms', '', ''],
|
|
46
|
+
ERR: ['ev', '', '']
|
|
47
|
+
},
|
|
48
|
+
// Index 0 is always "other", so an unrecognised name still records.
|
|
49
|
+
ext: ['other', 'rb', 'js', 'jsx', 'erb', 'haml', 'css', 'scss', 'html', 'md', 'json', 'yml', 'ts', 'tsx'],
|
|
50
|
+
searchBackend: ['other', 'rg', 'git', 'grep'],
|
|
51
|
+
lspMethod: ['other', 'definition', 'hover', 'completion', 'diagnostics', 'references', 'rename',
|
|
52
|
+
'format', 'signatureHelp', 'documentSymbol', 'foldingRange', 'documentHighlight',
|
|
53
|
+
'selectionRange', 'codeAction'],
|
|
54
|
+
collabPhase: ['other', 'join', 'seed', 'attach', 'defer', 'update', 'reconnect', 'leave', 'degrade']
|
|
55
|
+
};
|
|
56
|
+
Object.keys(EV).forEach(function (name) { LEGEND.ev[EV[name]] = name; });
|
|
57
|
+
|
|
58
|
+
// Preallocated: rec() reuses the slot, so recording allocates nothing.
|
|
59
|
+
var ring = new Array(CAPACITY);
|
|
60
|
+
for (var i = 0; i < CAPACITY; i++) ring[i] = [0, 0, 0, 0, 0];
|
|
61
|
+
|
|
62
|
+
var write = 0;
|
|
63
|
+
var count = 0;
|
|
64
|
+
var enabled = false;
|
|
65
|
+
var scheduled = false;
|
|
66
|
+
var observing = false;
|
|
67
|
+
|
|
68
|
+
// The whole privacy guarantee in one line.
|
|
69
|
+
function num(v) { return typeof v === 'number' && isFinite(v) ? v : 0; }
|
|
70
|
+
|
|
71
|
+
function rec(ev, a, b, c) {
|
|
72
|
+
if (!enabled) return;
|
|
73
|
+
var e = ring[write];
|
|
74
|
+
e[0] = performance.now() | 0;
|
|
75
|
+
e[1] = num(ev);
|
|
76
|
+
e[2] = num(a);
|
|
77
|
+
e[3] = num(b);
|
|
78
|
+
e[4] = num(c);
|
|
79
|
+
write = write + 1 === CAPACITY ? 0 : write + 1;
|
|
80
|
+
if (count < CAPACITY) count++;
|
|
81
|
+
if (count >= FLUSH_AT) schedule();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function code(dimension, name) {
|
|
85
|
+
var table = LEGEND[dimension];
|
|
86
|
+
var index = table ? table.indexOf(name) : -1;
|
|
87
|
+
return index < 0 ? 0 : index;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function drain() {
|
|
91
|
+
var out = new Array(count);
|
|
92
|
+
var start = (write - count + CAPACITY) % CAPACITY;
|
|
93
|
+
for (var i = 0; i < count; i++) {
|
|
94
|
+
var e = ring[(start + i) % CAPACITY];
|
|
95
|
+
out[i] = [e[0], e[1], e[2], e[3], e[4]];
|
|
96
|
+
}
|
|
97
|
+
count = 0;
|
|
98
|
+
write = 0;
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// keepalive rather than navigator.sendBeacon: the CSRF guard needs the
|
|
103
|
+
// X-Mbeditor-Client header and sendBeacon cannot set one.
|
|
104
|
+
function flush() {
|
|
105
|
+
scheduled = false;
|
|
106
|
+
if (!enabled || count === 0) return Promise.resolve();
|
|
107
|
+
var body = JSON.stringify({ events: drain() });
|
|
108
|
+
return fetch(window.mbeditorBasePath() + '/audit_log', {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
keepalive: true,
|
|
111
|
+
headers: { 'X-Mbeditor-Client': '1', 'Content-Type': 'application/json' },
|
|
112
|
+
body: body
|
|
113
|
+
})['catch'](function () {});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function schedule() {
|
|
117
|
+
if (scheduled) return;
|
|
118
|
+
scheduled = true;
|
|
119
|
+
if (window.requestIdleCallback) {
|
|
120
|
+
window.requestIdleCallback(function () { flush(); }, { timeout: 2000 });
|
|
121
|
+
} else {
|
|
122
|
+
setTimeout(function () { flush(); }, 0);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function observe() {
|
|
127
|
+
if (observing) return;
|
|
128
|
+
observing = true;
|
|
129
|
+
try {
|
|
130
|
+
new PerformanceObserver(function (list) {
|
|
131
|
+
var items = list.getEntries();
|
|
132
|
+
for (var i = 0; i < items.length; i++) rec(EV.LONGTASK, items[i].duration | 0);
|
|
133
|
+
}).observe({ type: 'longtask', buffered: true });
|
|
134
|
+
} catch (e) {
|
|
135
|
+
// Safari has no longtask entry type. Everything else keeps recording.
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function clear() { count = 0; write = 0; }
|
|
140
|
+
|
|
141
|
+
function setEnabled(on) {
|
|
142
|
+
on = !!on;
|
|
143
|
+
if (on === enabled) return;
|
|
144
|
+
enabled = on;
|
|
145
|
+
// Disabled means nothing recorded, including what was buffered before the
|
|
146
|
+
// preference arrived from the server.
|
|
147
|
+
if (on) observe(); else clear();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
window.addEventListener('pagehide', function () { flush(); });
|
|
151
|
+
document.addEventListener('visibilitychange', function () {
|
|
152
|
+
if (document.visibilityState === 'hidden') flush();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
EV: EV,
|
|
157
|
+
LEGEND: LEGEND,
|
|
158
|
+
rec: rec,
|
|
159
|
+
code: code,
|
|
160
|
+
flush: flush,
|
|
161
|
+
clear: clear,
|
|
162
|
+
setEnabled: setEnabled,
|
|
163
|
+
buffered: function () { return count; }
|
|
164
|
+
};
|
|
165
|
+
})();
|