forked from CollaboraOnline/online
-
Notifications
You must be signed in to change notification settings - Fork 0
/
README
397 lines (325 loc) · 16.6 KB
/
README
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
Leaflet platform for Collabora Online
========================================
This is the client part of Collabora Online. For the server part, see the
../wsd/README, and install it first.
Build dependencies
------------------
npm is provided by the nodejs package.
npm should be at least 2.14, if not 3.x. Use `npm -v` to find the current version.
Upgrade npm (as root):
npm install -g npm
Another way is to use npm as a user, but set its prefix to a directory where
you have write access. If you want that, you need to have an ~/.npmrc with the
line e.g.
prefix=/opt/npm
All of the dependency tree is locked in the repository, so there is no need to fetch
data from npm registry at all. An npm install will use the tarballs in node_shrinkwrap/
directory, so build process can move forward even without an internet connection.
To update any of the dependency, process often goes like this:
1.) Change version of the dependency in package.json
2.) Do an `npm update <package_name>', which fetches the new module from npm registry. Make sure that
only the module that you want to update is updated.
3.) `npm shrinkwrap --include=dev` to update npm-shrinkwrap.json with newer information. You might see
that this tool updates path convention of tarballs inside node_shrinkwrap/ also, but this
should get corrected in next step.
4.) Do `shrinkpack', which should remove the old tarball, add new one, and make appropriate
changes to npm-shrinkwrap.json (removing path convention changes by step 3).
If you have not installed `shrinkpack' globally using `npm install -g shrinkpack@next', it should be
in node_modules/.bin/shrinkpack, so you can use the binary from there.
If you need to get the sources:
make libs
To bundle the file sanitize-url.js
browserify braintree-sanitize-url/index.js --standalone sanitizeUrl > sanitize-url.js
Building
--------
Just do:
make
Above step would create a non-minified bundle.js and admin-bundle.js without source-maps in dist/ for main browser and admin console
respectively.
To build with debug-info, i.e with sourcemaps:
make DEBUG=true
Above will produce source-map files, bundle.js.map and admin-bundle.js.map, for bundle.js and admin-bundle.js respectively.
It will also link existing bundle.js and admin-bundle.js to their map files by adding a sourceMappingURL to them. While debugging,
these .map files will be fetched from the server if present in dist/, otherwise there is no way to debug while browsing without these
source-map files.
To minify our bundle.js and admin-bundle.js passing a MINIFY=true flag to 'make' will minify it. This can be helpful in production
environments.
make MINIFY=true
'make dist' forces minifying.
Running
-------
To see an example:
* run coolwsd, like:
./coolwsd --o:sys_template_path=${SYSTEMPLATE} --o:child_root_path=${ROOTFORJAILS}
Note that this will, by default, set the coolwsd's file server's root to the parent directory of coolwsd,
which means you can access all the files in browser using /browser/ path. It is advised to set
file_server_root_path manually for more control. See wsd/README for more information.
* open dist/cool.html through coolwsd's fileserver
https://localhost:9980/browser/dist/cool.html?file_path=file:///PATH/TO_DOC&host=wss://localhost:9980
and you should see the document in the browser.
Note that accessing local storage is disabled by default for security reasons. You need to explicitly enable it
with the --o:storage.filesystem[@allow]=true option of coolwsd. In case anything goes wrong, check the coolwsd console for
the debugging output. You might be asked to confirm the certificate if you are using self-signed certificate
for coolwsd.
Development
-----------
For faster development you might want to install browser-sync which can reload app in your browsers automatically
after you edit and save the source code (so for .css only):
npm install -g browser-sync
Remember to add '--enable-browsersync' argument for './configure' script and delete `dist` directory.
Run server and start browser-sync:
COOL_SERVE_FROM_FS=1 make run
and in the second terminal:
make sync-[writer|calc|impress]
Your browser will open example document and now you can edit .css files and see the result without server restart.
To run another document use:
browser-sync start --config browsersync-config.js --startPath "browser/96c23f663/cool.html?file_path=file:///path/to/the/file.ods"
Admin Panel
-----------
You can do live monitoring of all the user sessions running on coolwsd instance. To access the admin
console you need to ask for admin.html file from coolwsd which resides in dist/admin/admin.html.
For example:
https://localhost:9980/browser/dist/admin/admin.html
It will ask for username and password which is set by the admin_console options of coolwsd. For example you can
pass --o:admin_console.username=admin --o:admin_console.password=admin in command line, or set these values in
coolwsd.xml. After entering the correct password you should be able to monitor the live documents opened, total
users, memory consumption, document URLs with number of users viewing that document etc. You can also kill the
documents directly from the panel which would result in closing the socket connection to the respective document.
API & events
------------
#######################################################################
# See /browser/reference.html for a better formatted documentation. #
# See /wsd/reference.md for the HTTP API documentation. #
#######################################################################
Search:
- API:
map.search(text, [backward])
map.highlightAll(text)
- events:
map.on('search', function (e) {}) (currently only fired when no search result is found) where:
+ e.originalPhrase = the phrase that has been searched for
+ e.count = number of results
+ e.results = [SearchResult], where SearchResult = {part: part, rectangles: [Bounds]}
Zoom:
- API:
map.zoomIn(amount)
map.zoomOut(amount)
map.getMinZoom()
map.getMaxZoom()
- events:
map.on('zoomend zoomlevelschange', function)
Edit, view, readOnly:
- API:
map.setPermission('edit' | 'view' | 'readonly')
- events:
app.events.on('updatepermission', function (e) {}) where:
+ e.detail.perm == 'edit' | 'view' | 'readonly'
Buttons like Bold, Italic, Strike through etc.
- API:
map.toggleCommandState('.uno:' + 'Bold' | 'Italic' | 'Underline' | 'Strikeout' |
'LeftPara' | 'CenterPara' | 'RightPara' | 'JustifyPara' |
'IncrementIndent' | 'DecrementIndent'
- events:
map.on('commandstatechanged', function (e) {}) where:
+ e.commandName == '.uno:' + 'Bold' | 'Italic' | 'StyleApply' | 'CharFontName' | 'FontHeight' etc.
+ e.state = 'true' | 'false'
+ e.state = fontName | fontSize | styleName
map.on('commandresult', function (e) {}) where:
+ e.commandName == '.uno:' + 'Bold' | 'Italic' | 'StyleApply' | 'CharFontName' | 'FontHeight' etc.
+ e.success = true | false | undefined
Parts (like slides in presentation, or sheets in spreadsheets):
- API:
map.setPart('next' | 'prev' | partNumber)
map.getNumberOfParts()
map.getCurrentPartNumber()
map.getPreview(id, index, maxWidth, maxHeight, [options], forAllClients)
+ id = the ID of the request so that the response can be identified
+ index = the part / page 's number
+ maxWidth / maxHeight = max dimensions so that the ratio is preserved
+ options = {autoUpdate: <boolean>, broadcast: <boolean>} -
+ autoUpdate - boolean, automatically updates the previews
+ broadcast - boolean, whether the response (a preview of a slide) should be sent to all clients
viewing the same presentation
map.getCustomPreview(id, part, width, height, tilePosX, tilePosY, tileWidth, tileHeight, [options])
+ id = the ID of the request so that the response can be identified
+ part = the part containing the desired preview
+ width / height = the preview's size in pixels
+ tilePosX / tilePosY = the rectangles's starting position in twips
+ tileWidth / tileHeight = the rectangle's dimension in twips
+ options = {autoUpdate: true} - automatically updates the previews
map.removePreviewUpdate(id)
+ id = the preview's id
- events:
map.on('updateparts', function (e) {}) where:
+ e.selectedPart is the current part
+ e.parts == the number of parts that the document has
+ e.docType == 'text' | 'spreadsheet' | 'presentation' | 'drawing' | 'other'
+ [e.partNames] if present, part names (e.g. sheet names)
map.on('tilepreview', function (e) {}) where:
+ e.tile - the preview image
+ e.id - the preview id
+ e.width - width of the image
+ e.height - height of the image
+ [e.part] - if the preview is for a part
+ e.docType
progress (when the document is loading):
- events
map.on('progress', function (e) {}) where:
+ e.statusType = 'start' | 'setvalue' | 'finish' | 'coolloaded' | 'alltilesloaded'
+ e.type == 'bg' for a background operation
+ e.value == a value from 0 to 100 indicating the status
if the statusType is 'setvalue
+ 'coolloaded' is fired when the JS code is initialized and the document
load request is sent and we're waiting for the tiles
+ 'alltilesloaded' is fired when all newly requested (empty tiles) have been loaded
it is not fired during pre-fetching and during editing
Save:
- API:
map.saveAs(url, [format, options])
map.downloadAs(name, [format, options])
Scroll (the following are measured in pixels):
- API:
+ options = An object with members: update (type: Boolean, default: false)
like {update: true}
map.scroll(x,y, options)
+ scroll right by 'x' and down by 'y' (or left and up if negative)
map.scrollDown(y, options)
+ scroll down by 'y' (or up if negative)
map.scrollRight(x, options)
+ scroll right by 'x' (or left if negative)
map.scrollTop(y, options)
+ scroll to 'y' offset relative to the beginning of the document
map.scrollLeft(x, options)
+ scroll to 'x' offset relative to the beginning of the document
map.scrollOffset()
+ returns the scroll offset relative to the beginning of the document
map.getDocSize()
+ returns the document's size in pixels
map.getDocType()
+ returns 'text' | 'spreadsheet' | 'presentation' | 'drawing' | 'other'
- events
map.on('docsize', function (e) {}) where:
+ e.x = document width
+ e.y = document height
map.on('updatescrolloffset', function (e) {}) where:
+ e.x = difference between document's left and current view's left
(how much has the document been scrolled right)
+ e.y = difference between document's top and current view's top
(how much has the document been scrolled down)
- this event is fired when zooming and the current view is maintained but the
document shrinks or grow OR when the document is panned OR when the container is resized
map.on('scrollto', function (e) {}) where:
+ e.x = view's left position (so that the cursor/search result is in the center)
+ e.y = view's top position (so that the cursor/search result is in the center)
map.on('scrollby', function (e) {}) where:
+ e.x = the amount scrolled to the right (or left if negative)
+ e.y = the amount scrolled to the bottom (or top if negative)
Writer pages:
- API:
map.goToPage(page)
map.getNumberOfPages()
map.getCurrentPageNumber()
map.getPreview(id, index, maxWidth, maxHeight, [options])
+ id = the ID of the request so that the response can be identified
+ index = the part / page 's number
+ maxWidth / maxHeight = max dimensions so that the ratio is preserved
+ options = {autoUpdate: true} - automatically updates the previews
map.getCustomPreview(id, part, width, height, tilePosX, tilePosY, tileWidth, tileHeight, [options])
+ id = the ID of the request so that the response can be identified
+ part = the part containing the desired preview
+ width / height = the preview's size in pixels
+ tilePosX / tilePosY = the rectangles's starting position in twips
+ tileWidth / tileHeight = the rectangle's dimension in twips
+ options = {autoUpdate: true} - automatically updates the previews
map.removePreviewUpdate(id)
+ id = the preview's id
map.getPageSizes()
+ returns {twips: [Bounds], pixels: [Bounds]}
- events
map.on('pagenumberchanged', function (e) {}) where:
+ e.currentPage = the page on which the cursor lies
+ e.pages = number of pages
+ e.docType = document type, should be 'text'
Error:
- events
map.on('error', function (e) {}) where
+ [e.msg] = a message describing the error
+ [e.cmd] = the command that caused the error
+ [e.kind] = the kind of error
Infobars:
- events
map.on('infobar', function (e) {}) where
+ [e.msg] = a message
+ [e.actionlabel] = Label for the action button
+ [e.action] = A link (starting with http).
Please extend to allow other actions when needed.
CommandValues:
- api:
map.getToolbarCommandValues(command)
+ returns a JSON mapping of all possible values for the command
map.applyFont(fontName)
map.applyFontSize(fontSize)
map.applyStyle(style, styleFamily)
- events
map.on('updatetoolbarcommandvalues', function (e) {}) where
+ e.commandName = '.uno:StyleApply', etc
+ e.commandValues = a JSON mapping of all possible values for the command
Print:
- events
map.on('print', function (e) {}) where
+ e.url = file download url
Contributing
------------
Code conventions:
* files should have unix line terminators (LF)
* tools to convert files: dos2unix or fromdos
Implementation details
----------------------
Loading a document:
The map should have the following options:
- server address
- doc - path to the document that will be loaded
- edit = the initial permission
- readOnly - whether the document is read only
- [timestamp] - optionally provided for remote documents
How zooming works:
The zoom level goes from 1 to 20 (those limits can be changed) and the initial
level is 10, which represents the 100% zoom level. The zoom factor is 1.2
Controls are added above the map in a div called "controls" is intended to be used as a toolbar.
There is no leaflet method of adding them in a separate div, so for now this is done in the html
document after the map initialization.
To enable scrollbars the map is placed above a div that contains a bigger div of
the document's size (a mock document). So the div under the map gets scrollbars which
are independent of the map's div, thus enabling us to link them to the map as needed.
When the user scrolls, the map is panned by the same amount as it would've been scrolled.
Also, some custom jquery scrollbars are used, to trigger the same scroll events across
browsers.
Z-index values:
-------------------------------------------
leaflet
-------------------------------------------
10 map
11 ruler
-------------------------------------------
under menu
-------------------------------------------
990 sidebar
999 toolbar-up
999 Notebookbar tabs (.ui-tabs.notebookbar)
-------------------------------------------
menu items
-------------------------------------------
x menu-nb-hamburger > ul (calculated from jquery.smartmenus.js)
1000 main-menu(desktop-only)
11 toolbar-down
1050 closebuttonwrapper (not being used currently)
-------------------------------------------
on the top
-------------------------------------------
1105 dialogs, tooltips
1001 mobile-edit-button
1500 mobile-wizard (with class=menuwizard)
1501 toolbar-hamburger (with class=menuwizard-opened)
2000 JSDialog overlay
2001 JSDialog modal
-------------------------------------------