2015-04-21 09:03:17 -05:00
|
|
|
Leaflet platform for LibreOffice On-Line
|
|
|
|
========================================
|
2015-03-09 08:58:37 -05:00
|
|
|
|
2015-04-21 09:03:17 -05:00
|
|
|
This is the client part of LibreOffice On-Line. For the server part, see the
|
|
|
|
../loolwsd/README, and install it first.
|
|
|
|
|
|
|
|
Build dependencies
|
|
|
|
------------------
|
|
|
|
|
|
|
|
First you need to install 'jake'. As root, do:
|
2015-03-09 08:58:37 -05:00
|
|
|
|
|
|
|
npm install -g jake
|
|
|
|
npm install
|
2015-04-21 09:03:17 -05:00
|
|
|
|
2015-08-21 10:13:26 -05:00
|
|
|
npm is provided by the nodejs package.
|
2015-04-21 09:03:17 -05:00
|
|
|
Alternatively, you can use the provided zip (as a normal user):
|
|
|
|
|
|
|
|
unzip node_modules/modules.zip -d node_modules
|
|
|
|
|
2015-05-27 09:08:58 -05:00
|
|
|
A third 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
|
|
|
|
|
2015-04-21 09:03:17 -05:00
|
|
|
Building
|
|
|
|
--------
|
|
|
|
|
|
|
|
As a normal user:
|
|
|
|
|
2015-03-09 08:58:37 -05:00
|
|
|
jake build
|
2015-04-06 09:14:21 -05:00
|
|
|
cd plugins/draw-0.2.4
|
|
|
|
jake build
|
2015-03-23 12:24:39 -05:00
|
|
|
|
2015-04-21 09:03:17 -05:00
|
|
|
Running
|
|
|
|
-------
|
|
|
|
|
|
|
|
To see an example:
|
|
|
|
|
|
|
|
* run loolwsd, like:
|
|
|
|
|
2015-05-06 02:08:56 -05:00
|
|
|
./loolwsd --systemplate=${SYSTEMPLATE} --lotemplate=${MASTER}/instdir --childroot=${ROOTFORJAILS}
|
2015-04-21 09:03:17 -05:00
|
|
|
|
|
|
|
* open debug/document/document_simple_example.html in the browser, like:
|
|
|
|
|
|
|
|
firefox debug/document/document_simple_example.html
|
|
|
|
|
2015-05-06 02:08:56 -05:00
|
|
|
* modify the URL to allow loleaflet to connect to a server and open a document
|
|
|
|
|
2015-07-15 11:25:34 -05:00
|
|
|
http://web-page/document_simple_example.html?file_path=file:///PATH/TO/DOC&host=ws://localhost:9980
|
2015-05-06 02:08:56 -05:00
|
|
|
|
2015-04-21 09:03:17 -05:00
|
|
|
and you should see the document in the browser. In case anything goes wrong,
|
|
|
|
check the loolwsd console for the debugging output.
|
|
|
|
|
2015-07-15 11:25:34 -05:00
|
|
|
API & events
|
|
|
|
------------
|
|
|
|
|
|
|
|
Search:
|
|
|
|
- API:
|
|
|
|
map.search(text, [backward])
|
|
|
|
- events:
|
2015-08-12 10:06:49 -05:00
|
|
|
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
|
2015-07-15 11:25:34 -05:00
|
|
|
|
|
|
|
Zoom:
|
|
|
|
- API:
|
|
|
|
map.zoomIn(amount)
|
|
|
|
map.zoomOut(amout)
|
|
|
|
map.getMinZoom()
|
|
|
|
map.getMaxZoom()
|
|
|
|
- events:
|
|
|
|
map.on('zoomend zoomlevelschange', function)
|
|
|
|
|
|
|
|
Edit, view, readOnly:
|
|
|
|
- API:
|
|
|
|
map.setPermission('edit' | 'view' | 'readonly')
|
|
|
|
- events:
|
|
|
|
map.on('updatepermission', function (e) {}) where:
|
|
|
|
+ e.perm == 'edit' | 'view' | 'readonly'
|
|
|
|
|
|
|
|
Buttons like Bold, Italic, Strike through etc.
|
|
|
|
- API:
|
2015-09-15 03:52:55 -05:00
|
|
|
map.toggleCommandState('.uno:' + 'Bold' | 'Italic' | 'Underline' | 'Strikeout' |
|
2015-09-10 04:57:11 -05:00
|
|
|
'LeftPara' | 'CenterPara' | 'RightPara' | 'JustifyPara' |
|
|
|
|
'IncrementIndent' | 'DecrementIndent'
|
2015-07-15 11:25:34 -05:00
|
|
|
- events:
|
|
|
|
map.on('commandstatechanged', function (e) {}) where:
|
2015-09-15 03:52:55 -05:00
|
|
|
+ e.commandName == '.uno:' + 'Bold' | 'Italic' | 'StyleApply' | 'CharFontName' | 'FontHeight' etc.
|
2015-07-15 11:25:34 -05:00
|
|
|
+ e.state = 'true' | 'false'
|
2015-09-14 12:14:28 -05:00
|
|
|
+ e.state = fontName | fontSize | styleName
|
2015-07-15 11:25:34 -05:00
|
|
|
|
|
|
|
Parts (like slides in presentation, or sheets in spreadsheets):
|
|
|
|
- API:
|
|
|
|
map.setPart('next' | 'prev' | partNumber)
|
2015-09-02 09:12:02 -05:00
|
|
|
map.getPartPreview(id, part, maxWidth, maxHeight, [options]) where:
|
2015-07-15 11:25:34 -05:00
|
|
|
+ id = the ID of the request so that the response can be identified
|
|
|
|
+ maxWidth / maxHeight are the desired dimensions of the preview, a smaller
|
|
|
|
image might be returned in order to keep the original ratio of the document
|
2015-09-02 09:12:02 -05:00
|
|
|
+ options = {autoUpdate: true} - automatically updates the previews
|
2015-08-12 11:16:34 -05:00
|
|
|
map.getNumberOfParts()
|
2015-08-13 05:18:56 -05:00
|
|
|
map.getCurrentPartNumber()
|
2015-09-07 08:36:45 -05:00
|
|
|
map.removePreviewUpdate(id)
|
|
|
|
+ id = the preview's id
|
|
|
|
|
2015-07-15 11:25:34 -05:00
|
|
|
- events:
|
|
|
|
map.on('updateparts', function (e) {}) where:
|
2015-09-15 09:53:27 -05:00
|
|
|
+ e.selectedPart is the current part
|
2015-07-15 11:25:34 -05:00
|
|
|
+ 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)
|
2015-09-02 09:12:02 -05:00
|
|
|
map.on('invalidatepreview', function (e) {})
|
|
|
|
+ e.id = the preview's id
|
2015-09-07 08:28:10 -05:00
|
|
|
map.on('tilepreview', function (e) {}) where:
|
|
|
|
+ e.tile - the preview image
|
|
|
|
+ e.id - the preview id
|
|
|
|
+ e.width - widht of the image
|
|
|
|
+ e.height - height of the image
|
|
|
|
+ [e.part] - if the preview is for a part
|
|
|
|
+ e.docType
|
2015-07-15 11:25:34 -05:00
|
|
|
|
|
|
|
Statusindicator (when the document is loading):
|
|
|
|
- events
|
|
|
|
map.on('statusindicator', function (e) {}) where:
|
2015-08-07 01:50:50 -05:00
|
|
|
+ e.statusType = 'start' | 'setvalue' | 'finish' | 'loleafletloaded' | 'alltilesloaded'
|
2015-07-15 11:25:34 -05:00
|
|
|
+ e.value == a value from 0 to 100 indicating the status
|
|
|
|
if the statusType is 'setvalue
|
2015-08-06 09:04:00 -05:00
|
|
|
+ 'loleafletloaded' is fired when the JS code is initialized and the document
|
|
|
|
load request is sent and we're waiting for the tiles
|
2015-08-07 01:50:50 -05:00
|
|
|
+ 'alltilesloaded' is fired when all newly requested (empty tiles) have been loaded
|
|
|
|
it is not fired during pre-fetching and during editing
|
2015-07-15 11:25:34 -05:00
|
|
|
|
2015-07-16 04:50:08 -05:00
|
|
|
Save:
|
|
|
|
- API:
|
|
|
|
map.saveAs(url, [format, options])
|
|
|
|
|
2015-07-24 08:04:28 -05:00
|
|
|
Scroll (the following are measured in pixels):
|
|
|
|
- API:
|
2015-08-12 11:43:15 -05:00
|
|
|
+ options = An object with members: update (type: Boolean, default: false)
|
|
|
|
like {update: true}
|
|
|
|
map.scroll(x,y, options)
|
2015-07-24 08:04:28 -05:00
|
|
|
+ scroll right by 'x' and down by 'y' (or left and up if negative)
|
2015-08-12 11:43:15 -05:00
|
|
|
map.scrollDown(y, options)
|
2015-07-24 08:04:28 -05:00
|
|
|
+ scroll down by 'y' (or up if negative)
|
2015-08-12 11:43:15 -05:00
|
|
|
map.scrollRight(x, options)
|
2015-07-24 08:04:28 -05:00
|
|
|
+ scroll right by 'x' (or left if nevative)
|
2015-08-12 11:43:15 -05:00
|
|
|
map.scrollTop(y, options)
|
2015-08-04 03:09:10 -05:00
|
|
|
+ scroll to 'y' offset relative to the beginning of the document
|
2015-08-12 11:43:15 -05:00
|
|
|
map.scrollLeft(x, options)
|
2015-08-04 03:09:10 -05:00
|
|
|
+ scroll to 'x' offset relative to the beginning of the document
|
|
|
|
map.scrollOffset()
|
|
|
|
+ returns the scroll offset relative to the beginning of the document
|
2015-08-12 11:22:26 -05:00
|
|
|
map.getDocSize()
|
|
|
|
+ returns the document's size in pixels
|
2015-08-12 11:54:32 -05:00
|
|
|
map.getDocType()
|
|
|
|
+ returns 'text' | 'spreadsheet' | 'presentation' | 'drawing' | 'other'
|
2015-07-24 08:04:28 -05:00
|
|
|
- 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)
|
|
|
|
|
2015-08-03 11:19:38 -05:00
|
|
|
Writer pages:
|
|
|
|
- API:
|
|
|
|
map.goToPage(page)
|
|
|
|
map.getNumberOfPages()
|
2015-08-13 05:18:56 -05:00
|
|
|
map.getCurrentPageNumber()
|
2015-09-02 09:12:02 -05:00
|
|
|
map.getDocPreview(id, maxWidth, maxHeight, x, y, width, height, [options])
|
2015-08-13 04:58:59 -05:00
|
|
|
+ id = the ID of the request so that the response can be identified
|
|
|
|
+ maxWidth / maxHeight are the desired dimensions of the preview, a smaller
|
|
|
|
image might be returned in order to keep the original ratio of the document
|
|
|
|
+ x/y = starting position, where to get the preview from
|
2015-09-02 09:12:02 -05:00
|
|
|
+ options = {autoUpdate: true} - automatically updates the previews
|
2015-09-07 08:36:45 -05:00
|
|
|
map.removePreviewUpdate(id)
|
|
|
|
+ id = the preview's id
|
2015-08-13 04:58:59 -05:00
|
|
|
|
2015-08-03 11:19:38 -05:00
|
|
|
- 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'
|
2015-09-02 09:12:02 -05:00
|
|
|
map.on('invalidatepreview', function (e) {})
|
|
|
|
+ e.id = the preview's id
|
2015-08-06 09:41:56 -05:00
|
|
|
|
|
|
|
Error:
|
|
|
|
- events
|
|
|
|
map.on('error', function (e) {}) where
|
2015-08-11 03:37:26 -05:00
|
|
|
+ [e.msg] = a message describing the error
|
|
|
|
+ [e.cmd] = the command that caused the error
|
|
|
|
+ [e.kind] = the kind of error
|
2015-08-06 09:41:56 -05:00
|
|
|
|
2015-09-09 12:35:36 -05:00
|
|
|
CommandValues:
|
|
|
|
- api:
|
|
|
|
map.getToolbarCommandValues(command)
|
|
|
|
+ returns a JSON mapping of all possible values for the command
|
2015-09-10 03:26:47 -05:00
|
|
|
map.applyFont(fontName)
|
|
|
|
map.applyFontSize(fontSize)
|
2015-09-10 03:29:19 -05:00
|
|
|
map.applyStyle(style, styleFamily)
|
2015-09-09 12:35:36 -05:00
|
|
|
- events
|
|
|
|
map.on('updatetoolbarcommandvalues', function (e) {}) where
|
|
|
|
+ e.commandName = '.uno:StyleAplly', etc
|
|
|
|
+ e.commandValues = a JSON mapping of all possible values for the command
|
|
|
|
|
2015-08-18 06:34:10 -05:00
|
|
|
Testing
|
|
|
|
-------
|
|
|
|
- to simulate an editing session and to get the tile loading times
|
|
|
|
+ open spec/tilebench.html in the browser
|
|
|
|
- to simulate a client opening several documents in the browser
|
|
|
|
+ open spec/loadtest.html in the browser
|
|
|
|
- to simulate a client opening several documents in the console
|
|
|
|
+ run: mocha headlessLoadTest.js
|
|
|
|
|
|
|
|
|
2015-04-21 09:03:17 -05:00
|
|
|
Contributing
|
|
|
|
------------
|
|
|
|
|
|
|
|
Code conventions:
|
|
|
|
|
|
|
|
* 'jake lint' should be run before commiting
|
|
|
|
* files should have unix line terminators (LF)
|
|
|
|
* tools to convert files: dos2unix or fromdos
|
|
|
|
|
|
|
|
Implementation details
|
|
|
|
----------------------
|
2015-03-24 06:15:43 -05:00
|
|
|
|
2015-03-23 12:24:39 -05:00
|
|
|
Loading a document:
|
|
|
|
The map should have the following options:
|
|
|
|
- server address
|
2015-09-01 10:15:43 -05:00
|
|
|
- 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
|
2015-03-23 12:24:39 -05:00
|
|
|
|
2015-04-10 08:29:01 -05:00
|
|
|
How zooming works:
|
2015-05-01 11:18:03 -05:00
|
|
|
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
|
2015-04-10 08:29:01 -05:00
|
|
|
|
2015-04-06 09:14:21 -05:00
|
|
|
Controls are added above the map in a div called "controls" is intended to be used as a toolbar.
|
2015-05-01 11:18:03 -05:00
|
|
|
There is no leaflet method of adding them in a separate div, so for now this is done in the html
|
2015-04-06 09:14:21 -05:00
|
|
|
document after the map initialization.
|
2015-05-01 11:18:03 -05:00
|
|
|
|
2015-05-06 02:08:56 -05:00
|
|
|
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
|
2015-05-01 11:18:03 -05:00
|
|
|
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.
|
2015-05-06 02:08:56 -05:00
|
|
|
Also, some custom jquery scrollbars are used, to trigger the same scroll events across
|
2015-05-01 11:18:03 -05:00
|
|
|
browsers.
|