07a305df80
An event is fired with the page dimensions. Also the current page number is updated based on which page contains the current view's center
262 lines
10 KiB
Text
262 lines
10 KiB
Text
Leaflet platform for LibreOffice On-Line
|
|
========================================
|
|
|
|
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:
|
|
|
|
npm install -g jake
|
|
npm install
|
|
|
|
npm is provided by the nodejs package.
|
|
Alternatively, you can use the provided zip (as a normal user):
|
|
|
|
unzip node_modules/modules.zip -d node_modules
|
|
|
|
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
|
|
|
|
Building
|
|
--------
|
|
|
|
As a normal user:
|
|
|
|
jake build
|
|
cd plugins/draw-0.2.4
|
|
jake build
|
|
|
|
Running
|
|
-------
|
|
|
|
To see an example:
|
|
|
|
* run loolwsd, like:
|
|
|
|
./loolwsd --systemplate=${SYSTEMPLATE} --lotemplate=${MASTER}/instdir --childroot=${ROOTFORJAILS}
|
|
|
|
* open debug/document/document_simple_example.html in the browser, like:
|
|
|
|
firefox debug/document/document_simple_example.html
|
|
|
|
* modify the URL to allow loleaflet to connect to a server and open a document
|
|
|
|
http://web-page/document_simple_example.html?file_path=file:///PATH/TO/DOC&host=ws://localhost:9980
|
|
|
|
and you should see the document in the browser. In case anything goes wrong,
|
|
check the loolwsd console for the debugging output.
|
|
|
|
API & events
|
|
------------
|
|
|
|
Search:
|
|
- API:
|
|
map.search(text, [backward])
|
|
- 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
|
|
|
|
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:
|
|
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
|
|
|
|
Parts (like slides in presentation, or sheets in spreadsheets):
|
|
- API:
|
|
map.setPart('next' | 'prev' | partNumber)
|
|
map.getPartPreview(id, part, maxWidth, maxHeight, [options]) where:
|
|
+ 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
|
|
+ options = {autoUpdate: true} - automatically updates the previews
|
|
map.getNumberOfParts()
|
|
map.getCurrentPartNumber()
|
|
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('invalidatepreview', function (e) {})
|
|
+ e.id = the preview's id
|
|
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
|
|
|
|
Statusindicator (when the document is loading):
|
|
- events
|
|
map.on('statusindicator', function (e) {}) where:
|
|
+ e.statusType = 'start' | 'setvalue' | 'finish' | 'loleafletloaded' | 'alltilesloaded'
|
|
+ e.value == a value from 0 to 100 indicating the status
|
|
if the statusType is 'setvalue
|
|
+ 'loleafletloaded' 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])
|
|
|
|
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 nevative)
|
|
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.getDocPreview(id, maxWidth, maxHeight, x, y, width, height, [options])
|
|
+ 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
|
|
+ options = {autoUpdate: true} - automatically updates the previews
|
|
map.removePreviewUpdate(id)
|
|
+ id = the preview's id
|
|
|
|
- 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'
|
|
map.on('invalidatepreview', function (e) {})
|
|
+ e.id = the preview's id
|
|
map.on('partpagerectangles', function (e) {}) where:
|
|
+ e.pixelRectangles = An array of bounds representing each page's dimension in pixels on the current zoom level
|
|
+ e.twipsRectangles = An array of bounds representing each page's dimension in twips.
|
|
|
|
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
|
|
|
|
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:StyleAplly', etc
|
|
+ e.commandValues = a JSON mapping of all possible values for the command
|
|
|
|
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
|
|
|
|
|
|
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
|
|
----------------------
|
|
|
|
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.
|